Merge tag 'acpi-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 29 Jun 2021 20:39:41 +0000 (13:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 29 Jun 2021 20:39:41 +0000 (13:39 -0700)
Pull ACPI updates from Rafael Wysocki:
 "These update the ACPICA code in the kernel to the 20210604 upstream
  revision, add preliminary support for the Platform Runtime Mechanism
  (PRM), address issues related to the handling of device dependencies
  in the ACPI device eunmeration code, improve the tracking of ACPI
  power resource states, improve the ACPI support for suspend-to-idle on
  AMD systems, continue the unification of message printing in the ACPI
  code, address assorted issues and clean up the code in a number of
  places.

  Specifics:

   - Update ACPICA code in the kernel to upstrea revision 20210604
     including the following changes:

      - Add defines for the CXL Host Bridge Structureand and add the
        CFMWS structure definition to CEDT (Alison Schofield).
      - iASL: Finish support for the IVRS ACPI table (Bob Moore).
      - iASL: Add support for the SVKL table (Bob Moore).
      - iASL: Add full support for RGRT ACPI table (Bob Moore).
      - iASL: Add support for the BDAT ACPI table (Bob Moore).
      - iASL: add disassembler support for PRMT (Erik Kaneda).
      - Fix memory leak caused by _CID repair function (Erik Kaneda).
      - Add support for PlatformRtMechanism OpRegion (Erik Kaneda).
      - Add PRMT module header to facilitate parsing (Erik Kaneda).
      - Add _PLD panel positions (Fabian Wüthrich).
      - MADT: add Multiprocessor Wakeup Mailbox Structure and the SVKL
        table headers (Kuppuswamy Sathyanarayanan).
      - Use ACPI_FALLTHROUGH (Wei Ming Chen).

   - Add preliminary support for the Platform Runtime Mechanism (PRM) to
     allow the AML interpreter to call PRM functions (Erik Kaneda).

   - Address some issues related to the handling of device dependencies
     reported by _DEP in the ACPI device enumeration code and clean up
     some related pieces of it (Rafael Wysocki).

   - Improve the tracking of states of ACPI power resources (Rafael
     Wysocki).

   - Improve ACPI support for suspend-to-idle on AMD systems (Alex
     Deucher, Mario Limonciello, Pratik Vishwakarma).

   - Continue the unification and cleanup of message printing in the
     ACPI code (Hanjun Guo, Heiner Kallweit).

   - Fix possible buffer overrun issue with the description_show() sysfs
     attribute method (Krzysztof Wilczyński).

   - Improve the acpi_mask_gpe kernel command line parameter handling
     and clean up the core ACPI code related to sysfs (Andy Shevchenko,
     Baokun Li, Clayton Casciato).

   - Postpone bringing devices in the general ACPI PM domain to D0
     during resume from system-wide suspend until they are really needed
     (Dmitry Torokhov).

   - Make the ACPI processor driver fix up C-state latency if not
     ordered (Mario Limonciello).

   - Add support for identifying devices depening on the given one that
     are not its direct descendants with the help of _DEP (Daniel
     Scally).

   - Extend the checks related to ACPI IRQ overrides on x86 in order to
     avoid false-positives (Hui Wang).

   - Add battery DPTF participant for Intel SoCs (Sumeet Pawnikar).

   - Rearrange the ACPI fan driver and device power management code to
     use a common list of device IDs (Rafael Wysocki).

   - Fix clang CFI violation in the ACPI BGRT table parsing code and
     clean it up (Nathan Chancellor).

   - Add GPE-related quirks for some laptops to the EC driver (Chris
     Chiu, Zhang Rui).

   - Make the ACPI PPTT table parsing code populate the cache-id value
     if present in the firmware (James Morse).

   - Remove redundant clearing of context->ret.pointer from
     acpi_run_osc() (Hans de Goede).

   - Add missing acpi_put_table() in acpi_init_fpdt() (Jing Xiangfeng).

   - Make ACPI APEI handle ARM Processor Error CPER records like Memory
     Error ones to avoid user space task lockups (Xiaofei Tan).

   - Stop warning about disabled ACPI in APEI (Jon Hunter).

   - Fix fall-through warning for Clang in the SBSHC driver (Gustavo A.
     R. Silva).

   - Add custom DSDT file as Makefile prerequisite (Richard Fitzgerald).

   - Initialize local variable to avoid garbage being returned (Colin
     Ian King).

   - Simplify assorted pieces of code, address assorted coding style and
     documentation issues and comment typos (Baokun Li, Christophe
     JAILLET, Clayton Casciato, Liu Shixin, Shaokun Zhang, Wei Yongjun,
     Yang Li, Zhen Lei)"

* tag 'acpi-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (97 commits)
  ACPI: PM: postpone bringing devices to D0 unless we need them
  ACPI: tables: Add custom DSDT file as makefile prerequisite
  ACPI: bgrt: Use sysfs_emit
  ACPI: bgrt: Fix CFI violation
  ACPI: EC: trust DSDT GPE for certain HP laptop
  ACPI: scan: Simplify acpi_table_events_fn()
  ACPI: PM: Adjust behavior for field problems on AMD systems
  ACPI: PM: s2idle: Add support for new Microsoft UUID
  ACPI: PM: s2idle: Add support for multiple func mask
  ACPI: PM: s2idle: Refactor common code
  ACPI: PM: s2idle: Use correct revision id
  ACPI: sysfs: Remove tailing return statement in void function
  ACPI: sysfs: Use __ATTR_RO() and __ATTR_RW() macros
  ACPI: sysfs: Sort headers alphabetically
  ACPI: sysfs: Refactor param_get_trace_state() to drop dead code
  ACPI: sysfs: Unify pattern of memory allocations
  ACPI: sysfs: Allow bitmap list to be supplied to acpi_mask_gpe
  ACPI: sysfs: Make sparse happy about address space in use
  ACPI: scan: Fix race related to dropping dependencies
  ACPI: scan: Reorganize acpi_device_add()
  ...

2521 files changed:
.mailmap
Documentation/ABI/obsolete/sysfs-cpuidle
Documentation/ABI/removed/sysfs-kernel-uids
Documentation/ABI/stable/sysfs-bus-vmbus
Documentation/ABI/stable/sysfs-bus-xen-backend
Documentation/ABI/stable/sysfs-devices-system-cpu
Documentation/ABI/stable/sysfs-driver-dma-idxd
Documentation/ABI/stable/sysfs-driver-mlxreg-io
Documentation/ABI/testing/configfs-iio
Documentation/ABI/testing/configfs-most
Documentation/ABI/testing/configfs-usb-gadget
Documentation/ABI/testing/configfs-usb-gadget-uvc
Documentation/ABI/testing/debugfs-driver-genwqe
Documentation/ABI/testing/debugfs-driver-habanalabs
Documentation/ABI/testing/evm
Documentation/ABI/testing/sysfs-bus-fsi
Documentation/ABI/testing/sysfs-bus-iio
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-class-backlight
Documentation/ABI/testing/sysfs-class-backlight-adp5520 [deleted file]
Documentation/ABI/testing/sysfs-class-backlight-adp8860 [deleted file]
Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 [deleted file]
Documentation/ABI/testing/sysfs-class-led-driver-el15203000 [deleted file]
Documentation/ABI/testing/sysfs-class-led-trigger-pattern
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-driver-ufs
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/ABI/testing/sysfs-kernel-iommu_groups
Documentation/Makefile
Documentation/PCI/acpi-info.rst
Documentation/PCI/endpoint/pci-endpoint-cfs.rst
Documentation/PCI/pci.rst
Documentation/accounting/delay-accounting.rst
Documentation/admin-guide/cputopology.rst
Documentation/admin-guide/ext4.rst
Documentation/admin-guide/hw-vuln/core-scheduling.rst [new file with mode: 0644]
Documentation/admin-guide/hw-vuln/index.rst
Documentation/admin-guide/hw-vuln/special-register-buffer-data-sampling.rst
Documentation/admin-guide/kdump/kdump.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/media/bt8xx.rst
Documentation/admin-guide/media/bttv.rst
Documentation/admin-guide/media/index.rst
Documentation/admin-guide/media/ipu3.rst
Documentation/admin-guide/media/saa7134.rst
Documentation/admin-guide/pm/cpuidle.rst
Documentation/admin-guide/pm/intel_idle.rst
Documentation/admin-guide/pm/intel_pstate.rst
Documentation/admin-guide/pstore-blk.rst
Documentation/admin-guide/reporting-issues.rst
Documentation/admin-guide/sysctl/abi.rst
Documentation/admin-guide/sysctl/kernel.rst
Documentation/arm/marvell.rst
Documentation/arm64/booting.rst
Documentation/block/biodoc.rst
Documentation/block/blk-mq.rst
Documentation/block/stat.rst
Documentation/bpf/bpf_lsm.rst
Documentation/conf.py
Documentation/core-api/bus-virt-phys-mapping.rst
Documentation/core-api/dma-api.rst
Documentation/core-api/dma-isa-lpc.rst
Documentation/core-api/index.rst
Documentation/core-api/irq/irq-domain.rst
Documentation/core-api/printk-formats.rst
Documentation/dev-tools/checkpatch.rst
Documentation/dev-tools/kunit/api/index.rst
Documentation/dev-tools/kunit/faq.rst
Documentation/dev-tools/kunit/index.rst
Documentation/dev-tools/kunit/start.rst
Documentation/dev-tools/kunit/tips.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/dev-tools/testing-overview.rst
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt [deleted file]
Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/firmware/intel,ixp4xx-network-processing-engine.yaml
Documentation/devicetree/bindings/hwmon/lm75.yaml
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml
Documentation/devicetree/bindings/media/atmel,isc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/atmel-isc.txt [deleted file]
Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/mediatek-vcodec.txt
Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/microchip,xisc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
Documentation/devicetree/bindings/media/rc.yaml
Documentation/devicetree/bindings/media/renesas,csi2.yaml
Documentation/devicetree/bindings/media/renesas,isp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/renesas,vin.yaml
Documentation/devicetree/bindings/media/rockchip,vdec.yaml
Documentation/devicetree/bindings/media/rockchip-vpu.yaml
Documentation/devicetree/bindings/media/tango-ir.txt [deleted file]
Documentation/devicetree/bindings/mfd/mt6397.txt
Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
Documentation/devicetree/bindings/mmc/ingenic,mmc.yaml
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Documentation/devicetree/bindings/mmc/renesas,mmcif.txt [deleted file]
Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
Documentation/devicetree/bindings/mmc/sdhci-am654.yaml
Documentation/devicetree/bindings/regulator/max8893.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml
Documentation/devicetree/bindings/regulator/regulator.yaml
Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt [deleted file]
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
Documentation/devicetree/bindings/spi/spi-cadence.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-cadence.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/devicetree/bindings/spi/spi-rockchip.yaml
Documentation/devicetree/bindings/spi/spi-xilinx.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-xilinx.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/submitting-patches.rst
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/doc-guide/contributing.rst
Documentation/driver-api/acpi/linuxized-acpica.rst
Documentation/driver-api/gpio/using-gpio.rst
Documentation/driver-api/ioctl.rst
Documentation/driver-api/media/drivers/bttv-devel.rst
Documentation/driver-api/media/drivers/ccs/ccs-regs.asc
Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
Documentation/driver-api/media/drivers/zoran.rst
Documentation/driver-api/media/index.rst
Documentation/driver-api/pm/devices.rst
Documentation/driver-api/surface_aggregator/clients/index.rst
Documentation/driver-api/surface_aggregator/internal.rst
Documentation/driver-api/surface_aggregator/overview.rst
Documentation/driver-api/thermal/sysfs-api.rst
Documentation/driver-api/usb/dma.rst
Documentation/fault-injection/fault-injection.rst
Documentation/filesystems/dax.rst [new file with mode: 0644]
Documentation/filesystems/dax.txt [deleted file]
Documentation/filesystems/ext2.rst
Documentation/filesystems/ext4/blockgroup.rst
Documentation/filesystems/index.rst
Documentation/filesystems/path-lookup.rst
Documentation/firmware-guide/acpi/dsd/data-node-references.rst
Documentation/firmware-guide/acpi/dsd/graph.rst
Documentation/firmware-guide/acpi/enumeration.rst
Documentation/hwmon/adm1177.rst
Documentation/hwmon/dps920ab.rst [new file with mode: 0644]
Documentation/hwmon/index.rst
Documentation/hwmon/ir36021.rst
Documentation/hwmon/lm75.rst
Documentation/hwmon/ltc2992.rst
Documentation/hwmon/max31790.rst
Documentation/hwmon/mp2888.rst [new file with mode: 0644]
Documentation/hwmon/pim4328.rst [new file with mode: 0644]
Documentation/hwmon/pm6764tr.rst
Documentation/hwmon/pmbus-core.rst
Documentation/hwmon/pmbus.rst
Documentation/hwmon/sht4x.rst [new file with mode: 0644]
Documentation/hwmon/zl6100.rst
Documentation/i2c/instantiating-devices.rst
Documentation/i2c/old-module-parameters.rst
Documentation/i2c/smbus-protocol.rst
Documentation/input/joydev/joystick-api.rst
Documentation/kernel-hacking/hacking.rst
Documentation/locking/lockdep-design.rst
Documentation/networking/device_drivers/ethernet/intel/i40e.rst
Documentation/networking/device_drivers/ethernet/intel/iavf.rst
Documentation/networking/devlink/devlink-region.rst
Documentation/networking/devlink/devlink-trap.rst
Documentation/networking/packet_mmap.rst
Documentation/networking/tuntap.rst
Documentation/power/runtime_pm.rst
Documentation/process/submitting-patches.rst
Documentation/riscv/vm-layout.rst
Documentation/scheduler/sched-bwc.rst
Documentation/scheduler/sched-capacity.rst
Documentation/scheduler/sched-energy.rst
Documentation/scheduler/sched-nice-design.rst
Documentation/security/IMA-templates.rst
Documentation/security/landlock.rst
Documentation/spi/pxa2xx.rst
Documentation/trace/coresight/coresight-etm4x-reference.rst
Documentation/trace/coresight/coresight.rst
Documentation/trace/ftrace.rst
Documentation/trace/kprobes.rst
Documentation/translations/index.rst
Documentation/translations/it_IT/index.rst
Documentation/translations/it_IT/process/coding-style.rst
Documentation/translations/ja_JP/index.rst
Documentation/translations/ko_KR/index.rst
Documentation/translations/zh_CN/admin-guide/index.rst
Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/cachetlb.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/index.rst
Documentation/translations/zh_CN/core-api/kernel-api.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/kobject.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/local_ops.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/padata.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/printk-basics.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/printk-formats.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/symbol-namespaces.rst [new file with mode: 0644]
Documentation/translations/zh_CN/core-api/workqueue.rst [new file with mode: 0644]
Documentation/translations/zh_CN/dev-tools/index.rst
Documentation/translations/zh_CN/dev-tools/kasan.rst [new file with mode: 0644]
Documentation/translations/zh_CN/index.rst
Documentation/translations/zh_CN/maintainer/configure-git.rst [new file with mode: 0644]
Documentation/translations/zh_CN/maintainer/index.rst [new file with mode: 0644]
Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst [new file with mode: 0644]
Documentation/translations/zh_CN/maintainer/modifying-patches.rst [new file with mode: 0644]
Documentation/translations/zh_CN/maintainer/pull-requests.rst [new file with mode: 0644]
Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst [new file with mode: 0644]
Documentation/translations/zh_CN/parisc/debugging.rst [new file with mode: 0644]
Documentation/translations/zh_CN/parisc/index.rst [new file with mode: 0644]
Documentation/translations/zh_CN/parisc/registers.rst [new file with mode: 0644]
Documentation/translations/zh_CN/process/8.Conclusion.rst
Documentation/translations/zh_CN/process/coding-style.rst
Documentation/usb/ehci.rst
Documentation/usb/gadget_printer.rst
Documentation/userspace-api/ioctl/hdio.rst
Documentation/userspace-api/landlock.rst
Documentation/userspace-api/media/Makefile
Documentation/userspace-api/media/audio.h.rst.exceptions [deleted file]
Documentation/userspace-api/media/drivers/hantro.rst [new file with mode: 0644]
Documentation/userspace-api/media/drivers/index.rst
Documentation/userspace-api/media/dvb/dmx-fopen.rst
Documentation/userspace-api/media/dvb/dmx-fread.rst
Documentation/userspace-api/media/dvb/dmx-set-filter.rst
Documentation/userspace-api/media/dvb/headers.rst
Documentation/userspace-api/media/dvb/intro.rst
Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst
Documentation/userspace-api/media/fdl-appendix.rst
Documentation/userspace-api/media/glossary.rst
Documentation/userspace-api/media/index.rst
Documentation/userspace-api/media/v4l/biblio.rst
Documentation/userspace-api/media/v4l/dev-decoder.rst
Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
Documentation/userspace-api/media/v4l/pixfmt-compressed.rst
Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst
Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
Documentation/userspace-api/media/video.h.rst.exceptions [deleted file]
Documentation/userspace-api/media/videodev2.h.rst.exceptions
Documentation/userspace-api/seccomp_filter.rst
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/cpuid.rst
Documentation/virt/kvm/hypercalls.rst
Documentation/virt/kvm/locking.rst
Documentation/virt/kvm/mmu.rst
Documentation/virt/kvm/msr.rst
Documentation/virt/kvm/s390-pv-boot.rst
Documentation/virt/kvm/vcpu-requests.rst
Documentation/vm/slub.rst
Documentation/vm/zswap.rst
Documentation/x86/boot.rst
Documentation/x86/buslock.rst [new file with mode: 0644]
Documentation/x86/index.rst
Documentation/x86/mtrr.rst
Documentation/x86/x86_64/boot-options.rst
MAINTAINERS
Makefile
arch/alpha/configs/defconfig
arch/alpha/include/asm/atomic.h
arch/alpha/include/asm/cmpxchg.h
arch/alpha/include/asm/page.h
arch/alpha/kernel/process.c
arch/alpha/kernel/smp.c
arch/arc/include/asm/atomic.h
arch/arc/include/asm/cmpxchg.h
arch/arc/include/uapi/asm/sigcontext.h
arch/arc/kernel/kprobes.c
arch/arc/kernel/signal.c
arch/arc/kernel/smp.c
arch/arc/kernel/stacktrace.c
arch/arc/kernel/vmlinux.lds.S
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/configs/footbridge_defconfig
arch/arm/configs/pxa_defconfig
arch/arm/crypto/Makefile
arch/arm/crypto/poly1305-core.S_shipped [deleted file]
arch/arm/crypto/sha256-core.S_shipped [deleted file]
arch/arm/crypto/sha512-core.S_shipped [deleted file]
arch/arm/include/asm/atomic.h
arch/arm/include/asm/cmpxchg.h
arch/arm/include/asm/cpuidle.h
arch/arm/include/asm/sync_bitops.h
arch/arm/kernel/irq.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-zynq/Kconfig
arch/arm/probes/kprobes/core.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/crypto/Makefile
arch/arm64/crypto/poly1305-core.S_shipped [deleted file]
arch/arm64/crypto/sha256-core.S_shipped [deleted file]
arch/arm64/crypto/sha512-core.S_shipped [deleted file]
arch/arm64/include/asm/alternative-macros.h
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/asm-prototypes.h
arch/arm64/include/asm/asm_pointer_auth.h
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/atomic.h
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cpu.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cpuidle.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/exception.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/fpsimdmacros.h
arch/arm64/include/asm/insn-def.h [new file with mode: 0644]
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/kvm_mte.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_pgtable.h
arch/arm64/include/asm/linkage.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/module.lds.h
arch/arm64/include/asm/mte-def.h
arch/arm64/include/asm/mte-kasan.h
arch/arm64/include/asm/mte.h
arch/arm64/include/asm/page.h
arch/arm64/include/asm/patching.h [new file with mode: 0644]
arch/arm64/include/asm/perf_event.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/pointer_auth.h
arch/arm64/include/asm/preempt.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/scs.h
arch/arm64/include/asm/sdei.h
arch/arm64/include/asm/smp.h
arch/arm64/include/asm/stacktrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/tlb.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/acpi.c
arch/arm64/kernel/alternative.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/efi-entry.S
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/entry-fpsimd.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hibernate-asm.S
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/idle.c [new file with mode: 0644]
arch/arm64/kernel/idreg-override.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/jump_label.c
arch/arm64/kernel/kaslr.c
arch/arm64/kernel/kgdb.c
arch/arm64/kernel/machine_kexec.c
arch/arm64/kernel/mte.c
arch/arm64/kernel/patching.c [new file with mode: 0644]
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/probes/kprobes.c
arch/arm64/kernel/probes/simulate-insn.c
arch/arm64/kernel/probes/uprobes.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/sdei.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/smccc-call.S
arch/arm64/kernel/smp.c
arch/arm64/kernel/smp_spin_table.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/sys_compat.c
arch/arm64/kernel/traps.c
arch/arm64/kvm/Kconfig
arch/arm64/kvm/Makefile
arch/arm64/kvm/arch_timer.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/exception.c
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
arch/arm64/kvm/hyp/include/nvhe/gfp.h
arch/arm64/kvm/hyp/include/nvhe/mem_protect.h
arch/arm64/kvm/hyp/include/nvhe/memory.h
arch/arm64/kvm/hyp/include/nvhe/mm.h
arch/arm64/kvm/hyp/nvhe/cache.S
arch/arm64/kvm/hyp/nvhe/mem_protect.c
arch/arm64/kvm/hyp/nvhe/page_alloc.c
arch/arm64/kvm/hyp/nvhe/setup.c
arch/arm64/kvm/hyp/nvhe/tlb.c
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/hyp/reserved_mem.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-v2.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/kvm/vgic/vgic.c
arch/arm64/lib/Makefile
arch/arm64/lib/clear_user.S
arch/arm64/lib/insn.c [moved from arch/arm64/kernel/insn.c with 86% similarity]
arch/arm64/lib/kasan_sw_tags.S [new file with mode: 0644]
arch/arm64/lib/memchr.S
arch/arm64/lib/memcmp.S
arch/arm64/lib/memcpy.S
arch/arm64/lib/memmove.S [deleted file]
arch/arm64/lib/mte.S
arch/arm64/lib/strcmp.S
arch/arm64/lib/strlen.S
arch/arm64/lib/strncmp.S
arch/arm64/lib/uaccess_flushcache.c
arch/arm64/mm/cache.S
arch/arm64/mm/context.c
arch/arm64/mm/fault.c
arch/arm64/mm/flush.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/proc.S
arch/arm64/mm/ptdump.c
arch/arm64/net/bpf_jit_comp.c
arch/arm64/tools/cpucaps
arch/csky/include/asm/cmpxchg.h
arch/csky/kernel/asm-offsets.c
arch/csky/kernel/probes/kprobes.c
arch/csky/kernel/smp.c
arch/csky/kernel/stacktrace.c
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/atomic.h [deleted file]
arch/h8300/include/asm/cmpxchg.h [deleted file]
arch/h8300/kernel/asm-offsets.c
arch/h8300/kernel/process.c
arch/hexagon/include/asm/atomic.h
arch/hexagon/include/asm/cmpxchg.h
arch/hexagon/kernel/process.c
arch/ia64/include/asm/atomic.h
arch/ia64/include/asm/cmpxchg.h [new file with mode: 0644]
arch/ia64/include/asm/page.h
arch/ia64/include/uapi/asm/cmpxchg.h
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/process.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/smpboot.c
arch/m68k/Kconfig.machine
arch/m68k/Makefile
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/atomic.h
arch/m68k/include/asm/cmpxchg.h
arch/m68k/include/asm/mmu_context.h
arch/m68k/include/asm/page_no.h
arch/m68k/kernel/dma.c
arch/m68k/kernel/process.c
arch/m68k/mac/config.c
arch/m68k/q40/config.c
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/atomic.h [deleted file]
arch/microblaze/include/asm/cmpxchg.h [deleted file]
arch/microblaze/kernel/asm-offsets.c
arch/mips/include/asm/atomic.h
arch/mips/include/asm/cmpxchg.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/kvm_host.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/cmpxchg.c
arch/mips/kernel/kprobes.c
arch/mips/kernel/process.c
arch/mips/kernel/smp.c
arch/mips/kvm/Makefile
arch/mips/kvm/mips.c
arch/mips/lantiq/xway/dma.c
arch/mips/pci/pci-rt3883.c
arch/mips/pci/pci-xtalk-bridge.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip30/ip30-irq.c
arch/nds32/kernel/process.c
arch/nios2/include/asm/irq.h
arch/nios2/kernel/irq.c
arch/nios2/kernel/process.c
arch/openrisc/include/asm/atomic.h
arch/openrisc/include/asm/cmpxchg.h
arch/openrisc/kernel/asm-offsets.c
arch/openrisc/kernel/smp.c
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/cmpxchg.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/process.c
arch/parisc/kernel/smp.c
arch/powerpc/include/asm/asm-prototypes.h
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
arch/powerpc/include/asm/cmpxchg.h
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/jump_label.h
arch/powerpc/include/asm/kvm_asm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/qspinlock.h
arch/powerpc/include/asm/time.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/kprobes.c
arch/powerpc/kernel/mce.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/security.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_64_entry.S [new file with mode: 0644]
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_64_vio_hv.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_interrupts.S
arch/powerpc/kvm/book3s_hv_nested.c
arch/powerpc/kvm/book3s_hv_p9_entry.c [new file with mode: 0644]
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rm_xics.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_hv_uvmem.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_pr_papr.c
arch/powerpc/kvm/book3s_segment.S
arch/powerpc/kvm/book3s_xive.c
arch/powerpc/kvm/book3s_xive.h
arch/powerpc/kvm/book3s_xive_native.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/mm/book3s64/radix_tlb.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_context.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/pmu.c
arch/powerpc/platforms/embedded6xx/flipper-pic.c
arch/powerpc/platforms/powermac/Kconfig
arch/powerpc/platforms/powernv/idle.c
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/ps3/interrupt.c
arch/powerpc/platforms/pseries/ibmebus.c
arch/powerpc/sysdev/ehv_pic.c
arch/powerpc/sysdev/fsl_mpic_err.c
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/tsi108_pci.c
arch/powerpc/sysdev/xics/icp-hv.c
arch/powerpc/sysdev/xics/icp-opal.c
arch/powerpc/sysdev/xics/xics-common.c
arch/powerpc/sysdev/xive/Kconfig
arch/powerpc/xmon/xmon.c
arch/riscv/Kconfig.socs
arch/riscv/Makefile
arch/riscv/boot/dts/sifive/fu740-c000.dtsi
arch/riscv/include/asm/atomic.h
arch/riscv/include/asm/cmpxchg.h
arch/riscv/include/asm/pgtable.h
arch/riscv/kernel/probes/kprobes.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/stacktrace.c
arch/riscv/mm/kasan_init.c
arch/s390/include/asm/atomic.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/page.h
arch/s390/include/asm/preempt.h
arch/s390/include/asm/stacktrace.h
arch/s390/kernel/entry.S
arch/s390/kernel/kprobes.c
arch/s390/kernel/process.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/topology.c
arch/s390/kvm/Makefile
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/pv.c
arch/s390/mm/fault.c
arch/s390/tools/gen_facilities.c
arch/sh/include/asm/atomic-grb.h
arch/sh/include/asm/atomic-irq.h
arch/sh/include/asm/atomic-llsc.h
arch/sh/include/asm/atomic.h
arch/sh/include/asm/cmpxchg.h
arch/sh/kernel/kprobes.c
arch/sh/kernel/process_32.c
arch/sh/kernel/smp.c
arch/sparc/include/asm/atomic_32.h
arch/sparc/include/asm/atomic_64.h
arch/sparc/include/asm/cmpxchg_32.h
arch/sparc/include/asm/cmpxchg_64.h
arch/sparc/kernel/kprobes.c
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/smp_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/lib/atomic32.c
arch/sparc/lib/atomic_64.S
arch/um/kernel/process.c
arch/um/kernel/skas/syscall.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/.gitignore
arch/x86/boot/Makefile
arch/x86/boot/genimage.sh
arch/x86/boot/mtools.conf.in
arch/x86/crypto/curve25519-x86_64.c
arch/x86/entry/Makefile
arch/x86/entry/calling.h
arch/x86/entry/common.c
arch/x86/entry/entry_64.S
arch/x86/entry/syscall_32.c
arch/x86/entry/syscall_64.c
arch/x86/entry/syscall_x32.c
arch/x86/entry/syscalls/Makefile
arch/x86/entry/syscalls/syscallhdr.sh [deleted file]
arch/x86/entry/syscalls/syscalltbl.sh [deleted file]
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
arch/x86/events/rapl.c
arch/x86/hyperv/hv_init.c
arch/x86/include/asm/Kbuild
arch/x86/include/asm/asm.h
arch/x86/include/asm/atomic.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/crash.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/idtentry.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nops.h
arch/x86/include/asm/page.h
arch/x86/include/asm/page_64.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/preempt.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/sev-common.h
arch/x86/include/asm/sgx.h
arch/x86/include/asm/stackprotector.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/syscall.h
arch/x86/include/asm/syscall_wrapper.h
arch/x86/include/asm/unistd.h
arch/x86/include/uapi/asm/hwcap2.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/include/uapi/asm/svm.h
arch/x86/kernel/acpi/cstate.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_nb.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/hygon.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mce/amd.c
arch/x86/kernel/cpu/mce/apei.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/resctrl/internal.h
arch/x86/kernel/cpu/resctrl/pseudo_lock.c
arch/x86/kernel/cpu/sgx/encl.c
arch/x86/kernel/cpu/sgx/virt.c
arch/x86/kernel/cpu/tsx.c
arch/x86/kernel/crash.c
arch/x86/kernel/fpu/signal.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/head_64.S
arch/x86/kernel/idt.c
arch/x86/kernel/jump_label.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/process.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/sev.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/umip.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/cpuid.c
arch/x86/kvm/debugfs.c
arch/x86/kvm/emulate.c
arch/x86/kvm/fpu.h [new file with mode: 0644]
arch/x86/kvm/hyperv.c
arch/x86/kvm/hyperv.h
arch/x86/kvm/kvm_cache_regs.h
arch/x86/kvm/kvm_emulate.h
arch/x86/kvm/kvm_onhyperv.c [new file with mode: 0644]
arch/x86/kvm/kvm_onhyperv.h [new file with mode: 0644]
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.h
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/mmu_internal.h
arch/x86/kvm/mmu/mmutrace.h
arch/x86/kvm/mmu/page_track.c
arch/x86/kvm/mmu/paging_tmpl.h
arch/x86/kvm/mmu/spte.c
arch/x86/kvm/mmu/spte.h
arch/x86/kvm/mmu/tdp_mmu.c
arch/x86/kvm/mmu/tdp_mmu.h
arch/x86/kvm/svm/avic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/svm/svm_onhyperv.c [new file with mode: 0644]
arch/x86/kvm/svm/svm_onhyperv.h [new file with mode: 0644]
arch/x86/kvm/trace.h
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/evmcs.c
arch/x86/kvm/vmx/evmcs.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/nested.h
arch/x86/kvm/vmx/vmcs.h
arch/x86/kvm/vmx/vmcs12.c
arch/x86/kvm/vmx/vmcs12.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lib/insn-eval.c
arch/x86/lib/retpoline.S
arch/x86/mm/fault.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa.c
arch/x86/mm/pkeys.c
arch/x86/mm/tlb.c
arch/x86/pci/fixup.c
arch/x86/platform/efi/efi.c
arch/x86/realmode/Makefile
arch/x86/um/sys_call_table_32.c
arch/x86/um/sys_call_table_64.c
arch/x86/xen/enlighten_pv.c
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/kernel/process.c
arch/xtensa/kernel/smp.c
block/blk-mq.c
crypto/af_alg.c
crypto/algapi.c
crypto/algboss.c
crypto/drbg.c
crypto/ecdh.c
crypto/internal.h
crypto/khazad.c
crypto/shash.c
crypto/sm2.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
crypto/wp512.c
drivers/Kconfig
drivers/Makefile
drivers/accessibility/braille/braille_console.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_sunxi.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_cypress.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_falcon.c
drivers/ata/pata_macio.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_rb532_cf.c
drivers/ata/pata_sc1200.c
drivers/ata/pata_serverworks.c
drivers/ata/sata_fsl.c
drivers/ata/sata_highbank.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_sil24.c
drivers/atm/fore200e.c
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/base/power/runtime.c
drivers/base/power/wakeirq.c
drivers/base/regmap/Kconfig
drivers/base/regmap/Makefile
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-mdio.c [new file with mode: 0644]
drivers/base/regmap/regmap.c
drivers/base/swnode.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/amd-rng.c
drivers/char/hw_random/core.c
drivers/char/hw_random/exynos-trng.c
drivers/char/hw_random/ks-sa-rng.c
drivers/char/hw_random/omap-rng.c
drivers/clocksource/Kconfig
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/arm_global_timer.c
drivers/clocksource/ingenic-sysost.c
drivers/clocksource/samsung_pwm_timer.c
drivers/clocksource/timer-mediatek.c
drivers/clocksource/timer-ti-dm.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/sh-cpufreq.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/governors/teo.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/cavium/cpt/cptpf_main.c
drivers/crypto/cavium/cpt/cptvf_reqmanager.c
drivers/crypto/cavium/nitrox/nitrox_isr.c
drivers/crypto/cavium/nitrox/nitrox_main.c
drivers/crypto/cavium/nitrox/nitrox_mbx.c
drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
drivers/crypto/cavium/nitrox/nitrox_skcipher.c
drivers/crypto/ccp/ccp-dev.c
drivers/crypto/ccp/ccp-dmaengine.c
drivers/crypto/ccp/sev-dev.c
drivers/crypto/ccp/sp-pci.c
drivers/crypto/gemini/Makefile [new file with mode: 0644]
drivers/crypto/gemini/sl3516-ce-cipher.c [new file with mode: 0644]
drivers/crypto/gemini/sl3516-ce-core.c [new file with mode: 0644]
drivers/crypto/gemini/sl3516-ce-rng.c [new file with mode: 0644]
drivers/crypto/gemini/sl3516-ce.h [new file with mode: 0644]
drivers/crypto/hisilicon/hpre/hpre_crypto.c
drivers/crypto/hisilicon/hpre/hpre_main.c
drivers/crypto/hisilicon/qm.c
drivers/crypto/hisilicon/qm.h
drivers/crypto/hisilicon/sec2/sec.h
drivers/crypto/hisilicon/sec2/sec_crypto.c
drivers/crypto/hisilicon/sec2/sec_crypto.h
drivers/crypto/hisilicon/sec2/sec_main.c
drivers/crypto/hisilicon/zip/zip_main.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/marvell/cesa/cesa.h
drivers/crypto/marvell/octeontx2/Makefile
drivers/crypto/marvell/octeontx2/cn10k_cpt.c [new file with mode: 0644]
drivers/crypto/marvell/octeontx2/cn10k_cpt.h [new file with mode: 0644]
drivers/crypto/marvell/octeontx2/otx2_cpt_common.h
drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
drivers/crypto/marvell/octeontx2/otx2_cptlf.c
drivers/crypto/marvell/octeontx2/otx2_cptlf.h
drivers/crypto/marvell/octeontx2/otx2_cptpf.h
drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h
drivers/crypto/marvell/octeontx2/otx2_cptvf.h
drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c
drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c
drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
drivers/crypto/nx/nx-842-pseries.c
drivers/crypto/nx/nx-aes-cbc.c
drivers/crypto/nx/nx-aes-ccm.c
drivers/crypto/nx/nx-aes-ctr.c
drivers/crypto/nx/nx-aes-ecb.c
drivers/crypto/nx/nx-aes-gcm.c
drivers/crypto/nx/nx-common-powernv.c
drivers/crypto/nx/nx-sha256.c
drivers/crypto/nx/nx-sha512.c
drivers/crypto/nx/nx_csbcpb.h
drivers/crypto/omap-des.c
drivers/crypto/omap-sham.c
drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h
drivers/crypto/qat/qat_common/qat_hal.c
drivers/crypto/qat/qat_common/qat_uclo.c
drivers/crypto/qce/Makefile
drivers/crypto/qce/aead.c [new file with mode: 0644]
drivers/crypto/qce/aead.h [new file with mode: 0644]
drivers/crypto/qce/common.c
drivers/crypto/qce/common.h
drivers/crypto/qce/core.c
drivers/crypto/qce/skcipher.c
drivers/crypto/sa2ul.c
drivers/crypto/ux500/hash/hash_core.c
drivers/devfreq/Kconfig
drivers/devfreq/devfreq.c
drivers/devfreq/governor_passive.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/imx-bus.c
drivers/devfreq/tegra30-devfreq.c
drivers/dma/Kconfig
drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c
drivers/dma/idxd/cdev.c
drivers/dma/idxd/init.c
drivers/dma/ipu/ipu_irq.c
drivers/dma/mediatek/mtk-uart-apdma.c
drivers/dma/pl330.c
drivers/dma/qcom/Kconfig
drivers/dma/sf-pdma/Kconfig
drivers/dma/sh/rcar-dmac.c
drivers/dma/ste_dma40.c
drivers/dma/stm32-mdma.c
drivers/dma/xilinx/xilinx_dpdma.c
drivers/dma/xilinx/zynqmp_dma.c
drivers/edac/mce_amd.c
drivers/firewire/core-topology.c
drivers/firmware/efi/apple-properties.c
drivers/firmware/efi/dev-path-parser.c
drivers/firmware/psci/psci.c
drivers/firmware/smccc/smccc.c
drivers/gpio/Kconfig
drivers/gpio/gpio-mxc.c
drivers/gpio/gpiolib-cdev.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/kmb/kmb_drv.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_prime.c
drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
drivers/gpu/drm/panel/panel-samsung-ld9040.c
drivers/gpu/drm/radeon/radeon_prime.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/hv/Makefile
drivers/hv/channel.c
drivers/hv/connection.c
drivers/hv/hv_balloon.c
drivers/hv/hv_common.c [new file with mode: 0644]
drivers/hv/hv_fcopy.c
drivers/hv/hv_kvp.c
drivers/hv/hv_util.c
drivers/hv/hyperv_vmbus.h
drivers/hv/ring_buffer.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/bt1-pvt.c
drivers/hwmon/corsair-cpro.c
drivers/hwmon/hwmon.c
drivers/hwmon/ina3221.c
drivers/hwmon/lm70.c
drivers/hwmon/lm75.c
drivers/hwmon/lm90.c
drivers/hwmon/max31722.c
drivers/hwmon/max31790.c
drivers/hwmon/max6621.c
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/adm1275.c
drivers/hwmon/pmbus/bpa-rs600.c
drivers/hwmon/pmbus/dps920ab.c [new file with mode: 0644]
drivers/hwmon/pmbus/mp2888.c [new file with mode: 0644]
drivers/hwmon/pmbus/pim4328.c [new file with mode: 0644]
drivers/hwmon/pmbus/pmbus.c
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/pmbus/zl6100.c
drivers/hwmon/sch5627.c
drivers/hwmon/sch5636.c
drivers/hwmon/sch56xx-common.c
drivers/hwmon/sch56xx-common.h
drivers/hwmon/sht4x.c [new file with mode: 0644]
drivers/i2c/busses/i2c-cp2615.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-robotfuzz-osif.c
drivers/i2c/i2c-dev.c
drivers/ide/Kconfig [deleted file]
drivers/ide/Makefile [deleted file]
drivers/ide/aec62xx.c [deleted file]
drivers/ide/ali14xx.c [deleted file]
drivers/ide/alim15x3.c [deleted file]
drivers/ide/amd74xx.c [deleted file]
drivers/ide/atiixp.c [deleted file]
drivers/ide/buddha.c [deleted file]
drivers/ide/cmd640.c [deleted file]
drivers/ide/cmd64x.c [deleted file]
drivers/ide/cs5520.c [deleted file]
drivers/ide/cs5530.c [deleted file]
drivers/ide/cs5535.c [deleted file]
drivers/ide/cs5536.c [deleted file]
drivers/ide/cy82c693.c [deleted file]
drivers/ide/delkin_cb.c [deleted file]
drivers/ide/dtc2278.c [deleted file]
drivers/ide/falconide.c [deleted file]
drivers/ide/gayle.c [deleted file]
drivers/ide/hpt366.c [deleted file]
drivers/ide/ht6560b.c [deleted file]
drivers/ide/icside.c [deleted file]
drivers/ide/ide-4drives.c [deleted file]
drivers/ide/ide-acpi.c [deleted file]
drivers/ide/ide-atapi.c [deleted file]
drivers/ide/ide-cd.c [deleted file]
drivers/ide/ide-cd.h [deleted file]
drivers/ide/ide-cd_ioctl.c [deleted file]
drivers/ide/ide-cd_verbose.c [deleted file]
drivers/ide/ide-cs.c [deleted file]
drivers/ide/ide-devsets.c [deleted file]
drivers/ide/ide-disk.c [deleted file]
drivers/ide/ide-disk.h [deleted file]
drivers/ide/ide-disk_ioctl.c [deleted file]
drivers/ide/ide-disk_proc.c [deleted file]
drivers/ide/ide-dma-sff.c [deleted file]
drivers/ide/ide-dma.c [deleted file]
drivers/ide/ide-eh.c [deleted file]
drivers/ide/ide-floppy.c [deleted file]
drivers/ide/ide-floppy.h [deleted file]
drivers/ide/ide-floppy_ioctl.c [deleted file]
drivers/ide/ide-floppy_proc.c [deleted file]
drivers/ide/ide-gd.c [deleted file]
drivers/ide/ide-gd.h [deleted file]
drivers/ide/ide-generic.c [deleted file]
drivers/ide/ide-io-std.c [deleted file]
drivers/ide/ide-io.c [deleted file]
drivers/ide/ide-ioctls.c [deleted file]
drivers/ide/ide-iops.c [deleted file]
drivers/ide/ide-legacy.c [deleted file]
drivers/ide/ide-lib.c [deleted file]
drivers/ide/ide-park.c [deleted file]
drivers/ide/ide-pci-generic.c [deleted file]
drivers/ide/ide-pio-blacklist.c [deleted file]
drivers/ide/ide-pm.c [deleted file]
drivers/ide/ide-pnp.c [deleted file]
drivers/ide/ide-probe.c [deleted file]
drivers/ide/ide-proc.c [deleted file]
drivers/ide/ide-scan-pci.c [deleted file]
drivers/ide/ide-sysfs.c [deleted file]
drivers/ide/ide-tape.c [deleted file]
drivers/ide/ide-taskfile.c [deleted file]
drivers/ide/ide-timings.c [deleted file]
drivers/ide/ide-xfer-mode.c [deleted file]
drivers/ide/ide.c [deleted file]
drivers/ide/ide_platform.c [deleted file]
drivers/ide/it8172.c [deleted file]
drivers/ide/it8213.c [deleted file]
drivers/ide/it821x.c [deleted file]
drivers/ide/jmicron.c [deleted file]
drivers/ide/macide.c [deleted file]
drivers/ide/ns87415.c [deleted file]
drivers/ide/opti621.c [deleted file]
drivers/ide/palm_bk3710.c [deleted file]
drivers/ide/pdc202xx_new.c [deleted file]
drivers/ide/pdc202xx_old.c [deleted file]
drivers/ide/piix.c [deleted file]
drivers/ide/pmac.c [deleted file]
drivers/ide/q40ide.c [deleted file]
drivers/ide/qd65xx.c [deleted file]
drivers/ide/qd65xx.h [deleted file]
drivers/ide/rapide.c [deleted file]
drivers/ide/rz1000.c [deleted file]
drivers/ide/sc1200.c [deleted file]
drivers/ide/serverworks.c [deleted file]
drivers/ide/setup-pci.c [deleted file]
drivers/ide/siimage.c [deleted file]
drivers/ide/sis5513.c [deleted file]
drivers/ide/sl82c105.c [deleted file]
drivers/ide/slc90e66.c [deleted file]
drivers/ide/tc86c001.c [deleted file]
drivers/ide/triflex.c [deleted file]
drivers/ide/trm290.c [deleted file]
drivers/ide/tx4938ide.c [deleted file]
drivers/ide/tx4939ide.c [deleted file]
drivers/ide/umc8672.c [deleted file]
drivers/ide/via82cxxx.c [deleted file]
drivers/idle/intel_idle.c
drivers/input/keyboard/Kconfig
drivers/irqchip/Kconfig
drivers/irqchip/exynos-combiner.c
drivers/irqchip/irq-al-fic.c
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-aspeed-i2c-ic.c
drivers/irqchip/irq-aspeed-scu-ic.c
drivers/irqchip/irq-ath79-misc.c
drivers/irqchip/irq-bcm2835.c
drivers/irqchip/irq-bcm2836.c
drivers/irqchip/irq-bcm7038-l1.c
drivers/irqchip/irq-bcm7120-l2.c
drivers/irqchip/irq-brcmstb-l2.c
drivers/irqchip/irq-dw-apb-ictl.c
drivers/irqchip/irq-gic-common.c
drivers/irqchip/irq-gic-common.h
drivers/irqchip/irq-gic-pm.c
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-goldfish-pic.c
drivers/irqchip/irq-i8259.c
drivers/irqchip/irq-idt3243x.c
drivers/irqchip/irq-imgpdc.c
drivers/irqchip/irq-imx-gpcv2.c
drivers/irqchip/irq-imx-intmux.c
drivers/irqchip/irq-imx-irqsteer.c
drivers/irqchip/irq-ingenic-tcu.c
drivers/irqchip/irq-ingenic.c
drivers/irqchip/irq-keystone.c
drivers/irqchip/irq-loongson-htpic.c
drivers/irqchip/irq-loongson-htvec.c
drivers/irqchip/irq-loongson-liointc.c
drivers/irqchip/irq-lpc32xx.c
drivers/irqchip/irq-ls-scfg-msi.c
drivers/irqchip/irq-ls1x.c
drivers/irqchip/irq-mbigen.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-mscc-ocelot.c
drivers/irqchip/irq-mvebu-pic.c
drivers/irqchip/irq-mvebu-sei.c
drivers/irqchip/irq-nvic.c
drivers/irqchip/irq-orion.c
drivers/irqchip/irq-partition-percpu.c
drivers/irqchip/irq-pruss-intc.c
drivers/irqchip/irq-realtek-rtl.c
drivers/irqchip/irq-renesas-irqc.c
drivers/irqchip/irq-sifive-plic.c
drivers/irqchip/irq-stm32-exti.c
drivers/irqchip/irq-sun4i.c
drivers/irqchip/irq-sunxi-nmi.c
drivers/irqchip/irq-tb10x.c
drivers/irqchip/irq-ti-sci-inta.c
drivers/irqchip/irq-ts4800.c
drivers/irqchip/irq-versatile-fpga.c
drivers/irqchip/irq-vic.c
drivers/irqchip/irq-xilinx-intc.c
drivers/irqchip/qcom-irq-combiner.c
drivers/irqchip/qcom-pdc.c
drivers/md/dm.c
drivers/media/cec/platform/s5p/s5p_cec.c
drivers/media/common/Kconfig
drivers/media/common/Makefile
drivers/media/common/siano/smscoreapi.c
drivers/media/common/siano/smscoreapi.h
drivers/media/common/siano/smsdvb-main.c
drivers/media/common/ttpci-eeprom.c [moved from drivers/media/pci/ttpci/ttpci-eeprom.c with 100% similarity]
drivers/media/common/ttpci-eeprom.h [moved from drivers/media/pci/ttpci/ttpci-eeprom.h with 100% similarity]
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb_ca_en50221.c
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_net.c
drivers/media/dvb-core/dvbdev.c
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/drx39xyj/drxj.h
drivers/media/dvb-frontends/mxl692.c
drivers/media/dvb-frontends/rtl2832_sdr.c
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/adv7170.c
drivers/media/i2c/adv7175.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7183.c
drivers/media/i2c/adv748x/adv748x-afe.c
drivers/media/i2c/adv748x/adv748x-csi2.c
drivers/media/i2c/adv748x/adv748x-hdmi.c
drivers/media/i2c/adv7511-v4l2.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/ak7375.c
drivers/media/i2c/ak881x.c
drivers/media/i2c/ccs/ccs-core.c
drivers/media/i2c/ccs/ccs-limits.c
drivers/media/i2c/ccs/ccs-limits.h
drivers/media/i2c/ccs/ccs-regs.h
drivers/media/i2c/cx25840/cx25840-core.c
drivers/media/i2c/dw9714.c
drivers/media/i2c/dw9768.c
drivers/media/i2c/dw9807-vcm.c
drivers/media/i2c/et8ek8/et8ek8_driver.c
drivers/media/i2c/hi556.c
drivers/media/i2c/imx208.c [new file with mode: 0644]
drivers/media/i2c/imx214.c
drivers/media/i2c/imx219.c
drivers/media/i2c/imx258.c
drivers/media/i2c/imx274.c
drivers/media/i2c/imx290.c
drivers/media/i2c/imx319.c
drivers/media/i2c/imx334.c
drivers/media/i2c/imx355.c
drivers/media/i2c/ir-kbd-i2c.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/i2c/max9271.c
drivers/media/i2c/max9271.h
drivers/media/i2c/max9286.c
drivers/media/i2c/ml86v7667.c
drivers/media/i2c/mt9m001.c
drivers/media/i2c/mt9m032.c
drivers/media/i2c/mt9m111.c
drivers/media/i2c/mt9p031.c
drivers/media/i2c/mt9t001.c
drivers/media/i2c/mt9t112.c
drivers/media/i2c/mt9v011.c
drivers/media/i2c/mt9v032.c
drivers/media/i2c/mt9v111.c
drivers/media/i2c/noon010pc30.c
drivers/media/i2c/ov02a10.c
drivers/media/i2c/ov13858.c
drivers/media/i2c/ov2640.c
drivers/media/i2c/ov2659.c
drivers/media/i2c/ov2680.c
drivers/media/i2c/ov2685.c
drivers/media/i2c/ov2740.c
drivers/media/i2c/ov5640.c
drivers/media/i2c/ov5645.c
drivers/media/i2c/ov5647.c
drivers/media/i2c/ov5648.c
drivers/media/i2c/ov5670.c
drivers/media/i2c/ov5675.c
drivers/media/i2c/ov5695.c
drivers/media/i2c/ov6650.c
drivers/media/i2c/ov7251.c
drivers/media/i2c/ov7670.c
drivers/media/i2c/ov772x.c
drivers/media/i2c/ov7740.c
drivers/media/i2c/ov8856.c
drivers/media/i2c/ov8865.c
drivers/media/i2c/ov9640.c
drivers/media/i2c/ov9650.c
drivers/media/i2c/ov9734.c
drivers/media/i2c/rdacm20.c
drivers/media/i2c/rdacm21.c
drivers/media/i2c/rj54n1cb0c.c
drivers/media/i2c/s5c73m3/s5c73m3-core.c
drivers/media/i2c/s5c73m3/s5c73m3.h
drivers/media/i2c/s5k4ecgx.c
drivers/media/i2c/s5k5baf.c
drivers/media/i2c/s5k6a3.c
drivers/media/i2c/s5k6aa.c
drivers/media/i2c/saa6588.c
drivers/media/i2c/saa6752hs.c
drivers/media/i2c/saa7115.c
drivers/media/i2c/saa717x.c
drivers/media/i2c/sr030pc30.c
drivers/media/i2c/st-mipid02.c
drivers/media/i2c/tc358743.c
drivers/media/i2c/tda1997x.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp5150.c
drivers/media/i2c/tvp7002.c
drivers/media/i2c/tw9910.c
drivers/media/i2c/video-i2c.c
drivers/media/i2c/vs6624.c
drivers/media/mc/Makefile
drivers/media/mc/mc-entity.c
drivers/media/mc/mc-request.c
drivers/media/pci/bt8xx/bt878.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/cobalt/cobalt-driver.c
drivers/media/pci/cobalt/cobalt-driver.h
drivers/media/pci/cx18/cx18-av-core.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/cx88/cx88-blackbird.c
drivers/media/pci/cx88/cx88-core.c
drivers/media/pci/cx88/cx88-dvb.c
drivers/media/pci/cx88/cx88-mpeg.c
drivers/media/pci/cx88/cx88-vbi.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/intel/ipu3/cio2-bridge.c
drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
drivers/media/pci/ivtv/Kconfig
drivers/media/pci/ivtv/ivtv-driver.h
drivers/media/pci/ivtv/ivtv-ioctl.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-empress.c
drivers/media/pci/saa7134/saa7134-tvaudio.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/ttpci/Kconfig
drivers/media/pci/ttpci/Makefile
drivers/media/pci/ttpci/budget-core.c
drivers/media/pci/ttpci/budget.h
drivers/media/pci/tw5864/tw5864-reg.h
drivers/media/platform/Makefile
drivers/media/platform/allegro-dvt/nal-h264.c
drivers/media/platform/allegro-dvt/nal-hevc.c
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/atmel/Kconfig
drivers/media/platform/atmel/Makefile
drivers/media/platform/atmel/atmel-isc-base.c
drivers/media/platform/atmel/atmel-isc-regs.h
drivers/media/platform/atmel/atmel-isc.h
drivers/media/platform/atmel/atmel-isi.c
drivers/media/platform/atmel/atmel-sama5d2-isc.c
drivers/media/platform/atmel/atmel-sama7g5-isc.c [new file with mode: 0644]
drivers/media/platform/cadence/cdns-csi2rx.c
drivers/media/platform/cadence/cdns-csi2tx.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpbe_venc.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/fimc-isp.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/imx-jpeg/mxc-jpeg.c
drivers/media/platform/imx-jpeg/mxc-jpeg.h
drivers/media/platform/marvell-ccic/cafe-driver.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
drivers/media/platform/mtk-vpu/mtk_vpu.c
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispccp2.c
drivers/media/platform/omap3isp/ispcsi2.c
drivers/media/platform/omap3isp/isppreview.c
drivers/media/platform/omap3isp/ispresizer.c
drivers/media/platform/pxa_camera.c
drivers/media/platform/qcom/camss/camss-csid.c
drivers/media/platform/qcom/camss/camss-csiphy.c
drivers/media/platform/qcom/camss/camss-ispif.c
drivers/media/platform/qcom/camss/camss-vfe.c
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/helpers.c
drivers/media/platform/qcom/venus/hfi_cmds.c
drivers/media/platform/qcom/venus/hfi_cmds.h
drivers/media/platform/qcom/venus/hfi_helper.h
drivers/media/platform/qcom/venus/hfi_msgs.c
drivers/media/platform/qcom/venus/hfi_msgs.h
drivers/media/platform/qcom/venus/hfi_platform.c
drivers/media/platform/qcom/venus/hfi_platform.h
drivers/media/platform/qcom/venus/hfi_platform_v4.c
drivers/media/platform/qcom/venus/hfi_platform_v6.c
drivers/media/platform/qcom/venus/pm_helpers.c
drivers/media/platform/qcom/venus/vdec.c
drivers/media/platform/qcom/venus/venc.c
drivers/media/platform/rcar-fcp.c
drivers/media/platform/rcar-vin/rcar-core.c
drivers/media/platform/rcar-vin/rcar-csi2.c
drivers/media/platform/rcar-vin/rcar-dma.c
drivers/media/platform/rcar-vin/rcar-v4l2.c
drivers/media/platform/rcar_fdp1.c
drivers/media/platform/rcar_jpu.c
drivers/media/platform/renesas-ceu.c
drivers/media/platform/rockchip/rga/rga-buf.c
drivers/media/platform/rockchip/rga/rga.c
drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s3c-camif/camif-core.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
drivers/media/platform/sh_vou.c
drivers/media/platform/sti/bdisp/Makefile
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
drivers/media/platform/sti/delta/Makefile
drivers/media/platform/sti/delta/delta-v4l2.c
drivers/media/platform/sti/hva/Makefile
drivers/media/platform/sti/hva/hva-hw.c
drivers/media/platform/stm32/stm32-dcmi.c
drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
drivers/media/platform/ti-vpe/cal-camerarx.c
drivers/media/platform/ti-vpe/cal-video.c
drivers/media/platform/ti-vpe/cal.c
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/via-camera.c
drivers/media/platform/video-mux.c
drivers/media/platform/vsp1/vsp1_brx.c
drivers/media/platform/vsp1/vsp1_clu.c
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_entity.c
drivers/media/platform/vsp1/vsp1_entity.h
drivers/media/platform/vsp1/vsp1_histo.c
drivers/media/platform/vsp1/vsp1_hsit.c
drivers/media/platform/vsp1/vsp1_lif.c
drivers/media/platform/vsp1/vsp1_lut.c
drivers/media/platform/vsp1/vsp1_rwpf.c
drivers/media/platform/vsp1/vsp1_rwpf.h
drivers/media/platform/vsp1/vsp1_sru.c
drivers/media/platform/vsp1/vsp1_uds.c
drivers/media/platform/vsp1/vsp1_uif.c
drivers/media/platform/xilinx/xilinx-csi2rxss.c
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-tpg.c
drivers/media/platform/xilinx/xilinx-vip.c
drivers/media/platform/xilinx/xilinx-vip.h
drivers/media/radio/si4713/radio-platform-si4713.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/imon.c
drivers/media/rc/ite-cir.h
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-ct-90405.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-tango.c [deleted file]
drivers/media/rc/st_rc.c
drivers/media/rc/tango-ir.c [deleted file]
drivers/media/spi/cxd2880-spi.c
drivers/media/test-drivers/vim2m.c
drivers/media/test-drivers/vimc/vimc-debayer.c
drivers/media/test-drivers/vimc/vimc-scaler.c
drivers/media/test-drivers/vimc/vimc-sensor.c
drivers/media/test-drivers/vivid/vivid-core.c
drivers/media/test-drivers/vivid/vivid-core.h
drivers/media/test-drivers/vivid/vivid-kthread-cap.c
drivers/media/test-drivers/vivid/vivid-sdr-cap.c
drivers/media/test-drivers/vivid/vivid-vbi-cap.c
drivers/media/usb/Kconfig
drivers/media/usb/airspy/airspy.c
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/cpia2/cpia2.h
drivers/media/usb/cpia2/cpia2_core.c
drivers/media/usb/cpia2/cpia2_usb.c
drivers/media/usb/cpia2/cpia2_v4l.c
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb/Makefile
drivers/media/usb/dvb-usb/cinergyT2-core.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dtv5100.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/go7007/s2250-board.c
drivers/media/usb/gspca/cpia1.c
drivers/media/usb/gspca/gl860/gl860.c
drivers/media/usb/gspca/ov519.c
drivers/media/usb/gspca/sq905.c
drivers/media/usb/gspca/sunplus.c
drivers/media/usb/hackrf/hackrf.c
drivers/media/usb/msi2500/msi2500.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/ttusb-dec/ttusb_dec.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/zr364xx/zr364xx.c
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/Makefile
drivers/media/v4l2-core/v4l2-async.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ctrls-api.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-ctrls-core.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-ctrls-defs.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-ctrls-priv.h [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-ctrls-request.c [new file with mode: 0644]
drivers/media/v4l2-core/v4l2-ctrls.c [deleted file]
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-event.c
drivers/media/v4l2-core/v4l2-fh.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-subdev.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/memstick/core/ms_block.c
drivers/memstick/host/rtsx_usb_ms.c
drivers/mfd/ioc3.c
drivers/mfd/mt6358-irq.c
drivers/mfd/mt6397-core.c
drivers/misc/lkdtm/bugs.c
drivers/mmc/core/block.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/sd.c
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/cqhci-core.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/of_mmc_spi.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/sdhci-of-aspeed.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-gli.c
drivers/mmc/host/sdhci-sprd.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdhci_am654.c
drivers/mmc/host/usdhi6rol0.c
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/vub300.c
drivers/mtd/mtdpstore.c
drivers/mtd/nand/spi/core.c
drivers/net/caif/caif_serial.c
drivers/net/can/usb/mcba_usb.c
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/ec_bhf.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/lantiq_xrx200.c
drivers/net/ethernet/mellanox/mlx5/core/dev.c
drivers/net/ethernet/mellanox/mlx5/core/en/devlink.c
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
drivers/net/ethernet/mellanox/mlx5/core/en_arfs.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/en_tc.h
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/mr.c
drivers/net/ethernet/mellanox/mlx5/core/rdma.c
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c
drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
drivers/net/ethernet/mellanox/mlx5/core/transobj.c
drivers/net/ethernet/mellanox/mlx5/core/vport.c
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/neterion/vxge/vxge-config.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qed/qed_dcbx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/hamradio/mkiss.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/rndis_filter.c
drivers/net/mhi/net.c
drivers/net/phy/dp83867.c
drivers/net/usb/cdc_eem.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/usb/smsc75xx.c
drivers/net/vrf.c
drivers/net/wireless/mac80211_hwsim.c
drivers/opp/core.c
drivers/opp/of.c
drivers/pci/controller/dwc/Makefile
drivers/pci/controller/dwc/pcie-tegra194-acpi.c [new file with mode: 0644]
drivers/pci/controller/dwc/pcie-tegra194.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/of.c
drivers/pci/pci.c
drivers/pci/quirks.c
drivers/perf/arm-cci.c
drivers/perf/arm-ccn.c
drivers/perf/arm-cmn.c
drivers/perf/arm_dmc620_pmu.c
drivers/perf/arm_dsu_pmu.c
drivers/perf/arm_pmu.c
drivers/perf/arm_smmuv3_pmu.c
drivers/perf/arm_spe_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/hisilicon/hisi_uncore_pa_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.h
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
drivers/perf/qcom_l2_pmu.c
drivers/perf/qcom_l3_pmu.c
drivers/perf/thunderx2_pmu.c
drivers/perf/xgene_pmu.c
drivers/pinctrl/pinctrl-microchip-sgpio.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/ptp/ptp_clock.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/bd70528-regulator.c [deleted file]
drivers/regulator/bd71815-regulator.c
drivers/regulator/bd9576-regulator.c
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/devres.c
drivers/regulator/fan53555.c
drivers/regulator/fan53880.c
drivers/regulator/fixed.c
drivers/regulator/hi6421-regulator.c
drivers/regulator/hi6421v600-regulator.c
drivers/regulator/hi655x-regulator.c
drivers/regulator/internal.h
drivers/regulator/irq_helpers.c [new file with mode: 0644]
drivers/regulator/lp8755.c
drivers/regulator/ltc3589.c
drivers/regulator/max77686-regulator.c
drivers/regulator/max77802-regulator.c
drivers/regulator/max8893.c [new file with mode: 0644]
drivers/regulator/max8973-regulator.c
drivers/regulator/mcp16502.c
drivers/regulator/mp5416.c
drivers/regulator/mp886x.c
drivers/regulator/mt6315-regulator.c
drivers/regulator/mt6358-regulator.c
drivers/regulator/mt6359-regulator.c [new file with mode: 0644]
drivers/regulator/of_regulator.c
drivers/regulator/pca9450-regulator.c
drivers/regulator/qcom-labibb-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/qcom_spmi-regulator.c
drivers/regulator/qcom_usb_vbus-regulator.c
drivers/regulator/rk808-regulator.c
drivers/regulator/rt4831-regulator.c
drivers/regulator/rt6160-regulator.c [new file with mode: 0644]
drivers/regulator/rt6245-regulator.c [new file with mode: 0644]
drivers/regulator/stpmic1_regulator.c
drivers/regulator/sy7636a-regulator.c [new file with mode: 0644]
drivers/regulator/uniphier-regulator.c
drivers/regulator/userspace-consumer.c
drivers/rtc/rtc-mt6397.c
drivers/s390/crypto/ap_queue.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/storvsc_drv.c
drivers/soc/ixp4xx/ixp4xx-npe.c
drivers/spi/Kconfig
drivers/spi/spi-altera-dfl.c
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-geni-qcom.c
drivers/spi/spi-hisi-kunpeng.c
drivers/spi/spi-lm70llp.c
drivers/spi/spi-loopback-test.c
drivers/spi/spi-mem.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-mpc52xx-psc.c
drivers/spi/spi-mpc52xx.c
drivers/spi/spi-npcm-pspi.c
drivers/spi/spi-nxp-fspi.c
drivers/spi/spi-oc-tiny.c
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap-uwire.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pl022.c
drivers/spi/spi-ppc4xx.c
drivers/spi/spi-pxa2xx-dma.c
drivers/spi/spi-pxa2xx-pci.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.h
drivers/spi/spi-rockchip.c
drivers/spi/spi-rspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-sun6i.c
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-tegra210-quad.c
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi-uniphier.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/atomisp/Makefile
drivers/staging/media/atomisp/TODO
drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
drivers/staging/media/atomisp/i2c/mt9m114.h
drivers/staging/media/atomisp/i2c/ov2680.h
drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
drivers/staging/media/atomisp/pci/atomisp_acc.c
drivers/staging/media/atomisp/pci/atomisp_cmd.c
drivers/staging/media/atomisp/pci/atomisp_cmd.h
drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c [deleted file]
drivers/staging/media/atomisp/pci/atomisp_csi2.c
drivers/staging/media/atomisp/pci/atomisp_csi2.h
drivers/staging/media/atomisp/pci/atomisp_file.c
drivers/staging/media/atomisp/pci/atomisp_fops.c
drivers/staging/media/atomisp/pci/atomisp_subdev.c
drivers/staging/media/atomisp/pci/atomisp_subdev.h
drivers/staging/media/atomisp/pci/atomisp_tpg.c
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
drivers/staging/media/atomisp/pci/sh_css.c
drivers/staging/media/av7110/Kconfig [new file with mode: 0644]
drivers/staging/media/av7110/Makefile [new file with mode: 0644]
drivers/staging/media/av7110/TODO [new file with mode: 0644]
drivers/staging/media/av7110/audio-bilingual-channel-select.rst [moved from Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst with 100% similarity]
drivers/staging/media/av7110/audio-channel-select.rst [moved from Documentation/userspace-api/media/dvb/audio-channel-select.rst with 100% similarity]
drivers/staging/media/av7110/audio-clear-buffer.rst [moved from Documentation/userspace-api/media/dvb/audio-clear-buffer.rst with 100% similarity]
drivers/staging/media/av7110/audio-continue.rst [moved from Documentation/userspace-api/media/dvb/audio-continue.rst with 100% similarity]
drivers/staging/media/av7110/audio-fclose.rst [moved from Documentation/userspace-api/media/dvb/audio-fclose.rst with 100% similarity]
drivers/staging/media/av7110/audio-fopen.rst [moved from Documentation/userspace-api/media/dvb/audio-fopen.rst with 100% similarity]
drivers/staging/media/av7110/audio-fwrite.rst [moved from Documentation/userspace-api/media/dvb/audio-fwrite.rst with 100% similarity]
drivers/staging/media/av7110/audio-get-capabilities.rst [moved from Documentation/userspace-api/media/dvb/audio-get-capabilities.rst with 100% similarity]
drivers/staging/media/av7110/audio-get-status.rst [moved from Documentation/userspace-api/media/dvb/audio-get-status.rst with 100% similarity]
drivers/staging/media/av7110/audio-pause.rst [moved from Documentation/userspace-api/media/dvb/audio-pause.rst with 100% similarity]
drivers/staging/media/av7110/audio-play.rst [moved from Documentation/userspace-api/media/dvb/audio-play.rst with 100% similarity]
drivers/staging/media/av7110/audio-select-source.rst [moved from Documentation/userspace-api/media/dvb/audio-select-source.rst with 100% similarity]
drivers/staging/media/av7110/audio-set-av-sync.rst [moved from Documentation/userspace-api/media/dvb/audio-set-av-sync.rst with 100% similarity]
drivers/staging/media/av7110/audio-set-bypass-mode.rst [moved from Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst with 94% similarity]
drivers/staging/media/av7110/audio-set-id.rst [moved from Documentation/userspace-api/media/dvb/audio-set-id.rst with 100% similarity]
drivers/staging/media/av7110/audio-set-mixer.rst [moved from Documentation/userspace-api/media/dvb/audio-set-mixer.rst with 100% similarity]
drivers/staging/media/av7110/audio-set-mute.rst [moved from Documentation/userspace-api/media/dvb/audio-set-mute.rst with 100% similarity]
drivers/staging/media/av7110/audio-set-streamtype.rst [moved from Documentation/userspace-api/media/dvb/audio-set-streamtype.rst with 100% similarity]
drivers/staging/media/av7110/audio-stop.rst [moved from Documentation/userspace-api/media/dvb/audio-stop.rst with 100% similarity]
drivers/staging/media/av7110/audio.h [moved from include/uapi/linux/dvb/audio.h with 100% similarity]
drivers/staging/media/av7110/audio.rst [moved from Documentation/userspace-api/media/dvb/audio.rst with 90% similarity]
drivers/staging/media/av7110/audio_data_types.rst [moved from Documentation/userspace-api/media/dvb/audio_data_types.rst with 100% similarity]
drivers/staging/media/av7110/audio_function_calls.rst [moved from Documentation/userspace-api/media/dvb/audio_function_calls.rst with 100% similarity]
drivers/staging/media/av7110/av7110.c [moved from drivers/media/pci/ttpci/av7110.c with 100% similarity]
drivers/staging/media/av7110/av7110.h [moved from drivers/media/pci/ttpci/av7110.h with 98% similarity]
drivers/staging/media/av7110/av7110_av.c [moved from drivers/media/pci/ttpci/av7110_av.c with 100% similarity]
drivers/staging/media/av7110/av7110_av.h [moved from drivers/media/pci/ttpci/av7110_av.h with 100% similarity]
drivers/staging/media/av7110/av7110_ca.c [moved from drivers/media/pci/ttpci/av7110_ca.c with 100% similarity]
drivers/staging/media/av7110/av7110_ca.h [moved from drivers/media/pci/ttpci/av7110_ca.h with 100% similarity]
drivers/staging/media/av7110/av7110_hw.c [moved from drivers/media/pci/ttpci/av7110_hw.c with 100% similarity]
drivers/staging/media/av7110/av7110_hw.h [moved from drivers/media/pci/ttpci/av7110_hw.h with 100% similarity]
drivers/staging/media/av7110/av7110_ipack.c [moved from drivers/media/pci/ttpci/av7110_ipack.c with 100% similarity]
drivers/staging/media/av7110/av7110_ipack.h [moved from drivers/media/pci/ttpci/av7110_ipack.h with 100% similarity]
drivers/staging/media/av7110/av7110_ir.c [moved from drivers/media/pci/ttpci/av7110_ir.c with 100% similarity]
drivers/staging/media/av7110/av7110_v4l.c [moved from drivers/media/pci/ttpci/av7110_v4l.c with 100% similarity]
drivers/staging/media/av7110/budget-patch.c [moved from drivers/media/pci/ttpci/budget-patch.c with 100% similarity]
drivers/staging/media/av7110/dvb_filter.c [moved from drivers/media/pci/ttpci/dvb_filter.c with 100% similarity]
drivers/staging/media/av7110/dvb_filter.h [moved from drivers/media/pci/ttpci/dvb_filter.h with 100% similarity]
drivers/staging/media/av7110/osd.h [moved from include/uapi/linux/dvb/osd.h with 100% similarity]
drivers/staging/media/av7110/sp8870.c [moved from drivers/media/dvb-frontends/sp8870.c with 100% similarity]
drivers/staging/media/av7110/sp8870.h [moved from drivers/media/dvb-frontends/sp8870.h with 100% similarity]
drivers/staging/media/av7110/video-clear-buffer.rst [moved from Documentation/userspace-api/media/dvb/video-clear-buffer.rst with 100% similarity]
drivers/staging/media/av7110/video-command.rst [moved from Documentation/userspace-api/media/dvb/video-command.rst with 100% similarity]
drivers/staging/media/av7110/video-continue.rst [moved from Documentation/userspace-api/media/dvb/video-continue.rst with 100% similarity]
drivers/staging/media/av7110/video-fast-forward.rst [moved from Documentation/userspace-api/media/dvb/video-fast-forward.rst with 100% similarity]
drivers/staging/media/av7110/video-fclose.rst [moved from Documentation/userspace-api/media/dvb/video-fclose.rst with 100% similarity]
drivers/staging/media/av7110/video-fopen.rst [moved from Documentation/userspace-api/media/dvb/video-fopen.rst with 100% similarity]
drivers/staging/media/av7110/video-freeze.rst [moved from Documentation/userspace-api/media/dvb/video-freeze.rst with 100% similarity]
drivers/staging/media/av7110/video-fwrite.rst [moved from Documentation/userspace-api/media/dvb/video-fwrite.rst with 100% similarity]
drivers/staging/media/av7110/video-get-capabilities.rst [moved from Documentation/userspace-api/media/dvb/video-get-capabilities.rst with 100% similarity]
drivers/staging/media/av7110/video-get-event.rst [moved from Documentation/userspace-api/media/dvb/video-get-event.rst with 100% similarity]
drivers/staging/media/av7110/video-get-frame-count.rst [moved from Documentation/userspace-api/media/dvb/video-get-frame-count.rst with 100% similarity]
drivers/staging/media/av7110/video-get-pts.rst [moved from Documentation/userspace-api/media/dvb/video-get-pts.rst with 100% similarity]
drivers/staging/media/av7110/video-get-size.rst [moved from Documentation/userspace-api/media/dvb/video-get-size.rst with 100% similarity]
drivers/staging/media/av7110/video-get-status.rst [moved from Documentation/userspace-api/media/dvb/video-get-status.rst with 100% similarity]
drivers/staging/media/av7110/video-play.rst [moved from Documentation/userspace-api/media/dvb/video-play.rst with 100% similarity]
drivers/staging/media/av7110/video-select-source.rst [moved from Documentation/userspace-api/media/dvb/video-select-source.rst with 100% similarity]
drivers/staging/media/av7110/video-set-blank.rst [moved from Documentation/userspace-api/media/dvb/video-set-blank.rst with 100% similarity]
drivers/staging/media/av7110/video-set-display-format.rst [moved from Documentation/userspace-api/media/dvb/video-set-display-format.rst with 100% similarity]
drivers/staging/media/av7110/video-set-format.rst [moved from Documentation/userspace-api/media/dvb/video-set-format.rst with 100% similarity]
drivers/staging/media/av7110/video-set-streamtype.rst [moved from Documentation/userspace-api/media/dvb/video-set-streamtype.rst with 100% similarity]
drivers/staging/media/av7110/video-slowmotion.rst [moved from Documentation/userspace-api/media/dvb/video-slowmotion.rst with 100% similarity]
drivers/staging/media/av7110/video-stillpicture.rst [moved from Documentation/userspace-api/media/dvb/video-stillpicture.rst with 100% similarity]
drivers/staging/media/av7110/video-stop.rst [moved from Documentation/userspace-api/media/dvb/video-stop.rst with 100% similarity]
drivers/staging/media/av7110/video-try-command.rst [moved from Documentation/userspace-api/media/dvb/video-try-command.rst with 100% similarity]
drivers/staging/media/av7110/video.h [moved from include/uapi/linux/dvb/video.h with 100% similarity]
drivers/staging/media/av7110/video.rst [moved from Documentation/userspace-api/media/dvb/video.rst with 93% similarity]
drivers/staging/media/av7110/video_function_calls.rst [moved from Documentation/userspace-api/media/dvb/video_function_calls.rst with 100% similarity]
drivers/staging/media/av7110/video_types.rst [moved from Documentation/userspace-api/media/dvb/video_types.rst with 100% similarity]
drivers/staging/media/hantro/Kconfig
drivers/staging/media/hantro/Makefile
drivers/staging/media/hantro/hantro.h
drivers/staging/media/hantro/hantro_drv.c
drivers/staging/media/hantro/hantro_g1.c [new file with mode: 0644]
drivers/staging/media/hantro/hantro_g1_h264_dec.c
drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
drivers/staging/media/hantro/hantro_g1_vp8_dec.c
drivers/staging/media/hantro/hantro_g2_hevc_dec.c [new file with mode: 0644]
drivers/staging/media/hantro/hantro_g2_regs.h [new file with mode: 0644]
drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
drivers/staging/media/hantro/hantro_hevc.c [new file with mode: 0644]
drivers/staging/media/hantro/hantro_hw.h
drivers/staging/media/hantro/hantro_mpeg2.c
drivers/staging/media/hantro/hantro_postproc.c
drivers/staging/media/hantro/hantro_v4l2.c
drivers/staging/media/hantro/imx8m_vpu_hw.c
drivers/staging/media/hantro/rk3288_vpu_hw.c [deleted file]
drivers/staging/media/hantro/rk3399_vpu_hw.c [deleted file]
drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c [moved from drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c with 87% similarity]
drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c [moved from drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c with 66% similarity]
drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c [moved from drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c with 99% similarity]
drivers/staging/media/hantro/rockchip_vpu2_regs.h [moved from drivers/staging/media/hantro/rk3399_vpu_regs.h with 99% similarity]
drivers/staging/media/hantro/rockchip_vpu_hw.c [new file with mode: 0644]
drivers/staging/media/hantro/sama5d4_vdec_hw.c [new file with mode: 0644]
drivers/staging/media/imx/imx-ic-prp.c
drivers/staging/media/imx/imx-ic-prpencvf.c
drivers/staging/media/imx/imx-media-csi.c
drivers/staging/media/imx/imx-media-utils.c
drivers/staging/media/imx/imx-media-vdic.c
drivers/staging/media/imx/imx-media.h
drivers/staging/media/imx/imx6-mipi-csi2.c
drivers/staging/media/imx/imx7-media-csi.c
drivers/staging/media/imx/imx7-mipi-csis.c
drivers/staging/media/ipu3/include/uapi/intel-ipu3.h [moved from drivers/staging/media/ipu3/include/intel-ipu3.h with 99% similarity]
drivers/staging/media/ipu3/ipu3-abi.h
drivers/staging/media/ipu3/ipu3-css-pool.h
drivers/staging/media/ipu3/ipu3-v4l2.c
drivers/staging/media/ipu3/ipu3.c
drivers/staging/media/meson/vdec/vdec_helpers.c
drivers/staging/media/omap4iss/iss.h
drivers/staging/media/omap4iss/iss_csi2.c
drivers/staging/media/omap4iss/iss_ipipe.c
drivers/staging/media/omap4iss/iss_ipipeif.c
drivers/staging/media/omap4iss/iss_resizer.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/rkvdec/rkvdec.c
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus.h
drivers/staging/media/sunxi/cedrus/cedrus_dec.c
drivers/staging/media/sunxi/cedrus/cedrus_h265.c
drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
drivers/staging/media/sunxi/cedrus/cedrus_video.c
drivers/staging/media/tegra-vde/vde.c
drivers/staging/media/tegra-video/csi.c
drivers/staging/media/tegra-video/vi.c
drivers/staging/media/zoran/zoran.h
drivers/staging/media/zoran/zoran_card.c
drivers/staging/media/zoran/zoran_device.c
drivers/staging/media/zoran/zoran_device.h
drivers/staging/media/zoran/zoran_driver.c
drivers/staging/media/zoran/zr36016.c
drivers/staging/media/zoran/zr36050.c
drivers/staging/media/zoran/zr36057.h
drivers/staging/media/zoran/zr36060.c
drivers/staging/octeon-usb/octeon-hcd.c
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
drivers/tee/tee_core.c
drivers/thermal/cpufreq_cooling.c
drivers/thermal/thermal_core.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/core/hub.c
drivers/usb/dwc3/core.c
drivers/usb/gadget/udc/max3420_udc.c
drivers/usb/host/max3421-hcd.c
drivers/usb/host/xhci-tegra.c
drivers/watchdog/machzwd.c
drivers/watchdog/octeon-wdt-main.c
drivers/xen/events/events_base.c
fs/afs/main.c
fs/afs/write.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/btrfs/Kconfig
fs/btrfs/backref.c
fs/btrfs/block-group.c
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delalloc-space.c
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-ref.c
fs/btrfs/dev-replace.c
fs/btrfs/discard.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/locking.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/props.c
fs/btrfs/qgroup.c
fs/btrfs/reflink.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/space-info.c
fs/btrfs/space-info.h
fs/btrfs/subpage.c
fs/btrfs/subpage.h
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/tests/extent-map-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/zoned.c
fs/btrfs/zoned.h
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/super.h
fs/crypto/fname.c
fs/crypto/keysetup.c
fs/erofs/Kconfig
fs/erofs/compress.h
fs/erofs/data.c
fs/erofs/decompressor.c
fs/erofs/dir.c
fs/erofs/erofs_fs.h
fs/erofs/inode.c
fs/erofs/internal.h
fs/erofs/namei.c
fs/erofs/super.c
fs/erofs/tagptr.h
fs/erofs/utils.c
fs/erofs/xattr.c
fs/erofs/xattr.h
fs/erofs/zdata.c
fs/erofs/zdata.h
fs/erofs/zmap.c
fs/erofs/zpvec.h
fs/exec.c
fs/hugetlbfs/inode.c
fs/netfs/read_helper.c
fs/nilfs2/sysfs.c
fs/notify/fanotify/fanotify_user.c
fs/proc/array.c
fs/proc/base.c
fs/proc/loadavg.c
fs/proc/stat.c
fs/pstore/blk.c
fs/reiserfs/namei.c
fs/userfaultfd.c
fs/xfs/libxfs/xfs_ag_resv.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/scrub/agheader.c
fs/xfs/scrub/bmap.c
fs/xfs/scrub/btree.c
fs/xfs/scrub/common.c
fs/xfs/scrub/dabtree.c
fs/xfs/scrub/repair.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_export.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.c
fs/xfs/xfs_trans_buf.c
include/asm-generic/atomic-instrumented.h
include/asm-generic/atomic.h
include/asm-generic/atomic64.h
include/asm-generic/cmpxchg-local.h
include/asm-generic/cmpxchg.h
include/asm-generic/hyperv-tlfs.h
include/asm-generic/preempt.h
include/clocksource/samsung_pwm.h
include/clocksource/timer-ti-dm.h
include/crypto/aead.h
include/crypto/algapi.h
include/crypto/engine.h
include/crypto/hash.h
include/crypto/internal/hash.h
include/kvm/arm_vgic.h
include/linux/arch_topology.h
include/linux/arm-smccc.h
include/linux/ata.h
include/linux/atomic-fallback.h [deleted file]
include/linux/atomic.h
include/linux/ceph/auth.h
include/linux/clocksource.h
include/linux/compiler.h
include/linux/cred.h
include/linux/crypto.h
include/linux/debug_locks.h
include/linux/delayacct.h
include/linux/dev_printk.h
include/linux/device.h
include/linux/energy_model.h
include/linux/evm.h
include/linux/gfp.h
include/linux/highmem.h
include/linux/huge_mm.h
include/linux/hugetlb.h
include/linux/hyperv.h
include/linux/ide.h [deleted file]
include/linux/instrumentation.h
include/linux/integrity.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/irqchip/arm-gic-common.h
include/linux/irqchip/arm-vgic-info.h [new file with mode: 0644]
include/linux/irqdesc.h
include/linux/irqdomain.h
include/linux/jump_label.h
include/linux/kasan.h
include/linux/kprobes.h
include/linux/kthread.h
include/linux/kvm_host.h
include/linux/kvm_types.h
include/linux/libata.h
include/linux/lockdep_types.h
include/linux/math64.h
include/linux/mfd/madera/pdata.h
include/linux/mfd/mt6358/core.h
include/linux/mfd/mt6359/core.h [new file with mode: 0644]
include/linux/mfd/mt6359/registers.h [new file with mode: 0644]
include/linux/mfd/mt6359p/registers.h [new file with mode: 0644]
include/linux/mfd/mt6397/core.h
include/linux/mfd/mt6397/rtc.h
include/linux/mlx5/driver.h
include/linux/mlx5/transobj.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/host.h
include/linux/mmc/sd.h
include/linux/mtd/spinand.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/pinctrl/pinconf-generic.h
include/linux/platform_data/spi-ath79.h [deleted file]
include/linux/platform_profile.h
include/linux/pm_domain.h
include/linux/pm_runtime.h
include/linux/pmbus.h
include/linux/prandom.h
include/linux/printk.h
include/linux/pstore_blk.h
include/linux/ptp_clock_kernel.h
include/linux/pxa2xx_ssp.h
include/linux/reboot.h
include/linux/regmap.h
include/linux/regulator/consumer.h
include/linux/regulator/coupler.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/regulator/mt6359-regulator.h [new file with mode: 0644]
include/linux/rmap.h
include/linux/sched.h
include/linux/sched/cpufreq.h
include/linux/sched/debug.h
include/linux/sched/sd_flags.h
include/linux/sched/signal.h
include/linux/sched/stat.h
include/linux/sched/user.h
include/linux/sched_clock.h
include/linux/seqlock.h
include/linux/shmem_fs.h
include/linux/signal.h
include/linux/signal_types.h
include/linux/socket.h
include/linux/spi/pxa2xx_spi.h
include/linux/spi/spi-mem.h
include/linux/spi/spi.h
include/linux/swapops.h
include/linux/tick.h
include/linux/user_namespace.h
include/linux/vmalloc.h
include/media/hevc-ctrls.h
include/media/media-dev-allocator.h
include/media/mpeg2-ctrls.h [deleted file]
include/media/rc-map.h
include/media/v4l2-ctrls.h
include/media/v4l2-subdev.h
include/media/videobuf2-v4l2.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/sock.h
include/trace/events/btrfs.h
include/trace/events/mmflags.h
include/trace/events/spi.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/btrfs.h
include/uapi/linux/btrfs_tree.h
include/uapi/linux/cec-funcs.h
include/uapi/linux/futex.h
include/uapi/linux/in.h
include/uapi/linux/kvm.h
include/uapi/linux/kvm_para.h
include/uapi/linux/lirc.h
include/uapi/linux/prctl.h
include/uapi/linux/seccomp.h
include/uapi/linux/userfaultfd.h
include/uapi/linux/v4l2-controls.h
include/uapi/linux/videodev2.h
init/init_task.c
init/main.c
ipc/mqueue.c
ipc/shm.c
kernel/Kconfig.preempt
kernel/bpf/verifier.c
kernel/cgroup/cgroup-v1.c
kernel/cpu.c
kernel/crash_core.c
kernel/cred.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_support.c
kernel/delayacct.c
kernel/dma/swiotlb.c
kernel/events/core.c
kernel/events/hw_breakpoint.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/freezer.c
kernel/futex.c
kernel/hung_task.c
kernel/irq/Kconfig
kernel/irq/chip.c
kernel/irq/handle.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/settings.h
kernel/jump_label.c
kernel/kcsan/report.c
kernel/kprobes.c
kernel/kthread.c
kernel/locking/lockdep.c
kernel/locking/mutex.c
kernel/locking/rtmutex.c
kernel/locking/rwsem.c
kernel/module.c
kernel/power/Kconfig
kernel/power/process.c
kernel/power/snapshot.c
kernel/power/swap.c
kernel/printk/printk.c
kernel/printk/printk_safe.c
kernel/ptrace.c
kernel/rcu/rcutorture.c
kernel/rcu/tree_plugin.h
kernel/rcu/tree_stall.h
kernel/reboot.c
kernel/sched/Makefile
kernel/sched/core.c
kernel/sched/core_sched.c [new file with mode: 0644]
kernel/sched/cpuacct.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/idle.c
kernel/sched/isolation.c
kernel/sched/loadavg.c
kernel/sched/pelt.h
kernel/sched/psi.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stats.h
kernel/sched/stop_task.c
kernel/sched/topology.c
kernel/seccomp.c
kernel/signal.c
kernel/smpboot.c
kernel/softirq.c
kernel/sys.c
kernel/sysctl.c
kernel/time/Kconfig
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/clocksource-wdtest.c [new file with mode: 0644]
kernel/time/clocksource.c
kernel/time/jiffies.c
kernel/time/posix-cpu-timers.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-sched.c
kernel/time/time_test.c [new file with mode: 0644]
kernel/time/timeconv.c
kernel/time/timer.c
kernel/time/timer_list.c
kernel/trace/trace.c
kernel/trace/trace_clock.c
kernel/ucount.c
kernel/user.c
kernel/user_namespace.c
lib/Kconfig.debug
lib/Makefile
lib/atomic64.c
lib/debug_locks.c
lib/dump_stack.c
lib/kstrtox.c
lib/kstrtox.h
lib/locking-selftest.c
lib/smp_processor_id.c
lib/syscall.c
lib/test_printf.c
lib/test_scanf.c [new file with mode: 0644]
lib/vsprintf.c
mm/compaction.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/kasan/common.c
mm/kasan/hw_tags.c
mm/kasan/sw_tags.c
mm/memfd.c
mm/memory-failure.c
mm/memory.c
mm/mempool.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/page_alloc.c
mm/page_vma_mapped.c
mm/pgtable-generic.c
mm/rmap.c
mm/shmem.c
mm/slab_common.c
mm/slub.c
mm/sparse.c
mm/swapfile.c
mm/truncate.c
mm/vmalloc.c
net/appletalk/aarp.c
net/batman-adv/bat_iv_ogm.c
net/bluetooth/smp.c
net/bridge/br_private.h
net/bridge/br_vlan_tunnel.c
net/can/bcm.c
net/can/isotp.c
net/can/j1939/transport.c
net/can/raw.c
net/ceph/auth.c
net/ceph/auth_none.c
net/ceph/auth_x.c
net/core/dev.c
net/core/filter.c
net/core/neighbour.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/core/skbuff.c
net/ethtool/eeprom.c
net/ethtool/ioctl.c
net/ethtool/strset.c
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/cipso_ipv4.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_semantics.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/ip_vti.c
net/ipv4/ipcomp.c
net/ipv4/ping.c
net/ipv4/route.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/netfilter/nft_fib_ipv6.c
net/ipv6/udp.c
net/kcm/kcmsock.c
net/mac80211/debugfs.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/tx.c
net/mac80211/util.c
net/mptcp/options.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netrom/nr_route.c
net/packet/af_packet.c
net/qrtr/qrtr.c
net/rds/recv.c
net/rds/tcp_connect.c
net/rds/threads.c
net/rxrpc/af_rxrpc.c
net/sched/act_ct.c
net/sched/sch_cake.c
net/sctp/input.c
net/socket.c
net/sunrpc/xprtmultipath.c
net/tipc/link.c
net/unix/af_unix.c
net/vmw_vsock/hyperv_transport.c
net/wireless/Makefile
net/wireless/core.c
net/wireless/pmsr.c
net/wireless/sysfs.c
net/wireless/util.c
net/xfrm/xfrm_interface.c
samples/kprobes/kprobe_example.c
scripts/Makefile.build
scripts/Makefile.kasan
scripts/atomic/check-atomics.sh
scripts/atomic/gen-atomic-instrumented.sh
scripts/atomic/gen-atomics.sh
scripts/documentation-file-ref-check
scripts/kernel-doc
scripts/recordmcount.h
scripts/sphinx-pre-install
scripts/tools-support-relr.sh
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/evm/evm_secfs.c
security/integrity/iint.c
security/integrity/ima/Kconfig
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_asymmetric_keys.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_kexec.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_queue.c
security/integrity/ima/ima_template.c
security/integrity/ima/ima_template_lib.c
security/integrity/ima/ima_template_lib.h
security/security.c
security/tomoyo/audit.c
security/tomoyo/securityfs_if.c
security/tomoyo/tomoyo.c
security/tomoyo/util.c
sound/soc/codecs/rt5645.c
sound/soc/pxa/pxa-ssp.c
tools/arch/x86/include/asm/asm.h [new file with mode: 0644]
tools/arch/x86/include/asm/irq_vectors.h
tools/arch/x86/include/asm/nops.h
tools/debugging/kernel-chktaint
tools/include/uapi/asm-generic/unistd.h
tools/include/uapi/linux/in.h
tools/include/uapi/linux/prctl.h
tools/lib/bpf/xsk.c
tools/lib/traceevent/plugins/plugin_kvm.c
tools/objtool/arch/x86/decode.c
tools/objtool/arch/x86/include/arch/special.h
tools/objtool/check.c
tools/objtool/elf.c
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/objtool.h
tools/objtool/include/objtool/special.h
tools/objtool/special.c
tools/perf/tests/shell/stat_bpf_counters.sh
tools/perf/trace/beauty/include/linux/socket.h
tools/perf/util/machine.c
tools/perf/util/metricgroup.c
tools/testing/selftests/Makefile
tools/testing/selftests/arm64/fp/sve-probe-vls.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/bpf/verifier/and.c
tools/testing/selftests/bpf/verifier/bounds.c
tools/testing/selftests/bpf/verifier/dead_code.c
tools/testing/selftests/bpf/verifier/jmp32.c
tools/testing/selftests/bpf/verifier/jset.c
tools/testing/selftests/bpf/verifier/unpriv.c
tools/testing/selftests/bpf/verifier/value_ptr_arith.c
tools/testing/selftests/futex/functional/.gitignore
tools/testing/selftests/futex/functional/Makefile
tools/testing/selftests/futex/functional/futex_requeue.c [new file with mode: 0644]
tools/testing/selftests/futex/functional/futex_wait.c [new file with mode: 0644]
tools/testing/selftests/futex/functional/futex_wait_timeout.c
tools/testing/selftests/futex/functional/run.sh
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/aarch64/debug-exceptions.c [new file with mode: 0644]
tools/testing/selftests/kvm/aarch64/get-reg-list-sve.c [deleted file]
tools/testing/selftests/kvm/aarch64/get-reg-list.c
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/hardware_disable_test.c
tools/testing/selftests/kvm/include/aarch64/processor.h
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/include/x86_64/apic.h [new file with mode: 0644]
tools/testing/selftests/kvm/include/x86_64/evmcs.h [moved from tools/testing/selftests/kvm/include/evmcs.h with 99% similarity]
tools/testing/selftests/kvm/include/x86_64/hyperv.h [new file with mode: 0644]
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/include/x86_64/vmx.h
tools/testing/selftests/kvm/kvm_binary_stats_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/kvm_page_table_test.c
tools/testing/selftests/kvm/lib/aarch64/handlers.S [new file with mode: 0644]
tools/testing/selftests/kvm/lib/aarch64/processor.c
tools/testing/selftests/kvm/lib/aarch64/ucall.c
tools/testing/selftests/kvm/lib/elf.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/perf_test_util.c
tools/testing/selftests/kvm/lib/s390x/processor.c
tools/testing/selftests/kvm/lib/test_util.c
tools/testing/selftests/kvm/lib/x86_64/apic.c [new file with mode: 0644]
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/lib/x86_64/svm.c
tools/testing/selftests/kvm/lib/x86_64/vmx.c
tools/testing/selftests/kvm/memslot_perf_test.c
tools/testing/selftests/kvm/set_memory_region_test.c
tools/testing/selftests/kvm/steal_time.c
tools/testing/selftests/kvm/x86_64/emulator_error_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/evmcs_test.c
tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
tools/testing/selftests/kvm/x86_64/hyperv_clock.c
tools/testing/selftests/kvm/x86_64/hyperv_features.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/kvm_pv_test.c
tools/testing/selftests/kvm/x86_64/mmu_role_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c
tools/testing/selftests/kvm/x86_64/smm_test.c
tools/testing/selftests/kvm/x86_64/sync_regs_test.c
tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c
tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c
tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c
tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c
tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c
tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c
tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c
tools/testing/selftests/lib/Makefile
tools/testing/selftests/lib/config
tools/testing/selftests/lib/scanf.sh [new file with mode: 0755]
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/icmp.sh [new file with mode: 0755]
tools/testing/selftests/net/mptcp/mptcp_connect.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/nft_fib.sh [new file with mode: 0755]
tools/testing/selftests/rlimits/.gitignore [new file with mode: 0644]
tools/testing/selftests/rlimits/Makefile [new file with mode: 0644]
tools/testing/selftests/rlimits/config [new file with mode: 0644]
tools/testing/selftests/rlimits/rlimits-per-userns.c [new file with mode: 0644]
tools/testing/selftests/sched/.gitignore [new file with mode: 0644]
tools/testing/selftests/sched/Makefile [new file with mode: 0644]
tools/testing/selftests/sched/config [new file with mode: 0644]
tools/testing/selftests/sched/cs_prctl_test.c [new file with mode: 0644]
tools/testing/selftests/seccomp/seccomp_benchmark.c
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/testing/selftests/x86/syscall_numbering.c
virt/kvm/Kconfig
virt/kvm/binary_stats.c [new file with mode: 0644]
virt/kvm/kvm_main.c

index c79a787..a35ae24 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -102,6 +102,7 @@ Felipe W Damasio <felipewd@terra.com.br>
 Felix Kuhling <fxkuehl@gmx.de>
 Felix Moeller <felix@derklecks.de>
 Filipe Lautert <filipe@icewall.org>
+Finn Thain <fthain@linux-m68k.org> <fthain@telegraphics.com.au>
 Franck Bui-Huu <vagabon.xyz@gmail.com>
 Frank Rowand <frowand.list@gmail.com> <frank.rowand@am.sony.com>
 Frank Rowand <frowand.list@gmail.com> <frank.rowand@sonymobile.com>
@@ -212,6 +213,8 @@ Manivannan Sadhasivam <mani@kernel.org> <manivannanece23@gmail.com>
 Manivannan Sadhasivam <mani@kernel.org> <manivannan.sadhasivam@linaro.org>
 Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
 Marc Zyngier <maz@kernel.org> <marc.zyngier@arm.com>
+Marek Behún <kabel@kernel.org> <marek.behun@nic.cz>
+Marek Behún <kabel@kernel.org> Marek Behun <marek.behun@nic.cz>
 Mark Brown <broonie@sirena.org.uk>
 Mark Starovoytov <mstarovo@pm.me> <mstarovoitov@marvell.com>
 Mark Yao <markyao0591@gmail.com> <mark.yao@rock-chips.com>
index e398fb5..972cc11 100644 (file)
@@ -6,4 +6,4 @@ Description:
        with the update that cpuidle governor can be changed at runtime in default,
        both current_governor and current_governor_ro co-exist under
        /sys/devices/system/cpu/cpuidle/ file, it's duplicate so make
-       current_governor_ro obselete.
+       current_governor_ro obsolete.
index dc4463f..85a90b8 100644 (file)
@@ -5,7 +5,7 @@ Contact:        Dhaval Giani <dhaval@linux.vnet.ibm.com>
 Description:
                The /sys/kernel/uids/<uid>/cpu_shares tunable is used
                to set the cpu bandwidth a user is allowed. This is a
-               propotional value. What that means is that if there
+               proportional value. What that means is that if there
                are two users logged in, each with an equal number of
                shares, then they will get equal CPU bandwidth. Another
                example would be, if User A has shares = 1024 and user
index 42599d9..3066fea 100644 (file)
@@ -61,7 +61,7 @@ Date:         September. 2017
 KernelVersion: 4.14
 Contact:       Stephen Hemminger <sthemmin@microsoft.com>
 Description:   Directory for per-channel information
-               NN is the VMBUS relid associtated with the channel.
+               NN is the VMBUS relid associated with the channel.
 
 What:          /sys/bus/vmbus/devices/<UUID>/channels/<N>/cpu
 Date:          September. 2017
index e8b60bd..480a89e 100644 (file)
@@ -19,7 +19,7 @@ Date:         April 2011
 KernelVersion: 3.0
 Contact:       Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 Description:
-                The major:minor number (in hexidecimal) of the
+                The major:minor number (in hexadecimal) of the
                 physical device providing the storage for this backend
                 block device.
 
index 33c133e..516dafe 100644 (file)
@@ -23,3 +23,86 @@ Description: Default value for the Data Stream Control Register (DSCR) on
                here).
                If set by a process it will be inherited by child processes.
 Values:                64 bit unsigned integer (bit field)
+
+What:           /sys/devices/system/cpu/cpuX/topology/physical_package_id
+Description:    physical package id of cpuX. Typically corresponds to a physical
+                socket number, but the actual value is architecture and platform
+                dependent.
+Values:         integer
+
+What:           /sys/devices/system/cpu/cpuX/topology/die_id
+Description:    the CPU die ID of cpuX. Typically it is the hardware platform's
+                identifier (rather than the kernel's). The actual value is
+                architecture and platform dependent.
+Values:         integer
+
+What:           /sys/devices/system/cpu/cpuX/topology/core_id
+Description:    the CPU core ID of cpuX. Typically it is the hardware platform's
+                identifier (rather than the kernel's). The actual value is
+                architecture and platform dependent.
+Values:         integer
+
+What:           /sys/devices/system/cpu/cpuX/topology/book_id
+Description:    the book ID of cpuX. Typically it is the hardware platform's
+                identifier (rather than the kernel's). The actual value is
+                architecture and platform dependent. it's only used on s390.
+Values:         integer
+
+What:           /sys/devices/system/cpu/cpuX/topology/drawer_id
+Description:    the drawer ID of cpuX. Typically it is the hardware platform's
+                identifier (rather than the kernel's). The actual value is
+                architecture and platform dependent. it's only used on s390.
+Values:         integer
+
+What:           /sys/devices/system/cpu/cpuX/topology/core_cpus
+Description:    internal kernel map of CPUs within the same core.
+                (deprecated name: "thread_siblings")
+Values:         hexadecimal bitmask.
+
+What:           /sys/devices/system/cpu/cpuX/topology/core_cpus_list
+Description:    human-readable list of CPUs within the same core.
+                The format is like 0-3, 8-11, 14,17.
+                (deprecated name: "thread_siblings_list").
+Values:         decimal list.
+
+What:           /sys/devices/system/cpu/cpuX/topology/package_cpus
+Description:    internal kernel map of the CPUs sharing the same physical_package_id.
+                (deprecated name: "core_siblings").
+Values:         hexadecimal bitmask.
+
+What:           /sys/devices/system/cpu/cpuX/topology/package_cpus_list
+Description:    human-readable list of CPUs sharing the same physical_package_id.
+                The format is like 0-3, 8-11, 14,17.
+                (deprecated name: "core_siblings_list")
+Values:         decimal list.
+
+What:           /sys/devices/system/cpu/cpuX/topology/die_cpus
+Description:    internal kernel map of CPUs within the same die.
+Values:         hexadecimal bitmask.
+
+What:           /sys/devices/system/cpu/cpuX/topology/die_cpus_list
+Description:    human-readable list of CPUs within the same die.
+                The format is like 0-3, 8-11, 14,17.
+Values:         decimal list.
+
+What:           /sys/devices/system/cpu/cpuX/topology/book_siblings
+Description:    internal kernel map of cpuX's hardware threads within the same
+                book_id. it's only used on s390.
+Values:         hexadecimal bitmask.
+
+What:           /sys/devices/system/cpu/cpuX/topology/book_siblings_list
+Description:    human-readable list of cpuX's hardware threads within the same
+                book_id.
+                The format is like 0-3, 8-11, 14,17. it's only used on s390.
+Values:         decimal list.
+
+What:           /sys/devices/system/cpu/cpuX/topology/drawer_siblings
+Description:    internal kernel map of cpuX's hardware threads within the same
+                drawer_id. it's only used on s390.
+Values:         hexadecimal bitmask.
+
+What:           /sys/devices/system/cpu/cpuX/topology/drawer_siblings_list
+Description:    human-readable list of cpuX's hardware threads within the same
+                drawer_id.
+                The format is like 0-3, 8-11, 14,17. it's only used on s390.
+Values:         decimal list.
index 55285c1..d431e2d 100644 (file)
@@ -173,7 +173,7 @@ What:           /sys/bus/dsa/devices/wq<m>.<n>/priority
 Date:           Oct 25, 2019
 KernelVersion:  5.6.0
 Contact:        dmaengine@vger.kernel.org
-Description:    The priority value of this work queue, it is a vlue relative to
+Description:    The priority value of this work queue, it is a value relative to
                other work queue in the same group to control quality of service
                for dispatching work from multiple workqueues in the same group.
 
index fd9a804..b2553df 100644 (file)
@@ -137,7 +137,7 @@ Contact:    Vadim Pasternak <vadimpmellanox.com>
 Description:   These files show the system reset cause, as following:
                COMEX thermal shutdown; wathchdog power off or reset was derived
                by one of the next components: COMEX, switch board or by Small Form
-               Factor mezzanine, reset requested from ASIC, reset cuased by BIOS
+               Factor mezzanine, reset requested from ASIC, reset caused by BIOS
                reload. Value 1 in file means this is reset cause, 0 - otherwise.
                Only one of the above causes could be 1 at the same time, representing
                only last reset cause.
@@ -183,7 +183,7 @@ What:               /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/vpd_wp
 Date:          January 2020
 KernelVersion: 5.6
 Contact:       Vadim Pasternak <vadimpmellanox.com>
-Description:   This file allows to overwrite system VPD hardware wrtie
+Description:   This file allows to overwrite system VPD hardware write
                protection when attribute is set 1.
 
                The file is read/write.
index aebda53..1637fcb 100644 (file)
@@ -31,4 +31,4 @@ Date:         April 2016
 KernelVersion: 4.7
 Description:
                Dummy IIO devices directory. Creating a directory here will result
-               in creating a dummy IIO device in the IIO subystem.
+               in creating a dummy IIO device in the IIO subsystem.
index bc6b8bd..0a4b864 100644 (file)
@@ -20,7 +20,7 @@ Description:
 
                subbuffer_size
                                configure the sub-buffer size for this channel
-                               (needed for synchronous and isochrnous data)
+                               (needed for synchronous and isochronous data)
 
 
                num_buffers
@@ -75,7 +75,7 @@ Description:
 
                subbuffer_size
                                configure the sub-buffer size for this channel
-                               (needed for synchronous and isochrnous data)
+                               (needed for synchronous and isochronous data)
 
 
                num_buffers
@@ -130,7 +130,7 @@ Description:
 
                subbuffer_size
                                configure the sub-buffer size for this channel
-                               (needed for synchronous and isochrnous data)
+                               (needed for synchronous and isochronous data)
 
 
                num_buffers
@@ -196,7 +196,7 @@ Description:
 
                subbuffer_size
                                configure the sub-buffer size for this channel
-                               (needed for synchronous and isochrnous data)
+                               (needed for synchronous and isochronous data)
 
 
                num_buffers
index dc351e9..b7943aa 100644 (file)
@@ -137,7 +137,7 @@ Description:
                This group contains "OS String" extension handling attributes.
 
                =============   ===============================================
-               use             flag turning "OS Desctiptors" support on/off
+               use             flag turning "OS Descriptors" support on/off
                b_vendor_code   one-byte value used for custom per-device and
                                per-interface requests
                qw_sign         an identifier to be reported as "OS String"
index ac5e11a..889ed45 100644 (file)
@@ -170,7 +170,7 @@ Description:        Default color matching descriptors
                bMatrixCoefficients       matrix used to compute luma and
                                          chroma values from the color primaries
                bTransferCharacteristics  optoelectronic transfer
-                                         characteristic of the source picutre,
+                                         characteristic of the source picture,
                                          also called the gamma function
                bColorPrimaries           color primaries and the reference
                                          white
@@ -311,7 +311,7 @@ Description:        Specific streaming header descriptors
                                        a hardware trigger interrupt event
                bTriggerSupport         flag specifying if hardware
                                        triggering is supported
-               bStillCaptureMethod     method of still image caputre
+               bStillCaptureMethod     method of still image capture
                                        supported
                bTerminalLink           id of the output terminal to which
                                        the video endpoint of this interface
index 1c2f256..b45b016 100644 (file)
@@ -31,7 +31,7 @@ What:           /sys/kernel/debug/genwqe/genwqe<n>_card/prev_regs
 Date:           Oct 2013
 Contact:        haver@linux.vnet.ibm.com
 Description:    Dump of the error registers before the last reset of
-                the card occured.
+                the card occurred.
                 Only available for PF.
 
 What:           /sys/kernel/debug/genwqe/genwqe<n>_card/prev_dbg_uid0
index c78fc92..e89c635 100644 (file)
@@ -153,7 +153,7 @@ KernelVersion:  5.1
 Contact:        ogabbay@kernel.org
 Description:    Triggers an I2C transaction that is generated by the device's
                 CPU. Writing to this file generates a write transaction while
-                reading from the file generates a read transcation
+                reading from the file generates a read transaction
 
 What:           /sys/kernel/debug/habanalabs/hl<n>/i2c_reg
 Date:           Jan 2019
index 3c477ba..553fd8a 100644 (file)
@@ -24,7 +24,7 @@ Description:
                1         Enable digital signature validation
                2         Permit modification of EVM-protected metadata at
                          runtime. Not supported if HMAC validation and
-                         creation is enabled.
+                         creation is enabled (deprecated).
                31        Disable further runtime modification of EVM policy
                ===       ==================================================
 
@@ -47,10 +47,38 @@ Description:
 
                will enable digital signature validation, permit
                modification of EVM-protected metadata and
-               disable all further modification of policy
+               disable all further modification of policy. This option is now
+               deprecated in favor of::
 
-               Note that once a key has been loaded, it will no longer be
-               possible to enable metadata modification.
+                 echo 0x80000002 ><securityfs>/evm
+
+               as the outstanding issues that prevent the usage of EVM portable
+               signatures have been solved.
+
+               Echoing a value is additive, the new value is added to the
+               existing initialization flags.
+
+               For example, after::
+
+                 echo 2 ><securityfs>/evm
+
+               another echo can be performed::
+
+                 echo 1 ><securityfs>/evm
+
+               and the resulting value will be 3.
+
+               Note that once an HMAC key has been loaded, it will no longer
+               be possible to enable metadata modification. Signaling that an
+               HMAC key has been loaded will clear the corresponding flag.
+               For example, if the current value is 6 (2 and 4 set)::
+
+                 echo 1 ><securityfs>/evm
+
+               will set the new value to 3 (4 cleared).
+
+               Loading an HMAC key is the only way to disable metadata
+               modification.
 
                Until key loading has been signaled EVM can not create
                or validate the 'security.evm' xattr, but returns
index d148214..76e0caa 100644 (file)
@@ -12,7 +12,7 @@ KernelVersion:  4.12
 Contact:        linux-fsi@lists.ozlabs.org
 Description:
                Sends an FSI BREAK command on a master's communication
-               link to any connnected slaves.  A BREAK resets connected
+               link to any connected slaves.  A BREAK resets connected
                device's logic and preps it to receive further commands
                from the master.
 
index 2679735..6f98b6a 100644 (file)
@@ -786,7 +786,7 @@ What:               /sys/.../events/in_capacitanceY_adaptive_thresh_rising_en
 What:          /sys/.../events/in_capacitanceY_adaptive_thresh_falling_en
 KernelVersion: 5.13
 Contact:       linux-iio@vger.kernel.org
-Descrption:
+Description:
                Adaptive thresholds are similar to normal fixed thresholds
                but the value is expressed as an offset from a value which
                provides a low frequency approximation of the channel itself.
@@ -798,10 +798,10 @@ What:             /sys/.../in_capacitanceY_adaptive_thresh_rising_timeout
 What:          /sys/.../in_capacitanceY_adaptive_thresh_falling_timeout
 KernelVersion: 5.11
 Contact:       linux-iio@vger.kernel.org
-Descrption:
+Description:
                When adaptive thresholds are used, the tracking signal
                may adjust too slowly to step changes in the raw signal.
-               *_timeout (in seconds) specifies a time for which the
+               Thus these specify the time in seconds for which the
                difference between the slow tracking signal and the raw
                signal is allowed to remain out-of-range before a reset
                event occurs in which the tracking signal is made equal
index ef00fad..793cbb7 100644 (file)
@@ -139,8 +139,8 @@ Description:
                binary file containing the Vital Product Data for the
                device.  It should follow the VPD format defined in
                PCI Specification 2.1 or 2.2, but users should consider
-               that some devices may have malformatted data.  If the
-               underlying VPD has a writable section then the
+               that some devices may have incorrectly formatted data.  
+               If the underlying VPD has a writable section then the
                corresponding section of this file will be writable.
 
 What:          /sys/bus/pci/devices/.../virtfnN
index 1fc8640..c453646 100644 (file)
@@ -84,3 +84,103 @@ Description:
                It can be enabled by writing the value stored in
                /sys/class/backlight/<backlight>/max_brightness to
                /sys/class/backlight/<backlight>/brightness.
+
+What:          /sys/class/backlight/<backlight>/<ambient light zone>_max
+Date:          Sep, 2009
+KernelVersion: v2.6.32
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Control the maximum brightness for <ambient light zone>
+               on this <backlight>. Values are between 0 and 127. This file
+               will also show the brightness level stored for this
+               <ambient light zone>.
+
+               The <ambient light zone> is device-driver specific:
+
+               For ADP5520 and ADP5501, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               daylight     /sys/class/backlight/<backlight>/daylight_max
+               office       /sys/class/backlight/<backlight>/office_max
+               dark         /sys/class/backlight/<backlight>/dark_max
+               ===========  ================================================
+
+               For ADP8860, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               l1_daylight  /sys/class/backlight/<backlight>/l1_daylight_max
+               l2_office    /sys/class/backlight/<backlight>/l2_office_max
+               l3_dark      /sys/class/backlight/<backlight>/l3_dark_max
+               ===========  ================================================
+
+               For ADP8870, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               l1_daylight  /sys/class/backlight/<backlight>/l1_daylight_max
+               l2_bright    /sys/class/backlight/<backlight>/l2_bright_max
+               l3_office    /sys/class/backlight/<backlight>/l3_office_max
+               l4_indoor    /sys/class/backlight/<backlight>/l4_indoor_max
+               l5_dark      /sys/class/backlight/<backlight>/l5_dark_max
+               ===========  ================================================
+
+               See also: /sys/class/backlight/<backlight>/ambient_light_zone.
+
+What:          /sys/class/backlight/<backlight>/<ambient light zone>_dim
+Date:          Sep, 2009
+KernelVersion: v2.6.32
+Contact:       device-drivers-devel@blackfin.uclinux.org
+Description:
+               Control the dim brightness for <ambient light zone>
+               on this <backlight>. Values are between 0 and 127, typically
+               set to 0. Full off when the backlight is disabled.
+               This file will also show the dim brightness level stored for
+               this <ambient light zone>.
+
+               The <ambient light zone> is device-driver specific:
+
+               For ADP5520 and ADP5501, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               daylight     /sys/class/backlight/<backlight>/daylight_dim
+               office       /sys/class/backlight/<backlight>/office_dim
+               dark         /sys/class/backlight/<backlight>/dark_dim
+               ===========  ================================================
+
+               For ADP8860, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               l1_daylight  /sys/class/backlight/<backlight>/l1_daylight_dim
+               l2_office    /sys/class/backlight/<backlight>/l2_office_dim
+               l3_dark      /sys/class/backlight/<backlight>/l3_dark_dim
+               ===========  ================================================
+
+               For ADP8870, <ambient light zone> can be:
+
+               ===========  ================================================
+               Ambient      sysfs entry
+               light zone
+               ===========  ================================================
+               l1_daylight  /sys/class/backlight/<backlight>/l1_daylight_dim
+               l2_bright    /sys/class/backlight/<backlight>/l2_bright_dim
+               l3_office    /sys/class/backlight/<backlight>/l3_office_dim
+               l4_indoor    /sys/class/backlight/<backlight>/l4_indoor_dim
+               l5_dark      /sys/class/backlight/<backlight>/l5_dark_dim
+               ===========  ================================================
+
+               See also: /sys/class/backlight/<backlight>/ambient_light_zone.
+
diff --git a/Documentation/ABI/testing/sysfs-class-backlight-adp5520 b/Documentation/ABI/testing/sysfs-class-backlight-adp5520
deleted file mode 100644 (file)
index 34b6eba..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-sysfs interface for analog devices adp5520(01) backlight driver
----------------------------------------------------------------
-
-The backlight brightness control operates at three different levels for the
-adp5520 and adp5501 devices: daylight (level 1), office (level 2) and dark
-(level 3). By default the brightness operates at the daylight brightness level.
-
-What:          /sys/class/backlight/<backlight>/daylight_max
-What:          /sys/class/backlight/<backlight>/office_max
-What:          /sys/class/backlight/<backlight>/dark_max
-Date:          Sep, 2009
-KernelVersion: v2.6.32
-Contact:       Michael Hennerich <michael.hennerich@analog.com>
-Description:
-               (RW) Maximum current setting for the backlight when brightness
-               is at one of the three levels (daylight, office or dark). This
-               is an input code between 0 and 127, which is transformed to a
-               value between 0 mA and 30 mA using linear or non-linear
-               algorithms.
-
-What:          /sys/class/backlight/<backlight>/daylight_dim
-What:          /sys/class/backlight/<backlight>/office_dim
-What:          /sys/class/backlight/<backlight>/dark_dim
-Date:          Sep, 2009
-KernelVersion: v2.6.32
-Contact:       Michael Hennerich <michael.hennerich@analog.com>
-Description:
-               (RW) Dim current setting for the backlight when brightness is at
-               one of the three levels (daylight, office or dark). This is an
-               input code between 0 and 127, which is transformed to a value
-               between 0 mA and 30 mA using linear or non-linear algorithms.
diff --git a/Documentation/ABI/testing/sysfs-class-backlight-adp8860 b/Documentation/ABI/testing/sysfs-class-backlight-adp8860
deleted file mode 100644 (file)
index 6610ac7..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-sysfs interface for analog devices adp8860 backlight driver
------------------------------------------------------------
-
-The backlight brightness control operates at three different levels for the
-adp8860, adp8861 and adp8863 devices: daylight (level 1), office (level 2) and
-dark (level 3). By default the brightness operates at the daylight brightness
-level.
-
-See also /sys/class/backlight/<backlight>/ambient_light_level and
-/sys/class/backlight/<backlight>/ambient_light_zone.
-
-
-What:          /sys/class/backlight/<backlight>/l1_daylight_max
-What:          /sys/class/backlight/<backlight>/l2_office_max
-What:          /sys/class/backlight/<backlight>/l3_dark_max
-Date:          Apr, 2010
-KernelVersion: v2.6.35
-Contact:       Michael Hennerich <michael.hennerich@analog.com>
-Description:
-               (RW) Maximum current setting for the backlight when brightness
-               is at one of the three levels (daylight, office or dark). This
-               is an input code between 0 and 127, which is transformed to a
-               value between 0 mA and 30 mA using linear or non-linear
-               algorithms.
-
-
-What:          /sys/class/backlight/<backlight>/l1_daylight_dim
-What:          /sys/class/backlight/<backlight>/l2_office_dim
-What:          /sys/class/backlight/<backlight>/l3_dark_dim
-Date:          Apr, 2010
-KernelVersion: v2.6.35
-Contact:       Michael Hennerich <michael.hennerich@analog.com>
-Description:
-               (RW) Dim current setting for the backlight when brightness is at
-               one of the three levels (daylight, office or dark). This is an
-               input code between 0 and 127, which is transformed to a value
-               between 0 mA and 30 mA using linear or non-linear algorithms.
diff --git a/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870 b/Documentation/ABI/testing/sysfs-class-backlight-driver-adp8870
deleted file mode 100644 (file)
index b08ca91..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-See also /sys/class/backlight/<backlight>/ambient_light_level and
-/sys/class/backlight/<backlight>/ambient_light_zone.
-
-What:          /sys/class/backlight/<backlight>/<ambient light zone>_max
-What:          /sys/class/backlight/<backlight>/l1_daylight_max
-What:          /sys/class/backlight/<backlight>/l2_bright_max
-What:          /sys/class/backlight/<backlight>/l3_office_max
-What:          /sys/class/backlight/<backlight>/l4_indoor_max
-What:          /sys/class/backlight/<backlight>/l5_dark_max
-Date:          May 2011
-KernelVersion: 3.0
-Contact:       device-drivers-devel@blackfin.uclinux.org
-Description:
-               Control the maximum brightness for <ambient light zone>
-               on this <backlight>. Values are between 0 and 127. This file
-               will also show the brightness level stored for this
-               <ambient light zone>.
-
-What:          /sys/class/backlight/<backlight>/<ambient light zone>_dim
-What:          /sys/class/backlight/<backlight>/l2_bright_dim
-What:          /sys/class/backlight/<backlight>/l3_office_dim
-What:          /sys/class/backlight/<backlight>/l4_indoor_dim
-What:          /sys/class/backlight/<backlight>/l5_dark_dim
-Date:          May 2011
-KernelVersion: 3.0
-Contact:       device-drivers-devel@blackfin.uclinux.org
-Description:
-               Control the dim brightness for <ambient light zone>
-               on this <backlight>. Values are between 0 and 127, typically
-               set to 0. Full off when the backlight is disabled.
-               This file will also show the dim brightness level stored for
-               this <ambient light zone>.
diff --git a/Documentation/ABI/testing/sysfs-class-led-driver-el15203000 b/Documentation/ABI/testing/sysfs-class-led-driver-el15203000
deleted file mode 100644 (file)
index 04f3ffd..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-What:          /sys/class/leds/<led>/repeat
-Date:          September 2019
-KernelVersion: 5.5
-Description:
-               EL15203000 supports only indefinitely patterns,
-               so this file should always store -1.
-
-               For more info, please see:
-               Documentation/ABI/testing/sysfs-class-led-trigger-pattern
index d91a077..8c57d27 100644 (file)
@@ -35,3 +35,6 @@ Description:
 
                This file will always return the originally written repeat
                number.
+
+               It should be noticed that some leds, like EL15203000 may
+               only support indefinitely patterns, so they always store -1.
index fe13baa..160b10c 100644 (file)
@@ -50,7 +50,7 @@ Description:  Dynamic addition and removal of CPU's.  This is not hotplug
                architecture specific.
 
                release: writes to this file dynamically remove a CPU from
-               the system.  Information writtento the file to remove CPU's
+               the system.  Information written to the file to remove CPU's
                is architecture specific.
 
 What:          /sys/devices/system/cpu/cpu#/node
@@ -97,7 +97,7 @@ Description:  CPU topology files that describe a logical CPU's relationship
                corresponds to a physical socket number, but the actual value
                is architecture and platform dependent.
 
-               thread_siblings: internel kernel map of cpu#'s hardware
+               thread_siblings: internal kernel map of cpu#'s hardware
                threads within the same core as cpu#
 
                thread_siblings_list: human-readable list of cpu#'s hardware
@@ -280,7 +280,7 @@ Description:        Disable L3 cache indices
                on a processor with this functionality will return the currently
                disabled index for that node. There is one L3 structure per
                node, or per internal node on MCM machines. Writing a valid
-               index to one of these files will cause the specificed cache
+               index to one of these files will cause the specified cache
                index to be disabled.
 
                All AMD processors with L3 caches provide this functionality.
@@ -295,7 +295,7 @@ Description:        Processor frequency boosting control
 
                This switch controls the boost setting for the whole system.
                Boosting allows the CPU and the firmware to run at a frequency
-               beyound it's nominal limit.
+               beyond it's nominal limit.
 
                More details can be found in
                Documentation/admin-guide/pm/cpufreq.rst
@@ -532,7 +532,7 @@ What:               /sys/devices/system/cpu/smt
                /sys/devices/system/cpu/smt/control
 Date:          June 2018
 Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
-Description:   Control Symetric Multi Threading (SMT)
+Description:   Control Symmetric Multi Threading (SMT)
 
                active:  Tells whether SMT is active (enabled and siblings online)
 
index d1bc23c..eaac689 100644 (file)
@@ -168,7 +168,7 @@ Description:        This file shows the manufacturing date in BCD format.
 What:          /sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturer_id
 Date:          February 2018
 Contact:       Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
-Description:   This file shows the manufacturee ID. This is one of the
+Description:   This file shows the manufacturer ID. This is one of the
                UFS device descriptor parameters. The full information about
                the descriptor could be found at UFS specifications 2.1.
 
@@ -521,7 +521,7 @@ Description:        This file shows maximum VCC, VCCQ and VCCQ2 value for
 What:          /sys/bus/platform/drivers/ufshcd/*/string_descriptors/manufacturer_name
 Date:          February 2018
 Contact:       Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
-Description:   This file contains a device manufactureer name string.
+Description:   This file contains a device manufacturer name string.
                The full information about the descriptor could be found at
                UFS specifications 2.1.
 
index 4849b8e..5d9ae27 100644 (file)
@@ -238,7 +238,7 @@ Description:        Shows current reserved blocks in system, it may be temporarily
 What:          /sys/fs/f2fs/<disk>/gc_urgent
 Date:          August 2017
 Contact:       "Jaegeuk Kim" <jaegeuk@kernel.org>
-Description:   Do background GC agressively when set. When gc_urgent = 1,
+Description:   Do background GC aggressively when set. When gc_urgent = 1,
                background thread starts to do GC by given gc_urgent_sleep_time
                interval. When gc_urgent = 2, F2FS will lower the bar of
                checking idle in order to process outstanding discard commands
index 0fedbb0..eae2f1c 100644 (file)
@@ -25,14 +25,10 @@ Description:    /sys/kernel/iommu_groups/reserved_regions list IOVA
                the base IOVA, the second is the end IOVA and the third
                field describes the type of the region.
 
-What:          /sys/kernel/iommu_groups/reserved_regions
-Date:          June 2019
-KernelVersion:  v5.3
-Contact:       Eric Auger <eric.auger@redhat.com>
-Description:    In case an RMRR is used only by graphics or USB devices
-               it is now exposed as "direct-relaxable" instead of "direct".
-               In device assignment use case, for instance, those RMRR
-               are considered to be relaxable and safe.
+               Since kernel 5.3, in case an RMRR is used only by graphics or
+               USB devices it is now exposed as "direct-relaxable" instead
+               of "direct". In device assignment use case, for instance,
+               those RMRR are considered to be relaxable and safe.
 
 What:          /sys/kernel/iommu_groups/<grp_id>/type
 Date:          November 2020
index 9c42dde..c3feb65 100644 (file)
@@ -76,7 +76,7 @@ quiet_cmd_sphinx = SPHINX  $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
        PYTHONDONTWRITEBYTECODE=1 \
        BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \
        $(PYTHON3) $(srctree)/scripts/jobserver-exec \
-       $(SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \
+       $(CONFIG_SHELL) $(srctree)/Documentation/sphinx/parallel-wrapper.sh \
        $(SPHINXBUILD) \
        -b $2 \
        -c $(abspath $(srctree)/$(src)) \
index 0602170..34c64a5 100644 (file)
@@ -22,9 +22,9 @@ or if the device has INTx interrupts connected by platform interrupt
 controllers and a _PRT is needed to describe those connections.
 
 ACPI resource description is done via _CRS objects of devices in the ACPI
-namespace [2].   The _CRS is like a generalized PCI BAR: the OS can read
+namespace [2].   The _CRS is like a generalized PCI BAR: the OS can read
 _CRS and figure out what resource is being consumed even if it doesn't have
-a driver for the device [3].  That's important because it means an old OS
+a driver for the device [3].  That's important because it means an old OS
 can work correctly even on a system with new devices unknown to the OS.
 The new devices might not do anything, but the OS can at least make sure no
 resources conflict with them.
@@ -41,15 +41,15 @@ ACPI, that device will have a specific _HID/_CID that tells the OS what
 driver to bind to it, and the _CRS tells the OS and the driver where the
 device's registers are.
 
-PCI host bridges are PNP0A03 or PNP0A08 devices.  Their _CRS should
-describe all the address space they consume.  This includes all the windows
+PCI host bridges are PNP0A03 or PNP0A08 devices.  Their _CRS should
+describe all the address space they consume.  This includes all the windows
 they forward down to the PCI bus, as well as registers of the host bridge
-itself that are not forwarded to PCI.  The host bridge registers include
+itself that are not forwarded to PCI.  The host bridge registers include
 things like secondary/subordinate bus registers that determine the bus
 range below the bridge, window registers that describe the apertures, etc.
 These are all device-specific, non-architected things, so the only way a
 PNP0A03/PNP0A08 driver can manage them is via _PRS/_CRS/_SRS, which contain
-the device-specific details.  The host bridge registers also include ECAM
+the device-specific details.  The host bridge registers also include ECAM
 space, since it is consumed by the host bridge.
 
 ACPI defines a Consumer/Producer bit to distinguish the bridge registers
@@ -66,7 +66,7 @@ the PNP0A03/PNP0A08 device itself.  The workaround was to describe the
 bridge registers (including ECAM space) in PNP0C02 catch-all devices [6].
 With the exception of ECAM, the bridge register space is device-specific
 anyway, so the generic PNP0A03/PNP0A08 driver (pci_root.c) has no need to
-know about it.  
+know about it.  
 
 New architectures should be able to use "Consumer" Extended Address Space
 descriptors in the PNP0A03 device for bridge registers, including ECAM,
@@ -75,9 +75,9 @@ ia64 kernels assume all address space descriptors, including "Consumer"
 Extended Address Space ones, are windows, so it would not be safe to
 describe bridge registers this way on those architectures.
 
-PNP0C02 "motherboard" devices are basically a catch-all.  There's no
+PNP0C02 "motherboard" devices are basically a catch-all.  There's no
 programming model for them other than "don't use these resources for
-anything else."  So a PNP0C02 _CRS should claim any address space that is
+anything else."  So a PNP0C02 _CRS should claim any address space that is
 (1) not claimed by _CRS under any other device object in the ACPI namespace
 and (2) should not be assigned by the OS to something else.
 
index 696f8ee..db609b9 100644 (file)
@@ -125,4 +125,4 @@ all the EPF devices are created and linked with the EPC device.
                                                | interrupt_pin
                                                | function
 
-[1] :doc:`pci-endpoint`
+[1] Documentation/PCI/endpoint/pci-endpoint.rst
index 814b40f..fa651e2 100644 (file)
@@ -265,7 +265,7 @@ Set the DMA mask size
 ---------------------
 .. note::
    If anything below doesn't make sense, please refer to
-   :doc:`/core-api/dma-api`. This section is just a reminder that
+   Documentation/core-api/dma-api.rst. This section is just a reminder that
    drivers need to indicate DMA capabilities of the device and is not
    an authoritative source for DMA interfaces.
 
@@ -291,7 +291,7 @@ Many 64-bit "PCI" devices (before PCI-X) and some PCI-X devices are
 Setup shared control data
 -------------------------
 Once the DMA masks are set, the driver can allocate "consistent" (a.k.a. shared)
-memory.  See :doc:`/core-api/dma-api` for a full description of
+memory.  See Documentation/core-api/dma-api.rst for a full description of
 the DMA APIs. This section is just a reminder that it needs to be done
 before enabling DMA on the device.
 
@@ -421,7 +421,7 @@ owners if there is one.
 
 Then clean up "consistent" buffers which contain the control data.
 
-See :doc:`/core-api/dma-api` for details on unmapping interfaces.
+See Documentation/core-api/dma-api.rst for details on unmapping interfaces.
 
 
 Unregister from other subsystems
index 7cc7f58..1b8b46d 100644 (file)
@@ -69,13 +69,15 @@ Compile the kernel with::
        CONFIG_TASK_DELAY_ACCT=y
        CONFIG_TASKSTATS=y
 
-Delay accounting is enabled by default at boot up.
-To disable, add::
+Delay accounting is disabled by default at boot up.
+To enable, add::
 
-   nodelayacct
+   delayacct
 
-to the kernel boot options. The rest of the instructions
-below assume this has not been done.
+to the kernel boot options. The rest of the instructions below assume this has
+been done. Alternatively, use sysctl kernel.task_delayacct to switch the state
+at runtime. Note however that only tasks started after enabling it will have
+delayacct information.
 
 After the system has booted up, use a utility
 similar to  getdelays.c to access the delays
index b90dafc..8632a1d 100644 (file)
@@ -2,87 +2,10 @@
 How CPU topology info is exported via sysfs
 ===========================================
 
-Export CPU topology info via sysfs. Items (attributes) are similar
-to /proc/cpuinfo output of some architectures.  They reside in
-/sys/devices/system/cpu/cpuX/topology/:
-
-physical_package_id:
-
-       physical package id of cpuX. Typically corresponds to a physical
-       socket number, but the actual value is architecture and platform
-       dependent.
-
-die_id:
-
-       the CPU die ID of cpuX. Typically it is the hardware platform's
-       identifier (rather than the kernel's).  The actual value is
-       architecture and platform dependent.
-
-core_id:
-
-       the CPU core ID of cpuX. Typically it is the hardware platform's
-       identifier (rather than the kernel's).  The actual value is
-       architecture and platform dependent.
-
-book_id:
-
-       the book ID of cpuX. Typically it is the hardware platform's
-       identifier (rather than the kernel's).  The actual value is
-       architecture and platform dependent.
-
-drawer_id:
-
-       the drawer ID of cpuX. Typically it is the hardware platform's
-       identifier (rather than the kernel's).  The actual value is
-       architecture and platform dependent.
-
-core_cpus:
-
-       internal kernel map of CPUs within the same core.
-       (deprecated name: "thread_siblings")
-
-core_cpus_list:
-
-       human-readable list of CPUs within the same core.
-       (deprecated name: "thread_siblings_list");
-
-package_cpus:
-
-       internal kernel map of the CPUs sharing the same physical_package_id.
-       (deprecated name: "core_siblings")
-
-package_cpus_list:
-
-       human-readable list of CPUs sharing the same physical_package_id.
-       (deprecated name: "core_siblings_list")
-
-die_cpus:
-
-       internal kernel map of CPUs within the same die.
-
-die_cpus_list:
-
-       human-readable list of CPUs within the same die.
-
-book_siblings:
-
-       internal kernel map of cpuX's hardware threads within the same
-       book_id.
-
-book_siblings_list:
-
-       human-readable list of cpuX's hardware threads within the same
-       book_id.
-
-drawer_siblings:
-
-       internal kernel map of cpuX's hardware threads within the same
-       drawer_id.
-
-drawer_siblings_list:
-
-       human-readable list of cpuX's hardware threads within the same
-       drawer_id.
+CPU topology info is exported via sysfs. Items (attributes) are similar
+to /proc/cpuinfo output of some architectures. They reside in
+/sys/devices/system/cpu/cpuX/topology/. Please refer to the ABI file:
+Documentation/ABI/stable/sysfs-devices-system-cpu.
 
 Architecture-neutral, drivers/base/topology.c, exports these attributes.
 However, the book and drawer related sysfs files will only be created if
index d2795ca..4c559e0 100644 (file)
@@ -392,7 +392,7 @@ When mounting an ext4 filesystem, the following option are accepted:
 
   dax
         Use direct access (no page cache).  See
-        Documentation/filesystems/dax.txt.  Note that this option is
+        Documentation/filesystems/dax.rst.  Note that this option is
         incompatible with data=journal.
 
   inlinecrypt
diff --git a/Documentation/admin-guide/hw-vuln/core-scheduling.rst b/Documentation/admin-guide/hw-vuln/core-scheduling.rst
new file mode 100644 (file)
index 0000000..7b410ae
--- /dev/null
@@ -0,0 +1,223 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+Core Scheduling
+===============
+Core scheduling support allows userspace to define groups of tasks that can
+share a core. These groups can be specified either for security usecases (one
+group of tasks don't trust another), or for performance usecases (some
+workloads may benefit from running on the same core as they don't need the same
+hardware resources of the shared core, or may prefer different cores if they
+do share hardware resource needs). This document only describes the security
+usecase.
+
+Security usecase
+----------------
+A cross-HT attack involves the attacker and victim running on different Hyper
+Threads of the same core. MDS and L1TF are examples of such attacks.  The only
+full mitigation of cross-HT attacks is to disable Hyper Threading (HT). Core
+scheduling is a scheduler feature that can mitigate some (not all) cross-HT
+attacks. It allows HT to be turned on safely by ensuring that only tasks in a
+user-designated trusted group can share a core. This increase in core sharing
+can also improve performance, however it is not guaranteed that performance
+will always improve, though that is seen to be the case with a number of real
+world workloads. In theory, core scheduling aims to perform at least as good as
+when Hyper Threading is disabled. In practice, this is mostly the case though
+not always: as synchronizing scheduling decisions across 2 or more CPUs in a
+core involves additional overhead - especially when the system is lightly
+loaded. When ``total_threads <= N_CPUS/2``, the extra overhead may cause core
+scheduling to perform more poorly compared to SMT-disabled, where N_CPUS is the
+total number of CPUs. Please measure the performance of your workloads always.
+
+Usage
+-----
+Core scheduling support is enabled via the ``CONFIG_SCHED_CORE`` config option.
+Using this feature, userspace defines groups of tasks that can be co-scheduled
+on the same core. The core scheduler uses this information to make sure that
+tasks that are not in the same group never run simultaneously on a core, while
+doing its best to satisfy the system's scheduling requirements.
+
+Core scheduling can be enabled via the ``PR_SCHED_CORE`` prctl interface.
+This interface provides support for the creation of core scheduling groups, as
+well as admission and removal of tasks from created groups::
+
+    #include <sys/prctl.h>
+
+    int prctl(int option, unsigned long arg2, unsigned long arg3,
+            unsigned long arg4, unsigned long arg5);
+
+option:
+    ``PR_SCHED_CORE``
+
+arg2:
+    Command for operation, must be one off:
+
+    - ``PR_SCHED_CORE_GET`` -- get core_sched cookie of ``pid``.
+    - ``PR_SCHED_CORE_CREATE`` -- create a new unique cookie for ``pid``.
+    - ``PR_SCHED_CORE_SHARE_TO`` -- push core_sched cookie to ``pid``.
+    - ``PR_SCHED_CORE_SHARE_FROM`` -- pull core_sched cookie from ``pid``.
+
+arg3:
+    ``pid`` of the task for which the operation applies.
+
+arg4:
+    ``pid_type`` for which the operation applies. It is of type ``enum pid_type``.
+    For example, if arg4 is ``PIDTYPE_TGID``, then the operation of this command
+    will be performed for all tasks in the task group of ``pid``.
+
+arg5:
+    userspace pointer to an unsigned long for storing the cookie returned by
+    ``PR_SCHED_CORE_GET`` command. Should be 0 for all other commands.
+
+In order for a process to push a cookie to, or pull a cookie from a process, it
+is required to have the ptrace access mode: `PTRACE_MODE_READ_REALCREDS` to the
+process.
+
+Building hierarchies of tasks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The simplest way to build hierarchies of threads/processes which share a
+cookie and thus a core is to rely on the fact that the core-sched cookie is
+inherited across forks/clones and execs, thus setting a cookie for the
+'initial' script/executable/daemon will place every spawned child in the
+same core-sched group.
+
+Cookie Transferral
+~~~~~~~~~~~~~~~~~~
+Transferring a cookie between the current and other tasks is possible using
+PR_SCHED_CORE_SHARE_FROM and PR_SCHED_CORE_SHARE_TO to inherit a cookie from a
+specified task or a share a cookie with a task. In combination this allows a
+simple helper program to pull a cookie from a task in an existing core
+scheduling group and share it with already running tasks.
+
+Design/Implementation
+---------------------
+Each task that is tagged is assigned a cookie internally in the kernel. As
+mentioned in `Usage`_, tasks with the same cookie value are assumed to trust
+each other and share a core.
+
+The basic idea is that, every schedule event tries to select tasks for all the
+siblings of a core such that all the selected tasks running on a core are
+trusted (same cookie) at any point in time. Kernel threads are assumed trusted.
+The idle task is considered special, as it trusts everything and everything
+trusts it.
+
+During a schedule() event on any sibling of a core, the highest priority task on
+the sibling's core is picked and assigned to the sibling calling schedule(), if
+the sibling has the task enqueued. For rest of the siblings in the core,
+highest priority task with the same cookie is selected if there is one runnable
+in their individual run queues. If a task with same cookie is not available,
+the idle task is selected.  Idle task is globally trusted.
+
+Once a task has been selected for all the siblings in the core, an IPI is sent to
+siblings for whom a new task was selected. Siblings on receiving the IPI will
+switch to the new task immediately. If an idle task is selected for a sibling,
+then the sibling is considered to be in a `forced idle` state. I.e., it may
+have tasks on its on runqueue to run, however it will still have to run idle.
+More on this in the next section.
+
+Forced-idling of hyperthreads
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The scheduler tries its best to find tasks that trust each other such that all
+tasks selected to be scheduled are of the highest priority in a core.  However,
+it is possible that some runqueues had tasks that were incompatible with the
+highest priority ones in the core. Favoring security over fairness, one or more
+siblings could be forced to select a lower priority task if the highest
+priority task is not trusted with respect to the core wide highest priority
+task.  If a sibling does not have a trusted task to run, it will be forced idle
+by the scheduler (idle thread is scheduled to run).
+
+When the highest priority task is selected to run, a reschedule-IPI is sent to
+the sibling to force it into idle. This results in 4 cases which need to be
+considered depending on whether a VM or a regular usermode process was running
+on either HT::
+
+          HT1 (attack)            HT2 (victim)
+   A      idle -> user space      user space -> idle
+   B      idle -> user space      guest -> idle
+   C      idle -> guest           user space -> idle
+   D      idle -> guest           guest -> idle
+
+Note that for better performance, we do not wait for the destination CPU
+(victim) to enter idle mode. This is because the sending of the IPI would bring
+the destination CPU immediately into kernel mode from user space, or VMEXIT
+in the case of guests. At best, this would only leak some scheduler metadata
+which may not be worth protecting. It is also possible that the IPI is received
+too late on some architectures, but this has not been observed in the case of
+x86.
+
+Trust model
+~~~~~~~~~~~
+Core scheduling maintains trust relationships amongst groups of tasks by
+assigning them a tag that is the same cookie value.
+When a system with core scheduling boots, all tasks are considered to trust
+each other. This is because the core scheduler does not have information about
+trust relationships until userspace uses the above mentioned interfaces, to
+communicate them. In other words, all tasks have a default cookie value of 0.
+and are considered system-wide trusted. The forced-idling of siblings running
+cookie-0 tasks is also avoided.
+
+Once userspace uses the above mentioned interfaces to group sets of tasks, tasks
+within such groups are considered to trust each other, but do not trust those
+outside. Tasks outside the group also don't trust tasks within.
+
+Limitations of core-scheduling
+------------------------------
+Core scheduling tries to guarantee that only trusted tasks run concurrently on a
+core. But there could be small window of time during which untrusted tasks run
+concurrently or kernel could be running concurrently with a task not trusted by
+kernel.
+
+IPI processing delays
+~~~~~~~~~~~~~~~~~~~~~
+Core scheduling selects only trusted tasks to run together. IPI is used to notify
+the siblings to switch to the new task. But there could be hardware delays in
+receiving of the IPI on some arch (on x86, this has not been observed). This may
+cause an attacker task to start running on a CPU before its siblings receive the
+IPI. Even though cache is flushed on entry to user mode, victim tasks on siblings
+may populate data in the cache and micro architectural buffers after the attacker
+starts to run and this is a possibility for data leak.
+
+Open cross-HT issues that core scheduling does not solve
+--------------------------------------------------------
+1. For MDS
+~~~~~~~~~~
+Core scheduling cannot protect against MDS attacks between an HT running in
+user mode and another running in kernel mode. Even though both HTs run tasks
+which trust each other, kernel memory is still considered untrusted. Such
+attacks are possible for any combination of sibling CPU modes (host or guest mode).
+
+2. For L1TF
+~~~~~~~~~~~
+Core scheduling cannot protect against an L1TF guest attacker exploiting a
+guest or host victim. This is because the guest attacker can craft invalid
+PTEs which are not inverted due to a vulnerable guest kernel. The only
+solution is to disable EPT (Extended Page Tables).
+
+For both MDS and L1TF, if the guest vCPU is configured to not trust each
+other (by tagging separately), then the guest to guest attacks would go away.
+Or it could be a system admin policy which considers guest to guest attacks as
+a guest problem.
+
+Another approach to resolve these would be to make every untrusted task on the
+system to not trust every other untrusted task. While this could reduce
+parallelism of the untrusted tasks, it would still solve the above issues while
+allowing system processes (trusted tasks) to share a core.
+
+3. Protecting the kernel (IRQ, syscall, VMEXIT)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Unfortunately, core scheduling does not protect kernel contexts running on
+sibling hyperthreads from one another. Prototypes of mitigations have been posted
+to LKML to solve this, but it is debatable whether such windows are practically
+exploitable, and whether the performance overhead of the prototypes are worth
+it (not to mention, the added code complexity).
+
+Other Use cases
+---------------
+The main use case for Core scheduling is mitigating the cross-HT vulnerabilities
+with SMT enabled. There are other use cases where this feature could be used:
+
+- Isolating tasks that needs a whole core: Examples include realtime tasks, tasks
+  that uses SIMD instructions etc.
+- Gang scheduling: Requirements for a group of tasks that needs to be scheduled
+  together could also be realized using core scheduling. One example is vCPUs of
+  a VM.
index ca4dbdd..f12cda5 100644 (file)
@@ -15,3 +15,4 @@ are configurable at compile, boot or run time.
    tsx_async_abort
    multihit.rst
    special-register-buffer-data-sampling.rst
+   core-scheduling.rst
index 3b1ce68..966c9b3 100644 (file)
@@ -3,7 +3,8 @@
 SRBDS - Special Register Buffer Data Sampling
 =============================================
 
-SRBDS is a hardware vulnerability that allows MDS :doc:`mds` techniques to
+SRBDS is a hardware vulnerability that allows MDS
+Documentation/admin-guide/hw-vuln/mds.rst techniques to
 infer values returned from special register accesses.  Special register
 accesses are accesses to off core registers.  According to Intel's evaluation,
 the special register reads that have a security expectation of privacy are
index 75a9dd9..cb30ca3 100644 (file)
@@ -2,7 +2,7 @@
 Documentation for Kdump - The kexec-based Crash Dumping Solution
 ================================================================
 
-This document includes overview, setup and installation, and analysis
+This document includes overview, setup, installation, and analysis
 information.
 
 Overview
@@ -13,9 +13,9 @@ dump of the system kernel's memory needs to be taken (for example, when
 the system panics). The system kernel's memory image is preserved across
 the reboot and is accessible to the dump-capture kernel.
 
-You can use common commands, such as cp and scp, to copy the
-memory image to a dump file on the local disk, or across the network to
-a remote system.
+You can use common commands, such as cp, scp or makedumpfile to copy
+the memory image to a dump file on the local disk, or across the network
+to a remote system.
 
 Kdump and kexec are currently supported on the x86, x86_64, ppc64, ia64,
 s390x, arm and arm64 architectures.
@@ -26,13 +26,15 @@ the dump-capture kernel. This ensures that ongoing Direct Memory Access
 The kexec -p command loads the dump-capture kernel into this reserved
 memory.
 
-On x86 machines, the first 640 KB of physical memory is needed to boot,
-regardless of where the kernel loads. Therefore, kexec backs up this
-region just before rebooting into the dump-capture kernel.
+On x86 machines, the first 640 KB of physical memory is needed for boot,
+regardless of where the kernel loads. For simpler handling, the whole
+low 1M is reserved to avoid any later kernel or device driver writing
+data into this area. Like this, the low 1M can be reused as system RAM
+by kdump kernel without extra handling.
 
-Similarly on PPC64 machines first 32KB of physical memory is needed for
-booting regardless of where the kernel is loaded and to support 64K page
-size kexec backs up the first 64KB memory.
+On PPC64 machines first 32KB of physical memory is needed for booting
+regardless of where the kernel is loaded and to support 64K page size
+kexec backs up the first 64KB memory.
 
 For s390x, when kdump is triggered, the crashkernel region is exchanged
 with the region [0, crashkernel region size] and then the kdump kernel
@@ -46,14 +48,14 @@ passed to the dump-capture kernel through the elfcorehdr= boot
 parameter. Optionally the size of the ELF header can also be passed
 when using the elfcorehdr=[size[KMG]@]offset[KMG] syntax.
 
-
 With the dump-capture kernel, you can access the memory image through
 /proc/vmcore. This exports the dump as an ELF-format file that you can
-write out using file copy commands such as cp or scp. Further, you can
-use analysis tools such as the GNU Debugger (GDB) and the Crash tool to
-debug the dump file. This method ensures that the dump pages are correctly
-ordered.
-
+write out using file copy commands such as cp or scp. You can also use
+makedumpfile utility to analyze and write out filtered contents with
+options, e.g with '-d 31' it will only write out kernel data. Further,
+you can use analysis tools such as the GNU Debugger (GDB) and the Crash
+tool to debug the dump file. This method ensures that the dump pages are
+correctly ordered.
 
 Setup and Installation
 ======================
@@ -125,9 +127,18 @@ dump-capture kernels for enabling kdump support.
 System kernel config options
 ----------------------------
 
-1) Enable "kexec system call" in "Processor type and features."::
+1) Enable "kexec system call" or "kexec file based system call" in
+   "Processor type and features."::
+
+       CONFIG_KEXEC=y or CONFIG_KEXEC_FILE=y
+
+   And both of them will select KEXEC_CORE::
 
-       CONFIG_KEXEC=y
+       CONFIG_KEXEC_CORE=y
+
+   Subsequently, CRASH_CORE is selected by KEXEC_CORE::
+
+       CONFIG_CRASH_CORE=y
 
 2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo
    filesystems." This is usually enabled by default::
@@ -175,17 +186,19 @@ Dump-capture kernel config options (Arch Dependent, i386 and x86_64)
 
        CONFIG_HIGHMEM4G
 
-2) On i386 and x86_64, disable symmetric multi-processing support
-   under "Processor type and features"::
+2) With CONFIG_SMP=y, usually nr_cpus=1 need specified on the kernel
+   command line when loading the dump-capture kernel because one
+   CPU is enough for kdump kernel to dump vmcore on most of systems.
 
-       CONFIG_SMP=n
+   However, you can also specify nr_cpus=X to enable multiple processors
+   in kdump kernel. In this case, "disable_cpu_apicid=" is needed to
+   tell kdump kernel which cpu is 1st kernel's BSP. Please refer to
+   admin-guide/kernel-parameters.txt for more details.
 
-   (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
-   when loading the dump-capture kernel, see section "Load the Dump-capture
-   Kernel".)
+   With CONFIG_SMP=n, the above things are not related.
 
-3) If one wants to build and use a relocatable kernel,
-   Enable "Build a relocatable kernel" support under "Processor type and
+3) A relocatable kernel is suggested to be built by default. If not yet,
+   enable "Build a relocatable kernel" support under "Processor type and
    features"::
 
        CONFIG_RELOCATABLE=y
@@ -232,7 +245,7 @@ Dump-capture kernel config options (Arch Dependent, ia64)
   as a dump-capture kernel if desired.
 
   The crashkernel region can be automatically placed by the system
-  kernel at run time. This is done by specifying the base address as 0,
+  kernel at runtime. This is done by specifying the base address as 0,
   or omitting it all together::
 
        crashkernel=256M@0
@@ -241,10 +254,6 @@ Dump-capture kernel config options (Arch Dependent, ia64)
 
        crashkernel=256M
 
-  If the start address is specified, note that the start address of the
-  kernel will be aligned to 64Mb, so if the start address is not then
-  any space below the alignment point will be wasted.
-
 Dump-capture kernel config options (Arch Dependent, arm)
 ----------------------------------------------------------
 
@@ -260,46 +269,82 @@ Dump-capture kernel config options (Arch Dependent, arm64)
   on non-VHE systems even if it is configured. This is because the CPU
   will not be reset to EL2 on panic.
 
-Extended crashkernel syntax
+crashkernel syntax
 ===========================
+1) crashkernel=size@offset
 
-While the "crashkernel=size[@offset]" syntax is sufficient for most
-configurations, sometimes it's handy to have the reserved memory dependent
-on the value of System RAM -- that's mostly for distributors that pre-setup
-the kernel command line to avoid a unbootable system after some memory has
-been removed from the machine.
+   Here 'size' specifies how much memory to reserve for the dump-capture kernel
+   and 'offset' specifies the beginning of this reserved memory. For example,
+   "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
+   starting at physical address 0x01000000 (16MB) for the dump-capture kernel.
 
-The syntax is::
+   The crashkernel region can be automatically placed by the system
+   kernel at run time. This is done by specifying the base address as 0,
+   or omitting it all together::
 
-    crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
-    range=start-[end]
+         crashkernel=256M@0
 
-For example::
+   or::
 
-    crashkernel=512M-2G:64M,2G-:128M
+         crashkernel=256M
 
-This would mean:
+   If the start address is specified, note that the start address of the
+   kernel will be aligned to a value (which is Arch dependent), so if the
+   start address is not then any space below the alignment point will be
+   wasted.
 
-    1) if the RAM is smaller than 512M, then don't reserve anything
-       (this is the "rescue" case)
-    2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
-    3) if the RAM size is larger than 2G, then reserve 128M
+2) range1:size1[,range2:size2,...][@offset]
 
+   While the "crashkernel=size[@offset]" syntax is sufficient for most
+   configurations, sometimes it's handy to have the reserved memory dependent
+   on the value of System RAM -- that's mostly for distributors that pre-setup
+   the kernel command line to avoid a unbootable system after some memory has
+   been removed from the machine.
 
+   The syntax is::
 
-Boot into System Kernel
-=======================
+       crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
+       range=start-[end]
+
+   For example::
+
+       crashkernel=512M-2G:64M,2G-:128M
 
+   This would mean:
+
+       1) if the RAM is smaller than 512M, then don't reserve anything
+          (this is the "rescue" case)
+       2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
+       3) if the RAM size is larger than 2G, then reserve 128M
+
+3) crashkernel=size,high and crashkernel=size,low
+
+   If memory above 4G is preferred, crashkernel=size,high can be used to
+   fulfill that. With it, physical memory is allowed to be allocated from top,
+   so could be above 4G if system has more than 4G RAM installed. Otherwise,
+   memory region will be allocated below 4G if available.
+
+   When crashkernel=X,high is passed, kernel could allocate physical memory
+   region above 4G, low memory under 4G is needed in this case. There are
+   three ways to get low memory:
+
+      1) Kernel will allocate at least 256M memory below 4G automatically
+         if crashkernel=Y,low is not specified.
+      2) Let user specify low memory size instead.
+      3) Specified value 0 will disable low memory allocation::
+
+            crashkernel=0,low
+
+Boot into System Kernel
+-----------------------
 1) Update the boot loader (such as grub, yaboot, or lilo) configuration
    files as necessary.
 
-2) Boot the system kernel with the boot parameter "crashkernel=Y@X",
-   where Y specifies how much memory to reserve for the dump-capture kernel
-   and X specifies the beginning of this reserved memory. For example,
-   "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
-   starting at physical address 0x01000000 (16MB) for the dump-capture kernel.
+2) Boot the system kernel with the boot parameter "crashkernel=Y@X".
 
-   On x86 and x86_64, use "crashkernel=64M@16M".
+   On x86 and x86_64, use "crashkernel=Y[@X]". Most of the time, the
+   start address 'X' is not necessary, kernel will search a suitable
+   area. Unless an explicit start address is expected.
 
    On ppc64, use "crashkernel=128M@32M".
 
@@ -331,8 +376,8 @@ of dump-capture kernel. Following is the summary.
 
 For i386 and x86_64:
 
-       - Use vmlinux if kernel is not relocatable.
        - Use bzImage/vmlinuz if kernel is relocatable.
+       - Use vmlinux if kernel is not relocatable.
 
 For ppc64:
 
@@ -392,7 +437,7 @@ loading dump-capture kernel.
 
 For i386, x86_64 and ia64:
 
-       "1 irqpoll maxcpus=1 reset_devices"
+       "1 irqpoll nr_cpus=1 reset_devices"
 
 For ppc64:
 
@@ -400,7 +445,7 @@ For ppc64:
 
 For s390x:
 
-       "1 maxcpus=1 cgroup_disable=memory"
+       "1 nr_cpus=1 cgroup_disable=memory"
 
 For arm:
 
@@ -408,7 +453,7 @@ For arm:
 
 For arm64:
 
-       "1 maxcpus=1 reset_devices"
+       "1 nr_cpus=1 reset_devices"
 
 Notes on loading the dump-capture kernel:
 
@@ -488,6 +533,10 @@ the following command::
 
    cp /proc/vmcore <dump-file>
 
+You can also use makedumpfile utility to write out the dump file
+with specified options to filter out unwanted contents, e.g::
+
+   makedumpfile -l --message-level 1 -d 31 /proc/vmcore <dump-file>
 
 Analysis
 ========
@@ -535,8 +584,7 @@ This will cause a kdump to occur at the add_taint()->panic() call.
 Contact
 =======
 
-- Vivek Goyal (vgoyal@redhat.com)
-- Maneesh Soni (maneesh@in.ibm.com)
+- kexec@lists.infradead.org
 
 GDB macros
 ==========
index a161e58..fed6c30 100644 (file)
                        loops can be debugged more effectively on production
                        systems.
 
+       clocksource.max_cswd_read_retries= [KNL]
+                       Number of clocksource_watchdog() retries due to
+                       external delays before the clock will be marked
+                       unstable.  Defaults to three retries, that is,
+                       four attempts to read the clock under test.
+
+       clocksource.verify_n_cpus= [KNL]
+                       Limit the number of CPUs checked for clocksources
+                       marked with CLOCK_SOURCE_VERIFY_PERCPU that
+                       are marked unstable due to excessive skew.
+                       A negative value says to check all CPUs, while
+                       zero says not to check any.  Values larger than
+                       nr_cpu_ids are silently truncated to nr_cpu_ids.
+                       The actual CPUs are chosen randomly, with
+                       no replacement if the same CPU is chosen twice.
+
+       clocksource-wdtest.holdoff= [KNL]
+                       Set the time in seconds that the clocksource
+                       watchdog test waits before commencing its tests.
+                       Defaults to zero when built as a module and to
+                       10 seconds when built into the kernel.
+
        clearcpuid=BITNUM[,BITNUM...] [X86]
                        Disable CPUID feature X for the kernel. See
                        arch/x86/include/asm/cpufeatures.h for the valid bit
 
        noclflush       [BUGS=X86] Don't use the CLFLUSH instruction
 
-       nodelayacct     [KNL] Disable per-task delay accounting
+       delayacct       [KNL] Enable per-task delay accounting
 
        nodsp           [SH] Disable hardware DSP at boot time.
 
 
        nr_uarts=       [SERIAL] maximum number of UARTs to be registered.
 
+       numa=off        [KNL, ARM64, PPC, RISCV, SPARC, X86] Disable NUMA, Only
+                       set up a single NUMA node spanning all memory.
+
        numa_balancing= [KNL,ARM64,PPC,RISCV,S390,X86] Enable or disable automatic
                        NUMA balancing.
                        Allowed values are enable and disable
                        Reserves a hole at the top of the kernel virtual
                        address space.
 
-       reservelow=     [X86]
-                       Format: nn[K]
-                       Set the amount of memory to reserve for BIOS at
-                       the bottom of the address space.
-
        reset_devices   [KNL] Force drivers to reset the underlying device
                        during initialization.
 
                                  exception. Default behavior is by #AC if
                                  both features are enabled in hardware.
 
+                       ratelimit:N -
+                                 Set system wide rate limit to N bus locks
+                                 per second for bus lock detection.
+                                 0 < N <= 1000.
+
+                                 N/A for split lock detection.
+
+
                        If an #AC exception is hit in the kernel or in
                        firmware (i.e. not while executing in user mode)
                        the kernel will oops in either "warn" or "fatal"
index 1382ada..3589f6a 100644 (file)
@@ -15,11 +15,12 @@ Authors:
 General information
 -------------------
 
-This class of cards has a bt878a as the PCI interface, and require the bttv driver
-for accessing the i2c bus and the gpio pins of the bt8xx chipset.
+This class of cards has a bt878a as the PCI interface, and require the bttv
+driver for accessing the i2c bus and the gpio pins of the bt8xx chipset.
 
-Please see :doc:`bttv-cardlist` for a complete list of Cards based on the
-Conexant Bt8xx PCI bridge supported by the Linux Kernel.
+Please see Documentation/admin-guide/media/bttv-cardlist.rst for a complete
+list of Cards based on the Conexant Bt8xx PCI bridge supported by the
+Linux Kernel.
 
 In order to be able to compile the kernel, some config options should be
 enabled::
@@ -80,7 +81,7 @@ for dvb-bt8xx drivers by passing modprobe parameters may be necessary.
 Running TwinHan and Clones
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-As shown at :doc:`bttv-cardlist`, TwinHan and
+As shown at Documentation/admin-guide/media/bttv-cardlist.rst, TwinHan and
 clones use ``card=113`` modprobe parameter. So, in order to properly
 detect it for devices without EEPROM, you should use::
 
@@ -105,12 +106,12 @@ The autodetected values are determined by the cards' "response string".
 In your logs see f. ex.: dst_get_device_id: Recognize [DSTMCI].
 
 For bug reports please send in a complete log with verbose=4 activated.
-Please also see :doc:`ci`.
+Please also see Documentation/admin-guide/media/ci.rst.
 
 Running multiple cards
 ~~~~~~~~~~~~~~~~~~~~~~
 
-See :doc:`bttv-cardlist` for a complete list of
+See Documentation/admin-guide/media/bttv-cardlist.rst for a complete list of
 Card ID. Some examples:
 
        ===========================     ===
index 0ef1f20..125f6f4 100644 (file)
@@ -24,7 +24,8 @@ If your board has digital TV, you'll also need::
 
     ./scripts/config -m DVB_BT8XX
 
-In this case, please see :doc:`bt8xx` for additional notes.
+In this case, please see Documentation/admin-guide/media/bt8xx.rst
+for additional notes.
 
 Make bttv work with your card
 -----------------------------
@@ -39,7 +40,7 @@ If it doesn't bttv likely could not autodetect your card and needs some
 insmod options.  The most important insmod option for bttv is "card=n"
 to select the correct card type.  If you get video but no sound you've
 very likely specified the wrong (or no) card type.  A list of supported
-cards is in :doc:`bttv-cardlist`.
+cards is in Documentation/admin-guide/media/bttv-cardlist.rst.
 
 If bttv takes very long to load (happens sometimes with the cheap
 cards which have no tuner), try adding this to your modules configuration
@@ -57,8 +58,8 @@ directory should be enough for it to be autoload during the driver's
 probing mode (e. g. when the Kernel boots or when the driver is
 manually loaded via ``modprobe`` command).
 
-If your card isn't listed in :doc:`bttv-cardlist` or if you have
-trouble making audio work, please read :ref:`still_doesnt_work`.
+If your card isn't listed in Documentation/admin-guide/media/bttv-cardlist.rst
+or if you have trouble making audio work, please read :ref:`still_doesnt_work`.
 
 
 Autodetecting cards
@@ -77,8 +78,8 @@ the Subsystem ID in the second line, looks like this:
 only bt878-based cards can have a subsystem ID (which does not mean
 that every card really has one).  bt848 cards can't have a Subsystem
 ID and therefore can't be autodetected.  There is a list with the ID's
-at :doc:`bttv-cardlist` (in case you are interested or want to mail
-patches with updates).
+at Documentation/admin-guide/media/bttv-cardlist.rst
+(in case you are interested or want to mail patches with updates).
 
 
 .. _still_doesnt_work:
@@ -259,15 +260,15 @@ bug.  It is very helpful if you can tell where exactly it broke
 With a hard freeze you probably doesn't find anything in the logfiles.
 The only way to capture any kernel messages is to hook up a serial
 console and let some terminal application log the messages.  /me uses
-screen.  See :doc:`/admin-guide/serial-console` for details on setting
-up a serial console.
+screen.  See Documentation/admin-guide/serial-console.rst for details on
+setting up a serial console.
 
-Read :doc:`/admin-guide/bug-hunting` to learn how to get any useful
+Read Documentation/admin-guide/bug-hunting.rst to learn how to get any useful
 information out of a register+stack dump printed by the kernel on
 protection faults (so-called "kernel oops").
 
 If you run into some kind of deadlock, you can try to dump a call trace
-for each process using sysrq-t (see :doc:`/admin-guide/sysrq`).
+for each process using sysrq-t (see Documentation/admin-guide/sysrq.rst).
 This way it is possible to figure where *exactly* some process in "D"
 state is stuck.
 
index 6e0d2ba..c676af6 100644 (file)
@@ -11,12 +11,14 @@ its supported drivers.
 
 Please see:
 
-- :doc:`/userspace-api/media/index`
-     for the userspace APIs used on media devices.
+Documentation/userspace-api/media/index.rst
 
-- :doc:`/driver-api/media/index`
-     for driver development information and Kernel APIs used by
-     media devices;
+  - for the userspace APIs used on media devices.
+
+Documentation/driver-api/media/index.rst
+
+  - for driver development information and Kernel APIs used by
+    media devices;
 
 The media subsystem
 ===================
index f59697c..52c1c04 100644 (file)
@@ -234,22 +234,23 @@ The IPU3 ImgU pipelines can be configured using the Media Controller, defined at
 Running mode and firmware binary selection
 ------------------------------------------
 
-ImgU works based on firmware, currently the ImgU firmware support run 2 pipes in
-time-sharing with single input frame data. Each pipe can run at certain mode -
-"VIDEO" or "STILL", "VIDEO" mode is commonly used for video frames capture, and
-"STILL" is used for still frame capture. However, you can also select "VIDEO" to
-capture still frames if you want to capture images with less system load and
-power. For "STILL" mode, ImgU will try to use smaller BDS factor and output
-larger bayer frame for further YUV processing than "VIDEO" mode to get high
-quality images. Besides, "STILL" mode need XNR3 to do noise reduction, hence
-"STILL" mode will need more power and memory bandwidth than "VIDEO" mode. TNR
-will be enabled in "VIDEO" mode and bypassed by "STILL" mode. ImgU is running at
-“VIDEO” mode by default, the user can use v4l2 control V4L2_CID_INTEL_IPU3_MODE
-(currently defined in drivers/staging/media/ipu3/include/intel-ipu3.h) to query
-and set the running mode. For user, there is no difference for buffer queueing
-between the "VIDEO" and "STILL" mode, mandatory input and main output node
-should be enabled and buffers need be queued, the statistics and the view-finder
-queues are optional.
+ImgU works based on firmware, currently the ImgU firmware support run 2 pipes
+in time-sharing with single input frame data. Each pipe can run at certain mode
+- "VIDEO" or "STILL", "VIDEO" mode is commonly used for video frames capture,
+and "STILL" is used for still frame capture. However, you can also select
+"VIDEO" to capture still frames if you want to capture images with less system
+load and power. For "STILL" mode, ImgU will try to use smaller BDS factor and
+output larger bayer frame for further YUV processing than "VIDEO" mode to get
+high quality images. Besides, "STILL" mode need XNR3 to do noise reduction,
+hence "STILL" mode will need more power and memory bandwidth than "VIDEO" mode.
+TNR will be enabled in "VIDEO" mode and bypassed by "STILL" mode. ImgU is
+running at "VIDEO" mode by default, the user can use v4l2 control
+V4L2_CID_INTEL_IPU3_MODE (currently defined in
+drivers/staging/media/ipu3/include/uapi/intel-ipu3.h) to query and set the
+running mode. For user, there is no difference for buffer queueing between the
+"VIDEO" and "STILL" mode, mandatory input and main output node should be
+enabled and buffers need be queued, the statistics and the view-finder queues
+are optional.
 
 The firmware binary will be selected according to current running mode, such log
 "using binary if_to_osys_striped " or "using binary if_to_osys_primary_striped"
@@ -586,7 +587,7 @@ preserved.
 References
 ==========
 
-.. [#f5] drivers/staging/media/ipu3/include/intel-ipu3.h
+.. [#f5] drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
 
 .. [#f1] https://github.com/intel/nvt
 
index 7ab9c70..51eae7e 100644 (file)
@@ -50,7 +50,8 @@ To build and install, you should run::
 Once the new Kernel is booted, saa7134 driver should be loaded automatically.
 
 Depending on the card you might have to pass ``card=<nr>`` as insmod option.
-If so, please check :doc:`saa7134-cardlist` for valid choices.
+If so, please check Documentation/admin-guide/media/saa7134-cardlist.rst
+for valid choices.
 
 Once you have your card type number, you can pass a modules configuration
 via a file (usually, it is either ``/etc/modules.conf`` or some file at
index 10fde58..aec2cd2 100644 (file)
@@ -347,81 +347,8 @@ for tickless systems.  It follows the same basic strategy as the ``menu`` `one
 <menu-gov_>`_: it always tries to find the deepest idle state suitable for the
 given conditions.  However, it applies a different approach to that problem.
 
-First, it does not use sleep length correction factors, but instead it attempts
-to correlate the observed idle duration values with the available idle states
-and use that information to pick up the idle state that is most likely to
-"match" the upcoming CPU idle interval.   Second, it does not take the tasks
-that were running on the given CPU in the past and are waiting on some I/O
-operations to complete now at all (there is no guarantee that they will run on
-the same CPU when they become runnable again) and the pattern detection code in
-it avoids taking timer wakeups into account.  It also only uses idle duration
-values less than the current time till the closest timer (with the scheduler
-tick excluded) for that purpose.
-
-Like in the ``menu`` governor `case <menu-gov_>`_, the first step is to obtain
-the *sleep length*, which is the time until the closest timer event with the
-assumption that the scheduler tick will be stopped (that also is the upper bound
-on the time until the next CPU wakeup).  That value is then used to preselect an
-idle state on the basis of three metrics maintained for each idle state provided
-by the ``CPUIdle`` driver: ``hits``, ``misses`` and ``early_hits``.
-
-The ``hits`` and ``misses`` metrics measure the likelihood that a given idle
-state will "match" the observed (post-wakeup) idle duration if it "matches" the
-sleep length.  They both are subject to decay (after a CPU wakeup) every time
-the target residency of the idle state corresponding to them is less than or
-equal to the sleep length and the target residency of the next idle state is
-greater than the sleep length (that is, when the idle state corresponding to
-them "matches" the sleep length).  The ``hits`` metric is increased if the
-former condition is satisfied and the target residency of the given idle state
-is less than or equal to the observed idle duration and the target residency of
-the next idle state is greater than the observed idle duration at the same time
-(that is, it is increased when the given idle state "matches" both the sleep
-length and the observed idle duration).  In turn, the ``misses`` metric is
-increased when the given idle state "matches" the sleep length only and the
-observed idle duration is too short for its target residency.
-
-The ``early_hits`` metric measures the likelihood that a given idle state will
-"match" the observed (post-wakeup) idle duration if it does not "match" the
-sleep length.  It is subject to decay on every CPU wakeup and it is increased
-when the idle state corresponding to it "matches" the observed (post-wakeup)
-idle duration and the target residency of the next idle state is less than or
-equal to the sleep length (i.e. the idle state "matching" the sleep length is
-deeper than the given one).
-
-The governor walks the list of idle states provided by the ``CPUIdle`` driver
-and finds the last (deepest) one with the target residency less than or equal
-to the sleep length.  Then, the ``hits`` and ``misses`` metrics of that idle
-state are compared with each other and it is preselected if the ``hits`` one is
-greater (which means that that idle state is likely to "match" the observed idle
-duration after CPU wakeup).  If the ``misses`` one is greater, the governor
-preselects the shallower idle state with the maximum ``early_hits`` metric
-(or if there are multiple shallower idle states with equal ``early_hits``
-metric which also is the maximum, the shallowest of them will be preselected).
-[If there is a wakeup latency constraint coming from the `PM QoS framework
-<cpu-pm-qos_>`_ which is hit before reaching the deepest idle state with the
-target residency within the sleep length, the deepest idle state with the exit
-latency within the constraint is preselected without consulting the ``hits``,
-``misses`` and ``early_hits`` metrics.]
-
-Next, the governor takes several idle duration values observed most recently
-into consideration and if at least a half of them are greater than or equal to
-the target residency of the preselected idle state, that idle state becomes the
-final candidate to ask for.  Otherwise, the average of the most recent idle
-duration values below the target residency of the preselected idle state is
-computed and the governor walks the idle states shallower than the preselected
-one and finds the deepest of them with the target residency within that average.
-That idle state is then taken as the final candidate to ask for.
-
-Still, at this point the governor may need to refine the idle state selection if
-it has not decided to `stop the scheduler tick <idle-cpus-and-tick_>`_.  That
-generally happens if the target residency of the idle state selected so far is
-less than the tick period and the tick has not been stopped already (in a
-previous iteration of the idle loop).  Then, like in the ``menu`` governor
-`case <menu-gov_>`_, the sleep length used in the previous computations may not
-reflect the real time until the closest timer event and if it really is greater
-than that time, a shallower state with a suitable target residency may need to
-be selected.
-
+.. kernel-doc:: drivers/cpuidle/governors/teo.c
+   :doc: teo-description
 
 .. _idle-states-representation:
 
index 89309e1..b799a43 100644 (file)
@@ -20,8 +20,8 @@ Nehalem and later generations of Intel processors, but the level of support for
 a particular processor model in it depends on whether or not it recognizes that
 processor model and may also depend on information coming from the platform
 firmware.  [To understand ``intel_idle`` it is necessary to know how ``CPUIdle``
-works in general, so this is the time to get familiar with :doc:`cpuidle` if you
-have not done that yet.]
+works in general, so this is the time to get familiar with
+Documentation/admin-guide/pm/cpuidle.rst if you have not done that yet.]
 
 ``intel_idle`` uses the ``MWAIT`` instruction to inform the processor that the
 logical CPU executing it is idle and so it may be possible to put some of the
@@ -53,7 +53,8 @@ processor) corresponding to them depends on the processor model and it may also
 depend on the configuration of the platform.
 
 In order to create a list of available idle states required by the ``CPUIdle``
-subsystem (see :ref:`idle-states-representation` in :doc:`cpuidle`),
+subsystem (see :ref:`idle-states-representation` in
+Documentation/admin-guide/pm/cpuidle.rst),
 ``intel_idle`` can use two sources of information: static tables of idle states
 for different processor models included in the driver itself and the ACPI tables
 of the system.  The former are always used if the processor model at hand is
@@ -98,7 +99,8 @@ states may not be enabled by default if there are no matching entries in the
 preliminary list of idle states coming from the ACPI tables.  In that case user
 space still can enable them later (on a per-CPU basis) with the help of
 the ``disable`` idle state attribute in ``sysfs`` (see
-:ref:`idle-states-representation` in :doc:`cpuidle`).  This basically means that
+:ref:`idle-states-representation` in
+Documentation/admin-guide/pm/cpuidle.rst).  This basically means that
 the idle states "known" to the driver may not be enabled by default if they have
 not been exposed by the platform firmware (through the ACPI tables).
 
@@ -186,7 +188,8 @@ be desirable.  In practice, it is only really necessary to do that if the idle
 states in question cannot be enabled during system startup, because in the
 working state of the system the CPU power management quality of service (PM
 QoS) feature can be used to prevent ``CPUIdle`` from touching those idle states
-even if they have been enumerated (see :ref:`cpu-pm-qos` in :doc:`cpuidle`).
+even if they have been enumerated (see :ref:`cpu-pm-qos` in
+Documentation/admin-guide/pm/cpuidle.rst).
 Setting ``max_cstate`` to 0 causes the ``intel_idle`` initialization to fail.
 
 The ``no_acpi`` and ``use_acpi`` module parameters (recognized by ``intel_idle``
@@ -202,7 +205,8 @@ Namely, the positions of the bits that are set in the ``states_off`` value are
 the indices of idle states to be disabled by default (as reflected by the names
 of the corresponding idle state directories in ``sysfs``, :file:`state0`,
 :file:`state1` ... :file:`state<i>` ..., where ``<i>`` is the index of the given
-idle state; see :ref:`idle-states-representation` in :doc:`cpuidle`).
+idle state; see :ref:`idle-states-representation` in
+Documentation/admin-guide/pm/cpuidle.rst).
 
 For example, if ``states_off`` is equal to 3, the driver will disable idle
 states 0 and 1 by default, and if it is equal to 8, idle state 3 will be
index df29b4f..d5043cd 100644 (file)
@@ -18,8 +18,8 @@ General Information
 (``CPUFreq``).  It is a scaling driver for the Sandy Bridge and later
 generations of Intel processors.  Note, however, that some of those processors
 may not be supported.  [To understand ``intel_pstate`` it is necessary to know
-how ``CPUFreq`` works in general, so this is the time to read :doc:`cpufreq` if
-you have not done that yet.]
+how ``CPUFreq`` works in general, so this is the time to read
+Documentation/admin-guide/pm/cpufreq.rst if you have not done that yet.]
 
 For the processors supported by ``intel_pstate``, the P-state concept is broader
 than just an operating frequency or an operating performance point (see the
@@ -365,6 +365,9 @@ argument is passed to the kernel in the command line.
        inclusive) including both turbo and non-turbo P-states (see
        `Turbo P-states Support`_).
 
+       This attribute is present only if the value exposed by it is the same
+       for all of the CPUs in the system.
+
        The value of this attribute is not affected by the ``no_turbo``
        setting described `below <no_turbo_attr_>`_.
 
@@ -374,6 +377,9 @@ argument is passed to the kernel in the command line.
        Ratio of the `turbo range <turbo_>`_ size to the size of the entire
        range of supported P-states, in percent.
 
+       This attribute is present only if the value exposed by it is the same
+       for all of the CPUs in the system.
+
        This attribute is read-only.
 
 .. _no_turbo_attr:
@@ -445,8 +451,9 @@ Interpretation of Policy Attributes
 -----------------------------------
 
 The interpretation of some ``CPUFreq`` policy attributes described in
-:doc:`cpufreq` is special with ``intel_pstate`` as the current scaling driver
-and it generally depends on the driver's `operation mode <Operation Modes_>`_.
+Documentation/admin-guide/pm/cpufreq.rst is special with ``intel_pstate``
+as the current scaling driver and it generally depends on the driver's
+`operation mode <Operation Modes_>`_.
 
 First of all, the values of the ``cpuinfo_max_freq``, ``cpuinfo_min_freq`` and
 ``scaling_cur_freq`` attributes are produced by applying a processor-specific
index 49d8149..2d22ead 100644 (file)
@@ -45,15 +45,18 @@ blkdev
 The block device to use. Most of the time, it is a partition of block device.
 It's required for pstore/blk. It is also used for MTD device.
 
-It accepts the following variants for block device:
+When pstore/blk is built as a module, "blkdev" accepts the following variants:
 
-1. <hex_major><hex_minor> device number in hexadecimal represents itself; no
-   leading 0x, for example b302.
-#. /dev/<disk_name> represents the device number of disk
+1. /dev/<disk_name> represents the device number of disk
 #. /dev/<disk_name><decimal> represents the device number of partition - device
    number of disk plus the partition number
 #. /dev/<disk_name>p<decimal> - same as the above; this form is used when disk
    name of partitioned disk ends with a digit.
+
+When pstore/blk is built into the kernel, "blkdev" accepts the following variants:
+
+#. <hex_major><hex_minor> device number in hexadecimal representation,
+   with no leading 0x, for example b302.
 #. PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF represents the unique id of
    a partition if the partition table provides it. The UUID may be either an
    EFI/GPT UUID, or refer to an MSDOS partition using the format SSSSSSSS-PP,
@@ -227,8 +230,5 @@ For developer reference, here are all the important structures and APIs:
 .. kernel-doc:: include/linux/pstore_zone.h
    :internal:
 
-.. kernel-doc:: fs/pstore/blk.c
-   :internal:
-
 .. kernel-doc:: include/linux/pstore_blk.h
    :internal:
index 18d8e25..d7ac13f 100644 (file)
@@ -1248,7 +1248,7 @@ paragraph makes the severeness obvious.
 
 In case you performed a successful bisection, use the title of the change that
 introduced the regression as the second part of your subject. Make the report
-also mention the commit id of the culprit. In case of an unsuccessful bisection,
+also mention the commit id of the culprit. In case of an unsuccessful bisection,
 make your report mention the latest tested version that's working fine (say 5.7)
 and the oldest where the issue occurs (say 5.8-rc1).
 
index 77b1d1b..4e6db0a 100644 (file)
@@ -11,7 +11,7 @@ Documentation for /proc/sys/abi/
 
 Copyright (c) 2020, Stephen Kitt
 
-For general info, see :doc:`index`.
+For general info, see Documentation/admin-guide/sysctl/index.rst.
 
 ------------------------------------------------------------------------------
 
index 68b2139..10dd4b1 100644 (file)
@@ -9,7 +9,8 @@ Copyright (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 Copyright (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
-For general info and legal blurb, please look in :doc:`index`.
+For general info and legal blurb, please look in
+Documentation/admin-guide/sysctl/index.rst.
 
 ------------------------------------------------------------------------------
 
@@ -54,7 +55,7 @@ free space valid for 30 seconds.
 acpi_video_flags
 ================
 
-See :doc:`/power/video`. This allows the video resume mode to be set,
+See Documentation/power/video.rst. This allows the video resume mode to be set,
 in a similar fashion to the ``acpi_sleep`` kernel parameter, by
 combining the following values:
 
@@ -89,7 +90,7 @@ is 0x15 and the full version number is 0x234, this file will contain
 the value 340 = 0x154.
 
 See the ``type_of_loader`` and ``ext_loader_type`` fields in
-:doc:`/x86/boot` for additional information.
+Documentation/x86/boot.rst for additional information.
 
 
 bootloader_version (x86 only)
@@ -99,7 +100,7 @@ The complete bootloader version number.  In the example above, this
 file will contain the value 564 = 0x234.
 
 See the ``type_of_loader`` and ``ext_loader_ver`` fields in
-:doc:`/x86/boot` for additional information.
+Documentation/x86/boot.rst for additional information.
 
 
 bpf_stats_enabled
@@ -269,7 +270,7 @@ see the ``hostname(1)`` man page.
 firmware_config
 ===============
 
-See :doc:`/driver-api/firmware/fallback-mechanisms`.
+See Documentation/driver-api/firmware/fallback-mechanisms.rst.
 
 The entries in this directory allow the firmware loader helper
 fallback to be controlled:
@@ -297,7 +298,7 @@ crashes and outputting them to a serial console.
 ftrace_enabled, stack_tracer_enabled
 ====================================
 
-See :doc:`/trace/ftrace`.
+See Documentation/trace/ftrace.rst.
 
 
 hardlockup_all_cpu_backtrace
@@ -325,7 +326,7 @@ when a hard lockup is detected.
 1 Panic on hard lockup.
 = ===========================
 
-See :doc:`/admin-guide/lockup-watchdogs` for more information.
+See Documentation/admin-guide/lockup-watchdogs.rst for more information.
 This can also be set using the nmi_watchdog kernel parameter.
 
 
@@ -333,7 +334,12 @@ hotplug
 =======
 
 Path for the hotplug policy agent.
-Default value is "``/sbin/hotplug``".
+Default value is ``CONFIG_UEVENT_HELPER_PATH``, which in turn defaults
+to the empty string.
+
+This file only exists when ``CONFIG_UEVENT_HELPER`` is enabled. Most
+modern systems rely exclusively on the netlink-based uevent source and
+don't need this.
 
 
 hung_task_all_cpu_backtrace
@@ -582,7 +588,8 @@ in a KVM virtual machine. This default can be overridden by adding::
 
    nmi_watchdog=1
 
-to the guest kernel command line (see :doc:`/admin-guide/kernel-parameters`).
+to the guest kernel command line (see
+Documentation/admin-guide/kernel-parameters.rst).
 
 
 numa_balancing
@@ -1067,7 +1074,7 @@ that support this feature.
 real-root-dev
 =============
 
-See :doc:`/admin-guide/initrd`.
+See Documentation/admin-guide/initrd.rst.
 
 
 reboot-cmd (SPARC only)
@@ -1088,6 +1095,13 @@ Model available). If your platform happens to meet the
 requirements for EAS but you do not want to use it, change
 this value to 0.
 
+task_delayacct
+===============
+
+Enables/disables task delay accounting (see
+:doc:`accounting/delay-accounting.rst`). Enabling this feature incurs
+a small amount of overhead in the scheduler but is useful for debugging
+and performance tuning. It is required by some tools such as iotop.
 
 sched_schedstats
 ================
@@ -1154,7 +1168,7 @@ will take effect.
 seccomp
 =======
 
-See :doc:`/userspace-api/seccomp_filter`.
+See Documentation/userspace-api/seccomp_filter.rst.
 
 
 sg-big-buff
@@ -1325,7 +1339,7 @@ the boot PROM.
 sysrq
 =====
 
-See :doc:`/admin-guide/sysrq`.
+See Documentation/admin-guide/sysrq.rst.
 
 
 tainted
@@ -1355,15 +1369,16 @@ ORed together. The letters are seen in "Tainted" line of Oops reports.
 131072  `(T)`  The kernel was built with the struct randomization plugin
 ======  =====  ==============================================================
 
-See :doc:`/admin-guide/tainted-kernels` for more information.
+See Documentation/admin-guide/tainted-kernels.rst for more information.
 
 Note:
   writes to this sysctl interface will fail with ``EINVAL`` if the kernel is
   booted with the command line option ``panic_on_taint=<bitmask>,nousertaint``
   and any of the ORed together values being written to ``tainted`` match with
   the bitmask declared on panic_on_taint.
-  See :doc:`/admin-guide/kernel-parameters` for more details on that particular
-  kernel command line option and its optional ``nousertaint`` switch.
+  See Documentation/admin-guide/kernel-parameters.rst for more details on
+  that particular kernel command line option and its optional
+  ``nousertaint`` switch.
 
 threads-max
 ===========
@@ -1387,7 +1402,7 @@ If a value outside of this range is written to ``threads-max`` an
 traceoff_on_warning
 ===================
 
-When set, disables tracing (see :doc:`/trace/ftrace`) when a
+When set, disables tracing (see Documentation/trace/ftrace.rst) when a
 ``WARN()`` is hit.
 
 
@@ -1407,8 +1422,8 @@ will send them to printk() again.
 
 This only works if the kernel was booted with ``tp_printk`` enabled.
 
-See :doc:`/admin-guide/kernel-parameters` and
-:doc:`/trace/boottime-trace`.
+See Documentation/admin-guide/kernel-parameters.rst and
+Documentation/trace/boottime-trace.rst.
 
 
 .. _unaligned-dump-stack:
index c50be71..db22464 100644 (file)
@@ -259,7 +259,7 @@ Storage family
        https://web.archive.org/web/20191129073953/http://www.marvell.com/storage/armada-sp/
 
   Core:
-       Sheeva ARMv7 comatible Quad-core PJ4C
+       Sheeva ARMv7 compatible Quad-core PJ4C
 
   (not supported in upstream Linux kernel)
 
index 18b8cc1..a9192e7 100644 (file)
@@ -277,6 +277,12 @@ Before jumping into the kernel, the following conditions must be met:
 
     - SCR_EL3.FGTEn (bit 27) must be initialised to 0b1.
 
+  For CPUs with support for HCRX_EL2 (FEAT_HCX) present:
+
+  - If EL3 is present and the kernel is entered at EL2:
+
+    - SCR_EL3.HXEn (bit 38) must be initialised to 0b1.
+
   For CPUs with Advanced SIMD and floating point support:
 
   - If EL3 is present:
index 1d4d71e..2098477 100644 (file)
@@ -196,7 +196,7 @@ a virtual address mapping (unlike the earlier scheme of virtual address
 do not have a corresponding kernel virtual address space mapping) and
 low-memory pages.
 
-Note: Please refer to :doc:`/core-api/dma-api-howto` for a discussion
+Note: Please refer to Documentation/core-api/dma-api-howto.rst for a discussion
 on PCI high mem DMA aspects and mapping of scatter gather lists, and support
 for 64 bit PCI.
 
index a980d23..d96118c 100644 (file)
@@ -62,7 +62,7 @@ queue, to be sent in the future, when the hardware is able.
 Software staging queues
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-The block IO subsystem adds requests  in the software staging queues
+The block IO subsystem adds requests in the software staging queues
 (represented by struct blk_mq_ctx) in case that they weren't sent
 directly to the driver. A request is one or more BIOs. They arrived at the
 block layer through the data structure struct bio. The block layer
@@ -132,7 +132,7 @@ In order to indicate which request has been completed, every request is
 identified by an integer, ranging from 0 to the dispatch queue size. This tag
 is generated by the block layer and later reused by the device driver, removing
 the need to create a redundant identifier. When a request is completed in the
-drive, the tag is sent back to the block layer to notify it of the finalization.
+driver, the tag is sent back to the block layer to notify it of the finalization.
 This removes the need to do a linear search to find out which IO has been
 completed.
 
index 7731133..a1cd9db 100644 (file)
@@ -18,7 +18,7 @@ A.
    each, it would be impossible to guarantee that a set of readings
    represent a single point in time.
 
-The stat file consists of a single line of text containing 11 decimal
+The stat file consists of a single line of text containing 17 decimal
 values separated by whitespace.  The fields are summarized in the
 following table, and described in more detail below.
 
index 1c0a75a..0dc3fb0 100644 (file)
@@ -20,10 +20,10 @@ LSM hook:
 Other LSM hooks which can be instrumented can be found in
 ``include/linux/lsm_hooks.h``.
 
-eBPF programs that use :doc:`/bpf/btf` do not need to include kernel headers
-for accessing information from the attached eBPF program's context. They can
-simply declare the structures in the eBPF program and only specify the fields
-that need to be accessed.
+eBPF programs that use Documentation/bpf/btf.rst do not need to include kernel
+headers for accessing information from the attached eBPF program's context.
+They can simply declare the structures in the eBPF program and only specify
+the fields that need to be accessed.
 
 .. code-block:: c
 
@@ -88,8 +88,9 @@ example:
 
 The ``__attribute__((preserve_access_index))`` is a clang feature that allows
 the BPF verifier to update the offsets for the access at runtime using the
-:doc:`/bpf/btf` information. Since the BPF verifier is aware of the types, it
-also validates all the accesses made to the various types in the eBPF program.
+Documentation/bpf/btf.rst information. Since the BPF verifier is aware of the
+types, it also validates all the accesses made to the various types in the
+eBPF program.
 
 Loading
 -------
index 879e86d..7d92ec3 100644 (file)
@@ -41,15 +41,7 @@ extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include',
               'maintainers_include', 'sphinx.ext.autosectionlabel',
               'kernel_abi', 'kernel_feat']
 
-#
-# cdomain is badly broken in Sphinx 3+.  Leaving it out generates *most*
-# of the docs correctly, but not all.  Scream bloody murder but allow
-# the process to proceed; hopefully somebody will fix this properly soon.
-#
 if major >= 3:
-    sys.stderr.write('''WARNING: The kernel documentation build process
-        support for Sphinx v3.0 and above is brand new. Be prepared for
-        possible issues in the generated output.\n''')
     if (major > 3) or (minor > 0 or patch >= 2):
         # Sphinx c function parser is more pedantic with regards to type
         # checking. Due to that, having macros at c:function cause problems.
@@ -353,6 +345,8 @@ latex_elements = {
 
     # Additional stuff for the LaTeX preamble.
     'preamble': '''
+       % Prevent column squeezing of tabulary.
+       \\setlength{\\tymin}{20em}
         % Use some font with UTF-8 support with XeLaTeX
         \\usepackage{fontspec}
         \\setsansfont{DejaVu Sans}
@@ -366,11 +360,23 @@ latex_elements = {
 
 cjk_cmd = check_output(['fc-list', '--format="%{family[0]}\n"']).decode('utf-8', 'ignore')
 if cjk_cmd.find("Noto Sans CJK SC") >= 0:
-    print ("enabling CJK for LaTeX builder")
     latex_elements['preamble']  += '''
        % This is needed for translations
         \\usepackage{xeCJK}
         \\setCJKmainfont{Noto Sans CJK SC}
+       % Define custom macros to on/off CJK
+       \\newcommand{\\kerneldocCJKon}{\\makexeCJKactive}
+       \\newcommand{\\kerneldocCJKoff}{\\makexeCJKinactive}
+       % To customize \sphinxtableofcontents
+       \\usepackage{etoolbox}
+       % Inactivate CJK after tableofcontents
+       \\apptocmd{\\sphinxtableofcontents}{\\kerneldocCJKoff}{}{}
+     '''
+else:
+    latex_elements['preamble']  += '''
+       % Custom macros to on/off CJK (Dummy)
+       \\newcommand{\\kerneldocCJKon}{}
+       \\newcommand{\\kerneldocCJKoff}{}
      '''
 
 # Fix reference escape troubles with Sphinx 1.4.x
index c7bc99c..c72b24a 100644 (file)
@@ -8,7 +8,7 @@ How to access I/O mapped memory from within device drivers
 
        The virt_to_bus() and bus_to_virt() functions have been
        superseded by the functionality provided by the PCI DMA interface
-       (see :doc:`/core-api/dma-api-howto`).  They continue
+       (see Documentation/core-api/dma-api-howto.rst).  They continue
        to be documented below for historical purposes, but new code
        must not use them. --davidm 00/12/12
 
index 00a1d4f..6d6d0ed 100644 (file)
@@ -5,7 +5,7 @@ Dynamic DMA mapping using the generic device
 :Author: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
 
 This document describes the DMA API.  For a more gentle introduction
-of the API (and actual examples), see :doc:`/core-api/dma-api-howto`.
+of the API (and actual examples), see Documentation/core-api/dma-api-howto.rst.
 
 This API is split into two pieces.  Part I describes the basic API.
 Part II describes extensions for supporting non-consistent memory
@@ -479,7 +479,8 @@ without the _attrs suffixes, except that they pass an optional
 dma_attrs.
 
 The interpretation of DMA attributes is architecture-specific, and
-each attribute should be documented in :doc:`/core-api/dma-attributes`.
+each attribute should be documented in
+Documentation/core-api/dma-attributes.rst.
 
 If dma_attrs are 0, the semantics of each of these functions
 is identical to those of the corresponding function
index e59a3d3..17b1936 100644 (file)
@@ -17,7 +17,7 @@ To do ISA style DMA you need to include two headers::
        #include <asm/dma.h>
 
 The first is the generic DMA API used to convert virtual addresses to
-bus addresses (see :doc:`/core-api/dma-api` for details).
+bus addresses (see Documentation/core-api/dma-api.rst for details).
 
 The second contains the routines specific to ISA DMA transfers. Since
 this is not present on all platforms make sure you construct your
index f1c9d20..5de2c7a 100644 (file)
@@ -48,7 +48,7 @@ Concurrency primitives
 ======================
 
 How Linux keeps everything from happening at the same time.  See
-:doc:`/locking/index` for more related documentation.
+Documentation/locking/index.rst for more related documentation.
 
 .. toctree::
    :maxdepth: 1
@@ -77,7 +77,7 @@ Memory management
 =================
 
 How to allocate and use memory in the kernel.  Note that there is a lot
-more memory-management documentation in :doc:`/vm/index`.
+more memory-management documentation in Documentation/vm/index.rst.
 
 .. toctree::
    :maxdepth: 1
index 8214e21..53283b3 100644 (file)
@@ -146,7 +146,6 @@ Legacy
 
        irq_domain_add_simple()
        irq_domain_add_legacy()
-       irq_domain_add_legacy_isa()
        irq_domain_create_simple()
        irq_domain_create_legacy()
 
index f063a38..4346ae1 100644 (file)
@@ -37,14 +37,13 @@ Integer types
                u64                     %llu or %llx
 
 
-If <type> is dependent on a config option for its size (e.g., sector_t,
-blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a
-format specifier of its largest possible type and explicitly cast to it.
+If <type> is architecture-dependent for its size (e.g., cycles_t, tcflag_t) or
+is dependent on a config option for its size (e.g., blk_status_t), use a format
+specifier of its largest possible type and explicitly cast to it.
 
 Example::
 
-       printk("test: sector number/total blocks: %llu/%llu\n",
-               (unsigned long long)sector, (unsigned long long)blockcount);
+       printk("test: latency: %llu cycles\n", (unsigned long long)time);
 
 Reminder: sizeof() returns type size_t.
 
@@ -514,9 +513,10 @@ Time and date
 ::
 
        %pt[RT]                 YYYY-mm-ddTHH:MM:SS
+       %pt[RT]s                YYYY-mm-dd HH:MM:SS
        %pt[RT]d                YYYY-mm-dd
        %pt[RT]t                HH:MM:SS
-       %pt[RT][dt][r]
+       %pt[RT][dt][r][s]
 
 For printing date and time as represented by::
 
@@ -528,6 +528,10 @@ in human readable format.
 By default year will be incremented by 1900 and month by 1.
 Use %pt[RT]r (raw) to suppress this behaviour.
 
+The %pt[RT]s (space) will override ISO 8601 separator by using ' ' (space)
+instead of 'T' (Capital T) between date and time. It won't have any effect
+when date or time is omitted.
+
 Passed by reference.
 
 struct clk
index 51fed1b..f0956e9 100644 (file)
@@ -246,6 +246,7 @@ Allocation style
     The first argument for kcalloc or kmalloc_array should be the
     number of elements.  sizeof() as the first argument is generally
     wrong.
+
     See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html
 
   **ALLOC_SIZEOF_STRUCT**
@@ -264,6 +265,7 @@ Allocation style
   **ALLOC_WITH_MULTIPLY**
     Prefer kmalloc_array/kcalloc over kmalloc/kzalloc with a
     sizeof multiply.
+
     See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html
 
 
@@ -284,6 +286,7 @@ API usage
     BUG() or BUG_ON() should be avoided totally.
     Use WARN() and WARN_ON() instead, and handle the "impossible"
     error condition as gracefully as possible.
+
     See: https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on
 
   **CONSIDER_KSTRTO**
@@ -292,12 +295,161 @@ API usage
     may lead to unexpected results in callers.  The respective kstrtol(),
     kstrtoll(), kstrtoul(), and kstrtoull() functions tend to be the
     correct replacements.
+
     See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull
 
+  **CONSTANT_CONVERSION**
+    Use of __constant_<foo> form is discouraged for the following functions::
+
+      __constant_cpu_to_be[x]
+      __constant_cpu_to_le[x]
+      __constant_be[x]_to_cpu
+      __constant_le[x]_to_cpu
+      __constant_htons
+      __constant_ntohs
+
+    Using any of these outside of include/uapi/ is not preferred as using the
+    function without __constant_ is identical when the argument is a
+    constant.
+
+    In big endian systems, the macros like __constant_cpu_to_be32(x) and
+    cpu_to_be32(x) expand to the same expression::
+
+      #define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x))
+      #define __cpu_to_be32(x)          ((__force __be32)(__u32)(x))
+
+    In little endian systems, the macros __constant_cpu_to_be32(x) and
+    cpu_to_be32(x) expand to __constant_swab32 and __swab32.  __swab32
+    has a __builtin_constant_p check::
+
+      #define __swab32(x)                              \
+        (__builtin_constant_p((__u32)(x)) ?    \
+        ___constant_swab32(x) :                        \
+        __fswab32(x))
+
+    So ultimately they have a special case for constants.
+    Similar is the case with all of the macros in the list.  Thus
+    using the __constant_... forms are unnecessarily verbose and
+    not preferred outside of include/uapi.
+
+    See: https://lore.kernel.org/lkml/1400106425.12666.6.camel@joe-AO725/
+
+  **DEPRECATED_API**
+    Usage of a deprecated RCU API is detected.  It is recommended to replace
+    old flavourful RCU APIs by their new vanilla-RCU counterparts.
+
+    The full list of available RCU APIs can be viewed from the kernel docs.
+
+    See: https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis
+
+  **DEPRECATED_VARIABLE**
+    EXTRA_{A,C,CPP,LD}FLAGS are deprecated and should be replaced by the new
+    flags added via commit f77bf01425b1 ("kbuild: introduce ccflags-y,
+    asflags-y and ldflags-y").
+
+    The following conversion scheme maybe used::
+
+      EXTRA_AFLAGS    ->  asflags-y
+      EXTRA_CFLAGS    ->  ccflags-y
+      EXTRA_CPPFLAGS  ->  cppflags-y
+      EXTRA_LDFLAGS   ->  ldflags-y
+
+    See:
+
+      1. https://lore.kernel.org/lkml/20070930191054.GA15876@uranus.ravnborg.org/
+      2. https://lore.kernel.org/lkml/1313384834-24433-12-git-send-email-lacombar@gmail.com/
+      3. https://www.kernel.org/doc/html/latest/kbuild/makefiles.html#compilation-flags
+
+  **DEVICE_ATTR_FUNCTIONS**
+    The function names used in DEVICE_ATTR is unusual.
+    Typically, the store and show functions are used with <attr>_store and
+    <attr>_show, where <attr> is a named attribute variable of the device.
+
+    Consider the following examples::
+
+      static DEVICE_ATTR(type, 0444, type_show, NULL);
+      static DEVICE_ATTR(power, 0644, power_show, power_store);
+
+    The function names should preferably follow the above pattern.
+
+    See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes
+
+  **DEVICE_ATTR_RO**
+    The DEVICE_ATTR_RO(name) helper macro can be used instead of
+    DEVICE_ATTR(name, 0444, name_show, NULL);
+
+    Note that the macro automatically appends _show to the named
+    attribute variable of the device for the show method.
+
+    See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes
+
+  **DEVICE_ATTR_RW**
+    The DEVICE_ATTR_RW(name) helper macro can be used instead of
+    DEVICE_ATTR(name, 0644, name_show, name_store);
+
+    Note that the macro automatically appends _show and _store to the
+    named attribute variable of the device for the show and store methods.
+
+    See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes
+
+  **DEVICE_ATTR_WO**
+    The DEVICE_AATR_WO(name) helper macro can be used instead of
+    DEVICE_ATTR(name, 0200, NULL, name_store);
+
+    Note that the macro automatically appends _store to the
+    named attribute variable of the device for the store method.
+
+    See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes
+
+  **DUPLICATED_SYSCTL_CONST**
+    Commit d91bff3011cf ("proc/sysctl: add shared variables for range
+    check") added some shared const variables to be used instead of a local
+    copy in each source file.
+
+    Consider replacing the sysctl range checking value with the shared
+    one in include/linux/sysctl.h.  The following conversion scheme may
+    be used::
+
+      &zero     ->  SYSCTL_ZERO
+      &one      ->  SYSCTL_ONE
+      &int_max  ->  SYSCTL_INT_MAX
+
+    See:
+
+      1. https://lore.kernel.org/lkml/20190430180111.10688-1-mcroce@redhat.com/
+      2. https://lore.kernel.org/lkml/20190531131422.14970-1-mcroce@redhat.com/
+
+  **ENOSYS**
+    ENOSYS means that a nonexistent system call was called.
+    Earlier, it was wrongly used for things like invalid operations on
+    otherwise valid syscalls.  This should be avoided in new code.
+
+    See: https://lore.kernel.org/lkml/5eb299021dec23c1a48fa7d9f2c8b794e967766d.1408730669.git.luto@amacapital.net/
+
+  **ENOTSUPP**
+    ENOTSUPP is not a standard error code and should be avoided in new patches.
+    EOPNOTSUPP should be used instead.
+
+    See: https://lore.kernel.org/netdev/20200510182252.GA411829@lunn.ch/
+
+  **EXPORT_SYMBOL**
+    EXPORT_SYMBOL should immediately follow the symbol to be exported.
+
+  **IN_ATOMIC**
+    in_atomic() is not for driver use so any such use is reported as an ERROR.
+    Also in_atomic() is often used to determine if sleeping is permitted,
+    but it is not reliable in this use model.  Therefore its use is
+    strongly discouraged.
+
+    However, in_atomic() is ok for core kernel use.
+
+    See: https://lore.kernel.org/lkml/20080320201723.b87b3732.akpm@linux-foundation.org/
+
   **LOCKDEP**
     The lockdep_no_validate class was added as a temporary measure to
     prevent warnings on conversion of device->sem to device->mutex.
     It should not be used for any other purpose.
+
     See: https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/
 
   **MALFORMED_INCLUDE**
@@ -308,14 +460,21 @@ API usage
   **USE_LOCKDEP**
     lockdep_assert_held() annotations should be preferred over
     assertions based on spin_is_locked()
+
     See: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html#annotations
 
   **UAPI_INCLUDE**
     No #include statements in include/uapi should use a uapi/ path.
 
+  **USLEEP_RANGE**
+    usleep_range() should be preferred over udelay(). The proper way of
+    using usleep_range() is mentioned in the kernel docs.
 
-Comment style
--------------
+    See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms
+
+
+Comments
+--------
 
   **BLOCK_COMMENT_STYLE**
     The comment style is incorrect.  The preferred style for multi-
@@ -338,8 +497,24 @@ Comment style
   **C99_COMMENTS**
     C99 style single line comments (//) should not be used.
     Prefer the block comment style instead.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting
 
+  **DATA_RACE**
+    Applications of data_race() should have a comment so as to document the
+    reasoning behind why it was deemed safe.
+
+    See: https://lore.kernel.org/lkml/20200401101714.44781-1-elver@google.com/
+
+  **FSF_MAILING_ADDRESS**
+    Kernel maintainers reject new instances of the GPL boilerplate paragraph
+    directing people to write to the FSF for a copy of the GPL, since the
+    FSF has moved in the past and may do so again.
+    So do not write paragraphs about writing to the Free Software Foundation's
+    mailing address.
+
+    See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/
+
 
 Commit message
 --------------
@@ -347,6 +522,7 @@ Commit message
   **BAD_SIGN_OFF**
     The signed-off-by line does not fall in line with the standards
     specified by the community.
+
     See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1
 
   **BAD_STABLE_ADDRESS_STYLE**
@@ -368,12 +544,33 @@ Commit message
   **COMMIT_MESSAGE**
     The patch is missing a commit description.  A brief
     description of the changes made by the patch should be added.
+
+    See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes
+
+  **EMAIL_SUBJECT**
+    Naming the tool that found the issue is not very useful in the
+    subject line.  A good subject line summarizes the change that
+    the patch brings.
+
     See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes
 
+  **FROM_SIGN_OFF_MISMATCH**
+    The author's email does not match with that in the Signed-off-by:
+    line(s). This can be sometimes caused due to an improperly configured
+    email client.
+
+    This message is emitted due to any of the following reasons::
+
+      - The email names do not match.
+      - The email addresses do not match.
+      - The email subaddresses do not match.
+      - The email comments do not match.
+
   **MISSING_SIGN_OFF**
     The patch is missing a Signed-off-by line.  A signed-off-by
     line should be added according to Developer's certificate of
     Origin.
+
     See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
 
   **NO_AUTHOR_SIGN_OFF**
@@ -382,6 +579,7 @@ Commit message
     end of explanation of the patch to denote that the author has
     written it or otherwise has the rights to pass it on as an open
     source patch.
+
     See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
 
   **DIFF_IN_COMMIT_MSG**
@@ -389,6 +587,7 @@ Commit message
     This causes problems when one tries to apply a file containing both
     the changelog and the diff because patch(1) tries to apply the diff
     which it found in the changelog.
+
     See: https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/
 
   **GERRIT_CHANGE_ID**
@@ -431,6 +630,7 @@ Comparison style
   **BOOL_COMPARISON**
     Comparisons of A to true and false are better written
     as A and !A.
+
     See: https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/
 
   **COMPARISON_TO_NULL**
@@ -442,6 +642,87 @@ Comparison style
     side of the test should be avoided.
 
 
+Indentation and Line Breaks
+---------------------------
+
+  **CODE_INDENT**
+    Code indent should use tabs instead of spaces.
+    Outside of comments, documentation and Kconfig,
+    spaces are never used for indentation.
+
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation
+
+  **DEEP_INDENTATION**
+    Indentation with 6 or more tabs usually indicate overly indented
+    code.
+
+    It is suggested to refactor excessive indentation of
+    if/else/for/do/while/switch statements.
+
+    See: https://lore.kernel.org/lkml/1328311239.21255.24.camel@joe2Laptop/
+
+  **SWITCH_CASE_INDENT_LEVEL**
+    switch should be at the same indent as case.
+    Example::
+
+      switch (suffix) {
+      case 'G':
+      case 'g':
+              mem <<= 30;
+              break;
+      case 'M':
+      case 'm':
+              mem <<= 20;
+              break;
+      case 'K':
+      case 'k':
+              mem <<= 10;
+              fallthrough;
+      default:
+              break;
+      }
+
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation
+
+  **LONG_LINE**
+    The line has exceeded the specified maximum length.
+    To use a different maximum line length, the --max-line-length=n option
+    may be added while invoking checkpatch.
+
+    Earlier, the default line length was 80 columns.  Commit bdc48fa11e46
+    ("checkpatch/coding-style: deprecate 80-column warning") increased the
+    limit to 100 columns.  This is not a hard limit either and it's
+    preferable to stay within 80 columns whenever possible.
+
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
+
+  **LONG_LINE_STRING**
+    A string starts before but extends beyond the maximum line length.
+    To use a different maximum line length, the --max-line-length=n option
+    may be added while invoking checkpatch.
+
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
+
+  **LONG_LINE_COMMENT**
+    A comment starts before but extends beyond the maximum line length.
+    To use a different maximum line length, the --max-line-length=n option
+    may be added while invoking checkpatch.
+
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
+
+  **TRAILING_STATEMENTS**
+    Trailing statements (for example after any conditional) should be
+    on the next line.
+    Statements, such as::
+
+      if (x == y) break;
+
+    should be::
+
+      if (x == y)
+              break;
+
+
 Macros, Attributes and Symbols
 ------------------------------
 
@@ -472,7 +753,7 @@ Macros, Attributes and Symbols
 
   **BIT_MACRO**
     Defines like: 1 << <digit> could be BIT(digit).
-    The BIT() macro is defined in include/linux/bitops.h::
+    The BIT() macro is defined via include/linux/bits.h::
 
       #define BIT(nr)         (1UL << (nr))
 
@@ -492,6 +773,7 @@ Macros, Attributes and Symbols
     The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros,
     and enables warnings if they are used as they can lead to
     non-deterministic builds.
+
     See: https://www.kernel.org/doc/html/latest/kbuild/reproducible-builds.html#timestamps
 
   **DEFINE_ARCH_HAS**
@@ -502,8 +784,12 @@ Macros, Attributes and Symbols
     want architectures able to override them with optimized ones, we
     should either use weak functions (appropriate for some cases), or
     the symbol that protects them should be the same symbol we use.
+
     See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/
 
+  **DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON**
+    do {} while(0) macros should not have a trailing semicolon.
+
   **INIT_ATTRIBUTE**
     Const init definitions should use __initconst instead of
     __initdata.
@@ -528,6 +814,20 @@ Macros, Attributes and Symbols
               ...
       }
 
+  **MISPLACED_INIT**
+    It is possible to use section markers on variables in a way
+    which gcc doesn't understand (or at least not the way the
+    developer intended)::
+
+      static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = {
+
+    does not put exynos4_plls in the .initdata section. The __initdata
+    marker can be virtually anywhere on the line, except right after
+    "struct". The preferred location is before the "=" sign if there is
+    one, or before the trailing ";" otherwise.
+
+    See: https://lore.kernel.org/lkml/1377655732.3619.19.camel@joe-AO722/
+
   **MULTISTATEMENT_MACRO_USE_DO_WHILE**
     Macros with multiple statements should be enclosed in a
     do - while block.  Same should also be the case for macros
@@ -541,6 +841,10 @@ Macros, Attributes and Symbols
 
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
 
+  **PREFER_FALLTHROUGH**
+    Use the `fallthrough;` pseudo keyword instead of
+    `/* fallthrough */` like comments.
+
   **WEAK_DECLARATION**
     Using weak declarations like __attribute__((weak)) or __weak
     can have unintended link defects.  Avoid using them.
@@ -551,8 +855,51 @@ Functions and Variables
 
   **CAMELCASE**
     Avoid CamelCase Identifiers.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming
 
+  **CONST_CONST**
+    Using `const <type> const *` is generally meant to be
+    written `const <type> * const`.
+
+  **CONST_STRUCT**
+    Using const is generally a good idea.  Checkpatch reads
+    a list of frequently used structs that are always or
+    almost always constant.
+
+    The existing structs list can be viewed from
+    `scripts/const_structs.checkpatch`.
+
+    See: https://lore.kernel.org/lkml/alpine.DEB.2.10.1608281509480.3321@hadrien/
+
+  **EMBEDDED_FUNCTION_NAME**
+    Embedded function names are less appropriate to use as
+    refactoring can cause function renaming.  Prefer the use of
+    "%s", __func__ to embedded function names.
+
+    Note that this does not work with -f (--file) checkpatch option
+    as it depends on patch context providing the function name.
+
+  **FUNCTION_ARGUMENTS**
+    This warning is emitted due to any of the following reasons:
+
+      1. Arguments for the function declaration do not follow
+         the identifier name.  Example::
+
+           void foo
+           (int bar, int baz)
+
+         This should be corrected to::
+
+           void foo(int bar, int baz)
+
+      2. Some arguments for the function definition do not
+         have an identifier name.  Example::
+
+           void foo(int)
+
+         All arguments should have identifier names.
+
   **FUNCTION_WITHOUT_ARGS**
     Function declarations without arguments like::
 
@@ -583,6 +930,34 @@ Functions and Variables
       return bar;
 
 
+Permissions
+-----------
+
+  **DEVICE_ATTR_PERMS**
+    The permissions used in DEVICE_ATTR are unusual.
+    Typically only three permissions are used - 0644 (RW), 0444 (RO)
+    and 0200 (WO).
+
+    See: https://www.kernel.org/doc/html/latest/filesystems/sysfs.html#attributes
+
+  **EXECUTE_PERMISSIONS**
+    There is no reason for source files to be executable.  The executable
+    bit can be removed safely.
+
+  **EXPORTED_WORLD_WRITABLE**
+    Exporting world writable sysfs/debugfs files is usually a bad thing.
+    When done arbitrarily they can introduce serious security bugs.
+    In the past, some of the debugfs vulnerabilities would seemingly allow
+    any local user to write arbitrary values into device registers - a
+    situation from which little good can be expected to emerge.
+
+    See: https://lore.kernel.org/linux-arm-kernel/cover.1296818921.git.segoon@openwall.com/
+
+  **NON_OCTAL_PERMISSIONS**
+    Permission bits should use 4 digit octal permissions (like 0700 or 0444).
+    Avoid using any other base like decimal.
+
+
 Spacing and Brackets
 --------------------
 
@@ -616,7 +991,7 @@ Spacing and Brackets
 
     1. With a type on the left::
 
-        ;int [] a;
+        int [] a;
 
     2. At the beginning of a line for slice initialisers::
 
@@ -626,12 +1001,6 @@ Spacing and Brackets
 
         = { [0...10] = 5 }
 
-  **CODE_INDENT**
-    Code indent should use tabs instead of spaces.
-    Outside of comments, documentation and Kconfig,
-    spaces are never used for indentation.
-    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation
-
   **CONCATENATED_STRING**
     Concatenated elements should have a space in between.
     Example::
@@ -644,17 +1013,20 @@ Spacing and Brackets
 
   **ELSE_AFTER_BRACE**
     `else {` should follow the closing block `}` on the same line.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
 
   **LINE_SPACING**
     Vertical space is wasted given the limited number of lines an
     editor window can display when multiple blank lines are used.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces
 
   **OPEN_BRACE**
     The opening brace should be following the function definitions on the
     next line.  For any non-functional block it should be on the same line
     as the last construct.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
 
   **POINTER_LOCATION**
@@ -671,37 +1043,47 @@ Spacing and Brackets
 
   **SPACING**
     Whitespace style used in the kernel sources is described in kernel docs.
-    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces
 
-  **SWITCH_CASE_INDENT_LEVEL**
-    switch should be at the same indent as case.
-    Example::
-
-      switch (suffix) {
-      case 'G':
-      case 'g':
-              mem <<= 30;
-              break;
-      case 'M':
-      case 'm':
-              mem <<= 20;
-              break;
-      case 'K':
-      case 'k':
-              mem <<= 10;
-              /* fall through */
-      default:
-              break;
-      }
-
-    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation
+    See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces
 
   **TRAILING_WHITESPACE**
     Trailing whitespace should always be removed.
     Some editors highlight the trailing whitespace and cause visual
     distractions when editing files.
+
     See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces
 
+  **UNNECESSARY_PARENTHESES**
+    Parentheses are not required in the following cases:
+
+      1. Function pointer uses::
+
+          (foo->bar)();
+
+        could be::
+
+          foo->bar();
+
+      2. Comparisons in if::
+
+          if ((foo->bar) && (foo->baz))
+          if ((foo == bar))
+
+        could be::
+
+          if (foo->bar && foo->baz)
+          if (foo == bar)
+
+      3. addressof/dereference single Lvalues::
+
+          &(foo->bar)
+          *(foo->bar)
+
+        could be::
+
+          &foo->bar
+          *foo->bar
+
   **WHILE_AFTER_BRACE**
     while should follow the closing bracket on the same line::
 
@@ -723,17 +1105,50 @@ Others
     The patch seems to be corrupted or lines are wrapped.
     Please regenerate the patch file before sending it to the maintainer.
 
+  **CVS_KEYWORD**
+    Since linux moved to git, the CVS markers are no longer used.
+    So, CVS style keywords ($Id$, $Revision$, $Log$) should not be
+    added.
+
+  **DEFAULT_NO_BREAK**
+    switch default case is sometimes written as "default:;".  This can
+    cause new cases added below default to be defective.
+
+    A "break;" should be added after empty default statement to avoid
+    unwanted fallthrough.
+
   **DOS_LINE_ENDINGS**
     For DOS-formatted patches, there are extra ^M symbols at the end of
     the line.  These should be removed.
 
-  **EXECUTE_PERMISSIONS**
-    There is no reason for source files to be executable.  The executable
-    bit can be removed safely.
+  **DT_SCHEMA_BINDING_PATCH**
+    DT bindings moved to a json-schema based format instead of
+    freeform text.
 
-  **NON_OCTAL_PERMISSIONS**
-    Permission bits should use 4 digit octal permissions (like 0700 or 0444).
-    Avoid using any other base like decimal.
+    See: https://www.kernel.org/doc/html/latest/devicetree/bindings/writing-schema.html
+
+  **DT_SPLIT_BINDING_PATCH**
+    Devicetree bindings should be their own patch.  This is because
+    bindings are logically independent from a driver implementation,
+    they have a different maintainer (even though they often
+    are applied via the same tree), and it makes for a cleaner history in the
+    DT only tree created with git-filter-branch.
+
+    See: https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
+
+  **EMBEDDED_FILENAME**
+    Embedding the complete filename path inside the file isn't particularly
+    useful as often the path is moved around and becomes incorrect.
+
+  **FILE_PATH_CHANGES**
+    Whenever files are added, moved, or deleted, the MAINTAINERS file
+    patterns can be out of sync or outdated.
+
+    So MAINTAINERS might need updating in these cases.
+
+  **MEMSET**
+    The memset use appears to be incorrect.  This may be caused due to
+    badly ordered parameters.  Please recheck the usage.
 
   **NOT_UNIFIED_DIFF**
     The patch file does not appear to be in unified-diff format.  Please
@@ -742,14 +1157,12 @@ Others
   **PRINTF_0XDECIMAL**
     Prefixing 0x with decimal output is defective and should be corrected.
 
-  **TRAILING_STATEMENTS**
-    Trailing statements (for example after any conditional) should be
-    on the next line.
-    Like::
-
-      if (x == y) break;
+  **SPDX_LICENSE_TAG**
+    The source file is missing or has an improper SPDX identifier tag.
+    The Linux kernel requires the precise SPDX identifier in all source files,
+    and it is thoroughly documented in the kernel docs.
 
-    should be::
+    See: https://www.kernel.org/doc/html/latest/process/license-rules.html
 
-      if (x == y)
-              break;
+  **TYPO_SPELLING**
+    Some words may have been misspelled.  Consider reviewing them.
index 9b9bffe..b33ad72 100644 (file)
@@ -10,7 +10,7 @@ API Reference
 This section documents the KUnit kernel testing API. It is divided into the
 following sections:
 
-================================= ==============================================
-:doc:`test`                       documents all of the standard testing API
-                                  excluding mocking or mocking related features.
-================================= ==============================================
+Documentation/dev-tools/kunit/api/test.rst
+
+ - documents all of the standard testing API excluding mocking
+   or mocking related features.
index 8d5029a..5c6555d 100644 (file)
@@ -97,7 +97,7 @@ things to try.
    modules will automatically execute associated tests when loaded. Test results
    can be collected from ``/sys/kernel/debug/kunit/<test suite>/results``, and
    can be parsed with ``kunit.py parse``. For more details, see "KUnit on
-   non-UML architectures" in :doc:`usage`.
+   non-UML architectures" in Documentation/dev-tools/kunit/usage.rst.
 
 If none of the above tricks help, you are always welcome to email any issues to
 kunit-dev@googlegroups.com.
index 8484788..25d92a9 100644 (file)
@@ -36,7 +36,7 @@ To make running these tests (and reading the results) easier, KUnit offers
 results. This provides a quick way of running KUnit tests during development,
 without requiring a virtual machine or separate hardware.
 
-Get started now: :doc:`start`
+Get started now: Documentation/dev-tools/kunit/start.rst
 
 Why KUnit?
 ==========
@@ -88,9 +88,9 @@ it takes to read their test log?
 How do I use it?
 ================
 
-*   :doc:`start` - for new users of KUnit
-*   :doc:`tips` - for short examples of best practices
-*   :doc:`usage` - for a more detailed explanation of KUnit features
-*   :doc:`api/index` - for the list of KUnit APIs used for testing
-*   :doc:`kunit-tool` - for more information on the kunit_tool helper script
-*   :doc:`faq` - for answers to some common questions about KUnit
+*   Documentation/dev-tools/kunit/start.rst - for new users of KUnit
+*   Documentation/dev-tools/kunit/tips.rst - for short examples of best practices
+*   Documentation/dev-tools/kunit/usage.rst - for a more detailed explanation of KUnit features
+*   Documentation/dev-tools/kunit/api/index.rst - for the list of KUnit APIs used for testing
+*   Documentation/dev-tools/kunit/kunit-tool.rst - for more information on the kunit_tool helper script
+*   Documentation/dev-tools/kunit/faq.rst - for answers to some common questions about KUnit
index 0e65cab..63ef7b6 100644 (file)
@@ -21,7 +21,7 @@ The wrapper can be run with:
        ./tools/testing/kunit/kunit.py run
 
 For more information on this wrapper (also called kunit_tool) check out the
-:doc:`kunit-tool` page.
+Documentation/dev-tools/kunit/kunit-tool.rst page.
 
 Creating a .kunitconfig
 -----------------------
@@ -234,7 +234,7 @@ Congrats! You just wrote your first KUnit test!
 
 Next Steps
 ==========
-*   Check out the :doc:`tips` page for tips on
+*   Check out the Documentation/dev-tools/kunit/tips.rst page for tips on
     writing idiomatic KUnit tests.
 *   Optional: see the :doc:`usage` page for a more
     in-depth explanation of KUnit.
index 8d8c238..492d2de 100644 (file)
@@ -125,7 +125,8 @@ Here's a slightly in-depth example of how one could implement "mocking":
 
 
 Note: here we're able to get away with using ``test->priv``, but if you wanted
-something more flexible you could use a named ``kunit_resource``, see :doc:`api/test`.
+something more flexible you could use a named ``kunit_resource``, see
+Documentation/dev-tools/kunit/api/test.rst.
 
 Failing the current test
 ------------------------
@@ -185,5 +186,5 @@ Alternatively, one can take full control over the error message by using ``KUNIT
 
 Next Steps
 ==========
-*   Optional: see the :doc:`usage` page for a more
+*   Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more
     in-depth explanation of KUnit.
index 650f995..3ee7ab9 100644 (file)
@@ -10,7 +10,7 @@ understand it. This guide assumes a working knowledge of the Linux kernel and
 some basic knowledge of testing.
 
 For a high level introduction to KUnit, including setting up KUnit for your
-project, see :doc:`start`.
+project, see Documentation/dev-tools/kunit/start.rst.
 
 Organization of this document
 =============================
@@ -99,7 +99,8 @@ violated; however, the test will continue running, potentially trying other
 expectations until the test case ends or is otherwise terminated. This is as
 opposed to *assertions* which are discussed later.
 
-To learn about more expectations supported by KUnit, see :doc:`api/test`.
+To learn about more expectations supported by KUnit, see
+Documentation/dev-tools/kunit/api/test.rst.
 
 .. note::
    A single test case should be pretty short, pretty easy to understand,
@@ -216,7 +217,8 @@ test suite in a special linker section so that it can be run by KUnit either
 after late_init, or when the test module is loaded (depending on whether the
 test was built in or not).
 
-For more information on these types of things see the :doc:`api/test`.
+For more information on these types of things see the
+Documentation/dev-tools/kunit/api/test.rst.
 
 Common Patterns
 ===============
index b5b4670..65feb81 100644 (file)
@@ -71,15 +71,15 @@ can be used to verify that a test is executing particular functions or lines
 of code. This is useful for determining how much of the kernel is being tested,
 and for finding corner-cases which are not covered by the appropriate test.
 
-:doc:`gcov` is GCC's coverage testing tool, which can be used with the kernel
-to get global or per-module coverage. Unlike KCOV, it does not record per-task
-coverage. Coverage data can be read from debugfs, and interpreted using the
-usual gcov tooling.
-
-:doc:`kcov` is a feature which can be built in to the kernel to allow
-capturing coverage on a per-task level. It's therefore useful for fuzzing and
-other situations where information about code executed during, for example, a
-single syscall is useful.
+Documentation/dev-tools/gcov.rst is GCC's coverage testing tool, which can be
+used with the kernel to get global or per-module coverage. Unlike KCOV, it
+does not record per-task coverage. Coverage data can be read from debugfs,
+and interpreted using the usual gcov tooling.
+
+Documentation/dev-tools/kcov.rst is a feature which can be built in to the
+kernel to allow capturing coverage on a per-task level. It's therefore useful
+for fuzzing and other situations where information about code executed during,
+for example, a single syscall is useful.
 
 
 Dynamic Analysis Tools
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-actmon.txt
deleted file mode 100644 (file)
index 897eedf..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-NVIDIA Tegra Activity Monitor
-
-The activity monitor block collects statistics about the behaviour of other
-components in the system. This information can be used to derive the rate at
-which the external memory needs to be clocked in order to serve all requests
-from the monitored clients.
-
-Required properties:
-- compatible: should be "nvidia,tegra<chip>-actmon"
-- reg: offset and length of the register set for the device
-- interrupts: standard interrupt property
-- clocks: Must contain a phandle and clock specifier pair for each entry in
-clock-names. See ../../clock/clock-bindings.txt for details.
-- clock-names: Must include the following entries:
-  - actmon
-  - emc
-- resets: Must contain an entry for each entry in reset-names. See
-../../reset/reset.txt for details.
-- reset-names: Must include the following entries:
-  - actmon
-- operating-points-v2: See ../bindings/opp/opp.txt for details.
-- interconnects: Should contain entries for memory clients sitting on
-                 MC->EMC memory interconnect path.
-- interconnect-names: Should include name of the interconnect path for each
-                      interconnect entry. Consult TRM documentation for
-                      information about available memory clients, see MEMORY
-                      CONTROLLER section.
-
-For each opp entry in 'operating-points-v2' table:
-- opp-supported-hw: bitfield indicating SoC speedo ID mask
-- opp-peak-kBps: peak bandwidth of the memory channel
-
-Example:
-       dfs_opp_table: opp-table {
-               compatible = "operating-points-v2";
-
-               opp@12750000 {
-                       opp-hz = /bits/ 64 <12750000>;
-                       opp-supported-hw = <0x000F>;
-                       opp-peak-kBps = <51000>;
-               };
-               ...
-       };
-
-       actmon@6000c800 {
-               compatible = "nvidia,tegra124-actmon";
-               reg = <0x0 0x6000c800 0x0 0x400>;
-               interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&tegra_car TEGRA124_CLK_ACTMON>,
-                        <&tegra_car TEGRA124_CLK_EMC>;
-               clock-names = "actmon", "emc";
-               resets = <&tegra_car 119>;
-               reset-names = "actmon";
-               operating-points-v2 = <&dfs_opp_table>;
-               interconnects = <&mc TEGRA124_MC_MPCORER &emc>;
-               interconnect-names = "cpu";
-       };
diff --git a/Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml b/Documentation/devicetree/bindings/crypto/cortina,sl3516-crypto.yaml
new file mode 100644 (file)
index 0000000..b633b8d
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/cortina,sl3516-crypto.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SL3516 cryptographic offloader driver
+
+maintainers:
+  - Corentin Labbe <clabbe@baylibre.com>
+
+properties:
+  compatible:
+    enum:
+      - cortina,sl3516-crypto
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/clock/cortina,gemini-clock.h>
+    #include <dt-bindings/reset/cortina,gemini-reset.h>
+
+    crypto@62000000 {
+        compatible = "cortina,sl3516-crypto";
+        reg = <0x62000000 0x10000>;
+        interrupts = <7 IRQ_TYPE_EDGE_RISING>;
+        resets = <&syscon GEMINI_RESET_SECURITY>;
+        clocks = <&syscon GEMINI_CLK_GATE_SECURITY>;
+    };
diff --git a/Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml b/Documentation/devicetree/bindings/crypto/intel,ixp4xx-crypto.yaml
new file mode 100644 (file)
index 0000000..9c53c27
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2018 Linaro Ltd.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/crypto/intel,ixp4xx-crypto.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Intel IXP4xx cryptographic engine
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  The Intel IXP4xx cryptographic engine makes use of the IXP4xx NPE
+  (Network Processing Engine). Since it is not a device on its own
+  it is defined as a subnode of the NPE, if crypto support is
+  available on the platform.
+
+properties:
+  compatible:
+    const: intel,ixp4xx-crypto
+
+  intel,npe-handle:
+    $ref: '/schemas/types.yaml#/definitions/phandle-array'
+    maxItems: 1
+    description: phandle to the NPE this crypto engine is using, the cell
+      describing the NPE instance to be used.
+
+  queue-rx:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    maxItems: 1
+    description: phandle to the RX queue on the NPE, the cell describing
+      the queue instance to be used.
+
+  queue-txready:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    maxItems: 1
+    description: phandle to the TX READY queue on the NPE, the cell describing
+      the queue instance to be used.
+
+required:
+  - compatible
+  - intel,npe-handle
+  - queue-rx
+  - queue-txready
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml b/Documentation/devicetree/bindings/devfreq/nvidia,tegra30-actmon.yaml
new file mode 100644 (file)
index 0000000..e3379d1
--- /dev/null
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/nvidia,tegra30-actmon.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 Activity Monitor
+
+maintainers:
+  - Dmitry Osipenko <digetx@gmail.com>
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Thierry Reding <thierry.reding@gmail.com>
+
+description: |
+  The activity monitor block collects statistics about the behaviour of other
+  components in the system. This information can be used to derive the rate at
+  which the external memory needs to be clocked in order to serve all requests
+  from the monitored clients.
+
+properties:
+  compatible:
+    enum:
+      - nvidia,tegra30-actmon
+      - nvidia,tegra114-actmon
+      - nvidia,tegra124-actmon
+      - nvidia,tegra210-actmon
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: actmon
+      - const: emc
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: actmon
+
+  interrupts:
+    maxItems: 1
+
+  interconnects:
+    minItems: 1
+    maxItems: 12
+
+  interconnect-names:
+    minItems: 1
+    maxItems: 12
+    description:
+      Should include name of the interconnect path for each interconnect
+      entry. Consult TRM documentation for information about available
+      memory clients, see MEMORY CONTROLLER and ACTIVITY MONITOR sections.
+
+  operating-points-v2:
+    description:
+      Should contain freqs and voltages and opp-supported-hw property, which
+      is a bitfield indicating SoC speedo ID mask.
+
+  "#cooling-cells":
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - interrupts
+  - interconnects
+  - interconnect-names
+  - operating-points-v2
+  - "#cooling-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/memory/tegra30-mc.h>
+
+    mc: memory-controller@7000f000 {
+        compatible = "nvidia,tegra30-mc";
+        reg = <0x7000f000 0x400>;
+        clocks = <&clk 32>;
+        clock-names = "mc";
+
+        interrupts = <0 77 4>;
+
+        #iommu-cells = <1>;
+        #reset-cells = <1>;
+        #interconnect-cells = <1>;
+    };
+
+    emc: external-memory-controller@7000f400 {
+        compatible = "nvidia,tegra30-emc";
+        reg = <0x7000f400 0x400>;
+        interrupts = <0 78 4>;
+        clocks = <&clk 57>;
+
+        nvidia,memory-controller = <&mc>;
+        operating-points-v2 = <&dvfs_opp_table>;
+        power-domains = <&domain>;
+
+        #interconnect-cells = <0>;
+    };
+
+    actmon@6000c800 {
+        compatible = "nvidia,tegra30-actmon";
+        reg = <0x6000c800 0x400>;
+        interrupts = <0 45 4>;
+        clocks = <&clk 119>, <&clk 57>;
+        clock-names = "actmon", "emc";
+        resets = <&rst 119>;
+        reset-names = "actmon";
+        operating-points-v2 = <&dvfs_opp_table>;
+        interconnects = <&mc TEGRA30_MC_MPCORER &emc>;
+        interconnect-names = "cpu-read";
+        #cooling-cells = <2>;
+    };
index 1bd2870..c435c9f 100644 (file)
@@ -26,9 +26,16 @@ properties:
 
   reg:
     items:
-      - description: NPE0 register range
-      - description: NPE1 register range
-      - description: NPE2 register range
+      - description: NPE0 (NPE-A) register range
+      - description: NPE1 (NPE-B) register range
+      - description: NPE2 (NPE-C) register range
+
+  crypto:
+    $ref: /schemas/crypto/intel,ixp4xx-crypto.yaml#
+    type: object
+    description: Optional node for the embedded crypto engine, the node
+      should be named with the instance number of the NPE engine used for
+      the crypto engine.
 
 required:
   - compatible
@@ -38,8 +45,15 @@ additionalProperties: false
 
 examples:
   - |
-    npe@c8006000 {
+    npe: npe@c8006000 {
          compatible = "intel,ixp4xx-network-processing-engine";
          reg = <0xc8006000 0x1000>, <0xc8007000 0x1000>, <0xc8008000 0x1000>;
+
+         crypto {
+             compatible = "intel,ixp4xx-crypto";
+             intel,npe-handle = <&npe 2>;
+             queue-rx = <&qmgr 30>;
+             queue-txready = <&qmgr 29>;
+         };
     };
 ...
index 96eed5c..72980d0 100644 (file)
@@ -30,6 +30,7 @@ properties:
       - st,stds75
       - st,stlm75
       - microchip,tcn75
+      - ti,tmp1075
       - ti,tmp100
       - ti,tmp101
       - ti,tmp105
index 1ecd183..c84f9fe 100644 (file)
@@ -145,6 +145,19 @@ properties:
         required:
           - affinity
 
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: aclk
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
 dependencies:
   mbi-ranges: [ msi-controller ]
   msi-controller: [ mbi-ranges ]
index b67b8cb..abb22db 100644 (file)
@@ -29,6 +29,7 @@ properties:
           - renesas,intc-ex-r8a774c0    # RZ/G2E
           - renesas,intc-ex-r8a7795     # R-Car H3
           - renesas,intc-ex-r8a7796     # R-Car M3-W
+          - renesas,intc-ex-r8a77961    # R-Car M3-W+
           - renesas,intc-ex-r8a77965    # R-Car M3-N
           - renesas,intc-ex-r8a77970    # R-Car V3M
           - renesas,intc-ex-r8a77980    # R-Car V3H
diff --git a/Documentation/devicetree/bindings/media/atmel,isc.yaml b/Documentation/devicetree/bindings/media/atmel,isc.yaml
new file mode 100644 (file)
index 0000000..3e4bb88
--- /dev/null
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2016-2021 Microchip Technology, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/atmel,isc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel Image Sensor Controller (ISC)
+
+maintainers:
+  - Eugen Hristev <eugen.hristev@microchip.com>
+
+description: |
+  The Image Sensor Controller (ISC) device provides the video input capabilities for the
+  Atmel/Microchip AT91 SAMA family of devices.
+
+  The ISC has a single parallel input that supports RAW Bayer, RGB or YUV video,
+  with both external synchronization and BT.656 synchronization for the latter.
+
+properties:
+  compatible:
+    const: atmel,sama5d2-isc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 3
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: hclock
+      - const: iscck
+      - const: gck
+
+  '#clock-cells':
+    const: 0
+
+  clock-output-names:
+    const: isc-mck
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Input port node, single endpoint describing the input pad.
+
+    properties:
+      endpoint:
+        $ref: video-interfaces.yaml#
+
+        properties:
+          remote-endpoint: true
+
+          bus-width:
+            enum: [8, 9, 10, 11, 12]
+            default: 12
+
+          hsync-active:
+            enum: [0, 1]
+            default: 1
+
+          vsync-active:
+            enum: [0, 1]
+            default: 1
+
+          pclk-sample:
+            enum: [0, 1]
+            default: 1
+
+        required:
+          - remote-endpoint
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+  - clock-output-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    isc: isc@f0008000 {
+        compatible = "atmel,sama5d2-isc";
+        reg = <0xf0008000 0x4000>;
+        interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>;
+        clocks = <&isc_clk>, <&iscck>, <&isc_gclk>;
+        clock-names = "hclock", "iscck", "gck";
+        #clock-cells = <0>;
+        clock-output-names = "isc-mck";
+
+        port {
+                isc_0: endpoint {
+                       remote-endpoint = <&ov7740_0>;
+                       hsync-active = <1>;
+                       vsync-active = <0>;
+                       pclk-sample = <1>;
+                       bus-width = <8>;
+                };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/media/atmel-isc.txt b/Documentation/devicetree/bindings/media/atmel-isc.txt
deleted file mode 100644 (file)
index bbe0e87..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Atmel Image Sensor Controller (ISC)
-----------------------------------------------
-
-Required properties for ISC:
-- compatible
-       Must be "atmel,sama5d2-isc".
-- reg
-       Physical base address and length of the registers set for the device.
-- interrupts
-       Should contain IRQ line for the ISC.
-- clocks
-       List of clock specifiers, corresponding to entries in
-       the clock-names property;
-       Please refer to clock-bindings.txt.
-- clock-names
-       Required elements: "hclock", "iscck", "gck".
-- #clock-cells
-       Should be 0.
-- clock-output-names
-       Should be "isc-mck".
-- pinctrl-names, pinctrl-0
-       Please refer to pinctrl-bindings.txt.
-
-ISC supports a single port node with parallel bus. It should contain one
-'port' child node with child 'endpoint' node. Please refer to the bindings
-defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
-
-Example:
-isc: isc@f0008000 {
-       compatible = "atmel,sama5d2-isc";
-       reg = <0xf0008000 0x4000>;
-       interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>;
-       clocks = <&isc_clk>, <&iscck>, <&isc_gclk>;
-       clock-names = "hclock", "iscck", "gck";
-       #clock-cells = <0>;
-       clock-output-names = "isc-mck";
-       pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>;
-
-       port {
-               isc_0: endpoint {
-                       remote-endpoint = <&ov7740_0>;
-                       hsync-active = <1>;
-                       vsync-active = <0>;
-                       pclk-sample = <1>;
-               };
-       };
-};
-
-i2c1: i2c@fc028000 {
-       ov7740: camera@21 {
-               compatible = "ovti,ov7740";
-               reg = <0x21>;
-               clocks = <&isc>;
-               clock-names = "xvclk";
-               assigned-clocks = <&isc>;
-               assigned-clock-rates = <24000000>;
-
-               port {
-                       ov7740_0: endpoint {
-                               remote-endpoint = <&isc_0>;
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml b/Documentation/devicetree/bindings/media/i2c/rda,rda5807.yaml
new file mode 100644 (file)
index 0000000..f50e54a
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/rda,rda5807.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Unisoc Communications RDA5807 FM radio receiver
+
+maintainers:
+  - Paul Cercueil <paul@crapouillou.net>
+
+properties:
+  compatible:
+    enum:
+      - rda,rda5807
+
+  reg:
+    description: I2C address.
+    maxItems: 1
+
+  power-supply: true
+
+  rda,lnan:
+    description: Use LNAN input port.
+    type: boolean
+
+  rda,lnap:
+    description: Use LNAP input port.
+    type: boolean
+
+  rda,analog-out:
+    description: Enable analog audio output.
+    type: boolean
+
+  rda,i2s-out:
+    description: Enable I2S digital audio output.
+    type: boolean
+
+  rda,lna-microamp:
+    description: LNA working current, in micro-amperes.
+    default: 2500
+    enum: [1800, 2100, 2500, 3000]
+
+required:
+  - compatible
+  - reg
+  - power-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      radio@11 {
+        compatible = "rda,rda5807";
+        reg = <0x11>;
+
+        power-supply = <&ldo6>;
+
+        rda,lnan;
+        rda,lnap;
+        rda,analog-out;
+      };
+    };
index 06db683..ad1321e 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
   "mediatek,mt8173-vcodec-enc" for mt8173 avc encoder.
   "mediatek,mt8183-vcodec-enc" for MT8183 encoder.
   "mediatek,mt8173-vcodec-dec" for MT8173 decoder.
+  "mediatek,mt8192-vcodec-enc" for MT8192 encoder.
 - reg : Physical base address of the video codec registers and length of
   memory mapped region.
 - interrupts : interrupt number to the cpu.
@@ -22,6 +23,7 @@ Required properties:
 - iommus : should point to the respective IOMMU block with master port as
   argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
   for details.
+- dma-ranges : describes the dma address range space that the codec hw access.
 One of the two following nodes:
 - mediatek,vpu : the node of the video processor unit, if using VPU.
 - mediatek,scp : the node of the SCP unit, if using SCP.
diff --git a/Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml b/Documentation/devicetree/bindings/media/microchip,sama5d4-vdec.yaml
new file mode 100644 (file)
index 0000000..4b77103
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/microchip,sama5d4-vdec.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Hantro G1 VPU codec implemented on Microchip SAMA5D4 SoCs
+
+maintainers:
+  - Emil Velikov <emil.velikov@collabora.com>
+
+description:
+  Hantro G1 video decode accelerator present on Microchip SAMA5D4 SoCs.
+
+properties:
+  compatible:
+    const: microchip,sama5d4-vdec
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+        #include <dt-bindings/clock/at91.h>
+        #include <dt-bindings/interrupt-controller/irq.h>
+
+        vdec0: vdec@300000 {
+                compatible = "microchip,sama5d4-vdec";
+                reg = <0x00300000 0x100000>;
+                interrupts = <19 IRQ_TYPE_LEVEL_HIGH 4>;
+                clocks = <&pmc PMC_TYPE_PERIPHERAL 19>;
+        };
diff --git a/Documentation/devicetree/bindings/media/microchip,xisc.yaml b/Documentation/devicetree/bindings/media/microchip,xisc.yaml
new file mode 100644 (file)
index 0000000..41afe2e
--- /dev/null
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2021 Microchip Technology, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/microchip,xisc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip eXtended Image Sensor Controller (XISC)
+
+maintainers:
+  - Eugen Hristev <eugen.hristev@microchip.com>
+
+description: |
+  The eXtended Image Sensor Controller (XISC) device provides the video input capabilities for the
+  Microchip AT91 SAM family of devices.
+
+  The XISC has a single internal parallel input that supports RAW Bayer, RGB or YUV video.
+  The source can be either a demuxer from a CSI2 type of bus, or a simple direct bridge to a
+  parallel sensor.
+
+  The XISC provides one clock output that is used to clock the demuxer/bridge.
+
+properties:
+  compatible:
+    const: microchip,sama7g5-isc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: hclock
+
+  '#clock-cells':
+    const: 0
+
+  clock-output-names:
+    const: isc-mck
+
+  microchip,mipi-mode:
+    type: boolean
+    description:
+      As the XISC is usually connected to a demux/bridge, the XISC receives
+      the same type of input, however, it should be aware of the type of
+      signals received. The mipi-mode enables different internal handling
+      of the data and clock lines.
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      Input port node, single endpoint describing the input pad.
+
+    properties:
+      endpoint:
+        $ref: video-interfaces.yaml#
+
+        properties:
+          bus-type:
+            enum: [5, 6]
+
+          remote-endpoint: true
+
+          bus-width:
+            enum: [8, 9, 10, 11, 12]
+            default: 12
+
+          hsync-active:
+            enum: [0, 1]
+            default: 1
+
+          vsync-active:
+            enum: [0, 1]
+            default: 1
+
+          pclk-sample:
+            enum: [0, 1]
+            default: 1
+
+        required:
+          - remote-endpoint
+          - bus-type
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - '#clock-cells'
+  - clock-output-names
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/at91.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    xisc: xisc@e1408000 {
+        compatible = "microchip,sama7g5-isc";
+        reg = <0xe1408000 0x2000>;
+        interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&pmc PMC_TYPE_PERIPHERAL 56>;
+        clock-names = "hclock";
+        #clock-cells = <0>;
+        clock-output-names = "isc-mck";
+
+        port {
+                xisc_in: endpoint {
+                       bus-type = <5>; /* Parallel */
+                       remote-endpoint = <&csi2dc_out>;
+                       hsync-active = <1>;
+                       vsync-active = <1>;
+                       bus-width = <12>;
+                };
+        };
+    };
+
index d8ed480..7c09eec 100644 (file)
@@ -4,15 +4,17 @@
 $id: http://devicetree.org/schemas/media/nxp,imx7-mipi-csi2.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: NXP i.MX7 MIPI CSI-2 receiver
+title: NXP i.MX7 and i.MX8 MIPI CSI-2 receiver
 
 maintainers:
   - Rui Miguel Silva <rmfrfs@gmail.com>
+  - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 
 description: |-
-  The NXP i.MX7 SoC family includes a MIPI CSI-2 receiver IP core, documented
-  as "CSIS V3.3". The IP core seems to originate from Samsung, and may be
-  compatible with some of the Exynos4 ad S5P SoCs.
+  The NXP i.MX7 and i.MX8 families contain SoCs that include a MIPI CSI-2
+  receiver IP core named CSIS. The IP core originates from Samsung, and may be
+  compatible with some of the Exynos4 and S5P SoCs. i.MX7 SoCs use CSIS version
+  3.3, and i.MX8 SoCs use CSIS version 3.6.3.
 
   While the CSI-2 receiver is separate from the MIPI D-PHY IP core, the PHY is
   completely wrapped by the CSIS and doesn't expose a control interface of its
@@ -20,7 +22,9 @@ description: |-
 
 properties:
   compatible:
-    const: fsl,imx7-mipi-csi2
+    enum:
+      - fsl,imx7-mipi-csi2
+      - fsl,imx8mm-mipi-csi2
 
   reg:
     maxItems: 1
@@ -29,16 +33,20 @@ properties:
     maxItems: 1
 
   clocks:
+    minItems: 3
     items:
       - description: The peripheral clock (a.k.a. APB clock)
       - description: The external clock (optionally used as the pixel clock)
       - description: The MIPI D-PHY clock
+      - description: The AXI clock
 
   clock-names:
+    minItems: 3
     items:
       - const: pclk
       - const: wrap
       - const: phy
+      - const: axi
 
   power-domains:
     maxItems: 1
@@ -71,16 +79,30 @@ properties:
 
             properties:
               data-lanes:
-                oneOf:
-                  - items:
-                      - const: 1
-                  - items:
-                      - const: 1
-                      - const: 2
+                items:
+                  minItems: 1
+                  maxItems: 4
+                  items:
+                    - const: 1
+                    - const: 2
+                    - const: 3
+                    - const: 4
 
             required:
               - data-lanes
 
+            allOf:
+              - if:
+                  properties:
+                    compatible:
+                      contains:
+                        const: fsl,imx7-mipi-csi2
+                then:
+                  properties:
+                    data-lanes:
+                      items:
+                        maxItems: 2
+
       port@1:
         $ref: /schemas/graph.yaml#/properties/port
         description:
@@ -93,12 +115,29 @@ required:
   - clocks
   - clock-names
   - power-domains
-  - phy-supply
-  - resets
   - ports
 
 additionalProperties: false
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: fsl,imx7-mipi-csi2
+    then:
+      required:
+        - phy-supply
+        - resets
+    else:
+      properties:
+        clocks:
+          minItems: 4
+        clock-names:
+          minItems: 4
+        phy-supply: false
+        resets: false
+
 examples:
   - |
     #include <dt-bindings/clock/imx7d-clock.h>
@@ -106,7 +145,7 @@ examples:
     #include <dt-bindings/interrupt-controller/irq.h>
     #include <dt-bindings/reset/imx7-reset.h>
 
-    mipi_csi: mipi-csi@30750000 {
+    mipi-csi@30750000 {
         compatible = "fsl,imx7-mipi-csi2";
         reg = <0x30750000 0x10000>;
         interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
@@ -144,4 +183,46 @@ examples:
         };
     };
 
+  - |
+    #include <dt-bindings/clock/imx8mm-clock.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    mipi-csi@32e30000 {
+        compatible = "fsl,imx8mm-mipi-csi2";
+        reg = <0x32e30000 0x1000>;
+        interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+        clock-frequency = <333000000>;
+        clocks = <&clk IMX8MM_CLK_DISP_APB_ROOT>,
+                 <&clk IMX8MM_CLK_CSI1_ROOT>,
+                 <&clk IMX8MM_CLK_CSI1_PHY_REF>,
+                 <&clk IMX8MM_CLK_DISP_AXI_ROOT>;
+        clock-names = "pclk", "wrap", "phy", "axi";
+        power-domains = <&mipi_pd>;
+
+        status = "disabled";
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+
+                imx8mm_mipi_csi_in: endpoint {
+                    remote-endpoint = <&imx477_out>;
+                    data-lanes = <1 2 3 4>;
+                };
+            };
+
+            port@1 {
+                reg = <1>;
+
+                imx8mm_mipi_csi_out: endpoint {
+                    remote-endpoint = <&csi_in>;
+                };
+            };
+        };
+    };
+
 ...
index af9e7e5..d4c541c 100644 (file)
@@ -45,6 +45,7 @@ properties:
       - rc-cec
       - rc-cinergy
       - rc-cinergy-1400
+      - rc-ct-90405
       - rc-d680-dmb
       - rc-delock-61959
       - rc-dib0700-nec
@@ -125,7 +126,6 @@ properties:
       - rc-snapstream-firefly
       - rc-streamzap
       - rc-su3000
-      - rc-tango
       - rc-tanix-tx3mini
       - rc-tanix-tx5max
       - rc-tbs-nec
index 20396f1..23703b7 100644 (file)
@@ -25,6 +25,7 @@ properties:
           - renesas,r8a774e1-csi2 # RZ/G2H
           - renesas,r8a7795-csi2  # R-Car H3
           - renesas,r8a7796-csi2  # R-Car M3-W
+          - renesas,r8a77961-csi2 # R-Car M3-W+
           - renesas,r8a77965-csi2 # R-Car M3-N
           - renesas,r8a77970-csi2 # R-Car V3M
           - renesas,r8a77980-csi2 # R-Car V3H
diff --git a/Documentation/devicetree/bindings/media/renesas,isp.yaml b/Documentation/devicetree/bindings/media/renesas,isp.yaml
new file mode 100644 (file)
index 0000000..514857d
--- /dev/null
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+# Copyright (C) 2021 Renesas Electronics Corp.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/renesas,isp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas R-Car ISP Channel Selector
+
+maintainers:
+  - Niklas Söderlund <niklas.soderlund@ragnatech.se>
+
+description:
+  The R-Car ISP Channel Selector provides MIPI CSI-2 VC and DT filtering
+  capabilities for the Renesas R-Car family of devices. It is used in
+  conjunction with the R-Car VIN and CSI-2 modules, which provides the video
+  capture capabilities.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r8a779a0-isp # V3U
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Input port node, multiple endpoints describing the connected R-Car
+          CSI-2 receivers.
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 0.
+
+      port@2:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 1.
+
+      port@3:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 2.
+
+      port@4:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 3.
+
+      port@5:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 4.
+
+      port@6:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 5.
+
+      port@7:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 6.
+
+      port@8:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Single endpoint describing the R-Car VIN connected to output port 7.
+
+    required:
+      - port@0
+      - port@1
+      - port@2
+      - port@3
+      - port@4
+      - port@5
+      - port@6
+      - port@7
+      - port@8
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - power-domains
+  - resets
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/r8a779a0-sysc.h>
+
+    isp1: isp@fed20000 {
+            compatible = "renesas,r8a779a0-isp";
+            reg = <0xfed20000 0x10000>;
+            interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&cpg CPG_MOD 613>;
+            power-domains = <&sysc R8A779A0_PD_A3ISP01>;
+            resets = <&cpg 613>;
+
+            ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    port@0 {
+                            #address-cells = <1>;
+                            #size-cells = <0>;
+
+                            reg = <0>;
+                            isp1csi41: endpoint@1 {
+                                    reg = <1>;
+                                    remote-endpoint = <&csi41isp1>;
+                            };
+                    };
+
+                    port@1 {
+                            reg = <1>;
+                            isp1vin08: endpoint {
+                                    remote-endpoint = <&vin08isp1>;
+                            };
+                    };
+
+                    port@2 {
+                            reg = <2>;
+                            isp1vin09: endpoint {
+                                    remote-endpoint = <&vin09isp1>;
+                            };
+                    };
+
+                    port@3 {
+                            reg = <3>;
+                            isp1vin10: endpoint {
+                                    remote-endpoint = <&vin10isp1>;
+                            };
+                    };
+
+                    port@4 {
+                            reg = <4>;
+                            isp1vin11: endpoint {
+                                    remote-endpoint = <&vin11isp1>;
+                            };
+                    };
+
+                    port@5 {
+                            reg = <5>;
+                            isp1vin12: endpoint {
+                                    remote-endpoint = <&vin12isp1>;
+                            };
+                    };
+
+                    port@6 {
+                            reg = <6>;
+                            isp1vin13: endpoint {
+                                    remote-endpoint = <&vin13isp1>;
+                            };
+                    };
+
+                    port@7 {
+                            reg = <7>;
+                            isp1vin14: endpoint {
+                                    remote-endpoint = <&vin14isp1>;
+                            };
+                    };
+
+                    port@8 {
+                            reg = <8>;
+                            isp1vin15: endpoint {
+                                    remote-endpoint = <&vin15isp1>;
+                            };
+                    };
+            };
+    };
index dd1a5ce..39bb6db 100644 (file)
@@ -46,11 +46,13 @@ properties:
               - renesas,vin-r8a7779  # R-Car H1
               - renesas,vin-r8a7795  # R-Car H3
               - renesas,vin-r8a7796  # R-Car M3-W
+              - renesas,vin-r8a77961 # R-Car M3-W+
               - renesas,vin-r8a77965 # R-Car M3-N
               - renesas,vin-r8a77970 # R-Car V3M
               - renesas,vin-r8a77980 # R-Car V3H
               - renesas,vin-r8a77990 # R-Car E3
               - renesas,vin-r8a77995 # R-Car D3
+              - renesas,vin-r8a779a0 # R-Car V3U
 
   reg:
     maxItems: 1
@@ -111,7 +113,7 @@ properties:
     description: VIN channel number
     $ref: /schemas/types.yaml#/definitions/uint32
     minimum: 0
-    maximum: 15
+    maximum: 31
 
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
@@ -187,6 +189,29 @@ properties:
           - required:
               - endpoint@3
 
+      port@2:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Input port node, multiple endpoints describing all the R-Car ISP
+          modules connected the VIN.
+
+        properties:
+          endpoint@0:
+            $ref: /schemas/graph.yaml#/properties/endpoint
+            description: Endpoint connected to ISP0.
+
+          endpoint@1:
+            $ref: /schemas/graph.yaml#/properties/endpoint
+            description: Endpoint connected to ISP1.
+
+          endpoint@2:
+            $ref: /schemas/graph.yaml#/properties/endpoint
+            description: Endpoint connected to ISP2.
+
+          endpoint@3:
+            $ref: /schemas/graph.yaml#/properties/endpoint
+            description: Endpoint connected to ISP3.
+
 required:
   - compatible
   - reg
index 8d35c32..089f11d 100644 (file)
@@ -15,7 +15,11 @@ description: |-
 
 properties:
   compatible:
-    const: rockchip,rk3399-vdec
+    oneOf:
+      - const: rockchip,rk3399-vdec
+      - items:
+          - const: rockchip,rk3228-vdec
+          - const: rockchip,rk3399-vdec
 
   reg:
     maxItems: 1
@@ -37,6 +41,10 @@ properties:
       - const: cabac
       - const: core
 
+  assigned-clocks: true
+
+  assigned-clock-rates: true
+
   power-domains:
     maxItems: 1
 
index c81dbc3..b88172a 100644 (file)
@@ -15,10 +15,19 @@ description:
 
 properties:
   compatible:
-    enum:
-      - rockchip,rk3288-vpu
-      - rockchip,rk3328-vpu
-      - rockchip,rk3399-vpu
+    oneOf:
+      - enum:
+          - rockchip,rk3036-vpu
+          - rockchip,rk3066-vpu
+          - rockchip,rk3288-vpu
+          - rockchip,rk3328-vpu
+          - rockchip,rk3399-vpu
+      - items:
+          - const: rockchip,rk3188-vpu
+          - const: rockchip,rk3066-vpu
+      - items:
+          - const: rockchip,rk3228-vpu
+          - const: rockchip,rk3399-vpu
 
   reg:
     maxItems: 1
@@ -35,12 +44,20 @@ properties:
           - const: vdpu
 
   clocks:
-    maxItems: 2
+    oneOf:
+      - maxItems: 2
+      - maxItems: 4
 
   clock-names:
-    items:
-      - const: aclk
-      - const: hclk
+    oneOf:
+      - items:
+          - const: aclk
+          - const: hclk
+      - items:
+          - const: aclk_vdpu
+          - const: hclk_vdpu
+          - const: aclk_vepu
+          - const: hclk_vepu
 
   power-domains:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/tango-ir.txt b/Documentation/devicetree/bindings/media/tango-ir.txt
deleted file mode 100644 (file)
index a9f00c2..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Sigma Designs Tango IR NEC/RC-5/RC-6 decoder (SMP86xx and SMP87xx)
-
-Required properties:
-
-- compatible: "sigma,smp8642-ir"
-- reg: address/size of NEC+RC5 area, address/size of RC6 area
-- interrupts: spec for IR IRQ
-- clocks: spec for IR clock (typically the crystal oscillator)
-
-Optional properties:
-
-- linux,rc-map-name: see Documentation/devicetree/bindings/media/rc.txt
-
-Example:
-
-       ir@10518 {
-               compatible = "sigma,smp8642-ir";
-               reg = <0x10518 0x18>, <0x105e0 0x1c>;
-               interrupts = <21 IRQ_TYPE_EDGE_RISING>;
-               clocks = <&xtal>;
-       };
index 2661775..99a84b6 100644 (file)
@@ -21,6 +21,7 @@ Required properties:
 compatible:
        "mediatek,mt6323" for PMIC MT6323
        "mediatek,mt6358" for PMIC MT6358
+       "mediatek,mt6359" for PMIC MT6359
        "mediatek,mt6397" for PMIC MT6397
 
 Optional subnodes:
index 6f569fb..2f63f2c 100644 (file)
@@ -21,6 +21,7 @@ properties:
       - brcm,bcm2711-emmc2
       - brcm,sdhci-iproc-cygnus
       - brcm,sdhci-iproc
+      - brcm,bcm7211a0-sdhci
 
   reg:
     minItems: 1
index 04ba8b7..546480f 100644 (file)
@@ -19,6 +19,7 @@ properties:
           - ingenic,jz4740-mmc
           - ingenic,jz4725b-mmc
           - ingenic,jz4760-mmc
+          - ingenic,jz4775-mmc
           - ingenic,jz4780-mmc
           - ingenic,x1000-mmc
       - items:
index e141330..25ac8e2 100644 (file)
@@ -220,6 +220,11 @@ properties:
     description:
       eMMC HS400 enhanced strobe mode is supported
 
+  no-mmc-hs400:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      All eMMC HS400 modes are not supported.
+
   dsr:
     description:
       Value the card Driver Stage Register (DSR) should be programmed
@@ -358,22 +363,6 @@ additionalProperties: true
 
 examples:
   - |
-    mmc@ab000000 {
-        compatible = "sdhci";
-        reg = <0xab000000 0x200>;
-        interrupts = <23>;
-        bus-width = <4>;
-        cd-gpios = <&gpio 69 0>;
-        cd-inverted;
-        wp-gpios = <&gpio 70 0>;
-        max-frequency = <50000000>;
-        keep-power-in-suspend;
-        wakeup-source;
-        mmc-pwrseq = <&sdhci0_pwrseq>;
-        clk-phase-sd-hs = <63>, <72>;
-    };
-
-  - |
     mmc3: mmc@1c12000 {
         #address-cells = <1>;
         #size-cells = <0>;
@@ -385,9 +374,9 @@ examples:
         non-removable;
         mmc-pwrseq = <&sdhci0_pwrseq>;
 
-        brcmf: bcrmf@1 {
+        brcmf: wifi@1 {
             reg = <1>;
-            compatible = "brcm,bcm43xx-fmac";
+            compatible = "brcm,bcm4329-fmac";
             interrupt-parent = <&pio>;
             interrupts = <10 8>;
             interrupt-names = "host-wake";
diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
deleted file mode 100644 (file)
index 291532a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-* Renesas Multi Media Card Interface (MMCIF) Controller
-
-This file documents differences between the core properties in mmc.txt
-and the properties used by the MMCIF device.
-
-
-Required properties:
-
-- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
-  fallback. Examples with <soctype> are:
-       - "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs
-       - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
-       - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
-       - "renesas,mmcif-r8a7742" for the MMCIF found in r8a7742 SoCs
-       - "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs
-       - "renesas,mmcif-r8a7744" for the MMCIF found in r8a7744 SoCs
-       - "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs
-       - "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
-       - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
-       - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
-       - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
-       - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
-       - "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
-
-- interrupts: Some SoCs have only 1 shared interrupt, while others have either
-  2 or 3 individual interrupts (error, int, card detect). Below is the number
-  of interrupts for each SoC:
-    1: r8a73a4, r8a7742, r8a7743, r8a7744, r8a7745, r8a7778, r8a7790, r8a7791,
-       r8a7793, r8a7794
-    2: r8a7740, sh73a0
-    3: r7s72100
-
-- clocks: reference to the functional clock
-
-- dmas: reference to the DMA channels, one per channel name listed in the
-  dma-names property.
-- dma-names: must contain "tx" for the transmit DMA channel and "rx" for the
-  receive DMA channel.
-- max-frequency: Maximum operating clock frequency, driver uses default clock
-  frequency if it is not set.
-
-
-Example: R8A7790 (R-Car H2) MMCIF0
-
-       mmcif0: mmc@ee200000 {
-               compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
-               reg = <0 0xee200000 0 0x80>;
-               interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>;
-               dmas = <&dmac0 0xd1>, <&dmac0 0xd2>;
-               dma-names = "tx", "rx";
-               max-frequency = <97500000>;
-       };
diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml b/Documentation/devicetree/bindings/mmc/renesas,mmcif.yaml
new file mode 100644 (file)
index 0000000..c36ba56
--- /dev/null
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/renesas,mmcif.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas Multi Media Card Interface (MMCIF) Controller
+
+maintainers:
+  - Wolfram Sang <wsa+renesas@sang-engineering.com>
+
+allOf:
+  - $ref: "mmc-controller.yaml"
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,mmcif-r7s72100 # RZ/A1H
+          - renesas,mmcif-r8a73a4  # R-Mobile APE6
+          - renesas,mmcif-r8a7740  # R-Mobile A1
+          - renesas,mmcif-r8a7742  # RZ/G1H
+          - renesas,mmcif-r8a7743  # RZ/G1M
+          - renesas,mmcif-r8a7744  # RZ/G1N
+          - renesas,mmcif-r8a7745  # RZ/G1E
+          - renesas,mmcif-r8a7778  # R-Car M1A
+          - renesas,mmcif-r8a7790  # R-Car H2
+          - renesas,mmcif-r8a7791  # R-Car M2-W
+          - renesas,mmcif-r8a7793  # R-Car M2-N
+          - renesas,mmcif-r8a7794  # R-Car E2
+          - renesas,mmcif-sh73a0   # SH-Mobile AG5
+      - const: renesas,sh-mmcif
+
+  reg:
+    maxItems: 1
+
+  interrupts: true
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  dmas:
+    minItems: 2
+    maxItems: 4
+    description:
+      Must contain a list of pairs of references to DMA specifiers, one for
+      transmission, and one for reception.
+
+  dma-names:
+    minItems: 2
+    maxItems: 4
+    items:
+      enum:
+        - tx
+        - rx
+
+  max-frequency: true
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - power-domains
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: renesas,mmcif-r7s72100
+then:
+  properties:
+    interrupts:
+      items:
+        - description: Error interrupt
+        - description: Normal operation interrupt
+        - description: Card detection interrupt
+else:
+  if:
+    properties:
+      compatible:
+        contains:
+          enum:
+            - renesas,mmcif-r8a7740
+            - renesas,mmcif-sh73a0
+  then:
+    properties:
+      interrupts:
+        items:
+          - description: Error interrupt
+          - description: Normal operation interrupt
+  else:
+    if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - renesas,mmcif-r8a73a4
+              - renesas,mmcif-r8a7778
+    then:
+      properties:
+        interrupts:
+          maxItems: 1
+    else:
+      properties:
+        interrupts:
+          maxItems: 1
+      required:
+        - resets
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/r8a7790-cpg-mssr.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/r8a7790-sysc.h>
+
+    mmcif0: mmc@ee200000 {
+            compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
+            reg = <0xee200000 0x80>;
+            interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&cpg CPG_MOD 315>;
+            power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
+            resets = <&cpg 315>;
+            dmas = <&dmac0 0xd1>, <&dmac0 0xd2>, <&dmac1 0xd1>, <&dmac1 0xd2>;
+            dma-names = "tx", "rx", "tx", "rx";
+            max-frequency = <97500000>;
+    };
index 3762f1c..54fb598 100644 (file)
@@ -29,21 +29,15 @@ properties:
       - const: rockchip,rk3288-dw-mshc
       - items:
           - enum:
-            # for Rockchip PX30
               - rockchip,px30-dw-mshc
-            # for Rockchip RK3036
+              - rockchip,rk1808-dw-mshc
               - rockchip,rk3036-dw-mshc
-            # for Rockchip RK322x
               - rockchip,rk3228-dw-mshc
-            # for Rockchip RK3308
               - rockchip,rk3308-dw-mshc
-            # for Rockchip RK3328
               - rockchip,rk3328-dw-mshc
-            # for Rockchip RK3368
               - rockchip,rk3368-dw-mshc
-            # for Rockchip RK3399
               - rockchip,rk3399-dw-mshc
-            # for Rockchip RV1108
+              - rockchip,rk3568-dw-mshc
               - rockchip,rv1108-dw-mshc
           - const: rockchip,rk3288-dw-mshc
 
index 3a79e39..29399e8 100644 (file)
@@ -19,7 +19,6 @@ properties:
       - const: ti,am654-sdhci-5.1
       - const: ti,j721e-sdhci-8bit
       - const: ti,j721e-sdhci-4bit
-      - const: ti,j721e-sdhci-4bit
       - const: ti,am64-sdhci-8bit
       - const: ti,am64-sdhci-4bit
       - items:
diff --git a/Documentation/devicetree/bindings/regulator/max8893.yaml b/Documentation/devicetree/bindings/regulator/max8893.yaml
new file mode 100644 (file)
index 0000000..2b5e977
--- /dev/null
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/max8893.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Regulator driver for MAX8893 PMIC from Maxim Integrated.
+
+maintainers:
+  - Sergey Larin <cerg2010cerg2010@mail.ru>
+
+description: |
+  The device has 5 LDO regulators and a single BUCK regulator.
+  Programming is done through I2C bus.
+
+properties:
+  compatible:
+    const: maxim,max8893
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+
+    patternProperties:
+      "^(ldo[1-5]|buck)$":
+        $ref: "regulator.yaml#"
+
+    additionalProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - regulators
+
+examples:
+  - |
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            pmic@3e {
+                    compatible = "maxim,max8893";
+                    reg = <0x3e>;
+
+                    regulators {
+                            /* Front camera - s5k6aafx, back - m5mo */
+                            /* Numbers used to indicate the sequence */
+                            front_1_back_1: buck {
+                                    regulator-name = "cam_isp_core_1v2";
+                                    regulator-min-microvolt = <1200000>;
+                                    regulator-max-microvolt = <1200000>;
+                            };
+
+                            front_4_back_5: ldo1 {
+                                    regulator-name = "vt_io_1v8,cam_isp_1v8";
+                                    regulator-min-microvolt = <1800000>;
+                                    regulator-max-microvolt = <1800000>;
+                            };
+
+                            front_3_back_4: ldo2 {
+                                    regulator-name = "vt_core_1v5";
+                                    regulator-min-microvolt = <1500000>;
+                                    regulator-max-microvolt = <1500000>;
+                            };
+
+                            front_5_back_6: ldo3 {
+                                    regulator-name = "vt_cam_1v8,vt_sensor_io_1v8";
+                                    regulator-min-microvolt = <1800000>;
+                                    regulator-max-microvolt = <1800000>;
+                            };
+
+                            ldo4 {
+                                    /* not used */
+                            };
+
+                            back_7: ldo5 {
+                                    regulator-name = "cam_sensor_io_1v8";
+                                    regulator-min-microvolt = <1800000>;
+                                    regulator-max-microvolt = <1800000>;
+                            };
+                    };
+            };
+    };
+...
diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
new file mode 100644 (file)
index 0000000..8cc413e
--- /dev/null
@@ -0,0 +1,385 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mt6359-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MT6359 Regulator from MediaTek Integrated
+
+maintainers:
+  - Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>
+
+description: |
+  List of regulators provided by this controller. It is named
+  according to its regulator type, buck_<name> and ldo_<name>.
+  MT6359 regulators node should be sub node of the MT6397 MFD node.
+
+patternProperties:
+  "^buck_v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$"
+
+    unevaluatedProperties: false
+
+  "^ldo_v(ibr|rf12|usb|camio|efuse|xo22)$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^v(ibr|rf12|usb|camio|efuse|xo22)$"
+
+    unevaluatedProperties: false
+
+  "^ldo_v(rfck|emc|a12|a09|ufs|bbck)$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^v(rfck|emc|a12|a09|ufs|bbck)$"
+
+    unevaluatedProperties: false
+
+  "^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$"
+
+    unevaluatedProperties: false
+
+  "^ldo_vsram_(proc2|others|md|proc1|others_sshub)$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^vsram_(proc2|others|md|proc1|others_sshub)$"
+
+    unevaluatedProperties: false
+
+  "^ldo_v(fe|bif|io)28$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^v(fe|bif|io)28$"
+
+    unevaluatedProperties: false
+
+  "^ldo_v(aud|io|aux|rf|m)18$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^v(aud|io|aux|rf|m)18$"
+
+    unevaluatedProperties: false
+
+  "^ldo_vsim[12]$":
+    type: object
+    $ref: "regulator.yaml#"
+
+    properties:
+      regulator-name:
+        pattern: "^vsim[12]$"
+
+    required:
+      - regulator-name
+
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    pmic {
+      regulators {
+        mt6359_vs1_buck_reg: buck_vs1 {
+          regulator-name = "vs1";
+          regulator-min-microvolt = <800000>;
+          regulator-max-microvolt = <2200000>;
+          regulator-enable-ramp-delay = <0>;
+          regulator-always-on;
+        };
+        mt6359_vgpu11_buck_reg: buck_vgpu11 {
+          regulator-name = "vgpu11";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+          regulator-ramp-delay = <5000>;
+          regulator-enable-ramp-delay = <200>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+        mt6359_vmodem_buck_reg: buck_vmodem {
+          regulator-name = "vmodem";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1100000>;
+          regulator-ramp-delay = <10760>;
+          regulator-enable-ramp-delay = <200>;
+        };
+        mt6359_vpu_buck_reg: buck_vpu {
+          regulator-name = "vpu";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+          regulator-ramp-delay = <5000>;
+          regulator-enable-ramp-delay = <200>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+        mt6359_vcore_buck_reg: buck_vcore {
+          regulator-name = "vcore";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1300000>;
+          regulator-ramp-delay = <5000>;
+          regulator-enable-ramp-delay = <200>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+        mt6359_vs2_buck_reg: buck_vs2 {
+          regulator-name = "vs2";
+          regulator-min-microvolt = <800000>;
+          regulator-max-microvolt = <1600000>;
+          regulator-enable-ramp-delay = <0>;
+          regulator-always-on;
+        };
+        mt6359_vpa_buck_reg: buck_vpa {
+          regulator-name = "vpa";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <3650000>;
+          regulator-enable-ramp-delay = <300>;
+        };
+        mt6359_vproc2_buck_reg: buck_vproc2 {
+          regulator-name = "vproc2";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+          regulator-ramp-delay = <7500>;
+          regulator-enable-ramp-delay = <200>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+        mt6359_vproc1_buck_reg: buck_vproc1 {
+          regulator-name = "vproc1";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+          regulator-ramp-delay = <7500>;
+          regulator-enable-ramp-delay = <200>;
+          regulator-allowed-modes = <0 1 2>;
+        };
+        mt6359_vcore_sshub_buck_reg: buck_vcore_sshub {
+          regulator-name = "vcore_sshub";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+        };
+        mt6359_vgpu11_sshub_buck_reg: buck_vgpu11_sshub {
+          regulator-name = "vgpu11_sshub";
+          regulator-min-microvolt = <400000>;
+          regulator-max-microvolt = <1193750>;
+        };
+        mt6359_vaud18_ldo_reg: ldo_vaud18 {
+          regulator-name = "vaud18";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <1800000>;
+          regulator-enable-ramp-delay = <240>;
+        };
+        mt6359_vsim1_ldo_reg: ldo_vsim1 {
+          regulator-name = "vsim1";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <3100000>;
+        };
+        mt6359_vibr_ldo_reg: ldo_vibr {
+          regulator-name = "vibr";
+          regulator-min-microvolt = <1200000>;
+          regulator-max-microvolt = <3300000>;
+        };
+        mt6359_vrf12_ldo_reg: ldo_vrf12 {
+          regulator-name = "vrf12";
+          regulator-min-microvolt = <1100000>;
+          regulator-max-microvolt = <1300000>;
+        };
+        mt6359_vusb_ldo_reg: ldo_vusb {
+          regulator-name = "vusb";
+          regulator-min-microvolt = <3000000>;
+          regulator-max-microvolt = <3000000>;
+          regulator-enable-ramp-delay = <960>;
+          regulator-always-on;
+        };
+        mt6359_vsram_proc2_ldo_reg: ldo_vsram_proc2 {
+          regulator-name = "vsram_proc2";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <1293750>;
+          regulator-ramp-delay = <7500>;
+          regulator-enable-ramp-delay = <240>;
+          regulator-always-on;
+        };
+        mt6359_vio18_ldo_reg: ldo_vio18 {
+          regulator-name = "vio18";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <1900000>;
+          regulator-enable-ramp-delay = <960>;
+          regulator-always-on;
+        };
+        mt6359_vcamio_ldo_reg: ldo_vcamio {
+          regulator-name = "vcamio";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <1900000>;
+        };
+        mt6359_vcn18_ldo_reg: ldo_vcn18 {
+          regulator-name = "vcn18";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <1800000>;
+          regulator-enable-ramp-delay = <240>;
+        };
+        mt6359_vfe28_ldo_reg: ldo_vfe28 {
+          regulator-name = "vfe28";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <2800000>;
+          regulator-enable-ramp-delay = <120>;
+        };
+        mt6359_vcn13_ldo_reg: ldo_vcn13 {
+          regulator-name = "vcn13";
+          regulator-min-microvolt = <900000>;
+          regulator-max-microvolt = <1300000>;
+        };
+        mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1_bt {
+          regulator-name = "vcn33_1_bt";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <3500000>;
+        };
+        mt6359_vcn33_1_wifi_ldo_reg: ldo_vcn33_1_wifi {
+          regulator-name = "vcn33_1_wifi";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <3500000>;
+        };
+        mt6359_vaux18_ldo_reg: ldo_vaux18 {
+          regulator-name = "vaux18";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <1800000>;
+          regulator-enable-ramp-delay = <240>;
+          regulator-always-on;
+        };
+        mt6359_vsram_others_ldo_reg: ldo_vsram_others {
+          regulator-name = "vsram_others";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <1293750>;
+          regulator-ramp-delay = <5000>;
+          regulator-enable-ramp-delay = <240>;
+        };
+        mt6359_vefuse_ldo_reg: ldo_vefuse {
+          regulator-name = "vefuse";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <2000000>;
+        };
+        mt6359_vxo22_ldo_reg: ldo_vxo22 {
+          regulator-name = "vxo22";
+          regulator-min-microvolt = <1800000>;
+          regulator-max-microvolt = <2200000>;
+          regulator-always-on;
+        };
+        mt6359_vrfck_ldo_reg: ldo_vrfck {
+          regulator-name = "vrfck";
+          regulator-min-microvolt = <1500000>;
+          regulator-max-microvolt = <1700000>;
+        };
+        mt6359_vrfck_1_ldo_reg: ldo_vrfck_1 {
+          regulator-name = "vrfck";
+          regulator-min-microvolt = <1240000>;
+          regulator-max-microvolt = <1600000>;
+        };
+        mt6359_vbif28_ldo_reg: ldo_vbif28 {
+          regulator-name = "vbif28";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <2800000>;
+          regulator-enable-ramp-delay = <240>;
+        };
+        mt6359_vio28_ldo_reg: ldo_vio28 {
+          regulator-name = "vio28";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <3300000>;
+          regulator-always-on;
+        };
+        mt6359_vemc_ldo_reg: ldo_vemc {
+          regulator-name = "vemc";
+          regulator-min-microvolt = <2900000>;
+          regulator-max-microvolt = <3300000>;
+        };
+        mt6359_vemc_1_ldo_reg: ldo_vemc_1 {
+          regulator-name = "vemc";
+          regulator-min-microvolt = <2500000>;
+          regulator-max-microvolt = <3300000>;
+        };
+        mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2_bt {
+          regulator-name = "vcn33_2_bt";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <3500000>;
+        };
+        mt6359_vcn33_2_wifi_ldo_reg: ldo_vcn33_2_wifi {
+          regulator-name = "vcn33_2_wifi";
+          regulator-min-microvolt = <2800000>;
+          regulator-max-microvolt = <3500000>;
+        };
+        mt6359_va12_ldo_reg: ldo_va12 {
+          regulator-name = "va12";
+          regulator-min-microvolt = <1200000>;
+          regulator-max-microvolt = <1300000>;
+          regulator-always-on;
+        };
+        mt6359_va09_ldo_reg: ldo_va09 {
+          regulator-name = "va09";
+          regulator-min-microvolt = <800000>;
+          regulator-max-microvolt = <1200000>;
+        };
+        mt6359_vrf18_ldo_reg: ldo_vrf18 {
+          regulator-name = "vrf18";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <1810000>;
+        };
+        mt6359_vsram_md_ldo_reg: ldo_vsram_md {
+          regulator-name = "vsram_md";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <1293750>;
+          regulator-ramp-delay = <10760>;
+          regulator-enable-ramp-delay = <240>;
+        };
+        mt6359_vufs_ldo_reg: ldo_vufs {
+          regulator-name = "vufs";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <1900000>;
+        };
+        mt6359_vm18_ldo_reg: ldo_vm18 {
+          regulator-name = "vm18";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <1900000>;
+          regulator-always-on;
+        };
+        mt6359_vbbck_ldo_reg: ldo_vbbck {
+          regulator-name = "vbbck";
+          regulator-min-microvolt = <1100000>;
+          regulator-max-microvolt = <1200000>;
+        };
+        mt6359_vsram_proc1_ldo_reg: ldo_vsram_proc1 {
+          regulator-name = "vsram_proc1";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <1293750>;
+          regulator-ramp-delay = <7500>;
+          regulator-enable-ramp-delay = <240>;
+          regulator-always-on;
+        };
+        mt6359_vsim2_ldo_reg: ldo_vsim2 {
+          regulator-name = "vsim2";
+          regulator-min-microvolt = <1700000>;
+          regulator-max-microvolt = <3100000>;
+        };
+        mt6359_vsram_others_sshub_ldo: ldo_vsram_others_sshub {
+          regulator-name = "vsram_others_sshub";
+          regulator-min-microvolt = <500000>;
+          regulator-max-microvolt = <1293750>;
+        };
+      };
+    };
+...
index e561a5b..34de383 100644 (file)
@@ -33,6 +33,9 @@ description: |
 
     The names used for regulator nodes must match those supported by a given
     PMIC. Supported regulator node names are
+      For PM6150, smps1 - smps5, ldo1 - ldo19
+      For PM6150L, smps1 - smps8, ldo1 - ldo11, bob
+      For PM7325, smps1 - smps8, ldo1 - ldo19
       For PM8005, smps1 - smps4
       For PM8009, smps1 - smps2, ldo1 - ldo7
       For PM8150, smps1 - smps10, ldo1 - ldo18
@@ -41,15 +44,15 @@ description: |
       For PM8350C, smps1 - smps10, ldo1 - ldo13, bob
       For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
       For PMI8998, bob
-      For PM6150, smps1 - smps5, ldo1 - ldo19
-      For PM6150L, smps1 - smps8, ldo1 - ldo11, bob
-      For PMX55, smps1 - smps7, ldo1 - ldo16
-      For PM7325, smps1 - smps8, ldo1 - ldo19
       For PMR735A, smps1 - smps3, ldo1 - ldo7
+      For PMX55, smps1 - smps7, ldo1 - ldo16
 
 properties:
   compatible:
     enum:
+      - qcom,pm6150-rpmh-regulators
+      - qcom,pm6150l-rpmh-regulators
+      - qcom,pm7325-rpmh-regulators
       - qcom,pm8005-rpmh-regulators
       - qcom,pm8009-rpmh-regulators
       - qcom,pm8009-1-rpmh-regulators
@@ -59,11 +62,9 @@ properties:
       - qcom,pm8350c-rpmh-regulators
       - qcom,pm8998-rpmh-regulators
       - qcom,pmi8998-rpmh-regulators
-      - qcom,pm6150-rpmh-regulators
-      - qcom,pm6150l-rpmh-regulators
-      - qcom,pmx55-rpmh-regulators
-      - qcom,pm7325-rpmh-regulators
+      - qcom,pmm8155au-rpmh-regulators
       - qcom,pmr735a-rpmh-regulators
+      - qcom,pmx55-rpmh-regulators
 
   qcom,pmic-id:
     description: |
index a35c6cb..83b5357 100644 (file)
@@ -24,6 +24,10 @@ description:
 
   For mp5496, s2
 
+  For pm8226, s1, s2, s3, s4, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10,
+  l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25,
+  l26, l27, l28, lvs1
+
   For pm8841, s1, s2, s3, s4, s5, s6, s7, s8
 
   For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
@@ -68,6 +72,7 @@ properties:
   compatible:
     enum:
       - qcom,rpm-mp5496-regulators
+      - qcom,rpm-pm8226-regulators
       - qcom,rpm-pm8841-regulators
       - qcom,rpm-pm8916-regulators
       - qcom,rpm-pm8941-regulators
index 6d0bc9c..a6ae9ec 100644 (file)
@@ -117,6 +117,88 @@ properties:
     description: Enable over current protection.
     type: boolean
 
+  regulator-oc-protection-microamp:
+    description: Set over current protection limit. This is a limit where
+      hardware performs emergency shutdown. Zero can be passed to disable
+      protection and value '1' indicates that protection should be enabled but
+      limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+    description: Set over current error limit. This is a limit where part of
+      the hardware propably is malfunctional and damage prevention is requested.
+      Zero can be passed to disable error detection and value '1' indicates
+      that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+    description: Set over current warning limit. This is a limit where hardware
+      is assumed still to be functional but approaching limit where it gets
+      damaged. Recovery actions should be initiated. Zero can be passed to
+      disable detection and value '1' indicates that detection should
+      be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+    description: Set over voltage protection limit. This is a limit where
+      hardware performs emergency shutdown. Zero can be passed to disable
+      protection and value '1' indicates that protection should be enabled but
+      limit setting can be omitted. Limit is given as microvolt offset from
+      voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+    description: Set over voltage error limit. This is a limit where part of
+      the hardware propably is malfunctional and damage prevention is requested
+      Zero can be passed to disable error detection and value '1' indicates
+      that detection should be enabled but limit setting can be omitted. Limit
+      is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+    description: Set over voltage warning limit. This is a limit where hardware
+      is assumed still to be functional but approaching limit where it gets
+      damaged. Recovery actions should be initiated. Zero can be passed to
+      disable detection and value '1' indicates that detection should
+      be enabled but limit setting can be omitted. Limit is given as microvolt
+      offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+    description: Set over under voltage protection limit. This is a limit where
+      hardware performs emergency shutdown. Zero can be passed to disable
+      protection and value '1' indicates that protection should be enabled but
+      limit setting can be omitted. Limit is given as microvolt offset from
+      voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+    description: Set under voltage error limit. This is a limit where part of
+      the hardware propably is malfunctional and damage prevention is requested
+      Zero can be passed to disable error detection and value '1' indicates
+      that detection should be enabled but limit setting can be omitted. Limit
+      is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+    description: Set over under voltage warning limit. This is a limit where
+      hardware is assumed still to be functional but approaching limit where
+      it gets damaged. Recovery actions should be initiated. Zero can be passed
+      to disable detection and value '1' indicates that detection should
+      be enabled but limit setting can be omitted. Limit is given as microvolt
+      offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+    description: Set over temperature protection limit. This is a limit where
+      hardware performs emergency shutdown. Zero can be passed to disable
+      protection and value '1' indicates that protection should be enabled but
+      limit setting can be omitted.
+
+  regulator-temp-error-kelvin:
+    description: Set over temperature error limit. This is a limit where part of
+      the hardware propably is malfunctional and damage prevention is requested
+      Zero can be passed to disable error detection and value '1' indicates
+      that detection should be enabled but limit setting can be omitted.
+
+  regulator-temp-warn-kelvin:
+    description: Set over temperature warning limit. This is a limit where
+      hardware is assumed still to be functional but approaching limit where it
+      gets damaged. Recovery actions should be initiated. Zero can be passed to
+      disable detection and value '1' indicates that detection should
+      be enabled but limit setting can be omitted.
+
   regulator-active-discharge:
     description: |
       tristate, enable/disable active discharge of regulators. The values are:
diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt6160-regulator.yaml
new file mode 100644 (file)
index 0000000..0534b0d
--- /dev/null
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/richtek,rt6160-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Richtek RT6160 BuckBoost converter
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  The RT6160 is a high-efficiency buck-boost converter that can provide
+  up to 3A output current from 2025mV to 5200mV. And it support the wide
+  input voltage range from 2200mV to 5500mV.
+
+  Datasheet is available at
+  https://www.richtek.com/assets/product_file/RT6160A/DS6160A-00.pdf
+
+allOf:
+  - $ref: regulator.yaml#
+
+properties:
+  compatible:
+    enum:
+      - richtek,rt6160
+
+  reg:
+    maxItems: 1
+
+  enable-gpios:
+    description: A connection of the 'enable' gpio line.
+    maxItems: 1
+
+  richtek,vsel-active-low:
+    description: |
+      Used to indicate the 'vsel' pin active level. if not specified, use
+      high active level as the default.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      rt6160@75 {
+        compatible = "richtek,rt6160";
+        reg = <0x75>;
+        enable-gpios = <&gpio26 2 0>;
+        regulator-name = "rt6160-buckboost";
+        regulator-min-microvolt = <2025000>;
+        regulator-max-microvolt = <5200000>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt6245-regulator.yaml
new file mode 100644 (file)
index 0000000..796ceac
--- /dev/null
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/richtek,rt6245-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Richtek RT6245 High Current Voltage Regulator
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  The RT6245 is a high-performance, synchronous step-down converter
+  that can deliver up to 14A output current with an input supply
+  voltage range of 4.5V to 17V.
+
+allOf:
+  - $ref: regulator.yaml#
+
+properties:
+  compatible:
+    enum:
+      - richtek,rt6245
+
+  reg:
+    maxItems: 1
+
+  enable-gpios:
+    description: |
+      A connection of the chip 'enable' gpio line. If not provided,
+      it will be treat as a default-on power.
+    maxItems: 1
+
+  richtek,oc-level-select:
+    $ref: "/schemas/types.yaml#/definitions/uint8"
+    enum: [0, 1, 2, 3]
+    description: |
+      Over current level selection. Each respective value means the current
+      limit 8A, 14A, 12A, 10A. If this property is missing then keep in
+      in chip default.
+
+  richtek,ot-level-select:
+    $ref: "/schemas/types.yaml#/definitions/uint8"
+    enum: [0, 1, 2]
+    description: |
+      Over temperature level selection. Each respective value means the degree
+      150'c, 130'c, 170'c. If this property is missing then keep in chip
+      default.
+
+  richtek,pgdly-time-select:
+    $ref: "/schemas/types.yaml#/definitions/uint8"
+    enum: [0, 1, 2, 3]
+    description: |
+      Power good signal delay time selection. Each respective value means the
+      delay time 0us, 10us, 20us, 40us. If this property is missing then keep
+      in chip default.
+
+
+  richtek,switch-freq-select:
+    $ref: "/schemas/types.yaml#/definitions/uint8"
+    enum: [0, 1, 2]
+    description: |
+      Buck switch frequency selection. Each respective value means 400KHz,
+      800KHz, 1200KHz. If this property is missing then keep in chip default.
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      rt6245@34 {
+        compatible = "richtek,rt6245";
+        status = "okay";
+        reg = <0x34>;
+        enable-gpios = <&gpio26 2 0>;
+
+        regulator-name = "rt6245-regulator";
+        regulator-min-microvolt = <437500>;
+        regulator-max-microvolt = <1387500>;
+        regulator-boot-on;
+      };
+    };
index b6515a0..7cb74cc 100644 (file)
@@ -27,6 +27,12 @@ patternProperties:
       Properties for single regulator.
     $ref: "regulator.yaml#"
 
+    properties:
+      rohm,ocw-fet-ron-micro-ohms:
+        description: |
+          External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+          to be set.
+
     required:
       - regulator-name
 
diff --git a/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt b/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt
deleted file mode 100644 (file)
index fb1a672..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Renesas RZ/N1 SPI Controller
-
-This controller is based on the Synopsys DW Synchronous Serial Interface and
-inherits all properties defined in snps,dw-apb-ssi.txt except for the
-compatible property.
-
-Required properties:
-- compatible : The device specific string followed by the generic RZ/N1 string.
-   Therefore it must be one of:
-   "renesas,r9a06g032-spi", "renesas,rzn1-spi"
-   "renesas,r9a06g033-spi", "renesas,rzn1-spi"
index 4825157..ca91201 100644 (file)
@@ -67,6 +67,12 @@ properties:
         const: baikal,bt1-sys-ssi
       - description: Canaan Kendryte K210 SoS SPI Controller
         const: canaan,k210-spi
+      - description: Renesas RZ/N1 SPI Controller
+        items:
+          - enum:
+              - renesas,r9a06g032-spi # RZ/N1D
+              - renesas,r9a06g033-spi # RZ/N1S
+          - const: renesas,rzn1-spi   # RZ/N1
 
   reg:
     minItems: 1
diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.txt b/Documentation/devicetree/bindings/spi/spi-cadence.txt
deleted file mode 100644 (file)
index 05a2ef9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Cadence SPI controller Device Tree Bindings
--------------------------------------------
-
-Required properties:
-- compatible           : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6".
-- reg                  : Physical base address and size of SPI registers map.
-- interrupts           : Property with a value describing the interrupt
-                         number.
-- clock-names          : List of input clock names - "ref_clk", "pclk"
-                         (See clock bindings for details).
-- clocks               : Clock phandles (see clock bindings for details).
-
-Optional properties:
-- num-cs               : Number of chip selects used.
-                         If a decoder is used, this will be the number of
-                         chip selects after the decoder.
-- is-decoded-cs                : Flag to indicate whether decoder is used or not.
-
-Example:
-
-       spi@e0007000 {
-               compatible = "xlnx,zynq-spi-r1p6";
-               clock-names = "ref_clk", "pclk";
-               clocks = <&clkc 26>, <&clkc 35>;
-               interrupt-parent = <&intc>;
-               interrupts = <0 49 4>;
-               num-cs = <4>;
-               is-decoded-cs = <0>;
-               reg = <0xe0007000 0x1000>;
-       } ;
diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.yaml b/Documentation/devicetree/bindings/spi/spi-cadence.yaml
new file mode 100644 (file)
index 0000000..9787be2
--- /dev/null
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-cadence.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence SPI controller Device Tree Bindings
+
+maintainers:
+  - Michal Simek <michal.simek@xilinx.com>
+
+allOf:
+  - $ref: "spi-controller.yaml#"
+
+properties:
+  compatible:
+    enum:
+      - cdns,spi-r1p6
+      - xlnx,zynq-spi-r1p6
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: ref_clk
+      - const: pclk
+
+  clocks:
+    maxItems: 2
+
+  num-cs:
+    description: |
+      Number of chip selects used. If a decoder is used,
+      this will be the number of chip selects after the
+      decoder.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+    maximum: 4
+    default: 4
+
+  is-decoded-cs:
+    description: |
+      Flag to indicate whether decoder is used or not.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [ 0, 1 ]
+    default: 0
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    spi@e0007000 {
+      compatible = "xlnx,zynq-spi-r1p6";
+      clock-names = "ref_clk", "pclk";
+      clocks = <&clkc 26>, <&clkc 35>;
+      interrupt-parent = <&intc>;
+      interrupts = <0 49 4>;
+      num-cs = <4>;
+      is-decoded-cs = <0>;
+      reg = <0xe0007000 0x1000>;
+    };
+...
index 0477396..faef4f6 100644 (file)
@@ -114,8 +114,11 @@ patternProperties:
           Compatible of the SPI device.
 
       reg:
-        minimum: 0
-        maximum: 256
+        minItems: 1
+        maxItems: 256
+        items:
+          minimum: 0
+          maximum: 256
         description:
           Chip select used by the device.
 
index 1e6cf29..7f987e7 100644 (file)
@@ -33,6 +33,7 @@ properties:
               - rockchip,rk3328-spi
               - rockchip,rk3368-spi
               - rockchip,rk3399-spi
+              - rockchip,rv1126-spi
           - const: rockchip,rk3066-spi
 
   reg:
diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.txt b/Documentation/devicetree/bindings/spi/spi-xilinx.txt
deleted file mode 100644 (file)
index 5f4ed3e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-Xilinx SPI controller Device Tree Bindings
--------------------------------------------------
-
-Required properties:
-- compatible           : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a"
-- reg                  : Physical base address and size of SPI registers map.
-- interrupts           : Property with a value describing the interrupt
-                         number.
-
-Optional properties:
-- xlnx,num-ss-bits      : Number of chip selects used.
-- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified
-
-Example:
-       axi_quad_spi@41e00000 {
-                       compatible = "xlnx,xps-spi-2.00.a";
-                       interrupt-parent = <&intc>;
-                       interrupts = <0 31 1>;
-                       reg = <0x41e00000 0x10000>;
-                       xlnx,num-ss-bits = <0x1>;
-                       xlnx,num-transfer-bits = <32>;
-       };
-
diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.yaml b/Documentation/devicetree/bindings/spi/spi-xilinx.yaml
new file mode 100644 (file)
index 0000000..593f769
--- /dev/null
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-xilinx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx SPI controller Device Tree Bindings
+
+maintainers:
+  - Michal Simek <michal.simek@xilinx.com>
+
+allOf:
+  - $ref: "spi-controller.yaml#"
+
+properties:
+  compatible:
+    enum:
+      - xlnx,xps-spi-2.00.a
+      - xlnx,xps-spi-2.00.b
+      - xlnx,axi-quad-spi-1.00.a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  xlnx,num-ss-bits:
+    description: Number of chip selects used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+    maximum: 32
+
+  xlnx,num-transfer-bits:
+    description: Number of bits per transfer. This will be 8 if not specified.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [8, 16, 32]
+    default: 8
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    spi0: spi@41e00000 {
+      compatible = "xlnx,xps-spi-2.00.a";
+      interrupt-parent = <&intc>;
+      interrupts = <0 31 1>;
+      reg = <0x41e00000 0x10000>;
+      xlnx,num-ss-bits = <0x1>;
+      xlnx,num-transfer-bits = <32>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt
deleted file mode 100644 (file)
index 0f6d37f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
--------------------------------------------------------------------
-
-Required properties:
-- compatible           : Should be "xlnx,zynqmp-qspi-1.0".
-- reg                  : Physical base address and size of GQSPI registers map.
-- interrupts           : Property with a value describing the interrupt
-                         number.
-- clock-names          : List of input clock names - "ref_clk", "pclk"
-                         (See clock bindings for details).
-- clocks               : Clock phandles (see clock bindings for details).
-
-Optional properties:
-- num-cs               : Number of chip selects used.
-
-Example:
-       qspi: spi@ff0f0000 {
-               compatible = "xlnx,zynqmp-qspi-1.0";
-               clock-names = "ref_clk", "pclk";
-               clocks = <&misc_clk &misc_clk>;
-               interrupts = <0 15 4>;
-               interrupt-parent = <&gic>;
-               num-cs = <1>;
-               reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>;
-       };
diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
new file mode 100644 (file)
index 0000000..ea72c80
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-zynqmp-qspi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
+
+maintainers:
+  - Michal Simek <michal.simek@xilinx.com>
+
+allOf:
+  - $ref: "spi-controller.yaml#"
+
+properties:
+  compatible:
+    const: xlnx,zynqmp-qspi-1.0
+
+  reg:
+    maxItems: 2
+
+  interrupts:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: ref_clk
+      - const: pclk
+
+  clocks:
+    maxItems: 2
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/xlnx-zynqmp-clk.h>
+    soc {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      qspi: spi@ff0f0000 {
+        compatible = "xlnx,zynqmp-qspi-1.0";
+        clocks = <&zynqmp_clk QSPI_REF>, <&zynqmp_clk LPD_LSBUS>;
+        clock-names = "ref_clk", "pclk";
+        interrupts = <0 15 4>;
+        interrupt-parent = <&gic>;
+        reg = <0x0 0xff0f0000 0x0 0x1000>,
+              <0x0 0xc0000000 0x0 0x8000000>;
+      };
+    };
index 104fa8f..8087780 100644 (file)
@@ -7,8 +7,8 @@ Submitting Devicetree (DT) binding patches
 I. For patch submitters
 =======================
 
-  0) Normal patch submission rules from Documentation/process/submitting-patches.rst
-     applies.
+  0) Normal patch submission rules from
+     Documentation/process/submitting-patches.rst applies.
 
   1) The Documentation/ and include/dt-bindings/ portion of the patch should
      be a separate patch. The preferred subject prefix for binding patches is::
@@ -25,8 +25,8 @@ I. For patch submitters
 
        make dt_binding_check
 
-     See Documentation/devicetree/bindings/writing-schema.rst for more details about
-     schema and tools setup.
+     See Documentation/devicetree/bindings/writing-schema.rst for more details
+     about schema and tools setup.
 
   3) DT binding files should be dual licensed. The preferred license tag is
      (GPL-2.0-only OR BSD-2-Clause).
@@ -84,7 +84,8 @@ II. For kernel maintainers
 III. Notes
 ==========
 
-  0) Please see :doc:`ABI` for details regarding devicetree ABI.
+  0) Please see Documentation/devicetree/bindings/ABI.rst for details
+     regarding devicetree ABI.
 
   1) This document is intended as a general familiarization with the process as
      decided at the 2013 Kernel Summit.  When in doubt, the current word of the
index 8341e9d..37ac0a3 100644 (file)
@@ -73,6 +73,8 @@ properties:
           - dallas,ds4510
             # Digital Thermometer and Thermostat
           - dallas,ds75
+          # Delta Electronics DPS920AB 920W 54V Power Supply
+          - delta,dps920ab
             # 1/4 Brick DC/DC Regulated Power Module
           - delta,q54sj108a2
             # Devantech SRF02 ultrasonic ranger in I2C mode
@@ -103,6 +105,8 @@ properties:
           - fsl,mpl3115
             # MPR121: Proximity Capacitive Touch Sensor Controller
           - fsl,mpr121
+            # Monolithic Power Systems Inc. multi-phase controller mp2888
+          - mps,mp2888
             # Monolithic Power Systems Inc. multi-phase controller mp2975
           - mps,mp2975
             # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
index 67ee369..207fd93 100644 (file)
@@ -237,10 +237,10 @@ We have been trying to improve the situation through the creation of
 a set of "books" that group documentation for specific readers.  These
 include:
 
- - :doc:`../admin-guide/index`
- - :doc:`../core-api/index`
- - :doc:`../driver-api/index`
- - :doc:`../userspace-api/index`
+ - Documentation/admin-guide/index.rst
+ - Documentation/core-api/index.rst
+ - Documentation/driver-api/index.rst
+ - Documentation/userspace-api/index.rst
 
 As well as this book on documentation itself.
 
index 6bee033..cc23435 100644 (file)
@@ -276,4 +276,4 @@ before they become available from the ACPICA release process.
    # git clone https://github.com/acpica/acpica
    # git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    # cd acpica
-   # generate/linux/divergences.sh -s ../linux
+   # generate/linux/divergence.sh -s ../linux
index dda0694..64c8d3f 100644 (file)
@@ -9,13 +9,13 @@ with them.
 
 For examples of already existing generic drivers that will also be good
 examples for any other kernel drivers you want to author, refer to
-:doc:`drivers-on-gpio`
+Documentation/driver-api/gpio/drivers-on-gpio.rst
 
 For any kind of mass produced system you want to support, such as servers,
 laptops, phones, tablets, routers, and any consumer or office or business goods
 using appropriate kernel drivers is paramount. Submit your code for inclusion
 in the upstream Linux kernel when you feel it is mature enough and you will get
-help to refine it, see :doc:`../../process/submitting-patches`.
+help to refine it, see Documentation/process/submitting-patches.rst.
 
 In Linux GPIO lines also have a userspace ABI.
 
index c455db0..35795f6 100644 (file)
@@ -25,16 +25,16 @@ ioctl commands that follow modern conventions: ``_IO``, ``_IOR``,
 with the correct parameters:
 
 _IO/_IOR/_IOW/_IOWR
-   The macro name specifies how the argument will be used.  It may be a
+   The macro name specifies how the argument will be used.  It may be a
    pointer to data to be passed into the kernel (_IOW), out of the kernel
-   (_IOR), or both (_IOWR).  _IO can indicate either commands with no
+   (_IOR), or both (_IOWR).  _IO can indicate either commands with no
    argument or those passing an integer value instead of a pointer.
    It is recommended to only use _IO for commands without arguments,
    and use pointers for passing data.
 
 type
    An 8-bit number, often a character literal, specific to a subsystem
-   or driver, and listed in :doc:`../userspace-api/ioctl/ioctl-number`
+   or driver, and listed in Documentation/userspace-api/ioctl/ioctl-number.rst
 
 nr
   An 8-bit number identifying the specific command, unique for a give
@@ -200,10 +200,10 @@ cause an information leak, which can be used to defeat kernel address
 space layout randomization (KASLR), helping in an attack.
 
 For this reason (and for compat support) it is best to avoid any
-implicit padding in data structures.  Where there is implicit padding
+implicit padding in data structures.  Where there is implicit padding
 in an existing structure, kernel drivers must be careful to fully
 initialize an instance of the structure before copying it to user
-space.  This is usually done by calling memset() before assigning to
+space.  This is usually done by calling memset() before assigning to
 individual members.
 
 Subsystem abstractions
index c9aa8b9..0885a04 100644 (file)
@@ -21,7 +21,7 @@ log, telling which card type is used.  Like this one::
 
 You should verify this is correct.  If it isn't, you have to pass the
 correct board type as insmod argument, ``insmod bttv card=2`` for
-example.  The file :doc:`/admin-guide/media/bttv-cardlist` has a list
+example.  The file Documentation/admin-guide/media/bttv-cardlist.rst has a list
 of valid arguments for card.
 
 If your card isn't listed there, you might check the source code for
index f2042ac..bbf9213 100644 (file)
@@ -210,7 +210,7 @@ pll_multiplier                              0x0306  16
 op_pix_clk_div                         0x0308  16
 op_sys_clk_div                         0x030a  16
 op_pre_pll_clk_div                     0x030c  16
-op_pll_multiplier                      0x031e  16
+op_pll_multiplier                      0x030e  16
 pll_mode                               0x0310  8
 - f                                    0       0
 - e    single                          0
index 6668dea..2a4edc7 100755 (executable)
@@ -72,13 +72,14 @@ $uc_header =~ s/[^A-Z0-9]/_/g;
 
 my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n";
 my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause";
+my $note = "/*\n * Generated by $0;\n * do not modify.\n */\n";
 
 for my $fh ($A, $LC) {
-       print $fh "// $license\n$copyright\n" if defined $fh;
+       print $fh "// $license\n$copyright$note\n" if defined $fh;
 }
 
 for my $fh ($H, $LH) {
-       print $fh "/* $license */\n$copyright\n";
+       print $fh "/* $license */\n$copyright$note\n";
 }
 
 sub bit_def($) {
index 83cbae9..b205e10 100644 (file)
@@ -319,7 +319,7 @@ Conexant bt866 TV encoder
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 - is used in AVS6EYES, and
-- can generate: NTSC/PAL, PAL­M, PAL­N
+- can generate: NTSC/PAL, PAL-M, PAL-N
 
 The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
index 2ad71df..813d7db 100644 (file)
@@ -11,11 +11,13 @@ its supported drivers.
 
 Please see:
 
-- :doc:`/admin-guide/media/index`
-    for usage information about media subsystem and supported drivers;
+Documentation/admin-guide/media/index.rst
 
-- :doc:`/userspace-api/media/index`
-     for the userspace APIs used on media devices.
+  - for usage information about media subsystem and supported drivers;
+
+Documentation/userspace-api/media/index.rst
+
+  - for the userspace APIs used on media devices.
 
 
 .. only:: html
index 6b3bfd2..d448cb5 100644 (file)
@@ -217,7 +217,7 @@ system-wide transition to a sleep state even though its :c:member:`runtime_auto`
 flag is clear.
 
 For more information about the runtime power management framework, refer to
-:file:`Documentation/power/runtime_pm.rst`.
+Documentation/power/runtime_pm.rst.
 
 
 Calling Drivers to Enter and Leave System Sleep States
@@ -655,7 +655,7 @@ been thawed.  Generally speaking, the PM notifiers are suitable for performing
 actions that either require user space to be available, or at least won't
 interfere with user space.
 
-For details refer to :doc:`notifiers`.
+For details refer to Documentation/driver-api/pm/notifiers.rst.
 
 
 Device Low-Power (suspend) States
@@ -726,7 +726,7 @@ it into account in any way.
 
 Devices may be defined as IRQ-safe which indicates to the PM core that their
 runtime PM callbacks may be invoked with disabled interrupts (see
-:file:`Documentation/power/runtime_pm.rst` for more information).  If an
+Documentation/power/runtime_pm.rst for more information).  If an
 IRQ-safe device belongs to a PM domain, the runtime PM of the domain will be
 disallowed, unless the domain itself is defined as IRQ-safe. However, it
 makes sense to define a PM domain as IRQ-safe only if all the devices in it
@@ -805,7 +805,7 @@ The ``DPM_FLAG_MAY_SKIP_RESUME`` Driver Flag
 --------------------------------------------
 
 During system-wide resume from a sleep state it's easiest to put devices into
-the full-power state, as explained in :file:`Documentation/power/runtime_pm.rst`.
+the full-power state, as explained in Documentation/power/runtime_pm.rst.
 [Refer to that document for more information regarding this particular issue as
 well as for information on the device runtime power management framework in
 general.]  However, it often is desirable to leave devices in suspend after
index 98ea994..3016051 100644 (file)
@@ -5,7 +5,8 @@ Client Driver Documentation
 ===========================
 
 This is the documentation for client drivers themselves. Refer to
-:doc:`../client` for documentation on how to write client drivers.
+Documentation/driver-api/surface_aggregator/client.rst for documentation
+on how to write client drivers.
 
 .. toctree::
    :maxdepth: 1
index 7270473..8c7c80c 100644 (file)
@@ -87,10 +87,11 @@ native SSAM devices, i.e. devices that are not defined in ACPI and not
 implemented as platform devices, via |ssam_device| and |ssam_device_driver|
 simplify management of client devices and client drivers.
 
-Refer to :doc:`client` for documentation regarding the client device/driver
-API and interface options for other kernel drivers. It is recommended to
-familiarize oneself with that chapter and the :doc:`ssh` before continuing
-with the architectural overview below.
+Refer to Documentation/driver-api/surface_aggregator/client.rst for
+documentation regarding the client device/driver API and interface options
+for other kernel drivers. It is recommended to familiarize oneself with
+that chapter and the Documentation/driver-api/surface_aggregator/ssh.rst
+before continuing with the architectural overview below.
 
 
 Packet Transport Layer
@@ -190,9 +191,9 @@ with success on the transmitter thread.
 
 Transmission of sequenced packets is limited by the number of concurrently
 pending packets, i.e. a limit on how many packets may be waiting for an ACK
-from the EC in parallel. This limit is currently set to one (see :doc:`ssh`
-for the reasoning behind this). Control packets (i.e. ACK and NAK) can
-always be transmitted.
+from the EC in parallel. This limit is currently set to one (see
+Documentation/driver-api/surface_aggregator/ssh.rst for the reasoning behind
+this). Control packets (i.e. ACK and NAK) can always be transmitted.
 
 Receiver Thread
 ---------------
index 1e9d57e..26415e1 100644 (file)
@@ -73,5 +73,7 @@ being a direct response to a previous request. We may also refer to requests
 without response as commands. In general, events need to be enabled via one
 of multiple dedicated requests before they are sent by the EC.
 
-See :doc:`ssh` for a more technical protocol documentation and
-:doc:`internal` for an overview of the internal driver architecture.
+See Documentation/driver-api/surface_aggregator/ssh.rst for a
+more technical protocol documentation and
+Documentation/driver-api/surface_aggregator/internal.rst for an
+overview of the internal driver architecture.
index 4b638c1..c93fa5e 100644 (file)
@@ -740,21 +740,15 @@ possible.
 5. thermal_emergency_poweroff
 =============================
 
-On an event of critical trip temperature crossing. Thermal framework
-allows the system to shutdown gracefully by calling orderly_poweroff().
-In the event of a failure of orderly_poweroff() to shut down the system
-we are in danger of keeping the system alive at undesirably high
-temperatures. To mitigate this high risk scenario we program a work
-queue to fire after a pre-determined number of seconds to start
-an emergency shutdown of the device using the kernel_power_off()
-function. In case kernel_power_off() fails then finally
-emergency_restart() is called in the worst case.
+On an event of critical trip temperature crossing the thermal framework
+shuts down the system by calling hw_protection_shutdown(). The
+hw_protection_shutdown() first attempts to perform an orderly shutdown
+but accepts a delay after which it proceeds doing a forced power-off
+or as last resort an emergency_restart.
 
 The delay should be carefully profiled so as to give adequate time for
-orderly_poweroff(). In case of failure of an orderly_poweroff() the
-emergency poweroff kicks in after the delay has elapsed and shuts down
-the system.
+orderly poweroff.
 
-If set to 0 emergency poweroff will not be supported. So a carefully
-profiled non-zero positive value is a must for emergency poweroff to be
-triggered.
+If the delay is set to 0 emergency poweroff will not be supported. So a
+carefully profiled non-zero positive value is a must for emergency
+poweroff to be triggered.
index 2b3dbd3..d32c27e 100644 (file)
@@ -10,7 +10,7 @@ API overview
 
 The big picture is that USB drivers can continue to ignore most DMA issues,
 though they still must provide DMA-ready buffers (see
-:doc:`/core-api/dma-api-howto`).  That's how they've worked through
+Documentation/core-api/dma-api-howto.rst).  That's how they've worked through
 the 2.4 (and earlier) kernels, or they can now be DMA-aware.
 
 DMA-aware usb drivers:
@@ -60,7 +60,7 @@ and effects like cache-trashing can impose subtle penalties.
   force a consistent memory access ordering by using memory barriers.  It's
   not using a streaming DMA mapping, so it's good for small transfers on
   systems where the I/O would otherwise thrash an IOMMU mapping.  (See
-  :doc:`/core-api/dma-api-howto` for definitions of "coherent" and
+  Documentation/core-api/dma-api-howto.rst for definitions of "coherent" and
   "streaming" DMA mappings.)
 
   Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
@@ -91,7 +91,7 @@ Working with existing buffers
 Existing buffers aren't usable for DMA without first being mapped into the
 DMA address space of the device.  However, most buffers passed to your
 driver can safely be used with such DMA mapping.  (See the first section
-of :doc:`/core-api/dma-api-howto`, titled "What memory is DMA-able?")
+of Documentation/core-api/dma-api-howto.rst, titled "What memory is DMA-able?")
 
 - When you're using scatterlists, you can map everything at once.  On some
   systems, this kicks in an IOMMU and turns the scatterlists into single
index 31ecfe4..f47d05e 100644 (file)
@@ -78,8 +78,10 @@ configuration of fault-injection capabilities.
 
 - /sys/kernel/debug/fail*/times:
 
-       specifies how many times failures may happen at most.
-       A value of -1 means "no limit".
+       specifies how many times failures may happen at most. A value of -1
+       means "no limit". Note, though, that this file only accepts unsigned
+       values. So, if you want to specify -1, you better use 'printf' instead
+       of 'echo', e.g.: $ printf %#x -1 > times
 
 - /sys/kernel/debug/fail*/space:
 
@@ -167,11 +169,13 @@ configuration of fault-injection capabilities.
        - ERRNO: retval must be -1 to -MAX_ERRNO (-4096).
        - ERR_NULL: retval must be 0 or -1 to -MAX_ERRNO (-4096).
 
-- /sys/kernel/debug/fail_function/<functiuon-name>/retval:
+- /sys/kernel/debug/fail_function/<function-name>/retval:
 
-       specifies the "error" return value to inject to the given
-       function for given function. This will be created when
-       user specifies new injection entry.
+       specifies the "error" return value to inject to the given function.
+       This will be created when the user specifies a new injection entry.
+       Note that this file only accepts unsigned values. So, if you want to
+       use a negative errno, you better use 'printf' instead of 'echo', e.g.:
+       $ printf %#x -12 > retval
 
 Boot option
 ^^^^^^^^^^^
@@ -255,7 +259,7 @@ Application Examples
     echo Y > /sys/kernel/debug/$FAILTYPE/task-filter
     echo 10 > /sys/kernel/debug/$FAILTYPE/probability
     echo 100 > /sys/kernel/debug/$FAILTYPE/interval
-    echo -1 > /sys/kernel/debug/$FAILTYPE/times
+    printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
     echo 0 > /sys/kernel/debug/$FAILTYPE/space
     echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
     echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
@@ -309,7 +313,7 @@ Application Examples
     echo N > /sys/kernel/debug/$FAILTYPE/task-filter
     echo 10 > /sys/kernel/debug/$FAILTYPE/probability
     echo 100 > /sys/kernel/debug/$FAILTYPE/interval
-    echo -1 > /sys/kernel/debug/$FAILTYPE/times
+    printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
     echo 0 > /sys/kernel/debug/$FAILTYPE/space
     echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
     echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
@@ -336,11 +340,11 @@ Application Examples
     FAILTYPE=fail_function
     FAILFUNC=open_ctree
     echo $FAILFUNC > /sys/kernel/debug/$FAILTYPE/inject
-    echo -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval
+    printf %#x -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval
     echo N > /sys/kernel/debug/$FAILTYPE/task-filter
     echo 100 > /sys/kernel/debug/$FAILTYPE/probability
     echo 0 > /sys/kernel/debug/$FAILTYPE/interval
-    echo -1 > /sys/kernel/debug/$FAILTYPE/times
+    printf %#x -1 > /sys/kernel/debug/$FAILTYPE/times
     echo 0 > /sys/kernel/debug/$FAILTYPE/space
     echo 1 > /sys/kernel/debug/$FAILTYPE/verbose
 
diff --git a/Documentation/filesystems/dax.rst b/Documentation/filesystems/dax.rst
new file mode 100644 (file)
index 0000000..9a1b8fd
--- /dev/null
@@ -0,0 +1,291 @@
+=======================
+Direct Access for files
+=======================
+
+Motivation
+----------
+
+The page cache is usually used to buffer reads and writes to files.
+It is also used to provide the pages which are mapped into userspace
+by a call to mmap.
+
+For block devices that are memory-like, the page cache pages would be
+unnecessary copies of the original storage.  The `DAX` code removes the
+extra copy by performing reads and writes directly to the storage device.
+For file mappings, the storage device is mapped directly into userspace.
+
+
+Usage
+-----
+
+If you have a block device which supports `DAX`, you can make a filesystem
+on it as usual.  The `DAX` code currently only supports files with a block
+size equal to your kernel's `PAGE_SIZE`, so you may need to specify a block
+size when creating the filesystem.
+
+Currently 3 filesystems support `DAX`: ext2, ext4 and xfs.  Enabling `DAX` on them
+is different.
+
+Enabling DAX on ext2
+--------------------
+
+When mounting the filesystem, use the ``-o dax`` option on the command line or
+add 'dax' to the options in ``/etc/fstab``.  This works to enable `DAX` on all files
+within the filesystem.  It is equivalent to the ``-o dax=always`` behavior below.
+
+
+Enabling DAX on xfs and ext4
+----------------------------
+
+Summary
+-------
+
+ 1. There exists an in-kernel file access mode flag `S_DAX` that corresponds to
+    the statx flag `STATX_ATTR_DAX`.  See the manpage for statx(2) for details
+    about this access mode.
+
+ 2. There exists a persistent flag `FS_XFLAG_DAX` that can be applied to regular
+    files and directories. This advisory flag can be set or cleared at any
+    time, but doing so does not immediately affect the `S_DAX` state.
+
+ 3. If the persistent `FS_XFLAG_DAX` flag is set on a directory, this flag will
+    be inherited by all regular files and subdirectories that are subsequently
+    created in this directory. Files and subdirectories that exist at the time
+    this flag is set or cleared on the parent directory are not modified by
+    this modification of the parent directory.
+
+ 4. There exist dax mount options which can override `FS_XFLAG_DAX` in the
+    setting of the `S_DAX` flag.  Given underlying storage which supports `DAX` the
+    following hold:
+
+    ``-o dax=inode``  means "follow `FS_XFLAG_DAX`" and is the default.
+
+    ``-o dax=never``  means "never set `S_DAX`, ignore `FS_XFLAG_DAX`."
+
+    ``-o dax=always`` means "always set `S_DAX` ignore `FS_XFLAG_DAX`."
+
+    ``-o dax``      is a legacy option which is an alias for ``dax=always``.
+
+    .. warning::
+
+      The option ``-o dax`` may be removed in the future so ``-o dax=always`` is
+      the preferred method for specifying this behavior.
+
+    .. note::
+
+      Modifications to and the inheritance behavior of `FS_XFLAG_DAX` remain
+      the same even when the filesystem is mounted with a dax option.  However,
+      in-core inode state (`S_DAX`) will be overridden until the filesystem is
+      remounted with dax=inode and the inode is evicted from kernel memory.
+
+ 5. The `S_DAX` policy can be changed via:
+
+    a) Setting the parent directory `FS_XFLAG_DAX` as needed before files are
+       created
+
+    b) Setting the appropriate dax="foo" mount option
+
+    c) Changing the `FS_XFLAG_DAX` flag on existing regular files and
+       directories.  This has runtime constraints and limitations that are
+       described in 6) below.
+
+ 6. When changing the `S_DAX` policy via toggling the persistent `FS_XFLAG_DAX`
+    flag, the change to existing regular files won't take effect until the
+    files are closed by all processes.
+
+
+Details
+-------
+
+There are 2 per-file dax flags.  One is a persistent inode setting (`FS_XFLAG_DAX`)
+and the other is a volatile flag indicating the active state of the feature
+(`S_DAX`).
+
+`FS_XFLAG_DAX` is preserved within the filesystem.  This persistent config
+setting can be set, cleared and/or queried using the `FS_IOC_FS`[`GS`]`ETXATTR` ioctl
+(see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'.
+
+New files and directories automatically inherit `FS_XFLAG_DAX` from
+their parent directory **when created**.  Therefore, setting `FS_XFLAG_DAX` at
+directory creation time can be used to set a default behavior for an entire
+sub-tree.
+
+To clarify inheritance, here are 3 examples:
+
+Example A:
+
+.. code-block:: shell
+
+  mkdir -p a/b/c
+  xfs_io -c 'chattr +x' a
+  mkdir a/b/c/d
+  mkdir a/e
+
+  ------[outcome]------
+
+  dax: a,e
+  no dax: b,c,d
+
+Example B:
+
+.. code-block:: shell
+
+  mkdir a
+  xfs_io -c 'chattr +x' a
+  mkdir -p a/b/c/d
+
+  ------[outcome]------
+
+  dax: a,b,c,d
+  no dax:
+
+Example C:
+
+.. code-block:: shell
+
+  mkdir -p a/b/c
+  xfs_io -c 'chattr +x' c
+  mkdir a/b/c/d
+
+  ------[outcome]------
+
+  dax: c,d
+  no dax: a,b
+
+The current enabled state (`S_DAX`) is set when a file inode is instantiated in
+memory by the kernel.  It is set based on the underlying media support, the
+value of `FS_XFLAG_DAX` and the filesystem's dax mount option.
+
+statx can be used to query `S_DAX`.
+
+.. note::
+
+  That only regular files will ever have `S_DAX` set and therefore statx
+  will never indicate that `S_DAX` is set on directories.
+
+Setting the `FS_XFLAG_DAX` flag (specifically or through inheritance) occurs even
+if the underlying media does not support dax and/or the filesystem is
+overridden with a mount option.
+
+
+Implementation Tips for Block Driver Writers
+--------------------------------------------
+
+To support `DAX` in your block driver, implement the 'direct_access'
+block device operation.  It is used to translate the sector number
+(expressed in units of 512-byte sectors) to a page frame number (pfn)
+that identifies the physical page for the memory.  It also returns a
+kernel virtual address that can be used to access the memory.
+
+The direct_access method takes a 'size' parameter that indicates the
+number of bytes being requested.  The function should return the number
+of bytes that can be contiguously accessed at that offset.  It may also
+return a negative errno if an error occurs.
+
+In order to support this method, the storage must be byte-accessible by
+the CPU at all times.  If your device uses paging techniques to expose
+a large amount of memory through a smaller window, then you cannot
+implement direct_access.  Equally, if your device can occasionally
+stall the CPU for an extended period, you should also not attempt to
+implement direct_access.
+
+These block devices may be used for inspiration:
+- brd: RAM backed block device driver
+- dcssblk: s390 dcss block device driver
+- pmem: NVDIMM persistent memory driver
+
+
+Implementation Tips for Filesystem Writers
+------------------------------------------
+
+Filesystem support consists of:
+
+* Adding support to mark inodes as being `DAX` by setting the `S_DAX` flag in
+  i_flags
+* Implementing ->read_iter and ->write_iter operations which use
+  :c:func:`dax_iomap_rw()` when inode has `S_DAX` flag set
+* Implementing an mmap file operation for `DAX` files which sets the
+  `VM_MIXEDMAP` and `VM_HUGEPAGE` flags on the `VMA`, and setting the vm_ops to
+  include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These
+  handlers should probably call :c:func:`dax_iomap_fault()` passing the
+  appropriate fault size and iomap operations.
+* Calling :c:func:`iomap_zero_range()` passing appropriate iomap operations
+  instead of :c:func:`block_truncate_page()` for `DAX` files
+* Ensuring that there is sufficient locking between reads, writes,
+  truncates and page faults
+
+The iomap handlers for allocating blocks must make sure that allocated blocks
+are zeroed out and converted to written extents before being returned to avoid
+exposure of uninitialized data through mmap.
+
+These filesystems may be used for inspiration:
+
+.. seealso::
+
+  ext2: see Documentation/filesystems/ext2.rst
+
+.. seealso::
+
+  xfs:  see Documentation/admin-guide/xfs.rst
+
+.. seealso::
+
+  ext4: see Documentation/filesystems/ext4/
+
+
+Handling Media Errors
+---------------------
+
+The libnvdimm subsystem stores a record of known media error locations for
+each pmem block device (in gendisk->badblocks). If we fault at such location,
+or one with a latent error not yet discovered, the application can expect
+to receive a `SIGBUS`. Libnvdimm also allows clearing of these errors by simply
+writing the affected sectors (through the pmem driver, and if the underlying
+NVDIMM supports the clear_poison DSM defined by ACPI).
+
+Since `DAX` IO normally doesn't go through the ``driver/bio`` path, applications or
+sysadmins have an option to restore the lost data from a prior ``backup/inbuilt``
+redundancy in the following ways:
+
+1. Delete the affected file, and restore from a backup (sysadmin route):
+   This will free the filesystem blocks that were being used by the file,
+   and the next time they're allocated, they will be zeroed first, which
+   happens through the driver, and will clear bad sectors.
+
+2. Truncate or hole-punch the part of the file that has a bad-block (at least
+   an entire aligned sector has to be hole-punched, but not necessarily an
+   entire filesystem block).
+
+These are the two basic paths that allow `DAX` filesystems to continue operating
+in the presence of media errors. More robust error recovery mechanisms can be
+built on top of this in the future, for example, involving redundancy/mirroring
+provided at the block layer through DM, or additionally, at the filesystem
+level. These would have to rely on the above two tenets, that error clearing
+can happen either by sending an IO through the driver, or zeroing (also through
+the driver).
+
+
+Shortcomings
+------------
+
+Even if the kernel or its modules are stored on a filesystem that supports
+`DAX` on a block device that supports `DAX`, they will still be copied into RAM.
+
+The DAX code does not work correctly on architectures which have virtually
+mapped caches such as ARM, MIPS and SPARC.
+
+Calling :c:func:`get_user_pages()` on a range of user memory that has been
+mmaped from a `DAX` file will fail when there are no 'struct page' to describe
+those pages.  This problem has been addressed in some device drivers
+by adding optional struct page support for pages under the control of
+the driver (see `CONFIG_NVDIMM_PFN` in ``drivers/nvdimm`` for an example of
+how to do this). In the non struct page cases `O_DIRECT` reads/writes to
+those memory ranges from a non-`DAX` file will fail 
+
+
+.. note::
+
+  `O_DIRECT` reads/writes _of a `DAX` file do work, it is the memory that
+  is being accessed that is key here).  Other things that will not work in
+  the non struct page case include RDMA, :c:func:`sendfile()` and
+  :c:func:`splice()`.
diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt
deleted file mode 100644 (file)
index e03c205..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-Direct Access for files
------------------------
-
-Motivation
-----------
-
-The page cache is usually used to buffer reads and writes to files.
-It is also used to provide the pages which are mapped into userspace
-by a call to mmap.
-
-For block devices that are memory-like, the page cache pages would be
-unnecessary copies of the original storage.  The DAX code removes the
-extra copy by performing reads and writes directly to the storage device.
-For file mappings, the storage device is mapped directly into userspace.
-
-
-Usage
------
-
-If you have a block device which supports DAX, you can make a filesystem
-on it as usual.  The DAX code currently only supports files with a block
-size equal to your kernel's PAGE_SIZE, so you may need to specify a block
-size when creating the filesystem.
-
-Currently 3 filesystems support DAX: ext2, ext4 and xfs.  Enabling DAX on them
-is different.
-
-Enabling DAX on ext2
------------------------------
-
-When mounting the filesystem, use the "-o dax" option on the command line or
-add 'dax' to the options in /etc/fstab.  This works to enable DAX on all files
-within the filesystem.  It is equivalent to the '-o dax=always' behavior below.
-
-
-Enabling DAX on xfs and ext4
-----------------------------
-
-Summary
--------
-
- 1. There exists an in-kernel file access mode flag S_DAX that corresponds to
-    the statx flag STATX_ATTR_DAX.  See the manpage for statx(2) for details
-    about this access mode.
-
- 2. There exists a persistent flag FS_XFLAG_DAX that can be applied to regular
-    files and directories. This advisory flag can be set or cleared at any
-    time, but doing so does not immediately affect the S_DAX state.
-
- 3. If the persistent FS_XFLAG_DAX flag is set on a directory, this flag will
-    be inherited by all regular files and subdirectories that are subsequently
-    created in this directory. Files and subdirectories that exist at the time
-    this flag is set or cleared on the parent directory are not modified by
-    this modification of the parent directory.
-
- 4. There exist dax mount options which can override FS_XFLAG_DAX in the
-    setting of the S_DAX flag.  Given underlying storage which supports DAX the
-    following hold:
-
-    "-o dax=inode"  means "follow FS_XFLAG_DAX" and is the default.
-
-    "-o dax=never"  means "never set S_DAX, ignore FS_XFLAG_DAX."
-
-    "-o dax=always" means "always set S_DAX ignore FS_XFLAG_DAX."
-
-    "-o dax"        is a legacy option which is an alias for "dax=always".
-                   This may be removed in the future so "-o dax=always" is
-                   the preferred method for specifying this behavior.
-
-    NOTE: Modifications to and the inheritance behavior of FS_XFLAG_DAX remain
-    the same even when the filesystem is mounted with a dax option.  However,
-    in-core inode state (S_DAX) will be overridden until the filesystem is
-    remounted with dax=inode and the inode is evicted from kernel memory.
-
- 5. The S_DAX policy can be changed via:
-
-    a) Setting the parent directory FS_XFLAG_DAX as needed before files are
-       created
-
-    b) Setting the appropriate dax="foo" mount option
-
-    c) Changing the FS_XFLAG_DAX flag on existing regular files and
-       directories.  This has runtime constraints and limitations that are
-       described in 6) below.
-
- 6. When changing the S_DAX policy via toggling the persistent FS_XFLAG_DAX
-    flag, the change to existing regular files won't take effect until the
-    files are closed by all processes.
-
-
-Details
--------
-
-There are 2 per-file dax flags.  One is a persistent inode setting (FS_XFLAG_DAX)
-and the other is a volatile flag indicating the active state of the feature
-(S_DAX).
-
-FS_XFLAG_DAX is preserved within the filesystem.  This persistent config
-setting can be set, cleared and/or queried using the FS_IOC_FS[GS]ETXATTR ioctl
-(see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'.
-
-New files and directories automatically inherit FS_XFLAG_DAX from
-their parent directory _when_ _created_.  Therefore, setting FS_XFLAG_DAX at
-directory creation time can be used to set a default behavior for an entire
-sub-tree.
-
-To clarify inheritance, here are 3 examples:
-
-Example A:
-
-mkdir -p a/b/c
-xfs_io -c 'chattr +x' a
-mkdir a/b/c/d
-mkdir a/e
-
-       dax: a,e
-       no dax: b,c,d
-
-Example B:
-
-mkdir a
-xfs_io -c 'chattr +x' a
-mkdir -p a/b/c/d
-
-       dax: a,b,c,d
-       no dax:
-
-Example C:
-
-mkdir -p a/b/c
-xfs_io -c 'chattr +x' c
-mkdir a/b/c/d
-
-       dax: c,d
-       no dax: a,b
-
-
-The current enabled state (S_DAX) is set when a file inode is instantiated in
-memory by the kernel.  It is set based on the underlying media support, the
-value of FS_XFLAG_DAX and the filesystem's dax mount option.
-
-statx can be used to query S_DAX.  NOTE that only regular files will ever have
-S_DAX set and therefore statx will never indicate that S_DAX is set on
-directories.
-
-Setting the FS_XFLAG_DAX flag (specifically or through inheritance) occurs even
-if the underlying media does not support dax and/or the filesystem is
-overridden with a mount option.
-
-
-
-Implementation Tips for Block Driver Writers
---------------------------------------------
-
-To support DAX in your block driver, implement the 'direct_access'
-block device operation.  It is used to translate the sector number
-(expressed in units of 512-byte sectors) to a page frame number (pfn)
-that identifies the physical page for the memory.  It also returns a
-kernel virtual address that can be used to access the memory.
-
-The direct_access method takes a 'size' parameter that indicates the
-number of bytes being requested.  The function should return the number
-of bytes that can be contiguously accessed at that offset.  It may also
-return a negative errno if an error occurs.
-
-In order to support this method, the storage must be byte-accessible by
-the CPU at all times.  If your device uses paging techniques to expose
-a large amount of memory through a smaller window, then you cannot
-implement direct_access.  Equally, if your device can occasionally
-stall the CPU for an extended period, you should also not attempt to
-implement direct_access.
-
-These block devices may be used for inspiration:
-- brd: RAM backed block device driver
-- dcssblk: s390 dcss block device driver
-- pmem: NVDIMM persistent memory driver
-
-
-Implementation Tips for Filesystem Writers
-------------------------------------------
-
-Filesystem support consists of
-- adding support to mark inodes as being DAX by setting the S_DAX flag in
-  i_flags
-- implementing ->read_iter and ->write_iter operations which use dax_iomap_rw()
-  when inode has S_DAX flag set
-- implementing an mmap file operation for DAX files which sets the
-  VM_MIXEDMAP and VM_HUGEPAGE flags on the VMA, and setting the vm_ops to
-  include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These
-  handlers should probably call dax_iomap_fault() passing the appropriate
-  fault size and iomap operations.
-- calling iomap_zero_range() passing appropriate iomap operations instead of
-  block_truncate_page() for DAX files
-- ensuring that there is sufficient locking between reads, writes,
-  truncates and page faults
-
-The iomap handlers for allocating blocks must make sure that allocated blocks
-are zeroed out and converted to written extents before being returned to avoid
-exposure of uninitialized data through mmap.
-
-These filesystems may be used for inspiration:
-- ext2: see Documentation/filesystems/ext2.rst
-- ext4: see Documentation/filesystems/ext4/
-- xfs:  see Documentation/admin-guide/xfs.rst
-
-
-Handling Media Errors
----------------------
-
-The libnvdimm subsystem stores a record of known media error locations for
-each pmem block device (in gendisk->badblocks). If we fault at such location,
-or one with a latent error not yet discovered, the application can expect
-to receive a SIGBUS. Libnvdimm also allows clearing of these errors by simply
-writing the affected sectors (through the pmem driver, and if the underlying
-NVDIMM supports the clear_poison DSM defined by ACPI).
-
-Since DAX IO normally doesn't go through the driver/bio path, applications or
-sysadmins have an option to restore the lost data from a prior backup/inbuilt
-redundancy in the following ways:
-
-1. Delete the affected file, and restore from a backup (sysadmin route):
-   This will free the filesystem blocks that were being used by the file,
-   and the next time they're allocated, they will be zeroed first, which
-   happens through the driver, and will clear bad sectors.
-
-2. Truncate or hole-punch the part of the file that has a bad-block (at least
-   an entire aligned sector has to be hole-punched, but not necessarily an
-   entire filesystem block).
-
-These are the two basic paths that allow DAX filesystems to continue operating
-in the presence of media errors. More robust error recovery mechanisms can be
-built on top of this in the future, for example, involving redundancy/mirroring
-provided at the block layer through DM, or additionally, at the filesystem
-level. These would have to rely on the above two tenets, that error clearing
-can happen either by sending an IO through the driver, or zeroing (also through
-the driver).
-
-
-Shortcomings
-------------
-
-Even if the kernel or its modules are stored on a filesystem that supports
-DAX on a block device that supports DAX, they will still be copied into RAM.
-
-The DAX code does not work correctly on architectures which have virtually
-mapped caches such as ARM, MIPS and SPARC.
-
-Calling get_user_pages() on a range of user memory that has been mmaped
-from a DAX file will fail when there are no 'struct page' to describe
-those pages.  This problem has been addressed in some device drivers
-by adding optional struct page support for pages under the control of
-the driver (see CONFIG_NVDIMM_PFN in drivers/nvdimm for an example of
-how to do this). In the non struct page cases O_DIRECT reads/writes to
-those memory ranges from a non-DAX file will fail (note that O_DIRECT
-reads/writes _of a DAX file_ do work, it is the memory that is being
-accessed that is key here).  Other things that will not work in the
-non struct page case include RDMA, sendfile() and splice().
index c2fce22..154101c 100644 (file)
@@ -25,7 +25,7 @@ check=none, nocheck   (*)     Don't do extra checking of bitmaps on mount
                                (check=normal and check=strict options removed)
 
 dax                            Use direct access (no page cache).  See
-                               Documentation/filesystems/dax.txt.
+                               Documentation/filesystems/dax.rst.
 
 debug                          Extra debugging information is sent to the
                                kernel syslog.  Useful for developers.
index 3da1566..d5d652a 100644 (file)
@@ -84,7 +84,7 @@ Without the option META\_BG, for safety concerns, all block group
 descriptors copies are kept in the first block group. Given the default
 128MiB(2^27 bytes) block group size and 64-byte group descriptors, ext4
 can have at most 2^27/64 = 2^21 block groups. This limits the entire
-filesystem size to 2^21  2^27 = 2^48bytes or 256TiB.
+filesystem size to 2^21 * 2^27 = 2^48bytes or 256TiB.
 
 The solution to this problem is to use the metablock group feature
 (META\_BG), which is already in ext3 for all 2.6 releases. With the
index d4853cb..246af51 100644 (file)
@@ -77,6 +77,7 @@ Documentation for filesystem implementations.
    coda
    configfs
    cramfs
+   dax
    debugfs
    dlmfs
    ecryptfs
index c482e16..a6fa761 100644 (file)
@@ -448,15 +448,17 @@ described.  If it finds a ``LAST_NORM`` component it first calls
 filesystem to revalidate the result if it is that sort of filesystem.
 If that doesn't get a good result, it calls "``lookup_slow()``" which
 takes ``i_rwsem``, rechecks the cache, and then asks the filesystem
-to find a definitive answer.  Each of these will call
-``follow_managed()`` (as described below) to handle any mount points.
-
-In the absence of symbolic links, ``walk_component()`` creates a new
-``struct path`` containing a counted reference to the new dentry and a
-reference to the new ``vfsmount`` which is only counted if it is
-different from the previous ``vfsmount``.  It then calls
-``path_to_nameidata()`` to install the new ``struct path`` in the
-``struct nameidata`` and drop the unneeded references.
+to find a definitive answer.
+
+As the last step of walk_component(), step_into() will be called either
+directly from walk_component() or from handle_dots().  It calls
+handle_mounts(), to check and handle mount points, in which a new
+``struct path`` is created containing a counted reference to the new dentry and
+a reference to the new ``vfsmount`` which is only counted if it is
+different from the previous ``vfsmount``. Then if there is
+a symbolic link, step_into() calls pick_link() to deal with it,
+otherwise it installs the new ``struct path`` in the ``struct nameidata``, and
+drops the unneeded references.
 
 This "hand-over-hand" sequencing of getting a reference to the new
 dentry before dropping the reference to the previous dentry may
@@ -470,8 +472,8 @@ Handling the final component
 ``nd->last_type`` to refer to the final component of the path.  It does
 not call ``walk_component()`` that last time.  Handling that final
 component remains for the caller to sort out. Those callers are
-``path_lookupat()``, ``path_parentat()``, ``path_mountpoint()`` and
-``path_openat()`` each of which handles the differing requirements of
+path_lookupat(), path_parentat() and
+path_openat() each of which handles the differing requirements of
 different system calls.
 
 ``path_parentat()`` is clearly the simplest - it just wraps a little bit
@@ -486,20 +488,18 @@ perform their operation.
 object is wanted such as by ``stat()`` or ``chmod()``.  It essentially just
 calls ``walk_component()`` on the final component through a call to
 ``lookup_last()``.  ``path_lookupat()`` returns just the final dentry.
-
-``path_mountpoint()`` handles the special case of unmounting which must
-not try to revalidate the mounted filesystem.  It effectively
-contains, through a call to ``mountpoint_last()``, an alternate
-implementation of ``lookup_slow()`` which skips that step.  This is
-important when unmounting a filesystem that is inaccessible, such as
+It is worth noting that when flag ``LOOKUP_MOUNTPOINT`` is set,
+path_lookupat() will unset LOOKUP_JUMPED in nameidata so that in the
+subsequent path traversal d_weak_revalidate() won't be called.
+This is important when unmounting a filesystem that is inaccessible, such as
 one provided by a dead NFS server.
 
 Finally ``path_openat()`` is used for the ``open()`` system call; it
-contains, in support functions starting with "``do_last()``", all the
+contains, in support functions starting with "open_last_lookups()", all the
 complexity needed to handle the different subtleties of O_CREAT (with
 or without O_EXCL), final "``/``" characters, and trailing symbolic
 links.  We will revisit this in the final part of this series, which
-focuses on those symbolic links.  "``do_last()``" will sometimes, but
+focuses on those symbolic links.  "open_last_lookups()" will sometimes, but
 not always, take ``i_rwsem``, depending on what it finds.
 
 Each of these, or the functions which call them, need to be alert to
@@ -535,8 +535,7 @@ covered in greater detail in autofs.txt in the Linux documentation
 tree, but a few notes specifically related to path lookup are in order
 here.
 
-The Linux VFS has a concept of "managed" dentries which is reflected
-in function names such as "``follow_managed()``".  There are three
+The Linux VFS has a concept of "managed" dentries.  There are three
 potentially interesting things about these dentries corresponding
 to three different flags that might be set in ``dentry->d_flags``:
 
@@ -652,10 +651,10 @@ RCU-walk finds it cannot stop gracefully, it simply gives up and
 restarts from the top with REF-walk.
 
 This pattern of "try RCU-walk, if that fails try REF-walk" can be
-clearly seen in functions like ``filename_lookup()``,
-``filename_parentat()``, ``filename_mountpoint()``,
-``do_filp_open()``, and ``do_file_open_root()``.  These five
-correspond roughly to the four ``path_*()`` functions we met earlier,
+clearly seen in functions like filename_lookup(),
+filename_parentat(),
+do_filp_open(), and do_file_open_root().  These four
+correspond roughly to the three ``path_*()`` functions we met earlier,
 each of which calls ``link_path_walk()``.  The ``path_*()`` functions are
 called using different mode flags until a mode is found which works.
 They are first called with ``LOOKUP_RCU`` set to request "RCU-walk".  If
@@ -993,8 +992,8 @@ is 4096.  There are a number of reasons for this limit; not letting the
 kernel spend too much time on just one path is one of them.  With
 symbolic links you can effectively generate much longer paths so some
 sort of limit is needed for the same reason.  Linux imposes a limit of
-at most 40 symlinks in any one path lookup.  It previously imposed a
-further limit of eight on the maximum depth of recursion, but that was
+at most 40 (MAXSYMLINKS) symlinks in any one path lookup.  It previously imposed
+further limit of eight on the maximum depth of recursion, but that was
 raised to 40 when a separate stack was implemented, so there is now
 just the one limit.
 
@@ -1061,42 +1060,26 @@ filesystem cannot successfully get a reference in RCU-walk mode, it
 must return ``-ECHILD`` and ``unlazy_walk()`` will be called to return to
 REF-walk mode in which the filesystem is allowed to sleep.
 
-The place for all this to happen is the ``i_op->follow_link()`` inode
-method.  In the present mainline code this is never actually called in
-RCU-walk mode as the rewrite is not quite complete.  It is likely that
-in a future release this method will be passed an ``inode`` pointer when
-called in RCU-walk mode so it both (1) knows to be careful, and (2) has the
-validated pointer.  Much like the ``i_op->permission()`` method we
-looked at previously, ``->follow_link()`` would need to be careful that
+The place for all this to happen is the ``i_op->get_link()`` inode
+method. This is called both in RCU-walk and REF-walk. In RCU-walk the
+``dentry*`` argument is NULL, ``->get_link()`` can return -ECHILD to drop out of
+RCU-walk.  Much like the ``i_op->permission()`` method we
+looked at previously, ``->get_link()`` would need to be careful that
 all the data structures it references are safe to be accessed while
-holding no counted reference, only the RCU lock.  Though getting a
-reference with ``->follow_link()`` is not yet done in RCU-walk mode, the
-code is ready to release the reference when that does happen.
-
-This need to drop the reference to a symlink adds significant
-complexity.  It requires a reference to the inode so that the
-``i_op->put_link()`` inode operation can be called.  In REF-walk, that
-reference is kept implicitly through a reference to the dentry, so
-keeping the ``struct path`` of the symlink is easiest.  For RCU-walk,
-the pointer to the inode is kept separately.  To allow switching from
-RCU-walk back to REF-walk in the middle of processing nested symlinks
-we also need the seq number for the dentry so we can confirm that
-switching back was safe.
-
-Finally, when providing a reference to a symlink, the filesystem also
-provides an opaque "cookie" that must be passed to ``->put_link()`` so that it
-knows what to free.  This might be the allocated memory area, or a
-pointer to the ``struct page`` in the page cache, or something else
-completely.  Only the filesystem knows what it is.
+holding no counted reference, only the RCU lock. A callback
+``struct delayed_called`` will be passed to ``->get_link()``:
+file systems can set their own put_link function and argument through
+set_delayed_call(). Later on, when VFS wants to put link, it will call
+do_delayed_call() to invoke that callback function with the argument.
 
 In order for the reference to each symlink to be dropped when the walk completes,
 whether in RCU-walk or REF-walk, the symlink stack needs to contain,
 along with the path remnants:
 
-- the ``struct path`` to provide a reference to the inode in REF-walk
-- the ``struct inode *`` to provide a reference to the inode in RCU-walk
+- the ``struct path`` to provide a reference to the previous path
+- the ``const char *`` to provide a reference to the to previous name
 - the ``seq`` to allow the path to be safely switched from RCU-walk to REF-walk
-- the ``cookie`` that tells ``->put_path()`` what to put.
+- the ``struct delayed_call`` for later invocation.
 
 This means that each entry in the symlink stack needs to hold five
 pointers and an integer instead of just one pointer (the path
@@ -1120,12 +1103,10 @@ doesn't need to notice.  Getting this ``name`` variable on and off the
 stack is very straightforward; pushing and popping the references is
 a little more complex.
 
-When a symlink is found, ``walk_component()`` returns the value ``1``
-(``0`` is returned for any other sort of success, and a negative number
-is, as usual, an error indicator).  This causes ``get_link()`` to be
-called; it then gets the link from the filesystem.  Providing that
-operation is successful, the old path ``name`` is placed on the stack,
-and the new value is used as the ``name`` for a while.  When the end of
+When a symlink is found, walk_component() calls pick_link() via step_into()
+which returns the link from the filesystem.
+Providing that operation is successful, the old path ``name`` is placed on the
+stack, and the new value is used as the ``name`` for a while.  When the end of
 the path is found (i.e. ``*name`` is ``'\0'``) the old ``name`` is restored
 off the stack and path walking continues.
 
@@ -1142,23 +1123,23 @@ stack in ``walk_component()`` immediately when the symlink is found;
 old symlink as it walks that last component.  So it is quite
 convenient for ``walk_component()`` to release the old symlink and pop
 the references just before pushing the reference information for the
-new symlink.  It is guided in this by two flags; ``WALK_GET``, which
-gives it permission to follow a symlink if it finds one, and
-``WALK_PUT``, which tells it to release the current symlink after it has been
-followed.  ``WALK_PUT`` is tested first, leading to a call to
-``put_link()``.  ``WALK_GET`` is tested subsequently (by
-``should_follow_link()``) leading to a call to ``pick_link()`` which sets
-up the stack frame.
+new symlink.  It is guided in this by three flags: ``WALK_NOFOLLOW`` which
+forbids it from following a symlink if it finds one, ``WALK_MORE``
+which indicates that it is yet too early to release the
+current symlink, and ``WALK_TRAILING`` which indicates that it is on the final
+component of the lookup, so we will check userspace flag ``LOOKUP_FOLLOW`` to
+decide whether follow it when it is a symlink and call ``may_follow_link()`` to
+check if we have privilege to follow it.
 
 Symlinks with no final component
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 A pair of special-case symlinks deserve a little further explanation.
 Both result in a new ``struct path`` (with mount and dentry) being set
-up in the ``nameidata``, and result in ``get_link()`` returning ``NULL``.
+up in the ``nameidata``, and result in pick_link() returning ``NULL``.
 
 The more obvious case is a symlink to "``/``".  All symlinks starting
-with "``/``" are detected in ``get_link()`` which resets the ``nameidata``
+with "``/``" are detected in pick_link() which resets the ``nameidata``
 to point to the effective filesystem root.  If the symlink only
 contains "``/``" then there is nothing more to do, no components at all,
 so ``NULL`` is returned to indicate that the symlink can be released and
@@ -1175,12 +1156,11 @@ something that looks like a symlink.  It is really a reference to the
 target file, not just the name of it.  When you ``readlink`` these
 objects you get a name that might refer to the same file - unless it
 has been unlinked or mounted over.  When ``walk_component()`` follows
-one of these, the ``->follow_link()`` method in "procfs" doesn't return
-a string name, but instead calls ``nd_jump_link()`` which updates the
-``nameidata`` in place to point to that target.  ``->follow_link()`` then
-returns ``NULL``.  Again there is no final component and ``get_link()``
-reports this by leaving the ``last_type`` field of ``nameidata`` as
-``LAST_BIND``.
+one of these, the ``->get_link()`` method in "procfs" doesn't return
+a string name, but instead calls nd_jump_link() which updates the
+``nameidata`` in place to point to that target.  ``->get_link()`` then
+returns ``NULL``.  Again there is no final component and pick_link()
+returns ``NULL``.
 
 Following the symlink in the final component
 --------------------------------------------
@@ -1197,42 +1177,38 @@ potentially need to call ``link_path_walk()`` again and again on
 successive symlinks until one is found that doesn't point to another
 symlink.
 
-This case is handled by the relevant caller of ``link_path_walk()``, such as
-``path_lookupat()`` using a loop that calls ``link_path_walk()``, and then
-handles the final component.  If the final component is a symlink
-that needs to be followed, then ``trailing_symlink()`` is called to set
-things up properly and the loop repeats, calling ``link_path_walk()``
-again.  This could loop as many as 40 times if the last component of
-each symlink is another symlink.
-
-The various functions that examine the final component and possibly
-report that it is a symlink are ``lookup_last()``, ``mountpoint_last()``
-and ``do_last()``, each of which use the same convention as
-``walk_component()`` of returning ``1`` if a symlink was found that needs
-to be followed.
-
-Of these, ``do_last()`` is the most interesting as it is used for
-opening a file.  Part of ``do_last()`` runs with ``i_rwsem`` held and this
-part is in a separate function: ``lookup_open()``.
-
-Explaining ``do_last()`` completely is beyond the scope of this article,
-but a few highlights should help those interested in exploring the
-code.
-
-1. Rather than just finding the target file, ``do_last()`` needs to open
+This case is handled by relevant callers of link_path_walk(), such as
+path_lookupat(), path_openat() using a loop that calls link_path_walk(),
+and then handles the final component by calling open_last_lookups() or
+lookup_last(). If it is a symlink that needs to be followed,
+open_last_lookups() or lookup_last() will set things up properly and
+return the path so that the loop repeats, calling
+link_path_walk() again.  This could loop as many as 40 times if the last
+component of each symlink is another symlink.
+
+Of the various functions that examine the final component, 
+open_last_lookups() is the most interesting as it works in tandem
+with do_open() for opening a file.  Part of open_last_lookups() runs
+with ``i_rwsem`` held and this part is in a separate function: lookup_open().
+
+Explaining open_last_lookups() and do_open() completely is beyond the scope
+of this article, but a few highlights should help those interested in exploring
+the code.
+
+1. Rather than just finding the target file, do_open() is used after
+   open_last_lookup() to open
    it.  If the file was found in the dcache, then ``vfs_open()`` is used for
    this.  If not, then ``lookup_open()`` will either call ``atomic_open()`` (if
    the filesystem provides it) to combine the final lookup with the open, or
-   will perform the separate ``lookup_real()`` and ``vfs_create()`` steps
+   will perform the separate ``i_op->lookup()`` and ``i_op->create()`` steps
    directly.  In the later case the actual "open" of this newly found or
-   created file will be performed by ``vfs_open()``, just as if the name
+   created file will be performed by vfs_open(), just as if the name
    were found in the dcache.
 
-2. ``vfs_open()`` can fail with ``-EOPENSTALE`` if the cached information
-   wasn't quite current enough.  Rather than restarting the lookup from
-   the top with ``LOOKUP_REVAL`` set, ``lookup_open()`` is called instead,
-   giving the filesystem a chance to resolve small inconsistencies.
-   If that doesn't work, only then is the lookup restarted from the top.
+2. vfs_open() can fail with ``-EOPENSTALE`` if the cached information
+   wasn't quite current enough.  If it's in RCU-walk ``-ECHILD`` will be returned
+   otherwise ``-ESTALE`` is returned.  When ``-ESTALE`` is returned, the caller may
+   retry with ``LOOKUP_REVAL`` flag set.
 
 3. An open with O_CREAT **does** follow a symlink in the final component,
    unlike other creation system calls (like ``mkdir``).  So the sequence::
@@ -1242,8 +1218,8 @@ code.
 
    will create a file called ``/tmp/bar``.  This is not permitted if
    ``O_EXCL`` is set but otherwise is handled for an O_CREAT open much
-   like for a non-creating open: ``should_follow_link()`` returns ``1``, and
-   so does ``do_last()`` so that ``trailing_symlink()`` gets called and the
+   like for a non-creating open: lookup_last() or open_last_lookup()
+   returns a non ``NULL`` value, and link_path_walk() gets called and the
    open process continues on the symlink that was found.
 
 Updating the access time
index 9b17dc7..b7ad47d 100644 (file)
@@ -79,7 +79,8 @@ the ANOD object which is also the final target node of the reference.
            })
        }
 
-Please also see a graph example in :doc:`graph`.
+Please also see a graph example in
+Documentation/firmware-guide/acpi/dsd/graph.rst.
 
 References
 ==========
index 7072db8..4341299 100644 (file)
@@ -174,4 +174,4 @@ References
     referenced 2016-10-04.
 
 [7] _DSD Device Properties Usage Rules.
-    :doc:`../DSD-properties-rules`
+    Documentation/firmware-guide/acpi/DSD-properties-rules.rst
index 9f0d5c8..18074eb 100644 (file)
@@ -339,8 +339,8 @@ a code like this::
 There are also devm_* versions of these functions which release the
 descriptors once the device is released.
 
-See Documentation/firmware-guide/acpi/gpio-properties.rst for more information about the
-_DSD binding related to GPIOs.
+See Documentation/firmware-guide/acpi/gpio-properties.rst for more information
+about the _DSD binding related to GPIOs.
 
 MFD devices
 ===========
@@ -460,7 +460,8 @@ the _DSD of the device object itself or the _DSD of its ancestor in the
 Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible"
 property returned by it is meaningless.
 
-Refer to :doc:`DSD-properties-rules` for more information.
+Refer to Documentation/firmware-guide/acpi/DSD-properties-rules.rst for more
+information.
 
 PCI hierarchy representation
 ============================
index 471be1e..1c85a2a 100644 (file)
@@ -20,7 +20,8 @@ Usage Notes
 -----------
 
 This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see :doc:`/i2c/instantiating-devices` for details.
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst
+for details.
 
 
 Sysfs entries
diff --git a/Documentation/hwmon/dps920ab.rst b/Documentation/hwmon/dps920ab.rst
new file mode 100644 (file)
index 0000000..c33b4cd
--- /dev/null
@@ -0,0 +1,73 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Kernel driver dps920ab
+========================
+
+Supported chips:
+
+  * Delta DPS920AB
+
+    Prefix: 'dps920ab'
+
+    Addresses scanned: -
+
+Authors:
+    Robert Marko <robert.marko@sartura.hr>
+
+
+Description
+-----------
+
+This driver implements support for Delta DPS920AB 920W 54V DC single output
+power supply with PMBus support.
+
+The driver is a client driver to the core PMBus driver.
+Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
+details.
+
+
+Sysfs entries
+-------------
+
+======================= ======================================================
+curr1_label            "iin"
+curr1_input            Measured input current
+curr1_alarm            Input current high alarm
+
+curr2_label            "iout1"
+curr2_input            Measured output current
+curr2_max              Maximum output current
+curr2_rated_max                Maximum rated output current
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_alarm              Input voltage alarm
+
+in2_label              "vout1"
+in2_input              Measured output voltage
+in2_rated_min          Minimum rated output voltage
+in2_rated_max          Maximum rated output voltage
+in2_alarm              Output voltage alarm
+
+power1_label           "pin"
+power1_input           Measured input power
+power1_alarm           Input power high alarm
+
+power2_label           "pout1"
+power2_input           Measured output power
+power2_rated_max       Maximum rated output power
+
+temp[1-3]_input                Measured temperature
+temp[1-3]_alarm                Temperature alarm
+
+fan1_alarm             Fan 1 warning.
+fan1_fault             Fan 1 fault.
+fan1_input             Fan 1 speed in RPM.
+======================= ======================================================
index 9ed60fa..bc01601 100644 (file)
@@ -53,6 +53,7 @@ Hardware Monitoring Kernel Drivers
    da9055
    dell-smm-hwmon
    dme1737
+   dps920ab
    drivetemp
    ds1621
    ds620
@@ -137,6 +138,7 @@ Hardware Monitoring Kernel Drivers
    mcp3021
    menf21bmc
    mlxreg-fan
+   mp2888
    mp2975
    nct6683
    nct6775
@@ -150,6 +152,7 @@ Hardware Monitoring Kernel Drivers
    pc87360
    pc87427
    pcf8591
+   pim4328
    pm6764tr
    pmbus
    powr1220
@@ -164,6 +167,7 @@ Hardware Monitoring Kernel Drivers
    sht15
    sht21
    sht3x
+   sht4x
    shtc1
    sis5595
    sl28cpld
index ca3436b..1faa85c 100644 (file)
@@ -19,7 +19,7 @@ Authors:
 Description
 -----------
 
-The IR36021 is a dual‐loop digital multi‐phase buck controller designed for
+The IR36021 is a dual-loop digital multi-phase buck controller designed for
 point of load applications.
 
 Usage Notes
index 81257d5..8d0ab4a 100644 (file)
@@ -93,9 +93,9 @@ Supported chips:
 
               https://www.st.com/resource/en/datasheet/stlm75.pdf
 
-  * Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP75B, TMP75C, TMP175, TMP275
+  * Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP75B, TMP75C, TMP175, TMP275, TMP1075
 
-    Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp75b', 'tmp75c', 'tmp275'
+    Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp75b', 'tmp75c', 'tmp275', 'tmp1075'
 
     Addresses scanned: none
 
@@ -119,6 +119,8 @@ Supported chips:
 
               https://www.ti.com/product/tmp275
 
+         https://www.ti.com/product/TMP1075
+
   * NXP LM75B, PCT2075
 
     Prefix: 'lm75b', 'pct2075'
index 46aa1aa..a0bcd86 100644 (file)
@@ -19,7 +19,7 @@ This driver supports hardware monitoring for Linear Technology LTC2992 power mon
 LTC2992 is a rail-to-rail system monitor that measures current,
 voltage, and power of two supplies.
 
-Two ADCs simultaneously measure each supplys current. A third ADC monitors
+Two ADCs simultaneously measure each supply's current. A third ADC monitors
 the input voltages and four auxiliary external voltages.
 
 
index f301385..7b097c3 100644 (file)
@@ -38,6 +38,7 @@ Sysfs entries
 fan[1-12]_input    RO  fan tachometer speed in RPM
 fan[1-12]_fault    RO  fan experienced fault
 fan[1-6]_target    RW  desired fan speed in RPM
-pwm[1-6]_enable    RW  regulator mode, 0=disabled, 1=manual mode, 2=rpm mode
-pwm[1-6]           RW  fan target duty cycle (0-255)
+pwm[1-6]_enable    RW  regulator mode, 0=disabled (duty cycle=0%), 1=manual mode, 2=rpm mode
+pwm[1-6]           RW  read: current pwm duty cycle,
+                       write: target pwm duty cycle (0-255)
 ================== === =======================================================
diff --git a/Documentation/hwmon/mp2888.rst b/Documentation/hwmon/mp2888.rst
new file mode 100644 (file)
index 0000000..5e578fd
--- /dev/null
@@ -0,0 +1,113 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver mp2888
+====================
+
+Supported chips:
+
+  * MPS MP12254
+
+    Prefix: 'mp2888'
+
+Author:
+
+       Vadim Pasternak <vadimp@nvidia.com>
+
+Description
+-----------
+
+This driver implements support for Monolithic Power Systems, Inc. (MPS)
+vendor dual-loop, digital, multi-phase controller MP2888.
+
+This device: supports:
+
+- One power rail.
+- Programmable Multi-Phase up to 10 Phases.
+- PWM-VID Interface
+- One pages 0 for telemetry.
+- Programmable pins for PMBus Address.
+- Built-In EEPROM to Store Custom Configurations.
+
+Device complaint with:
+
+- PMBus rev 1.3 interface.
+
+Device supports direct format for reading output current, output voltage,
+input and output power and temperature.
+Device supports linear format for reading input voltage and input power.
+
+The driver provides the next attributes for the current:
+
+- for current out input and maximum alarm;
+- for phase current: input and label.
+
+The driver exports the following attributes via the 'sysfs' files, where:
+
+- 'n' is number of configured phases (from 1 to 10);
+- index 1 for "iout";
+- indexes 2 ... 1 + n for phases.
+
+**curr[1-{1+n}]_input**
+
+**curr[1-{1+n}]_label**
+
+**curr1_max**
+
+**curr1_max_alarm**
+
+The driver provides the next attributes for the voltage:
+
+- for voltage in: input, low and high critical thresholds, low and high
+  critical alarms;
+- for voltage out: input and high alarm;
+
+The driver exports the following attributes via the 'sysfs' files, where
+
+**in1_crit**
+
+**in1_crit_alarm**
+
+**in1_input**
+
+**in1_label**
+
+**in1_min**
+
+**in1_min_alarm**
+
+**in2_alarm**
+
+**in2_input**
+
+**in2_label**
+
+The driver provides the next attributes for the power:
+
+- for power in alarm and input.
+- for power out: cap, cap alarm an input.
+
+The driver exports the following attributes via the 'sysfs' files, where
+- indexes 1 for "pin";
+- indexes 2 for "pout";
+
+**power1_alarm**
+
+**power1_input**
+
+**power1_label**
+
+**power2_input**
+
+**power2_label**
+
+**power2_max**
+
+**power2_max_alarm**
+
+The driver provides the next attributes for the temperature:
+
+**temp1_input**
+
+**temp1_max**
+
+**temp1_max_alarm**
diff --git a/Documentation/hwmon/pim4328.rst b/Documentation/hwmon/pim4328.rst
new file mode 100644 (file)
index 0000000..70c9e7a
--- /dev/null
@@ -0,0 +1,105 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver pim4328
+=====================
+
+Supported chips:
+
+  * Flex PIM4328
+
+    Prefix: 'pim4328', 'bmr455'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+https://flexpowermodules.com/resources/fpm-techspec-pim4328
+
+  * Flex PIM4820
+
+    Prefixes: 'pim4820'
+
+    Addresses scanned: -
+
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-pim4820
+
+  * Flex PIM4006, PIM4106, PIM4206, PIM4306, PIM4406
+
+    Prefixes: 'pim4006', 'pim4106', 'pim4206', 'pim4306', 'pim4406'
+
+    Addresses scanned: -
+
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-pim4006
+
+Author: Erik Rosen <erik.rosen@metormote.com>
+
+
+Description
+-----------
+
+This driver supports hardware monitoring for Flex PIM4328 and
+compatible digital power interface modules.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details
+on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. All attributes are read-only.
+
+======================= ========================================================
+in1_label              "vin"
+in1_input              Measured input voltage.
+in1_alarm              Input voltage alarm.
+
+in2_label              "vin.0"
+in2_input              Measured input voltage on input A.
+
+                       PIM4328 and PIM4X06
+
+in3_label              "vin.1"
+in3_input              Measured input voltage on input B.
+
+                       PIM4328 and PIM4X06
+
+in4_label              "vcap"
+in4_input              Measured voltage on holdup capacitor.
+
+                       PIM4328
+
+curr1_label            "iin.0"
+curr1_input            Measured input current on input A.
+
+                       PIM4X06
+
+curr2_label            "iin.1"
+curr2_input            Measured input current on input B.
+
+                       PIM4X06
+
+currX_label            "iout1"
+currX_input            Measured output current.
+currX_alarm            Output current alarm.
+
+                       X is 1 for PIM4820, 3 otherwise.
+
+temp1_input            Measured temperature.
+temp1_alarm            High temperature alarm.
+======================= ========================================================
index a1fb8fe..294a8ff 100644 (file)
@@ -20,7 +20,7 @@ Description:
 ------------
 
 This driver supports the STMicroelectronics PM6764TR chip. The PM6764TR is a high
-performance digital controller designed to power Intels VR12.5 processors and memories.
+performance digital controller designed to power Intel's VR12.5 processors and memories.
 
 The device utilizes digital technology to implement all control and power management
 functions to provide maximum flexibility and performance. The NVM is embedded to store
index 73e23ab..e7e0c9e 100644 (file)
@@ -289,12 +289,22 @@ PMBus driver platform data
 ==========================
 
 PMBus platform data is defined in include/linux/pmbus.h. Platform data
-currently only provides a flag field with a single bit used::
+currently provides a flags field with four bits used::
 
-       #define PMBUS_SKIP_STATUS_CHECK (1 << 0)
+       #define PMBUS_SKIP_STATUS_CHECK                 BIT(0)
+
+       #define PMBUS_WRITE_PROTECTED                   BIT(1)
+
+       #define PMBUS_NO_CAPABILITY                     BIT(2)
+
+       #define PMBUS_READ_STATUS_AFTER_FAILED_CHECK    BIT(3)
 
        struct pmbus_platform_data {
                u32 flags;              /* Device specific flags */
+
+               /* regulator support */
+               int num_regulators;
+               struct regulator_init_data *reg_init_data;
        };
 
 
@@ -302,8 +312,9 @@ Flags
 -----
 
 PMBUS_SKIP_STATUS_CHECK
-       During register detection, skip checking the status register for
-       communication or command errors.
+
+During register detection, skip checking the status register for
+communication or command errors.
 
 Some PMBus chips respond with valid data when trying to read an unsupported
 register. For such chips, checking the status register is mandatory when
@@ -315,3 +326,26 @@ status register must be disabled.
 Some i2c controllers do not support single-byte commands (write commands with
 no data, i2c_smbus_write_byte()). With such controllers, clearing the status
 register is impossible, and the PMBUS_SKIP_STATUS_CHECK flag must be set.
+
+PMBUS_WRITE_PROTECTED
+
+Set if the chip is write protected and write protection is not determined
+by the standard WRITE_PROTECT command.
+
+PMBUS_NO_CAPABILITY
+
+Some PMBus chips don't respond with valid data when reading the CAPABILITY
+register. For such chips, this flag should be set so that the PMBus core
+driver doesn't use CAPABILITY to determine it's behavior.
+
+PMBUS_READ_STATUS_AFTER_FAILED_CHECK
+
+Read the STATUS register after each failed register check.
+
+Some PMBus chips end up in an undefined state when trying to read an
+unsupported register. For such chips, it is necessary to reset the
+chip pmbus controller to a known state after a failed register check.
+This can be done by reading a known register. By setting this flag the
+driver will try to read the STATUS register after each failed
+register check. This read may fail, but it will put the chip into a
+known state.
index c44f141..7ecfec6 100644 (file)
@@ -3,15 +3,18 @@ Kernel driver pmbus
 
 Supported chips:
 
-  * Ericsson BMR453, BMR454
+  * Flex BMR310, BMR453, BMR454, BMR456, BMR457, BMR458, BMR480,
+    BMR490, BMR491, BMR492
 
-    Prefixes: 'bmr453', 'bmr454'
+    Prefixes: 'bmr310', 'bmr453', 'bmr454', 'bmr456', 'bmr457', 'bmr458', 'bmr480',
+    'bmr490', 'bmr491', 'bmr492'
 
     Addresses scanned: -
 
-    Datasheet:
+    Datasheets:
+
+       https://flexpowermodules.com/products
 
- http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395
 
   * ON Semiconductor ADP4000, NCP4200, NCP4208
 
diff --git a/Documentation/hwmon/sht4x.rst b/Documentation/hwmon/sht4x.rst
new file mode 100644 (file)
index 0000000..3b37abc
--- /dev/null
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver sht4x
+===================
+
+Supported Chips:
+
+  * Sensirion SHT4X
+
+    Prefix: 'sht4x'
+
+    Addresses scanned: None
+
+    Datasheet:
+
+      English: https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT4x_Datasheet.pdf
+
+Author: Navin Sankar Velliangiri <navin@linumiz.com>
+
+
+Description
+-----------
+
+This driver implements support for the Sensirion SHT4x chip, a humidity
+and temperature sensor. Temperature is measured in degree celsius, relative
+humidity is expressed as a percentage. In sysfs interface, all values are
+scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500.
+
+Usage Notes
+-----------
+
+The device communicates with the I2C protocol. Sensors can have the I2C
+address 0x44. See Documentation/i2c/instantiating-devices.rst for methods
+to instantiate the device.
+
+Sysfs entries
+-------------
+
+=============== ============================================
+temp1_input     Measured temperature in millidegrees Celcius
+humidity1_input Measured humidity in %H
+update_interval The minimum interval for polling the sensor,
+                in milliseconds. Writable. Must be at least
+                2000.
+============== =============================================
index 968aff1..d42ed9d 100644 (file)
@@ -3,87 +3,103 @@ Kernel driver zl6100
 
 Supported chips:
 
-  * Intersil / Zilker Labs ZL2004
+  * Renesas / Intersil / Zilker Labs ZL2004
 
     Prefix: 'zl2004'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6847.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2004-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL2005
+  * Renesas / Intersil / Zilker Labs ZL2005
 
     Prefix: 'zl2005'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6848.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2005-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL2006
+  * Renesas / Intersil / Zilker Labs ZL2006
 
     Prefix: 'zl2006'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6850.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2006-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL2008
+  * Renesas / Intersil / Zilker Labs ZL2008
 
     Prefix: 'zl2008'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6859.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2008-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL2105
+  * Renesas / Intersil / Zilker Labs ZL2105
 
     Prefix: 'zl2105'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6851.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2105-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL2106
+  * Renesas / Intersil / Zilker Labs ZL2106
 
     Prefix: 'zl2106'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6852.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl2106-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL6100
+  * Renesas / Intersil / Zilker Labs ZL6100
 
     Prefix: 'zl6100'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6876.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl6100-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL6105
+  * Renesas / Intersil / Zilker Labs ZL6105
 
     Prefix: 'zl6105'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn6906.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl6105-datasheet.pdf
 
-  * Intersil / Zilker Labs ZL9101M
+  * Renesas / Intersil / Zilker Labs ZL8802
+
+    Prefix: 'zl8802'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl8802-datasheet
+
+  * Renesas / Intersil / Zilker Labs ZL9101M
 
     Prefix: 'zl9101'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn7669.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl9101m-datasheet
 
-  * Intersil / Zilker Labs ZL9117M
+  * Renesas / Intersil / Zilker Labs ZL9117M
 
     Prefix: 'zl9117'
 
     Addresses scanned: -
 
-    Datasheet: http://www.intersil.com/data/fn/fn7914.pdf
+    Datasheet: https://www.renesas.com/us/en/document/dst/zl9117m-datasheet
+
+  * Renesas / Intersil / Zilker Labs ZLS1003, ZLS4009
+
+    Prefix: 'zls1003', zls4009
+
+    Addresses scanned: -
+
+    Datasheet: Not published
 
-  * Ericsson BMR450, BMR451
+  * Flex BMR450, BMR451
 
     Prefix: 'bmr450', 'bmr451'
 
@@ -91,17 +107,39 @@ Supported chips:
 
     Datasheet:
 
-http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146401
+https://flexpowermodules.com/resources/fpm-techspec-bmr450-digital-pol-regulators-20a
 
-  * Ericsson BMR462, BMR463, BMR464
+  * Flex BMR462, BMR463, BMR464
 
     Prefixes: 'bmr462', 'bmr463', 'bmr464'
 
     Addresses scanned: -
 
-    Datasheet:
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr462
+
+  * Flex BMR465, BMR467
+
+    Prefixes: 'bmr465', 'bmr467'
+
+    Addresses scanned: -
+
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr465-digital-pol
+
+  * Flex BMR466
+
+    Prefixes: 'bmr466'
+
+    Addresses scanned: -
+
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr466-8x12
 
-       http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146256
+  * Flex BMR469
+
+    Prefixes: 'bmr469'
+
+    Addresses scanned: -
+
+    Datasheet: https://flexpowermodules.com/resources/fpm-techspec-bmr4696001
 
 Author: Guenter Roeck <linux@roeck-us.net>
 
@@ -109,8 +147,8 @@ Author: Guenter Roeck <linux@roeck-us.net>
 Description
 -----------
 
-This driver supports hardware monitoring for Intersil / Zilker Labs ZL6100 and
-compatible digital DC-DC controllers.
+This driver supports hardware monitoring for Renesas / Intersil / Zilker Labs
+ZL6100 and compatible digital DC-DC controllers.
 
 The driver is a client driver to the core PMBus driver. Please see
 Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details
@@ -147,12 +185,12 @@ Module parameters
 delay
 -----
 
-Intersil/Zilker Labs DC-DC controllers require a minimum interval between I2C
-bus accesses. According to Intersil, the minimum interval is 2 ms, though 1 ms
-appears to be sufficient and has not caused any problems in testing. The problem
-is known to affect all currently supported chips. For manual override, the
-driver provides a writeable module parameter, 'delay', which can be used to set
-the interval to a value between 0 and 65,535 microseconds.
+Renesas/Intersil/Zilker Labs DC-DC controllers require a minimum interval
+between I2C bus accesses. According to Intersil, the minimum interval is 2 ms,
+though 1 ms appears to be sufficient and has not caused any problems in testing.
+The problem is known to affect all currently supported chips. For manual override,
+the driver provides a writeable module parameter, 'delay', which can be used
+to set the interval to a value between 0 and 65,535 microseconds.
 
 
 Sysfs entries
@@ -182,24 +220,32 @@ in2_crit          Critical maximum VMON/VDRV voltage.
 in2_lcrit_alarm                VMON/VDRV voltage critical low alarm.
 in2_crit_alarm         VMON/VDRV voltage critical high alarm.
 
-                       vmon attributes are supported on ZL2004, ZL9101M,
-                       and ZL9117M only.
+                       vmon attributes are supported on ZL2004, ZL8802,
+                       ZL9101M, ZL9117M and ZLS4009 only.
 
-inX_label              "vout1"
+inX_label              "vout[12]"
 inX_input              Measured output voltage.
 inX_lcrit              Critical minimum output Voltage.
 inX_crit               Critical maximum output voltage.
 inX_lcrit_alarm                Critical output voltage critical low alarm.
 inX_crit_alarm         Critical output voltage critical high alarm.
 
-                       X is 3 for ZL2004, ZL9101M, and ZL9117M, 2 otherwise.
+                       X is 3 for ZL2004, ZL9101M, and ZL9117M,
+                       3, 4 for ZL8802 and 2 otherwise.
+
+curr1_label            "iin"
+curr1_input            Measured input current.
+
+                       iin attributes are supported on ZL8802 only
+
+currY_label            "iout[12]"
+currY_input            Measured output current.
+currY_lcrit            Critical minimum output current.
+currY_crit             Critical maximum output current.
+currY_lcrit_alarm      Output current critical low alarm.
+currY_crit_alarm       Output current critical high alarm.
 
-curr1_label            "iout1"
-curr1_input            Measured output current.
-curr1_lcrit            Critical minimum output current.
-curr1_crit             Critical maximum output current.
-curr1_lcrit_alarm      Output current critical low alarm.
-curr1_crit_alarm       Output current critical high alarm.
+                       Y is 2, 3 for ZL8802, 1 otherwise
 
 temp[12]_input         Measured temperature.
 temp[12]_min           Minimum temperature.
index e558e0a..890c936 100644 (file)
@@ -59,7 +59,7 @@ Declare the I2C devices via ACPI
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 ACPI can also describe I2C devices. There is special documentation for this
-which is currently located at :doc:`../firmware-guide/acpi/enumeration`.
+which is currently located at Documentation/firmware-guide/acpi/enumeration.rst.
 
 
 Declare the I2C devices in board files
index 38e5582..b08b6da 100644 (file)
@@ -17,7 +17,8 @@ address), ``force`` (to forcibly attach the driver to a given device) and
 With the conversion of the I2C subsystem to the standard device driver
 binding model, it became clear that these per-module parameters were no
 longer needed, and that a centralized implementation was possible. The new,
-sysfs-based interface is described in :doc:`instantiating-devices`, section
+sysfs-based interface is described in
+Documentation/i2c/instantiating-devices.rst, section
 "Method 4: Instantiate from user-space".
 
 Below is a mapping from the old module parameters to the new interface.
index 64689d1..9e07e6b 100644 (file)
@@ -27,8 +27,8 @@ a different protocol operation entirely.
 Each transaction type corresponds to a functionality flag. Before calling a
 transaction function, a device driver should always check (just once) for
 the corresponding functionality flag to ensure that the underlying I2C
-adapter supports the transaction in question. See :doc:`functionality` for
-the details.
+adapter supports the transaction in question. See
+Documentation/i2c/functionality.rst for the details.
 
 
 Key to symbols
index af5934c..5db6dc6 100644 (file)
@@ -263,7 +263,7 @@ possible overrun should the name be too long::
 
        char name[128];
        if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
-               strncpy(name, "Unknown", sizeof(name));
+               strscpy(name, "Unknown", sizeof(name));
        printf("Name: %s\n", name);
 
 
index 4515234..df65c19 100644 (file)
@@ -601,7 +601,7 @@ Defined in ``include/linux/export.h``
 
 This is the variant of `EXPORT_SYMBOL()` that allows specifying a symbol
 namespace. Symbol Namespaces are documented in
-:doc:`../core-api/symbol-namespaces`
+Documentation/core-api/symbol-namespaces.rst
 
 :c:func:`EXPORT_SYMBOL_NS_GPL()`
 --------------------------------
@@ -610,7 +610,7 @@ Defined in ``include/linux/export.h``
 
 This is the variant of `EXPORT_SYMBOL_GPL()` that allows specifying a symbol
 namespace. Symbol Namespaces are documented in
-:doc:`../core-api/symbol-namespaces`
+Documentation/core-api/symbol-namespaces.rst
 
 Routines and Conventions
 ========================
index 9f3cfca..82f36ca 100644 (file)
@@ -453,9 +453,9 @@ There are simply four block conditions:
 Block condition matrix, Y means the row blocks the column, and N means otherwise.
 
        +---+---+---+---+
-       |   | E | r | R |
+       |   | W | r | R |
        +---+---+---+---+
-       | E | Y | Y | Y |
+       | W | Y | Y | Y |
        +---+---+---+---+
        | r | Y | Y | N |
        +---+---+---+---+
index 2d3f6bd..ac35bd4 100644 (file)
@@ -466,7 +466,7 @@ network. PTP support varies among Intel devices that support this driver. Use
 "ethtool -T <netdev name>" to get a definitive list of PTP capabilities
 supported by the device.
 
-IEEE 802.1ad (QinQ) Support
+IEEE 802.1ad (QinQ) Support
 ---------------------------
 The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN
 IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as
@@ -523,8 +523,8 @@ of a port's bandwidth (should it be available). The sum of all the values for
 Maximum Bandwidth is not restricted, because no more than 100% of a port's
 bandwidth can ever be used.
 
-NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions
-per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says
+NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions
+per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says
 "add vsi failed for VF N, aq_err 16". To workaround the issue, enable less than
 64 virtual functions (VFs).
 
index 25330b7..151af0a 100644 (file)
@@ -113,7 +113,7 @@ which the AVF is associated. The following are base mode features:
 - AVF device ID
 - HW mailbox is used for VF to PF communications (including on Windows)
 
-IEEE 802.1ad (QinQ) Support
+IEEE 802.1ad (QinQ) Support
 ---------------------------
 The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN
 IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as
index 3654c3e..58fe95e 100644 (file)
@@ -22,7 +22,7 @@ The major benefit to creating a region is to provide access to internal
 address regions that are otherwise inaccessible to the user.
 
 Regions may also be used to provide an additional way to debug complex error
-states, but see also :doc:`devlink-health`
+states, but see also Documentation/networking/devlink/devlink-health.rst
 
 Regions may optionally support capturing a snapshot on demand via the
 ``DEVLINK_CMD_REGION_NEW`` netlink message. A driver wishing to allow
index 935b639..efa5f7f 100644 (file)
@@ -495,8 +495,8 @@ help debug packet drops caused by these exceptions. The following list includes
 links to the description of driver-specific traps registered by various device
 drivers:
 
-  * :doc:`netdevsim`
-  * :doc:`mlxsw`
+  * Documentation/networking/devlink/netdevsim.rst
+  * Documentation/networking/devlink/mlxsw.rst
 
 .. _Generic-Packet-Trap-Groups:
 
index 500ef60..c5da1a5 100644 (file)
@@ -153,7 +153,7 @@ As capture, each frame contains two parts::
     struct ifreq s_ifr;
     ...
 
-    strncpy (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name));
+    strscpy_pad (s_ifr.ifr_name, "eth0", sizeof(s_ifr.ifr_name));
 
     /* get interface index of eth0 */
     ioctl(this->socket, SIOCGIFINDEX, &s_ifr);
index a59d1dd..4d7087f 100644 (file)
@@ -107,7 +107,7 @@ Note that the character pointer becomes overwritten with the real device name
        */
       ifr.ifr_flags = IFF_TUN;
       if( *dev )
-        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+        strscpy_pad(ifr.ifr_name, dev, IFNAMSIZ);
 
       if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
         close(fd);
index 18ae21b..d6bf84f 100644 (file)
@@ -378,7 +378,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
 
   `int pm_runtime_get_sync(struct device *dev);`
     - increment the device's usage counter, run pm_runtime_resume(dev) and
-      return its result
+      return its result;
+      note that it does not drop the device's usage counter on errors, so
+      consider using pm_runtime_resume_and_get() instead of it, especially
+      if its return value is checked by the caller, as this is likely to
+      result in cleaner code.
 
   `int pm_runtime_get_if_in_use(struct device *dev);`
     - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
@@ -827,6 +831,15 @@ or driver about runtime power changes.  Instead, the driver for the device's
 parent must take responsibility for telling the device's driver when the
 parent's power state changes.
 
+Note that, in some cases it may not be desirable for subsystems/drivers to call
+pm_runtime_no_callbacks() for their devices. This could be because a subset of
+the runtime PM callbacks needs to be implemented, a platform dependent PM
+domain could get attached to the device or that the device is power managed
+through a supplier device link. For these reasons and to avoid boilerplate code
+in subsystems/drivers, the PM core allows runtime PM callbacks to be
+unassigned. More precisely, if a callback pointer is NULL, the PM core will act
+as though there was a callback and it returned 0.
+
 9. Autosuspend, or automatically-delayed suspends
 =================================================
 
index c66a192..0852bcf 100644 (file)
@@ -10,10 +10,11 @@ can greatly increase the chances of your change being accepted.
 
 This document contains a large number of suggestions in a relatively terse
 format.  For detailed information on how the kernel development process
-works, see :doc:`development-process`. Also, read :doc:`submit-checklist`
+works, see Documentation/process/development-process.rst. Also, read
+Documentation/process/submit-checklist.rst
 for a list of items to check before submitting code.  If you are submitting
-a driver, also read :doc:`submitting-drivers`; for device tree binding patches,
-read :doc:`submitting-patches`.
+a driver, also read Documentation/process/submitting-drivers.rst; for device
+tree binding patches, read Documentation/process/submitting-patches.rst.
 
 This documentation assumes that you're using ``git`` to prepare your patches.
 If you're unfamiliar with ``git``, you would be well-advised to learn how to
@@ -178,8 +179,7 @@ Style-check your changes
 ------------------------
 
 Check your patch for basic style violations, details of which can be
-found in
-:ref:`Documentation/process/coding-style.rst <codingstyle>`.
+found in Documentation/process/coding-style.rst.
 Failure to do so simply wastes
 the reviewers time and will get your patch rejected, probably
 without even being read.
@@ -238,7 +238,7 @@ If you have a patch that fixes an exploitable security bug, send that patch
 to security@kernel.org.  For severe bugs, a short embargo may be considered
 to allow distributors to get the patch out to users; in such cases,
 obviously, the patch should not be sent to any public lists. See also
-:doc:`/admin-guide/security-bugs`.
+Documentation/admin-guide/security-bugs.rst.
 
 Patches that fix a severe bug in a released kernel should be directed
 toward the stable maintainers by putting a line like this::
@@ -246,9 +246,8 @@ toward the stable maintainers by putting a line like this::
   Cc: stable@vger.kernel.org
 
 into the sign-off area of your patch (note, NOT an email recipient).  You
-should also read
-:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
-in addition to this file.
+should also read Documentation/process/stable-kernel-rules.rst
+in addition to this document.
 
 If changes affect userland-kernel interfaces, please send the MAN-PAGES
 maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at
@@ -305,8 +304,8 @@ decreasing the likelihood of your MIME-attached change being accepted.
 Exception:  If your mailer is mangling patches then someone may ask
 you to re-send them using MIME.
 
-See :doc:`/process/email-clients` for hints about configuring your e-mail
-client so that it sends your patches untouched.
+See Documentation/process/email-clients.rst for hints about configuring
+your e-mail client so that it sends your patches untouched.
 
 Respond to review comments
 --------------------------
@@ -324,7 +323,7 @@ for their time.  Code review is a tiring and time-consuming process, and
 reviewers sometimes get grumpy.  Even in that case, though, respond
 politely and address the problems they have pointed out.
 
-See :doc:`email-clients` for recommendations on email
+See Documentation/process/email-clients.rst for recommendations on email
 clients and mailing list etiquette.
 
 
@@ -562,10 +561,10 @@ method for indicating a bug fixed by the patch. See :ref:`describe_changes`
 for more details.
 
 Note: Attaching a Fixes: tag does not subvert the stable kernel rules
-process nor the requirement to Cc: stable@vger.kernel.org on all stable 
+process nor the requirement to Cc: stable@vger.kernel.org on all stable
 patch candidates. For more information, please read
-:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
-     
+Documentation/process/stable-kernel-rules.rst.
+
 .. _the_canonical_patch_format:
 
 The canonical patch format
@@ -824,8 +823,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
   <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
 
-Kernel Documentation/process/coding-style.rst:
-  :ref:`Documentation/process/coding-style.rst <codingstyle>`
+Kernel Documentation/process/coding-style.rst
 
 Linus Torvalds's mail on the canonical patch format:
   <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
index 329d320..b7f9893 100644 (file)
@@ -58,6 +58,6 @@ RISC-V Linux Kernel SV39
                                                               |
   ____________________________________________________________|____________________________________________________________
                     |            |                  |         |
-   ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | modules
-   ffffffff80000000 |   -2    GB | ffffffffffffffff |    2 GB | kernel, BPF
+   ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | modules, BPF
+   ffffffff80000000 |   -2    GB | ffffffffffffffff |    2 GB | kernel
   __________________|____________|__________________|_________|____________________________________________________________
index 845eee6..1fc7355 100644 (file)
@@ -29,7 +29,7 @@ Quota and period are managed within the cpu subsystem via cgroupfs.
 .. note::
    The cgroupfs files described in this section are only applicable
    to cgroup v1. For cgroup v2, see
-   :ref:`Documentation/admin-guide/cgroupv2.rst <cgroup-v2-cpu>`.
+   :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`.
 
 - cpu.cfs_quota_us: the total available run-time within a period (in
   microseconds)
index 9b7cbe4..805f85f 100644 (file)
@@ -284,8 +284,10 @@ whether the system exhibits asymmetric CPU capacities. Should that be the
 case:
 
 - The sched_asym_cpucapacity static key will be enabled.
-- The SD_ASYM_CPUCAPACITY flag will be set at the lowest sched_domain level that
-  spans all unique CPU capacity values.
+- The SD_ASYM_CPUCAPACITY_FULL flag will be set at the lowest sched_domain
+  level that spans all unique CPU capacity values.
+- The SD_ASYM_CPUCAPACITY flag will be set for any sched_domain that spans
+  CPUs with any range of asymmetry.
 
 The sched_asym_cpucapacity static key is intended to guard sections of code that
 cater to asymmetric CPU capacity systems. Do note however that said key is
index afe02d3..8fbce5e 100644 (file)
@@ -328,7 +328,7 @@ section lists these dependencies and provides hints as to how they can be met.
 
 As mentioned in the introduction, EAS is only supported on platforms with
 asymmetric CPU topologies for now. This requirement is checked at run-time by
-looking for the presence of the SD_ASYM_CPUCAPACITY flag when the scheduling
+looking for the presence of the SD_ASYM_CPUCAPACITY_FULL flag when the scheduling
 domains are built.
 
 See Documentation/scheduler/sched-capacity.rst for requirements to be met for this
index 0571f1b..889bf2b 100644 (file)
@@ -60,7 +60,7 @@ within the constraints of HZ and jiffies and their nasty design level
 coupling to timeslices and granularity it was not really viable.
 
 The second (less frequent but still periodically occurring) complaint
-about Linux's nice level support was its assymetry around the origo
+about Linux's nice level support was its asymmetry around the origin
 (which you can see demonstrated in the picture above), or more
 accurately: the fact that nice level behavior depended on the _absolute_
 nice level as well, while the nice API itself is fundamentally
index c5a8432..1a91d92 100644 (file)
@@ -70,9 +70,18 @@ descriptors by adding their identifier to the format string
    prefix is shown only if the hash algorithm is not SHA1 or MD5);
  - 'd-modsig': the digest of the event without the appended modsig;
  - 'n-ng': the name of the event, without size limitations;
- - 'sig': the file signature;
+ - 'sig': the file signature, or the EVM portable signature if the file
+   signature is not found;
  - 'modsig' the appended file signature;
  - 'buf': the buffer data that was used to generate the hash without size limitations;
+ - 'evmsig': the EVM portable signature;
+ - 'iuid': the inode UID;
+ - 'igid': the inode GID;
+ - 'imode': the inode mode;
+ - 'xattrnames': a list of xattr names (separated by ``|``), only if the xattr is
+    present;
+ - 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present;
+ - 'xattrvalues': a list of xattr values;
 
 
 Below, there is the list of defined template descriptors:
@@ -82,6 +91,7 @@ Below, there is the list of defined template descriptors:
  - "ima-sig": its format is ``d-ng|n-ng|sig``;
  - "ima-buf": its format is ``d-ng|n-ng|buf``;
  - "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
+ - "evm-sig": its format is ``d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode``;
 
 
 Use
index 2e84925..3df68cb 100644 (file)
@@ -25,7 +25,8 @@ Any user can enforce Landlock rulesets on their processes.  They are merged and
 evaluated according to the inherited ones in a way that ensures that only more
 constraints can be added.
 
-User space documentation can be found here: :doc:`/userspace-api/landlock`.
+User space documentation can be found here:
+Documentation/userspace-api/landlock.rst.
 
 Guiding principles for safe access controls
 ===========================================
index 882d3cc..6312968 100644 (file)
@@ -2,43 +2,47 @@
 PXA2xx SPI on SSP driver HOWTO
 ==============================
 
-This a mini howto on the pxa2xx_spi driver.  The driver turns a PXA2xx
-synchronous serial port into a SPI master controller
+This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx
+synchronous serial port into an SPI master controller
 (see Documentation/spi/spi-summary.rst). The driver has the following features
 
-- Support for any PXA2xx SSP
+- Support for any PXA2xx and compatible SSP.
 - SSP PIO and SSP DMA data transfers.
 - External and Internal (SSPFRM) chip selects.
 - Per slave device (chip) configuration.
 - Full suspend, freeze, resume support.
 
-The driver is built around a "spi_message" fifo serviced by workqueue and a
-tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet
-(pump_transfer) is responsible for queuing SPI transactions and setting up and
-launching the dma/interrupt driven transfers.
+The driver is built around a &struct spi_message FIFO serviced by kernel
+thread. The kernel thread, spi_pump_messages(), drives message FIFO and
+is responsible for queuing SPI transactions and setting up and launching
+the DMA or interrupt driven transfers.
 
 Declaring PXA2xx Master Controllers
 -----------------------------------
-Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
-"platform device".  The master configuration is passed to the driver via a table
-found in include/linux/spi/pxa2xx_spi.h::
+Typically, for a legacy platform, an SPI master is defined in the
+arch/.../mach-*/board-*.c as a "platform device". The master configuration
+is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h::
 
   struct pxa2xx_spi_controller {
        u16 num_chipselect;
        u8 enable_dma;
+       ...
   };
 
 The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of
 slave device (chips) attached to this SPI master.
 
 The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should
-be used.  This caused the driver to acquire two DMA channels: rx_channel and
-tx_channel.  The rx_channel has a higher DMA service priority the tx_channel.
+be used. This caused the driver to acquire two DMA channels: Rx channel and
+Tx channel. The Rx channel has a higher DMA service priority than the Tx channel.
 See the "PXA2xx Developer Manual" section "DMA Controller".
 
+For the new platforms the description of the controller and peripheral devices
+comes from Device Tree or ACPI.
+
 NSSP MASTER SAMPLE
 ------------------
-Below is a sample configuration using the PXA255 NSSP::
+Below is a sample configuration using the PXA255 NSSP for a legacy platform::
 
   static struct resource pxa_spi_nssp_resources[] = {
        [0] = {
@@ -79,9 +83,10 @@ Below is a sample configuration using the PXA255 NSSP::
 
 Declaring Slave Devices
 -----------------------
-Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c
-using the "spi_board_info" structure found in "linux/spi/spi.h". See
-"Documentation/spi/spi-summary.rst" for additional information.
+Typically, for a legacy platform, each SPI slave (chip) is defined in the
+arch/.../mach-*/board-*.c using the "spi_board_info" structure found in
+"linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional
+information.
 
 Each slave device attached to the PXA must provide slave specific configuration
 information via the structure "pxa2xx_spi_chip" found in
@@ -101,9 +106,9 @@ device. All fields are optional.
   };
 
 The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
-used to configure the SSP hardware fifo.  These fields are critical to the
+used to configure the SSP hardware FIFO. These fields are critical to the
 performance of pxa2xx_spi driver and misconfiguration will result in rx
-fifo overruns (especially in PIO mode transfers). Good default values are::
+FIFO overruns (especially in PIO mode transfers). Good default values are::
 
        .tx_threshold = 8,
        .rx_threshold = 8,
@@ -118,7 +123,7 @@ use a value of 8. The driver will determine a reasonable default if
 dma_burst_size == 0.
 
 The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
-trailing bytes in the SSP receiver fifo.  The correct value for this field is
+trailing bytes in the SSP receiver FIFO. The correct value for this field is
 dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
 slave device.  Please note that the PXA2xx SSP 1 does not support trailing byte
 timeouts and must busy-wait any trailing bytes.
@@ -131,19 +136,19 @@ testing.
 The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
 function for asserting/deasserting a slave device chip select.  If the field is
 NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
-configured to use SSPFRM instead.
+configured to use GPIO or SSPFRM instead.
 
 NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
 chipselect is dropped after each spi_transfer.  Most devices need chip select
-asserted around the complete message.  Use SSPFRM as a GPIO (through cs_control)
+asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor)
 to accommodate these chips.
 
 
 NSSP SLAVE SAMPLE
 -----------------
-The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
-"spi_board_info.controller_data" field. Below is a sample configuration using
-the PXA255 NSSP.
+For a legacy platform or in some other cases, the pxa2xx_spi_chip structure
+is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data"
+field. Below is a sample configuration using the PXA255 NSSP.
 
 ::
 
@@ -212,7 +217,9 @@ DMA and PIO I/O Support
 -----------------------
 The pxa2xx_spi driver supports both DMA and interrupt driven PIO message
 transfers.  The driver defaults to PIO mode and DMA transfers must be enabled
-by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure.  The DMA
+by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure.
+For the newer platforms, that are known to support DMA, the driver will enable
+it automatically and try it first with a possible fallback to PIO. The DMA
 mode supports both coherent and stream based DMA mappings.
 
 The following logic is used to determine the type of I/O to be used on
@@ -236,5 +243,4 @@ a per "spi_transfer" basis::
 
 THANKS TO
 ---------
-
 David Brownell and others for mentoring the development of this driver.
index b64d9a9..d25dfe8 100644 (file)
@@ -427,7 +427,7 @@ the ‘TRC’ prefix.
 :Syntax:
     ``echo idx > vmid_idx``
 
-    Where idx <  numvmidc
+    Where idx <  numvmidc
 
 ----
 
index 169749e..1ec8dc3 100644 (file)
@@ -315,7 +315,8 @@ intermediate links as required.
 
 Note: ``cti_sys0`` appears in two of the connections lists above.
 CTIs can connect to multiple devices and are arranged in a star topology
-via the CTM. See (:doc:`coresight-ect`) [#fourth]_ for further details.
+via the CTM. See (Documentation/trace/coresight/coresight-ect.rst)
+[#fourth]_ for further details.
 Looking at this device we see 4 connections::
 
   linaro-developer:~# ls -l /sys/bus/coresight/devices/cti_sys0/connections
@@ -606,7 +607,8 @@ interface provided for that purpose by the generic STM API::
     crw-------    1 root     root       10,  61 Jan  3 18:11 /dev/stm0
     root@genericarmv8:~#
 
-Details on how to use the generic STM API can be found here:- :doc:`../stm` [#second]_.
+Details on how to use the generic STM API can be found here:
+- Documentation/trace/stm.rst [#second]_.
 
 The CTI & CTM Modules
 ---------------------
@@ -616,7 +618,7 @@ individual CTIs and components, and can propagate these between all CTIs via
 channels on the CTM (Cross Trigger Matrix).
 
 A separate documentation file is provided to explain the use of these devices.
-(:doc:`coresight-ect`) [#fourth]_.
+(Documentation/trace/coresight/coresight-ect.rst) [#fourth]_.
 
 
 .. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
index 62c98e9..cfc81e9 100644 (file)
@@ -40,7 +40,7 @@ See events.rst for more information.
 Implementation Details
 ----------------------
 
-See :doc:`ftrace-design` for details for arch porters and such.
+See Documentation/trace/ftrace-design.rst for details for arch porters and such.
 
 
 The File System
@@ -354,8 +354,8 @@ of ftrace. Here is a list of some of the key files:
        is being directly called by the function. If the count is greater
        than 1 it most likely will be ftrace_ops_list_func().
 
-       If the callback of the function jumps to a trampoline that is
-       specific to a the callback and not the standard trampoline,
+       If the callback of a function jumps to a trampoline that is
+       specific to the callback and which is not the standard trampoline,
        its address will be printed as well as the function that the
        trampoline calls.
 
index b757b6d..998149c 100644 (file)
@@ -362,14 +362,11 @@ register_kprobe
        #include <linux/kprobes.h>
        int register_kprobe(struct kprobe *kp);
 
-Sets a breakpoint at the address kp->addr.  When the breakpoint is
-hit, Kprobes calls kp->pre_handler.  After the probed instruction
-is single-stepped, Kprobe calls kp->post_handler.  If a fault
-occurs during execution of kp->pre_handler or kp->post_handler,
-or during single-stepping of the probed instruction, Kprobes calls
-kp->fault_handler.  Any or all handlers can be NULL. If kp->flags
-is set KPROBE_FLAG_DISABLED, that kp will be registered but disabled,
-so, its handlers aren't hit until calling enable_kprobe(kp).
+Sets a breakpoint at the address kp->addr.  When the breakpoint is hit, Kprobes
+calls kp->pre_handler.  After the probed instruction is single-stepped, Kprobe
+calls kp->post_handler.  Any or all handlers can be NULL. If kp->flags is set
+KPROBE_FLAG_DISABLED, that kp will be registered but disabled, so, its handlers
+aren't hit until calling enable_kprobe(kp).
 
 .. note::
 
@@ -415,17 +412,6 @@ User's post-handler (kp->post_handler)::
 p and regs are as described for the pre_handler.  flags always seems
 to be zero.
 
-User's fault-handler (kp->fault_handler)::
-
-       #include <linux/kprobes.h>
-       #include <linux/ptrace.h>
-       int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr);
-
-p and regs are as described for the pre_handler.  trapnr is the
-architecture-specific trap number associated with the fault (e.g.,
-on i386, 13 for a general protection fault or 14 for a page fault).
-Returns 1 if it successfully handled the exception.
-
 register_kretprobe
 ------------------
 
index e446e5e..556b050 100644 (file)
@@ -18,6 +18,10 @@ Translations
 Disclaimer
 ----------
 
+.. raw:: latex
+
+       \kerneldocCJKoff
+
 Translation's purpose is to ease reading and understanding in languages other
 than English. Its aim is to help people who do not understand English or have
 doubts about its interpretation. Additionally, some people prefer to read
index bb8fa73..e80a309 100644 (file)
@@ -4,6 +4,10 @@
 Traduzione italiana
 ===================
 
+.. raw:: latex
+
+       \kerneldocCJKoff
+
 :manutentore: Federico Vaga <federico.vaga@vaga.pv.it>
 
 .. _it_disclaimer:
index 95f2e7c..ecc74ba 100644 (file)
@@ -62,7 +62,7 @@ i ``case``.  Un esempio.:
        case 'K':
        case 'k':
                mem <<= 10;
-               /* fall through */
+               fallthrough;
        default:
                break;
        }
index 2f91b89..f94ba62 100644 (file)
@@ -1,7 +1,8 @@
 .. raw:: latex
 
-        \renewcommand\thesection*
-        \renewcommand\thesubsection*
+       \renewcommand\thesection*
+       \renewcommand\thesubsection*
+       \kerneldocCJKon
 
 Japanese translations
 =====================
index b9e27d2..6ae2581 100644 (file)
@@ -1,7 +1,8 @@
 .. raw:: latex
 
-        \renewcommand\thesection*
-        \renewcommand\thesubsection*
+       \renewcommand\thesection*
+       \renewcommand\thesubsection*
+       \kerneldocCJKon
 
 한국어 번역
 ===========
index be835ec..460034c 100644 (file)
@@ -65,6 +65,7 @@ Todolist:
 
    clearing-warn-once
    cpu-load
+   lockup-watchdogs
    unicode
 
 Todolist:
@@ -100,7 +101,6 @@ Todolist:
    laptops/index
    lcd-panel-cgram
    ldm
-   lockup-watchdogs
    LSM/index
    md
    media/index
diff --git a/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst b/Documentation/translations/zh_CN/admin-guide/lockup-watchdogs.rst
new file mode 100644 (file)
index 0000000..55ed3f4
--- /dev/null
@@ -0,0 +1,66 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/lockup-watchdogs.rst
+:Translator: Hailong Liu <liu.hailong6@zte.com.cn>
+
+.. _cn_lockup-watchdogs:
+
+
+=================================================
+Softlockup与hardlockup检测机制(又名:nmi_watchdog)
+=================================================
+
+Linux中内核实现了一种用以检测系统发生softlockup和hardlockup的看门狗机制。
+
+Softlockup是一种会引发系统在内核态中一直循环超过20秒(详见下面“实现”小节)导致
+其他任务没有机会得到运行的BUG。一旦检测到'softlockup'发生,默认情况下系统会打
+印当前堆栈跟踪信息并进入锁定状态。也可配置使其在检测到'softlockup'后进入panic
+状态;通过sysctl命令设置“kernel.softlockup_panic”、使用内核启动参数
+“softlockup_panic”(详见Documentation/admin-guide/kernel-parameters.rst)以及使
+能内核编译选项“BOOTPARAM_SOFTLOCKUP_PANIC”都可实现这种配置。
+
+而'hardlockup'是一种会引发系统在内核态一直循环超过10秒钟(详见"实现"小节)导致其
+他中断没有机会运行的缺陷。与'softlockup'情况类似,除了使用sysctl命令设置
+'hardlockup_panic'、使能内核选项“BOOTPARAM_HARDLOCKUP_PANIC”以及使用内核参数
+"nmi_watchdog"(详见:”Documentation/admin-guide/kernel-parameters.rst“)外,一旦检
+测到'hardlockup'默认情况下系统打印当前堆栈跟踪信息,然后进入锁定状态。
+
+这个panic选项也可以与panic_timeout结合使用(这个panic_timeout是通过稍具迷惑性的
+sysctl命令"kernel.panic"来设置),使系统在panic指定时间后自动重启。
+
+实现
+====
+
+Softlockup和hardlockup分别建立在hrtimer(高精度定时器)和perf两个子系统上而实现。
+这也就意味着理论上任何架构只要实现了这两个子系统就支持这两种检测机制。
+
+Hrtimer用于周期性产生中断并唤醒watchdog线程;NMI perf事件则以”watchdog_thresh“
+(编译时默认初始化为10秒,也可通过”watchdog_thresh“这个sysctl接口来进行配置修改)
+为间隔周期产生以检测 hardlockups。如果一个CPU在这个时间段内没有检测到hrtimer中
+断发生,'hardlockup 检测器'(即NMI perf事件处理函数)将会视系统配置而选择产生内核
+警告或者直接panic。
+
+而watchdog线程本质上是一个高优先级内核线程,每调度一次就对时间戳进行一次更新。
+如果时间戳在2*watchdog_thresh(这个是softlockup的触发门限)这段时间都未更新,那么
+"softlocup 检测器"(内部hrtimer定时器回调函数)会将相关的调试信息打印到系统日志中,
+然后如果系统配置了进入panic流程则进入panic,否则内核继续执行。
+
+Hrtimer定时器的周期是2*watchdog_thresh/5,也就是说在hardlockup被触发前hrtimer有
+2~3次机会产生时钟中断。
+
+如上所述,内核相当于为系统管理员提供了一个可调节hrtimer定时器和perf事件周期长度
+的调节旋钮。如何通过这个旋钮为特定使用场景配置一个合理的周期值要对lockups检测的
+响应速度和lockups检测开销这二者之间进行权衡。
+
+默认情况下所有在线cpu上都会运行一个watchdog线程。不过在内核配置了”NO_HZ_FULL“的
+情况下watchdog线程默认只会运行在管家(housekeeping)cpu上,而”nohz_full“启动参数指
+定的cpu上则不会有watchdog线程运行。试想,如果我们允许watchdog线程在”nohz_full“指
+定的cpu上运行,这些cpu上必须得运行时钟定时器来激发watchdog线程调度;这样一来就会
+使”nohz_full“保护用户程序免受内核干扰的功能失效。当然,副作用就是”nohz_full“指定
+的cpu即使在内核产生了lockup问题我们也无法检测到。不过,至少我们可以允许watchdog
+线程在管家(non-tickless)核上继续运行以便我们能继续正常的监测这些cpus上的lockups
+事件。
+
+不论哪种情况都可以通过sysctl命令kernel.watchdog_cpumask来对没有运行watchdog线程
+的cpu集合进行调节。对于nohz_full而言,如果nohz_full cpu上有异常挂住的情况,通过
+这种方式打开这些cpu上的watchdog进行调试可能会有所作用。
diff --git a/Documentation/translations/zh_CN/core-api/cachetlb.rst b/Documentation/translations/zh_CN/core-api/cachetlb.rst
new file mode 100644 (file)
index 0000000..8376485
--- /dev/null
@@ -0,0 +1,336 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/cachetlb.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+
+:校译:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _cn_core-api_cachetlb:
+
+======================
+Linux下的缓存和TLB刷新
+======================
+
+:作者: David S. Miller <davem@redhat.com>
+
+*译注:TLB,Translation Lookaside Buffer,页表缓存/变换旁查缓冲器*
+
+本文描述了由Linux虚拟内存子系统调用的缓存/TLB刷新接口。它列举了每个接
+口,描述了它的预期目的,以及接口被调用后的预期副作用。
+
+下面描述的副作用是针对单处理器的实现,以及在单个处理器上发生的情况。若
+为SMP,则只需将定义简单地扩展一下,使发生在某个特定接口的副作用扩展到系
+统的所有处理器上。不要被这句话吓到,以为SMP的缓存/tlb刷新一定是很低
+效的,事实上,这是一个可以进行很多优化的领域。例如,如果可以证明一个用
+户地址空间从未在某个cpu上执行过(见mm_cpumask()),那么就不需要在该
+cpu上对这个地址空间进行刷新。
+
+首先是TLB刷新接口,因为它们是最简单的。在Linux下,TLB被抽象为cpu
+用来缓存从软件页表获得的虚拟->物理地址转换的东西。这意味着,如果软件页
+表发生变化,这个“TLB”缓存中就有可能出现过时(脏)的翻译。因此,当软件页表
+发生变化时,内核会在页表发生 *变化后* 调用以下一种刷新方法:
+
+1) ``void flush_tlb_all(void)``
+
+       最严格的刷新。在这个接口运行后,任何以前的页表修改都会对cpu可见。
+
+       这通常是在内核页表被改变时调用的,因为这种转换在本质上是“全局”的。
+
+2) ``void flush_tlb_mm(struct mm_struct *mm)``
+
+       这个接口从TLB中刷新整个用户地址空间。在运行后,这个接口必须确保
+       以前对地址空间‘mm’的任何页表修改对cpu来说是可见的。也就是说,在
+       运行后,TLB中不会有‘mm’的页表项。
+
+       这个接口被用来处理整个地址空间的页表操作,比如在fork和exec过程
+       中发生的事情。
+
+3) ``void flush_tlb_range(struct vm_area_struct *vma,
+   unsigned long start, unsigned long end)``
+
+       这里我们要从TLB中刷新一个特定范围的(用户)虚拟地址转换。在运行后,
+       这个接口必须确保以前对‘start’到‘end-1’范围内的地址空间‘vma->vm_mm’
+       的任何页表修改对cpu来说是可见的。也就是说,在运行后,TLB中不会有
+       ‘mm’的页表项用于‘start’到‘end-1’范围内的虚拟地址。
+
+       “vma”是用于该区域的备份存储。主要是用于munmap()类型的操作。
+
+       提供这个接口是希望端口能够找到一个合适的有效方法来从TLB中删除多
+       个页面大小的转换,而不是让内核为每个可能被修改的页表项调用
+       flush_tlb_page(见下文)。
+
+4) ``void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)``
+
+       这一次我们需要从TLB中删除PAGE_SIZE大小的转换。‘vma’是Linux用来跟
+       踪进程的mmap区域的支持结构体,地址空间可以通过vma->vm_mm获得。另
+       外,可以通过测试(vma->vm_flags & VM_EXEC)来查看这个区域是否是
+       可执行的(因此在split-tlb类型的设置中可能在“指令TLB”中)。
+
+       在运行后,这个接口必须确保之前对用户虚拟地址“addr”的地址空间
+       “vma->vm_mm”的页表修改对cpu来说是可见的。也就是说,在运行后,TLB
+       中不会有虚拟地址‘addr’的‘vma->vm_mm’的页表项。
+
+       这主要是在故障处理时使用。
+
+5) ``void update_mmu_cache(struct vm_area_struct *vma,
+   unsigned long address, pte_t *ptep)``
+
+       在每个页面故障结束时,这个程序被调用,以告诉体系结构特定的代码,在
+       软件页表中,在地址空间“vma->vm_mm”的虚拟地址“地址”处,现在存在
+       一个翻译。
+
+       可以用它所选择的任何方式使用这个信息来进行移植。例如,它可以使用这
+       个事件来为软件管理的TLB配置预装TLB转换。目前sparc64移植就是这么干
+       的。
+
+接下来,我们有缓存刷新接口。一般来说,当Linux将现有的虚拟->物理映射
+改变为新的值时,其顺序将是以下形式之一::
+
+       1) flush_cache_mm(mm);
+               change_all_page_tables_of(mm);
+               flush_tlb_mm(mm);
+
+       2) flush_cache_range(vma, start, end);
+               change_range_of_page_tables(mm, start, end);
+               flush_tlb_range(vma, start, end);
+
+       3) flush_cache_page(vma, addr, pfn);
+               set_pte(pte_pointer, new_pte_val);
+               flush_tlb_page(vma, addr);
+
+缓存级别的刷新将永远是第一位的,因为这允许我们正确处理那些缓存严格,
+且在虚拟地址被从缓存中刷新时要求一个虚拟地址的虚拟->物理转换存在的系统。
+HyperSparc cpu就是这样一个具有这种属性的cpu。
+
+下面的缓存刷新程序只需要在特定的cpu需要的范围内处理缓存刷新。大多数
+情况下,这些程序必须为cpu实现,这些cpu有虚拟索引的缓存,当虚拟->物
+理转换被改变或移除时,必须被刷新。因此,例如,IA32处理器的物理索引
+的物理标记的缓存没有必要实现这些接口,因为这些缓存是完全同步的,并
+且不依赖于翻译信息。
+
+下面逐个列出这些程序:
+
+1) ``void flush_cache_mm(struct mm_struct *mm)``
+
+       这个接口将整个用户地址空间从高速缓存中刷掉。也就是说,在运行后,
+       将没有与‘mm’相关的缓存行。
+
+       这个接口被用来处理整个地址空间的页表操作,比如在退出和执行过程
+       中发生的事情。
+
+2) ``void flush_cache_dup_mm(struct mm_struct *mm)``
+
+       这个接口将整个用户地址空间从高速缓存中刷新掉。也就是说,在运行
+       后,将没有与‘mm’相关的缓存行。
+
+       这个接口被用来处理整个地址空间的页表操作,比如在fork过程中发生
+       的事情。
+
+       这个选项与flush_cache_mm分开,以允许对VIPT缓存进行一些优化。
+
+3) ``void flush_cache_range(struct vm_area_struct *vma,
+   unsigned long start, unsigned long end)``
+
+       在这里,我们要从缓存中刷新一个特定范围的(用户)虚拟地址。运行
+       后,在“start”到“end-1”范围内的虚拟地址的“vma->vm_mm”的缓存中
+       将没有页表项。
+
+       “vma”是被用于该区域的备份存储。主要是用于munmap()类型的操作。
+
+       提供这个接口是希望端口能够找到一个合适的有效方法来从缓存中删
+       除多个页面大小的区域, 而不是让内核为每个可能被修改的页表项调
+       用 flush_cache_page (见下文)。
+
+4) ``void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)``
+
+       这一次我们需要从缓存中删除一个PAGE_SIZE大小的区域。“vma”是
+       Linux用来跟踪进程的mmap区域的支持结构体,地址空间可以通过
+       vma->vm_mm获得。另外,我们可以通过测试(vma->vm_flags &
+       VM_EXEC)来查看这个区域是否是可执行的(因此在“Harvard”类
+       型的缓存布局中可能是在“指令缓存”中)。
+
+       “pfn”表示“addr”所对应的物理页框(通过PAGE_SHIFT左移这个
+       值来获得物理地址)。正是这个映射应该从缓存中删除。
+
+       在运行之后,对于虚拟地址‘addr’的‘vma->vm_mm’,在缓存中不会
+       有任何页表项,它被翻译成‘pfn’。
+
+       这主要是在故障处理过程中使用。
+
+5) ``void flush_cache_kmaps(void)``
+
+       只有在平台使用高位内存的情况下才需要实现这个程序。它将在所有的
+       kmaps失效之前被调用。
+
+       运行后,内核虚拟地址范围PKMAP_ADDR(0)到PKMAP_ADDR(LAST_PKMAP)
+       的缓存中将没有页表项。
+
+       这个程序应该在asm/highmem.h中实现。
+
+6) ``void flush_cache_vmap(unsigned long start, unsigned long end)``
+   ``void flush_cache_vunmap(unsigned long start, unsigned long end)``
+
+       在这里,在这两个接口中,我们从缓存中刷新一个特定范围的(内核)
+       虚拟地址。运行后,在“start”到“end-1”范围内的虚拟地址的内核地
+       址空间的缓存中不会有页表项。
+
+       这两个程序中的第一个是在vmap_range()安装了页表项之后调用的。
+       第二个是在vunmap_range()删除页表项之前调用的。
+
+还有一类cpu缓存问题,目前需要一套完全不同的接口来正确处理。最大
+的问题是处理器的数据缓存中的虚拟别名。
+
+.. note::
+
+       这段内容有些晦涩,为了减轻中文阅读压力,特作此译注。
+
+       别名(alias)属于缓存一致性问题,当不同的虚拟地址映射相同的
+       物理地址,而这些虚拟地址的index不同,此时就发生了别名现象(多
+       个虚拟地址被称为别名)。通俗点来说就是指同一个物理地址的数据被
+       加载到不同的cacheline中就会出现别名现象。
+
+       常见的解决方法有两种:第一种是硬件维护一致性,设计特定的cpu电
+       路来解决问题(例如设计为PIPT的cache);第二种是软件维护一致性,
+       就是下面介绍的sparc的解决方案——页面染色,涉及的技术细节太多,
+       译者不便展开,请读者自行查阅相关资料。
+
+您的移植是否容易在其D-cache中出现虚拟别名?嗯,如果您的D-cache
+是虚拟索引的,且cache大于PAGE_SIZE(页大小),并且不能防止同一
+物理地址的多个cache行同时存在,您就会遇到这个问题。
+
+如果你的D-cache有这个问题,首先正确定义asm/shmparam.h SHMLBA,
+它基本上应该是你的虚拟寻址D-cache的大小(或者如果大小是可变的,
+则是最大的可能大小)。这个设置将迫使SYSv IPC层只允许用户进程在
+这个值的倍数的地址上对共享内存进行映射。
+
+.. note::
+
+       这并不能解决共享mmaps的问题,请查看sparc64移植解决
+       这个问题的一个方法(特别是 SPARC_FLAG_MMAPSHARED)。
+
+接下来,你必须解决所有其他情况下的D-cache别名问题。请记住这个事
+实,对于一个给定的页面映射到某个用户地址空间,总是至少还有一个映
+射,那就是内核在其线性映射中从PAGE_OFFSET开始。因此,一旦第一个
+用户将一个给定的物理页映射到它的地址空间,就意味着D-cache的别名
+问题有可能存在,因为内核已经将这个页映射到它的虚拟地址。
+
+  ``void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)``
+  ``void clear_user_page(void *to, unsigned long addr, struct page *page)``
+
+       这两个程序在用户匿名或COW页中存储数据。它允许一个端口有效地
+       避免用户空间和内核之间的D-cache别名问题。
+
+       例如,一个端口可以在复制过程中把“from”和“to”暂时映射到内核
+       的虚拟地址上。这两个页面的虚拟地址的选择方式是,内核的加载/存
+       储指令发生在虚拟地址上,而这些虚拟地址与用户的页面映射是相同
+       的“颜色”。例如,Sparc64就使用这种技术。
+
+       “addr”参数告诉了用户最终要映射这个页面的虚拟地址,“page”参
+       数给出了一个指向目标页结构体的指针。
+
+       如果D-cache别名不是问题,这两个程序可以简单地直接调用
+       memcpy/memset而不做其他事情。
+
+  ``void flush_dcache_page(struct page *page)``
+
+       任何时候,当内核写到一个页面缓存页,或者内核要从一个页面缓存
+       页中读出,并且这个页面的用户空间共享/可写映射可能存在时,
+       这个程序就会被调用。
+
+       .. note::
+
+                       这个程序只需要为有可能被映射到用户进程的地址空间的
+                       页面缓存调用。因此,例如,处理页面缓存中vfs符号链
+                       接的VFS层代码根本不需要调用这个接口。
+
+       “内核写入页面缓存的页面”这句话的意思是,具体来说,内核执行存
+       储指令,在该页面的页面->虚拟映射处弄脏该页面的数据。在这里,通
+       过刷新的手段处理D-cache的别名是很重要的,以确保这些内核存储对
+       该页的用户空间映射是可见的。
+
+       推论的情况也同样重要,如果有用户对这个文件有共享+可写的映射,
+       我们必须确保内核对这些页面的读取会看到用户所做的最新的存储。
+
+       如果D-cache别名不是一个问题,这个程序可以简单地定义为该架构上
+       的nop。
+
+       在page->flags (PG_arch_1)中有一个位是“架构私有”。内核保证,
+       对于分页缓存的页面,当这样的页面第一次进入分页缓存时,它将清除
+       这个位。
+
+       这使得这些接口可以更有效地被实现。如果目前没有用户进程映射这个
+       页面,它允许我们“推迟”(也许是无限期)实际的刷新过程。请看
+       sparc64的flush_dcache_page和update_mmu_cache实现,以了解如
+       何做到这一点。
+
+       这个想法是,首先在flush_dcache_page()时,如果page->mapping->i_mmap
+       是一个空树,只需标记架构私有页标志位。之后,在update_mmu_cache()
+       中,会对这个标志位进行检查,如果设置了,就进行刷新,并清除标志位。
+
+       .. important::
+
+                               通常很重要的是,如果你推迟刷新,实际的刷新发生在同一个
+                               CPU上,因为它将cpu存储到页面上,使其变脏。同样,请看
+                               sparc64关于如何处理这个问题的例子。
+
+  ``void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long user_vaddr, void *dst, void *src, int len)``
+  ``void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long user_vaddr, void *dst, void *src, int len)``
+
+       当内核需要复制任意的数据进出任意的用户页时(比如ptrace()),它将使
+       用这两个程序。
+
+       任何必要的缓存刷新或其他需要发生的一致性操作都应该在这里发生。如果
+       处理器的指令缓存没有对cpu存储进行窥探,那么你很可能需要为
+       copy_to_user_page()刷新指令缓存。
+
+  ``void flush_anon_page(struct vm_area_struct *vma, struct page *page,
+  unsigned long vmaddr)``
+
+       当内核需要访问一个匿名页的内容时,它会调用这个函数(目前只有
+       get_user_pages())。注意:flush_dcache_page()故意对匿名页不起作
+       用。默认的实现是nop(对于所有相干的架构应该保持这样)。对于不一致性
+       的架构,它应该刷新vmaddr处的页面缓存。
+
+  ``void flush_kernel_dcache_page(struct page *page)``
+
+       当内核需要修改一个用kmap获得的用户页时,它会在所有修改完成后(但在
+       kunmapping之前)调用这个函数,以使底层页面达到最新状态。这里假定用
+       户没有不一致性的缓存副本(即原始页面是从类似get_user_pages()的机制
+       中获得的)。默认的实现是一个nop,在所有相干的架构上都应该如此。在不
+       一致性的架构上,这应该刷新内核缓存中的页面(使用page_address(page))。
+
+
+  ``void flush_icache_range(unsigned long start, unsigned long end)``
+
+       当内核存储到它将执行的地址中时(例如在加载模块时),这个函数被调用。
+
+       如果icache不对存储进行窥探,那么这个程序将需要对其进行刷新。
+
+  ``void flush_icache_page(struct vm_area_struct *vma, struct page *page)``
+
+       flush_icache_page的所有功能都可以在flush_dcache_page和update_mmu_cache
+       中实现。在未来,我们希望能够完全删除这个接口。
+
+最后一类API是用于I/O到内核内特意设置的别名地址范围。这种别名是通过使用
+vmap/vmalloc API设置的。由于内核I/O是通过物理页进行的,I/O子系统假定用户
+映射和内核偏移映射是唯一的别名。这对vmap别名来说是不正确的,所以内核中任何
+试图对vmap区域进行I/O的东西都必须手动管理一致性。它必须在做I/O之前刷新vmap
+范围,并在I/O返回后使其失效。
+
+  ``void flush_kernel_vmap_range(void *vaddr, int size)``
+
+       刷新vmap区域中指定的虚拟地址范围的内核缓存。这是为了确保内核在vmap范围
+       内修改的任何数据对物理页是可见的。这个设计是为了使这个区域可以安全地执
+       行I/O。注意,这个API并 *没有* 刷新该区域的偏移映射别名。
+
+  ``void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates``
+
+       在vmap区域的一个给定的虚拟地址范围的缓存,这可以防止处理器在物理页的I/O
+       发生时通过投机性地读取数据而使缓存变脏。这只对读入vmap区域的数据是必要的。
index f1fa71e..b4bde93 100644 (file)
 来的大量 kerneldoc 信息;有朝一日,若有人有动力的话,应当把它们拆分
 出来。
 
-Todolist:
+.. toctree::
+   :maxdepth: 1
 
    kernel-api
-   workqueue
    printk-basics
    printk-formats
+   workqueue
    symbol-namespaces
 
 数据结构和低级实用程序
@@ -32,9 +33,13 @@ Todolist:
 
 在整个内核中使用的函数库。
 
-Todolist:
+.. toctree::
+   :maxdepth: 1
 
    kobject
+
+Todolist:
+
    kref
    assoc_array
    xarray
@@ -58,12 +63,12 @@ Linux如何让一切同时发生。 详情请参阅
    :maxdepth: 1
 
    irq/index
-
-Todolist:
-
    refcount-vs-atomic
    local_ops
    padata
+
+Todolist:
+
    ../RCU/index
 
 低级硬件管理
@@ -71,9 +76,14 @@ Todolist:
 
 缓存管理,CPU热插拔管理等。
 
-Todolist:
+.. toctree::
+   :maxdepth: 1
 
    cachetlb
+
+Todolist:
+
+
    cpu_hotplug
    memory-hotplug
    genericirq
diff --git a/Documentation/translations/zh_CN/core-api/kernel-api.rst b/Documentation/translations/zh_CN/core-api/kernel-api.rst
new file mode 100644 (file)
index 0000000..d6f815e
--- /dev/null
@@ -0,0 +1,369 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/kernel-api.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_kernel-api.rst:
+
+
+============
+Linux内核API
+============
+
+
+列表管理函数
+============
+
+该API在以下内核代码中:
+
+include/linux/list.h
+
+基本的C库函数
+=============
+
+在编写驱动程序时,一般不能使用C库中的例程。部分函数通常很有用,它们在
+下面被列出。这些函数的行为可能会与ANSI定义的略有不同,这些偏差会在文中
+注明。
+
+字符串转换
+----------
+
+该API在以下内核代码中:
+
+lib/vsprintf.c
+
+include/linux/kernel.h
+
+include/linux/kernel.h
+
+lib/kstrtox.c
+
+lib/string_helpers.c
+
+字符串处理
+----------
+
+该API在以下内核代码中:
+
+lib/string.c
+
+include/linux/string.h
+
+mm/util.c
+
+基本的内核库函数
+================
+
+Linux内核提供了很多实用的基本函数。
+
+位运算
+------
+
+该API在以下内核代码中:
+
+include/asm-generic/bitops/instrumented-atomic.h
+
+include/asm-generic/bitops/instrumented-non-atomic.h
+
+include/asm-generic/bitops/instrumented-lock.h
+
+位图运算
+--------
+
+该API在以下内核代码中:
+
+lib/bitmap.c
+
+include/linux/bitmap.h
+
+include/linux/bitmap.h
+
+include/linux/bitmap.h
+
+lib/bitmap.c
+
+lib/bitmap.c
+
+include/linux/bitmap.h
+
+命令行解析
+----------
+
+该API在以下内核代码中:
+
+lib/cmdline.c
+
+排序
+----
+
+该API在以下内核代码中:
+
+lib/sort.c
+
+lib/list_sort.c
+
+文本检索
+--------
+
+该API在以下内核代码中:
+
+lib/textsearch.c
+
+lib/textsearch.c
+
+include/linux/textsearch.h
+
+Linux中的CRC和数学函数
+======================
+
+
+CRC函数
+-------
+
+*译注:CRC,Cyclic Redundancy Check,循环冗余校验*
+
+该API在以下内核代码中:
+
+lib/crc4.c
+
+lib/crc7.c
+
+lib/crc8.c
+
+lib/crc16.c
+
+lib/crc32.c
+
+lib/crc-ccitt.c
+
+lib/crc-itu-t.c
+
+基数为2的对数和幂函数
+---------------------
+
+该API在以下内核代码中:
+
+include/linux/log2.h
+
+整数幂函数
+----------
+
+该API在以下内核代码中:
+
+lib/math/int_pow.c
+
+lib/math/int_sqrt.c
+
+除法函数
+--------
+
+该API在以下内核代码中:
+
+include/asm-generic/div64.h
+
+include/linux/math64.h
+
+lib/math/div64.c
+
+lib/math/gcd.c
+
+UUID/GUID
+---------
+
+该API在以下内核代码中:
+
+lib/uuid.c
+
+内核IPC设备
+===========
+
+IPC实用程序
+-----------
+
+该API在以下内核代码中:
+
+ipc/util.c
+
+FIFO 缓冲区
+===========
+
+kfifo接口
+---------
+
+该API在以下内核代码中:
+
+include/linux/kfifo.h
+
+转发接口支持
+============
+
+转发接口支持旨在为工具和设备提供一种有效的机制,将大量数据从内核空间
+转发到用户空间。
+
+转发接口
+--------
+
+该API在以下内核代码中:
+
+kernel/relay.c
+
+kernel/relay.c
+
+模块支持
+========
+
+模块加载
+--------
+
+该API在以下内核代码中:
+
+kernel/kmod.c
+
+模块接口支持
+------------
+
+更多信息请参考文件kernel/module.c。
+
+硬件接口
+========
+
+
+该API在以下内核代码中:
+
+kernel/dma.c
+
+资源管理
+--------
+
+该API在以下内核代码中:
+
+kernel/resource.c
+
+kernel/resource.c
+
+MTRR处理
+--------
+
+该API在以下内核代码中:
+
+arch/x86/kernel/cpu/mtrr/mtrr.c
+
+安全框架
+========
+
+该API在以下内核代码中:
+
+security/security.c
+
+security/inode.c
+
+审计接口
+========
+
+该API在以下内核代码中:
+
+kernel/audit.c
+
+kernel/auditsc.c
+
+kernel/auditfilter.c
+
+核算框架
+========
+
+该API在以下内核代码中:
+
+kernel/acct.c
+
+块设备
+======
+
+该API在以下内核代码中:
+
+block/blk-core.c
+
+block/blk-core.c
+
+block/blk-map.c
+
+block/blk-sysfs.c
+
+block/blk-settings.c
+
+block/blk-exec.c
+
+block/blk-flush.c
+
+block/blk-lib.c
+
+block/blk-integrity.c
+
+kernel/trace/blktrace.c
+
+block/genhd.c
+
+block/genhd.c
+
+字符设备
+========
+
+该API在以下内核代码中:
+
+fs/char_dev.c
+
+时钟框架
+========
+
+时钟框架定义了编程接口,以支持系统时钟树的软件管理。该框架广泛用于系统级芯片(SOC)平
+台,以支持电源管理和各种可能需要自定义时钟速率的设备。请注意,这些 “时钟”与计时或实
+时时钟(RTC)无关,它们都有单独的框架。这些:c:type: `struct clk <clk>` 实例可用于管理
+各种时钟信号,例如一个96理例如96MHz的时钟信号,该信号可被用于总线或外设的数据交换,或以
+其他方式触发系统硬件中的同步状态机转换。
+
+通过明确的软件时钟门控来支持电源管理:未使用的时钟被禁用,因此系统不会因为改变不在使用
+中的晶体管的状态而浪费电源。在某些系统中,这可能是由硬件时钟门控支持的,其中时钟被门控
+而不在软件中被禁用。芯片的部分,在供电但没有时钟的情况下,可能会保留其最后的状态。这种
+低功耗状态通常被称为*保留模式*。这种模式仍然会产生漏电流,特别是在电路几何结构较细的情
+况下,但对于CMOS电路来说,电能主要是随着时钟翻转而被消耗的。
+
+电源感知驱动程序只有在其管理的设备处于活动使用状态时才会启用时钟。此外,系统睡眠状态通
+常根据哪些时钟域处于活动状态而有所不同:“待机”状态可能允许从多个活动域中唤醒,而
+"mem"(暂停到RAM)状态可能需要更全面地关闭来自高速PLL和振荡器的时钟,从而限制了可能
+的唤醒事件源的数量。驱动器的暂停方法可能需要注意目标睡眠状态的系统特定时钟约束。
+
+一些平台支持可编程时钟发生器。这些可以被各种外部芯片使用,如其他CPU、多媒体编解码器以
+及对接口时钟有严格要求的设备。
+
+该API在以下内核代码中:
+
+include/linux/clk.h
+
+同步原语
+========
+
+读-复制-更新(RCU)
+-------------------
+
+该API在以下内核代码中:
+
+include/linux/rcupdate.h
+
+kernel/rcu/tree.c
+
+kernel/rcu/tree_exp.h
+
+kernel/rcu/update.c
+
+include/linux/srcu.h
+
+kernel/rcu/srcutree.c
+
+include/linux/rculist_bl.h
+
+include/linux/rculist.h
+
+include/linux/rculist_nulls.h
+
+include/linux/rcu_sync.h
+
+kernel/rcu/sync.c
diff --git a/Documentation/translations/zh_CN/core-api/kobject.rst b/Documentation/translations/zh_CN/core-api/kobject.rst
new file mode 100644 (file)
index 0000000..f0e6a4a
--- /dev/null
@@ -0,0 +1,378 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/kobject.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_core_api_kobject.rst:
+
+=======================================================
+关于kobjects、ksets和ktypes的一切你没想过需要了解的东西
+=======================================================
+
+:作者: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+:最后一次更新: December 19, 2007
+
+根据Jon Corbet于2003年10月1日为lwn.net撰写的原创文章改编,网址是:
+https://lwn.net/Articles/51437/
+
+理解驱动模型和建立在其上的kobject抽象的部分的困难在于,没有明显的切入点。
+处理kobjects需要理解一些不同的类型,所有这些类型都会相互引用。为了使事情
+变得更简单,我们将多路并进,从模糊的术语开始,并逐渐增加细节。那么,先来
+了解一些我们将要使用的术语的简明定义吧。
+
+ - 一个kobject是一个kobject结构体类型的对象。Kobjects有一个名字和一个
+   引用计数。一个kobject也有一个父指针(允许对象被排列成层次结构),一个
+   特定的类型,并且,通常在sysfs虚拟文件系统中表示。
+
+  Kobjects本身通常并不引人关注;相反它们常常被嵌入到其他包含真正引人注目
+  的代码的结构体中。
+
+  任何结构体都 **不应该** 有一个以上的kobject嵌入其中。如果有的话,对象的引用计
+  数肯定会被打乱,而且不正确,你的代码就会出现错误。所以不要这样做。
+
+ - ktype是嵌入一个kobject的对象的类型。每个嵌入kobject的结构体都需要一个
+   相应的ktype。ktype控制着kobject在被创建和销毁时的行为。
+
+ - 一个kset是一组kobjects。这些kobjects可以是相同的ktype或者属于不同的
+   ktype。kset是kobjects集合的基本容器类型。Ksets包含它们自己的kobjects,
+   但你可以安全地忽略这个实现细节,因为kset的核心代码会自动处理这个kobject。
+
+ 当你看到一个下面全是其他目录的sysfs目录时,通常这些目录中的每一个都对应
+ 于同一个kset中的一个kobject。
+
+ 我们将研究如何创建和操作所有这些类型。将采取一种自下而上的方法,所以我们
+ 将回到kobjects。
+
+
+嵌入kobjects
+=============
+
+内核代码很少创建孤立的kobject,只有一个主要的例外,下面会解释。相反,
+kobjects被用来控制对一个更大的、特定领域的对象的访问。为此,kobjects会被
+嵌入到其他结构中。如果你习惯于用面向对象的术语来思考问题,那么kobjects可
+以被看作是一个顶级的抽象类,其他的类都是从它派生出来的。一个kobject实现了
+一系列的功能,这些功能本身并不特别有用,但在其他对象中却很好用。C语言不允
+许直接表达继承,所以必须使用其他技术——比如结构体嵌入。
+
+(对于那些熟悉内核链表实现的人来说,这类似于“list_head”结构本身很少有用,
+但总是被嵌入到感兴趣的更大的对象中)。
+
+例如, ``drivers/uio/uio.c`` 中的IO代码有一个结构体,定义了与uio设备相
+关的内存区域::
+
+    struct uio_map {
+            struct kobject kobj;
+            struct uio_mem *mem;
+    };
+
+如果你有一个uio_map结构体,找到其嵌入的kobject只是一个使用kobj成员的问题。
+然而,与kobjects一起工作的代码往往会遇到相反的问题:给定一个结构体kobject
+的指针,指向包含结构体的指针是什么?你必须避免使用一些技巧(比如假设
+kobject在结构的开头),相反,你得使用container_of()宏,其可以在 ``<linux/kernel.h>``
+中找到::
+
+    container_of(ptr, type, member)
+
+其中:
+
+  * ``ptr`` 是一个指向嵌入kobject的指针,
+  * ``type`` 是包含结构体的类型,
+  * ``member`` 是 ``指针`` 所指向的结构体域的名称。
+
+container_of()的返回值是一个指向相应容器类型的指针。因此,例如,一个嵌入到
+uio_map结构 **中** 的kobject结构体的指针kp可以被转换为一个指向 **包含** uio_map
+结构体的指针,方法是::
+
+    struct uio_map *u_map = container_of(kp, struct uio_map, kobj);
+
+为了方便起见,程序员经常定义一个简单的宏,用于将kobject指针 **反推** 到包含
+类型。在早期的 ``drivers/uio/uio.c`` 中正是如此,你可以在这里看到::
+
+    struct uio_map {
+            struct kobject kobj;
+            struct uio_mem *mem;
+    };
+
+    #define to_map(map) container_of(map, struct uio_map, kobj)
+
+其中宏的参数“map”是一个指向有关的kobject结构体的指针。该宏随后被调用::
+
+    struct uio_map *map = to_map(kobj);
+
+
+kobjects的初始化
+================
+
+当然,创建kobject的代码必须初始化该对象。一些内部字段是通过(强制)调用kobject_init()
+来设置的::
+
+    void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
+
+ktype是正确创建kobject的必要条件,因为每个kobject都必须有一个相关的kobj_type。
+在调用kobject_init()后,为了向sysfs注册kobject,必须调用函数kobject_add()::
+
+    int kobject_add(struct kobject *kobj, struct kobject *parent,
+                    const char *fmt, ...);
+
+这将正确设置kobject的父级和kobject的名称。如果该kobject要与一个特定的kset相关
+联,在调用kobject_add()之前必须分配kobj->kset。如果kset与kobject相关联,则
+kobject的父级可以在调用kobject_add()时被设置为NULL,则kobject的父级将是kset
+本身。
+
+由于kobject的名字是在它被添加到内核时设置的,所以kobject的名字不应该被直接操作。
+如果你必须改变kobject的名字,请调用kobject_rename()::
+
+    int kobject_rename(struct kobject *kobj, const char *new_name);
+
+kobject_rename()函数不会执行任何锁定操作,也不会对name进行可靠性检查,所以调用
+者自己检查和串行化操作是明智的选择
+
+有一个叫kobject_set_name()的函数,但那是历史遗产,正在被删除。如果你的代码需
+要调用这个函数,那么它是不正确的,需要被修复。
+
+要正确访问kobject的名称,请使用函数kobject_name()::
+
+    const char *kobject_name(const struct kobject * kobj);
+
+有一个辅助函数可以同时初始化和添加kobject到内核中,令人惊讶的是,该函数被称为
+kobject_init_and_add()::
+
+    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+                             struct kobject *parent, const char *fmt, ...);
+
+参数与上面描述的单个kobject_init()和kobject_add()函数相同。
+
+
+Uevents
+=======
+
+当一个kobject被注册到kobject核心后,你需要向全世界宣布它已经被创建了。这可以通
+过调用kobject_uevent()来实现::
+
+    int kobject_uevent(struct kobject *kobj, enum kobject_action action);
+
+当kobject第一次被添加到内核时,使用 *KOBJ_ADD* 动作。这应该在该kobject的任
+何属性或子对象被正确初始化后进行,因为当这个调用发生时,用户空间会立即开始寻
+找它们。
+
+当kobject从内核中移除时(关于如何做的细节在下面), **KOBJ_REMOVE** 的uevent
+将由kobject核心自动创建,所以调用者不必担心手动操作。
+
+
+引用计数
+========
+
+kobject的关键功能之一是作为它所嵌入的对象的一个引用计数器。只要对该对象的引用
+存在,该对象(以及支持它的代码)就必须继续存在。用于操作kobject的引用计数的低
+级函数是::
+
+    struct kobject *kobject_get(struct kobject *kobj);
+    void kobject_put(struct kobject *kobj);
+
+对kobject_get()的成功调用将增加kobject的引用计数器值并返回kobject的指针。
+
+当引用被释放时,对kobject_put()的调用将递减引用计数值,并可能释放该对象。请注
+意,kobject_init()将引用计数设置为1,所以设置kobject的代码最终需要kobject_put()
+来释放该引用。
+
+因为kobjects是动态的,所以它们不能以静态方式或在堆栈中声明,而总是以动态方式分
+配。未来版本的内核将包含对静态创建的kobjects的运行时检查,并将警告开发者这种不
+当的使用。
+
+如果你使用struct kobject只是为了给你的结构体提供一个引用计数器,请使用struct kref
+来代替;kobject是多余的。关于如何使用kref结构体的更多信息,请参见Linux内核源代
+码树中的文件Documentation/core-api/kref.rst
+
+
+创建“简单的”kobjects
+====================
+
+有时,开发者想要的只是在sysfs层次结构中创建一个简单的目录,而不必去搞那些复杂
+的ksets、显示和存储函数,以及其他细节。这是一个应该创建单个kobject的例外。要
+创建这样一个条目(即简单的目录),请使用函数::
+
+    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
+
+这个函数将创建一个kobject,并将其放在sysfs中指定的父kobject下面的位置。要创
+建与此kobject相关的简单属性,请使用::
+
+    int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
+
+或者::
+
+    int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
+
+这里使用的两种类型的属性,与已经用kobject_create_and_add()创建的kobject,
+都可以是kobj_attribute类型,所以不需要创建特殊的自定义属性。
+
+参见示例模块, ``samples/kobject/kobject-example.c`` ,以了解一个简单的
+kobject和属性的实现。
+
+
+
+ktypes和释放方法
+================
+
+以上讨论中还缺少一件重要的事情,那就是当一个kobject的引用次数达到零的时候
+会发生什么。创建kobject的代码通常不知道何时会发生这种情况;首先,如果它知
+道,那么使用kobject就没有什么意义。当sysfs被引入时,即使是可预测的对象生命
+周期也会变得更加复杂,因为内核的其他部分可以获得在系统中注册的任何kobject
+的引用。
+
+最终的结果是,一个由kobject保护的结构体在其引用计数归零之前不能被释放。引
+用计数不受创建kobject的代码的直接控制。因此,每当它的一个kobjects的最后一
+个引用消失时,必须异步通知该代码。
+
+一旦你通过kobject_add()注册了你的kobject,你绝对不能使用kfree()来直接释
+放它。唯一安全的方法是使用kobject_put()。在kobject_init()之后总是使用
+kobject_put()以避免错误的发生是一个很好的做法。
+
+这个通知是通过kobject的release()方法完成的。通常这样的方法有如下形式::
+
+    void my_object_release(struct kobject *kobj)
+    {
+            struct my_object *mine = container_of(kobj, struct my_object, kobj);
+
+            /* Perform any additional cleanup on this object, then... */
+            kfree(mine);
+    }
+
+有一点很重要:每个kobject都必须有一个release()方法,而且这个kobject必
+须持续存在(处于一致的状态),直到这个方法被调用。如果这些约束条件没有
+得到满足,那么代码就是有缺陷的。注意,如果你忘记提供release()方法,内
+核会警告你。不要试图通过提供一个“空”的释放函数来摆脱这个警告。
+
+如果你的清理函数只需要调用kfree(),那么你必须创建一个包装函数,该函数
+使用container_of()来向上造型到正确的类型(如上面的例子所示),然后在整个
+结构体上调用kfree()。
+
+注意,kobject的名字在release函数中是可用的,但它不能在这个回调中被改
+变。否则,在kobject核心中会出现内存泄漏,这让人很不爽。
+
+有趣的是,release()方法并不存储在kobject本身;相反,它与ktype相关。
+因此,让我们引入结构体kobj_type::
+
+    struct kobj_type {
+            void (*release)(struct kobject *kobj);
+            const struct sysfs_ops *sysfs_ops;
+            struct attribute **default_attrs;
+            const struct attribute_group **default_groups;
+            const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
+            const void *(*namespace)(struct kobject *kobj);
+            void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
+    };
+
+这个结构提用来描述一个特定类型的kobject(或者更正确地说,包含对象的
+类型)。每个kobject都需要有一个相关的kobj_type结构;当你调用
+kobject_init()或kobject_init_and_add()时必须指定一个指向该结构的
+指针。
+
+当然,kobj_type结构中的release字段是指向这种类型的kobject的release()
+方法的一个指针。另外两个字段(sysfs_ops 和 default_attrs)控制这种
+类型的对象如何在 sysfs 中被表示;它们超出了本文的范围。
+
+default_attrs 指针是一个默认属性的列表,它将为任何用这个 ktype 注册
+的 kobject 自动创建。
+
+
+ksets
+=====
+
+一个kset仅仅是一个希望相互关联的kobjects的集合。没有限制它们必须是相
+同的ktype,但是如果它们不是相同的,就要非常小心。
+
+一个kset有以下功能:
+
+ - 它像是一个包含一组对象的袋子。一个kset可以被内核用来追踪“所有块
+   设备”或“所有PCI设备驱动”。
+
+ - kset也是sysfs中的一个子目录,与kset相关的kobjects可以在这里显示
+   出来。每个kset都包含一个kobject,它可以被设置为其他kobject的父对象;
+   sysfs层次结构的顶级目录就是以这种方式构建的。
+
+ - Ksets可以支持kobjects的 "热插拔",并影响uevent事件如何被报告给
+   用户空间。
+
+ 在面向对象的术语中,“kset”是顶级的容器类;ksets包含它们自己的kobject,
+ 但是这个kobject是由kset代码管理的,不应该被任何其他用户所操纵。
+
+ kset在一个标准的内核链表中保存它的子对象。Kobjects通过其kset字段指向其
+ 包含的kset。在几乎所有的情况下,属于一个kset的kobjects在它们的父
+ 对象中都有那个kset(或者,严格地说,它的嵌入kobject)。
+
+ 由于kset中包含一个kobject,它应该总是被动态地创建,而不是静态地
+ 或在堆栈中声明。要创建一个新的kset,请使用::
+
+  struct kset *kset_create_and_add(const char *name,
+                                   const struct kset_uevent_ops *uevent_ops,
+                                   struct kobject *parent_kobj);
+
+当你完成对kset的处理后,调用::
+
+  void kset_unregister(struct kset *k);
+
+来销毁它。这将从sysfs中删除该kset并递减其引用计数值。当引用计数
+为零时,该kset将被释放。因为对该kset的其他引用可能仍然存在,
+释放可能发生在kset_unregister()返回之后。
+
+一个使用kset的例子可以在内核树中的 ``samples/kobject/kset-example.c``
+文件中看到。
+
+如果一个kset希望控制与它相关的kobjects的uevent操作,它可以使用
+结构体kset_uevent_ops来处理它::
+
+  struct kset_uevent_ops {
+          int (* const filter)(struct kset *kset, struct kobject *kobj);
+          const char *(* const name)(struct kset *kset, struct kobject *kobj);
+          int (* const uevent)(struct kset *kset, struct kobject *kobj,
+                        struct kobj_uevent_env *env);
+  };
+
+
+过滤器函数允许kset阻止一个特定kobject的uevent被发送到用户空间。
+如果该函数返回0,该uevent将不会被发射出去。
+
+name函数将被调用以覆盖uevent发送到用户空间的kset的默认名称。默
+认情况下,该名称将与kset本身相同,但这个函数,如果存在,可以覆盖
+该名称。
+
+当uevent即将被发送至用户空间时,uevent函数将被调用,以允许更多
+的环境变量被添加到uevent中。
+
+有人可能会问,鉴于没有提出执行该功能的函数,究竟如何将一个kobject
+添加到一个kset中。答案是这个任务是由kobject_add()处理的。当一个
+kobject被传递给kobject_add()时,它的kset成员应该指向这个kobject
+所属的kset。 kobject_add()将处理剩下的部分。
+
+如果属于一个kset的kobject没有父kobject集,它将被添加到kset的目
+录中。并非所有的kset成员都必须住在kset目录中。如果在添加kobject
+之前分配了一个明确的父kobject,那么该kobject将被注册到kset中,
+但是被添加到父kobject下面。
+
+
+移除Kobject
+===========
+
+当一个kobject在kobject核心注册成功后,在代码使用完它时,必须将其
+清理掉。要做到这一点,请调用kobject_put()。通过这样做,kobject核
+心会自动清理这个kobject分配的所有内存。如果为这个对象发送了 ``KOBJ_ADD``
+uevent,那么相应的 ``KOBJ_REMOVE`` uevent也将被发送,任何其他的
+sysfs内务将被正确处理。
+
+如果你需要分两次对kobject进行删除(比如说在你要销毁对象时无权睡眠),
+那么调用kobject_del()将从sysfs中取消kobject的注册。这使得kobject
+“不可见”,但它并没有被清理掉,而且该对象的引用计数仍然是一样的。在稍
+后的时间调用kobject_put()来完成与该kobject相关的内存的清理。
+
+kobject_del()可以用来放弃对父对象的引用,如果循环引用被构建的话。
+在某些情况下,一个父对象引用一个子对象是有效的。循环引用必须通过明
+确调用kobject_del()来打断,这样一个释放函数就会被调用,前一个循环
+中的对象会相互释放。
+
+
+示例代码出处
+============
+
+关于正确使用ksets和kobjects的更完整的例子,请参见示例程序
+``samples/kobject/{kobject-example.c,kset-example.c}`` ,如果
+您选择 ``CONFIG_SAMPLE_KOBJECT`` ,它们将被构建为可加载模块。
diff --git a/Documentation/translations/zh_CN/core-api/local_ops.rst b/Documentation/translations/zh_CN/core-api/local_ops.rst
new file mode 100644 (file)
index 0000000..ee67379
--- /dev/null
@@ -0,0 +1,194 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/local_ops.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_local_ops:
+
+
+========================
+本地原子操作的语义和行为
+========================
+
+:作者: Mathieu Desnoyers
+
+
+本文解释了本地原子操作的目的,如何为任何给定的架构实现这些操作,并说明了
+如何正确使用这些操作。它还强调了在内存写入顺序很重要的情况下,跨CPU读取
+这些本地变量时必须采取的预防措施。
+
+.. note::
+
+    注意,基于 ``local_t`` 的操作不建议用于一般内核操作。请使用 ``this_cpu``
+    操作来代替使用,除非真的有特殊目的。大多数内核中使用的 ``local_t`` 已
+    经被 ``this_cpu`` 操作所取代。 ``this_cpu`` 操作在一条指令中结合了重
+    定位和类似 ``local_t`` 的语义,产生了更紧凑和更快的执行代码。
+
+
+本地原子操作的目的
+==================
+
+本地原子操作的目的是提供快速和高度可重入的每CPU计数器。它们通过移除LOCK前
+缀和通常需要在CPU间同步的内存屏障,将标准原子操作的性能成本降到最低。
+
+在许多情况下,拥有快速的每CPU原子计数器是很有吸引力的:它不需要禁用中断来保护中
+断处理程序,它允许在NMI(Non Maskable Interrupt)处理程序中使用连贯的计数器。
+它对追踪目的和各种性能监测计数器特别有用。
+
+本地原子操作只保证在拥有数据的CPU上的变量修改的原子性。因此,必须注意确保只
+有一个CPU写到 ``local_t`` 的数据。这是通过使用每CPU的数据来实现的,并确
+保我们在一个抢占式安全上下文中修改它。然而,从任何一个CPU读取 ``local_t``
+数据都是允许的:这样它就会显得与所有者CPU的其他内存写入顺序不一致。
+
+
+针对特定架构的实现
+==================
+
+这可以通过稍微修改标准的原子操作来实现:只有它们的UP变体必须被保留。这通常
+意味着删除LOCK前缀(在i386和x86_64上)和任何SMP同步屏障。如果架构在SMP和
+UP之间没有不同的行为,在你的架构的 ``local.h`` 中包括 ``asm-generic/local.h``
+就足够了。
+
+通过在一个结构体中嵌入一个 ``atomic_long_t`` , ``local_t`` 类型被定义为
+一个不透明的 ``signed long`` 。这样做的目的是为了使从这个类型到
+``long`` 的转换失败。该定义看起来像::
+
+    typedef struct { atomic_long_t a; } local_t;
+
+
+使用本地原子操作时应遵循的规则
+==============================
+
+* 被本地操作触及的变量必须是每cpu的变量。
+
+* *只有* 这些变量的CPU所有者才可以写入这些变量。
+
+* 这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新
+  它的local_t变量。
+
+* 当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每
+  CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。
+
+* 当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局
+  部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占,
+  以确保它在-rt内核上仍能正确工作。
+
+* 读取本地cpu变量将提供该变量的当前拷贝。
+
+* 对这些变量的读取可以从任何CPU进行,因为对 “ ``long`` ”,对齐的变量的更新
+  总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 *其他* cpu的变
+  量时,可以读取该变量的过期副本。
+
+
+如何使用本地原子操作
+====================
+
+::
+
+    #include <linux/percpu.h>
+    #include <asm/local.h>
+
+    static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+
+计数器
+======
+
+计数是在一个signed long的所有位上进行的。
+
+在可抢占的上下文中,围绕本地原子操作使用 ``get_cpu_var()`` 和
+``put_cpu_var()`` :它确保在对每个cpu变量进行写访问时,抢占被禁用。比如
+说::
+
+    local_inc(&get_cpu_var(counters));
+    put_cpu_var(counters);
+
+如果你已经在一个抢占安全上下文中,你可以使用 ``this_cpu_ptr()`` 代替::
+
+    local_inc(this_cpu_ptr(&counters));
+
+
+
+读取计数器
+==========
+
+那些本地计数器可以从外部的CPU中读取,以求得计数的总和。请注意,local_read
+所看到的跨CPU的数据必须被认为是相对于拥有该数据的CPU上发生的其他内存写入来
+说不符合顺序的::
+
+    long sum = 0;
+    for_each_online_cpu(cpu)
+            sum += local_read(&per_cpu(counters, cpu));
+
+如果你想使用远程local_read来同步CPU之间对资源的访问,必须在写入者和读取者
+的CPU上分别使用显式的 ``smp_wmb()`` 和 ``smp_rmb()`` 内存屏障。如果你使
+用 ``local_t`` 变量作为写在缓冲区中的字节的计数器,就会出现这种情况:在缓
+冲区写和计数器增量之间应该有一个 ``smp_wmb()`` ,在计数器读和缓冲区读之间
+也应有一个 ``smp_rmb()`` 。
+
+下面是一个使用 ``local.h`` 实现每个cpu基本计数器的示例模块::
+
+    /* test-local.c
+     *
+     * Sample module for local.h usage.
+     */
+
+
+    #include <asm/local.h>
+    #include <linux/module.h>
+    #include <linux/timer.h>
+
+    static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+    static struct timer_list test_timer;
+
+    /* IPI called on each CPU. */
+    static void test_each(void *info)
+    {
+            /* Increment the counter from a non preemptible context */
+            printk("Increment on cpu %d\n", smp_processor_id());
+            local_inc(this_cpu_ptr(&counters));
+
+            /* This is what incrementing the variable would look like within a
+             * preemptible context (it disables preemption) :
+             *
+             * local_inc(&get_cpu_var(counters));
+             * put_cpu_var(counters);
+             */
+    }
+
+    static void do_test_timer(unsigned long data)
+    {
+            int cpu;
+
+            /* Increment the counters */
+            on_each_cpu(test_each, NULL, 1);
+            /* Read all the counters */
+            printk("Counters read from CPU %d\n", smp_processor_id());
+            for_each_online_cpu(cpu) {
+                    printk("Read : CPU %d, count %ld\n", cpu,
+                            local_read(&per_cpu(counters, cpu)));
+            }
+            mod_timer(&test_timer, jiffies + 1000);
+    }
+
+    static int __init test_init(void)
+    {
+            /* initialize the timer that will increment the counter */
+            timer_setup(&test_timer, do_test_timer, 0);
+            mod_timer(&test_timer, jiffies + 1);
+
+            return 0;
+    }
+
+    static void __exit test_exit(void)
+    {
+            del_timer_sync(&test_timer);
+    }
+
+    module_init(test_init);
+    module_exit(test_exit);
+
+    MODULE_LICENSE("GPL");
+    MODULE_AUTHOR("Mathieu Desnoyers");
+    MODULE_DESCRIPTION("Local Atomic Ops");
diff --git a/Documentation/translations/zh_CN/core-api/padata.rst b/Documentation/translations/zh_CN/core-api/padata.rst
new file mode 100644 (file)
index 0000000..c627f8f
--- /dev/null
@@ -0,0 +1,158 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/padata.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_core_api_padata.rst:
+
+==================
+padata并行执行机制
+==================
+
+:日期: 2020年5月
+
+Padata是一种机制,内核可以通过此机制将工作分散到多个CPU上并行完成,同时
+可以选择保持它们的顺序。
+
+它最初是为IPsec开发的,它需要在不对这些数据包重新排序的其前提下,为大量的数
+据包进行加密和解密。这是目前padata的序列化作业支持的唯一用途。
+
+Padata还支持多线程作业,将作业平均分割,同时在线程之间进行负载均衡和协调。
+
+执行序列化作业
+==============
+
+初始化
+------
+
+使用padata执行序列化作业的第一步是建立一个padata_instance结构体,以全面
+控制作业的运行方式::
+
+    #include <linux/padata.h>
+
+    struct padata_instance *padata_alloc(const char *name);
+
+'name'即标识了这个实例。
+
+然后,通过分配一个padata_shell来完成padata的初始化::
+
+   struct padata_shell *padata_alloc_shell(struct padata_instance *pinst);
+
+一个padata_shell用于向padata提交一个作业,并允许一系列这样的作业被独立地
+序列化。一个padata_instance可以有一个或多个padata_shell与之相关联,每个
+都允许一系列独立的作业。
+
+修改cpumasks
+------------
+
+用于运行作业的CPU可以通过两种方式改变,通过padata_set_cpumask()编程或通
+过sysfs。前者的定义是::
+
+    int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
+                          cpumask_var_t cpumask);
+
+这里cpumask_type是PADATA_CPU_PARALLEL(并行)或PADATA_CPU_SERIAL(串行)之一,其中并
+行cpumask描述了哪些处理器将被用来并行执行提交给这个实例的作业,串行cpumask
+定义了哪些处理器被允许用作串行化回调处理器。 cpumask指定了要使用的新cpumask。
+
+一个实例的cpumasks可能有sysfs文件。例如,pcrypt的文件在
+/sys/kernel/pcrypt/<instance-name>。在一个实例的目录中,有两个文件,parallel_cpumask
+和serial_cpumask,任何一个cpumask都可以通过在文件中回显(echo)一个bitmask
+来改变,比如说::
+
+    echo f > /sys/kernel/pcrypt/pencrypt/parallel_cpumask
+
+读取其中一个文件会显示用户提供的cpumask,它可能与“可用”的cpumask不同。
+
+Padata内部维护着两对cpumask,用户提供的cpumask和“可用的”cpumask(每一对由一个
+并行和一个串行cpumask组成)。用户提供的cpumasks在实例分配时默认为所有可能的CPU,
+并且可以如上所述进行更改。可用的cpumasks总是用户提供的cpumasks的一个子集,只包
+含用户提供的掩码中的在线CPU;这些是padata实际使用的cpumasks。因此,向padata提
+供一个包含离线CPU的cpumask是合法的。一旦用户提供的cpumask中的一个离线CPU上线,
+padata就会使用它。
+
+改变CPU掩码的操作代价很高,所以不应频繁更改。
+
+运行一个作业
+-------------
+
+实际上向padata实例提交工作需要创建一个padata_priv结构体,它代表一个作业::
+
+    struct padata_priv {
+        /* Other stuff here... */
+       void                    (*parallel)(struct padata_priv *padata);
+       void                    (*serial)(struct padata_priv *padata);
+    };
+
+这个结构体几乎肯定会被嵌入到一些针对要做的工作的大结构体中。它的大部分字段对
+padata来说是私有的,但是这个结构在初始化时应该被清零,并且应该提供parallel()和
+serial()函数。在完成工作的过程中,这些函数将被调用,我们马上就会遇到。
+
+工作的提交是通过::
+
+    int padata_do_parallel(struct padata_shell *ps,
+                          struct padata_priv *padata, int *cb_cpu);
+
+ps和padata结构体必须如上所述进行设置;cb_cpu指向作业完成后用于最终回调的首选CPU;
+它必须在当前实例的CPU掩码中(如果不是,cb_cpu指针将被更新为指向实际选择的CPU)。
+padata_do_parallel()的返回值在成功时为0,表示工作正在进行中。-EBUSY意味着有人
+在其他地方正在搞乱实例的CPU掩码,而当cb_cpu不在串行cpumask中、并行或串行cpumasks
+中无在线CPU,或实例停止时,则会出现-EINVAL反馈。
+
+每个提交给padata_do_parallel()的作业将依次传递给一个CPU上的上述parallel()函数
+的一个调用,所以真正的并行是通过提交多个作业来实现的。parallel()在运行时禁用软
+件中断,因此不能睡眠。parallel()函数把获得的padata_priv结构体指针作为其唯一的参
+数;关于实际要做的工作的信息可能是通过使用container_of()找到封装结构体来获得的。
+
+请注意,parallel()没有返回值;padata子系统假定parallel()将从此时开始负责这项工
+作。作业不需要在这次调用中完成,但是,如果parallel()留下了未完成的工作,它应该准
+备在前一个作业完成之前,被以新的作业再次调用
+
+序列化作业
+----------
+
+当一个作业完成时,parallel()(或任何实际完成该工作的函数)应该通过调用通知padata此
+事::
+
+    void padata_do_serial(struct padata_priv *padata);
+
+在未来的某个时刻,padata_do_serial()将触发对padata_priv结构体中serial()函数的调
+用。这个调用将发生在最初要求调用padata_do_parallel()的CPU上;它也是在本地软件中断
+被禁用的情况下运行的。
+请注意,这个调用可能会被推迟一段时间,因为padata代码会努力确保作业按照提交的顺序完
+成。
+
+销毁
+----
+
+清理一个padata实例时,可以预见的是调用两个free函数,这两个函数对应于分配的逆过程::
+
+    void padata_free_shell(struct padata_shell *ps);
+    void padata_free(struct padata_instance *pinst);
+
+用户有责任确保在调用上述任何一项之前,所有未完成的工作都已完成。
+
+运行多线程作业
+==============
+
+一个多线程作业有一个主线程和零个或多个辅助线程,主线程参与作业,然后等待所有辅助线
+程完成。padata将作业分割成称为chunk的单元,其中chunk是一个线程在一次调用线程函数
+中完成的作业片段。
+
+用户必须做三件事来运行一个多线程作业。首先,通过定义一个padata_mt_job结构体来描述
+作业,这在接口部分有解释。这包括一个指向线程函数的指针,padata每次将作业块分配给线
+程时都会调用这个函数。然后,定义线程函数,它接受三个参数: ``start`` 、 ``end`` 和 ``arg`` ,
+其中前两个参数限定了线程操作的范围,最后一个是指向作业共享状态的指针,如果有的话。
+准备好共享状态,它通常被分配在主线程的堆栈中。最后,调用padata_do_multithreaded(),
+它将在作业完成后返回。
+
+接口
+====
+
+该API在以下内核代码中:
+
+include/linux/padata.h
+
+kernel/padata.c
diff --git a/Documentation/translations/zh_CN/core-api/printk-basics.rst b/Documentation/translations/zh_CN/core-api/printk-basics.rst
new file mode 100644 (file)
index 0000000..2b20f63
--- /dev/null
@@ -0,0 +1,110 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/printk-basics.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_printk-basics.rst:
+
+
+==================
+使用printk记录消息
+==================
+
+printk()是Linux内核中最广为人知的函数之一。它是我们打印消息的标准工具,通常也是追踪和调试
+的最基本方法。如果你熟悉printf(3),你就能够知道printk()是基于它的,尽管它在功能上有一些不
+同之处:
+
+  - printk() 消息可以指定日志级别。
+
+  - 格式字符串虽然与C99基本兼容,但并不遵循完全相同的规范。它有一些扩展和一些限制(没
+    有 ``%n`` 或浮点转换指定符)。参见:ref: `如何正确地获得printk格式指定符<printk-specifiers>` 。
+
+所有的printk()消息都会被打印到内核日志缓冲区,这是一个通过/dev/kmsg输出到用户空间的环
+形缓冲区。读取它的通常方法是使用 ``dmesg`` 。
+
+printk()的用法通常是这样的::
+
+  printk(KERN_INFO "Message: %s\n", arg);
+
+其中 ``KERN_INFO`` 是日志级别(注意,它与格式字符串连在一起,日志级别不是一个单独的参数)。
+可用的日志级别是:
+
+
++----------------+--------+-----------------------------------------------+
+| 名称           | 字符串 |  别名函数                                     |
++================+========+===============================================+
+| KERN_EMERG     | "0"    | pr_emerg()                                    |
++----------------+--------+-----------------------------------------------+
+| KERN_ALERT     | "1"    | pr_alert()                                    |
++----------------+--------+-----------------------------------------------+
+| KERN_CRIT      | "2"    | pr_crit()                                     |
++----------------+--------+-----------------------------------------------+
+| KERN_ERR       | "3"    | pr_err()                                      |
++----------------+--------+-----------------------------------------------+
+| KERN_WARNING   | "4"    | pr_warn()                                     |
++----------------+--------+-----------------------------------------------+
+| KERN_NOTICE    | "5"    | pr_notice()                                   |
++----------------+--------+-----------------------------------------------+
+| KERN_INFO      | "6"    | pr_info()                                     |
++----------------+--------+-----------------------------------------------+
+| KERN_DEBUG     | "7"    | pr_debug() and pr_devel()  若定义了DEBUG      |
++----------------+--------+-----------------------------------------------+
+| KERN_DEFAULT   | ""     |                                               |
++----------------+--------+-----------------------------------------------+
+| KERN_CONT      | "c"    | pr_cont()                                     |
++----------------+--------+-----------------------------------------------+
+
+
+日志级别指定了一条消息的重要性。内核根据日志级别和当前 *console_loglevel* (一个内核变量)决
+定是否立即显示消息(将其打印到当前控制台)。如果消息的优先级比 *console_loglevel* 高(日志级
+别值较低),消息将被打印到控制台。
+
+如果省略了日志级别,则以 ``KERN_DEFAULT`` 级别打印消息。
+
+你可以用以下方法检查当前的 *console_loglevel* ::
+
+  $ cat /proc/sys/kernel/printk
+  4        4        1        7
+
+结果显示了 *current*, *default*, *minimum* 和 *boot-time-default* 日志级别
+
+要改变当前的 console_loglevel,只需在 ``/proc/sys/kernel/printk`` 中写入所需的
+级别。例如,要打印所有的消息到控制台上::
+
+  # echo 8 > /proc/sys/kernel/printk
+
+另一种方式,使用 ``dmesg``::
+
+  # dmesg -n 5
+
+设置 console_loglevel 打印 KERN_WARNING (4) 或更严重的消息到控制台。更多消息参
+见 ``dmesg(1)`` 。
+
+作为printk()的替代方案,你可以使用 ``pr_*()`` 别名来记录日志。这个系列的宏在宏名中
+嵌入了日志级别。例如::
+
+  pr_info("Info message no. %d\n", msg_num);
+
+打印 ``KERN_INFO`` 消息。
+
+除了比等效的printk()调用更简洁之外,它们还可以通过pr_fmt()宏为格式字符串使用一个通用
+的定义。例如,在源文件的顶部(在任何  ``#include`` 指令之前)定义这样的内容。::
+
+  #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+会在该文件中的每一条 pr_*() 消息前加上发起该消息的模块和函数名称。
+
+为了调试,还有两个有条件编译的宏:
+pr_debug()和pr_devel(),除非定义了 ``DEBUG`` (或者在pr_debug()的情况下定义了
+``CONFIG_DYNAMIC_DEBUG`` ),否则它们会被编译。
+
+
+函数接口
+========
+
+该API在以下内核代码中:
+
+kernel/printk/printk.c
+
+include/linux/printk.h
diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst
new file mode 100644 (file)
index 0000000..a680c8f
--- /dev/null
@@ -0,0 +1,595 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/printk-formats.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_printk-formats.rst:
+
+
+==============================
+如何获得正确的printk格式占位符
+==============================
+
+
+
+:作者: Randy Dunlap <rdunlap@infradead.org>
+:作者: Andrew Murray <amurray@mpc-data.co.uk>
+
+
+整数类型
+========
+
+::
+
+               若变量类型是Type,则使用printk格式占位符。
+               -------------------------------------------
+               char                    %d 或 %x
+               unsigned char           %u 或 %x
+               short int               %d 或 %x
+               unsigned short int      %u 或 %x
+               int                     %d 或 %x
+               unsigned int            %u 或 %x
+               long                    %ld 或 %lx
+               unsigned long           %lu 或 %lx
+               long long               %lld 或 %llx
+               unsigned long long      %llu 或 %llx
+               size_t                  %zu 或 %zx
+               ssize_t                 %zd 或 %zx
+               s8                      %d 或 %x
+               u8                      %u 或 %x
+               s16                     %d 或 %x
+               u16                     %u 或 %x
+               s32                     %d 或 %x
+               u32                     %u 或 %x
+               s64                     %lld 或 %llx
+               u64                     %llu 或 %llx
+
+
+如果 <type> 的大小依赖于配置选项 (例如 sector_t, blkcnt_t) 或其大小依赖于架构
+(例如 tcflag_t),则使用其可能的最大类型的格式占位符并显式强制转换为它。
+
+例如
+
+::
+
+       printk("test: sector number/total blocks: %llu/%llu\n",
+               (unsigned long long)sector, (unsigned long long)blockcount);
+
+提醒:sizeof()返回类型为size_t。
+
+内核的printf不支持%n。显而易见,浮点格式(%e, %f, %g, %a)也不被识别。使用任何不
+支持的占位符或长度限定符都会导致一个WARN并且终止vsnprintf()执行。
+
+指针类型
+========
+
+一个原始指针值可以用%p打印,它将在打印前对地址进行哈希处理。内核也支持扩展占位符来打印
+不同类型的指针。
+
+一些扩展占位符会打印给定地址上的数据,而不是打印地址本身。在这种情况下,以下错误消息可能
+会被打印出来,而不是无法访问的消息::
+
+       (null)   data on plain NULL address
+       (efault) data on invalid address
+       (einval) invalid data on a valid address
+
+普通指针
+----------
+
+::
+
+       %p      abcdef12 or 00000000abcdef12
+
+没有指定扩展名的指针(即没有修饰符的%p)被哈希(hash),以防止内核内存布局消息的泄露。这
+样还有一个额外的好处,就是提供一个唯一的标识符。在64位机器上,前32位被清零。当没有足够的
+熵进行散列处理时,内核将打印(ptrval)代替
+
+如果可能的话,使用专门的修饰符,如%pS或%pB(如下所述),以避免打印一个必须事后解释的非哈
+希地址。如果不可能,而且打印地址的目的是为调试提供更多的消息,使用%p,并在调试过程中
+用 ``no_hash_pointers`` 参数启动内核,这将打印所有未修改的%p地址。如果你 *真的* 想知
+道未修改的地址,请看下面的%px。
+
+如果(也只有在)你将地址作为虚拟文件的内容打印出来,例如在procfs或sysfs中(使用
+seq_printf(),而不是printk())由用户空间进程读取,使用下面描述的%pK修饰符,不
+要用%p或%px。
+
+
+错误指针
+--------
+
+::
+
+       %pe     -ENOSPC
+
+用于打印错误指针(即IS_ERR()为真的指针)的符号错误名。不知道符号名的错误值会以十进制打印,
+而作为%pe参数传递的非ERR_PTR会被视为普通的%p。
+
+符号/函数指针
+-------------
+
+::
+
+       %pS     versatile_init+0x0/0x110
+       %ps     versatile_init
+       %pSR    versatile_init+0x9/0x110
+               (with __builtin_extract_return_addr() translation)
+       %pB     prev_fn_of_versatile_init+0x88/0x88
+
+
+``S`` 和 ``s`` 占位符用于打印符号格式的指针。它们的结果是符号名称带有(S)或不带有(s)偏移
+量。如果禁用KALLSYMS,则打印符号地址。
+
+``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化
+的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。
+
+如果指针在一个模块内,模块名称和可选的构建ID将被打印在符号名称之后,并在说明符的末尾添加
+一个额外的 ``b`` 。
+
+::
+
+       %pS     versatile_init+0x0/0x110 [module_name]
+       %pSb    versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+       %pSRb   versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+               (with __builtin_extract_return_addr() translation)
+       %pBb    prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
+
+来自BPF / tracing追踪的探查指针
+----------------------------------
+
+::
+
+       %pks    kernel string
+       %pus    user string
+
+``k`` 和 ``u`` 指定符用于打印来自内核内存(k)或用户内存(u)的先前探测的内存。后面的 ``s`` 指
+定符的结果是打印一个字符串。对于直接在常规的vsnprintf()中使用时,(k)和(u)注释被忽略,但是,当
+在BPF的bpf_trace_printk()之外使用时,它会读取它所指向的内存,不会出现错误。
+
+内核指针
+--------
+
+::
+
+       %pK     01234567 or 0123456789abcdef
+
+用于打印应该对非特权用户隐藏的内核指针。%pK的行为取决于kptr_restrict sysctl——详见
+Documentation/admin-guide/sysctl/kernel.rst。
+
+未经修改的地址
+--------------
+
+::
+
+       %px     01234567 or 0123456789abcdef
+
+对于打印指针,当你 *真的* 想打印地址时。在用%px打印指针之前,请考虑你是否泄露了内核内
+存布局的敏感消息。%px在功能上等同于%lx(或%lu)。%px是首选,因为它在grep查找时更唯一。
+如果将来我们需要修改内核处理打印指针的方式,我们将能更好地找到调用点。
+
+在使用%px之前,请考虑使用%p并在调试过程中启用' ' no_hash_pointer ' '内核参数是否足
+够(参见上面的%p描述)。%px的一个有效场景可能是在panic发生之前立即打印消息,这样无论如何
+都可以防止任何敏感消息被利用,使用%px就不需要用no_hash_pointer来重现panic。
+
+指针差异
+--------
+
+::
+
+       %td     2560
+       %tx     a00
+
+为了打印指针的差异,使用ptrdiff_t的%t修饰符。
+
+例如::
+
+       printk("test: difference between pointers: %td\n", ptr2 - ptr1);
+
+结构体资源(Resources)
+-----------------------
+
+::
+
+       %pr     [mem 0x60000000-0x6fffffff flags 0x2200] or
+               [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
+       %pR     [mem 0x60000000-0x6fffffff pref] or
+               [mem 0x0000000060000000-0x000000006fffffff pref]
+
+用于打印结构体资源。 ``R`` 和 ``r`` 占位符的结果是打印出的资源带有(R)或不带有(r)解码标志
+成员。
+
+通过引用传递。
+
+物理地址类型 phys_addr_t
+------------------------
+
+::
+
+       %pa[p]  0x01234567 or 0x0123456789abcdef
+
+用于打印phys_addr_t类型(以及它的衍生物,如resource_size_t),该类型可以根据构建选项而
+变化,无论CPU数据真实物理地址宽度如何。
+
+通过引用传递。
+
+DMA地址类型dma_addr_t
+---------------------
+
+::
+
+       %pad    0x01234567 or 0x0123456789abcdef
+
+用于打印dma_addr_t类型,该类型可以根据构建选项而变化,而不考虑CPU数据路径的宽度。
+
+通过引用传递。
+
+原始缓冲区为转义字符串
+----------------------
+
+::
+
+       %*pE[achnops]
+
+用于将原始缓冲区打印成转义字符串。对于以下缓冲区::
+
+               1b 62 20 5c 43 07 22 90 0d 5d
+
+几个例子展示了如何进行转换(不包括两端的引号)。::
+
+               %*pE            "\eb \C\a"\220\r]"
+               %*pEhp          "\x1bb \C\x07"\x90\x0d]"
+               %*pEa           "\e\142\040\\\103\a\042\220\r\135"
+
+转换规则是根据可选的标志组合来应用的(详见:c:func:`string_escape_mem` 内核文档):
+
+       - a - ESCAPE_ANY
+       - c - ESCAPE_SPECIAL
+       - h - ESCAPE_HEX
+       - n - ESCAPE_NULL
+       - o - ESCAPE_OCTAL
+       - p - ESCAPE_NP
+       - s - ESCAPE_SPACE
+
+默认情况下,使用 ESCAPE_ANY_NP。
+
+ESCAPE_ANY_NP是许多情况下的明智选择,特别是对于打印SSID。
+
+如果字段宽度被省略,那么将只转义1个字节。
+
+原始缓冲区为十六进制字符串
+--------------------------
+
+::
+
+       %*ph    00 01 02  ...  3f
+       %*phC   00:01:02: ... :3f
+       %*phD   00-01-02- ... -3f
+       %*phN   000102 ... 3f
+
+对于打印小的缓冲区(最长64个字节),可以用一定的分隔符作为一个
+十六进制字符串。对于较大的缓冲区,可以考虑使用
+:c:func:`print_hex_dump` 。
+
+MAC/FDDI地址
+------------
+
+::
+
+       %pM     00:01:02:03:04:05
+       %pMR    05:04:03:02:01:00
+       %pMF    00-01-02-03-04-05
+       %pm     000102030405
+       %pmR    050403020100
+
+用于打印以十六进制表示的6字节MAC/FDDI地址。 ``M`` 和 ``m`` 占位符导致打印的
+地址有(M)或没有(m)字节分隔符。默认的字节分隔符是冒号(:)。
+
+对于FDDI地址,可以在 ``M`` 占位符之后使用 ``F`` 说明,以使用破折号(——)分隔符
+代替默认的分隔符。
+
+对于蓝牙地址, ``R`` 占位符应使用在 ``M`` 占位符之后,以使用反转的字节顺序,适
+合于以小尾端顺序的蓝牙地址的肉眼可见的解析。
+
+通过引用传递。
+
+IPv4地址
+--------
+
+::
+
+       %pI4    1.2.3.4
+       %pi4    001.002.003.004
+       %p[Ii]4[hnbl]
+
+用于打印IPv4点分隔的十进制地址。 ``I4`` 和 ``i4`` 占位符的结果是打印的地址
+有(i4)或没有(I4)前导零。
+
+附加的 ``h`` 、 ``n`` 、 ``b`` 和 ``l`` 占位符分别用于指定主机、网络、大
+尾端或小尾端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。
+
+通过引用传递。
+
+IPv6 地址
+---------
+
+::
+
+       %pI6    0001:0002:0003:0004:0005:0006:0007:0008
+       %pi6    00010002000300040005000600070008
+       %pI6c   1:2:3:4:5:6:7:8
+
+用于打印IPv6网络顺序的16位十六进制地址。 ``I6`` 和 ``i6`` 占位符的结果是
+打印的地址有(I6)或没有(i6)分号。始终使用前导零。
+
+额外的 ``c`` 占位符可与 ``I`` 占位符一起使用,以打印压缩的IPv6地址,如
+https://tools.ietf.org/html/rfc5952 所述
+
+通过引用传递。
+
+IPv4/IPv6地址(generic, with port, flowinfo, scope)
+--------------------------------------------------
+
+::
+
+       %pIS    1.2.3.4         or 0001:0002:0003:0004:0005:0006:0007:0008
+       %piS    001.002.003.004 or 00010002000300040005000600070008
+       %pISc   1.2.3.4         or 1:2:3:4:5:6:7:8
+       %pISpc  1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345
+       %p[Ii]S[pfschnbl]
+
+用于打印一个IP地址,不需要区分它的类型是AF_INET还是AF_INET6。一个指向有效结构
+体sockaddr的指针,通过 ``IS`` 或 ``IS`` 指定,可以传递给这个格式占位符。
+
+附加的 ``p`` 、  ``f`` 和 ``s`` 占位符用于指定port(IPv4, IPv6)、
+flowinfo (IPv6)和sope(IPv6)。port有一个 ``:`` 前缀,flowinfo是 ``/`` 和
+范围是 ``%`` ,每个后面都跟着实际的值。
+
+对于IPv6地址,如果指定了额外的指定符 ``c`` ,则使用
+https://tools.ietf.org/html/rfc5952 描述的压缩IPv6地址。
+如https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
+所建议的,IPv6地址由'[',']'包围,以防止出现额外的占位符 ``p`` , ``f`` 或 ``s`` 。
+
+对于IPv4地址,也可以使用额外的 ``h`` , ``n`` , ``b`` 和 ``l`` 说
+明符,但对于IPv6地址则忽略。
+
+通过引用传递。
+
+更多例子::
+
+       %pISfc          1.2.3.4         or [1:2:3:4:5:6:7:8]/123456789
+       %pISsc          1.2.3.4         or [1:2:3:4:5:6:7:8]%1234567890
+       %pISpfc         1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345/123456789
+
+UUID/GUID地址
+-------------
+
+::
+
+       %pUb    00010203-0405-0607-0809-0a0b0c0d0e0f
+       %pUB    00010203-0405-0607-0809-0A0B0C0D0E0F
+       %pUl    03020100-0504-0706-0809-0a0b0c0e0e0f
+       %pUL    03020100-0504-0706-0809-0A0B0C0E0E0F
+
+用于打印16字节的UUID/GUIDs地址。附加的 ``l`` , ``L`` , ``b`` 和 ``B`` 占位符用
+于指定小写(l)或大写(L)十六进制表示法中的小尾端顺序,以及小写(b)或大写(B)十六进制表
+示法中的大尾端顺序。
+
+如果没有使用额外的占位符,则将打印带有小写十六进制表示法的默认大端顺序。
+
+通过引用传递。
+
+目录项(dentry)的名称
+----------------------
+
+::
+
+       %pd{,2,3,4}
+       %pD{,2,3,4}
+
+用于打印dentry名称;如果我们用 :c:func:`d_move` 和它比较,名称可能是新旧混合的,但
+不会oops。 %pd dentry比较安全,其相当于我们以前用的%s dentry->d_name.name,%pd<n>打
+印 ``n`` 最后的组件。 %pD对结构文件做同样的事情。
+
+
+通过引用传递。
+
+块设备(block_device)名称
+--------------------------
+
+::
+
+       %pg     sda, sda1 or loop0p1
+
+用于打印block_device指针的名称。
+
+va_format结构体
+---------------
+
+::
+
+       %pV
+
+用于打印结构体va_format。这些结构包含一个格式字符串
+和va_list如下
+
+::
+
+       struct va_format {
+               const char *fmt;
+               va_list *va;
+       };
+
+实现 "递归vsnprintf"。
+
+如果没有一些机制来验证格式字符串和va_list参数的正确性,请不要使用这个功能。
+
+通过引用传递。
+
+设备树节点
+----------
+
+::
+
+       %pOF[fnpPcCF]
+
+
+用于打印设备树节点结构。默认行为相当于%pOFf。
+
+       - f - 设备节点全称
+       - n - 设备节点名
+       - p - 设备节点句柄
+       - P - 设备节点路径规范(名称+@单位)
+       - F - 设备节点标志
+       - c - 主要兼容字符串
+       - C - 全兼容字符串
+
+当使用多个参数时,分隔符是':'。
+
+例如
+
+::
+
+       %pOF    /foo/bar@0                      - Node full name
+       %pOFf   /foo/bar@0                      - Same as above
+       %pOFfp  /foo/bar@0:10                   - Node full name + phandle
+       %pOFfcF /foo/bar@0:foo,device:--P-      - Node full name +
+                                                 major compatible string +
+                                                 node flags
+                                                       D - dynamic
+                                                       d - detached
+                                                       P - Populated
+                                                       B - Populated bus
+
+通过引用传递。
+
+Fwnode handles
+--------------
+
+::
+
+       %pfw[fP]
+
+用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。
+这些修饰符在功能上等同于上面的%pOF。
+
+       - f - 节点的全名,包括路径。
+       - P - 节点名称,包括地址(如果有的话)。
+
+例如 (ACPI)
+
+::
+
+       %pfwf   \_SB.PCI0.CIO2.port@1.endpoint@0        - Full node name
+       %pfwP   endpoint@0                              - Node name
+
+例如 (OF)
+
+::
+
+       %pfwf   /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
+       %pfwP   endpoint                                - Node name
+
+时间和日期
+----------
+
+::
+
+       %pt[RT]                 YYYY-mm-ddTHH:MM:SS
+       %pt[RT]s                YYYY-mm-dd HH:MM:SS
+       %pt[RT]d                YYYY-mm-dd
+       %pt[RT]t                HH:MM:SS
+       %pt[RT][dt][r][s]
+
+用于打印日期和时间::
+
+       R  struct rtc_time structure
+       T  time64_t type
+
+以我们(人类)可读的格式。
+
+默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw)
+来抑制这种行为。
+
+%pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用''(空格)而
+不是'T'(大写T)。当日期或时间被省略时,它不会有任何影响。
+
+通过引用传递。
+
+clk结构体
+---------
+
+::
+
+       %pC     pll1
+       %pCn    pll1
+
+用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位
+ID(传统时钟框架)。
+
+通过引用传递。
+
+位图及其衍生物,如cpumask和nodemask
+-----------------------------------
+
+::
+
+       %*pb    0779
+       %*pbl   0,3-6,8-10
+
+对于打印位图(bitmap)及其派生的cpumask和nodemask,%*pb输出以字段宽度为位数的位图,
+%*pbl输出以字段宽度为位数的范围列表。
+
+字段宽度用值传递,位图用引用传递。可以使用辅助宏cpumask_pr_args()和
+nodemask_pr_args()来方便打印cpumask和nodemask。
+
+标志位字段,如页标志、gfp_flags
+-------------------------------
+
+::
+
+       %pGp    referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff
+       %pGg    GFP_USER|GFP_DMA32|GFP_NOWARN
+       %pGv    read|exec|mayread|maywrite|mayexec|denywrite
+
+将flags位字段打印为构造值的符号常量集合。标志的类型由第三个字符给出。目前支持的
+是[p]age flags, [v]ma_flags(都期望 ``unsigned long *`` )和
+[g]fp_flags(期望 ``gfp_t *`` )。标志名称和打印顺序取决于特定的类型。
+
+注意,这种格式不应该直接用于跟踪点的:c:func:`TP_printk()` 部分。相反,应使
+用 <trace/events/mmflags.h>中的show_*_flags()函数。
+
+通过引用传递。
+
+网络设备特性
+------------
+
+::
+
+       %pNF    0x000000000000c000
+
+用于打印netdev_features_t。
+
+通过引用传递。
+
+V4L2和DRM FourCC代码(像素格式)
+------------------------------
+
+::
+
+       %p4cc
+
+打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值。
+
+通过引用传递。
+
+例如::
+
+       %p4cc   BG12 little-endian (0x32314742)
+       %p4cc   Y10  little-endian (0x20303159)
+       %p4cc   NV12 big-endian (0xb231564e)
+
+谢谢
+====
+
+如果您添加了其他%p扩展,请在可行的情况下,用一个或多个测试用例扩展<lib/test_printf.c>。
+
+谢谢你的合作和关注。
diff --git a/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst
new file mode 100644 (file)
index 0000000..ea834e3
--- /dev/null
@@ -0,0 +1,154 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/refcount-vs-atomic.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_refcount-vs-atomic:
+
+
+=======================================
+与atomic_t相比,refcount_t的API是这样的
+=======================================
+
+.. contents:: :local:
+
+简介
+====
+
+refcount_t API的目标是为实现对象的引用计数器提供一个最小的API。虽然来自
+lib/refcount.c的独立于架构的通用实现在下面使用了原子操作,但一些 ``refcount_*()``
+和 ``atomic_*()`` 函数在内存顺序保证方面有很多不同。本文档概述了这些差异,并
+提供了相应的例子,以帮助开发者根据这些内存顺序保证的变化来验证他们的代码。
+
+本文档中使用的术语尽量遵循tools/memory-model/Documentation/explanation.txt
+中定义的正式LKMM。
+
+memory-barriers.txt和atomic_t.txt提供了更多关于内存顺序的背景,包括通用的
+和针对原子操作的。
+
+内存顺序的相关类型
+==================
+
+.. note:: 下面的部分只涵盖了本文使用的与原子操作和引用计数器有关的一些内存顺
+   序类型。如果想了解更广泛的情况,请查阅memory-barriers.txt文件。
+
+在没有任何内存顺序保证的情况下(即完全无序),atomics和refcounters只提供原
+子性和程序顺序(program order, po)关系(在同一个CPU上)。它保证每个
+``atomic_* ()`` 和 ``refcount_*()`` 操作都是原子性的,指令在单个CPU上按程序
+顺序执行。这是用READ_ONCE()/WRITE_ONCE()和比较并交换原语实现的。
+
+强(完全)内存顺序保证在同一CPU上的所有较早加载和存储的指令(所有程序顺序较早
+[po-earlier]指令)在执行任何程序顺序较后指令(po-later)之前完成。它还保证
+同一CPU上储存的程序优先较早的指令和来自其他CPU传播的指令必须在该CPU执行任何
+程序顺序较后指令之前传播到其他CPU(A-累积属性)。这是用smp_mb()实现的。
+
+RELEASE内存顺序保证了在同一CPU上所有较早加载和存储的指令(所有程序顺序较早
+指令)在此操作前完成。它还保证同一CPU上储存的程序优先较早的指令和来自其他CPU
+传播的指令必须在释放(release)操作之前传播到所有其他CPU(A-累积属性)。这是用
+smp_store_release()实现的。
+
+ACQUIRE内存顺序保证了同一CPU上的所有后加载和存储的指令(所有程序顺序较后
+指令)在获取(acquire)操作之后完成。它还保证在获取操作执行后,同一CPU上
+储存的所有程序顺序较后指令必须传播到所有其他CPU。这是用
+smp_acquire__after_ctrl_dep()实现的。
+
+对Refcounters的控制依赖(取决于成功)保证了如果一个对象的引用被成功获得(引用计数
+器的增量或增加行为发生了,函数返回true),那么进一步的存储是针对这个操作的命令。对存
+储的控制依赖没有使用任何明确的屏障来实现,而是依赖于CPU不对存储进行猜测。这只是
+一个单一的CPU关系,对其他CPU不提供任何保证。
+
+
+函数的比较
+==========
+
+情况1) - 非 “读/修改/写”(RMW)操作
+------------------------------------
+
+函数变化:
+
+ * atomic_set() --> refcount_set()
+ * atomic_read() --> refcount_read()
+
+内存顺序保证变化:
+
+ * none (两者都是完全无序的)
+
+
+情况2) - 基于增量的操作,不返回任何值
+--------------------------------------
+
+函数变化:
+
+ * atomic_inc() --> refcount_inc()
+ * atomic_add() --> refcount_add()
+
+内存顺序保证变化:
+
+ * none (两者都是完全无序的)
+
+情况3) - 基于递减的RMW操作,没有返回值
+---------------------------------------
+
+函数变化:
+
+ * atomic_dec() --> refcount_dec()
+
+内存顺序保证变化:
+
+ * 完全无序的 --> RELEASE顺序
+
+
+情况4) - 基于增量的RMW操作,返回一个值
+---------------------------------------
+
+函数变化:
+
+ * atomic_inc_not_zero() --> refcount_inc_not_zero()
+ * 无原子性对应函数 --> refcount_add_not_zero()
+
+内存顺序保证变化:
+
+ * 完全有序的 --> 控制依赖于存储的成功
+
+.. note:: 此处 **假设** 了,必要的顺序是作为获得对象指针的结果而提供的。
+
+
+情况 5) - 基于Dec/Sub递减的通用RMW操作,返回一个值
+---------------------------------------------------
+
+函数变化:
+
+ * atomic_dec_and_test() --> refcount_dec_and_test()
+ * atomic_sub_and_test() --> refcount_sub_and_test()
+
+内存顺序保证变化:
+
+ * 完全有序的 --> RELEASE顺序 + 成功后ACQUIRE顺序
+
+
+情况6)其他基于递减的RMW操作,返回一个值
+----------------------------------------
+
+函数变化:
+
+ * 无原子性对应函数 --> refcount_dec_if_one()
+ * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)``
+
+内存顺序保证变化:
+
+ * 完全有序的 --> RELEASE顺序 + 控制依赖
+
+.. note:: atomic_add_unless()只在执行成功时提供完整的顺序。
+
+
+情况7)--基于锁的RMW
+--------------------
+
+函数变化:
+
+ * atomic_dec_and_lock() --> refcount_dec_and_lock()
+ * atomic_dec_and_mutex_lock() --> refcount_dec_and_mutex_lock()
+
+内存顺序保证变化:
+
+ * 完全有序 --> RELEASE顺序 + 控制依赖 + 持有
diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
new file mode 100644 (file)
index 0000000..ce05c29
--- /dev/null
@@ -0,0 +1,142 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/symbol-namespaces.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_symbol-namespaces.rst:
+
+
+=================================
+符号命名空间(Symbol Namespaces)
+=================================
+
+本文档描述了如何使用符号命名空间来构造通过EXPORT_SYMBOL()系列宏导出的内核内符号的导出面。
+
+.. 目录
+
+       === 1 简介
+       === 2 如何定义符号命名空间
+          --- 2.1 使用EXPORT_SYMBOL宏
+          --- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
+       === 3 如何使用命名空间中导出的符号
+       === 4 加载使用命名空间符号的模块
+       === 5 自动创建MODULE_IMPORT_NS声明
+
+1. 简介
+=======
+
+符号命名空间已经被引入,作为构造内核内API的导出面的一种手段。它允许子系统维护者将
+他们导出的符号划分进独立的命名空间。这对于文档的编写非常有用(想想SUBSYSTEM_DEBUG
+命名空间),也可以限制一组符号在内核其他部分的使用。今后,使用导出到命名空间的符号
+的模块必须导入命名空间。否则,内核将根据其配置,拒绝加载该模块或警告说缺少
+导入。
+
+2. 如何定义符号命名空间
+=======================
+
+符号可以用不同的方法导出到命名空间。所有这些都在改变 EXPORT_SYMBOL 和与之类似的那些宏
+被检测到的方式,以创建 ksymtab 条目。
+
+2.1 使用EXPORT_SYMBOL宏
+=======================
+
+除了允许将内核符号导出到内核符号表的宏EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()之外,
+这些宏的变体还可以将符号导出到某个命名空间:EXPORT_SYMBOL_NS() 和 EXPORT_SYMBOL_NS_GPL()。
+它们需要一个额外的参数:命名空间(the namespace)。请注意,由于宏扩展,该参数需
+要是一个预处理器符号。例如,要把符号 ``usb_stor_suspend`` 导出到命名空间 ``USB_STORAGE``,
+请使用::
+
+       EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE);
+
+相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。
+导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
+``modpost`` 和kernel/module.c分别在构建时或模块加载时使用名称空间。
+
+2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
+====================================
+
+为一个子系统的所有符号定义命名空间可能会非常冗长,并可能变得难以维护。因此,我
+们提供了一个默认定义(DEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, 它将成
+为所有没有指定命名空间的 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 宏扩展的默认
+定义。
+
+有多种方法来指定这个定义,使用哪种方法取决于子系统和维护者的喜好。第一种方法是在
+子系统的 ``Makefile`` 中定义默认命名空间。例如,如果要将usb-common中定义的所有符号导
+出到USB_COMMON命名空间,可以在drivers/usb/common/Makefile中添加这样一行::
+
+       ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON
+
+这将影响所有 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 语句。当这个定义存在时,
+用EXPORT_SYMBOL_NS()导出的符号仍然会被导出到作为命名空间参数传递的命名空间中,
+因为这个参数优先于默认的符号命名空间。
+
+定义默认命名空间的第二个选项是直接在编译单元中作为预处理声明。上面的例子就会变
+成::
+
+       #undef  DEFAULT_SYMBOL_NAMESPACE
+       #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON
+
+应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前
+
+3. 如何使用命名空间中导出的符号
+===============================
+
+为了使用被导出到命名空间的符号,内核模块需要明确地导入这些命名空间。
+否则内核可能会拒绝加载该模块。模块代码需要使用宏MODULE_IMPORT_NS来
+表示它所使用的命名空间的符号。例如,一个使用usb_stor_suspend符号的
+模块,需要使用如下语句导入命名空间USB_STORAGE::
+
+       MODULE_IMPORT_NS(USB_STORAGE);
+
+这将在模块中为每个导入的命名空间创建一个 ``modinfo`` 标签。这也顺带
+使得可以用modinfo检查模块已导入的命名空间::
+
+       $ modinfo drivers/usb/storage/ums-karma.ko
+       [...]
+       import_ns:      USB_STORAGE
+       [...]
+
+
+建议将 MODULE_IMPORT_NS() 语句添加到靠近其他模块元数据定义的地方,
+如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入
+语句的方法,请参考第5节。
+
+4. 加载使用命名空间符号的模块
+=============================
+
+在模块加载时(比如 ``insmod`` ),内核将检查每个从模块中引用的符号是否可
+用,以及它可能被导出到的名字空间是否被模块导入。内核的默认行为是拒绝
+加载那些没有指明足以导入的模块。此错误会被记录下来,并且加载将以
+EINVAL方式失败。要允许加载不满足这个前提条件的模块,可以使用此配置选项:
+设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y 将使加载不受影响,但会
+发出警告。
+
+5. 自动创建MODULE_IMPORT_NS声明
+===============================
+
+缺少命名空间的导入可以在构建时很容易被检测到。事实上,如果一个模块
+使用了一个命名空间的符号而没有导入它,modpost会发出警告。
+MODULE_IMPORT_NS()语句通常会被添加到一个明确的位置(和其他模块元
+数据一起)。为了使模块作者(和子系统维护者)的生活更加轻松,我们提
+供了一个脚本和make目标来修复丢失的导入。修复丢失的导入可以用::
+
+       $ make nsdeps
+
+对模块作者来说,以下情况可能很典型::
+
+       - 编写依赖未导入命名空间的符号的代码
+       - ``make``
+       - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。
+       - 运行 ``make nsdeps``将导入添加到正确的代码位置。
+
+对于引入命名空间的子系统维护者来说,其步骤非常相似。同样,make nsdeps最终将
+为树内模块添加缺失的命名空间导入::
+
+       - 向命名空间转移或添加符号(例如,使用EXPORT_SYMBOL_NS())。
+       - `make e`(最好是用allmodconfig来覆盖所有的内核模块)。
+       - 注意 ``modpost`` 的警告,提醒你有一个丢失的导入。
+       - 运行 ``maknsdeps``将导入添加到正确的代码位置。
+
+你也可以为外部模块的构建运行nsdeps。典型的用法是::
+
+       $ make -C <path_to_kernel_src> M=$PWD nsdeps
diff --git a/Documentation/translations/zh_CN/core-api/workqueue.rst b/Documentation/translations/zh_CN/core-api/workqueue.rst
new file mode 100644 (file)
index 0000000..0b8f730
--- /dev/null
@@ -0,0 +1,337 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/core-api/workqueue.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_workqueue.rst:
+
+
+=========================
+并发管理的工作队列 (cmwq)
+=========================
+
+:日期: September, 2010
+:作者: Tejun Heo <tj@kernel.org>
+:作者: Florian Mickler <florian@mickler.org>
+
+
+简介
+====
+
+在很多情况下,需要一个异步进程的执行环境,工作队列(wq)API是这种情况下
+最常用的机制。
+
+当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work,
+即一个待执行的任务)被放在队列中。一个独立的线程作为异步执行环境。该队
+列被称为workqueue,线程被称为工作者(worker,即执行这一队列的线程)。
+
+当工作队列上有工作项时,工作者会一个接一个地执行与工作项相关的函数。当
+工作队列中没有任何工作项时,工作者就会变得空闲。当一个新的工作项被排入
+队列时,工作者又开始执行。
+
+
+为什么要cmwq?
+=============
+
+在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程
+(ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工
+作者数量。这些年来,内核增加了很多MT wq的用户,随着CPU核心数量的不断
+增加,一些系统刚启动就达到了默认的32k PID的饱和空间。
+
+尽管MT wq浪费了大量的资源,但所提供的并发性水平却不能令人满意。这个限
+制在ST和MT wq中都有,只是在MT中没有那么严重。每个wq都保持着自己独立的
+工作者池。一个MT wq只能为每个CPU提供一个执行环境,而一个ST wq则为整个
+系统提供一个。工作项必须竞争这些非常有限的执行上下文,从而导致各种问题,
+包括在单一执行上下文周围容易发生死锁。
+
+(MT wq)所提供的并发性水平和资源使用之间的矛盾也迫使其用户做出不必要的权衡,比
+如libata选择使用ST wq来轮询PIO,并接受一个不必要的限制,即没有两个轮
+询PIO可以同时进行。由于MT wq并没有提供更好的并发性,需要更高层次的并
+发性的用户,如async或fscache,不得不实现他们自己的线程池。
+
+并发管理工作队列(cmwq)是对wq的重新实现,重点是以下目标。
+
+* 保持与原始工作队列API的兼容性。
+
+* 使用由所有wq共享的每CPU统一的工作者池,在不浪费大量资源的情况下按
+* 需提供灵活的并发水平。
+
+* 自动调节工作者池和并发水平,使API用户不需要担心这些细节。
+
+
+设计
+====
+
+为了简化函数的异步执行,引入了一个新的抽象概念,即工作项。
+
+一个工作项是一个简单的结构,它持有一个指向将被异步执行的函数的指针。
+每当一个驱动程序或子系统希望一个函数被异步执行时,它必须建立一个指
+向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue
+队列里面去)
+
+特定目的线程,称为工作线程(工作者),一个接一个地执行队列中的功能。
+如果没有工作项排队,工作者线程就会闲置。这些工作者线程被管理在所谓
+的工作者池中。
+
+cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作,
+以及管理工作者池和处理排队工作项的后端机制。
+
+每个可能的CPU都有两个工作者池,一个用于正常的工作项,另一个用于高
+优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工
+作项目——这些后备池的数量是动态的。
+
+当他们认为合适的时候,子系统和驱动程序可以通过特殊的
+``workqueue API`` 函数创建和排队工作项。他们可以通过在工作队列上
+设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些
+标志包括诸如CPU定位、并发限制、优先级等等。要获得详细的概述,请参
+考下面的 ``alloc_workqueue()`` 的 API 描述。
+
+当一个工作项被排入一个工作队列时,目标工作池将根据队列参数和工作队
+列属性确定,并被附加到工作池的共享工作列表上。例如,除非特别重写,
+否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普
+通或高级工作工作者池的工作项列表中。
+
+对于任何工作者池的实施,管理并发水平(有多少执行上下文处于活动状
+态)是一个重要问题。最低水平是为了节省资源,而饱和水平是指系统被
+充分使用。
+
+每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当
+一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可
+运行的工作者的数量。一般来说,工作项不会占用CPU并消耗很多周期。这
+意味着保持足够的并发性以防止工作处理停滞应该是最优的。只要CPU上有
+一个或多个可运行的工作者,工作者池就不会开始执行新的工作,但是,当
+最后一个运行的工作者进入睡眠状态时,它会立即安排一个新的工作者,这
+样CPU就不会在有待处理的工作项目时闲置。这允许在不损失执行带宽的情
+况下使用最少的工作者。
+
+除了kthreads的内存空间外,保留空闲的工作者并没有其他成本,所以cmwq
+在杀死它们之前会保留一段时间的空闲。
+
+对于非绑定的工作队列,后备池的数量是动态的。可以使用
+``apply_workqueue_attrs()`` 为非绑定工作队列分配自定义属性,
+workqueue将自动创建与属性相匹配的后备工作者池。调节并发水平的责任在
+用户身上。也有一个标志可以将绑定的wq标记为忽略并发管理。
+详情请参考API部分。
+
+前进进度的保证依赖于当需要更多的执行上下文时可以创建工作者,这也是
+通过使用救援工作者来保证的。所有可能在处理内存回收的代码路径上使用
+的工作项都需要在wq上排队,wq上保留了一个救援工作者,以便在内存有压
+力的情况下下执行。否则,工作者池就有可能出现死锁,等待执行上下文释
+放出来。
+
+
+应用程序编程接口 (API)
+======================
+
+``alloc_workqueue()`` 分配了一个wq。原来的 ``create_*workqueue()``
+函数已被废弃,并计划删除。 ``alloc_workqueue()`` 需要三个
+参数 - ``@name`` , ``@flags`` 和 ``@max_active`` 。
+``@name`` 是wq的名称,如果有的话,也用作救援线程的名称。
+
+一个wq不再管理执行资源,而是作为前进进度保证、刷新(flush)和
+工作项属性的域。 ``@flags`` 和 ``@max_active`` 控制着工作
+项如何被分配执行资源、安排和执行。
+
+
+``flags``
+---------
+
+``WQ_UNBOUND``
+  排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不
+  绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提
+  供者,没有并发管理。非绑定工作者池试图尽快开始执行工作项。非
+  绑定的wq牺牲了局部性,但在以下情况下是有用的。
+
+  * 预计并发水平要求会有很大的波动,使用绑定的wq最终可能会在不
+    同的CPU上产生大量大部分未使用的工作者,因为发起线程在不同
+    的CPU上跳转。
+
+  * 长期运行的CPU密集型工作负载,可以由系统调度器更好地管理。
+
+``WQ_FREEZABLE``
+  一个可冻结的wq参与了系统暂停操作的冻结阶段。wq上的工作项被
+  排空,在解冻之前没有新的工作项开始执行。
+
+``WQ_MEM_RECLAIM``
+  所有可能在内存回收路径中使用的wq都必须设置这个标志。无论内
+  存压力如何,wq都能保证至少有一个执行上下文。
+
+``WQ_HIGHPRI``
+  高优先级wq的工作项目被排到目标cpu的高优先级工作者池中。高
+  优先级的工作者池由具有较高级别的工作者线程提供服务。
+
+  请注意,普通工作者池和高优先级工作者池之间并不相互影响。他
+  们各自维护其独立的工作者池,并在其工作者之间实现并发管理。
+
+``WQ_CPU_INTENSIVE``
+  CPU密集型wq的工作项对并发水平没有贡献。换句话说,可运行的
+  CPU密集型工作项不会阻止同一工作者池中的其他工作项开始执行。
+  这对于那些预计会占用CPU周期的绑定工作项很有用,这样它们的
+  执行就会受到系统调度器的监管。
+
+  尽管CPU密集型工作项不会对并发水平做出贡献,但它们的执行开
+  始仍然受到并发管理的管制,可运行的非CPU密集型工作项会延迟
+  CPU密集型工作项的执行。
+
+  这个标志对于未绑定的wq来说是没有意义的。
+
+请注意,标志 ``WQ_NON_REENTRANT`` 不再存在,因为现在所有的工作
+队列都是不可逆的——任何工作项都保证在任何时间内最多被整个系统的一
+个工作者执行。
+
+
+``max_active``
+--------------
+
+``@max_active`` 决定了每个CPU可以分配给wq的工作项的最大执行上
+下文数量。例如,如果 ``@max_active为16`` ,每个CPU最多可以同
+时执行16个wq的工作项。
+
+目前,对于一个绑定的wq, ``@max_active`` 的最大限制是512,当指
+定为0时使用的默认值是256。对于非绑定的wq,其限制是512和
+4 * ``num_possible_cpus()`` 中的较高值。这些值被选得足够高,所
+以它们不是限制性因素,同时会在失控情况下提供保护。
+
+一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用
+户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动
+工作项的数量,否则建议指定 为"0"。
+
+一些用户依赖于ST wq的严格执行顺序。 ``@max_active`` 为1和 ``WQ_UNBOUND``
+的组合用来实现这种行为。这种wq上的工作项目总是被排到未绑定的工作池
+中,并且在任何时候都只有一个工作项目处于活动状态,从而实现与ST wq相
+同的排序属性。
+
+在目前的实现中,上述配置只保证了特定NUMA节点内的ST行为。相反,
+``alloc_ordered_queue()`` 应该被用来实现全系统的ST行为。
+
+
+执行场景示例
+============
+
+下面的示例执行场景试图说明cmwq在不同配置下的行为。
+
+ 工作项w0、w1、w2被排到同一个CPU上的一个绑定的wq q0上。w0
+ 消耗CPU 5ms,然后睡眠10ms,然后在完成之前再次消耗CPU 5ms。
+
+忽略所有其他的任务、工作和处理开销,并假设简单的FIFO调度,
+下面是一个高度简化的原始wq的可能事件序列的版本。::
+
+ TIME IN MSECS EVENT
+ 0             w0 starts and burns CPU
+ 5             w0 sleeps
+ 15            w0 wakes up and burns CPU
+ 20            w0 finishes
+ 20            w1 starts and burns CPU
+ 25            w1 sleeps
+ 35            w1 wakes up and finishes
+ 35            w2 starts and burns CPU
+ 40            w2 sleeps
+ 50            w2 wakes up and finishes
+
+And with cmwq with ``@max_active`` >= 3, ::
+
+ TIME IN MSECS EVENT
+ 0             w0 starts and burns CPU
+ 5             w0 sleeps
+ 5             w1 starts and burns CPU
+ 10            w1 sleeps
+ 10            w2 starts and burns CPU
+ 15            w2 sleeps
+ 15            w0 wakes up and burns CPU
+ 20            w0 finishes
+ 20            w1 wakes up and finishes
+ 25            w2 wakes up and finishes
+
+如果 ``@max_active`` == 2, ::
+
+ TIME IN MSECS EVENT
+ 0             w0 starts and burns CPU
+ 5             w0 sleeps
+ 5             w1 starts and burns CPU
+ 10            w1 sleeps
+ 15            w0 wakes up and burns CPU
+ 20            w0 finishes
+ 20            w1 wakes up and finishes
+ 20            w2 starts and burns CPU
+ 25            w2 sleeps
+ 35            w2 wakes up and finishes
+
+现在,我们假设w1和w2被排到了不同的wq q1上,这个wq q1
+有 ``WQ_CPU_INTENSIVE`` 设置::
+
+ TIME IN MSECS EVENT
+ 0             w0 starts and burns CPU
+ 5             w0 sleeps
+ 5             w1 and w2 start and burn CPU
+ 10            w1 sleeps
+ 15            w2 sleeps
+ 15            w0 wakes up and burns CPU
+ 20            w0 finishes
+ 20            w1 wakes up and finishes
+ 25            w2 wakes up and finishes
+
+
+指南
+====
+
+* 如果一个wq可能处理在内存回收期间使用的工作项目,请不
+  要忘记使用 ``WQ_MEM_RECLAIM`` 。每个设置了
+  ``WQ_MEM_RECLAIM`` 的wq都有一个为其保留的执行环境。
+  如果在内存回收过程中使用的多个工作项之间存在依赖关系,
+  它们应该被排在不同的wq中,每个wq都有 ``WQ_MEM_RECLAIM`` 。
+
+* 除非需要严格排序,否则没有必要使用ST wq。
+
+* 除非有特殊需要,建议使用0作为@max_active。在大多数使用情
+  况下,并发水平通常保持在默认限制之下。
+
+* 一个wq作为前进进度保证(WQ_MEM_RECLAIM,冲洗(flush)和工
+  作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一
+  部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使
+  用专用wq和系统wq在执行特性上没有区别。
+
+* 除非工作项预计会消耗大量的CPU周期,否则使用绑定的wq通常是有
+  益的,因为wq操作和工作项执行中的定位水平提高了。
+
+
+调试
+====
+
+因为工作函数是由通用的工作者线程执行的,所以需要一些手段来揭示一些行为不端的工作队列用户。
+
+工作者线程在进程列表中显示为: ::
+
+  root      5671  0.0  0.0      0     0 ?        S    12:07   0:00 [kworker/0:1]
+  root      5672  0.0  0.0      0     0 ?        S    12:07   0:00 [kworker/1:2]
+  root      5673  0.0  0.0      0     0 ?        S    12:12   0:00 [kworker/0:0]
+  root      5674  0.0  0.0      0     0 ?        S    12:13   0:00 [kworker/1:0]
+
+如果kworkers失控了(使用了太多的cpu),有两类可能的问题:
+
+       1. 正在迅速调度的事情
+       2. 一个消耗大量cpu周期的工作项。
+
+第一个可以用追踪的方式进行跟踪: ::
+
+       $ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event
+       $ cat /sys/kernel/debug/tracing/trace_pipe > out.txt
+       (wait a few secs)
+
+如果有什么东西在工作队列上忙着做循环,它就会主导输出,可以用工作项函数确定违规者。
+
+对于第二类问题,应该可以只检查违规工作者线程的堆栈跟踪。 ::
+
+       $ cat /proc/THE_OFFENDING_KWORKER/stack
+
+工作项函数在堆栈追踪中应该是微不足道的。
+
+
+内核内联文档参考
+================
+
+该API在以下内核代码中:
+
+include/linux/workqueue.h
+
+kernel/workqueue.c
index fd73c47..e6c99f2 100644 (file)
    :maxdepth: 2
 
    gcov
+   kasan
 
 Todolist:
 
  - coccinelle
  - sparse
  - kcov
- - kasan
  - ubsan
  - kmemleak
  - kcsan
diff --git a/Documentation/translations/zh_CN/dev-tools/kasan.rst b/Documentation/translations/zh_CN/dev-tools/kasan.rst
new file mode 100644 (file)
index 0000000..23db9d4
--- /dev/null
@@ -0,0 +1,417 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/dev-tools/kasan.rst
+:Translator: 万家兵 Wan Jiabing <wanjiabing@vivo.com>
+
+内核地址消毒剂(KASAN)
+=====================
+
+概述
+----
+
+KernelAddressSANitizer(KASAN)是一种动态内存安全错误检测工具,主要功能是
+检查内存越界访问和使用已释放内存的问题。KASAN有三种模式:
+
+1. 通用KASAN(与用户空间的ASan类似)
+2. 基于软件标签的KASAN(与用户空间的HWASan类似)
+3. 基于硬件标签的KASAN(基于硬件内存标签)
+
+由于通用KASAN的内存开销较大,通用KASAN主要用于调试。基于软件标签的KASAN
+可用于dogfood测试,因为它具有较低的内存开销,并允许将其用于实际工作量。
+基于硬件标签的KASAN具有较低的内存和性能开销,因此可用于生产。同时可用于
+检测现场内存问题或作为安全缓解措施。
+
+软件KASAN模式(#1和#2)使用编译时工具在每次内存访问之前插入有效性检查,
+因此需要一个支持它的编译器版本。
+
+通用KASAN在GCC和Clang受支持。GCC需要8.3.0或更高版本。任何受支持的Clang
+版本都是兼容的,但从Clang 11才开始支持检测全局变量的越界访问。
+
+基于软件标签的KASAN模式仅在Clang中受支持。
+
+硬件KASAN模式(#3)依赖硬件来执行检查,但仍需要支持内存标签指令的编译器
+版本。GCC 10+和Clang 11+支持此模式。
+
+两种软件KASAN模式都适用于SLUB和SLAB内存分配器,而基于硬件标签的KASAN目前
+仅支持SLUB。
+
+目前x86_64、arm、arm64、xtensa、s390、riscv架构支持通用KASAN模式,仅
+arm64架构支持基于标签的KASAN模式。
+
+用法
+----
+
+要启用KASAN,请使用以下命令配置内核::
+
+         CONFIG_KASAN=y
+
+同时在 ``CONFIG_KASAN_GENERIC`` (启用通用KASAN模式), ``CONFIG_KASAN_SW_TAGS``
+(启用基于硬件标签的KASAN模式),和 ``CONFIG_KASAN_HW_TAGS`` (启用基于硬件标签
+的KASAN模式)之间进行选择。
+
+对于软件模式,还可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE``
+之间进行选择。outline和inline是编译器插桩类型。前者产生较小的二进制文件,
+而后者快1.1-2倍。
+
+要将受影响的slab对象的alloc和free堆栈跟踪包含到报告中,请启用
+``CONFIG_STACKTRACE`` 。要包括受影响物理页面的分配和释放堆栈跟踪的话,
+请启用 ``CONFIG_PAGE_OWNER`` 并使用 ``page_owner=on`` 进行引导。
+
+错误报告
+~~~~~~~~
+
+典型的KASAN报告如下所示::
+
+    ==================================================================
+    BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan]
+    Write of size 1 at addr ffff8801f44ec37b by task insmod/2760
+
+    CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698
+    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
+    Call Trace:
+     dump_stack+0x94/0xd8
+     print_address_description+0x73/0x280
+     kasan_report+0x144/0x187
+     __asan_report_store1_noabort+0x17/0x20
+     kmalloc_oob_right+0xa8/0xbc [test_kasan]
+     kmalloc_tests_init+0x16/0x700 [test_kasan]
+     do_one_initcall+0xa5/0x3ae
+     do_init_module+0x1b6/0x547
+     load_module+0x75df/0x8070
+     __do_sys_init_module+0x1c6/0x200
+     __x64_sys_init_module+0x6e/0xb0
+     do_syscall_64+0x9f/0x2c0
+     entry_SYSCALL_64_after_hwframe+0x44/0xa9
+    RIP: 0033:0x7f96443109da
+    RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
+    RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
+    RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000
+    RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000
+    R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88
+    R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000
+
+    Allocated by task 2760:
+     save_stack+0x43/0xd0
+     kasan_kmalloc+0xa7/0xd0
+     kmem_cache_alloc_trace+0xe1/0x1b0
+     kmalloc_oob_right+0x56/0xbc [test_kasan]
+     kmalloc_tests_init+0x16/0x700 [test_kasan]
+     do_one_initcall+0xa5/0x3ae
+     do_init_module+0x1b6/0x547
+     load_module+0x75df/0x8070
+     __do_sys_init_module+0x1c6/0x200
+     __x64_sys_init_module+0x6e/0xb0
+     do_syscall_64+0x9f/0x2c0
+     entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+    Freed by task 815:
+     save_stack+0x43/0xd0
+     __kasan_slab_free+0x135/0x190
+     kasan_slab_free+0xe/0x10
+     kfree+0x93/0x1a0
+     umh_complete+0x6a/0xa0
+     call_usermodehelper_exec_async+0x4c3/0x640
+     ret_from_fork+0x35/0x40
+
+    The buggy address belongs to the object at ffff8801f44ec300
+     which belongs to the cache kmalloc-128 of size 128
+    The buggy address is located 123 bytes inside of
+     128-byte region [ffff8801f44ec300, ffff8801f44ec380)
+    The buggy address belongs to the page:
+    page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0
+    flags: 0x200000000000100(slab)
+    raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640
+    raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000
+    page dumped because: kasan: bad access detected
+
+    Memory state around the buggy address:
+     ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+     ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+    >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03
+                                                                    ^
+     ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+     ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+    ==================================================================
+
+报告标题总结了发生的错误类型以及导致该错误的访问类型。紧随其后的是错误访问的
+堆栈跟踪、所访问内存分配位置的堆栈跟踪(对于访问了slab对象的情况)以及对象
+被释放的位置的堆栈跟踪(对于访问已释放内存的问题报告)。接下来是对访问的
+slab对象的描述以及关于访问的内存页的信息。
+
+最后,报告展示了访问地址周围的内存状态。在内部,KASAN单独跟踪每个内存颗粒的
+内存状态,根据KASAN模式分为8或16个对齐字节。报告的内存状态部分中的每个数字
+都显示了围绕访问地址的其中一个内存颗粒的状态。
+
+对于通用KASAN,每个内存颗粒的大小为8个字节。每个颗粒的状态被编码在一个影子字节
+中。这8个字节可以是可访问的,部分访问的,已释放的或成为Redzone的一部分。KASAN
+对每个影子字节使用以下编码:00表示对应内存区域的所有8个字节都可以访问;数字N
+(1 <= N <= 7)表示前N个字节可访问,其他(8 - N)个字节不可访问;任何负值都表示
+无法访问整个8字节。KASAN使用不同的负值来区分不同类型的不可访问内存,如redzones
+或已释放的内存(参见 mm/kasan/kasan.h)。
+
+在上面的报告中,箭头指向影子字节 ``03`` ,表示访问的地址是部分可访问的。
+
+对于基于标签的KASAN模式,报告最后的部分显示了访问地址周围的内存标签
+(参考 `实施细则`_ 章节)。
+
+请注意,KASAN错误标题(如 ``slab-out-of-bounds`` 或 ``use-after-free`` )
+是尽量接近的:KASAN根据其拥有的有限信息打印出最可能的错误类型。错误的实际类型
+可能会有所不同。
+
+通用KASAN还报告两个辅助调用堆栈跟踪。这些堆栈跟踪指向代码中与对象交互但不直接
+出现在错误访问堆栈跟踪中的位置。目前,这包括 call_rcu() 和排队的工作队列。
+
+启动参数
+~~~~~~~~
+
+KASAN受通用 ``panic_on_warn`` 命令行参数的影响。启用该功能后,KASAN在打印错误
+报告后会引起内核恐慌。
+
+默认情况下,KASAN只为第一次无效内存访问打印错误报告。使用 ``kasan_multi_shot`` ,
+KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告的 ``panic_on_warn`` 。
+
+基于硬件标签的KASAN模式(请参阅下面有关各种模式的部分)旨在在生产中用作安全缓解
+措施。因此,它支持允许禁用KASAN或控制其功能的引导参数。
+
+- ``kasan=off`` 或 ``=on`` 控制KASAN是否启用 (默认: ``on`` )。
+
+- ``kasan.mode=sync`` 或 ``=async`` 控制KASAN是否配置为同步或异步执行模式(默认:
+  ``sync`` )。同步模式:当标签检查错误发生时,立即检测到错误访问。异步模式:
+  延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的
+  TFSR_EL1寄存器中)。内核会定期检查硬件,并且仅在这些检查期间报告标签错误。
+
+- ``kasan.stacktrace=off`` 或 ``=on`` 禁用或启用alloc和free堆栈跟踪收集
+  (默认: ``on`` )。
+
+- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌
+  (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。
+
+实施细则
+--------
+
+通用KASAN
+~~~~~~~~~
+
+软件KASAN模式使用影子内存来记录每个内存字节是否可以安全访问,并使用编译时工具
+在每次内存访问之前插入影子内存检查。
+
+通用KASAN将1/8的内核内存专用于其影子内存(16TB以覆盖x86_64上的128TB),并使用
+具有比例和偏移量的直接映射将内存地址转换为其相应的影子地址。
+
+这是将地址转换为其相应影子地址的函数::
+
+    static inline void *kasan_mem_to_shadow(const void *addr)
+    {
+       return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
+               + KASAN_SHADOW_OFFSET;
+    }
+
+在这里 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。
+
+编译时工具用于插入内存访问检查。编译器在每次访问大小为1、2、4、8或16的内存之前
+插入函数调用( ``__asan_load*(addr)`` , ``__asan_store*(addr)``)。这些函数通过
+检查相应的影子内存来检查内存访问是否有效。
+
+使用inline插桩,编译器不进行函数调用,而是直接插入代码来检查影子内存。此选项
+显著地增大了内核体积,但与outline插桩内核相比,它提供了x1.1-x2的性能提升。
+
+通用KASAN是唯一一种通过隔离延迟重新使用已释放对象的模式
+(参见 mm/kasan/quarantine.c 以了解实现)。
+
+基于软件标签的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基于软件标签的KASAN使用软件内存标签方法来检查访问有效性。目前仅针对arm64架构实现。
+
+基于软件标签的KASAN使用arm64 CPU的顶部字节忽略(TBI)特性在内核指针的顶部字节中
+存储一个指针标签。它使用影子内存来存储与每个16字节内存单元相关的内存标签(因此,
+它将内核内存的1/16专用于影子内存)。
+
+在每次内存分配时,基于软件标签的KASAN都会生成一个随机标签,用这个标签标记分配
+的内存,并将相同的标签嵌入到返回的指针中。
+
+基于软件标签的KASAN使用编译时工具在每次内存访问之前插入检查。这些检查确保正在
+访问的内存的标签等于用于访问该内存的指针的标签。如果标签不匹配,基于软件标签
+的KASAN会打印错误报告。
+
+基于软件标签的KASAN也有两种插桩模式(outline,发出回调来检查内存访问;inline,
+执行内联的影子内存检查)。使用outline插桩模式,会从执行访问检查的函数打印错误
+报告。使用inline插桩,编译器会发出 ``brk`` 指令,并使用专用的 ``brk`` 处理程序
+来打印错误报告。
+
+基于软件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签
+的指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
+
+基于软件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
+
+基于硬件标签的KASAN模式
+~~~~~~~~~~~~~~~~~~~~~~~
+
+基于硬件标签的KASAN在概念上类似于软件模式,但它是使用硬件内存标签作为支持而
+不是编译器插桩和影子内存。
+
+基于硬件标签的KASAN目前仅针对arm64架构实现,并且基于ARMv8.5指令集架构中引入
+的arm64内存标记扩展(MTE)和最高字节忽略(TBI)。
+
+特殊的arm64指令用于为每次内存分配指定内存标签。相同的标签被指定给指向这些分配
+的指针。在每次内存访问时,硬件确保正在访问的内存的标签等于用于访问该内存的指针
+的标签。如果标签不匹配,则会生成故障并打印报告。
+
+基于硬件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签的
+指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
+
+基于硬件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
+
+如果硬件不支持MTE(ARMv8.5之前),则不会启用基于硬件标签的KASAN。在这种情况下,
+所有KASAN引导参数都将被忽略。
+
+请注意,启用CONFIG_KASAN_HW_TAGS始终会导致启用内核中的TBI。即使提供了
+``kasan.mode=off`` 或硬件不支持MTE(但支持TBI)。
+
+基于硬件标签的KASAN只报告第一个发现的错误。之后,MTE标签检查将被禁用。
+
+影子内存
+--------
+
+内核将内存映射到地址空间的几个不同部分。内核虚拟地址的范围很大:没有足够的真实
+内存来支持内核可以访问的每个地址的真实影子区域。因此,KASAN只为地址空间的某些
+部分映射真实的影子。
+
+默认行为
+~~~~~~~~
+
+默认情况下,体系结构仅将实际内存映射到用于线性映射的阴影区域(以及可能的其他
+小区域)。对于所有其他区域 —— 例如vmalloc和vmemmap空间 —— 一个只读页面被映射
+到阴影区域上。这个只读的影子页面声明所有内存访问都是允许的。
+
+这给模块带来了一个问题:它们不存在于线性映射中,而是存在于专用的模块空间中。
+通过连接模块分配器,KASAN临时映射真实的影子内存以覆盖它们。例如,这允许检测
+对模块全局变量的无效访问。
+
+这也造成了与 ``VMAP_STACK`` 的不兼容:如果堆栈位于vmalloc空间中,它将被分配
+只读页面的影子内存,并且内核在尝试为堆栈变量设置影子数据时会出错。
+
+CONFIG_KASAN_VMALLOC
+~~~~~~~~~~~~~~~~~~~~
+
+使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的内存使用为代价覆盖vmalloc
+空间。目前,这在x86、riscv、s390和powerpc上受支持。
+
+这通过连接到vmalloc和vmap并动态分配真实的影子内存来支持映射。
+
+vmalloc空间中的大多数映射都很小,需要不到一整页的阴影空间。因此,为每个映射
+分配一个完整的影子页面将是一种浪费。此外,为了确保不同的映射使用不同的影子
+页面,映射必须与 ``KASAN_GRANULE_SIZE * PAGE_SIZE`` 对齐。
+
+相反,KASAN跨多个映射共享后备空间。当vmalloc空间中的映射使用影子区域的特定
+页面时,它会分配一个后备页面。此页面稍后可以由其他vmalloc映射共享。
+
+KASAN连接到vmap基础架构以懒清理未使用的影子内存。
+
+为了避免交换映射的困难,KASAN预测覆盖vmalloc空间的阴影区域部分将不会被早期
+的阴影页面覆盖,但是将不会被映射。这将需要更改特定于arch的代码。
+
+这允许在x86上支持 ``VMAP_STACK`` ,并且可以简化对没有固定模块区域的架构的支持。
+
+对于开发者
+----------
+
+忽略访问
+~~~~~~~~
+
+软件KASAN模式使用编译器插桩来插入有效性检查。此类检测可能与内核的某些部分
+不兼容,因此需要禁用。
+
+内核的其他部分可能会访问已分配对象的元数据。通常,KASAN会检测并报告此类访问,
+但在某些情况下(例如,在内存分配器中),这些访问是有效的。
+
+对于软件KASAN模式,要禁用特定文件或目录的检测,请将 ``KASAN_SANITIZE`` 添加
+到相应的内核Makefile中:
+
+- 对于单个文件(例如,main.o)::
+
+    KASAN_SANITIZE_main.o := n
+
+- 对于一个目录下的所有文件::
+
+    KASAN_SANITIZE := n
+
+对于软件KASAN模式,要在每个函数的基础上禁用检测,请使用KASAN特定的
+``__no_sanitize_address`` 函数属性或通用的 ``noinstr`` 。
+
+请注意,禁用编译器插桩(基于每个文件或每个函数)会使KASAN忽略在软件KASAN模式
+的代码中直接发生的访问。当访问是间接发生的(通过调用检测函数)或使用没有编译器
+插桩的基于硬件标签的模式时,它没有帮助。
+
+对于软件KASAN模式,要在当前任务的一部分内核代码中禁用KASAN报告,请使用
+``kasan_disable_current()``/``kasan_enable_current()`` 部分注释这部分代码。
+这也会禁用通过函数调用发生的间接访问的报告。
+
+对于基于标签的KASAN模式(包括硬件模式),要禁用访问检查,请使用
+``kasan_reset_tag()`` 或 ``page_kasan_tag_reset()`` 。请注意,通过
+``page_kasan_tag_reset()`` 临时禁用访问检查需要通过 ``page_kasan_tag``
+/ ``page_kasan_tag_set`` 保存和恢复每页KASAN标签。
+
+测试
+~~~~
+
+有一些KASAN测试可以验证KASAN是否正常工作并可以检测某些类型的内存损坏。
+测试由两部分组成:
+
+1. 与KUnit测试框架集成的测试。使用 ``CONFIG_KASAN_KUNIT_TEST`` 启用。
+这些测试可以通过几种不同的方式自动运行和部分验证;请参阅下面的说明。
+
+2. 与KUnit不兼容的测试。使用 ``CONFIG_KASAN_MODULE_TEST`` 启用并且只能作为模块
+运行。这些测试只能通过加载内核模块并检查内核日志以获取KASAN报告来手动验证。
+
+如果检测到错误,每个KUnit兼容的KASAN测试都会打印多个KASAN报告之一,然后测试打印
+其编号和状态。
+
+当测试通过::
+
+        ok 28 - kmalloc_double_kzfree
+
+当由于 ``kmalloc`` 失败而导致测试失败时::
+
+        # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163
+        Expected ptr is not null, but is
+        not ok 4 - kmalloc_large_oob_right
+
+当由于缺少KASAN报告而导致测试失败时::
+
+        # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:629
+        Expected kasan_data->report_expected == kasan_data->report_found, but
+        kasan_data->report_expected == 1
+        kasan_data->report_found == 0
+        not ok 28 - kmalloc_double_kzfree
+
+最后打印所有KASAN测试的累积状态。成功::
+
+        ok 1 - kasan
+
+或者,如果其中一项测试失败::
+
+        not ok 1 - kasan
+
+有几种方法可以运行与KUnit兼容的KASAN测试。
+
+1. 可加载模块
+
+   启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit测试可以构建为可加载模块,并通过使用
+   ``insmod`` 或 ``modprobe`` 加载 ``test_kasan.ko`` 来运行。
+
+2. 内置
+
+   通过内置 ``CONFIG_KUNIT`` ,也可以内置KASAN-KUnit测试。在这种情况下,
+   测试将在启动时作为后期初始化调用运行。
+
+3. 使用kunit_tool
+
+   通过内置 ``CONFIG_KUNIT`` 和 ``CONFIG_KASAN_KUNIT_TEST`` ,还可以使用
+   ``kunit_tool`` 以更易读的方式查看KUnit测试结果。这不会打印通过测试
+   的KASAN报告。有关 ``kunit_tool`` 更多最新信息,请参阅
+   `KUnit文档 <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>`_ 。
+
+.. _KUnit: https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html
index d56d6b7..1f953d3 100644 (file)
@@ -4,6 +4,7 @@
 
        \renewcommand\thesection*
        \renewcommand\thesubsection*
+       \kerneldocCJKon
 
 .. _linux_doc_zh:
 
@@ -72,11 +73,11 @@ TODOlist:
    dev-tools/index
    doc-guide/index
    kernel-hacking/index
+   maintainer/index
 
 TODOList:
 
 * trace/index
-* maintainer/index
 * fault-injection/index
 * livepatch/index
 * rust/index
@@ -153,6 +154,7 @@ TODOList:
    arm64/index
    riscv/index
    openrisc/index
+   parisc/index
 
 TODOList:
 
@@ -160,7 +162,6 @@ TODOList:
 * ia64/index
 * m68k/index
 * nios2/index
-* parisc/index
 * powerpc/index
 * s390/index
 * sh/index
diff --git a/Documentation/translations/zh_CN/maintainer/configure-git.rst b/Documentation/translations/zh_CN/maintainer/configure-git.rst
new file mode 100644 (file)
index 0000000..a45ea73
--- /dev/null
@@ -0,0 +1,62 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/configure-git.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _configuregit_zh:
+
+Git配置
+=======
+
+本章讲述了维护者级别的git配置。
+
+Documentation/maintainer/pull-requests.rst 中使用的标记分支应使用开发人员的
+GPG公钥进行签名。可以通过将 ``-u`` 标志传递给 ``git tag`` 来创建签名标记。
+但是,由于 *通常* 对同一项目使用同一个密钥,因此可以设置::
+
+       git config user.signingkey "keyname"
+
+或者手动编辑你的 ``.git/config`` 或 ``~/.gitconfig`` 文件::
+
+       [user]
+               name = Jane Developer
+               email = jd@domain.org
+               signingkey = jd@domain.org
+
+你可能需要告诉 ``git`` 去使用 ``gpg2``::
+
+       [gpg]
+               program = /path/to/gpg2
+
+你可能也需要告诉 ``gpg`` 去使用哪个 ``tty`` (添加到你的shell rc文件中)::
+
+       export GPG_TTY=$(tty)
+
+
+创建链接到lore.kernel.org的提交
+-------------------------------
+
+http://lore.kernel.org 网站是所有涉及或影响内核开发的邮件列表的总存档。在这里
+存储补丁存档是推荐的做法,当维护人员将补丁应用到子系统树时,最好提供一个指向
+lore存档链接的标签,以便浏览提交历史的人可以找到某个更改背后的相关讨论和基本
+原理。链接标签如下所示:
+
+       Link: https://lore.kernel.org/r/<message-id>
+
+通过在git中添加以下钩子,可以将此配置为在发布 ``git am`` 时自动执行:
+
+.. code-block:: none
+
+       $ git config am.messageid true
+       $ cat >.git/hooks/applypatch-msg <<'EOF'
+       #!/bin/sh
+       . git-sh-setup
+       perl -pi -e 's|^Message-Id:\s*<?([^>]+)>?$|Link: https://lore.kernel.org/r/$1|g;' "$1"
+       test -x "$GIT_DIR/hooks/commit-msg" &&
+               exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+       :
+       EOF
+       $ chmod a+x .git/hooks/applypatch-msg
diff --git a/Documentation/translations/zh_CN/maintainer/index.rst b/Documentation/translations/zh_CN/maintainer/index.rst
new file mode 100644 (file)
index 0000000..eb75cce
--- /dev/null
@@ -0,0 +1,21 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/index.rst
+
+==============
+内核维护者手册
+==============
+
+本文档本是内核维护者手册的首页。
+本手册还需要大量完善!请自由提出(和编写)本手册的补充内容。
+*译注:指英文原版*
+
+.. toctree::
+   :maxdepth: 2
+
+   configure-git
+   rebasing-and-merging
+   pull-requests
+   maintainer-entry-profile
+   modifying-patches
+
diff --git a/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst b/Documentation/translations/zh_CN/maintainer/maintainer-entry-profile.rst
new file mode 100644 (file)
index 0000000..a1ee99c
--- /dev/null
@@ -0,0 +1,92 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/maintainer-entry-profile.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _maintainerentryprofile_zh:
+
+维护者条目概要
+==============
+
+维护人员条目概要补充了顶层过程文档(提交补丁,提交驱动程序……),增加了子系
+统/设备驱动程序本地习惯以及有关补丁提交生命周期的相关内容。贡献者使用此文档
+来调整他们的期望和避免常见错误;维护人员可以使用这些信息超越子系统层面查看
+是否有机会汇聚到通用实践中。
+
+
+总览
+----
+
+提供了子系统如何操作的介绍。MAINTAINERS文件告诉了贡献者应发送某文件的补丁到哪,
+但它没有传达其他子系统的本地基础设施和机制以协助开发。
+
+请考虑以下问题:
+
+- 当补丁被本地树接纳或合并到上游时是否有通知?
+- 子系统是否使用patchwork实例?Patchwork状态变更是否有通知?
+- 是否有任何机器人或CI基础设施监视列表,或子系统是否使用自动测试反馈以便把
+  控接纳补丁?
+- 被拉入-next的Git分支是哪个?
+- 贡献者应针对哪个分支提交?
+- 是否链接到其他维护者条目概要?例如一个设备驱动可能指向其父子系统的条目。
+  这使得贡献者意识到某维护者可能对提交链中其他维护者负有的义务。
+
+
+提交检查单补遗
+--------------
+
+列出强制性和咨询性标准,超出通用标准“提交检查表,以便维护者检查一个补丁是否
+足够健康。例如:“通过checkpatch.pl,没有错误、没有警告。通过单元测试详见某处”。
+
+提交检查单补遗还可以包括有关硬件规格状态的详细信息。例如,子系统接受补丁之前
+是否需要考虑在某个修订版上发布的规范。
+
+
+开发周期的关键日期
+------------------
+
+提交者常常会误以为补丁可以在合并窗口关闭之前的任何时间发送,且下一个-rc1时仍
+可以。事实上,大多数补丁都需要在下一个合并窗口打开之前提前进入linux-next中。
+向提交者澄清关键日期(以-rc发布周为标志)以明确什么时候补丁会被考虑合并以及
+何时需要等待下一个-rc。
+
+至少需要讲明:
+
+- 最后一个可以提交新功能的-rc:
+  针对下一个合并窗口的新功能提交应该在此点之前首次发布以供考虑。在此时间点
+  之后提交的补丁应该明确他们的目标为下下个合并窗口,或者给出应加快进度被接受
+  的充足理由。通常新特性贡献者的提交应出现在-rc5之前。
+
+- 最后合并-rc:合并决策的最后期限。
+  向贡献者指出尚未接受的补丁集需要等待下下个合并窗口。当然,维护者没有义务
+  接受所有给定的补丁集,但是如果审阅在此时间点尚未结束,那么希望贡献者应该
+  等待并在下一个合并窗口重新提交。
+
+可选项:
+
+- 开发基线分支的首个-rc,列在概述部分,视为已为新提交做好准备。
+
+
+审阅节奏
+--------
+
+贡献者最担心的问题之一是:补丁集已发布却未收到反馈,应在多久后发送提醒。除了
+指定在重新提交之前要等待多长时间,还可以指示更新的首选样式;例如,重新发送
+整个系列,或私下发送提醒邮件。本节也可以列出本区域的代码审阅方式,以及获取
+不能直接从维护者那里得到的反馈的方法。
+
+
+现有概要
+--------
+
+这里列出了现有的维护人员条目概要;我们可能会想要在不久的将来做一些不同的事情。
+
+.. toctree::
+   :maxdepth: 1
+
+   ../doc-guide/maintainer-profile
+   ../../../nvdimm/maintainer-entry-profile
+   ../../../riscv/patch-acceptance
diff --git a/Documentation/translations/zh_CN/maintainer/modifying-patches.rst b/Documentation/translations/zh_CN/maintainer/modifying-patches.rst
new file mode 100644 (file)
index 0000000..7f63261
--- /dev/null
@@ -0,0 +1,51 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/modifying-patches.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _modifyingpatches_zh:
+
+修改补丁
+========
+
+如果你是子系统或者分支的维护者,由于代码在你的和提交者的树中并不完全相同,
+有时你需要稍微修改一下收到的补丁以合并它们。
+
+如果你严格遵守开发者来源证书的规则(c),你应该要求提交者重做,但这完全是会
+适得其反的时间、精力浪费。规则(b)允许你调整代码,但这样修改提交者的代码并
+让他背书你的错误是非常不礼貌的。为解决此问题,建议在你之前最后一个
+Signed-off-by标签和你的之间添加一行,以指示更改的性质。这没有强制性要求,最
+好在描述前面加上你的邮件和/或姓名,用方括号括住整行,以明显指出你对最后一刻
+的更改负责。例如::
+
+        Signed-off-by: Random J Developer <random@developer.example.org>
+        [lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
+        Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
+
+如果您维护着一个稳定的分支,并希望同时明确贡献、跟踪更改、合并修复,并保护
+提交者免受责难,这种做法尤其有用。请注意,在任何情况下都不得更改作者的身份
+(From头),因为它会在变更日志中显示。
+
+向后移植(back-port)人员特别要注意:为了便于跟踪,请在提交消息的顶部(即主题行
+之后)插入补丁的来源,这是一种常见而有用的做法。例如,我们可以在3.x稳定版本
+中看到以下内容::
+
+        Date:   Tue Oct 7 07:26:38 2014 -0400
+
+        libata: Un-break ATA blacklist
+
+        commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
+
+下面是一个旧的内核在某补丁被向后移植后会出现的::
+
+        Date:   Tue May 13 22:12:27 2008 +0200
+
+        wireless, airo: waitbusy() won't delay
+
+        [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
+
+不管什么格式,这些信息都为人们跟踪你的树,以及试图解决你树中的错误的人提供了
+有价值的帮助。
diff --git a/Documentation/translations/zh_CN/maintainer/pull-requests.rst b/Documentation/translations/zh_CN/maintainer/pull-requests.rst
new file mode 100644 (file)
index 0000000..f46d6f3
--- /dev/null
@@ -0,0 +1,148 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/pull-requests.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+.. _pullrequests_zh:
+
+如何创建拉取请求
+================
+
+本章描述维护人员如何创建并向其他维护人员提交拉取请求。这对将更改从一个维护者
+树转移到另一个维护者树非常有用。
+
+本文档由Tobin C. Harding(当时他尚不是一名经验丰富的维护人员)编写,内容主要
+来自Greg Kroah Hartman和Linus Torvalds在LKML上的评论。Jonathan Corbet和Mauro
+Carvalho Chehab提出了一些建议和修改。错误不可避免,如有问题,请找Tobin C.
+Harding <me@tobin.cc>。
+
+原始邮件线程::
+
+       http://lkml.kernel.org/r/20171114110500.GA21175@kroah.com
+
+
+创建分支
+--------
+
+首先,您需要将希望包含拉取请求里的所有更改都放在单独分支中。通常您将基于某开发
+人员树的一个分支,一般是打算向其发送拉取请求的开发人员。
+
+为了创建拉取请求,您必须首先标记刚刚创建的分支。建议您选择一个有意义的标记名,
+以即使过了一段时间您和他人仍能理解的方式。在名称中包含源子系统和目标内核版本
+的指示也是一个好的做法。
+
+Greg提供了以下内容。对于一个含有drivers/char中混杂事项、将应用于4.15-rc1内核的
+拉取请求,可以命名为 ``char-misc-4.15-rc1`` 。如果要在 ``char-misc-next`` 分支
+上打上此标记,您可以使用以下命令::
+
+       git tag -s char-misc-4.15-rc1 char-misc-next
+
+这将在 ``char-misc-next`` 分支的最后一个提交上创建一个名为 ``char-misc-4.15-rc1``
+的标记,并用您的gpg密钥签名(参见 Documentation/maintainer/configure-git.rst )。
+
+Linus只接受基于签名过的标记的拉取请求。其他维护者可能会有所不同。
+
+当您运行上述命令时 ``git`` 会打开编辑器要求你描述一下这个标记。在本例中您需要
+描述拉取请求,所以请概述一下包含的内容,为什么要合并,是否完成任何测试。所有
+这些信息都将留在标记中,然后在维护者合并拉取请求时保留在合并提交中。所以把它
+写好,它将永远留在内核中。
+
+正如Linus所说::
+
+       不管怎么样,至少对我来说,重要的是 *信息* 。我需要知道我在拉取什么、
+       为什么我要拉取。我也希望将此消息用于合并消息,因此它不仅应该对我有
+       意义,也应该可以成为一个有意义的历史记录。
+
+       注意,如果拉取请求有一些不寻常的地方,请详细说明。如果你修改了并非
+       由你维护的文件,请解释 **为什么** 。我总会在差异中看到的,如果你不
+       提的话,我只会觉得分外可疑。当你在合并窗口后给我发新东西的时候,
+       (甚至是比较重大的错误修复),不仅需要解释做了什么、为什么这么做,
+       还请解释一下 **时间问题** 。为什么错过了合并窗口……
+
+       我会看你写在拉取请求邮件和签名标记里面的内容,所以根据你的工作流,
+       你可以在签名标记里面描述工作内容(也会自动放进拉取请求邮件),也
+       可以只在标记里面放个占位符,稍后在你实际发给我拉取请求时描述工作内容。
+
+       是的,我会编辑这些消息。部分因为我需要做一些琐碎的格式调整(整体缩进、
+       括号等),也因为此消息可能对我有意义(描述了冲突或一些个人问题)而对
+       合并提交信息上下文没啥意义,因此我需要尽力让它有意义起来。我也会
+       修复一些拼写和语法错误,特别是非母语者(母语者也是;^)。但我也会删掉
+       或增加一些内容。
+
+                       Linus
+
+Greg给出了一个拉取请求的例子::
+
+       Char/Misc patches for 4.15-rc1
+
+       Here is the big char/misc patch set for the 4.15-rc1 merge window.
+       Contained in here is the normal set of new functions added to all
+       of these crazy drivers, as well as the following brand new
+       subsystems:
+               - time_travel_controller: Finally a set of drivers for the
+                 latest time travel bus architecture that provides i/o to
+                 the CPU before it asked for it, allowing uninterrupted
+                 processing
+               - relativity_shifters: due to the affect that the
+                 time_travel_controllers have on the overall system, there
+                 was a need for a new set of relativity shifter drivers to
+                 accommodate the newly formed black holes that would
+                 threaten to suck CPUs into them.  This subsystem handles
+                 this in a way to successfully neutralize the problems.
+                 There is a Kconfig option to force these to be enabled
+                 when needed, so problems should not occur.
+
+       All of these patches have been successfully tested in the latest
+       linux-next releases, and the original problems that it found have
+       all been resolved (apologies to anyone living near Canberra for the
+       lack of the Kconfig options in the earlier versions of the
+       linux-next tree creations.)
+
+       Signed-off-by: Your-name-here <your_email@domain>
+
+
+此标记消息格式就像一个git提交。顶部有一行“总结标题”, 一定要在下面sign-off。
+
+现在您已经有了一个本地签名标记,您需要将它推送到可以被拉取的位置::
+
+       git push origin char-misc-4.15-rc1
+
+
+创建拉取请求
+------------
+
+最后要做的是创建拉取请求消息。可以使用 ``git request-pull`` 命令让 ``git``
+为你做这件事,但它需要确定你想拉取什么,以及拉取针对的基础(显示正确的拉取
+更改和变更状态)。以下命令将生成一个拉取请求::
+
+       git request-pull master git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git/ char-misc-4.15-rc1
+
+引用Greg的话::
+
+       此命令要求git比较从“char-misc-4.15-rc1”标记位置到“master”分支头(上述
+       例子中指向了我从Linus的树分叉的地方,通常是-rc发布)的差异,并去使用
+       git:// 协议拉取。如果你希望使用 https:// 协议,也可以用在这里(但是请
+       注意,部分人由于防火墙问题没法用https协议拉取)。
+
+       如果char-misc-4.15-rc1标记没有出现在我要求拉取的仓库中,git会提醒
+       它不在那里,所以记得推送到公开地方。
+
+       “git request-pull”会包含git树的地址和需要拉取的特定标记,以及标记
+       描述全文(详尽描述标记)。同时它也会创建此拉取请求的差异状态和单个
+       提交的缩短日志。
+
+Linus回复说他倾向于 ``git://`` 协议。其他维护者可能有不同的偏好。另外,请注意
+如果你创建的拉取请求没有签名标记, ``https://`` 可能是更好的选择。完整的讨论
+请看原邮件。
+
+
+提交拉取请求
+------------
+
+拉取请求的提交方式与普通补丁相同。向维护人员发送内联电子邮件并抄送LKML以及
+任何必要特定子系统的列表。对Linus的拉取请求通常有如下主题行::
+
+       [GIT PULL] <subsystem> changes for v4.15-rc1
diff --git a/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst b/Documentation/translations/zh_CN/maintainer/rebasing-and-merging.rst
new file mode 100644 (file)
index 0000000..83b7dab
--- /dev/null
@@ -0,0 +1,165 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/maintainer/rebasing-and-merging.rst
+
+:译者:
+
+ 吴想成 Wu XiangCheng <bobwxc@email.cn>
+
+==========
+变基与合并
+==========
+
+一般来说,维护子系统需要熟悉Git源代码管理系统。Git是一个功能强大的工具,有
+很多功能;就像这类工具常出现的情况一样,使用这些功能的方法有对有错。本文档
+特别介绍了变基与合并的用法。维护者经常在错误使用这些工具时遇到麻烦,但避免
+问题实际上并不那么困难。
+
+总的来说,需要注意的一点是:与许多其他项目不同,内核社区并不害怕在其开发历史
+中看到合并提交。事实上,考虑到该项目的规模,避免合并几乎是不可能的。维护者会
+在希望避免合并时遇到一些问题,而过于频繁的合并也会带来另一些问题。
+
+变基
+====
+
+“变基(Rebase)”是更改存储库中一系列提交的历史记录的过程。有两种不同型的操作
+都被称为变基,因为这两种操作都使用 ``git rebase`` 命令,但它们之间存在显著
+差异:
+
+ - 更改一系列补丁的父提交(起始提交)。例如,变基操作可以将基于上一内核版本
+   的一个补丁集重建到当前版本上。在下面的讨论中,我们将此操作称为“变根”。
+
+ - 通过修复(或删除)损坏的提交、添加补丁、添加标记以更改一系列补丁的历史,
+   来提交变更日志或更改已应用提交的顺序。在下文中,这种类型的操作称为“历史
+   修改”
+
+术语“变基”将用于指代上述两种操作。如果使用得当,变基可以产生更清晰、更整洁的
+开发历史;如果使用不当,它可能会模糊历史并引入错误。
+
+以下一些经验法则可以帮助开发者避免最糟糕的变基风险:
+
+ - 已经发布到你私人系统之外世界的历史通常不应更改。其他人可能会拉取你的树
+   的副本,然后基于它进行工作;修改你的树会给他们带来麻烦。如果工作需要变基,
+   这通常是表明它还没有准备好提交到公共存储库的信号。
+
+   但是,总有例外。有些树(linux-next是一个典型的例子)由于它们的需要经常
+   变基,开发人员知道不要基于它们来工作。开发人员有时会公开一个不稳定的分支,
+   供其他人或自动测试服务进行测试。如果您确实以这种方式公开了一个可能不稳定
+   的分支,请确保潜在使用者知道不要基于它来工作。
+
+ - 不要在包含由他人创建的历史的分支上变基。如果你从别的开发者的仓库拉取了变更,
+   那你现在就成了他们历史记录的保管人。你不应该改变它,除了少数例外情况。例如
+   树中有问题的提交必须显式恢复(即通过另一个补丁修复),而不是通过修改历史而
+   消失。
+
+ - 没有合理理由,不要对树变根。仅为了切换到更新的基或避免与上游储存库的合并
+   通常不是合理理由。
+
+ - 如果你必须对储存库进行变根,请不要随机选取一个提交作为新基。在发布节点之间
+   内核通常处于一个相对不稳定的状态;基于其中某点进行开发会增加遇到意外错误的
+   几率。当一系列补丁必须移动到新基时,请选择移动到一个稳定节点(例如-rc版本
+   节点)。
+
+ - 请知悉对补丁系列进行变根(或做明显的历史修改)会改变它们的开发环境,且很
+   可能使做过的大部分测试失效。一般来说,变基后的补丁系列应当像新代码一样对
+   待,并重新测试。
+
+合并窗口麻烦的一个常见原因是,Linus收到了一个明显在拉取请求发送之前不久才变根
+(通常是变根到随机的提交上)的补丁系列。这样一个系列被充分测试的可能性相对较
+低,拉取请求被接受的几率也同样较低。
+
+相反,如果变基仅限于私有树、提交基于一个通用的起点、且经过充分测试,则引起
+麻烦的可能性就很低。
+
+合并
+====
+
+内核开发过程中,合并是一个很常见的操作;5.1版本开发周期中有超过1126个合并
+——差不多占了整体的9%。内核开发工作积累在100多个不同的子系统树中,每个
+子系统树都可能包含多个主题分支;每个分支通常独立于其他分支进行开发。因此
+在任何给定分支进入上游储存库之前,至少需要一次合并。
+
+许多项目要求拉取请求中的分支基于当前主干,这样历史记录中就不会出现合并提交。
+内核并不是这样;任何为了避免合并而重新对分支变基都很可能导致麻烦。
+
+子系统维护人员发现他们必须进行两种类型的合并:从较低层级的子系统树和从其他
+子系统树(同级树或主线)进行合并。这两种情况下要遵循的最佳实践是不同的。
+
+合并较低层级树
+--------------
+
+较大的子系统往往有多个级别的维护人员,较低级别的维护人员向较高级别发送拉取
+请求。合并这样的请求执行几乎肯定会生成一个合并提交;这也是应该的。实际上,
+子系统维护人员可能希望在极少数快进合并情况下使用 ``-–no-ff`` 标志来强制添加
+合并提交,以便记录合并的原因。 **任何** 类型的合并的变更日志必须说明
+*为什么* 合并。对于较低级别的树,“为什么”通常是对该取所带来的变化的总结。
+
+各级维护人员都应在他们的拉取请求上使用经签名的标签,上游维护人员应在拉取分支
+时验证标签。不这样做会威胁整个开发过程的安全。
+
+根据上面列出的规则,一旦您将其他人的历史记录合并到树中,您就不得对该分支进行
+变基,即使您能够这样做。
+
+合并同级树或上游树
+------------------
+
+虽然来自下游的合并是常见且不起眼的,但当需要将一个分支推向上游时,其中来自
+其他树的合并往往是一个危险信号。这种合并需要仔细考虑并加以充分证明,否则后续
+的拉取请求很可能会被拒绝。
+
+想要将主分支合并到存储库中是很自然的;这种类型的合并通常被称为“反向合并”
+。反向合并有助于确保与并行的开发没有冲突,并且通常会给人一种温暖、舒服的
+感觉,即处于最新。但这种诱惑几乎总是应该避免的。
+
+为什么呢?反向合并将搅乱你自己分支的开发历史。它们会大大增加你遇到来自社区
+其他地方的错误的机会,且使你很难确保你所管理的工作稳定并准备好合入上游。
+频繁的合并还可以掩盖树中开发过程中的问题;它们会隐藏与其他树的交互,而这些
+交互不应该(经常)发生在管理良好的分支中。
+
+也就是说,偶尔需要进行反向合并;当这种情况发生时,一定要在提交信息中记录
+*为什么* 。同样,在一个众所周知的稳定点进行合并,而不是随机提交。即使这样,
+你也不应该反向合并一棵比你的直接上游树更高层级的树;如果确实需要更高级别的
+反向合并,应首先在上游树进行。
+
+导致合并相关问题最常见的原因之一是:在发送拉取请求之前维护者合并上游以解决
+合并冲突。同样,这种诱惑很容易理解,但绝对应该避免。对于最终拉取请求来说
+尤其如此:Linus坚信他更愿意看到合并冲突,而不是不必要的反向合并。看到冲突
+可以让他了解潜在的问题所在。他做过很多合并(在5.1版本开发周期中是382次),
+而且在解决冲突方面也很在行——通常比参与的开发人员要强。
+
+那么,当他们的子系统分支和主线之间发生冲突时,维护人员应该怎么做呢?最重要
+的一步是在拉取请求中提示Linus会发生冲突;如果啥都没说则表明您的分支可以正常
+合入。对于特别困难的冲突,创建并推送一个 *独立* 分支来展示你将如何解决问题。
+在拉取请求中提到该分支,但是请求本身应该针对未合并的分支。
+
+即使不存在已知冲突,在发送拉取请求之前进行合并测试也是个好主意。它可能会提醒
+您一些在linux-next树中没有发现的问题,并帮助您准确地理解您正在要求上游做什么。
+
+合并上游树或另一个子系统树的另一个原因是解决依赖关系。这些依赖性问题有时确实
+会发生,而且有时与另一棵树交叉合并是解决这些问题的最佳方法;同样,在这种情况
+下,合并提交应该解释为什么要进行合并。花点时间把它做好;会有人阅读这些变更
+日志。
+
+然而依赖性问题通常表明需要改变方法。合并另一个子系统树以解决依赖性风险会带来
+其他缺陷,几乎永远不应这样做。如果该子系统树无法被合到上游,那么它的任何问题
+也都会阻碍你的树合并。更可取的选择包括与维护人员达成一致意见,在其中一个树中
+同时进行两组更改;或者创建一个主题分支专门处理可以合并到两个树中的先决条件提交。
+如果依赖关系与主要的基础结构更改相关,正确的解决方案可能是将依赖提交保留一个
+开发周期,以便这些更改有时间在主线上稳定。
+
+最后
+====
+
+在开发周期的开头合并主线是比较常见的,可以获取树中其他地方的更改和修复。同样,
+这样的合并应该选择一个众所周知的发布点,而不是一些随机点。如果在合并窗口期间
+上游分支已完全清空到主线中,则可以使用以下命令向前拉取它::
+
+  git merge v5.2-rc1^0
+
+“^0”使Git执行快进合并(在这种情况下这应该可以),从而避免多余的虚假合并提交。
+
+上面列出的就是指导方针了。总是会有一些情况需要不同的解决方案,这些指导原则
+不应阻止开发人员在需要时做正确的事情。但是,我们应该时刻考虑是否真的出现了
+这样的需求,并准备好解释为什么需要做一些不寻常的事情。
diff --git a/Documentation/translations/zh_CN/parisc/debugging.rst b/Documentation/translations/zh_CN/parisc/debugging.rst
new file mode 100644 (file)
index 0000000..c21beb9
--- /dev/null
@@ -0,0 +1,42 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/parisc/debugging.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_debugging:
+
+=================
+调试PA-RISC
+=================
+
+好吧,这里有一些关于调试linux/parisc的较底层部分的信息。
+
+
+1. 绝对地址
+=====================
+
+很多汇编代码目前运行在实模式下,这意味着会使用绝对地址,而不是像内核其他
+部分那样使用虚拟地址。要将绝对地址转换为虚拟地址,你可以在System.map中查
+找,添加__PAGE_OFFSET(目前是0x10000000)。
+
+
+2. HPMCs
+========
+
+当实模式的代码试图访问不存在的内存时,会出现HPMC(high priority machine
+check)而不是内核oops。若要调试HPMC,请尝试找到系统响应程序/请求程序地址。
+系统请求程序地址应该与(某)处理器的HPA(I/O范围内的高地址)相匹配;系统响应程
+序地址是实模式代码试图访问的地址。
+
+系统响应程序地址的典型值是大于__PAGE_OFFSET (0x10000000)的地址,这意味着
+在实模式试图访问它之前,虚拟地址没有被翻译成物理地址。
+
+
+3. 有趣的Q位
+============
+
+某些非常关键的代码必须清除PSW中的Q位。当Q位被清除时,CPU不会更新中断处理
+程序所读取的寄存器,以找出机器被中断的位置——所以如果你在清除Q位的指令和再
+次设置Q位的RFI之间遇到中断,你不知道它到底发生在哪里。如果你幸运的话,IAOQ
+会指向清除Q位的指令,如果你不幸运的话,它会指向任何地方。通常Q位的问题会
+表现为无法解释的系统挂起或物理内存越界。
diff --git a/Documentation/translations/zh_CN/parisc/index.rst b/Documentation/translations/zh_CN/parisc/index.rst
new file mode 100644 (file)
index 0000000..a47454e
--- /dev/null
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/parisc/index.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_index:
+
+====================
+PA-RISC体系架构
+====================
+
+.. toctree::
+   :maxdepth: 2
+
+   debugging
+   registers
+
+Todolist:
+
+   features
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/translations/zh_CN/parisc/registers.rst b/Documentation/translations/zh_CN/parisc/registers.rst
new file mode 100644 (file)
index 0000000..71e2404
--- /dev/null
@@ -0,0 +1,153 @@
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/parisc/registers.rst
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+.. _cn_parisc_registers:
+
+=========================
+Linux/PA-RISC的寄存器用法
+=========================
+
+[ 用星号表示目前尚未实现的计划用途。 ]
+
+ABI约定的通用寄存器
+===================
+
+控制寄存器
+----------
+
+============================    =================================
+CR 0 (恢复计数器)               用于ptrace
+CR 1-CR 7(无定义)               未使用
+CR 8 (Protection ID)            每进程值*
+CR 9, 12, 13 (PIDS)             未使用
+CR10 (CCR)                      FPU延迟保存*
+CR11                            按照ABI的规定(SAR)
+CR14 (中断向量)                 初始化为 fault_vector
+CR15 (EIEM)                     所有位初始化为1*
+CR16 (间隔计时器)               读取周期数/写入开始时间间隔计时器
+CR17-CR22                       中断参数
+CR19                            中断指令寄存器
+CR20                            中断空间寄存器
+CR21                            中断偏移量寄存器
+CR22                            中断 PSW
+CR23 (EIRR)                     读取未决中断/写入清除位
+CR24 (TR 0)                     内核空间页目录指针
+CR25 (TR 1)                     用户空间页目录指针
+CR26 (TR 2)                     不使用
+CR27 (TR 3)                     线程描述符指针
+CR28 (TR 4)                     不使用
+CR29 (TR 5)                     不使用
+CR30 (TR 6)                     当前 / 0
+CR31 (TR 7)                     临时寄存器,在不同地方使用
+============================    =================================
+
+空间寄存器(内核模式)
+----------------------
+
+========                        ==============================
+SR0                             临时空间寄存器
+SR4-SR7                         设置为0
+SR1                             临时空间寄存器
+SR2                             内核不应该破坏它
+SR3                             用于用户空间访问(当前进程)
+========                        ==============================
+
+空间寄存器(用户模式)
+----------------------
+
+========                        ============================
+SR0                             临时空间寄存器
+SR1                             临时空间寄存器
+SR2                             保存Linux gateway page的空间
+SR3                             在内核中保存用户地址空间的值
+SR4-SR7                         定义了用户/内核的短地址空间
+========                        ============================
+
+
+处理器状态字
+------------
+
+======================          ================================================
+W (64位地址)                  0
+E (小尾端)                    0
+S (安全间隔计时器)            0
+T (产生分支陷阱)              0
+H (高特权级陷阱)              0
+L (低特权级陷阱)              0
+N (撤销下一条指令)            被C代码使用
+X (数据存储中断禁用)          0
+B (产生分支)                  被C代码使用
+C (代码地址转译)              1, 在执行实模式代码时为0
+V (除法步长校正)              被C代码使用
+M (HPMC 掩码)                 0, 在执行HPMC操作*时为1
+C/B (进/借 位)                被C代码使用
+O (有序引用)                  1*
+F (性能监视器)                0
+R (回收计数器陷阱)            0
+Q (收集中断状态)              1 (在rfi之前的代码中为0)
+P (保护标识符)                1*
+D (数据地址转译)              1, 在执行实模式代码时为0
+I (外部中断掩码)              由cli()/sti()宏使用。
+======================          ================================================
+
+“隐形”寄存器(影子寄存器)
+---------------------------
+
+=============                   ===================
+PSW W 默认值                    0
+PSW E 默认值                    0
+影子寄存器                      被中断处理代码使用
+TOC启用位                       1
+=============                   ===================
+
+----------------------------------------------------------
+
+PA-RISC架构定义了7个寄存器作为“影子寄存器”。这些寄存器在
+RETURN FROM INTERRUPTION AND RESTORE指令中使用,通过消
+除中断处理程序中对一般寄存器(GR)的保存和恢复的需要来减
+少状态保存和恢复时间。影子寄存器是GRs 1, 8, 9, 16, 17,
+24和25。
+
+-------------------------------------------------------------------------
+
+寄存器使用说明,最初由John Marvin提供,并由Randolph Chung提供一些补充说明。
+
+对于通用寄存器:
+
+r1,r2,r19-r26,r28,r29 & r31可以在不保存它们的情况下被使用。当然,如果你
+关心它们,在调用另一个程序之前,你也需要保存它们。上面的一些寄存器确实
+有特殊的含义,你应该注意一下:
+
+    r1:
+       addil指令是硬性规定将其结果放在r1中,所以如果你使用这条指令要
+       注意这点。
+
+    r2:
+       这就是返回指针。一般来说,你不想使用它,因为你需要这个指针来返
+       回给你的调用者。然而,它与这组寄存器组合在一起,因为调用者不能
+       依赖你返回时的值是相同的,也就是说,你可以将r2复制到另一个寄存
+       器,并在作废r2后通过该寄存器返回,这应该不会给调用程序带来问题。
+
+    r19-r22:
+       这些通常被认为是临时寄存器。
+       请注意,在64位中它们是arg7-arg4。
+
+    r23-r26:
+       这些是arg3-arg0,也就是说,如果你不再关心传入的值,你可以使用
+       它们。
+
+    r28,r29:
+       这俩是ret0和ret1。它们是你传入返回值的地方。r28是主返回值。当返回
+       小结构体时,r29也可以用来将数据传回给调用程序。
+
+    r30:
+       栈指针
+
+    r31:
+       ble指令将返回指针放在这里。
+
+
+    r3-r18,r27,r30需要被保存和恢复。r3-r18只是一般用途的寄存器。
+    r27是数据指针,用来使对全局变量的引用更容易。r30是栈指针。
index 71c3e30..4707f01 100644 (file)
@@ -19,7 +19,7 @@
 :ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>`
 文件是一个重要的起点;
 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
-和 :ref:`Documentation/transaltions/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>`
+和 :ref:`Documentation/translations/zh_CN/process/submitting-drivers.rst <cn_submittingdrivers>`
 也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制
 记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档
 (尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。
index 406d43a..b8c484a 100644 (file)
@@ -61,7 +61,7 @@ Linux 内核代码风格
        case 'K':
        case 'k':
                mem <<= 10;
-               /* fall through */
+               fallthrough;
        default:
                break;
        }
index 31f650e..7619050 100644 (file)
@@ -1,4 +1,4 @@
-===========
+===========
 EHCI driver
 ===========
 
index 5e5516c..e611a6d 100644 (file)
@@ -1,4 +1,4 @@
-===============================
+===============================
 Linux USB Printer Gadget Driver
 ===============================
 
index 817371b..6ee8fc8 100644 (file)
@@ -7,8 +7,8 @@ Summary of `HDIO_` ioctl calls
 November, 2004
 
 This document attempts to describe the ioctl(2) calls supported by
-the HD/IDE layer.  These are by-and-large implemented (as of Linux 2.6)
-in drivers/ide/ide.c and drivers/block/scsi_ioctl.c
+the HD/IDE layer.  These are by-and-large implemented (as of Linux 5.11)
+drivers/ata/libata-scsi.c.
 
 ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
 are as follows:
@@ -17,50 +17,17 @@ are as follows:
 
        ======================= =======================================
        HDIO_GETGEO             get device geometry
-       HDIO_GET_UNMASKINTR     get current unmask setting
-       HDIO_GET_MULTCOUNT      get current IDE blockmode setting
-       HDIO_GET_QDMA           get use-qdma flag
-       HDIO_SET_XFER           set transfer rate via proc
-       HDIO_OBSOLETE_IDENTITY  OBSOLETE, DO NOT USE
-       HDIO_GET_KEEPSETTINGS   get keep-settings-on-reset flag
        HDIO_GET_32BIT          get current io_32bit setting
-       HDIO_GET_NOWERR         get ignore-write-error flag
-       HDIO_GET_DMA            get use-dma flag
-       HDIO_GET_NICE           get nice flags
        HDIO_GET_IDENTITY       get IDE identification info
-       HDIO_GET_WCACHE         get write cache mode on|off
-       HDIO_GET_ACOUSTIC       get acoustic value
-       HDIO_GET_ADDRESS        get sector addressing mode
-       HDIO_GET_BUSSTATE       get the bus state of the hwif
-       HDIO_TRISTATE_HWIF      execute a channel tristate
-       HDIO_DRIVE_RESET        execute a device reset
        HDIO_DRIVE_TASKFILE     execute raw taskfile
        HDIO_DRIVE_TASK         execute task and special drive command
        HDIO_DRIVE_CMD          execute a special drive command
-       HDIO_DRIVE_CMD_AEB      HDIO_DRIVE_TASK
        ======================= =======================================
 
     ioctls that pass non-pointer values:
 
        ======================= =======================================
-       HDIO_SET_MULTCOUNT      change IDE blockmode
-       HDIO_SET_UNMASKINTR     permit other irqs during I/O
-       HDIO_SET_KEEPSETTINGS   keep ioctl settings on reset
        HDIO_SET_32BIT          change io_32bit flags
-       HDIO_SET_NOWERR         change ignore-write-error flag
-       HDIO_SET_DMA            change use-dma flag
-       HDIO_SET_PIO_MODE       reconfig interface to new speed
-       HDIO_SCAN_HWIF          register and (re)scan interface
-       HDIO_SET_NICE           set nice flags
-       HDIO_UNREGISTER_HWIF    unregister interface
-       HDIO_SET_WCACHE         change write cache enable-disable
-       HDIO_SET_ACOUSTIC       change acoustic behavior
-       HDIO_SET_BUSSTATE       set the bus state of the hwif
-       HDIO_SET_QDMA           change use-qdma flag
-       HDIO_SET_ADDRESS        change lba addressing modes
-
-       HDIO_SET_IDE_SCSI       Set scsi emulation mode on/off
-       HDIO_SET_SCSI_IDE       not implemented yet
        ======================= =======================================
 
 
@@ -137,512 +104,49 @@ HDIO_GETGEO
 
 
 
-
-HDIO_GET_UNMASKINTR
-       get current unmask setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_UNMASKINTR, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the drive's current unmask setting
-
-
-
-
-
-HDIO_SET_UNMASKINTR
-       permit other irqs during I/O
-
-
-       usage::
-
-         unsigned long val;
-
-         ioctl(fd, HDIO_SET_UNMASKINTR, val);
-
-       inputs:
-               New value for unmask flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-
-HDIO_GET_MULTCOUNT
-       get current IDE blockmode setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_MULTCOUNT, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current IDE block mode setting.  This
-               controls how many sectors the drive will transfer per
-               interrupt.
-
-
-
-HDIO_SET_MULTCOUNT
-       change IDE blockmode
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_MULTCOUNT, val);
-
-       inputs:
-               New value for IDE block mode setting.  This controls how many
-               sectors the drive will transfer per interrupt.
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range supported by disk.
-         - EBUSY       Controller busy or blockmode already set.
-         - EIO         Drive did not accept new block mode.
-
-       notes:
-         Source code comments read::
-
-           This is tightly woven into the driver->do_special cannot
-           touch.  DON'T do it again until a total personality rewrite
-           is committed.
-
-         If blockmode has already been set, this ioctl will fail with
-         -EBUSY
-
-
-
-HDIO_GET_QDMA
-       get use-qdma flag
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_XFER
-       set transfer rate via proc
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_OBSOLETE_IDENTITY
-       OBSOLETE, DO NOT USE
-
-
-       Same as HDIO_GET_IDENTITY (see below), except that it only
-       returns the first 142 bytes of drive identity information.
-
-
-
-HDIO_GET_IDENTITY
-       get IDE identification info
-
-
-       usage::
-
-         unsigned char identity[512];
-
-         ioctl(fd, HDIO_GET_IDENTITY, identity);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               ATA drive identity information.  For full description, see
-               the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in
-               the ATA specification.
-
-       error returns:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - ENOMSG      IDENTIFY DEVICE information not available
-
-       notes:
-               Returns information that was obtained when the drive was
-               probed.  Some of this information is subject to change, and
-               this ioctl does not re-probe the drive to update the
-               information.
-
-               This information is also available from /proc/ide/hdX/identify
-
-
-
-HDIO_GET_KEEPSETTINGS
-       get keep-settings-on-reset flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_KEEPSETTINGS, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current "keep settings" flag
-
-
-
-       notes:
-               When set, indicates that kernel should restore settings
-               after a drive reset.
-
-
-
-HDIO_SET_KEEPSETTINGS
-       keep ioctl settings on reset
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_KEEPSETTINGS, val);
-
-       inputs:
-               New value for keep_settings flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY               Controller busy
-
-
-
-HDIO_GET_32BIT
-       get current io_32bit setting
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_32BIT, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current io_32bit setting
-
-
-
-       notes:
-               0=16-bit, 1=32-bit, 2,3 = 32bit+sync
-
-
-
-
-
-HDIO_GET_NOWERR
-       get ignore-write-error flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_NOWERR, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current ignore-write-error flag
-
-
-
-
-
-HDIO_GET_DMA
-       get use-dma flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_DMA, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current use-dma flag
-
-
-
-
-
-HDIO_GET_NICE
-       get nice flags
-
-
-       usage::
-
-         long nice;
-
-         ioctl(fd, HDIO_GET_NICE, &nice);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The drive's "nice" values.
-
-
-
-       notes:
-               Per-drive flags which determine when the system will give more
-               bandwidth to other devices sharing the same IDE bus.
-
-               See <linux/hdreg.h>, near symbol IDE_NICE_DSC_OVERLAP.
-
-
-
-
-HDIO_SET_NICE
-       set nice flags
-
-
-       usage::
-
-         unsigned long nice;
-
-         ...
-         ioctl(fd, HDIO_SET_NICE, nice);
-
-       inputs:
-               bitmask of nice flags.
-
-
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EPERM       Flags other than DSC_OVERLAP and NICE_1 set.
-         - EPERM       DSC_OVERLAP specified but not supported by drive
-
-       notes:
-               This ioctl sets the DSC_OVERLAP and NICE_1 flags from values
-               provided by the user.
-
-               Nice flags are listed in <linux/hdreg.h>, starting with
-               IDE_NICE_DSC_OVERLAP.  These values represent shifts.
-
-
-
-
-
-HDIO_GET_WCACHE
-       get write cache mode on|off
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_WCACHE, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current write cache mode
-
-
-
-
-
-HDIO_GET_ACOUSTIC
-       get acoustic value
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_GET_ACOUSTIC, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current acoustic settings
-
-
-
-       notes:
-               See HDIO_SET_ACOUSTIC
-
-
-
-
-
-HDIO_GET_ADDRESS
-       usage::
-
-
-         long val;
-
-         ioctl(fd, HDIO_GET_ADDRESS, &val);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               The value of the current addressing mode:
-
-           =  ===================
-           0  28-bit
-           1  48-bit
-           2  48-bit doing 28-bit
-           3  64-bit
-           =  ===================
-
-
-
-HDIO_GET_BUSSTATE
-       get the bus state of the hwif
-
-
-       usage::
-
-         long state;
-
-         ioctl(fd, HDIO_SCAN_HWIF, &state);
-
-       inputs:
-               none
-
-
-
-       outputs:
-               Current power state of the IDE bus.  One of BUSSTATE_OFF,
-               BUSSTATE_ON, or BUSSTATE_TRISTATE
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-
-
-
-
-HDIO_SET_BUSSTATE
-       set the bus state of the hwif
+HDIO_GET_IDENTITY
+       get IDE identification info
 
 
        usage::
 
-         int state;
+         unsigned char identity[512];
 
-         ...
-         ioctl(fd, HDIO_SCAN_HWIF, state);
+         ioctl(fd, HDIO_GET_IDENTITY, identity);
 
        inputs:
-               Desired IDE power state.  One of BUSSTATE_OFF, BUSSTATE_ON,
-               or BUSSTATE_TRISTATE
-
-       outputs:
                none
 
 
 
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - EOPNOTSUPP  Hardware interface does not support bus power control
-
-
-
+       outputs:
+               ATA drive identity information.  For full description, see
+               the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in
+               the ATA specification.
 
-HDIO_TRISTATE_HWIF
-       execute a channel tristate
+       error returns:
+         - EINVAL      Called on a partition instead of the whole disk device
+         - ENOMSG      IDENTIFY DEVICE information not available
 
+       notes:
+               Returns information that was obtained when the drive was
+               probed.  Some of this information is subject to change, and
+               this ioctl does not re-probe the drive to update the
+               information.
 
-       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
+               This information is also available from /proc/ide/hdX/identify
 
 
 
-HDIO_DRIVE_RESET
-       execute a device reset
+HDIO_GET_32BIT
+       get current io_32bit setting
 
 
        usage::
 
-         int args[3]
+         long val;
 
-         ...
-         ioctl(fd, HDIO_DRIVE_RESET, args);
+         ioctl(fd, HDIO_GET_32BIT, &val);
 
        inputs:
                none
@@ -650,22 +154,12 @@ HDIO_DRIVE_RESET
 
 
        outputs:
-               none
-
+               The value of the current io_32bit setting
 
 
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - ENXIO       No such device: phy dead or ctl_addr == 0
-         - EIO         I/O error:      reset timed out or hardware error
 
        notes:
-
-         - Execute a reset on the device as soon as the current IO
-           operation has completed.
-
-         - Executes an ATAPI soft reset if applicable, otherwise
-           executes an ATA soft reset on the controller.
+               0=16-bit, 1=32-bit, 2,3 = 32bit+sync
 
 
 
@@ -1026,14 +520,6 @@ HDIO_DRIVE_TASK
 
 
 
-HDIO_DRIVE_CMD_AEB
-       HDIO_DRIVE_TASK
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
 HDIO_SET_32BIT
        change io_32bit flags
 
@@ -1059,284 +545,3 @@ HDIO_SET_32BIT
          - EACCES      Access denied:  requires CAP_SYS_ADMIN
          - EINVAL      value out of range [0 3]
          - EBUSY       Controller busy
-
-
-
-
-HDIO_SET_NOWERR
-       change ignore-write-error flag
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_NOWERR, val);
-
-       inputs:
-               New value for ignore-write-error flag.  Used for ignoring
-
-
-         WRERR_STAT
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY               Controller busy
-
-
-
-HDIO_SET_DMA
-       change use-dma flag
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_DMA, val);
-
-       inputs:
-               New value for use-dma flag
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_PIO_MODE
-       reconfig interface to new speed
-
-
-       usage::
-
-         long val;
-
-         ioctl(fd, HDIO_SET_PIO_MODE, val);
-
-       inputs:
-               New interface speed.
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 255]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SCAN_HWIF
-       register and (re)scan interface
-
-
-       usage::
-
-         int args[3]
-
-         ...
-         ioctl(fd, HDIO_SCAN_HWIF, args);
-
-       inputs:
-
-         =======       =========================
-         args[0]       io address to probe
-
-
-         args[1]       control address to probe
-         args[2]       irq number
-         =======       =========================
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-         - EIO         Probe failed.
-
-       notes:
-               This ioctl initializes the addresses and irq for a disk
-               controller, probes for drives, and creates /proc/ide
-               interfaces as appropriate.
-
-
-
-HDIO_UNREGISTER_HWIF
-       unregister interface
-
-
-       usage::
-
-         int index;
-
-         ioctl(fd, HDIO_UNREGISTER_HWIF, index);
-
-       inputs:
-               index           index of hardware interface to unregister
-
-
-
-       outputs:
-               none
-
-
-
-       error returns:
-         - EACCES      Access denied:  requires CAP_SYS_RAWIO
-
-       notes:
-               This ioctl removes a hardware interface from the kernel.
-
-               Currently (2.6.8) this ioctl silently fails if any drive on
-               the interface is busy.
-
-
-
-HDIO_SET_WCACHE
-       change write cache enable-disable
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_WCACHE, val);
-
-       inputs:
-               New value for write cache enable
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_ACOUSTIC
-       change acoustic behavior
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_ACOUSTIC, val);
-
-       inputs:
-               New value for drive acoustic settings
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 254]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_QDMA
-       change use-qdma flag
-
-
-       Not implemented, as of 2.6.8.1
-
-
-
-HDIO_SET_ADDRESS
-       change lba addressing modes
-
-
-       usage::
-
-         int val;
-
-         ioctl(fd, HDIO_SET_ADDRESS, val);
-
-       inputs:
-               New value for addressing mode
-
-           =   ===================
-           0   28-bit
-           1   48-bit
-           2   48-bit doing 28-bit
-           =   ===================
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 2]
-         - EBUSY               Controller busy
-         - EIO         Drive does not support lba48 mode.
-
-
-HDIO_SET_IDE_SCSI
-       usage::
-
-
-         long val;
-
-         ioctl(fd, HDIO_SET_IDE_SCSI, val);
-
-       inputs:
-               New value for scsi emulation mode (?)
-
-
-
-       outputs:
-               none
-
-
-
-       error return:
-         - EINVAL      Called on a partition instead of the whole disk device
-         - EACCES      Access denied:  requires CAP_SYS_ADMIN
-         - EINVAL      value out of range [0 1]
-         - EBUSY       Controller busy
-
-
-
-HDIO_SET_SCSI_IDE
-       Not implemented, as of 2.6.8.1
index 62c9361..f35552f 100644 (file)
@@ -145,7 +145,8 @@ Bind mounts and OverlayFS
 
 Landlock enables to restrict access to file hierarchies, which means that these
 access rights can be propagated with bind mounts (cf.
-:doc:`/filesystems/sharedsubtree`) but not with :doc:`/filesystems/overlayfs`.
+Documentation/filesystems/sharedsubtree.rst) but not with
+Documentation/filesystems/overlayfs.rst.
 
 A bind mount mirrors a source file hierarchy to a destination.  The destination
 hierarchy is then composed of the exact same files, on which Landlock rules can
@@ -170,8 +171,8 @@ Inheritance
 
 Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain
 restrictions from its parent.  This is similar to the seccomp inheritance (cf.
-:doc:`/userspace-api/seccomp_filter`) or any other LSM dealing with task's
-:manpage:`credentials(7)`.  For instance, one process's thread may apply
+Documentation/userspace-api/seccomp_filter.rst) or any other LSM dealing with
+task's :manpage:`credentials(7)`.  For instance, one process's thread may apply
 Landlock rules to itself, but they will not be automatically applied to other
 sibling threads (unlike POSIX thread credential changes, cf.
 :manpage:`nptl(7)`).
@@ -278,7 +279,7 @@ Memory usage
 ------------
 
 Kernel memory allocated to create rulesets is accounted and can be restricted
-by the :doc:`/admin-guide/cgroup-v1/memory`.
+by the Documentation/admin-guide/cgroup-v1/memory.rst.
 
 Questions and answers
 =====================
@@ -303,7 +304,7 @@ issues, especially when untrusted processes can manipulate them (cf.
 Additional documentation
 ========================
 
-* :doc:`/security/landlock`
+* Documentation/security/landlock.rst
 * https://landlock.io
 
 .. Links
index 81a4a1a..00922aa 100644 (file)
@@ -7,8 +7,8 @@ PARSER = $(srctree)/Documentation/sphinx/parse-headers.pl
 UAPI = $(srctree)/include/uapi/linux
 KAPI = $(srctree)/include/linux
 
-FILES = audio.h.rst ca.h.rst dmx.h.rst frontend.h.rst net.h.rst video.h.rst \
-         videodev2.h.rst media.h.rst cec.h.rst lirc.h.rst
+FILES = ca.h.rst dmx.h.rst frontend.h.rst net.h.rst \
+       videodev2.h.rst media.h.rst cec.h.rst lirc.h.rst
 
 TARGETS := $(addprefix $(BUILDDIR)/, $(FILES))
 
@@ -21,9 +21,6 @@ quiet_gen_rst = echo '  PARSE   $(patsubst $(srctree)/%,%,$<)'; \
 
 silent_gen_rst = ${gen_rst}
 
-$(BUILDDIR)/audio.h.rst: ${UAPI}/dvb/audio.h ${PARSER} $(SRC_DIR)/audio.h.rst.exceptions
-       @$($(quiet)gen_rst)
-
 $(BUILDDIR)/ca.h.rst: ${UAPI}/dvb/ca.h ${PARSER} $(SRC_DIR)/ca.h.rst.exceptions
        @$($(quiet)gen_rst)
 
@@ -36,9 +33,6 @@ $(BUILDDIR)/frontend.h.rst: ${UAPI}/dvb/frontend.h ${PARSER} $(SRC_DIR)/frontend
 $(BUILDDIR)/net.h.rst: ${UAPI}/dvb/net.h ${PARSER} $(SRC_DIR)/net.h.rst.exceptions
        @$($(quiet)gen_rst)
 
-$(BUILDDIR)/video.h.rst: ${UAPI}/dvb/video.h ${PARSER} $(SRC_DIR)/video.h.rst.exceptions
-       @$($(quiet)gen_rst)
-
 $(BUILDDIR)/videodev2.h.rst: ${UAPI}/videodev2.h ${PARSER} $(SRC_DIR)/videodev2.h.rst.exceptions
        @$($(quiet)gen_rst)
 
diff --git a/Documentation/userspace-api/media/audio.h.rst.exceptions b/Documentation/userspace-api/media/audio.h.rst.exceptions
deleted file mode 100644 (file)
index cf66204..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# Ignore header name
-ignore define _DVBAUDIO_H_
-
-# Undocumented audio caps, as this is a deprecated API anyway
-ignore define AUDIO_CAP_DTS
-ignore define AUDIO_CAP_LPCM
-ignore define AUDIO_CAP_MP1
-ignore define AUDIO_CAP_MP2
-ignore define AUDIO_CAP_MP3
-ignore define AUDIO_CAP_AAC
-ignore define AUDIO_CAP_OGG
-ignore define AUDIO_CAP_SDDS
-ignore define AUDIO_CAP_AC3
-
-# some typedefs should point to struct/enums
-replace typedef audio_mixer_t :c:type:`audio_mixer`
-replace typedef audio_status_t :c:type:`audio_status`
diff --git a/Documentation/userspace-api/media/drivers/hantro.rst b/Documentation/userspace-api/media/drivers/hantro.rst
new file mode 100644 (file)
index 0000000..cd9754b
--- /dev/null
@@ -0,0 +1,19 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Hantro video decoder driver
+===========================
+
+The Hantro video decoder driver implements the following driver-specific controls:
+
+``V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (integer)``
+    Specifies to Hantro HEVC video decoder driver the number of data (in bits) to
+    skip in the slice segment header.
+    If non-IDR, the bits to be skipped go from syntax element "pic_output_flag"
+    to before syntax element "slice_temporal_mvp_enabled_flag".
+    If IDR, the skipped bits are just "pic_output_flag"
+    (separate_colour_plane_flag is not supported).
+
+.. note::
+
+        This control is not yet part of the public kernel API and
+        it is expected to change.
index 1a9038f..12e3c51 100644 (file)
@@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux.
 
        ccs
        cx2341x-uapi
+        hantro
        imx-uapi
        max2175
        meye-uapi
index 8f0a2b8..50b36eb 100644 (file)
@@ -82,7 +82,7 @@ appropriately.
     :widths: 1 16
 
     -  -  ``EMFILE``
-       -  “Too many open files”, i.e. no more filters available.
+       -  "Too many open files", i.e. no more filters available.
 
 The generic error codes are described at the
 :ref:`Generic Error Codes <gen-errors>` chapter.
index 78e9dae..88c4cdd 100644 (file)
@@ -34,7 +34,7 @@ Description
 
 This system call returns filtered data, which might be section or Packetized
 Elementary Stream (PES) data. The filtered data is transferred from
-the drivers internal circular buffer to ``buf``. The maximum amount of data
+the driver's internal circular buffer to ``buf``. The maximum amount of data
 to be transferred is implied by count.
 
 .. note::
index f43455b..1b8c807 100644 (file)
@@ -37,7 +37,7 @@ parameters provided. A timeout may be defined stating number of seconds
 to wait for a section to be loaded. A value of 0 means that no timeout
 should be applied. Finally there is a flag field where it is possible to
 state whether a section should be CRC-checked, whether the filter should
-be a ”one-shot” filter, i.e. if the filtering operation should be
+be a "one-shot" filter, i.e. if the filtering operation should be
 stopped after the first section is received, and whether the filtering
 operation should be started immediately (without waiting for a
 :ref:`DMX_START` ioctl call). If a filter was previously set-up, this
index 9743ffc..88c3eb3 100644 (file)
@@ -14,10 +14,3 @@ Digital TV uAPI headers
 .. kernel-include:: $BUILDDIR/ca.h.rst
 
 .. kernel-include:: $BUILDDIR/net.h.rst
-
-Legacy uAPI
-***********
-
-.. kernel-include:: $BUILDDIR/audio.h.rst
-
-.. kernel-include:: $BUILDDIR/video.h.rst
index a935f39..6784ae7 100644 (file)
@@ -107,7 +107,7 @@ Audio and video decoder
       a Systems on a Chip (SoC) integrated circuit.
 
       It may also not be needed for certain usages (e.g. for data-only
-      uses like “internet over satellite”).
+      uses like "internet over satellite").
 
 :ref:`stb_components` shows a crude schematic of the control and data
 flow between those components.
@@ -148,9 +148,9 @@ individual devices are called:
 
 -  ``/dev/dvb/adapterN/caM``,
 
-where ``N`` enumerates the Digital TV cards in a system starting from 0, and
+where ``N`` enumerates the Digital TV cards in a system starting from 0, and
 ``M`` enumerates the devices of each type within each adapter, starting
-from 0, too. We will omit the “``/dev/dvb/adapterN/``\ ” in the further
+from 0, too. We will omit the "``/dev/dvb/adapterN/``\ " in the further
 discussion of these devices.
 
 More details about the data structures and function calls of all the
index 6104879..b97d56e 100644 (file)
@@ -11,11 +11,6 @@ The APIs described here **should not** be used on new drivers or applications.
 The DVBv3 frontend API has issues with new delivery systems, including
 DVB-S2, DVB-T2, ISDB, etc.
 
-There's just one driver for a very legacy hardware using the Digital TV
-audio and video APIs. No modern drivers should use it. Instead, audio and
-video should be using the V4L2 and ALSA APIs, and the pipelines should
-be set via the Media Controller API.
-
 .. attention::
 
    The APIs described here doesn't necessarily reflect the current
@@ -28,5 +23,3 @@ be set via the Media Controller API.
     :maxdepth: 1
 
     frontend_legacy_dvbv3_api
-    video
-    audio
index 683ebed..b1bc725 100644 (file)
@@ -13,14 +13,14 @@ GNU Free Documentation License
 ===========
 
 The purpose of this License is to make a manual, textbook, or other
-written document “free” in the sense of freedom: to assure everyone the
+written document "free" in the sense of freedom: to assure everyone the
 effective freedom to copy and redistribute it, with or without modifying
 it, either commercially or noncommercially. Secondarily, this License
 preserves for the author and publisher a way to get credit for their
 work, while not being considered responsible for modifications made by
 others.
 
-This License is a kind of “copyleft”, which means that derivative works
+This License is a kind of "copyleft", which means that derivative works
 of the document must themselves be free in the same sense. It
 complements the GNU General Public License, which is a copyleft license
 designed for free software.
@@ -44,21 +44,21 @@ works whose purpose is instruction or reference.
 
 This License applies to any manual or other work that contains a notice
 placed by the copyright holder saying it can be distributed under the
-terms of this License. The “Document”, below, refers to any such manual
+terms of this License. The "Document", below, refers to any such manual
 or work. Any member of the public is a licensee, and is addressed as
-“you”.
+"you".
 
 
 .. _fdl-modified:
 
-A “Modified Version” of the Document means any work containing the
+A "Modified Version" of the Document means any work containing the
 Document or a portion of it, either copied verbatim, or with
 modifications and/or translated into another language.
 
 
 .. _fdl-secondary:
 
-A “Secondary Section” is a named appendix or a front-matter section of
+A "Secondary Section" is a named appendix or a front-matter section of
 the :ref:`Document <fdl-document>` that deals exclusively with the
 relationship of the publishers or authors of the Document to the
 Document's overall subject (or to related matters) and contains nothing
@@ -72,7 +72,7 @@ regarding them.
 
 .. _fdl-invariant:
 
-The “Invariant Sections” are certain
+The "Invariant Sections" are certain
 :ref:`Secondary Sections <fdl-secondary>` whose titles are designated,
 as being those of Invariant Sections, in the notice that says that the
 :ref:`Document <fdl-document>` is released under this License.
@@ -80,14 +80,14 @@ as being those of Invariant Sections, in the notice that says that the
 
 .. _fdl-cover-texts:
 
-The “Cover Texts” are certain short passages of text that are listed, as
+The "Cover Texts" are certain short passages of text that are listed, as
 Front-Cover Texts or Back-Cover Texts, in the notice that says that the
 :ref:`Document <fdl-document>` is released under this License.
 
 
 .. _fdl-transparent:
 
-A “Transparent” copy of the :ref:`Document <fdl-document>` means a
+A "Transparent" copy of the :ref:`Document <fdl-document>` means a
 machine-readable copy, represented in a format whose specification is
 available to the general public, whose contents can be viewed and edited
 directly and straightforwardly with generic text editors or (for images
@@ -97,7 +97,7 @@ formatters or for automatic translation to a variety of formats suitable
 for input to text formatters. A copy made in an otherwise Transparent
 file format whose markup has been designed to thwart or discourage
 subsequent modification by readers is not Transparent. A copy that is
-not “Transparent” is called “Opaque”.
+not "Transparent" is called "Opaque".
 
 Examples of suitable formats for Transparent copies include plain ASCII
 without markup, Texinfo input format, LaTeX input format, SGML or XML
@@ -111,10 +111,10 @@ word processors for output purposes only.
 
 .. _fdl-title-page:
 
-The “Title Page” means, for a printed book, the title page itself, plus
+The "Title Page" means, for a printed book, the title page itself, plus
 such following pages as are needed to hold, legibly, the material this
 License requires to appear in the title page. For works in formats which
-do not have any title page as such, “Title Page” means the text near the
+do not have any title page as such, "Title Page" means the text near the
 most prominent appearance of the work's title, preceding the beginning
 of the body of the text.
 
@@ -242,11 +242,11 @@ Modified Version:
    Include an unaltered copy of this License.
 
 -  **I.**
-   Preserve the section entitled “History”, and its title, and add to it
+   Preserve the section entitled "History", and its title, and add to it
    an item stating at least the title, year, new authors, and publisher
    of the :ref:`Modified Version <fdl-modified>` as given on the
    :ref:`Title Page <fdl-title-page>`. If there is no section entitled
-   “History” in the :ref:`Document <fdl-document>`, create one stating
+   "History" in the :ref:`Document <fdl-document>`, create one stating
    the title, year, authors, and publisher of the Document as given on
    its Title Page, then add an item describing the Modified Version as
    stated in the previous sentence.
@@ -256,13 +256,13 @@ Modified Version:
    :ref:`Document <fdl-document>` for public access to a
    :ref:`Transparent <fdl-transparent>` copy of the Document, and
    likewise the network locations given in the Document for previous
-   versions it was based on. These may be placed in the “History”
+   versions it was based on. These may be placed in the "History"
    section. You may omit a network location for a work that was
    published at least four years before the Document itself, or if the
    original publisher of the version it refers to gives permission.
 
 -  **K.**
-   In any section entitled “Acknowledgements” or “Dedications”, preserve
+   In any section entitled "Acknowledgements" or "Dedications", preserve
    the section's title, and preserve in the section all the substance
    and tone of each of the contributor acknowledgements and/or
    dedications given therein.
@@ -274,11 +274,11 @@ Modified Version:
    part of the section titles.
 
 -  **M.**
-   Delete any section entitled “Endorsements”. Such a section may not be
+   Delete any section entitled "Endorsements". Such a section may not be
    included in the :ref:`Modified Version <fdl-modified>`.
 
 -  **N.**
-   Do not retitle any existing section as “Endorsements” or to conflict
+   Do not retitle any existing section as "Endorsements" or to conflict
    in title with any :ref:`Invariant Section <fdl-invariant>`.
 
 If the :ref:`Modified Version <fdl-modified>` includes new
@@ -290,7 +290,7 @@ of :ref:`Invariant Sections <fdl-invariant>` in the Modified Version's
 license notice. These titles must be distinct from any other section
 titles.
 
-You may add a section entitled “Endorsements”, provided it contains
+You may add a section entitled "Endorsements", provided it contains
 nothing but endorsements of your
 :ref:`Modified Version <fdl-modified>` by various parties--for
 example, statements of peer review or that the text has been approved by
@@ -337,11 +337,11 @@ the original author or publisher of that section if known, or else a
 unique number. Make the same adjustment to the section titles in the
 list of Invariant Sections in the license notice of the combined work.
 
-In the combination, you must combine any sections entitled “History” in
-the various original documents, forming one section entitled “History”;
-likewise combine any sections entitled “Acknowledgements”, and any
-sections entitled “Dedications”. You must delete all sections entitled
-“Endorsements.”
+In the combination, you must combine any sections entitled "History" in
+the various original documents, forming one section entitled "History";
+likewise combine any sections entitled "Acknowledgements", and any
+sections entitled "Dedications". You must delete all sections entitled
+"Endorsements."
 
 
 .. _fdl-section6:
@@ -372,7 +372,7 @@ with other separate and independent documents or works, in or on a
 volume of a storage or distribution medium, does not as a whole count as
 a :ref:`Modified Version <fdl-modified>` of the Document, provided no
 compilation copyright is claimed for the compilation. Such a compilation
-is called an “aggregate”, and this License does not apply to the other
+is called an "aggregate", and this License does not apply to the other
 self-contained works thus compiled with the Document , on account of
 their being thus compiled, if they are not themselves derivative works
 of the Document. If the :ref:`Cover Text <fdl-cover-texts>`
@@ -429,7 +429,7 @@ concerns. See
 
 Each version of the License is given a distinguishing version number. If
 the :ref:`Document <fdl-document>` specifies that a particular
-numbered version of this License “or any later version” applies to it,
+numbered version of this License "or any later version" applies to it,
 you have the option of following the terms and conditions either of that
 specified version or of any later version that has been published (not
 as a draft) by the Free Software Foundation. If the Document does not
@@ -455,13 +455,13 @@ notices just after the title page:
     being LIST THEIR TITLES, with the
     :ref:`Front-Cover Texts <fdl-cover-texts>` being LIST, and with
     the :ref:`Back-Cover Texts <fdl-cover-texts>` being LIST. A copy
-    of the license is included in the section entitled GNU Free
-    Documentation License.
+    of the license is included in the section entitled "GNU Free
+    Documentation License".
 
-If you have no :ref:`Invariant Sections <fdl-invariant>`, write with
-no Invariant Sections instead of saying which ones are invariant. If
-you have no :ref:`Front-Cover Texts <fdl-cover-texts>`, write no
-Front-Cover Texts” instead of “Front-Cover Texts being LIST”; likewise
+If you have no :ref:`Invariant Sections <fdl-invariant>`, write "with
+no Invariant Sections" instead of saying which ones are invariant. If
+you have no :ref:`Front-Cover Texts <fdl-cover-texts>`, write "no
+Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise
 for :ref:`Back-Cover Texts <fdl-cover-texts>`.
 
 If your document contains nontrivial examples of program code, we
index cb165d7..96a360e 100644 (file)
@@ -116,7 +116,7 @@ Glossary
          - :term:`RC API`; and
          - :term:`V4L2 API`.
 
-       See :doc:`index`.
+       See Documentation/userspace-api/media/index.rst.
 
     MC API
        **Media Controller API**
index 7f42f83..d839904 100644 (file)
@@ -11,12 +11,14 @@ used by media devices.
 
 Please see:
 
-- :doc:`/admin-guide/media/index`
-    for usage information about media subsystem and supported drivers;
+Documentation/admin-guide/media/index.rst
 
-- :doc:`/driver-api/media/index`
-     for driver development information and Kernel APIs used by
-     media devices;
+  - for usage information about media subsystem and supported drivers;
+
+Documentation/driver-api/media/index.rst
+
+  - for driver development information and Kernel APIs used by
+    media devices;
 
 
 .. only:: html
index 64d241d..7b8e673 100644 (file)
@@ -51,7 +51,7 @@ ISO 13818-1
 ===========
 
 
-:title:     ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information technology  Generic coding of moving pictures and associated audio information: Systems"
+:title:     ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information technology --- Generic coding of moving pictures and associated audio information: Systems"
 
 :author:    International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch)
 
@@ -61,7 +61,7 @@ ISO 13818-2
 ===========
 
 
-:title:     ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information technology  Generic coding of moving pictures and associated audio information: Video"
+:title:     ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information technology --- Generic coding of moving pictures and associated audio information: Video"
 
 :author:    International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch)
 
@@ -150,7 +150,7 @@ ITU-T.81
 ========
 
 
-:title:     ITU-T Recommendation T.81 "Information Technology — Digital Compression and Coding of Continous-Tone Still Images — Requirements and Guidelines"
+:title:     ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continous-Tone Still Images --- Requirements and Guidelines"
 
 :author:    International Telecommunication Union (http://www.itu.int)
 
@@ -310,7 +310,7 @@ ISO 12232:2006
 ==============
 
 
-:title:     Photography — Digital still cameras — Determination of exposure index, ISO speed ratings, standard output sensitivity, and recommended exposure index
+:title:     Photography --- Digital still cameras --- Determination of exposure index, ISO speed ratings, standard output sensitivity, and recommended exposure index
 
 :author:    International Organization for Standardization (http://www.iso.org)
 
index 3d4138a..5b9b83f 100644 (file)
@@ -38,7 +38,7 @@ Conventions and Notations Used in This Document
 6. i = [a..b]: sequence of integers from a to b, inclusive, i.e. i =
    [0..2]: i = 0, 1, 2.
 
-7. Given an ``OUTPUT`` buffer A, then A represents a buffer on the ``CAPTURE``
+7. Given an ``OUTPUT`` buffer A, then A' represents a buffer on the ``CAPTURE``
    queue containing data that resulted from processing buffer A.
 
 .. _decoder-glossary:
@@ -288,7 +288,7 @@ Initialization
 
       Changing the ``OUTPUT`` format may change the currently set ``CAPTURE``
       format. How the new ``CAPTURE`` format is determined is up to the decoder
-      and the client must ensure it matches its needs afterwards.
+      and the client must ensure it matches its needs afterwards.
 
 2.  Allocate source (bytestream) buffers via :c:func:`VIDIOC_REQBUFS` on
     ``OUTPUT``.
@@ -874,7 +874,7 @@ it may be affected as per normal decoder operation.
 
    any of the following results on the ``CAPTURE`` queue is allowed:
 
-     {A’, B’, G’, H’}, {A’, G’, H’}, {G’, H’}.
+     {A', B', G', H'}, {A', G', H'}, {G', H'}.
 
    To determine the CAPTURE buffer containing the first decoded frame after the
    seek, the client may observe the timestamps to match the CAPTURE and OUTPUT
index 3fc04da..72f5e85 100644 (file)
@@ -1244,3 +1244,217 @@ FWHT Flags
     * - __u8
       - ``padding[3]``
       - Applications and drivers must set this to zero.
+
+.. _v4l2-codec-stateless-mpeg2:
+
+``V4L2_CID_STATELESS_MPEG2_SEQUENCE (struct)``
+    Specifies the sequence parameters (as extracted from the bitstream) for the
+    associated MPEG-2 slice data. This includes fields matching the syntax
+    elements from the sequence header and sequence extension parts of the
+    bitstream as specified by :ref:`mpeg2part2`.
+
+.. c:type:: v4l2_ctrl_mpeg2_sequence
+
+.. raw:: latex
+
+    \small
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.4cm}|p{6.5cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_ctrl_mpeg2_sequence
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u16
+      - ``horizontal_size``
+      - The width of the displayable part of the frame's luminance component.
+    * - __u16
+      - ``vertical_size``
+      - The height of the displayable part of the frame's luminance component.
+    * - __u32
+      - ``vbv_buffer_size``
+      - Used to calculate the required size of the video buffering verifier,
+       defined (in bits) as: 16 * 1024 * vbv_buffer_size.
+    * - __u16
+      - ``profile_and_level_indication``
+      - The current profile and level indication as extracted from the
+       bitstream.
+    * - __u8
+      - ``chroma_format``
+      - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4).
+    * - __u8
+      - ``flags``
+      - See :ref:`MPEG-2 Sequence Flags <mpeg2_sequence_flags>`.
+
+.. _mpeg2_sequence_flags:
+
+``MPEG-2 Sequence Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE``
+      - 0x01
+      - Indication that all the frames for the sequence are progressive instead
+       of interlaced.
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_MPEG2_PICTURE (struct)``
+    Specifies the picture parameters (as extracted from the bitstream) for the
+    associated MPEG-2 slice data. This includes fields matching the syntax
+    elements from the picture header and picture coding extension parts of the
+    bitstream as specified by :ref:`mpeg2part2`.
+
+.. c:type:: v4l2_ctrl_mpeg2_picture
+
+.. raw:: latex
+
+    \small
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.0cm}|p{5.6cm}|p{10.7cm}|
+
+.. flat-table:: struct v4l2_ctrl_mpeg2_picture
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u64
+      - ``backward_ref_ts``
+      - Timestamp of the V4L2 capture buffer to use as backward reference, used
+        with B-coded and P-coded frames. The timestamp refers to the
+       ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the
+       :c:func:`v4l2_timeval_to_ns()` function to convert the struct
+       :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
+    * - __u64
+      - ``forward_ref_ts``
+      - Timestamp for the V4L2 capture buffer to use as forward reference, used
+        with B-coded frames. The timestamp refers to the ``timestamp`` field in
+       struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()`
+       function to convert the struct :c:type:`timeval` in struct
+       :c:type:`v4l2_buffer` to a __u64.
+    * - __u32
+      - ``flags``
+      - See :ref:`MPEG-2 Picture Flags <mpeg2_picture_flags>`.
+    * - __u8
+      - ``f_code[2][2]``
+      - Motion vector codes.
+    * - __u8
+      - ``picture_coding_type``
+      - Picture coding type for the frame covered by the current slice
+       (V4L2_MPEG2_PIC_CODING_TYPE_I, V4L2_MPEG2_PIC_CODING_TYPE_P or
+       V4L2_MPEG2_PIC_CODING_TYPE_B).
+    * - __u8
+      - ``picture_structure``
+      - Picture structure (1: interlaced top field, 2: interlaced bottom field,
+       3: progressive frame).
+    * - __u8
+      - ``intra_dc_precision``
+      - Precision of Discrete Cosine transform (0: 8 bits precision,
+       1: 9 bits precision, 2: 10 bits precision, 3: 11 bits precision).
+    * - __u8
+      - ``reserved[5]``
+      - Applications and drivers must set this to zero.
+
+.. _mpeg2_picture_flags:
+
+``MPEG-2 Picture Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST``
+      - 0x00000001
+      - If set and it's an interlaced stream, top field is output first.
+    * - ``V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT``
+      - 0x00000002
+      - If set only frame-DCT and frame prediction are used.
+    * - ``V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV``
+      - 0x00000004
+      -  If set motion vectors are coded for intra macroblocks.
+    * - ``V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE``
+      - 0x00000008
+      - This flag affects the inverse quantization process.
+    * - ``V4L2_MPEG2_PIC_FLAG_INTRA_VLC``
+      - 0x00000010
+      - This flag affects the decoding of transform coefficient data.
+    * - ``V4L2_MPEG2_PIC_FLAG_ALT_SCAN``
+      - 0x00000020
+      - This flag affects the decoding of transform coefficient data.
+    * - ``V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST``
+      - 0x00000040
+      - This flag affects the decoding process of progressive frames.
+    * - ``V4L2_MPEG2_PIC_FLAG_PROGRESSIVE``
+      - 0x00000080
+      - Indicates whether the current frame is progressive.
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_MPEG2_QUANTISATION (struct)``
+    Specifies quantisation matrices, in zigzag scanning order, for the
+    associated MPEG-2 slice data. This control is initialized by the kernel
+    to the matrices default values. If a bitstream transmits a user-defined
+    quantisation matrices load, applications are expected to use this control.
+    Applications are also expected to set the control loading the default
+    values, if the quantisation matrices need to be reset, for instance on a
+    sequence header. This process is specified by section 6.3.7.
+    "Quant matrix extension" of the specification.
+
+.. c:type:: v4l2_ctrl_mpeg2_quantisation
+
+.. tabularcolumns:: |p{0.8cm}|p{8.0cm}|p{8.5cm}|
+
+.. cssclass:: longtable
+
+.. raw:: latex
+
+    \small
+
+.. flat-table:: struct v4l2_ctrl_mpeg2_quantisation
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``intra_quantiser_matrix[64]``
+      - The quantisation matrix coefficients for intra-coded frames, in zigzag
+       scanning order. It is relevant for both luma and chroma components,
+       although it can be superseded by the chroma-specific matrix for
+       non-4:2:0 YUV formats.
+    * - __u8
+      - ``non_intra_quantiser_matrix[64]``
+      - The quantisation matrix coefficients for non-intra-coded frames, in
+       zigzag scanning order. It is relevant for both luma and chroma
+       components, although it can be superseded by the chroma-specific matrix
+       for non-4:2:0 YUV formats.
+    * - __u8
+      - ``chroma_intra_quantiser_matrix[64]``
+      - The quantisation matrix coefficients for the chominance component of
+       intra-coded frames, in zigzag scanning order. Only relevant for
+       non-4:2:0 YUV formats.
+    * - __u8
+      - ``chroma_non_intra_quantiser_matrix[64]``
+      - The quantisation matrix coefficients for the chrominance component of
+       non-intra-coded frames, in zigzag scanning order. Only relevant for
+       non-4:2:0 YUV formats.
+
+.. raw:: latex
+
+    \normalsize
index b0de4e6..8c6e2a1 100644 (file)
@@ -1606,223 +1606,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
 ``V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR (integer)``
     Indicates bit rate (bps) for hierarchical coding layer 6 for H264 encoder.
 
-.. _v4l2-mpeg-mpeg2:
-
-``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (struct)``
-    Specifies the slice parameters (as extracted from the bitstream) for the
-    associated MPEG-2 slice data. This includes the necessary parameters for
-    configuring a stateless hardware decoding pipeline for MPEG-2.
-    The bitstream parameters are defined according to :ref:`mpeg2part2`.
-
-    .. note::
-
-       This compound control is not yet part of the public kernel API and
-       it is expected to change.
-
-.. c:type:: v4l2_ctrl_mpeg2_slice_params
-
-.. tabularcolumns:: |p{5.6cm}|p{4.6cm}|p{7.1cm}|
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_mpeg2_slice_params
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u32
-      - ``bit_size``
-      - Size (in bits) of the current slice data.
-    * - __u32
-      - ``data_bit_offset``
-      - Offset (in bits) to the video data in the current slice data.
-    * - struct :c:type:`v4l2_mpeg2_sequence`
-      - ``sequence``
-      - Structure with MPEG-2 sequence metadata, merging relevant fields from
-       the sequence header and sequence extension parts of the bitstream.
-    * - struct :c:type:`v4l2_mpeg2_picture`
-      - ``picture``
-      - Structure with MPEG-2 picture metadata, merging relevant fields from
-       the picture header and picture coding extension parts of the bitstream.
-    * - __u64
-      - ``backward_ref_ts``
-      - Timestamp of the V4L2 capture buffer to use as backward reference, used
-        with B-coded and P-coded frames. The timestamp refers to the
-       ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the
-       :c:func:`v4l2_timeval_to_ns()` function to convert the struct
-       :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
-    * - __u64
-      - ``forward_ref_ts``
-      - Timestamp for the V4L2 capture buffer to use as forward reference, used
-        with B-coded frames. The timestamp refers to the ``timestamp`` field in
-       struct :c:type:`v4l2_buffer`. Use the :c:func:`v4l2_timeval_to_ns()`
-       function to convert the struct :c:type:`timeval` in struct
-       :c:type:`v4l2_buffer` to a __u64.
-    * - __u32
-      - ``quantiser_scale_code``
-      - Code used to determine the quantization scale to use for the IDCT.
-
-.. c:type:: v4l2_mpeg2_sequence
-
-.. cssclass:: longtable
-
-.. tabularcolumns:: |p{1.4cm}|p{6.5cm}|p{9.4cm}|
-
-.. flat-table:: struct v4l2_mpeg2_sequence
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u16
-      - ``horizontal_size``
-      - The width of the displayable part of the frame's luminance component.
-    * - __u16
-      - ``vertical_size``
-      - The height of the displayable part of the frame's luminance component.
-    * - __u32
-      - ``vbv_buffer_size``
-      - Used to calculate the required size of the video buffering verifier,
-       defined (in bits) as: 16 * 1024 * vbv_buffer_size.
-    * - __u16
-      - ``profile_and_level_indication``
-      - The current profile and level indication as extracted from the
-       bitstream.
-    * - __u8
-      - ``progressive_sequence``
-      - Indication that all the frames for the sequence are progressive instead
-       of interlaced.
-    * - __u8
-      - ``chroma_format``
-      - The chrominance sub-sampling format (1: 4:2:0, 2: 4:2:2, 3: 4:4:4).
-
-.. c:type:: v4l2_mpeg2_picture
-
-.. raw:: latex
-
-    \small
-
-.. cssclass:: longtable
-
-.. tabularcolumns:: |p{1.0cm}|p{5.6cm}|p{10.7cm}|
-
-.. flat-table:: struct v4l2_mpeg2_picture
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u8
-      - ``picture_coding_type``
-      - Picture coding type for the frame covered by the current slice
-       (V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or
-       V4L2_MPEG2_PICTURE_CODING_TYPE_B).
-    * - __u8
-      - ``f_code[2][2]``
-      - Motion vector codes.
-    * - __u8
-      - ``intra_dc_precision``
-      - Precision of Discrete Cosine transform (0: 8 bits precision,
-       1: 9 bits precision, 2: 10 bits precision, 3: 11 bits precision).
-    * - __u8
-      - ``picture_structure``
-      - Picture structure (1: interlaced top field, 2: interlaced bottom field,
-       3: progressive frame).
-    * - __u8
-      - ``top_field_first``
-      - If set to 1 and interlaced stream, top field is output first.
-    * - __u8
-      - ``frame_pred_frame_dct``
-      - If set to 1, only frame-DCT and frame prediction are used.
-    * - __u8
-      - ``concealment_motion_vectors``
-      -  If set to 1, motion vectors are coded for intra macroblocks.
-    * - __u8
-      - ``q_scale_type``
-      - This flag affects the inverse quantization process.
-    * - __u8
-      - ``intra_vlc_format``
-      - This flag affects the decoding of transform coefficient data.
-    * - __u8
-      - ``alternate_scan``
-      - This flag affects the decoding of transform coefficient data.
-    * - __u8
-      - ``repeat_first_field``
-      - This flag affects the decoding process of progressive frames.
-    * - __u16
-      - ``progressive_frame``
-      - Indicates whether the current frame is progressive.
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION (struct)``
-    Specifies quantization matrices (as extracted from the bitstream) for the
-    associated MPEG-2 slice data.
-
-    .. note::
-
-       This compound control is not yet part of the public kernel API and
-       it is expected to change.
-
-.. c:type:: v4l2_ctrl_mpeg2_quantization
-
-.. tabularcolumns:: |p{0.8cm}|p{8.0cm}|p{8.5cm}|
-
-.. cssclass:: longtable
-
-.. raw:: latex
-
-    \small
-
-.. flat-table:: struct v4l2_ctrl_mpeg2_quantization
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u8
-      - ``load_intra_quantiser_matrix``
-      - One bit to indicate whether to load the ``intra_quantiser_matrix`` data.
-    * - __u8
-      - ``load_non_intra_quantiser_matrix``
-      - One bit to indicate whether to load the ``non_intra_quantiser_matrix``
-       data.
-    * - __u8
-      - ``load_chroma_intra_quantiser_matrix``
-      - One bit to indicate whether to load the
-       ``chroma_intra_quantiser_matrix`` data, only relevant for non-4:2:0 YUV
-       formats.
-    * - __u8
-      - ``load_chroma_non_intra_quantiser_matrix``
-      - One bit to indicate whether to load the
-       ``chroma_non_intra_quantiser_matrix`` data, only relevant for non-4:2:0
-       YUV formats.
-    * - __u8
-      - ``intra_quantiser_matrix[64]``
-      - The quantization matrix coefficients for intra-coded frames, in zigzag
-       scanning order. It is relevant for both luma and chroma components,
-       although it can be superseded by the chroma-specific matrix for
-       non-4:2:0 YUV formats.
-    * - __u8
-      - ``non_intra_quantiser_matrix[64]``
-      - The quantization matrix coefficients for non-intra-coded frames, in
-       zigzag scanning order. It is relevant for both luma and chroma
-       components, although it can be superseded by the chroma-specific matrix
-       for non-4:2:0 YUV formats.
-    * - __u8
-      - ``chroma_intra_quantiser_matrix[64]``
-      - The quantization matrix coefficients for the chominance component of
-       intra-coded frames, in zigzag scanning order. Only relevant for
-       non-4:2:0 YUV formats.
-    * - __u8
-      - ``chroma_non_intra_quantiser_matrix[64]``
-      - The quantization matrix coefficients for the chrominance component of
-       non-intra-coded frames, in zigzag scanning order. Only relevant for
-       non-4:2:0 YUV formats.
-
-.. raw:: latex
-
-    \normalsize
-
 ``V4L2_CID_FWHT_I_FRAME_QP (integer)``
     Quantization parameter for an I frame for FWHT. Valid range: from 1
     to 31.
@@ -2924,6 +2707,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     * - __u8
       - ``chroma_format_idc``
       -
+    * - __u8
+      - ``sps_max_sub_layers_minus1``
+      -
     * - __u64
       - ``flags``
       - See :ref:`Sequence Parameter Set Flags <hevc_sps_flags>`
@@ -3000,6 +2786,12 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     * - __u8
       - ``num_extra_slice_header_bits``
       -
+    * - __u8
+      - ``num_ref_idx_l0_default_active_minus1``
+      - Specifies the inferred value of num_ref_idx_l0_active_minus1
+    * - __u8
+      - ``num_ref_idx_l1_default_active_minus1``
+      - Specifies the inferred value of num_ref_idx_l1_active_minus1
     * - __s8
       - ``init_qp_minus26``
       -
@@ -3053,7 +2845,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     :stub-columns: 0
     :widths:       1 1 2
 
-    * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT``
+    * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED``
       - 0x00000001
       -
     * - ``V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT``
@@ -3110,6 +2902,14 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     * - ``V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT``
       - 0x00040000
       -
+    * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT``
+      - 0x00080000
+      - Specifies the presence of deblocking filter control syntax elements in
+        the PPS
+    * - ``V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING``
+      - 0x00100000
+      - Specifies that tile column boundaries and likewise tile row boundaries
+        are distributed uniformly across the picture
 
 .. raw:: latex
 
@@ -3201,31 +3001,14 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
       - ``pic_struct``
       -
     * - __u8
-      - ``num_active_dpb_entries``
-      - The number of entries in ``dpb``.
-    * - __u8
       - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
       - The list of L0 reference elements as indices in the DPB.
     * - __u8
       - ``ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
       - The list of L1 reference elements as indices in the DPB.
     * - __u8
-      - ``num_rps_poc_st_curr_before``
-      - The number of reference pictures in the short-term set that come before
-        the current frame.
-    * - __u8
-      - ``num_rps_poc_st_curr_after``
-      - The number of reference pictures in the short-term set that come after
-        the current frame.
-    * - __u8
-      - ``num_rps_poc_lt_curr``
-      - The number of reference pictures in the long-term set.
-    * - __u8
-      - ``padding[7]``
+      - ``padding``
       - Applications and drivers must set this to zero.
-    * - struct :c:type:`v4l2_hevc_dpb_entry`
-      - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - The decoded picture buffer, for meta-data about reference frames.
     * - struct :c:type:`v4l2_hevc_pred_weight_table`
       - ``pred_weight_table``
       - The prediction weight coefficients for inter-picture prediction.
@@ -3277,6 +3060,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED``
       - 0x00000100
       -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT``
+      - 0x00000200
+      -
 
 .. raw:: latex
 
@@ -3478,3 +3264,78 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     encoding the next frame queued after setting this control.
     This provides a bitmask which consists of bits [0, LTR_COUNT-1].
     This is applicable to the H264 and HEVC encoders.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (struct)``
+    Specifies various decode parameters, especially the references picture order
+    count (POC) for all the lists (short, long, before, current, after) and the
+    number of entries for each of them.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 8.3 "Slice decoding process" of the
+    specification.
+
+.. c:type:: v4l2_ctrl_hevc_decode_params
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_decode_params
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __s32
+      - ``pic_order_cnt_val``
+      - PicOrderCntVal as described in section 8.3.1 "Decoding process
+        for picture order count" of the specification.
+    * - __u8
+      - ``num_active_dpb_entries``
+      - The number of entries in ``dpb``.
+    * - struct :c:type:`v4l2_hevc_dpb_entry`
+      - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The decoded picture buffer, for meta-data about reference frames.
+    * - __u8
+      - ``num_poc_st_curr_before``
+      - The number of reference pictures in the short-term set that come before
+        the current frame.
+    * - __u8
+      - ``num_poc_st_curr_after``
+      - The number of reference pictures in the short-term set that come after
+        the current frame.
+    * - __u8
+      - ``num_poc_lt_curr``
+      - The number of reference pictures in the long-term set.
+    * - __u8
+      - ``poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocStCurrBefore as described in section 8.3.2 "Decoding process for reference
+        picture set.
+    * - __u8
+      - ``poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocStCurrAfter as described in section 8.3.2 "Decoding process for reference
+        picture set.
+    * - __u8
+      - ``poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocLtCurr as described in section 8.3.2 "Decoding process for reference
+        picture set.
+    * - __u64
+      - ``flags``
+      - See :ref:`Decode Parameters Flags <hevc_decode_params_flags>`
+
+.. _hevc_decode_params_flags:
+
+``Decode Parameters Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC``
+      - 0x00000001
+      -
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC``
+      - 0x00000002
+      -
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR``
+      - 0x00000004
+      -
index 6dba70d..0ede399 100644 (file)
@@ -112,12 +112,13 @@ Compressed Formats
       - 'MG2S'
       - MPEG-2 parsed slice data, as extracted from the MPEG-2 bitstream.
        This format is adapted for stateless video decoders that implement a
-       MPEG-2 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`).
+       MPEG-2 pipeline with the :ref:`stateless_decoder`.
        Metadata associated with the frame to decode is required to be passed
-       through the ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS`` control and
-       quantization matrices can optionally be specified through the
-       ``V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION`` control.
-       See the :ref:`associated Codec Control IDs <v4l2-mpeg-mpeg2>`.
+       through the ``V4L2_CID_STATELESS_MPEG2_SEQUENCE`` and
+        ``V4L2_CID_STATELESS_MPEG2_PICTURE`` controls.
+        Quantisation matrices can optionally be specified through the
+       ``V4L2_CID_STATELESS_MPEG2_QUANTISATION`` control.
+       See the :ref:`associated Codec Control IDs <v4l2-codec-stateless-mpeg2>`.
        Exactly one output and one capture buffer must be provided for use with
        this pixel format. The output buffer must contain the appropriate number
        of macroblocks to decode a full corresponding frame to the matching
index 5f33d35..84d81dd 100644 (file)
@@ -78,4 +78,4 @@ hardware and algorithm details.
 Intel IPU3 ImgU uAPI data types
 ===============================
 
-.. kernel-doc:: drivers/staging/media/ipu3/include/intel-ipu3.h
+.. kernel-doc:: drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
index 3ba2298..2d6bc8d 100644 (file)
@@ -221,6 +221,18 @@ still cause this situation.
       - ``p_vp8_frame``
       - A pointer to a struct :c:type:`v4l2_ctrl_vp8_frame`. Valid if this control is
         of type ``V4L2_CTRL_TYPE_VP8_FRAME``.
+    * - struct :c:type:`v4l2_ctrl_mpeg2_sequence` *
+      - ``p_mpeg2_sequence``
+      - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_sequence`. Valid if this control is
+        of type ``V4L2_CTRL_TYPE_MPEG2_SEQUENCE``.
+    * - struct :c:type:`v4l2_ctrl_mpeg2_picture` *
+      - ``p_mpeg2_picture``
+      - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_picture`. Valid if this control is
+        of type ``V4L2_CTRL_TYPE_MPEG2_PICTURE``.
+    * - struct :c:type:`v4l2_ctrl_mpeg2_quantisation` *
+      - ``p_mpeg2_quantisation``
+      - A pointer to a struct :c:type:`v4l2_ctrl_mpeg2_quantisation`. Valid if this control is
+        of type ``V4L2_CTRL_TYPE_MPEG2_QUANTISATION``.
     * - struct :c:type:`v4l2_ctrl_hdr10_cll_info` *
       - ``p_hdr10_cll``
       - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_cll_info`. Valid if this control is
index 8a285da..f9ecf62 100644 (file)
@@ -417,18 +417,24 @@ See also the examples in :ref:`control`.
       - any
       - An unsigned 32-bit valued control ranging from minimum to maximum
        inclusive. The step value indicates the increment between values.
-    * - ``V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS``
+    * - ``V4L2_CTRL_TYPE_MPEG2_QUANTISATION``
       - n/a
       - n/a
       - n/a
-      - A struct :c:type:`v4l2_ctrl_mpeg2_slice_params`, containing MPEG-2
-       slice parameters for stateless video decoders.
-    * - ``V4L2_CTRL_TYPE_MPEG2_QUANTIZATION``
+      - A struct :c:type:`v4l2_ctrl_mpeg2_quantisation`, containing MPEG-2
+       quantisation matrices for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_MPEG2_SEQUENCE``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_mpeg2_sequence`, containing MPEG-2
+       sequence parameters for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_MPEG2_PICTURE``
       - n/a
       - n/a
       - n/a
-      - A struct :c:type:`v4l2_ctrl_mpeg2_quantization`, containing MPEG-2
-       quantization matrices for stateless video decoders.
+      - A struct :c:type:`v4l2_ctrl_mpeg2_picture`, containing MPEG-2
+       picture parameters for stateless video decoders.
     * - ``V4L2_CTRL_TYPE_AREA``
       - n/a
       - n/a
@@ -495,6 +501,12 @@ See also the examples in :ref:`control`.
       - n/a
       - A struct :c:type:`v4l2_ctrl_vp8_frame`, containing VP8
        frame parameters for stateless video decoders.
+    * - ``V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS``
+      - n/a
+      - n/a
+      - n/a
+      - A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
+       decoding parameters for stateless video decoders.
 
 .. raw:: latex
 
diff --git a/Documentation/userspace-api/media/video.h.rst.exceptions b/Documentation/userspace-api/media/video.h.rst.exceptions
deleted file mode 100644 (file)
index ea9de59..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# Ignore header name
-ignore define _UAPI_DVBVIDEO_H_
-
-# This is a deprecated obscure API. Just ignore things we don't know
-ignore define VIDEO_CMD_PLAY
-ignore define VIDEO_CMD_STOP
-ignore define VIDEO_CMD_FREEZE
-ignore define VIDEO_CMD_CONTINUE
-ignore define VIDEO_CMD_FREEZE_TO_BLACK
-ignore define VIDEO_CMD_STOP_TO_BLACK
-ignore define VIDEO_CMD_STOP_IMMEDIATELY
-ignore define VIDEO_PLAY_FMT_NONE
-ignore define VIDEO_PLAY_FMT_GOP
-ignore define VIDEO_VSYNC_FIELD_UNKNOWN
-ignore define VIDEO_VSYNC_FIELD_ODD
-ignore define VIDEO_VSYNC_FIELD_EVEN
-ignore define VIDEO_VSYNC_FIELD_PROGRESSIVE
-ignore define VIDEO_EVENT_SIZE_CHANGED
-ignore define VIDEO_EVENT_FRAME_RATE_CHANGED
-ignore define VIDEO_EVENT_DECODER_STOPPED
-ignore define VIDEO_EVENT_VSYNC
-ignore define VIDEO_CAP_MPEG1
-ignore define VIDEO_CAP_MPEG2
-ignore define VIDEO_CAP_SYS
-ignore define VIDEO_CAP_PROG
-ignore define VIDEO_CAP_SPU
-ignore define VIDEO_CAP_NAVI
-ignore define VIDEO_CAP_CSS
-
-# some typedefs should point to struct/enums
-replace typedef video_format_t :c:type:`video_format`
-replace typedef video_system_t :c:type:`video_system`
-replace typedef video_displayformat_t :c:type:`video_displayformat`
-replace typedef video_size_t :c:type:`video_size`
-replace typedef video_stream_source_t :c:type:`video_stream_source`
-replace typedef video_play_state_t :c:type:`video_play_state`
-replace typedef video_navi_pack_t :c:type:`video_navi_pack`
index f599403..2217b56 100644 (file)
@@ -134,8 +134,9 @@ replace symbol V4L2_CTRL_TYPE_STRING :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_U16 :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type`
-replace symbol V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS :c:type:`v4l2_ctrl_type`
-replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTIZATION :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_MPEG2_SEQUENCE :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_MPEG2_PICTURE :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTISATION :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`v4l2_ctrl_type`
index 6efb41c..d612198 100644 (file)
@@ -259,6 +259,18 @@ and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a response, indicating what should be
 returned to userspace. The ``id`` member of ``struct seccomp_notif_resp`` should
 be the same ``id`` as in ``struct seccomp_notif``.
 
+Userspace can also add file descriptors to the notifying process via
+``ioctl(SECCOMP_IOCTL_NOTIF_ADDFD)``. The ``id`` member of
+``struct seccomp_notif_addfd`` should be the same ``id`` as in
+``struct seccomp_notif``. The ``newfd_flags`` flag may be used to set flags
+like O_EXEC on the file descriptor in the notifying process. If the supervisor
+wants to inject the file descriptor with a specific number, the
+``SECCOMP_ADDFD_FLAG_SETFD`` flag can be used, and set the ``newfd`` member to
+the specific number to use. If that file descriptor is already open in the
+notifying process it will be replaced. The supervisor can also add an FD, and
+respond atomically by using the ``SECCOMP_ADDFD_FLAG_SEND`` flag and the return
+value will be the injected file descriptor number.
+
 It is worth noting that ``struct seccomp_data`` contains the values of register
 arguments to the syscall, but does not contain pointers to memory. The task's
 memory is accessible to suitably privileged traces via ``ptrace()`` or
index 7fcb2fd..c7b165c 100644 (file)
@@ -688,9 +688,14 @@ MSRs that have been set successfully.
 Defines the vcpu responses to the cpuid instruction.  Applications
 should use the KVM_SET_CPUID2 ioctl if available.
 
-Note, when this IOCTL fails, KVM gives no guarantees that previous valid CPUID
-configuration (if there is) is not corrupted. Userspace can get a copy of the
-resulting CPUID configuration through KVM_GET_CPUID2 in case.
+Caveat emptor:
+  - If this IOCTL fails, KVM gives no guarantees that previous valid CPUID
+    configuration (if there is) is not corrupted. Userspace can get a copy
+    of the resulting CPUID configuration through KVM_GET_CPUID2 in case.
+  - Using KVM_SET_CPUID{,2} after KVM_RUN, i.e. changing the guest vCPU model
+    after running the guest, may cause guest instability.
+  - Using heterogeneous CPUID configurations, modulo APIC IDs, topology, etc...
+    may cause guest instability.
 
 ::
 
@@ -5034,6 +5039,260 @@ see KVM_XEN_VCPU_SET_ATTR above.
 The KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST type may not be used
 with the KVM_XEN_VCPU_GET_ATTR ioctl.
 
+4.130 KVM_ARM_MTE_COPY_TAGS
+---------------------------
+
+:Capability: KVM_CAP_ARM_MTE
+:Architectures: arm64
+:Type: vm ioctl
+:Parameters: struct kvm_arm_copy_mte_tags
+:Returns: number of bytes copied, < 0 on error (-EINVAL for incorrect
+          arguments, -EFAULT if memory cannot be accessed).
+
+::
+
+  struct kvm_arm_copy_mte_tags {
+       __u64 guest_ipa;
+       __u64 length;
+       void __user *addr;
+       __u64 flags;
+       __u64 reserved[2];
+  };
+
+Copies Memory Tagging Extension (MTE) tags to/from guest tag memory. The
+``guest_ipa`` and ``length`` fields must be ``PAGE_SIZE`` aligned. The ``addr``
+field must point to a buffer which the tags will be copied to or from.
+
+``flags`` specifies the direction of copy, either ``KVM_ARM_TAGS_TO_GUEST`` or
+``KVM_ARM_TAGS_FROM_GUEST``.
+
+The size of the buffer to store the tags is ``(length / 16)`` bytes
+(granules in MTE are 16 bytes long). Each byte contains a single tag
+value. This matches the format of ``PTRACE_PEEKMTETAGS`` and
+``PTRACE_POKEMTETAGS``.
+
+If an error occurs before any data is copied then a negative error code is
+returned. If some tags have been copied before an error occurs then the number
+of bytes successfully copied is returned. If the call completes successfully
+then ``length`` is returned.
+
+4.131 KVM_GET_SREGS2
+------------------
+
+:Capability: KVM_CAP_SREGS2
+:Architectures: x86
+:Type: vcpu ioctl
+:Parameters: struct kvm_sregs2 (out)
+:Returns: 0 on success, -1 on error
+
+Reads special registers from the vcpu.
+This ioctl (when supported) replaces the KVM_GET_SREGS.
+
+::
+
+struct kvm_sregs2 {
+       /* out (KVM_GET_SREGS2) / in (KVM_SET_SREGS2) */
+       struct kvm_segment cs, ds, es, fs, gs, ss;
+       struct kvm_segment tr, ldt;
+       struct kvm_dtable gdt, idt;
+       __u64 cr0, cr2, cr3, cr4, cr8;
+       __u64 efer;
+       __u64 apic_base;
+       __u64 flags;
+       __u64 pdptrs[4];
+};
+
+flags values for ``kvm_sregs2``:
+
+``KVM_SREGS2_FLAGS_PDPTRS_VALID``
+
+  Indicates thats the struct contain valid PDPTR values.
+
+
+4.132 KVM_SET_SREGS2
+------------------
+
+:Capability: KVM_CAP_SREGS2
+:Architectures: x86
+:Type: vcpu ioctl
+:Parameters: struct kvm_sregs2 (in)
+:Returns: 0 on success, -1 on error
+
+Writes special registers into the vcpu.
+See KVM_GET_SREGS2 for the data structures.
+This ioctl (when supported) replaces the KVM_SET_SREGS.
+
+4.133 KVM_GET_STATS_FD
+----------------------
+
+:Capability: KVM_CAP_STATS_BINARY_FD
+:Architectures: all
+:Type: vm ioctl, vcpu ioctl
+:Parameters: none
+:Returns: statistics file descriptor on success, < 0 on error
+
+Errors:
+
+  ======     ======================================================
+  ENOMEM     if the fd could not be created due to lack of memory
+  EMFILE     if the number of opened files exceeds the limit
+  ======     ======================================================
+
+The returned file descriptor can be used to read VM/vCPU statistics data in
+binary format. The data in the file descriptor consists of four blocks
+organized as follows:
+
++-------------+
+|   Header    |
++-------------+
+|  id string  |
++-------------+
+| Descriptors |
++-------------+
+| Stats Data  |
++-------------+
+
+Apart from the header starting at offset 0, please be aware that it is
+not guaranteed that the four blocks are adjacent or in the above order;
+the offsets of the id, descriptors and data blocks are found in the
+header.  However, all four blocks are aligned to 64 bit offsets in the
+file and they do not overlap.
+
+All blocks except the data block are immutable.  Userspace can read them
+only one time after retrieving the file descriptor, and then use ``pread`` or
+``lseek`` to read the statistics repeatedly.
+
+All data is in system endianness.
+
+The format of the header is as follows::
+
+       struct kvm_stats_header {
+               __u32 flags;
+               __u32 name_size;
+               __u32 num_desc;
+               __u32 id_offset;
+               __u32 desc_offset;
+               __u32 data_offset;
+       };
+
+The ``flags`` field is not used at the moment. It is always read as 0.
+
+The ``name_size`` field is the size (in byte) of the statistics name string
+(including trailing '\0') which is contained in the "id string" block and
+appended at the end of every descriptor.
+
+The ``num_desc`` field is the number of descriptors that are included in the
+descriptor block.  (The actual number of values in the data block may be
+larger, since each descriptor may comprise more than one value).
+
+The ``id_offset`` field is the offset of the id string from the start of the
+file indicated by the file descriptor. It is a multiple of 8.
+
+The ``desc_offset`` field is the offset of the Descriptors block from the start
+of the file indicated by the file descriptor. It is a multiple of 8.
+
+The ``data_offset`` field is the offset of the Stats Data block from the start
+of the file indicated by the file descriptor. It is a multiple of 8.
+
+The id string block contains a string which identifies the file descriptor on
+which KVM_GET_STATS_FD was invoked.  The size of the block, including the
+trailing ``'\0'``, is indicated by the ``name_size`` field in the header.
+
+The descriptors block is only needed to be read once for the lifetime of the
+file descriptor contains a sequence of ``struct kvm_stats_desc``, each followed
+by a string of size ``name_size``.
+
+       #define KVM_STATS_TYPE_SHIFT            0
+       #define KVM_STATS_TYPE_MASK             (0xF << KVM_STATS_TYPE_SHIFT)
+       #define KVM_STATS_TYPE_CUMULATIVE       (0x0 << KVM_STATS_TYPE_SHIFT)
+       #define KVM_STATS_TYPE_INSTANT          (0x1 << KVM_STATS_TYPE_SHIFT)
+       #define KVM_STATS_TYPE_PEAK             (0x2 << KVM_STATS_TYPE_SHIFT)
+
+       #define KVM_STATS_UNIT_SHIFT            4
+       #define KVM_STATS_UNIT_MASK             (0xF << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_NONE             (0x0 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_BYTES            (0x1 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_SECONDS          (0x2 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_CYCLES           (0x3 << KVM_STATS_UNIT_SHIFT)
+
+       #define KVM_STATS_BASE_SHIFT            8
+       #define KVM_STATS_BASE_MASK             (0xF << KVM_STATS_BASE_SHIFT)
+       #define KVM_STATS_BASE_POW10            (0x0 << KVM_STATS_BASE_SHIFT)
+       #define KVM_STATS_BASE_POW2             (0x1 << KVM_STATS_BASE_SHIFT)
+
+       struct kvm_stats_desc {
+               __u32 flags;
+               __s16 exponent;
+               __u16 size;
+               __u32 offset;
+               __u32 unused;
+               char name[];
+       };
+
+The ``flags`` field contains the type and unit of the statistics data described
+by this descriptor. Its endianness is CPU native.
+The following flags are supported:
+
+Bits 0-3 of ``flags`` encode the type:
+  * ``KVM_STATS_TYPE_CUMULATIVE``
+    The statistics data is cumulative. The value of data can only be increased.
+    Most of the counters used in KVM are of this type.
+    The corresponding ``size`` field for this type is always 1.
+    All cumulative statistics data are read/write.
+  * ``KVM_STATS_TYPE_INSTANT``
+    The statistics data is instantaneous. Its value can be increased or
+    decreased. This type is usually used as a measurement of some resources,
+    like the number of dirty pages, the number of large pages, etc.
+    All instant statistics are read only.
+    The corresponding ``size`` field for this type is always 1.
+  * ``KVM_STATS_TYPE_PEAK``
+    The statistics data is peak. The value of data can only be increased, and
+    represents a peak value for a measurement, for example the maximum number
+    of items in a hash table bucket, the longest time waited and so on.
+    The corresponding ``size`` field for this type is always 1.
+
+Bits 4-7 of ``flags`` encode the unit:
+  * ``KVM_STATS_UNIT_NONE``
+    There is no unit for the value of statistics data. This usually means that
+    the value is a simple counter of an event.
+  * ``KVM_STATS_UNIT_BYTES``
+    It indicates that the statistics data is used to measure memory size, in the
+    unit of Byte, KiByte, MiByte, GiByte, etc. The unit of the data is
+    determined by the ``exponent`` field in the descriptor.
+  * ``KVM_STATS_UNIT_SECONDS``
+    It indicates that the statistics data is used to measure time or latency.
+  * ``KVM_STATS_UNIT_CYCLES``
+    It indicates that the statistics data is used to measure CPU clock cycles.
+
+Bits 8-11 of ``flags``, together with ``exponent``, encode the scale of the
+unit:
+  * ``KVM_STATS_BASE_POW10``
+    The scale is based on power of 10. It is used for measurement of time and
+    CPU clock cycles.  For example, an exponent of -9 can be used with
+    ``KVM_STATS_UNIT_SECONDS`` to express that the unit is nanoseconds.
+  * ``KVM_STATS_BASE_POW2``
+    The scale is based on power of 2. It is used for measurement of memory size.
+    For example, an exponent of 20 can be used with ``KVM_STATS_UNIT_BYTES`` to
+    express that the unit is MiB.
+
+The ``size`` field is the number of values of this statistics data. Its
+value is usually 1 for most of simple statistics. 1 means it contains an
+unsigned 64bit data.
+
+The ``offset`` field is the offset from the start of Data Block to the start of
+the corresponding statistics data.
+
+The ``unused`` field is reserved for future support for other types of
+statistics data, like log/linear histogram. Its value is always 0 for the types
+defined above.
+
+The ``name`` field is the name string of the statistics data. The name string
+starts at the end of ``struct kvm_stats_desc``.  The maximum length including
+the trailing ``'\0'``, is indicated by ``name_size`` in the header.
+
+The Stats Data block contains an array of 64-bit values in the same order
+as the descriptors in Descriptors block.
+
 5. The kvm_run structure
 ========================
 
@@ -6323,6 +6582,7 @@ KVM_RUN_BUS_LOCK flag is used to distinguish between them.
 This capability can be used to check / enable 2nd DAWR feature provided
 by POWER10 processor.
 
+
 7.24 KVM_CAP_VM_COPY_ENC_CONTEXT_FROM
 -------------------------------------
 
@@ -6360,7 +6620,67 @@ system fingerprint.  To prevent userspace from circumventing such restrictions
 by running an enclave in a VM, KVM prevents access to privileged attributes by
 default.
 
-See Documentation/x86/sgx/2.Kernel-internals.rst for more details.
+See Documentation/x86/sgx.rst for more details.
+
+7.26 KVM_CAP_PPC_RPT_INVALIDATE
+-------------------------------
+
+:Capability: KVM_CAP_PPC_RPT_INVALIDATE
+:Architectures: ppc
+:Type: vm
+
+This capability indicates that the kernel is capable of handling
+H_RPT_INVALIDATE hcall.
+
+In order to enable the use of H_RPT_INVALIDATE in the guest,
+user space might have to advertise it for the guest. For example,
+IBM pSeries (sPAPR) guest starts using it if "hcall-rpt-invalidate" is
+present in the "ibm,hypertas-functions" device-tree property.
+
+This capability is enabled for hypervisors on platforms like POWER9
+that support radix MMU.
+
+7.27 KVM_CAP_EXIT_ON_EMULATION_FAILURE
+--------------------------------------
+
+:Architectures: x86
+:Parameters: args[0] whether the feature should be enabled or not
+
+When this capability is enabled, an emulation failure will result in an exit
+to userspace with KVM_INTERNAL_ERROR (except when the emulator was invoked
+to handle a VMware backdoor instruction). Furthermore, KVM will now provide up
+to 15 instruction bytes for any exit to userspace resulting from an emulation
+failure.  When these exits to userspace occur use the emulation_failure struct
+instead of the internal struct.  They both have the same layout, but the
+emulation_failure struct matches the content better.  It also explicitly
+defines the 'flags' field which is used to describe the fields in the struct
+that are valid (ie: if KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES is
+set in the 'flags' field then both 'insn_size' and 'insn_bytes' have valid data
+in them.)
+
+7.28 KVM_CAP_ARM_MTE
+--------------------
+
+:Architectures: arm64
+:Parameters: none
+
+This capability indicates that KVM (and the hardware) supports exposing the
+Memory Tagging Extensions (MTE) to the guest. It must also be enabled by the
+VMM before creating any VCPUs to allow the guest access. Note that MTE is only
+available to a guest running in AArch64 mode and enabling this capability will
+cause attempts to create AArch32 VCPUs to fail.
+
+When enabled the guest is able to access tags associated with any memory given
+to the guest. KVM will ensure that the tags are maintained during swap or
+hibernation of the host; however the VMM needs to manually save/restore the
+tags as appropriate if the VM is migrated.
+
+When this capability is enabled all memory in memslots must be mapped as
+not-shareable (no MAP_SHARED), attempts to create a memslot with a
+MAP_SHARED mmap will result in an -EINVAL return.
+
+When enabled the VMM may make use of the ``KVM_ARM_MTE_COPY_TAGS`` ioctl to
+perform a bulk copy of tags to/from the guest.
 
 8. Other capabilities.
 ======================
@@ -6891,3 +7211,33 @@ This capability is always enabled.
 This capability indicates that the KVM virtual PTP service is
 supported in the host. A VMM can check whether the service is
 available to the guest on migration.
+
+8.33 KVM_CAP_HYPERV_ENFORCE_CPUID
+-----------------------------
+
+Architectures: x86
+
+When enabled, KVM will disable emulated Hyper-V features provided to the
+guest according to the bits Hyper-V CPUID feature leaves. Otherwise, all
+currently implmented Hyper-V features are provided unconditionally when
+Hyper-V identification is set in the HYPERV_CPUID_INTERFACE (0x40000001)
+leaf.
+
+8.34 KVM_CAP_EXIT_HYPERCALL
+---------------------------
+
+:Capability: KVM_CAP_EXIT_HYPERCALL
+:Architectures: x86
+:Type: vm
+
+This capability, if enabled, will cause KVM to exit to userspace
+with KVM_EXIT_HYPERCALL exit reason to process some hypercalls.
+
+Calling KVM_CHECK_EXTENSION for this capability will return a bitmask
+of hypercalls that can be configured to exit to userspace.
+Right now, the only such hypercall is KVM_HC_MAP_GPA_RANGE.
+
+The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset
+of the result of KVM_CHECK_EXTENSION.  KVM will forward to userspace
+the hypercalls whose corresponding bit is in the argument, and return
+ENOSYS for the others.
index cf62162..bda3e3e 100644 (file)
@@ -96,6 +96,13 @@ KVM_FEATURE_MSI_EXT_DEST_ID        15          guest checks this feature bit
                                                before using extended destination
                                                ID bits in MSI address bits 11-5.
 
+KVM_FEATURE_HC_MAP_GPA_RANGE       16          guest checks this feature bit before
+                                               using the map gpa range hypercall
+                                               to notify the page state change
+
+KVM_FEATURE_MIGRATION_CONTROL      17          guest checks this feature bit before
+                                               using MSR_KVM_MIGRATION_CONTROL
+
 KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 24          host will warn if no guest-side
                                                per-cpu warps are expected in
                                                kvmclock
index ed4fddd..e56fa8b 100644 (file)
@@ -169,3 +169,24 @@ a0: destination APIC ID
 
 :Usage example: When sending a call-function IPI-many to vCPUs, yield if
                any of the IPI target vCPUs was preempted.
+
+8. KVM_HC_MAP_GPA_RANGE
+-------------------------
+:Architecture: x86
+:Status: active
+:Purpose: Request KVM to map a GPA range with the specified attributes.
+
+a0: the guest physical address of the start page
+a1: the number of (4kb) pages (must be contiguous in GPA space)
+a2: attributes
+
+    Where 'attributes' :
+        * bits  3:0 - preferred page size encoding 0 = 4kb, 1 = 2mb, 2 = 1gb, etc...
+        * bit     4 - plaintext = 0, encrypted = 1
+        * bits 63:5 - reserved (must be zero)
+
+**Implementation note**: this hypercall is implemented in userspace via
+the KVM_CAP_EXIT_HYPERCALL capability. Userspace must enable that capability
+before advertising KVM_FEATURE_HC_MAP_GPA_RANGE in the guest CPUID.  In
+addition, if the guest supports KVM_FEATURE_MIGRATION_CONTROL, userspace
+must also set up an MSR filter to process writes to MSR_KVM_MIGRATION_CONTROL.
index 1fc860c..35eca37 100644 (file)
@@ -16,6 +16,11 @@ The acquisition orders for mutexes are as follows:
 - kvm->slots_lock is taken outside kvm->irq_lock, though acquiring
   them together is quite rare.
 
+- Unlike kvm->slots_lock, kvm->slots_arch_lock is released before
+  synchronize_srcu(&kvm->srcu).  Therefore kvm->slots_arch_lock
+  can be taken inside a kvm->srcu read-side critical section,
+  while kvm->slots_lock cannot.
+
 On x86:
 
 - vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock
index 20d85da..f60f548 100644 (file)
@@ -180,8 +180,8 @@ Shadow pages contain the following information:
   role.gpte_is_8_bytes:
     Reflects the size of the guest PTE for which the page is valid, i.e. '1'
     if 64-bit gptes are in use, '0' if 32-bit gptes are in use.
-  role.nxe:
-    Contains the value of efer.nxe for which the page is valid.
+  role.efer_nx:
+    Contains the value of efer.nx for which the page is valid.
   role.cr0_wp:
     Contains the value of cr0.wp for which the page is valid.
   role.smep_andnot_wp:
@@ -192,9 +192,6 @@ Shadow pages contain the following information:
     Contains the value of cr4.smap && !cr0.wp for which the page is valid
     (pages for which this is true are different from other pages; see the
     treatment of cr0.wp=0 below).
-  role.ept_sp:
-    This is a virtual flag to denote a shadowed nested EPT page.  ept_sp
-    is true if "cr0_wp && smap_andnot_wp", an otherwise invalid combination.
   role.smm:
     Is 1 if the page is valid in system management mode.  This field
     determines which of the kvm_memslots array was used to build this
index e37a14c..9315fc3 100644 (file)
@@ -376,3 +376,16 @@ data:
        write '1' to bit 0 of the MSR, this causes the host to re-scan its queue
        and check if there are more notifications pending. The MSR is available
        if KVM_FEATURE_ASYNC_PF_INT is present in CPUID.
+
+MSR_KVM_MIGRATION_CONTROL:
+        0x4b564d08
+
+data:
+        This MSR is available if KVM_FEATURE_MIGRATION_CONTROL is present in
+        CPUID.  Bit 0 represents whether live migration of the guest is allowed.
+
+        When a guest is started, bit 0 will be 0 if the guest has encrypted
+        memory and 1 if the guest does not have encrypted memory.  If the
+        guest is communicating page encryption status to the host using the
+        ``KVM_HC_MAP_GPA_RANGE`` hypercall, it can set bit 0 in this MSR to
+        allow live migration of the guest.
index ad1f786..73a6083 100644 (file)
@@ -10,7 +10,7 @@ The memory of Protected Virtual Machines (PVMs) is not accessible to
 I/O or the hypervisor. In those cases where the hypervisor needs to
 access the memory of a PVM, that memory must be made accessible.
 Memory made accessible to the hypervisor will be encrypted. See
-:doc:`s390-pv` for details."
+Documentation/virt/kvm/s390-pv.rst for details."
 
 On IPL (boot) a small plaintext bootloader is started, which provides
 information about the encrypted components and necessary metadata to
index af1b374..ad2915e 100644 (file)
@@ -304,6 +304,6 @@ VCPU returns from the call.
 References
 ==========
 
-.. [atomic-ops] Documentation/core-api/atomic_ops.rst
+.. [atomic-ops] Documentation/atomic_bitops.txt and Documentation/atomic_t.txt
 .. [memory-barriers] Documentation/memory-barriers.txt
 .. [lwn-mb] https://lwn.net/Articles/573436/
index 03f294a..d302855 100644 (file)
@@ -181,7 +181,7 @@ SLUB Debug output
 Here is a sample of slub debug output::
 
  ====================================================================
- BUG kmalloc-8: Redzone overwritten
+ BUG kmalloc-8: Right Redzone overwritten
  --------------------------------------------------------------------
 
  INFO: 0xc90f6d28-0xc90f6d2b. First byte 0x00 instead of 0xcc
@@ -189,10 +189,10 @@ Here is a sample of slub debug output::
  INFO: Object 0xc90f6d20 @offset=3360 fp=0xc90f6d58
  INFO: Allocated in get_modalias+0x61/0xf5 age=53 cpu=1 pid=554
 
- Bytes b4 0xc90f6d10:  00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
  Object 0xc90f6d20:  31 30 31 39 2e 30 30 35                         1019.005
 Redzone 0xc90f6d28:  00 cc cc cc                                     .
 Padding 0xc90f6d50:  5a 5a 5a 5a 5a 5a 5a 5a                         ZZZZZZZZ
+ Bytes b4 (0xc90f6d10): 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
Object   (0xc90f6d20): 31 30 31 39 2e 30 30 35                         1019.005
Redzone  (0xc90f6d28): 00 cc cc cc                                     .
Padding  (0xc90f6d50): 5a 5a 5a 5a 5a 5a 5a 5a                         ZZZZZZZZ
 
    [<c010523d>] dump_trace+0x63/0x1eb
    [<c01053df>] show_trace_log_lvl+0x1a/0x2f
index d8d9fa4..8edb8d5 100644 (file)
@@ -10,7 +10,7 @@ Overview
 Zswap is a lightweight compressed cache for swap pages. It takes pages that are
 in the process of being swapped out and attempts to compress them into a
 dynamically allocated RAM-based memory pool.  zswap basically trades CPU cycles
-for potentially reduced swap I/O.  This trade-off can also result in a
+for potentially reduced swap I/O.  This trade-off can also result in a
 significant performance improvement if reads from the compressed cache are
 faster than reads from a swap device.
 
@@ -26,7 +26,7 @@ faster than reads from a swap device.
   performance impact of swapping.
 * Overcommitted guests that share a common I/O resource can
   dramatically reduce their swap I/O pressure, avoiding heavy handed I/O
-  throttling by the hypervisor. This allows more work to get done with less
+  throttling by the hypervisor. This allows more work to get done with less
   impact to the guest workload and guests sharing the I/O subsystem
 * Users with SSDs as swap devices can extend the life of the device by
   drastically reducing life-shortening writes.
index fc84491..894a198 100644 (file)
@@ -1343,7 +1343,7 @@ follow::
 In addition to read/modify/write the setup header of the struct
 boot_params as that of 16-bit boot protocol, the boot loader should
 also fill the additional fields of the struct boot_params as
-described in chapter :doc:`zero-page`.
+described in chapter Documentation/x86/zero-page.rst.
 
 After setting up the struct boot_params, the boot loader can load the
 32/64-bit kernel in the same way as that of 16-bit boot protocol.
@@ -1379,7 +1379,7 @@ can be calculated as follows::
 In addition to read/modify/write the setup header of the struct
 boot_params as that of 16-bit boot protocol, the boot loader should
 also fill the additional fields of the struct boot_params as described
-in chapter :doc:`zero-page`.
+in chapter Documentation/x86/zero-page.rst.
 
 After setting up the struct boot_params, the boot loader can load
 64-bit kernel in the same way as that of 16-bit boot protocol, but
diff --git a/Documentation/x86/buslock.rst b/Documentation/x86/buslock.rst
new file mode 100644 (file)
index 0000000..7c051e7
--- /dev/null
@@ -0,0 +1,126 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: <isonum.txt>
+
+===============================
+Bus lock detection and handling
+===============================
+
+:Copyright: |copy| 2021 Intel Corporation
+:Authors: - Fenghua Yu <fenghua.yu@intel.com>
+          - Tony Luck <tony.luck@intel.com>
+
+Problem
+=======
+
+A split lock is any atomic operation whose operand crosses two cache lines.
+Since the operand spans two cache lines and the operation must be atomic,
+the system locks the bus while the CPU accesses the two cache lines.
+
+A bus lock is acquired through either split locked access to writeback (WB)
+memory or any locked access to non-WB memory. This is typically thousands of
+cycles slower than an atomic operation within a cache line. It also disrupts
+performance on other cores and brings the whole system to its knees.
+
+Detection
+=========
+
+Intel processors may support either or both of the following hardware
+mechanisms to detect split locks and bus locks.
+
+#AC exception for split lock detection
+--------------------------------------
+
+Beginning with the Tremont Atom CPU split lock operations may raise an
+Alignment Check (#AC) exception when a split lock operation is attemped.
+
+#DB exception for bus lock detection
+------------------------------------
+
+Some CPUs have the ability to notify the kernel by an #DB trap after a user
+instruction acquires a bus lock and is executed. This allows the kernel to
+terminate the application or to enforce throttling.
+
+Software handling
+=================
+
+The kernel #AC and #DB handlers handle bus lock based on the kernel
+parameter "split_lock_detect". Here is a summary of different options:
+
++------------------+----------------------------+-----------------------+
+|split_lock_detect=|#AC for split lock         |#DB for bus lock       |
++------------------+----------------------------+-----------------------+
+|off              |Do nothing                  |Do nothing             |
++------------------+----------------------------+-----------------------+
+|warn             |Kernel OOPs                 |Warn once per task and |
+|(default)        |Warn once per task and      |and continues to run.  |
+|                 |disable future checking     |                       |
+|                 |When both features are      |                       |
+|                 |supported, warn in #AC      |                       |
++------------------+----------------------------+-----------------------+
+|fatal            |Kernel OOPs                 |Send SIGBUS to user.   |
+|                 |Send SIGBUS to user         |                       |
+|                 |When both features are      |                       |
+|                 |supported, fatal in #AC     |                       |
++------------------+----------------------------+-----------------------+
+|ratelimit:N      |Do nothing                  |Limit bus lock rate to |
+|(0 < N <= 1000)   |                           |N bus locks per second |
+|                 |                            |system wide and warn on|
+|                 |                            |bus locks.             |
++------------------+----------------------------+-----------------------+
+
+Usages
+======
+
+Detecting and handling bus lock may find usages in various areas:
+
+It is critical for real time system designers who build consolidated real
+time systems. These systems run hard real time code on some cores and run
+"untrusted" user processes on other cores. The hard real time cannot afford
+to have any bus lock from the untrusted processes to hurt real time
+performance. To date the designers have been unable to deploy these
+solutions as they have no way to prevent the "untrusted" user code from
+generating split lock and bus lock to block the hard real time code to
+access memory during bus locking.
+
+It's also useful for general computing to prevent guests or user
+applications from slowing down the overall system by executing instructions
+with bus lock.
+
+
+Guidance
+========
+off
+---
+
+Disable checking for split lock and bus lock. This option can be useful if
+there are legacy applications that trigger these events at a low rate so
+that mitigation is not needed.
+
+warn
+----
+
+A warning is emitted when a bus lock is detected which allows to identify
+the offending application. This is the default behavior.
+
+fatal
+-----
+
+In this case, the bus lock is not tolerated and the process is killed.
+
+ratelimit
+---------
+
+A system wide bus lock rate limit N is specified where 0 < N <= 1000. This
+allows a bus lock rate up to N bus locks per second. When the bus lock rate
+is exceeded then any task which is caught via the buslock #DB exception is
+throttled by enforced sleeps until the rate goes under the limit again.
+
+This is an effective mitigation in cases where a minimal impact can be
+tolerated, but an eventual Denial of Service attack has to be prevented. It
+allows to identify the offending processes and analyze whether they are
+malicious or just badly written.
+
+Selecting a rate limit of 1000 allows the bus to be locked for up to about
+seven million cycles each second (assuming 7000 cycles for each bus
+lock). On a 2 GHz processor that would be about 0.35% system slowdown.
index 4693e19..0004f5d 100644 (file)
@@ -29,6 +29,7 @@ x86-specific Documentation
    microcode
    resctrl
    tsx_async_abort
+   buslock
    usb-legacy-support
    i386/index
    x86_64/index
index c5b695d..9f0b185 100644 (file)
@@ -28,7 +28,7 @@ are aligned with platform MTRR setup. If MTRRs are only set up by the platform
 firmware code though and the OS does not make any specific MTRR mapping
 requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID.
 
-For details refer to :doc:`pat`.
+For details refer to Documentation/x86/pat.rst.
 
 .. tip::
   On Intel P6 family processors (Pentium Pro, Pentium II and later)
index 324ceff..5f62b3b 100644 (file)
@@ -247,16 +247,11 @@ Multiple x86-64 PCI-DMA mapping implementations exist, for example:
       Kernel boot message: "PCI-DMA: Using software bounce buffering
       for IO (SWIOTLB)"
 
-   4. <arch/x86_64/pci-calgary.c> : IBM Calgary hardware IOMMU. Used in IBM
-      pSeries and xSeries servers. This hardware IOMMU supports DMA address
-      mapping with memory protection, etc.
-      Kernel boot message: "PCI-DMA: Using Calgary IOMMU"
-
 ::
 
   iommu=[<size>][,noagp][,off][,force][,noforce]
   [,memaper[=<order>]][,merge][,fullflush][,nomerge]
-  [,noaperture][,calgary]
+  [,noaperture]
 
 General iommu options:
 
@@ -295,8 +290,6 @@ iommu options only relevant to the AMD GART hardware IOMMU:
       Don't initialize the AGP driver and use full aperture.
     panic
       Always panic when IOMMU overflows.
-    calgary
-      Use the Calgary IOMMU if it is available
 
 iommu options only relevant to the software bounce buffering (SWIOTLB) IOMMU
 implementation:
@@ -307,28 +300,6 @@ implementation:
       force
         Force all IO through the software TLB.
 
-Settings for the IBM Calgary hardware IOMMU currently found in IBM
-pSeries and xSeries machines
-
-    calgary=[64k,128k,256k,512k,1M,2M,4M,8M]
-      Set the size of each PCI slot's translation table when using the
-      Calgary IOMMU. This is the size of the translation table itself
-      in main memory. The smallest table, 64k, covers an IO space of
-      32MB; the largest, 8MB table, can cover an IO space of 4GB.
-      Normally the kernel will make the right choice by itself.
-    calgary=[translate_empty_slots]
-      Enable translation even on slots that have no devices attached to
-      them, in case a device will be hotplugged in the future.
-    calgary=[disable=<PCI bus number>]
-      Disable translation on a given PHB. For
-      example, the built-in graphics adapter resides on the first bridge
-      (PCI bus number 0); if translation (isolation) is enabled on this
-      bridge, X servers that access the hardware directly from user
-      space might stop working. Use this option if you have devices that
-      are accessed from userspace directly on some PCI host bridge.
-    panic
-      Always panic when IOMMU overflows
-
 
 Miscellaneous
 =============
index bc0ceef..19cb1ea 100644 (file)
@@ -1811,12 +1811,13 @@ F:      Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt
 F:     Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt
 F:     Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt
 F:     arch/arm/mach-gemini/
+F:     drivers/crypto/gemini/
 F:     drivers/net/ethernet/cortina/
 F:     drivers/pinctrl/pinctrl-gemini.c
 F:     drivers/rtc/rtc-ftrtc010.c
 
 ARM/CZ.NIC TURRIS SUPPORT
-M:     Marek Behun <kabel@kernel.org>
+M:     Marek Behún <kabel@kernel.org>
 S:     Maintained
 W:     https://www.turris.cz/
 F:     Documentation/ABI/testing/debugfs-moxtet
@@ -1972,6 +1973,7 @@ F:        Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt
 F:     Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
 F:     arch/arm/mach-ixp4xx/
 F:     drivers/clocksource/timer-ixp4xx.c
+F:     drivers/crypto/ixp4xx_crypto.c
 F:     drivers/gpio/gpio-ixp4xx.c
 F:     drivers/irqchip/irq-ixp4xx.c
 F:     include/linux/irqchip/irq-ixp4xx.h
@@ -4610,6 +4612,12 @@ S:       Supported
 F:     drivers/video/console/
 F:     include/linux/console*
 
+CONTEXT TRACKING
+M:     Frederic Weisbecker <frederic@kernel.org>
+S:     Maintained
+F:     kernel/context_tracking.c
+F:     include/linux/context_tracking*
+
 CONTROL GROUP (CGROUP)
 M:     Tejun Heo <tj@kernel.org>
 M:     Zefan Li <lizefan.x@bytedance.com>
@@ -5189,6 +5197,13 @@ W:       https://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 F:     drivers/media/platform/sti/delta
 
+DELTA DPS920AB PSU DRIVER
+M:     Robert Marko <robert.marko@sartura.hr>
+L:     linux-hwmon@vger.kernel.org
+S:     Maintained
+F:     Documentation/hwmon/dps920ab.rst
+F:     drivers/hwmon/pmbus/dps920ab.c
+
 DENALI NAND DRIVER
 L:     linux-mtd@lists.infradead.org
 S:     Orphan
@@ -6771,7 +6786,7 @@ F:        include/video/s1d13xxxfb.h
 
 EROFS FILE SYSTEM
 M:     Gao Xiang <xiang@kernel.org>
-M:     Chao Yu <yuchao0@huawei.com>
+M:     Chao Yu <chao@kernel.org>
 L:     linux-erofs@lists.ozlabs.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
@@ -7166,7 +7181,7 @@ F:        include/video/
 
 FREESCALE CAAM (Cryptographic Acceleration and Assurance Module) DRIVER
 M:     Horia Geantă <horia.geanta@nxp.com>
-M:     Aymen Sghaier <aymen.sghaier@nxp.com>
+M:     Pankaj Gupta <pankaj.gupta@nxp.com>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/crypto/fsl-sec4.txt
@@ -7354,7 +7369,6 @@ F:        drivers/net/ethernet/freescale/fs_enet/
 F:     include/linux/fs_enet_pd.h
 
 FREESCALE SOC SOUND DRIVERS
-M:     Timur Tabi <timur@kernel.org>
 M:     Nicolin Chen <nicoleotsuka@gmail.com>
 M:     Xiubo Li <Xiubo.Lee@gmail.com>
 R:     Fabio Estevam <festevam@gmail.com>
@@ -7557,6 +7571,12 @@ M:       Kieran Bingham <kbingham@kernel.org>
 S:     Supported
 F:     scripts/gdb/
 
+GEMINI CRYPTO DRIVER
+M:     Corentin Labbe <clabbe@baylibre.com>
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/gemini/
+
 GEMTEK FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -8772,22 +8792,6 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/busses/i2c-icy.c
 
-IDE SUBSYSTEM
-M:     "David S. Miller" <davem@davemloft.net>
-L:     linux-ide@vger.kernel.org
-S:     Maintained
-Q:     http://patchwork.ozlabs.org/project/linux-ide/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git
-F:     Documentation/ide/
-F:     drivers/ide/
-F:     include/linux/ide.h
-
-IDE/ATAPI DRIVERS
-L:     linux-ide@vger.kernel.org
-S:     Orphan
-F:     Documentation/cdrom/ide-cd.rst
-F:     drivers/ide/ide-cd*
-
 IDEAPAD LAPTOP EXTRAS DRIVER
 M:     Ike Panhc <ike.pan@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -9244,6 +9248,12 @@ F:       Documentation/admin-guide/media/ipu3_rcb.svg
 F:     Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst
 F:     drivers/staging/media/ipu3/
 
+INTEL IXP4XX CRYPTO SUPPORT
+M:     Corentin Labbe <clabbe@baylibre.com>
+L:     linux-crypto@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/ixp4xx_crypto.c
+
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
 S:     Maintained
@@ -9995,6 +10005,8 @@ F:       arch/arm64/include/asm/kvm*
 F:     arch/arm64/include/uapi/asm/kvm*
 F:     arch/arm64/kvm/
 F:     include/kvm/arm_*
+F:     tools/testing/selftests/kvm/*/aarch64/
+F:     tools/testing/selftests/kvm/aarch64/
 
 KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
 M:     Huacai Chen <chenhuacai@kernel.org>
@@ -10946,7 +10958,7 @@ F:      include/linux/mv643xx.h
 
 MARVELL MV88X3310 PHY DRIVER
 M:     Russell King <linux@armlinux.org.uk>
-M:     Marek Behun <marek.behun@nic.cz>
+M:     Marek Behún <kabel@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/phy/marvell10g.c
@@ -11292,6 +11304,7 @@ F:      include/media/imx.h
 
 MEDIA DRIVERS FOR FREESCALE IMX7
 M:     Rui Miguel Silva <rmfrfs@gmail.com>
+M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 T:     git git://linuxtv.org/media_tree.git
@@ -11401,6 +11414,7 @@ L:      linux-renesas-soc@vger.kernel.org
 S:     Supported
 T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/renesas,csi2.yaml
+F:     Documentation/devicetree/bindings/media/renesas,isp.yaml
 F:     Documentation/devicetree/bindings/media/renesas,vin.yaml
 F:     drivers/media/platform/rcar-vin/
 
@@ -11990,11 +12004,13 @@ MICROCHIP ISC DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
-F:     Documentation/devicetree/bindings/media/atmel-isc.txt
+F:     Documentation/devicetree/bindings/media/atmel,isc.yaml
+F:     Documentation/devicetree/bindings/media/microchip,xisc.yaml
 F:     drivers/media/platform/atmel/atmel-isc-base.c
 F:     drivers/media/platform/atmel/atmel-isc-regs.h
 F:     drivers/media/platform/atmel/atmel-isc.h
 F:     drivers/media/platform/atmel/atmel-sama5d2-isc.c
+F:     drivers/media/platform/atmel/atmel-sama7g5-isc.c
 F:     include/linux/atmel-isc-media.h
 
 MICROCHIP ISI DRIVER
@@ -12602,7 +12618,7 @@ S:      Orphan
 F:     drivers/net/ethernet/natsemi/natsemi.c
 
 NCR 5380 SCSI DRIVERS
-M:     Finn Thain <fthain@telegraphics.com.au>
+M:     Finn Thain <fthain@linux-m68k.org>
 M:     Michael Schmitz <schmitzmic@gmail.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
@@ -13074,7 +13090,7 @@ F:      Documentation/filesystems/ntfs.rst
 F:     fs/ntfs/
 
 NUBUS SUBSYSTEM
-M:     Finn Thain <fthain@telegraphics.com.au>
+M:     Finn Thain <fthain@linux-m68k.org>
 L:     linux-m68k@lists.linux-m68k.org
 S:     Maintained
 F:     arch/*/include/asm/nubus.h
@@ -15141,6 +15157,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
 F:     drivers/cpufreq/qcom-cpufreq-nvmem.c
 
+QUALCOMM CRYPTO DRIVERS
+M:     Thara Gopinath <thara.gopinath@linaro.org>
+L:     linux-crypto@vger.kernel.org
+L:     linux-arm-msm@vger.kernel.org
+S:     Maintained
+F:     drivers/crypto/qce/
+
 QUALCOMM EMAC GIGABIT ETHERNET DRIVER
 M:     Timur Tabi <timur@kernel.org>
 L:     netdev@vger.kernel.org
@@ -16560,6 +16583,7 @@ F:      drivers/misc/sgi-xp/
 
 SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Karsten Graul <kgraul@linux.ibm.com>
+M:     Guvenc Gulce <guvenc@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
@@ -17005,6 +17029,13 @@ S:     Maintained
 F:     drivers/ssb/
 F:     include/linux/ssb/
 
+SONY IMX208 SENSOR DRIVER
+M:     Sakari Ailus <sakari.ailus@linux.intel.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
+F:     drivers/media/i2c/imx208.c
+
 SONY IMX214 SENSOR DRIVER
 M:     Ricardo Ribalda <ribalda@kernel.org>
 L:     linux-media@vger.kernel.org
@@ -19577,6 +19608,10 @@ F:     include/dt-bindings/regulator/
 F:     include/linux/regulator/
 K:     regulator_get_optional
 
+VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
+R:     Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+F:     drivers/regulator/irq_helpers.c
+
 VRF
 M:     David Ahern <dsahern@kernel.org>
 L:     netdev@vger.kernel.org
@@ -19594,6 +19629,7 @@ S:      Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pmladek/printk.git
 F:     Documentation/core-api/printk-formats.rst
 F:     lib/test_printf.c
+F:     lib/test_scanf.c
 F:     lib/vsprintf.c
 
 VT1211 HARDWARE MONITOR DRIVER
index ed669b2..88888ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
 VERSION = 5
 PATCHLEVEL = 13
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
-NAME = Frozen Wasteland
+EXTRAVERSION =
+NAME = Opossums on Parade
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -929,11 +929,14 @@ CC_FLAGS_LTO      += -fvisibility=hidden
 # Limit inlining across translation units to reduce binary size
 KBUILD_LDFLAGS += -mllvm -import-instr-limit=5
 
-# Check for frame size exceeding threshold during prolog/epilog insertion.
+# Check for frame size exceeding threshold during prolog/epilog insertion
+# when using lld < 13.0.0.
 ifneq ($(CONFIG_FRAME_WARN),0)
+ifeq ($(shell test $(CONFIG_LLD_VERSION) -lt 130000; echo $$?),0)
 KBUILD_LDFLAGS += -plugin-opt=-warn-stack-size=$(CONFIG_FRAME_WARN)
 endif
 endif
+endif
 
 ifdef CONFIG_LTO
 KBUILD_CFLAGS  += -fno-lto $(CC_FLAGS_LTO)
@@ -1036,7 +1039,7 @@ LDFLAGS_vmlinux   += $(call ld-option, -X,)
 endif
 
 ifeq ($(CONFIG_RELR),y)
-LDFLAGS_vmlinux        += --pack-dyn-relocs=relr
+LDFLAGS_vmlinux        += --pack-dyn-relocs=relr --use-android-relr-tags
 endif
 
 # We never want expected sections to be placed heuristically by the
index 724c407..dd2dd9f 100644 (file)
@@ -25,19 +25,18 @@ CONFIG_PNP=y
 CONFIG_ISAPNP=y
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_LOOP=m
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_ALI15X3=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_CY82C693=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_ALI=y
+CONFIG_PATA_CMD64X=y
+CONFIG_PATA_CYPRESS=y
+CONFIG_ATA_GENERIC=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_NET_ETHERNET=y
index e41c113..f2861a4 100644 (file)
 
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic64_read(v)       READ_ONCE((v)->counter)
+#define arch_atomic_read(v)    READ_ONCE((v)->counter)
+#define arch_atomic64_read(v)  READ_ONCE((v)->counter)
 
-#define atomic_set(v,i)                WRITE_ONCE((v)->counter, (i))
-#define atomic64_set(v,i)      WRITE_ONCE((v)->counter, (i))
+#define arch_atomic_set(v,i)   WRITE_ONCE((v)->counter, (i))
+#define arch_atomic64_set(v,i) WRITE_ONCE((v)->counter, (i))
 
 /*
  * To get proper branch prediction for the main line, we must branch
@@ -39,7 +39,7 @@
  */
 
 #define ATOMIC_OP(op, asm_op)                                          \
-static __inline__ void atomic_##op(int i, atomic_t * v)                        \
+static __inline__ void arch_atomic_##op(int i, atomic_t * v)           \
 {                                                                      \
        unsigned long temp;                                             \
        __asm__ __volatile__(                                           \
@@ -55,7 +55,7 @@ static __inline__ void atomic_##op(int i, atomic_t * v)                       \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, asm_op)                                   \
-static inline int atomic_##op##_return_relaxed(int i, atomic_t *v)     \
+static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)        \
 {                                                                      \
        long temp, result;                                              \
        __asm__ __volatile__(                                           \
@@ -74,7 +74,7 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v)    \
 }
 
 #define ATOMIC_FETCH_OP(op, asm_op)                                    \
-static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v)      \
+static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
 {                                                                      \
        long temp, result;                                              \
        __asm__ __volatile__(                                           \
@@ -92,7 +92,7 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v)     \
 }
 
 #define ATOMIC64_OP(op, asm_op)                                                \
-static __inline__ void atomic64_##op(s64 i, atomic64_t * v)            \
+static __inline__ void arch_atomic64_##op(s64 i, atomic64_t * v)       \
 {                                                                      \
        s64 temp;                                                       \
        __asm__ __volatile__(                                           \
@@ -108,7 +108,8 @@ static __inline__ void atomic64_##op(s64 i, atomic64_t * v)         \
 }                                                                      \
 
 #define ATOMIC64_OP_RETURN(op, asm_op)                                 \
-static __inline__ s64 atomic64_##op##_return_relaxed(s64 i, atomic64_t * v)    \
+static __inline__ s64                                                  \
+arch_atomic64_##op##_return_relaxed(s64 i, atomic64_t * v)             \
 {                                                                      \
        s64 temp, result;                                               \
        __asm__ __volatile__(                                           \
@@ -127,7 +128,8 @@ static __inline__ s64 atomic64_##op##_return_relaxed(s64 i, atomic64_t * v) \
 }
 
 #define ATOMIC64_FETCH_OP(op, asm_op)                                  \
-static __inline__ s64 atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v)     \
+static __inline__ s64                                                  \
+arch_atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v)              \
 {                                                                      \
        s64 temp, result;                                               \
        __asm__ __volatile__(                                           \
@@ -155,18 +157,18 @@ static __inline__ s64 atomic64_fetch_##op##_relaxed(s64 i, atomic64_t * v)        \
 ATOMIC_OPS(add)
 ATOMIC_OPS(sub)
 
-#define atomic_add_return_relaxed      atomic_add_return_relaxed
-#define atomic_sub_return_relaxed      atomic_sub_return_relaxed
-#define atomic_fetch_add_relaxed       atomic_fetch_add_relaxed
-#define atomic_fetch_sub_relaxed       atomic_fetch_sub_relaxed
+#define arch_atomic_add_return_relaxed         arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed         arch_atomic_sub_return_relaxed
+#define arch_atomic_fetch_add_relaxed          arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed          arch_atomic_fetch_sub_relaxed
 
-#define atomic64_add_return_relaxed    atomic64_add_return_relaxed
-#define atomic64_sub_return_relaxed    atomic64_sub_return_relaxed
-#define atomic64_fetch_add_relaxed     atomic64_fetch_add_relaxed
-#define atomic64_fetch_sub_relaxed     atomic64_fetch_sub_relaxed
+#define arch_atomic64_add_return_relaxed       arch_atomic64_add_return_relaxed
+#define arch_atomic64_sub_return_relaxed       arch_atomic64_sub_return_relaxed
+#define arch_atomic64_fetch_add_relaxed                arch_atomic64_fetch_add_relaxed
+#define arch_atomic64_fetch_sub_relaxed                arch_atomic64_fetch_sub_relaxed
 
-#define atomic_andnot atomic_andnot
-#define atomic64_andnot atomic64_andnot
+#define arch_atomic_andnot                     arch_atomic_andnot
+#define arch_atomic64_andnot                   arch_atomic64_andnot
 
 #undef ATOMIC_OPS
 #define ATOMIC_OPS(op, asm)                                            \
@@ -180,15 +182,15 @@ ATOMIC_OPS(andnot, bic)
 ATOMIC_OPS(or, bis)
 ATOMIC_OPS(xor, xor)
 
-#define atomic_fetch_and_relaxed       atomic_fetch_and_relaxed
-#define atomic_fetch_andnot_relaxed    atomic_fetch_andnot_relaxed
-#define atomic_fetch_or_relaxed                atomic_fetch_or_relaxed
-#define atomic_fetch_xor_relaxed       atomic_fetch_xor_relaxed
+#define arch_atomic_fetch_and_relaxed          arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_andnot_relaxed       arch_atomic_fetch_andnot_relaxed
+#define arch_atomic_fetch_or_relaxed           arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed          arch_atomic_fetch_xor_relaxed
 
-#define atomic64_fetch_and_relaxed     atomic64_fetch_and_relaxed
-#define atomic64_fetch_andnot_relaxed  atomic64_fetch_andnot_relaxed
-#define atomic64_fetch_or_relaxed      atomic64_fetch_or_relaxed
-#define atomic64_fetch_xor_relaxed     atomic64_fetch_xor_relaxed
+#define arch_atomic64_fetch_and_relaxed                arch_atomic64_fetch_and_relaxed
+#define arch_atomic64_fetch_andnot_relaxed     arch_atomic64_fetch_andnot_relaxed
+#define arch_atomic64_fetch_or_relaxed         arch_atomic64_fetch_or_relaxed
+#define arch_atomic64_fetch_xor_relaxed                arch_atomic64_fetch_xor_relaxed
 
 #undef ATOMIC_OPS
 #undef ATOMIC64_FETCH_OP
@@ -198,14 +200,18 @@ ATOMIC_OPS(xor, xor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic64_cmpxchg(v, old, new) \
+       (arch_cmpxchg(&((v)->counter), old, new))
+#define arch_atomic64_xchg(v, new) \
+       (arch_xchg(&((v)->counter), new))
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, old, new) \
+       (arch_cmpxchg(&((v)->counter), old, new))
+#define arch_atomic_xchg(v, new) \
+       (arch_xchg(&((v)->counter), new))
 
 /**
- * atomic_fetch_add_unless - add unless the number is a given value
+ * arch_atomic_fetch_add_unless - add unless the number is a given value
  * @v: pointer of type atomic_t
  * @a: the amount to add to v...
  * @u: ...unless v is equal to u.
@@ -213,7 +219,7 @@ ATOMIC_OPS(xor, xor)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns the old value of @v.
  */
-static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static __inline__ int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int c, new, old;
        smp_mb();
@@ -234,10 +240,10 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
        smp_mb();
        return old;
 }
-#define atomic_fetch_add_unless atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
 
 /**
- * atomic64_fetch_add_unless - add unless the number is a given value
+ * arch_atomic64_fetch_add_unless - add unless the number is a given value
  * @v: pointer of type atomic64_t
  * @a: the amount to add to v...
  * @u: ...unless v is equal to u.
@@ -245,7 +251,7 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns the old value of @v.
  */
-static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+static __inline__ s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        s64 c, new, old;
        smp_mb();
@@ -266,16 +272,16 @@ static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
        smp_mb();
        return old;
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
 
 /*
- * atomic64_dec_if_positive - decrement by 1 if old value positive
+ * arch_atomic64_dec_if_positive - decrement by 1 if old value positive
  * @v: pointer of type atomic_t
  *
  * The function returns the old value of *v minus 1, even if
  * the atomic variable, v, was not decremented.
  */
-static inline s64 atomic64_dec_if_positive(atomic64_t *v)
+static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
 {
        s64 old, tmp;
        smp_mb();
@@ -295,6 +301,6 @@ static inline s64 atomic64_dec_if_positive(atomic64_t *v)
        smp_mb();
        return old - 1;
 }
-#define atomic64_dec_if_positive atomic64_dec_if_positive
+#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
 
 #endif /* _ALPHA_ATOMIC_H */
index 6c7c394..6e0a850 100644 (file)
@@ -17,7 +17,7 @@
                                       sizeof(*(ptr)));                 \
 })
 
-#define cmpxchg_local(ptr, o, n)                                       \
+#define arch_cmpxchg_local(ptr, o, n)                                  \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
@@ -26,7 +26,7 @@
                                          sizeof(*(ptr)));              \
 })
 
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg_local((ptr), (o), (n));                                 \
@@ -42,7 +42,7 @@
  * The leading and the trailing memory barriers guarantee that these
  * operations are fully ordered.
  */
-#define xchg(ptr, x)                                                   \
+#define arch_xchg(ptr, x)                                              \
 ({                                                                     \
        __typeof__(*(ptr)) __ret;                                       \
        __typeof__(*(ptr)) _x_ = (x);                                   \
@@ -53,7 +53,7 @@
        __ret;                                                          \
 })
 
-#define cmpxchg(ptr, o, n)                                             \
+#define arch_cmpxchg(ptr, o, n)                                                \
 ({                                                                     \
        __typeof__(*(ptr)) __ret;                                       \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __ret;                                                          \
 })
 
-#define cmpxchg64(ptr, o, n)                                           \
+#define arch_cmpxchg64(ptr, o, n)                                      \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg((ptr), (o), (n));                                       \
+       arch_cmpxchg((ptr), (o), (n));                                  \
 })
 
 #undef ____cmpxchg
index 268f99b..18f48a6 100644 (file)
@@ -17,9 +17,9 @@
 extern void clear_page(void *page);
 #define clear_user_page(page, vaddr, pg)       clear_page(page)
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vmaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vmaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 
 extern void copy_page(void * _to, void * _from);
 #define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
index 5112ab9..ef0c08e 100644 (file)
@@ -380,7 +380,7 @@ get_wchan(struct task_struct *p)
 {
        unsigned long schedule_frame;
        unsigned long pc;
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
        /*
         * This one depends on the frame size of schedule().  Do a
index f4dd9f3..4b2575f 100644 (file)
@@ -166,7 +166,6 @@ smp_callin(void)
        DBGS(("smp_callin: commencing CPU %d current %p active_mm %p\n",
              cpuid, current, current->active_mm));
 
-       preempt_disable();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
index 5afc79c..7a36d79 100644 (file)
 #include <asm/barrier.h>
 #include <asm/smp.h>
 
-#define atomic_read(v)  READ_ONCE((v)->counter)
+#define arch_atomic_read(v)  READ_ONCE((v)->counter)
 
 #ifdef CONFIG_ARC_HAS_LLSC
 
-#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned int val;                                               \
                                                                        \
@@ -37,7 +37,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned int val;                                               \
                                                                        \
@@ -63,7 +63,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned int val, orig;                                         \
                                                                        \
@@ -94,11 +94,11 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                     \
 #ifndef CONFIG_SMP
 
  /* violating atomic_xxx API locking protocol in UP for optimization sake */
-#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
 
 #else
 
-static inline void atomic_set(atomic_t *v, int i)
+static inline void arch_atomic_set(atomic_t *v, int i)
 {
        /*
         * Independent of hardware support, all of the atomic_xxx() APIs need
@@ -116,7 +116,7 @@ static inline void atomic_set(atomic_t *v, int i)
        atomic_ops_unlock(flags);
 }
 
-#define atomic_set_release(v, i)       atomic_set((v), (i))
+#define arch_atomic_set_release(v, i)  arch_atomic_set((v), (i))
 
 #endif
 
@@ -126,7 +126,7 @@ static inline void atomic_set(atomic_t *v, int i)
  */
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -136,7 +136,7 @@ static inline void atomic_##op(int i, atomic_t *v)                  \
 }
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long flags;                                            \
        unsigned long temp;                                             \
@@ -154,7 +154,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned long flags;                                            \
        unsigned long orig;                                             \
@@ -180,9 +180,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                     \
 ATOMIC_OPS(add, +=, add)
 ATOMIC_OPS(sub, -=, sub)
 
-#define atomic_andnot          atomic_andnot
-#define atomic_fetch_andnot    atomic_fetch_andnot
-
 #undef ATOMIC_OPS
 #define ATOMIC_OPS(op, c_op, asm_op)                                   \
        ATOMIC_OP(op, c_op, asm_op)                                     \
@@ -193,6 +190,9 @@ ATOMIC_OPS(andnot, &= ~, bic)
 ATOMIC_OPS(or, |=, or)
 ATOMIC_OPS(xor, ^=, xor)
 
+#define arch_atomic_andnot             arch_atomic_andnot
+#define arch_atomic_fetch_andnot       arch_atomic_fetch_andnot
+
 #undef ATOMIC_OPS
 #undef ATOMIC_FETCH_OP
 #undef ATOMIC_OP_RETURN
@@ -220,7 +220,7 @@ typedef struct {
 
 #define ATOMIC64_INIT(a) { (a) }
 
-static inline s64 atomic64_read(const atomic64_t *v)
+static inline s64 arch_atomic64_read(const atomic64_t *v)
 {
        s64 val;
 
@@ -232,7 +232,7 @@ static inline s64 atomic64_read(const atomic64_t *v)
        return val;
 }
 
-static inline void atomic64_set(atomic64_t *v, s64 a)
+static inline void arch_atomic64_set(atomic64_t *v, s64 a)
 {
        /*
         * This could have been a simple assignment in "C" but would need
@@ -253,7 +253,7 @@ static inline void atomic64_set(atomic64_t *v, s64 a)
 }
 
 #define ATOMIC64_OP(op, op1, op2)                                      \
-static inline void atomic64_##op(s64 a, atomic64_t *v)                 \
+static inline void arch_atomic64_##op(s64 a, atomic64_t *v)            \
 {                                                                      \
        s64 val;                                                        \
                                                                        \
@@ -270,7 +270,7 @@ static inline void atomic64_##op(s64 a, atomic64_t *v)                      \
 }                                                                      \
 
 #define ATOMIC64_OP_RETURN(op, op1, op2)                               \
-static inline s64 atomic64_##op##_return(s64 a, atomic64_t *v)         \
+static inline s64 arch_atomic64_##op##_return(s64 a, atomic64_t *v)    \
 {                                                                      \
        s64 val;                                                        \
                                                                        \
@@ -293,7 +293,7 @@ static inline s64 atomic64_##op##_return(s64 a, atomic64_t *v)              \
 }
 
 #define ATOMIC64_FETCH_OP(op, op1, op2)                                        \
-static inline s64 atomic64_fetch_##op(s64 a, atomic64_t *v)            \
+static inline s64 arch_atomic64_fetch_##op(s64 a, atomic64_t *v)       \
 {                                                                      \
        s64 val, orig;                                                  \
                                                                        \
@@ -320,9 +320,6 @@ static inline s64 atomic64_fetch_##op(s64 a, atomic64_t *v)         \
        ATOMIC64_OP_RETURN(op, op1, op2)                                \
        ATOMIC64_FETCH_OP(op, op1, op2)
 
-#define atomic64_andnot                atomic64_andnot
-#define atomic64_fetch_andnot  atomic64_fetch_andnot
-
 ATOMIC64_OPS(add, add.f, adc)
 ATOMIC64_OPS(sub, sub.f, sbc)
 ATOMIC64_OPS(and, and, and)
@@ -330,13 +327,16 @@ ATOMIC64_OPS(andnot, bic, bic)
 ATOMIC64_OPS(or, or, or)
 ATOMIC64_OPS(xor, xor, xor)
 
+#define arch_atomic64_andnot           arch_atomic64_andnot
+#define arch_atomic64_fetch_andnot     arch_atomic64_fetch_andnot
+
 #undef ATOMIC64_OPS
 #undef ATOMIC64_FETCH_OP
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
 static inline s64
-atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new)
+arch_atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new)
 {
        s64 prev;
 
@@ -358,7 +358,7 @@ atomic64_cmpxchg(atomic64_t *ptr, s64 expected, s64 new)
        return prev;
 }
 
-static inline s64 atomic64_xchg(atomic64_t *ptr, s64 new)
+static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new)
 {
        s64 prev;
 
@@ -379,14 +379,14 @@ static inline s64 atomic64_xchg(atomic64_t *ptr, s64 new)
 }
 
 /**
- * atomic64_dec_if_positive - decrement by 1 if old value positive
+ * arch_atomic64_dec_if_positive - decrement by 1 if old value positive
  * @v: pointer of type atomic64_t
  *
  * The function returns the old value of *v minus 1, even if
  * the atomic variable, v, was not decremented.
  */
 
-static inline s64 atomic64_dec_if_positive(atomic64_t *v)
+static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
 {
        s64 val;
 
@@ -408,10 +408,10 @@ static inline s64 atomic64_dec_if_positive(atomic64_t *v)
 
        return val;
 }
-#define atomic64_dec_if_positive atomic64_dec_if_positive
+#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
 
 /**
- * atomic64_fetch_add_unless - add unless the number is a given value
+ * arch_atomic64_fetch_add_unless - add unless the number is a given value
  * @v: pointer of type atomic64_t
  * @a: the amount to add to v...
  * @u: ...unless v is equal to u.
@@ -419,7 +419,7 @@ static inline s64 atomic64_dec_if_positive(atomic64_t *v)
  * Atomically adds @a to @v, if it was not @u.
  * Returns the old value of @v
  */
-static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+static inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        s64 old, temp;
 
@@ -443,7 +443,7 @@ static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 
        return old;
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
 
 #endif /* !CONFIG_GENERIC_ATOMIC64 */
 
index dfeffa2..d42917e 100644 (file)
@@ -63,7 +63,7 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
 
 #endif
 
-#define cmpxchg(ptr, o, n) ({                          \
+#define arch_cmpxchg(ptr, o, n) ({                     \
        (typeof(*(ptr)))__cmpxchg((ptr),                \
                                  (unsigned long)(o),   \
                                  (unsigned long)(n));  \
@@ -75,7 +75,7 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
  *  !LLSC: cmpxchg() has to use an external lock atomic_ops_lock to guarantee
  *         semantics, and this lock also happens to be used by atomic_*()
  */
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_cmpxchg(v, o, n) ((int)arch_cmpxchg(&((v)->counter), (o), (n)))
 
 
 /*
@@ -123,7 +123,7 @@ static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
 
 #if !defined(CONFIG_ARC_HAS_LLSC) && defined(CONFIG_SMP)
 
-#define xchg(ptr, with)                        \
+#define arch_xchg(ptr, with)           \
 ({                                     \
        unsigned long flags;            \
        typeof(*(ptr)) old_val;         \
@@ -136,7 +136,7 @@ static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
 
 #else
 
-#define xchg(ptr, with)  _xchg(ptr, with)
+#define arch_xchg(ptr, with)  _xchg(ptr, with)
 
 #endif
 
@@ -153,6 +153,6 @@ static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
  *         can't be clobbered by others. Thus no serialization required when
  *         atomic_xchg is involved.
  */
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
 #endif
index 95f8a43..7a5449d 100644 (file)
@@ -18,6 +18,7 @@
  */
 struct sigcontext {
        struct user_regs_struct regs;
+       struct user_regs_arcv2 v2abi;
 };
 
 #endif /* _ASM_ARC_SIGCONTEXT_H */
index cabef45..5f0415f 100644 (file)
@@ -317,22 +317,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr)
                 * caused the fault.
                 */
 
-               /* We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
                /*
                 * In case the user-specified fault handler returned zero,
                 * try to fix up.
index b3ccb9e..cb2f885 100644 (file)
@@ -61,6 +61,41 @@ struct rt_sigframe {
        unsigned int sigret_magic;
 };
 
+static int save_arcv2_regs(struct sigcontext *mctx, struct pt_regs *regs)
+{
+       int err = 0;
+#ifndef CONFIG_ISA_ARCOMPACT
+       struct user_regs_arcv2 v2abi;
+
+       v2abi.r30 = regs->r30;
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+       v2abi.r58 = regs->r58;
+       v2abi.r59 = regs->r59;
+#else
+       v2abi.r58 = v2abi.r59 = 0;
+#endif
+       err = __copy_to_user(&mctx->v2abi, &v2abi, sizeof(v2abi));
+#endif
+       return err;
+}
+
+static int restore_arcv2_regs(struct sigcontext *mctx, struct pt_regs *regs)
+{
+       int err = 0;
+#ifndef CONFIG_ISA_ARCOMPACT
+       struct user_regs_arcv2 v2abi;
+
+       err = __copy_from_user(&v2abi, &mctx->v2abi, sizeof(v2abi));
+
+       regs->r30 = v2abi.r30;
+#ifdef CONFIG_ARC_HAS_ACCL_REGS
+       regs->r58 = v2abi.r58;
+       regs->r59 = v2abi.r59;
+#endif
+#endif
+       return err;
+}
+
 static int
 stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
               sigset_t *set)
@@ -94,6 +129,10 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,
 
        err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), &uregs.scratch,
                             sizeof(sf->uc.uc_mcontext.regs.scratch));
+
+       if (is_isa_arcv2())
+               err |= save_arcv2_regs(&(sf->uc.uc_mcontext), regs);
+
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t));
 
        return err ? -EFAULT : 0;
@@ -109,6 +148,10 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        err |= __copy_from_user(&uregs.scratch,
                                &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
+
+       if (is_isa_arcv2())
+               err |= restore_arcv2_regs(&(sf->uc.uc_mcontext), regs);
+
        if (err)
                return -EFAULT;
 
index 52906d3..db0e104 100644 (file)
@@ -189,7 +189,6 @@ void start_kernel_secondary(void)
        pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
 
        local_irq_enable();
-       preempt_disable();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
index f73da20..1b9576d 100644 (file)
@@ -83,7 +83,7 @@ seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs,
                 *    is safe-kept and BLINK at a well known location in there
                 */
 
-               if (tsk->state == TASK_RUNNING)
+               if (task_is_running(tsk))
                        return -1;
 
                frame_info->task = tsk;
index 33ce59d..e2146a8 100644 (file)
@@ -57,7 +57,6 @@ SECTIONS
        .init.ramfs : { INIT_RAM_FS }
 
        . = ALIGN(PAGE_SIZE);
-       _stext = .;
 
        HEAD_TEXT_SECTION
        INIT_TEXT_SECTION(L1_CACHE_BYTES)
@@ -83,6 +82,7 @@ SECTIONS
 
        .text : {
                _text = .;
+               _stext = .;
                TEXT_TEXT
                SCHED_TEXT
                CPUIDLE_TEXT
index 05c5587..e47e1ca 100644 (file)
                        ranges = <0 0x100000 0x2400>;
                };
 
+               vdec0: vdec@300000 {
+                       compatible = "microchip,sama5d4-vdec";
+                       reg = <0x00300000 0x100000>;
+                       interrupts = <19 IRQ_TYPE_LEVEL_HIGH 4>;
+                       clocks = <&pmc PMC_TYPE_PERIPHERAL 19>;
+               };
+
                usb0: gadget@400000 {
                        compatible = "atmel,sama5d3-udc";
                        reg = <0x00400000 0x100000
index 2aa3ebe..7a32de5 100644 (file)
@@ -64,7 +64,6 @@ CONFIG_PARIDE_ON26=m
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
-CONFIG_IDE=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_VENDOR_3COM=y
index 875a3c2..363f1b1 100644 (file)
@@ -215,8 +215,6 @@ CONFIG_IIO=m
 CONFIG_AD5446=m
 CONFIG_EEPROM_AT24=m
 CONFIG_SENSORS_LIS3_SPI=m
-CONFIG_IDE=m
-CONFIG_BLK_DEV_IDECS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=m
 CONFIG_CHR_DEV_ST=m
index 8f26c45..eafa898 100644 (file)
@@ -45,20 +45,12 @@ poly1305-arm-y := poly1305-core.o poly1305-glue.o
 nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
 curve25519-neon-y := curve25519-core.o curve25519-glue.o
 
-ifdef REGENERATE_ARM_CRYPTO
 quiet_cmd_perl = PERL    $@
       cmd_perl = $(PERL) $(<) > $(@)
 
-$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv4.pl
+$(obj)/%-core.S: $(src)/%-armv4.pl
        $(call cmd,perl)
 
-$(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl
-       $(call cmd,perl)
-
-$(src)/sha512-core.S_shipped: $(src)/sha512-armv4.pl
-       $(call cmd,perl)
-endif
-
 clean-files += poly1305-core.S sha256-core.S sha512-core.S
 
 # massage the perlasm code a bit so we only get the NEON routine if we need it
diff --git a/arch/arm/crypto/poly1305-core.S_shipped b/arch/arm/crypto/poly1305-core.S_shipped
deleted file mode 100644 (file)
index 37b71d9..0000000
+++ /dev/null
@@ -1,1158 +0,0 @@
-#ifndef        __KERNEL__
-# include "arm_arch.h"
-#else
-# define __ARM_ARCH__ __LINUX_ARM_ARCH__
-# define __ARM_MAX_ARCH__ __LINUX_ARM_ARCH__
-# define poly1305_init   poly1305_init_arm
-# define poly1305_blocks poly1305_blocks_arm
-# define poly1305_emit   poly1305_emit_arm
-.globl poly1305_blocks_neon
-#endif
-
-#if defined(__thumb2__)
-.syntax        unified
-.thumb
-#else
-.code  32
-#endif
-
-.text
-
-.globl poly1305_emit
-.globl poly1305_blocks
-.globl poly1305_init
-.type  poly1305_init,%function
-.align 5
-poly1305_init:
-.Lpoly1305_init:
-       stmdb   sp!,{r4-r11}
-
-       eor     r3,r3,r3
-       cmp     r1,#0
-       str     r3,[r0,#0]              @ zero hash value
-       str     r3,[r0,#4]
-       str     r3,[r0,#8]
-       str     r3,[r0,#12]
-       str     r3,[r0,#16]
-       str     r3,[r0,#36]             @ clear is_base2_26
-       add     r0,r0,#20
-
-#ifdef __thumb2__
-       it      eq
-#endif
-       moveq   r0,#0
-       beq     .Lno_key
-
-#if    __ARM_MAX_ARCH__>=7
-       mov     r3,#-1
-       str     r3,[r0,#28]             @ impossible key power value
-# ifndef __KERNEL__
-       adr     r11,.Lpoly1305_init
-       ldr     r12,.LOPENSSL_armcap
-# endif
-#endif
-       ldrb    r4,[r1,#0]
-       mov     r10,#0x0fffffff
-       ldrb    r5,[r1,#1]
-       and     r3,r10,#-4              @ 0x0ffffffc
-       ldrb    r6,[r1,#2]
-       ldrb    r7,[r1,#3]
-       orr     r4,r4,r5,lsl#8
-       ldrb    r5,[r1,#4]
-       orr     r4,r4,r6,lsl#16
-       ldrb    r6,[r1,#5]
-       orr     r4,r4,r7,lsl#24
-       ldrb    r7,[r1,#6]
-       and     r4,r4,r10
-
-#if    __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-# if !defined(_WIN32)
-       ldr     r12,[r11,r12]           @ OPENSSL_armcap_P
-# endif
-# if defined(__APPLE__) || defined(_WIN32)
-       ldr     r12,[r12]
-# endif
-#endif
-       ldrb    r8,[r1,#7]
-       orr     r5,r5,r6,lsl#8
-       ldrb    r6,[r1,#8]
-       orr     r5,r5,r7,lsl#16
-       ldrb    r7,[r1,#9]
-       orr     r5,r5,r8,lsl#24
-       ldrb    r8,[r1,#10]
-       and     r5,r5,r3
-
-#if    __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-       tst     r12,#ARMV7_NEON         @ check for NEON
-# ifdef        __thumb2__
-       adr     r9,.Lpoly1305_blocks_neon
-       adr     r11,.Lpoly1305_blocks
-       it      ne
-       movne   r11,r9
-       adr     r12,.Lpoly1305_emit
-       orr     r11,r11,#1              @ thumb-ify addresses
-       orr     r12,r12,#1
-# else
-       add     r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init)
-       ite     eq
-       addeq   r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init)
-       addne   r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init)
-# endif
-#endif
-       ldrb    r9,[r1,#11]
-       orr     r6,r6,r7,lsl#8
-       ldrb    r7,[r1,#12]
-       orr     r6,r6,r8,lsl#16
-       ldrb    r8,[r1,#13]
-       orr     r6,r6,r9,lsl#24
-       ldrb    r9,[r1,#14]
-       and     r6,r6,r3
-
-       ldrb    r10,[r1,#15]
-       orr     r7,r7,r8,lsl#8
-       str     r4,[r0,#0]
-       orr     r7,r7,r9,lsl#16
-       str     r5,[r0,#4]
-       orr     r7,r7,r10,lsl#24
-       str     r6,[r0,#8]
-       and     r7,r7,r3
-       str     r7,[r0,#12]
-#if    __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-       stmia   r2,{r11,r12}            @ fill functions table
-       mov     r0,#1
-#else
-       mov     r0,#0
-#endif
-.Lno_key:
-       ldmia   sp!,{r4-r11}
-#if    __ARM_ARCH__>=5
-       bx      lr                              @ bx    lr
-#else
-       tst     lr,#1
-       moveq   pc,lr                   @ be binary compatible with V4, yet
-       .word   0xe12fff1e                      @ interoperable with Thumb ISA:-)
-#endif
-.size  poly1305_init,.-poly1305_init
-.type  poly1305_blocks,%function
-.align 5
-poly1305_blocks:
-.Lpoly1305_blocks:
-       stmdb   sp!,{r3-r11,lr}
-
-       ands    r2,r2,#-16
-       beq     .Lno_data
-
-       add     r2,r2,r1                @ end pointer
-       sub     sp,sp,#32
-
-#if __ARM_ARCH__<7
-       ldmia   r0,{r4-r12}             @ load context
-       add     r0,r0,#20
-       str     r2,[sp,#16]             @ offload stuff
-       str     r0,[sp,#12]
-#else
-       ldr     lr,[r0,#36]             @ is_base2_26
-       ldmia   r0!,{r4-r8}             @ load hash value
-       str     r2,[sp,#16]             @ offload stuff
-       str     r0,[sp,#12]
-
-       adds    r9,r4,r5,lsl#26 @ base 2^26 -> base 2^32
-       mov     r10,r5,lsr#6
-       adcs    r10,r10,r6,lsl#20
-       mov     r11,r6,lsr#12
-       adcs    r11,r11,r7,lsl#14
-       mov     r12,r7,lsr#18
-       adcs    r12,r12,r8,lsl#8
-       mov     r2,#0
-       teq     lr,#0
-       str     r2,[r0,#16]             @ clear is_base2_26
-       adc     r2,r2,r8,lsr#24
-
-       itttt   ne
-       movne   r4,r9                   @ choose between radixes
-       movne   r5,r10
-       movne   r6,r11
-       movne   r7,r12
-       ldmia   r0,{r9-r12}             @ load key
-       it      ne
-       movne   r8,r2
-#endif
-
-       mov     lr,r1
-       cmp     r3,#0
-       str     r10,[sp,#20]
-       str     r11,[sp,#24]
-       str     r12,[sp,#28]
-       b       .Loop
-
-.align 4
-.Loop:
-#if __ARM_ARCH__<7
-       ldrb    r0,[lr],#16             @ load input
-# ifdef        __thumb2__
-       it      hi
-# endif
-       addhi   r8,r8,#1                @ 1<<128
-       ldrb    r1,[lr,#-15]
-       ldrb    r2,[lr,#-14]
-       ldrb    r3,[lr,#-13]
-       orr     r1,r0,r1,lsl#8
-       ldrb    r0,[lr,#-12]
-       orr     r2,r1,r2,lsl#16
-       ldrb    r1,[lr,#-11]
-       orr     r3,r2,r3,lsl#24
-       ldrb    r2,[lr,#-10]
-       adds    r4,r4,r3                @ accumulate input
-
-       ldrb    r3,[lr,#-9]
-       orr     r1,r0,r1,lsl#8
-       ldrb    r0,[lr,#-8]
-       orr     r2,r1,r2,lsl#16
-       ldrb    r1,[lr,#-7]
-       orr     r3,r2,r3,lsl#24
-       ldrb    r2,[lr,#-6]
-       adcs    r5,r5,r3
-
-       ldrb    r3,[lr,#-5]
-       orr     r1,r0,r1,lsl#8
-       ldrb    r0,[lr,#-4]
-       orr     r2,r1,r2,lsl#16
-       ldrb    r1,[lr,#-3]
-       orr     r3,r2,r3,lsl#24
-       ldrb    r2,[lr,#-2]
-       adcs    r6,r6,r3
-
-       ldrb    r3,[lr,#-1]
-       orr     r1,r0,r1,lsl#8
-       str     lr,[sp,#8]              @ offload input pointer
-       orr     r2,r1,r2,lsl#16
-       add     r10,r10,r10,lsr#2
-       orr     r3,r2,r3,lsl#24
-#else
-       ldr     r0,[lr],#16             @ load input
-       it      hi
-       addhi   r8,r8,#1                @ padbit
-       ldr     r1,[lr,#-12]
-       ldr     r2,[lr,#-8]
-       ldr     r3,[lr,#-4]
-# ifdef        __ARMEB__
-       rev     r0,r0
-       rev     r1,r1
-       rev     r2,r2
-       rev     r3,r3
-# endif
-       adds    r4,r4,r0                @ accumulate input
-       str     lr,[sp,#8]              @ offload input pointer
-       adcs    r5,r5,r1
-       add     r10,r10,r10,lsr#2
-       adcs    r6,r6,r2
-#endif
-       add     r11,r11,r11,lsr#2
-       adcs    r7,r7,r3
-       add     r12,r12,r12,lsr#2
-
-       umull   r2,r3,r5,r9
-        adc    r8,r8,#0
-       umull   r0,r1,r4,r9
-       umlal   r2,r3,r8,r10
-       umlal   r0,r1,r7,r10
-       ldr     r10,[sp,#20]            @ reload r10
-       umlal   r2,r3,r6,r12
-       umlal   r0,r1,r5,r12
-       umlal   r2,r3,r7,r11
-       umlal   r0,r1,r6,r11
-       umlal   r2,r3,r4,r10
-       str     r0,[sp,#0]              @ future r4
-        mul    r0,r11,r8
-       ldr     r11,[sp,#24]            @ reload r11
-       adds    r2,r2,r1                @ d1+=d0>>32
-        eor    r1,r1,r1
-       adc     lr,r3,#0                @ future r6
-       str     r2,[sp,#4]              @ future r5
-
-       mul     r2,r12,r8
-       eor     r3,r3,r3
-       umlal   r0,r1,r7,r12
-       ldr     r12,[sp,#28]            @ reload r12
-       umlal   r2,r3,r7,r9
-       umlal   r0,r1,r6,r9
-       umlal   r2,r3,r6,r10
-       umlal   r0,r1,r5,r10
-       umlal   r2,r3,r5,r11
-       umlal   r0,r1,r4,r11
-       umlal   r2,r3,r4,r12
-       ldr     r4,[sp,#0]
-       mul     r8,r9,r8
-       ldr     r5,[sp,#4]
-
-       adds    r6,lr,r0                @ d2+=d1>>32
-       ldr     lr,[sp,#8]              @ reload input pointer
-       adc     r1,r1,#0
-       adds    r7,r2,r1                @ d3+=d2>>32
-       ldr     r0,[sp,#16]             @ reload end pointer
-       adc     r3,r3,#0
-       add     r8,r8,r3                @ h4+=d3>>32
-
-       and     r1,r8,#-4
-       and     r8,r8,#3
-       add     r1,r1,r1,lsr#2          @ *=5
-       adds    r4,r4,r1
-       adcs    r5,r5,#0
-       adcs    r6,r6,#0
-       adcs    r7,r7,#0
-       adc     r8,r8,#0
-
-       cmp     r0,lr                   @ done yet?
-       bhi     .Loop
-
-       ldr     r0,[sp,#12]
-       add     sp,sp,#32
-       stmdb   r0,{r4-r8}              @ store the result
-
-.Lno_data:
-#if    __ARM_ARCH__>=5
-       ldmia   sp!,{r3-r11,pc}
-#else
-       ldmia   sp!,{r3-r11,lr}
-       tst     lr,#1
-       moveq   pc,lr                   @ be binary compatible with V4, yet
-       .word   0xe12fff1e                      @ interoperable with Thumb ISA:-)
-#endif
-.size  poly1305_blocks,.-poly1305_blocks
-.type  poly1305_emit,%function
-.align 5
-poly1305_emit:
-.Lpoly1305_emit:
-       stmdb   sp!,{r4-r11}
-
-       ldmia   r0,{r3-r7}
-
-#if __ARM_ARCH__>=7
-       ldr     ip,[r0,#36]             @ is_base2_26
-
-       adds    r8,r3,r4,lsl#26 @ base 2^26 -> base 2^32
-       mov     r9,r4,lsr#6
-       adcs    r9,r9,r5,lsl#20
-       mov     r10,r5,lsr#12
-       adcs    r10,r10,r6,lsl#14
-       mov     r11,r6,lsr#18
-       adcs    r11,r11,r7,lsl#8
-       mov     r0,#0
-       adc     r0,r0,r7,lsr#24
-
-       tst     ip,ip
-       itttt   ne
-       movne   r3,r8
-       movne   r4,r9
-       movne   r5,r10
-       movne   r6,r11
-       it      ne
-       movne   r7,r0
-#endif
-
-       adds    r8,r3,#5                @ compare to modulus
-       adcs    r9,r4,#0
-       adcs    r10,r5,#0
-       adcs    r11,r6,#0
-       adc     r0,r7,#0
-       tst     r0,#4                   @ did it carry/borrow?
-
-#ifdef __thumb2__
-       it      ne
-#endif
-       movne   r3,r8
-       ldr     r8,[r2,#0]
-#ifdef __thumb2__
-       it      ne
-#endif
-       movne   r4,r9
-       ldr     r9,[r2,#4]
-#ifdef __thumb2__
-       it      ne
-#endif
-       movne   r5,r10
-       ldr     r10,[r2,#8]
-#ifdef __thumb2__
-       it      ne
-#endif
-       movne   r6,r11
-       ldr     r11,[r2,#12]
-
-       adds    r3,r3,r8
-       adcs    r4,r4,r9
-       adcs    r5,r5,r10
-       adc     r6,r6,r11
-
-#if __ARM_ARCH__>=7
-# ifdef __ARMEB__
-       rev     r3,r3
-       rev     r4,r4
-       rev     r5,r5
-       rev     r6,r6
-# endif
-       str     r3,[r1,#0]
-       str     r4,[r1,#4]
-       str     r5,[r1,#8]
-       str     r6,[r1,#12]
-#else
-       strb    r3,[r1,#0]
-       mov     r3,r3,lsr#8
-       strb    r4,[r1,#4]
-       mov     r4,r4,lsr#8
-       strb    r5,[r1,#8]
-       mov     r5,r5,lsr#8
-       strb    r6,[r1,#12]
-       mov     r6,r6,lsr#8
-
-       strb    r3,[r1,#1]
-       mov     r3,r3,lsr#8
-       strb    r4,[r1,#5]
-       mov     r4,r4,lsr#8
-       strb    r5,[r1,#9]
-       mov     r5,r5,lsr#8
-       strb    r6,[r1,#13]
-       mov     r6,r6,lsr#8
-
-       strb    r3,[r1,#2]
-       mov     r3,r3,lsr#8
-       strb    r4,[r1,#6]
-       mov     r4,r4,lsr#8
-       strb    r5,[r1,#10]
-       mov     r5,r5,lsr#8
-       strb    r6,[r1,#14]
-       mov     r6,r6,lsr#8
-
-       strb    r3,[r1,#3]
-       strb    r4,[r1,#7]
-       strb    r5,[r1,#11]
-       strb    r6,[r1,#15]
-#endif
-       ldmia   sp!,{r4-r11}
-#if    __ARM_ARCH__>=5
-       bx      lr                              @ bx    lr
-#else
-       tst     lr,#1
-       moveq   pc,lr                   @ be binary compatible with V4, yet
-       .word   0xe12fff1e                      @ interoperable with Thumb ISA:-)
-#endif
-.size  poly1305_emit,.-poly1305_emit
-#if    __ARM_MAX_ARCH__>=7
-.fpu   neon
-
-.type  poly1305_init_neon,%function
-.align 5
-poly1305_init_neon:
-.Lpoly1305_init_neon:
-       ldr     r3,[r0,#48]             @ first table element
-       cmp     r3,#-1                  @ is value impossible?
-       bne     .Lno_init_neon
-
-       ldr     r4,[r0,#20]             @ load key base 2^32
-       ldr     r5,[r0,#24]
-       ldr     r6,[r0,#28]
-       ldr     r7,[r0,#32]
-
-       and     r2,r4,#0x03ffffff       @ base 2^32 -> base 2^26
-       mov     r3,r4,lsr#26
-       mov     r4,r5,lsr#20
-       orr     r3,r3,r5,lsl#6
-       mov     r5,r6,lsr#14
-       orr     r4,r4,r6,lsl#12
-       mov     r6,r7,lsr#8
-       orr     r5,r5,r7,lsl#18
-       and     r3,r3,#0x03ffffff
-       and     r4,r4,#0x03ffffff
-       and     r5,r5,#0x03ffffff
-
-       vdup.32 d0,r2                   @ r^1 in both lanes
-       add     r2,r3,r3,lsl#2          @ *5
-       vdup.32 d1,r3
-       add     r3,r4,r4,lsl#2
-       vdup.32 d2,r2
-       vdup.32 d3,r4
-       add     r4,r5,r5,lsl#2
-       vdup.32 d4,r3
-       vdup.32 d5,r5
-       add     r5,r6,r6,lsl#2
-       vdup.32 d6,r4
-       vdup.32 d7,r6
-       vdup.32 d8,r5
-
-       mov     r5,#2           @ counter
-
-.Lsquare_neon:
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
-       @ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
-       @ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
-       @ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
-       @ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
-
-       vmull.u32       q5,d0,d0[1]
-       vmull.u32       q6,d1,d0[1]
-       vmull.u32       q7,d3,d0[1]
-       vmull.u32       q8,d5,d0[1]
-       vmull.u32       q9,d7,d0[1]
-
-       vmlal.u32       q5,d7,d2[1]
-       vmlal.u32       q6,d0,d1[1]
-       vmlal.u32       q7,d1,d1[1]
-       vmlal.u32       q8,d3,d1[1]
-       vmlal.u32       q9,d5,d1[1]
-
-       vmlal.u32       q5,d5,d4[1]
-       vmlal.u32       q6,d7,d4[1]
-       vmlal.u32       q8,d1,d3[1]
-       vmlal.u32       q7,d0,d3[1]
-       vmlal.u32       q9,d3,d3[1]
-
-       vmlal.u32       q5,d3,d6[1]
-       vmlal.u32       q8,d0,d5[1]
-       vmlal.u32       q6,d5,d6[1]
-       vmlal.u32       q7,d7,d6[1]
-       vmlal.u32       q9,d1,d5[1]
-
-       vmlal.u32       q8,d7,d8[1]
-       vmlal.u32       q5,d1,d8[1]
-       vmlal.u32       q6,d3,d8[1]
-       vmlal.u32       q7,d5,d8[1]
-       vmlal.u32       q9,d0,d7[1]
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
-       @ and P. Schwabe
-       @
-       @ H0>>+H1>>+H2>>+H3>>+H4
-       @ H3>>+H4>>*5+H0>>+H1
-       @
-       @ Trivia.
-       @
-       @ Result of multiplication of n-bit number by m-bit number is
-       @ n+m bits wide. However! Even though 2^n is a n+1-bit number,
-       @ m-bit number multiplied by 2^n is still n+m bits wide.
-       @
-       @ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2,
-       @ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit
-       @ one is n+1 bits wide.
-       @
-       @ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that
-       @ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4
-       @ can be 27. However! In cases when their width exceeds 26 bits
-       @ they are limited by 2^26+2^6. This in turn means that *sum*
-       @ of the products with these values can still be viewed as sum
-       @ of 52-bit numbers as long as the amount of addends is not a
-       @ power of 2. For example,
-       @
-       @ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4,
-       @
-       @ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or
-       @ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than
-       @ 8 * (2^52) or 2^55. However, the value is then multiplied by
-       @ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12),
-       @ which is less than 32 * (2^52) or 2^57. And when processing
-       @ data we are looking at triple as many addends...
-       @
-       @ In key setup procedure pre-reduced H0 is limited by 5*4+1 and
-       @ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the
-       @ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while
-       @ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32
-       @ instruction accepts 2x32-bit input and writes 2x64-bit result.
-       @ This means that result of reduction have to be compressed upon
-       @ loop wrap-around. This can be done in the process of reduction
-       @ to minimize amount of instructions [as well as amount of
-       @ 128-bit instructions, which benefits low-end processors], but
-       @ one has to watch for H2 (which is narrower than H0) and 5*H4
-       @ not being wider than 58 bits, so that result of right shift
-       @ by 26 bits fits in 32 bits. This is also useful on x86,
-       @ because it allows to use paddd in place for paddq, which
-       @ benefits Atom, where paddq is ridiculously slow.
-
-       vshr.u64        q15,q8,#26
-       vmovn.i64       d16,q8
-        vshr.u64       q4,q5,#26
-        vmovn.i64      d10,q5
-       vadd.i64        q9,q9,q15               @ h3 -> h4
-       vbic.i32        d16,#0xfc000000 @ &=0x03ffffff
-        vadd.i64       q6,q6,q4                @ h0 -> h1
-        vbic.i32       d10,#0xfc000000
-
-       vshrn.u64       d30,q9,#26
-       vmovn.i64       d18,q9
-        vshr.u64       q4,q6,#26
-        vmovn.i64      d12,q6
-        vadd.i64       q7,q7,q4                @ h1 -> h2
-       vbic.i32        d18,#0xfc000000
-        vbic.i32       d12,#0xfc000000
-
-       vadd.i32        d10,d10,d30
-       vshl.u32        d30,d30,#2
-        vshrn.u64      d8,q7,#26
-        vmovn.i64      d14,q7
-       vadd.i32        d10,d10,d30     @ h4 -> h0
-        vadd.i32       d16,d16,d8      @ h2 -> h3
-        vbic.i32       d14,#0xfc000000
-
-       vshr.u32        d30,d10,#26
-       vbic.i32        d10,#0xfc000000
-        vshr.u32       d8,d16,#26
-        vbic.i32       d16,#0xfc000000
-       vadd.i32        d12,d12,d30     @ h0 -> h1
-        vadd.i32       d18,d18,d8      @ h3 -> h4
-
-       subs            r5,r5,#1
-       beq             .Lsquare_break_neon
-
-       add             r6,r0,#(48+0*9*4)
-       add             r7,r0,#(48+1*9*4)
-
-       vtrn.32         d0,d10          @ r^2:r^1
-       vtrn.32         d3,d14
-       vtrn.32         d5,d16
-       vtrn.32         d1,d12
-       vtrn.32         d7,d18
-
-       vshl.u32        d4,d3,#2                @ *5
-       vshl.u32        d6,d5,#2
-       vshl.u32        d2,d1,#2
-       vshl.u32        d8,d7,#2
-       vadd.i32        d4,d4,d3
-       vadd.i32        d2,d2,d1
-       vadd.i32        d6,d6,d5
-       vadd.i32        d8,d8,d7
-
-       vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r6]!
-       vst4.32         {d0[1],d1[1],d2[1],d3[1]},[r7]!
-       vst4.32         {d4[0],d5[0],d6[0],d7[0]},[r6]!
-       vst4.32         {d4[1],d5[1],d6[1],d7[1]},[r7]!
-       vst1.32         {d8[0]},[r6,:32]
-       vst1.32         {d8[1]},[r7,:32]
-
-       b               .Lsquare_neon
-
-.align 4
-.Lsquare_break_neon:
-       add             r6,r0,#(48+2*4*9)
-       add             r7,r0,#(48+3*4*9)
-
-       vmov            d0,d10          @ r^4:r^3
-       vshl.u32        d2,d12,#2               @ *5
-       vmov            d1,d12
-       vshl.u32        d4,d14,#2
-       vmov            d3,d14
-       vshl.u32        d6,d16,#2
-       vmov            d5,d16
-       vshl.u32        d8,d18,#2
-       vmov            d7,d18
-       vadd.i32        d2,d2,d12
-       vadd.i32        d4,d4,d14
-       vadd.i32        d6,d6,d16
-       vadd.i32        d8,d8,d18
-
-       vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r6]!
-       vst4.32         {d0[1],d1[1],d2[1],d3[1]},[r7]!
-       vst4.32         {d4[0],d5[0],d6[0],d7[0]},[r6]!
-       vst4.32         {d4[1],d5[1],d6[1],d7[1]},[r7]!
-       vst1.32         {d8[0]},[r6]
-       vst1.32         {d8[1]},[r7]
-
-.Lno_init_neon:
-       bx      lr                              @ bx    lr
-.size  poly1305_init_neon,.-poly1305_init_neon
-
-.type  poly1305_blocks_neon,%function
-.align 5
-poly1305_blocks_neon:
-.Lpoly1305_blocks_neon:
-       ldr     ip,[r0,#36]             @ is_base2_26
-
-       cmp     r2,#64
-       blo     .Lpoly1305_blocks
-
-       stmdb   sp!,{r4-r7}
-       vstmdb  sp!,{d8-d15}            @ ABI specification says so
-
-       tst     ip,ip                   @ is_base2_26?
-       bne     .Lbase2_26_neon
-
-       stmdb   sp!,{r1-r3,lr}
-       bl      .Lpoly1305_init_neon
-
-       ldr     r4,[r0,#0]              @ load hash value base 2^32
-       ldr     r5,[r0,#4]
-       ldr     r6,[r0,#8]
-       ldr     r7,[r0,#12]
-       ldr     ip,[r0,#16]
-
-       and     r2,r4,#0x03ffffff       @ base 2^32 -> base 2^26
-       mov     r3,r4,lsr#26
-        veor   d10,d10,d10
-       mov     r4,r5,lsr#20
-       orr     r3,r3,r5,lsl#6
-        veor   d12,d12,d12
-       mov     r5,r6,lsr#14
-       orr     r4,r4,r6,lsl#12
-        veor   d14,d14,d14
-       mov     r6,r7,lsr#8
-       orr     r5,r5,r7,lsl#18
-        veor   d16,d16,d16
-       and     r3,r3,#0x03ffffff
-       orr     r6,r6,ip,lsl#24
-        veor   d18,d18,d18
-       and     r4,r4,#0x03ffffff
-       mov     r1,#1
-       and     r5,r5,#0x03ffffff
-       str     r1,[r0,#36]             @ set is_base2_26
-
-       vmov.32 d10[0],r2
-       vmov.32 d12[0],r3
-       vmov.32 d14[0],r4
-       vmov.32 d16[0],r5
-       vmov.32 d18[0],r6
-       adr     r5,.Lzeros
-
-       ldmia   sp!,{r1-r3,lr}
-       b       .Lhash_loaded
-
-.align 4
-.Lbase2_26_neon:
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ load hash value
-
-       veor            d10,d10,d10
-       veor            d12,d12,d12
-       veor            d14,d14,d14
-       veor            d16,d16,d16
-       veor            d18,d18,d18
-       vld4.32         {d10[0],d12[0],d14[0],d16[0]},[r0]!
-       adr             r5,.Lzeros
-       vld1.32         {d18[0]},[r0]
-       sub             r0,r0,#16               @ rewind
-
-.Lhash_loaded:
-       add             r4,r1,#32
-       mov             r3,r3,lsl#24
-       tst             r2,#31
-       beq             .Leven
-
-       vld4.32         {d20[0],d22[0],d24[0],d26[0]},[r1]!
-       vmov.32         d28[0],r3
-       sub             r2,r2,#16
-       add             r4,r1,#32
-
-# ifdef        __ARMEB__
-       vrev32.8        q10,q10
-       vrev32.8        q13,q13
-       vrev32.8        q11,q11
-       vrev32.8        q12,q12
-# endif
-       vsri.u32        d28,d26,#8      @ base 2^32 -> base 2^26
-       vshl.u32        d26,d26,#18
-
-       vsri.u32        d26,d24,#14
-       vshl.u32        d24,d24,#12
-       vadd.i32        d29,d28,d18     @ add hash value and move to #hi
-
-       vbic.i32        d26,#0xfc000000
-       vsri.u32        d24,d22,#20
-       vshl.u32        d22,d22,#6
-
-       vbic.i32        d24,#0xfc000000
-       vsri.u32        d22,d20,#26
-       vadd.i32        d27,d26,d16
-
-       vbic.i32        d20,#0xfc000000
-       vbic.i32        d22,#0xfc000000
-       vadd.i32        d25,d24,d14
-
-       vadd.i32        d21,d20,d10
-       vadd.i32        d23,d22,d12
-
-       mov             r7,r5
-       add             r6,r0,#48
-
-       cmp             r2,r2
-       b               .Long_tail
-
-.align 4
-.Leven:
-       subs            r2,r2,#64
-       it              lo
-       movlo           r4,r5
-
-       vmov.i32        q14,#1<<24              @ padbit, yes, always
-       vld4.32         {d20,d22,d24,d26},[r1]  @ inp[0:1]
-       add             r1,r1,#64
-       vld4.32         {d21,d23,d25,d27},[r4]  @ inp[2:3] (or 0)
-       add             r4,r4,#64
-       itt             hi
-       addhi           r7,r0,#(48+1*9*4)
-       addhi           r6,r0,#(48+3*9*4)
-
-# ifdef        __ARMEB__
-       vrev32.8        q10,q10
-       vrev32.8        q13,q13
-       vrev32.8        q11,q11
-       vrev32.8        q12,q12
-# endif
-       vsri.u32        q14,q13,#8              @ base 2^32 -> base 2^26
-       vshl.u32        q13,q13,#18
-
-       vsri.u32        q13,q12,#14
-       vshl.u32        q12,q12,#12
-
-       vbic.i32        q13,#0xfc000000
-       vsri.u32        q12,q11,#20
-       vshl.u32        q11,q11,#6
-
-       vbic.i32        q12,#0xfc000000
-       vsri.u32        q11,q10,#26
-
-       vbic.i32        q10,#0xfc000000
-       vbic.i32        q11,#0xfc000000
-
-       bls             .Lskip_loop
-
-       vld4.32         {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^2
-       vld4.32         {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^4
-       vld4.32         {d4[1],d5[1],d6[1],d7[1]},[r7]!
-       vld4.32         {d4[0],d5[0],d6[0],d7[0]},[r6]!
-       b               .Loop_neon
-
-.align 5
-.Loop_neon:
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
-       @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
-       @   ___________________/
-       @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
-       @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
-       @   ___________________/ ____________________/
-       @
-       @ Note that we start with inp[2:3]*r^2. This is because it
-       @ doesn't depend on reduction in previous iteration.
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
-       @ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
-       @ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
-       @ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
-       @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ inp[2:3]*r^2
-
-       vadd.i32        d24,d24,d14     @ accumulate inp[0:1]
-       vmull.u32       q7,d25,d0[1]
-       vadd.i32        d20,d20,d10
-       vmull.u32       q5,d21,d0[1]
-       vadd.i32        d26,d26,d16
-       vmull.u32       q8,d27,d0[1]
-       vmlal.u32       q7,d23,d1[1]
-       vadd.i32        d22,d22,d12
-       vmull.u32       q6,d23,d0[1]
-
-       vadd.i32        d28,d28,d18
-       vmull.u32       q9,d29,d0[1]
-       subs            r2,r2,#64
-       vmlal.u32       q5,d29,d2[1]
-       it              lo
-       movlo           r4,r5
-       vmlal.u32       q8,d25,d1[1]
-       vld1.32         d8[1],[r7,:32]
-       vmlal.u32       q6,d21,d1[1]
-       vmlal.u32       q9,d27,d1[1]
-
-       vmlal.u32       q5,d27,d4[1]
-       vmlal.u32       q8,d23,d3[1]
-       vmlal.u32       q9,d25,d3[1]
-       vmlal.u32       q6,d29,d4[1]
-       vmlal.u32       q7,d21,d3[1]
-
-       vmlal.u32       q8,d21,d5[1]
-       vmlal.u32       q5,d25,d6[1]
-       vmlal.u32       q9,d23,d5[1]
-       vmlal.u32       q6,d27,d6[1]
-       vmlal.u32       q7,d29,d6[1]
-
-       vmlal.u32       q8,d29,d8[1]
-       vmlal.u32       q5,d23,d8[1]
-       vmlal.u32       q9,d21,d7[1]
-       vmlal.u32       q6,d25,d8[1]
-       vmlal.u32       q7,d27,d8[1]
-
-       vld4.32         {d21,d23,d25,d27},[r4]  @ inp[2:3] (or 0)
-       add             r4,r4,#64
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ (hash+inp[0:1])*r^4 and accumulate
-
-       vmlal.u32       q8,d26,d0[0]
-       vmlal.u32       q5,d20,d0[0]
-       vmlal.u32       q9,d28,d0[0]
-       vmlal.u32       q6,d22,d0[0]
-       vmlal.u32       q7,d24,d0[0]
-       vld1.32         d8[0],[r6,:32]
-
-       vmlal.u32       q8,d24,d1[0]
-       vmlal.u32       q5,d28,d2[0]
-       vmlal.u32       q9,d26,d1[0]
-       vmlal.u32       q6,d20,d1[0]
-       vmlal.u32       q7,d22,d1[0]
-
-       vmlal.u32       q8,d22,d3[0]
-       vmlal.u32       q5,d26,d4[0]
-       vmlal.u32       q9,d24,d3[0]
-       vmlal.u32       q6,d28,d4[0]
-       vmlal.u32       q7,d20,d3[0]
-
-       vmlal.u32       q8,d20,d5[0]
-       vmlal.u32       q5,d24,d6[0]
-       vmlal.u32       q9,d22,d5[0]
-       vmlal.u32       q6,d26,d6[0]
-       vmlal.u32       q8,d28,d8[0]
-
-       vmlal.u32       q7,d28,d6[0]
-       vmlal.u32       q5,d22,d8[0]
-       vmlal.u32       q9,d20,d7[0]
-       vmov.i32        q14,#1<<24              @ padbit, yes, always
-       vmlal.u32       q6,d24,d8[0]
-       vmlal.u32       q7,d26,d8[0]
-
-       vld4.32         {d20,d22,d24,d26},[r1]  @ inp[0:1]
-       add             r1,r1,#64
-# ifdef        __ARMEB__
-       vrev32.8        q10,q10
-       vrev32.8        q11,q11
-       vrev32.8        q12,q12
-       vrev32.8        q13,q13
-# endif
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ lazy reduction interleaved with base 2^32 -> base 2^26 of
-       @ inp[0:3] previously loaded to q10-q13 and smashed to q10-q14.
-
-       vshr.u64        q15,q8,#26
-       vmovn.i64       d16,q8
-        vshr.u64       q4,q5,#26
-        vmovn.i64      d10,q5
-       vadd.i64        q9,q9,q15               @ h3 -> h4
-       vbic.i32        d16,#0xfc000000
-         vsri.u32      q14,q13,#8              @ base 2^32 -> base 2^26
-        vadd.i64       q6,q6,q4                @ h0 -> h1
-         vshl.u32      q13,q13,#18
-        vbic.i32       d10,#0xfc000000
-
-       vshrn.u64       d30,q9,#26
-       vmovn.i64       d18,q9
-        vshr.u64       q4,q6,#26
-        vmovn.i64      d12,q6
-        vadd.i64       q7,q7,q4                @ h1 -> h2
-         vsri.u32      q13,q12,#14
-       vbic.i32        d18,#0xfc000000
-         vshl.u32      q12,q12,#12
-        vbic.i32       d12,#0xfc000000
-
-       vadd.i32        d10,d10,d30
-       vshl.u32        d30,d30,#2
-         vbic.i32      q13,#0xfc000000
-        vshrn.u64      d8,q7,#26
-        vmovn.i64      d14,q7
-       vaddl.u32       q5,d10,d30      @ h4 -> h0 [widen for a sec]
-         vsri.u32      q12,q11,#20
-        vadd.i32       d16,d16,d8      @ h2 -> h3
-         vshl.u32      q11,q11,#6
-        vbic.i32       d14,#0xfc000000
-         vbic.i32      q12,#0xfc000000
-
-       vshrn.u64       d30,q5,#26              @ re-narrow
-       vmovn.i64       d10,q5
-         vsri.u32      q11,q10,#26
-         vbic.i32      q10,#0xfc000000
-        vshr.u32       d8,d16,#26
-        vbic.i32       d16,#0xfc000000
-       vbic.i32        d10,#0xfc000000
-       vadd.i32        d12,d12,d30     @ h0 -> h1
-        vadd.i32       d18,d18,d8      @ h3 -> h4
-         vbic.i32      q11,#0xfc000000
-
-       bhi             .Loop_neon
-
-.Lskip_loop:
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
-
-       add             r7,r0,#(48+0*9*4)
-       add             r6,r0,#(48+1*9*4)
-       adds            r2,r2,#32
-       it              ne
-       movne           r2,#0
-       bne             .Long_tail
-
-       vadd.i32        d25,d24,d14     @ add hash value and move to #hi
-       vadd.i32        d21,d20,d10
-       vadd.i32        d27,d26,d16
-       vadd.i32        d23,d22,d12
-       vadd.i32        d29,d28,d18
-
-.Long_tail:
-       vld4.32         {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^1
-       vld4.32         {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^2
-
-       vadd.i32        d24,d24,d14     @ can be redundant
-       vmull.u32       q7,d25,d0
-       vadd.i32        d20,d20,d10
-       vmull.u32       q5,d21,d0
-       vadd.i32        d26,d26,d16
-       vmull.u32       q8,d27,d0
-       vadd.i32        d22,d22,d12
-       vmull.u32       q6,d23,d0
-       vadd.i32        d28,d28,d18
-       vmull.u32       q9,d29,d0
-
-       vmlal.u32       q5,d29,d2
-       vld4.32         {d4[1],d5[1],d6[1],d7[1]},[r7]!
-       vmlal.u32       q8,d25,d1
-       vld4.32         {d4[0],d5[0],d6[0],d7[0]},[r6]!
-       vmlal.u32       q6,d21,d1
-       vmlal.u32       q9,d27,d1
-       vmlal.u32       q7,d23,d1
-
-       vmlal.u32       q8,d23,d3
-       vld1.32         d8[1],[r7,:32]
-       vmlal.u32       q5,d27,d4
-       vld1.32         d8[0],[r6,:32]
-       vmlal.u32       q9,d25,d3
-       vmlal.u32       q6,d29,d4
-       vmlal.u32       q7,d21,d3
-
-       vmlal.u32       q8,d21,d5
-        it             ne
-        addne          r7,r0,#(48+2*9*4)
-       vmlal.u32       q5,d25,d6
-        it             ne
-        addne          r6,r0,#(48+3*9*4)
-       vmlal.u32       q9,d23,d5
-       vmlal.u32       q6,d27,d6
-       vmlal.u32       q7,d29,d6
-
-       vmlal.u32       q8,d29,d8
-        vorn           q0,q0,q0        @ all-ones, can be redundant
-       vmlal.u32       q5,d23,d8
-        vshr.u64       q0,q0,#38
-       vmlal.u32       q9,d21,d7
-       vmlal.u32       q6,d25,d8
-       vmlal.u32       q7,d27,d8
-
-       beq             .Lshort_tail
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ (hash+inp[0:1])*r^4:r^3 and accumulate
-
-       vld4.32         {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^3
-       vld4.32         {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^4
-
-       vmlal.u32       q7,d24,d0
-       vmlal.u32       q5,d20,d0
-       vmlal.u32       q8,d26,d0
-       vmlal.u32       q6,d22,d0
-       vmlal.u32       q9,d28,d0
-
-       vmlal.u32       q5,d28,d2
-       vld4.32         {d4[1],d5[1],d6[1],d7[1]},[r7]!
-       vmlal.u32       q8,d24,d1
-       vld4.32         {d4[0],d5[0],d6[0],d7[0]},[r6]!
-       vmlal.u32       q6,d20,d1
-       vmlal.u32       q9,d26,d1
-       vmlal.u32       q7,d22,d1
-
-       vmlal.u32       q8,d22,d3
-       vld1.32         d8[1],[r7,:32]
-       vmlal.u32       q5,d26,d4
-       vld1.32         d8[0],[r6,:32]
-       vmlal.u32       q9,d24,d3
-       vmlal.u32       q6,d28,d4
-       vmlal.u32       q7,d20,d3
-
-       vmlal.u32       q8,d20,d5
-       vmlal.u32       q5,d24,d6
-       vmlal.u32       q9,d22,d5
-       vmlal.u32       q6,d26,d6
-       vmlal.u32       q7,d28,d6
-
-       vmlal.u32       q8,d28,d8
-        vorn           q0,q0,q0        @ all-ones
-       vmlal.u32       q5,d22,d8
-        vshr.u64       q0,q0,#38
-       vmlal.u32       q9,d20,d7
-       vmlal.u32       q6,d24,d8
-       vmlal.u32       q7,d26,d8
-
-.Lshort_tail:
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ horizontal addition
-
-       vadd.i64        d16,d16,d17
-       vadd.i64        d10,d10,d11
-       vadd.i64        d18,d18,d19
-       vadd.i64        d12,d12,d13
-       vadd.i64        d14,d14,d15
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ lazy reduction, but without narrowing
-
-       vshr.u64        q15,q8,#26
-       vand.i64        q8,q8,q0
-        vshr.u64       q4,q5,#26
-        vand.i64       q5,q5,q0
-       vadd.i64        q9,q9,q15               @ h3 -> h4
-        vadd.i64       q6,q6,q4                @ h0 -> h1
-
-       vshr.u64        q15,q9,#26
-       vand.i64        q9,q9,q0
-        vshr.u64       q4,q6,#26
-        vand.i64       q6,q6,q0
-        vadd.i64       q7,q7,q4                @ h1 -> h2
-
-       vadd.i64        q5,q5,q15
-       vshl.u64        q15,q15,#2
-        vshr.u64       q4,q7,#26
-        vand.i64       q7,q7,q0
-       vadd.i64        q5,q5,q15               @ h4 -> h0
-        vadd.i64       q8,q8,q4                @ h2 -> h3
-
-       vshr.u64        q15,q5,#26
-       vand.i64        q5,q5,q0
-        vshr.u64       q4,q8,#26
-        vand.i64       q8,q8,q0
-       vadd.i64        q6,q6,q15               @ h0 -> h1
-        vadd.i64       q9,q9,q4                @ h3 -> h4
-
-       cmp             r2,#0
-       bne             .Leven
-
-       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-       @ store hash value
-
-       vst4.32         {d10[0],d12[0],d14[0],d16[0]},[r0]!
-       vst1.32         {d18[0]},[r0]
-
-       vldmia  sp!,{d8-d15}                    @ epilogue
-       ldmia   sp!,{r4-r7}
-       bx      lr                                      @ bx    lr
-.size  poly1305_blocks_neon,.-poly1305_blocks_neon
-
-.align 5
-.Lzeros:
-.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-#ifndef        __KERNEL__
-.LOPENSSL_armcap:
-# ifdef        _WIN32
-.word  OPENSSL_armcap_P
-# else
-.word  OPENSSL_armcap_P-.Lpoly1305_init
-# endif
-.comm  OPENSSL_armcap_P,4,4
-.hidden        OPENSSL_armcap_P
-#endif
-#endif
-.asciz "Poly1305 for ARMv4/NEON, CRYPTOGAMS by @dot-asm"
-.align 2
diff --git a/arch/arm/crypto/sha256-core.S_shipped b/arch/arm/crypto/sha256-core.S_shipped
deleted file mode 100644 (file)
index 6363014..0000000
+++ /dev/null
@@ -1,2816 +0,0 @@
-@ SPDX-License-Identifier: GPL-2.0
-
-@ This code is taken from the OpenSSL project but the author (Andy Polyakov)
-@ has relicensed it under the GPLv2. Therefore 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.
-@
-@ The original headers, including the original license headers, are
-@ included below for completeness.
-
-@ ====================================================================
-@ Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
-@ project. The module is, however, dual licensed under OpenSSL and
-@ CRYPTOGAMS licenses depending on where you obtain it. For further
-@ details see https://www.openssl.org/~appro/cryptogams/.
-@ ====================================================================
-
-@ SHA256 block procedure for ARMv4. May 2007.
-
-@ Performance is ~2x better than gcc 3.4 generated code and in "abso-
-@ lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per
-@ byte [on single-issue Xscale PXA250 core].
-
-@ July 2010.
-@
-@ Rescheduling for dual-issue pipeline resulted in 22% improvement on
-@ Cortex A8 core and ~20 cycles per processed byte.
-
-@ February 2011.
-@
-@ Profiler-assisted and platform-specific optimization resulted in 16%
-@ improvement on Cortex A8 core and ~15.4 cycles per processed byte.
-
-@ September 2013.
-@
-@ Add NEON implementation. On Cortex A8 it was measured to process one
-@ byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon
-@ S4 does it in 12.5 cycles too, but it's 50% faster than integer-only
-@ code (meaning that latter performs sub-optimally, nothing was done
-@ about it).
-
-@ May 2014.
-@
-@ Add ARMv8 code path performing at 2.0 cpb on Apple A7.
-
-#ifndef __KERNEL__
-# include "arm_arch.h"
-#else
-# define __ARM_ARCH__ __LINUX_ARM_ARCH__
-# define __ARM_MAX_ARCH__ 7
-#endif
-
-.text
-#if __ARM_ARCH__<7
-.code  32
-#else
-.syntax unified
-# ifdef __thumb2__
-.thumb
-# else
-.code   32
-# endif
-#endif
-
-.type  K256,%object
-.align 5
-K256:
-.word  0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
-.word  0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
-.word  0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
-.word  0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
-.word  0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
-.word  0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
-.word  0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
-.word  0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
-.word  0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
-.word  0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
-.word  0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
-.word  0xd192e819,0xd6990624,0xf40e3585,0x106aa070
-.word  0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
-.word  0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
-.word  0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
-.word  0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
-.size  K256,.-K256
-.word  0                               @ terminator
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-.LOPENSSL_armcap:
-.word  OPENSSL_armcap_P-sha256_block_data_order
-#endif
-.align 5
-
-.global        sha256_block_data_order
-.type  sha256_block_data_order,%function
-sha256_block_data_order:
-.Lsha256_block_data_order:
-#if __ARM_ARCH__<7
-       sub     r3,pc,#8                @ sha256_block_data_order
-#else
-       adr     r3,.Lsha256_block_data_order
-#endif
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-       ldr     r12,.LOPENSSL_armcap
-       ldr     r12,[r3,r12]            @ OPENSSL_armcap_P
-       tst     r12,#ARMV8_SHA256
-       bne     .LARMv8
-       tst     r12,#ARMV7_NEON
-       bne     .LNEON
-#endif
-       add     r2,r1,r2,lsl#6  @ len to point at the end of inp
-       stmdb   sp!,{r0,r1,r2,r4-r11,lr}
-       ldmia   r0,{r4,r5,r6,r7,r8,r9,r10,r11}
-       sub     r14,r3,#256+32  @ K256
-       sub     sp,sp,#16*4             @ alloca(X[16])
-.Loop:
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r5,r6                @ magic
-       eor     r12,r12,r12
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 0
-# if 0==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r8,r8,ror#5
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 0
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 0==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r8,r8,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r11,r11,r2                      @ h+=X[i]
-       str     r2,[sp,#0*4]
-       eor     r2,r9,r10
-       add     r11,r11,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r8
-       add     r11,r11,r12                     @ h+=K256[i]
-       eor     r2,r2,r10                       @ Ch(e,f,g)
-       eor     r0,r4,r4,ror#11
-       add     r11,r11,r2                      @ h+=Ch(e,f,g)
-#if 0==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 0<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#2*4]            @ from future BODY_16_xx
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-       ldr     r1,[sp,#15*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r4,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r7,r7,r11                       @ d+=h
-       eor     r3,r3,r5                        @ Maj(a,b,c)
-       add     r11,r11,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r11,r11,r3                      @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 1
-# if 1==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r7,r7,ror#5
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 1
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 1==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r7,r7,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r10,r10,r2                      @ h+=X[i]
-       str     r2,[sp,#1*4]
-       eor     r2,r8,r9
-       add     r10,r10,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r7
-       add     r10,r10,r3                      @ h+=K256[i]
-       eor     r2,r2,r9                        @ Ch(e,f,g)
-       eor     r0,r11,r11,ror#11
-       add     r10,r10,r2                      @ h+=Ch(e,f,g)
-#if 1==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 1<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#3*4]            @ from future BODY_16_xx
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-       ldr     r1,[sp,#0*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r11,ror#20        @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r6,r6,r10                       @ d+=h
-       eor     r12,r12,r4                      @ Maj(a,b,c)
-       add     r10,r10,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r10,r10,r12                     @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 2
-# if 2==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 2
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 2==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r6,r6,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r9,r9,r2                        @ h+=X[i]
-       str     r2,[sp,#2*4]
-       eor     r2,r7,r8
-       add     r9,r9,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r6
-       add     r9,r9,r12                       @ h+=K256[i]
-       eor     r2,r2,r8                        @ Ch(e,f,g)
-       eor     r0,r10,r10,ror#11
-       add     r9,r9,r2                        @ h+=Ch(e,f,g)
-#if 2==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 2<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#4*4]            @ from future BODY_16_xx
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-       ldr     r1,[sp,#1*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r10,ror#20        @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r5,r5,r9                        @ d+=h
-       eor     r3,r3,r11                       @ Maj(a,b,c)
-       add     r9,r9,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r9,r9,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 3
-# if 3==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r5,r5,ror#5
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 3
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 3==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r5,r5,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r8,r8,r2                        @ h+=X[i]
-       str     r2,[sp,#3*4]
-       eor     r2,r6,r7
-       add     r8,r8,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r5
-       add     r8,r8,r3                        @ h+=K256[i]
-       eor     r2,r2,r7                        @ Ch(e,f,g)
-       eor     r0,r9,r9,ror#11
-       add     r8,r8,r2                        @ h+=Ch(e,f,g)
-#if 3==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 3<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#5*4]            @ from future BODY_16_xx
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-       ldr     r1,[sp,#2*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r9,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r4,r4,r8                        @ d+=h
-       eor     r12,r12,r10                     @ Maj(a,b,c)
-       add     r8,r8,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r8,r8,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 4
-# if 4==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r4,r4,ror#5
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 4
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 4==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r4,r4,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r7,r7,r2                        @ h+=X[i]
-       str     r2,[sp,#4*4]
-       eor     r2,r5,r6
-       add     r7,r7,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r4
-       add     r7,r7,r12                       @ h+=K256[i]
-       eor     r2,r2,r6                        @ Ch(e,f,g)
-       eor     r0,r8,r8,ror#11
-       add     r7,r7,r2                        @ h+=Ch(e,f,g)
-#if 4==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 4<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#6*4]            @ from future BODY_16_xx
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-       ldr     r1,[sp,#3*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r8,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r11,r11,r7                      @ d+=h
-       eor     r3,r3,r9                        @ Maj(a,b,c)
-       add     r7,r7,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r7,r7,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 5
-# if 5==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r11,r11,ror#5
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 5
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 5==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r11,r11,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r6,r6,r2                        @ h+=X[i]
-       str     r2,[sp,#5*4]
-       eor     r2,r4,r5
-       add     r6,r6,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r11
-       add     r6,r6,r3                        @ h+=K256[i]
-       eor     r2,r2,r5                        @ Ch(e,f,g)
-       eor     r0,r7,r7,ror#11
-       add     r6,r6,r2                        @ h+=Ch(e,f,g)
-#if 5==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 5<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#7*4]            @ from future BODY_16_xx
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-       ldr     r1,[sp,#4*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r7,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r10,r10,r6                      @ d+=h
-       eor     r12,r12,r8                      @ Maj(a,b,c)
-       add     r6,r6,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r6,r6,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 6
-# if 6==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 6
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 6==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r10,r10,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r5,r5,r2                        @ h+=X[i]
-       str     r2,[sp,#6*4]
-       eor     r2,r11,r4
-       add     r5,r5,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r10
-       add     r5,r5,r12                       @ h+=K256[i]
-       eor     r2,r2,r4                        @ Ch(e,f,g)
-       eor     r0,r6,r6,ror#11
-       add     r5,r5,r2                        @ h+=Ch(e,f,g)
-#if 6==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 6<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#8*4]            @ from future BODY_16_xx
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-       ldr     r1,[sp,#5*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r6,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r9,r9,r5                        @ d+=h
-       eor     r3,r3,r7                        @ Maj(a,b,c)
-       add     r5,r5,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r5,r5,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 7
-# if 7==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r9,r9,ror#5
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 7
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 7==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r9,r9,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r4,r4,r2                        @ h+=X[i]
-       str     r2,[sp,#7*4]
-       eor     r2,r10,r11
-       add     r4,r4,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r9
-       add     r4,r4,r3                        @ h+=K256[i]
-       eor     r2,r2,r11                       @ Ch(e,f,g)
-       eor     r0,r5,r5,ror#11
-       add     r4,r4,r2                        @ h+=Ch(e,f,g)
-#if 7==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 7<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#9*4]            @ from future BODY_16_xx
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-       ldr     r1,[sp,#6*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r5,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r8,r8,r4                        @ d+=h
-       eor     r12,r12,r6                      @ Maj(a,b,c)
-       add     r4,r4,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r4,r4,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 8
-# if 8==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r8,r8,ror#5
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 8
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 8==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r8,r8,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r11,r11,r2                      @ h+=X[i]
-       str     r2,[sp,#8*4]
-       eor     r2,r9,r10
-       add     r11,r11,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r8
-       add     r11,r11,r12                     @ h+=K256[i]
-       eor     r2,r2,r10                       @ Ch(e,f,g)
-       eor     r0,r4,r4,ror#11
-       add     r11,r11,r2                      @ h+=Ch(e,f,g)
-#if 8==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 8<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#10*4]           @ from future BODY_16_xx
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-       ldr     r1,[sp,#7*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r4,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r7,r7,r11                       @ d+=h
-       eor     r3,r3,r5                        @ Maj(a,b,c)
-       add     r11,r11,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r11,r11,r3                      @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 9
-# if 9==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r7,r7,ror#5
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 9
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 9==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r7,r7,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r10,r10,r2                      @ h+=X[i]
-       str     r2,[sp,#9*4]
-       eor     r2,r8,r9
-       add     r10,r10,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r7
-       add     r10,r10,r3                      @ h+=K256[i]
-       eor     r2,r2,r9                        @ Ch(e,f,g)
-       eor     r0,r11,r11,ror#11
-       add     r10,r10,r2                      @ h+=Ch(e,f,g)
-#if 9==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 9<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#11*4]           @ from future BODY_16_xx
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-       ldr     r1,[sp,#8*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r11,ror#20        @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r6,r6,r10                       @ d+=h
-       eor     r12,r12,r4                      @ Maj(a,b,c)
-       add     r10,r10,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r10,r10,r12                     @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 10
-# if 10==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 10
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 10==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r6,r6,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r9,r9,r2                        @ h+=X[i]
-       str     r2,[sp,#10*4]
-       eor     r2,r7,r8
-       add     r9,r9,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r6
-       add     r9,r9,r12                       @ h+=K256[i]
-       eor     r2,r2,r8                        @ Ch(e,f,g)
-       eor     r0,r10,r10,ror#11
-       add     r9,r9,r2                        @ h+=Ch(e,f,g)
-#if 10==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 10<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#12*4]           @ from future BODY_16_xx
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-       ldr     r1,[sp,#9*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r10,ror#20        @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r5,r5,r9                        @ d+=h
-       eor     r3,r3,r11                       @ Maj(a,b,c)
-       add     r9,r9,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r9,r9,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 11
-# if 11==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r5,r5,ror#5
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 11
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 11==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r5,r5,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r8,r8,r2                        @ h+=X[i]
-       str     r2,[sp,#11*4]
-       eor     r2,r6,r7
-       add     r8,r8,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r5
-       add     r8,r8,r3                        @ h+=K256[i]
-       eor     r2,r2,r7                        @ Ch(e,f,g)
-       eor     r0,r9,r9,ror#11
-       add     r8,r8,r2                        @ h+=Ch(e,f,g)
-#if 11==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 11<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#13*4]           @ from future BODY_16_xx
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-       ldr     r1,[sp,#10*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r9,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r4,r4,r8                        @ d+=h
-       eor     r12,r12,r10                     @ Maj(a,b,c)
-       add     r8,r8,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r8,r8,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 12
-# if 12==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r4,r4,ror#5
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 12
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 12==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r4,r4,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r7,r7,r2                        @ h+=X[i]
-       str     r2,[sp,#12*4]
-       eor     r2,r5,r6
-       add     r7,r7,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r4
-       add     r7,r7,r12                       @ h+=K256[i]
-       eor     r2,r2,r6                        @ Ch(e,f,g)
-       eor     r0,r8,r8,ror#11
-       add     r7,r7,r2                        @ h+=Ch(e,f,g)
-#if 12==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 12<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#14*4]           @ from future BODY_16_xx
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-       ldr     r1,[sp,#11*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r8,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r11,r11,r7                      @ d+=h
-       eor     r3,r3,r9                        @ Maj(a,b,c)
-       add     r7,r7,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r7,r7,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 13
-# if 13==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r11,r11,ror#5
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 13
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 13==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r11,r11,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r6,r6,r2                        @ h+=X[i]
-       str     r2,[sp,#13*4]
-       eor     r2,r4,r5
-       add     r6,r6,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r11
-       add     r6,r6,r3                        @ h+=K256[i]
-       eor     r2,r2,r5                        @ Ch(e,f,g)
-       eor     r0,r7,r7,ror#11
-       add     r6,r6,r2                        @ h+=Ch(e,f,g)
-#if 13==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 13<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#15*4]           @ from future BODY_16_xx
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-       ldr     r1,[sp,#12*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r7,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r10,r10,r6                      @ d+=h
-       eor     r12,r12,r8                      @ Maj(a,b,c)
-       add     r6,r6,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r6,r6,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 14
-# if 14==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 14
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       ldrb    r12,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r12,lsl#8
-       ldrb    r12,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 14==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r10,r10,ror#5
-       orr     r2,r2,r12,lsl#24
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-#endif
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r5,r5,r2                        @ h+=X[i]
-       str     r2,[sp,#14*4]
-       eor     r2,r11,r4
-       add     r5,r5,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r10
-       add     r5,r5,r12                       @ h+=K256[i]
-       eor     r2,r2,r4                        @ Ch(e,f,g)
-       eor     r0,r6,r6,ror#11
-       add     r5,r5,r2                        @ h+=Ch(e,f,g)
-#if 14==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 14<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#0*4]            @ from future BODY_16_xx
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-       ldr     r1,[sp,#13*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r6,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r9,r9,r5                        @ d+=h
-       eor     r3,r3,r7                        @ Maj(a,b,c)
-       add     r5,r5,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r5,r5,r3                        @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       @ ldr   r2,[r1],#4                      @ 15
-# if 15==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r9,r9,ror#5
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-# ifndef __ARMEB__
-       rev     r2,r2
-# endif
-#else
-       @ ldrb  r2,[r1,#3]                      @ 15
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       ldrb    r3,[r1,#2]
-       ldrb    r0,[r1,#1]
-       orr     r2,r2,r3,lsl#8
-       ldrb    r3,[r1],#4
-       orr     r2,r2,r0,lsl#16
-# if 15==15
-       str     r1,[sp,#17*4]                   @ make room for r1
-# endif
-       eor     r0,r9,r9,ror#5
-       orr     r2,r2,r3,lsl#24
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-#endif
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r4,r4,r2                        @ h+=X[i]
-       str     r2,[sp,#15*4]
-       eor     r2,r10,r11
-       add     r4,r4,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r9
-       add     r4,r4,r3                        @ h+=K256[i]
-       eor     r2,r2,r11                       @ Ch(e,f,g)
-       eor     r0,r5,r5,ror#11
-       add     r4,r4,r2                        @ h+=Ch(e,f,g)
-#if 15==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 15<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#1*4]            @ from future BODY_16_xx
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-       ldr     r1,[sp,#14*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r5,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r8,r8,r4                        @ d+=h
-       eor     r12,r12,r6                      @ Maj(a,b,c)
-       add     r4,r4,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r4,r4,r12                       @ h+=Maj(a,b,c)
-.Lrounds_16_xx:
-       @ ldr   r2,[sp,#1*4]            @ 16
-       @ ldr   r1,[sp,#14*4]
-       mov     r0,r2,ror#7
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#0*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#9*4]
-
-       add     r12,r12,r0
-       eor     r0,r8,r8,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r11,r11,r2                      @ h+=X[i]
-       str     r2,[sp,#0*4]
-       eor     r2,r9,r10
-       add     r11,r11,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r8
-       add     r11,r11,r12                     @ h+=K256[i]
-       eor     r2,r2,r10                       @ Ch(e,f,g)
-       eor     r0,r4,r4,ror#11
-       add     r11,r11,r2                      @ h+=Ch(e,f,g)
-#if 16==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 16<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#2*4]            @ from future BODY_16_xx
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-       ldr     r1,[sp,#15*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r4,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r7,r7,r11                       @ d+=h
-       eor     r3,r3,r5                        @ Maj(a,b,c)
-       add     r11,r11,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r11,r11,r3                      @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#2*4]            @ 17
-       @ ldr   r1,[sp,#15*4]
-       mov     r0,r2,ror#7
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#1*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#10*4]
-
-       add     r3,r3,r0
-       eor     r0,r7,r7,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r10,r10,r2                      @ h+=X[i]
-       str     r2,[sp,#1*4]
-       eor     r2,r8,r9
-       add     r10,r10,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r7
-       add     r10,r10,r3                      @ h+=K256[i]
-       eor     r2,r2,r9                        @ Ch(e,f,g)
-       eor     r0,r11,r11,ror#11
-       add     r10,r10,r2                      @ h+=Ch(e,f,g)
-#if 17==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 17<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#3*4]            @ from future BODY_16_xx
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-       ldr     r1,[sp,#0*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r11,ror#20        @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r6,r6,r10                       @ d+=h
-       eor     r12,r12,r4                      @ Maj(a,b,c)
-       add     r10,r10,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r10,r10,r12                     @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#3*4]            @ 18
-       @ ldr   r1,[sp,#0*4]
-       mov     r0,r2,ror#7
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#2*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#11*4]
-
-       add     r12,r12,r0
-       eor     r0,r6,r6,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r9,r9,r2                        @ h+=X[i]
-       str     r2,[sp,#2*4]
-       eor     r2,r7,r8
-       add     r9,r9,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r6
-       add     r9,r9,r12                       @ h+=K256[i]
-       eor     r2,r2,r8                        @ Ch(e,f,g)
-       eor     r0,r10,r10,ror#11
-       add     r9,r9,r2                        @ h+=Ch(e,f,g)
-#if 18==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 18<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#4*4]            @ from future BODY_16_xx
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-       ldr     r1,[sp,#1*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r10,ror#20        @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r5,r5,r9                        @ d+=h
-       eor     r3,r3,r11                       @ Maj(a,b,c)
-       add     r9,r9,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r9,r9,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#4*4]            @ 19
-       @ ldr   r1,[sp,#1*4]
-       mov     r0,r2,ror#7
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#3*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#12*4]
-
-       add     r3,r3,r0
-       eor     r0,r5,r5,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r8,r8,r2                        @ h+=X[i]
-       str     r2,[sp,#3*4]
-       eor     r2,r6,r7
-       add     r8,r8,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r5
-       add     r8,r8,r3                        @ h+=K256[i]
-       eor     r2,r2,r7                        @ Ch(e,f,g)
-       eor     r0,r9,r9,ror#11
-       add     r8,r8,r2                        @ h+=Ch(e,f,g)
-#if 19==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 19<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#5*4]            @ from future BODY_16_xx
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-       ldr     r1,[sp,#2*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r9,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r4,r4,r8                        @ d+=h
-       eor     r12,r12,r10                     @ Maj(a,b,c)
-       add     r8,r8,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r8,r8,r12                       @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#5*4]            @ 20
-       @ ldr   r1,[sp,#2*4]
-       mov     r0,r2,ror#7
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#4*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#13*4]
-
-       add     r12,r12,r0
-       eor     r0,r4,r4,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r7,r7,r2                        @ h+=X[i]
-       str     r2,[sp,#4*4]
-       eor     r2,r5,r6
-       add     r7,r7,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r4
-       add     r7,r7,r12                       @ h+=K256[i]
-       eor     r2,r2,r6                        @ Ch(e,f,g)
-       eor     r0,r8,r8,ror#11
-       add     r7,r7,r2                        @ h+=Ch(e,f,g)
-#if 20==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 20<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#6*4]            @ from future BODY_16_xx
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-       ldr     r1,[sp,#3*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r8,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r11,r11,r7                      @ d+=h
-       eor     r3,r3,r9                        @ Maj(a,b,c)
-       add     r7,r7,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r7,r7,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#6*4]            @ 21
-       @ ldr   r1,[sp,#3*4]
-       mov     r0,r2,ror#7
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#5*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#14*4]
-
-       add     r3,r3,r0
-       eor     r0,r11,r11,ror#5        @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r6,r6,r2                        @ h+=X[i]
-       str     r2,[sp,#5*4]
-       eor     r2,r4,r5
-       add     r6,r6,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r11
-       add     r6,r6,r3                        @ h+=K256[i]
-       eor     r2,r2,r5                        @ Ch(e,f,g)
-       eor     r0,r7,r7,ror#11
-       add     r6,r6,r2                        @ h+=Ch(e,f,g)
-#if 21==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 21<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#7*4]            @ from future BODY_16_xx
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-       ldr     r1,[sp,#4*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r7,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r10,r10,r6                      @ d+=h
-       eor     r12,r12,r8                      @ Maj(a,b,c)
-       add     r6,r6,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r6,r6,r12                       @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#7*4]            @ 22
-       @ ldr   r1,[sp,#4*4]
-       mov     r0,r2,ror#7
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#6*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#15*4]
-
-       add     r12,r12,r0
-       eor     r0,r10,r10,ror#5        @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r5,r5,r2                        @ h+=X[i]
-       str     r2,[sp,#6*4]
-       eor     r2,r11,r4
-       add     r5,r5,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r10
-       add     r5,r5,r12                       @ h+=K256[i]
-       eor     r2,r2,r4                        @ Ch(e,f,g)
-       eor     r0,r6,r6,ror#11
-       add     r5,r5,r2                        @ h+=Ch(e,f,g)
-#if 22==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 22<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#8*4]            @ from future BODY_16_xx
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-       ldr     r1,[sp,#5*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r6,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r9,r9,r5                        @ d+=h
-       eor     r3,r3,r7                        @ Maj(a,b,c)
-       add     r5,r5,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r5,r5,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#8*4]            @ 23
-       @ ldr   r1,[sp,#5*4]
-       mov     r0,r2,ror#7
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#7*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#0*4]
-
-       add     r3,r3,r0
-       eor     r0,r9,r9,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r4,r4,r2                        @ h+=X[i]
-       str     r2,[sp,#7*4]
-       eor     r2,r10,r11
-       add     r4,r4,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r9
-       add     r4,r4,r3                        @ h+=K256[i]
-       eor     r2,r2,r11                       @ Ch(e,f,g)
-       eor     r0,r5,r5,ror#11
-       add     r4,r4,r2                        @ h+=Ch(e,f,g)
-#if 23==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 23<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#9*4]            @ from future BODY_16_xx
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-       ldr     r1,[sp,#6*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r5,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r8,r8,r4                        @ d+=h
-       eor     r12,r12,r6                      @ Maj(a,b,c)
-       add     r4,r4,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r4,r4,r12                       @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#9*4]            @ 24
-       @ ldr   r1,[sp,#6*4]
-       mov     r0,r2,ror#7
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#8*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#1*4]
-
-       add     r12,r12,r0
-       eor     r0,r8,r8,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r8,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r11,r11,r2                      @ h+=X[i]
-       str     r2,[sp,#8*4]
-       eor     r2,r9,r10
-       add     r11,r11,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r8
-       add     r11,r11,r12                     @ h+=K256[i]
-       eor     r2,r2,r10                       @ Ch(e,f,g)
-       eor     r0,r4,r4,ror#11
-       add     r11,r11,r2                      @ h+=Ch(e,f,g)
-#if 24==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 24<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#10*4]           @ from future BODY_16_xx
-       eor     r12,r4,r5                       @ a^b, b^c in next round
-       ldr     r1,[sp,#7*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r4,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r7,r7,r11                       @ d+=h
-       eor     r3,r3,r5                        @ Maj(a,b,c)
-       add     r11,r11,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r11,r11,r3                      @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#10*4]           @ 25
-       @ ldr   r1,[sp,#7*4]
-       mov     r0,r2,ror#7
-       add     r11,r11,r3                      @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#9*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#2*4]
-
-       add     r3,r3,r0
-       eor     r0,r7,r7,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r7,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r10,r10,r2                      @ h+=X[i]
-       str     r2,[sp,#9*4]
-       eor     r2,r8,r9
-       add     r10,r10,r0,ror#6        @ h+=Sigma1(e)
-       and     r2,r2,r7
-       add     r10,r10,r3                      @ h+=K256[i]
-       eor     r2,r2,r9                        @ Ch(e,f,g)
-       eor     r0,r11,r11,ror#11
-       add     r10,r10,r2                      @ h+=Ch(e,f,g)
-#if 25==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 25<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#11*4]           @ from future BODY_16_xx
-       eor     r3,r11,r4                       @ a^b, b^c in next round
-       ldr     r1,[sp,#8*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r11,ror#20        @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r6,r6,r10                       @ d+=h
-       eor     r12,r12,r4                      @ Maj(a,b,c)
-       add     r10,r10,r0,ror#2        @ h+=Sigma0(a)
-       @ add   r10,r10,r12                     @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#11*4]           @ 26
-       @ ldr   r1,[sp,#8*4]
-       mov     r0,r2,ror#7
-       add     r10,r10,r12                     @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#10*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#3*4]
-
-       add     r12,r12,r0
-       eor     r0,r6,r6,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r6,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r9,r9,r2                        @ h+=X[i]
-       str     r2,[sp,#10*4]
-       eor     r2,r7,r8
-       add     r9,r9,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r6
-       add     r9,r9,r12                       @ h+=K256[i]
-       eor     r2,r2,r8                        @ Ch(e,f,g)
-       eor     r0,r10,r10,ror#11
-       add     r9,r9,r2                        @ h+=Ch(e,f,g)
-#if 26==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 26<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#12*4]           @ from future BODY_16_xx
-       eor     r12,r10,r11                     @ a^b, b^c in next round
-       ldr     r1,[sp,#9*4]    @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r10,ror#20        @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r5,r5,r9                        @ d+=h
-       eor     r3,r3,r11                       @ Maj(a,b,c)
-       add     r9,r9,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r9,r9,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#12*4]           @ 27
-       @ ldr   r1,[sp,#9*4]
-       mov     r0,r2,ror#7
-       add     r9,r9,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#11*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#4*4]
-
-       add     r3,r3,r0
-       eor     r0,r5,r5,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r5,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r8,r8,r2                        @ h+=X[i]
-       str     r2,[sp,#11*4]
-       eor     r2,r6,r7
-       add     r8,r8,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r5
-       add     r8,r8,r3                        @ h+=K256[i]
-       eor     r2,r2,r7                        @ Ch(e,f,g)
-       eor     r0,r9,r9,ror#11
-       add     r8,r8,r2                        @ h+=Ch(e,f,g)
-#if 27==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 27<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#13*4]           @ from future BODY_16_xx
-       eor     r3,r9,r10                       @ a^b, b^c in next round
-       ldr     r1,[sp,#10*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r9,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r4,r4,r8                        @ d+=h
-       eor     r12,r12,r10                     @ Maj(a,b,c)
-       add     r8,r8,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r8,r8,r12                       @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#13*4]           @ 28
-       @ ldr   r1,[sp,#10*4]
-       mov     r0,r2,ror#7
-       add     r8,r8,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#12*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#5*4]
-
-       add     r12,r12,r0
-       eor     r0,r4,r4,ror#5  @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r4,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r7,r7,r2                        @ h+=X[i]
-       str     r2,[sp,#12*4]
-       eor     r2,r5,r6
-       add     r7,r7,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r4
-       add     r7,r7,r12                       @ h+=K256[i]
-       eor     r2,r2,r6                        @ Ch(e,f,g)
-       eor     r0,r8,r8,ror#11
-       add     r7,r7,r2                        @ h+=Ch(e,f,g)
-#if 28==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 28<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#14*4]           @ from future BODY_16_xx
-       eor     r12,r8,r9                       @ a^b, b^c in next round
-       ldr     r1,[sp,#11*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r8,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r11,r11,r7                      @ d+=h
-       eor     r3,r3,r9                        @ Maj(a,b,c)
-       add     r7,r7,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r7,r7,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#14*4]           @ 29
-       @ ldr   r1,[sp,#11*4]
-       mov     r0,r2,ror#7
-       add     r7,r7,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#13*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#6*4]
-
-       add     r3,r3,r0
-       eor     r0,r11,r11,ror#5        @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r11,ror#19        @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r6,r6,r2                        @ h+=X[i]
-       str     r2,[sp,#13*4]
-       eor     r2,r4,r5
-       add     r6,r6,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r11
-       add     r6,r6,r3                        @ h+=K256[i]
-       eor     r2,r2,r5                        @ Ch(e,f,g)
-       eor     r0,r7,r7,ror#11
-       add     r6,r6,r2                        @ h+=Ch(e,f,g)
-#if 29==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 29<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#15*4]           @ from future BODY_16_xx
-       eor     r3,r7,r8                        @ a^b, b^c in next round
-       ldr     r1,[sp,#12*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r7,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r10,r10,r6                      @ d+=h
-       eor     r12,r12,r8                      @ Maj(a,b,c)
-       add     r6,r6,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r6,r6,r12                       @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#15*4]           @ 30
-       @ ldr   r1,[sp,#12*4]
-       mov     r0,r2,ror#7
-       add     r6,r6,r12                       @ h+=Maj(a,b,c) from the past
-       mov     r12,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r12,r12,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#14*4]
-       eor     r12,r12,r1,lsr#10       @ sigma1(X[i+14])
-       ldr     r1,[sp,#7*4]
-
-       add     r12,r12,r0
-       eor     r0,r10,r10,ror#5        @ from BODY_00_15
-       add     r2,r2,r12
-       eor     r0,r0,r10,ror#19        @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r12,[r14],#4                    @ *K256++
-       add     r5,r5,r2                        @ h+=X[i]
-       str     r2,[sp,#14*4]
-       eor     r2,r11,r4
-       add     r5,r5,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r10
-       add     r5,r5,r12                       @ h+=K256[i]
-       eor     r2,r2,r4                        @ Ch(e,f,g)
-       eor     r0,r6,r6,ror#11
-       add     r5,r5,r2                        @ h+=Ch(e,f,g)
-#if 30==31
-       and     r12,r12,#0xff
-       cmp     r12,#0xf2                       @ done?
-#endif
-#if 30<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#0*4]            @ from future BODY_16_xx
-       eor     r12,r6,r7                       @ a^b, b^c in next round
-       ldr     r1,[sp,#13*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r6,ror#20 @ Sigma0(a)
-       and     r3,r3,r12                       @ (b^c)&=(a^b)
-       add     r9,r9,r5                        @ d+=h
-       eor     r3,r3,r7                        @ Maj(a,b,c)
-       add     r5,r5,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r5,r5,r3                        @ h+=Maj(a,b,c)
-       @ ldr   r2,[sp,#0*4]            @ 31
-       @ ldr   r1,[sp,#13*4]
-       mov     r0,r2,ror#7
-       add     r5,r5,r3                        @ h+=Maj(a,b,c) from the past
-       mov     r3,r1,ror#17
-       eor     r0,r0,r2,ror#18
-       eor     r3,r3,r1,ror#19
-       eor     r0,r0,r2,lsr#3  @ sigma0(X[i+1])
-       ldr     r2,[sp,#15*4]
-       eor     r3,r3,r1,lsr#10 @ sigma1(X[i+14])
-       ldr     r1,[sp,#8*4]
-
-       add     r3,r3,r0
-       eor     r0,r9,r9,ror#5  @ from BODY_00_15
-       add     r2,r2,r3
-       eor     r0,r0,r9,ror#19 @ Sigma1(e)
-       add     r2,r2,r1                        @ X[i]
-       ldr     r3,[r14],#4                     @ *K256++
-       add     r4,r4,r2                        @ h+=X[i]
-       str     r2,[sp,#15*4]
-       eor     r2,r10,r11
-       add     r4,r4,r0,ror#6  @ h+=Sigma1(e)
-       and     r2,r2,r9
-       add     r4,r4,r3                        @ h+=K256[i]
-       eor     r2,r2,r11                       @ Ch(e,f,g)
-       eor     r0,r5,r5,ror#11
-       add     r4,r4,r2                        @ h+=Ch(e,f,g)
-#if 31==31
-       and     r3,r3,#0xff
-       cmp     r3,#0xf2                        @ done?
-#endif
-#if 31<15
-# if __ARM_ARCH__>=7
-       ldr     r2,[r1],#4                      @ prefetch
-# else
-       ldrb    r2,[r1,#3]
-# endif
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-#else
-       ldr     r2,[sp,#1*4]            @ from future BODY_16_xx
-       eor     r3,r5,r6                        @ a^b, b^c in next round
-       ldr     r1,[sp,#14*4]   @ from future BODY_16_xx
-#endif
-       eor     r0,r0,r5,ror#20 @ Sigma0(a)
-       and     r12,r12,r3                      @ (b^c)&=(a^b)
-       add     r8,r8,r4                        @ d+=h
-       eor     r12,r12,r6                      @ Maj(a,b,c)
-       add     r4,r4,r0,ror#2  @ h+=Sigma0(a)
-       @ add   r4,r4,r12                       @ h+=Maj(a,b,c)
-#if __ARM_ARCH__>=7
-       ite     eq                      @ Thumb2 thing, sanity check in ARM
-#endif
-       ldreq   r3,[sp,#16*4]           @ pull ctx
-       bne     .Lrounds_16_xx
-
-       add     r4,r4,r12               @ h+=Maj(a,b,c) from the past
-       ldr     r0,[r3,#0]
-       ldr     r2,[r3,#4]
-       ldr     r12,[r3,#8]
-       add     r4,r4,r0
-       ldr     r0,[r3,#12]
-       add     r5,r5,r2
-       ldr     r2,[r3,#16]
-       add     r6,r6,r12
-       ldr     r12,[r3,#20]
-       add     r7,r7,r0
-       ldr     r0,[r3,#24]
-       add     r8,r8,r2
-       ldr     r2,[r3,#28]
-       add     r9,r9,r12
-       ldr     r1,[sp,#17*4]           @ pull inp
-       ldr     r12,[sp,#18*4]          @ pull inp+len
-       add     r10,r10,r0
-       add     r11,r11,r2
-       stmia   r3,{r4,r5,r6,r7,r8,r9,r10,r11}
-       cmp     r1,r12
-       sub     r14,r14,#256    @ rewind Ktbl
-       bne     .Loop
-
-       add     sp,sp,#19*4     @ destroy frame
-#if __ARM_ARCH__>=5
-       ldmia   sp!,{r4-r11,pc}
-#else
-       ldmia   sp!,{r4-r11,lr}
-       tst     lr,#1
-       moveq   pc,lr                   @ be binary compatible with V4, yet
-       .word   0xe12fff1e                      @ interoperable with Thumb ISA:-)
-#endif
-.size  sha256_block_data_order,.-sha256_block_data_order
-#if __ARM_MAX_ARCH__>=7
-.arch  armv7-a
-.fpu   neon
-
-.global        sha256_block_data_order_neon
-.type  sha256_block_data_order_neon,%function
-.align 4
-sha256_block_data_order_neon:
-.LNEON:
-       stmdb   sp!,{r4-r12,lr}
-
-       sub     r11,sp,#16*4+16
-       adr     r14,.Lsha256_block_data_order
-       sub     r14,r14,#.Lsha256_block_data_order-K256
-       bic     r11,r11,#15             @ align for 128-bit stores
-       mov     r12,sp
-       mov     sp,r11                  @ alloca
-       add     r2,r1,r2,lsl#6  @ len to point at the end of inp
-
-       vld1.8          {q0},[r1]!
-       vld1.8          {q1},[r1]!
-       vld1.8          {q2},[r1]!
-       vld1.8          {q3},[r1]!
-       vld1.32         {q8},[r14,:128]!
-       vld1.32         {q9},[r14,:128]!
-       vld1.32         {q10},[r14,:128]!
-       vld1.32         {q11},[r14,:128]!
-       vrev32.8        q0,q0           @ yes, even on
-       str             r0,[sp,#64]
-       vrev32.8        q1,q1           @ big-endian
-       str             r1,[sp,#68]
-       mov             r1,sp
-       vrev32.8        q2,q2
-       str             r2,[sp,#72]
-       vrev32.8        q3,q3
-       str             r12,[sp,#76]            @ save original sp
-       vadd.i32        q8,q8,q0
-       vadd.i32        q9,q9,q1
-       vst1.32         {q8},[r1,:128]!
-       vadd.i32        q10,q10,q2
-       vst1.32         {q9},[r1,:128]!
-       vadd.i32        q11,q11,q3
-       vst1.32         {q10},[r1,:128]!
-       vst1.32         {q11},[r1,:128]!
-
-       ldmia           r0,{r4-r11}
-       sub             r1,r1,#64
-       ldr             r2,[sp,#0]
-       eor             r12,r12,r12
-       eor             r3,r5,r6
-       b               .L_00_48
-
-.align 4
-.L_00_48:
-       vext.8  q8,q0,q1,#4
-       add     r11,r11,r2
-       eor     r2,r9,r10
-       eor     r0,r8,r8,ror#5
-       vext.8  q9,q2,q3,#4
-       add     r4,r4,r12
-       and     r2,r2,r8
-       eor     r12,r0,r8,ror#19
-       vshr.u32        q10,q8,#7
-       eor     r0,r4,r4,ror#11
-       eor     r2,r2,r10
-       vadd.i32        q0,q0,q9
-       add     r11,r11,r12,ror#6
-       eor     r12,r4,r5
-       vshr.u32        q9,q8,#3
-       eor     r0,r0,r4,ror#20
-       add     r11,r11,r2
-       vsli.32 q10,q8,#25
-       ldr     r2,[sp,#4]
-       and     r3,r3,r12
-       vshr.u32        q11,q8,#18
-       add     r7,r7,r11
-       add     r11,r11,r0,ror#2
-       eor     r3,r3,r5
-       veor    q9,q9,q10
-       add     r10,r10,r2
-       vsli.32 q11,q8,#14
-       eor     r2,r8,r9
-       eor     r0,r7,r7,ror#5
-       vshr.u32        d24,d7,#17
-       add     r11,r11,r3
-       and     r2,r2,r7
-       veor    q9,q9,q11
-       eor     r3,r0,r7,ror#19
-       eor     r0,r11,r11,ror#11
-       vsli.32 d24,d7,#15
-       eor     r2,r2,r9
-       add     r10,r10,r3,ror#6
-       vshr.u32        d25,d7,#10
-       eor     r3,r11,r4
-       eor     r0,r0,r11,ror#20
-       vadd.i32        q0,q0,q9
-       add     r10,r10,r2
-       ldr     r2,[sp,#8]
-       veor    d25,d25,d24
-       and     r12,r12,r3
-       add     r6,r6,r10
-       vshr.u32        d24,d7,#19
-       add     r10,r10,r0,ror#2
-       eor     r12,r12,r4
-       vsli.32 d24,d7,#13
-       add     r9,r9,r2
-       eor     r2,r7,r8
-       veor    d25,d25,d24
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12
-       vadd.i32        d0,d0,d25
-       and     r2,r2,r6
-       eor     r12,r0,r6,ror#19
-       vshr.u32        d24,d0,#17
-       eor     r0,r10,r10,ror#11
-       eor     r2,r2,r8
-       vsli.32 d24,d0,#15
-       add     r9,r9,r12,ror#6
-       eor     r12,r10,r11
-       vshr.u32        d25,d0,#10
-       eor     r0,r0,r10,ror#20
-       add     r9,r9,r2
-       veor    d25,d25,d24
-       ldr     r2,[sp,#12]
-       and     r3,r3,r12
-       vshr.u32        d24,d0,#19
-       add     r5,r5,r9
-       add     r9,r9,r0,ror#2
-       eor     r3,r3,r11
-       vld1.32 {q8},[r14,:128]!
-       add     r8,r8,r2
-       vsli.32 d24,d0,#13
-       eor     r2,r6,r7
-       eor     r0,r5,r5,ror#5
-       veor    d25,d25,d24
-       add     r9,r9,r3
-       and     r2,r2,r5
-       vadd.i32        d1,d1,d25
-       eor     r3,r0,r5,ror#19
-       eor     r0,r9,r9,ror#11
-       vadd.i32        q8,q8,q0
-       eor     r2,r2,r7
-       add     r8,r8,r3,ror#6
-       eor     r3,r9,r10
-       eor     r0,r0,r9,ror#20
-       add     r8,r8,r2
-       ldr     r2,[sp,#16]
-       and     r12,r12,r3
-       add     r4,r4,r8
-       vst1.32 {q8},[r1,:128]!
-       add     r8,r8,r0,ror#2
-       eor     r12,r12,r10
-       vext.8  q8,q1,q2,#4
-       add     r7,r7,r2
-       eor     r2,r5,r6
-       eor     r0,r4,r4,ror#5
-       vext.8  q9,q3,q0,#4
-       add     r8,r8,r12
-       and     r2,r2,r4
-       eor     r12,r0,r4,ror#19
-       vshr.u32        q10,q8,#7
-       eor     r0,r8,r8,ror#11
-       eor     r2,r2,r6
-       vadd.i32        q1,q1,q9
-       add     r7,r7,r12,ror#6
-       eor     r12,r8,r9
-       vshr.u32        q9,q8,#3
-       eor     r0,r0,r8,ror#20
-       add     r7,r7,r2
-       vsli.32 q10,q8,#25
-       ldr     r2,[sp,#20]
-       and     r3,r3,r12
-       vshr.u32        q11,q8,#18
-       add     r11,r11,r7
-       add     r7,r7,r0,ror#2
-       eor     r3,r3,r9
-       veor    q9,q9,q10
-       add     r6,r6,r2
-       vsli.32 q11,q8,#14
-       eor     r2,r4,r5
-       eor     r0,r11,r11,ror#5
-       vshr.u32        d24,d1,#17
-       add     r7,r7,r3
-       and     r2,r2,r11
-       veor    q9,q9,q11
-       eor     r3,r0,r11,ror#19
-       eor     r0,r7,r7,ror#11
-       vsli.32 d24,d1,#15
-       eor     r2,r2,r5
-       add     r6,r6,r3,ror#6
-       vshr.u32        d25,d1,#10
-       eor     r3,r7,r8
-       eor     r0,r0,r7,ror#20
-       vadd.i32        q1,q1,q9
-       add     r6,r6,r2
-       ldr     r2,[sp,#24]
-       veor    d25,d25,d24
-       and     r12,r12,r3
-       add     r10,r10,r6
-       vshr.u32        d24,d1,#19
-       add     r6,r6,r0,ror#2
-       eor     r12,r12,r8
-       vsli.32 d24,d1,#13
-       add     r5,r5,r2
-       eor     r2,r11,r4
-       veor    d25,d25,d24
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12
-       vadd.i32        d2,d2,d25
-       and     r2,r2,r10
-       eor     r12,r0,r10,ror#19
-       vshr.u32        d24,d2,#17
-       eor     r0,r6,r6,ror#11
-       eor     r2,r2,r4
-       vsli.32 d24,d2,#15
-       add     r5,r5,r12,ror#6
-       eor     r12,r6,r7
-       vshr.u32        d25,d2,#10
-       eor     r0,r0,r6,ror#20
-       add     r5,r5,r2
-       veor    d25,d25,d24
-       ldr     r2,[sp,#28]
-       and     r3,r3,r12
-       vshr.u32        d24,d2,#19
-       add     r9,r9,r5
-       add     r5,r5,r0,ror#2
-       eor     r3,r3,r7
-       vld1.32 {q8},[r14,:128]!
-       add     r4,r4,r2
-       vsli.32 d24,d2,#13
-       eor     r2,r10,r11
-       eor     r0,r9,r9,ror#5
-       veor    d25,d25,d24
-       add     r5,r5,r3
-       and     r2,r2,r9
-       vadd.i32        d3,d3,d25
-       eor     r3,r0,r9,ror#19
-       eor     r0,r5,r5,ror#11
-       vadd.i32        q8,q8,q1
-       eor     r2,r2,r11
-       add     r4,r4,r3,ror#6
-       eor     r3,r5,r6
-       eor     r0,r0,r5,ror#20
-       add     r4,r4,r2
-       ldr     r2,[sp,#32]
-       and     r12,r12,r3
-       add     r8,r8,r4
-       vst1.32 {q8},[r1,:128]!
-       add     r4,r4,r0,ror#2
-       eor     r12,r12,r6
-       vext.8  q8,q2,q3,#4
-       add     r11,r11,r2
-       eor     r2,r9,r10
-       eor     r0,r8,r8,ror#5
-       vext.8  q9,q0,q1,#4
-       add     r4,r4,r12
-       and     r2,r2,r8
-       eor     r12,r0,r8,ror#19
-       vshr.u32        q10,q8,#7
-       eor     r0,r4,r4,ror#11
-       eor     r2,r2,r10
-       vadd.i32        q2,q2,q9
-       add     r11,r11,r12,ror#6
-       eor     r12,r4,r5
-       vshr.u32        q9,q8,#3
-       eor     r0,r0,r4,ror#20
-       add     r11,r11,r2
-       vsli.32 q10,q8,#25
-       ldr     r2,[sp,#36]
-       and     r3,r3,r12
-       vshr.u32        q11,q8,#18
-       add     r7,r7,r11
-       add     r11,r11,r0,ror#2
-       eor     r3,r3,r5
-       veor    q9,q9,q10
-       add     r10,r10,r2
-       vsli.32 q11,q8,#14
-       eor     r2,r8,r9
-       eor     r0,r7,r7,ror#5
-       vshr.u32        d24,d3,#17
-       add     r11,r11,r3
-       and     r2,r2,r7
-       veor    q9,q9,q11
-       eor     r3,r0,r7,ror#19
-       eor     r0,r11,r11,ror#11
-       vsli.32 d24,d3,#15
-       eor     r2,r2,r9
-       add     r10,r10,r3,ror#6
-       vshr.u32        d25,d3,#10
-       eor     r3,r11,r4
-       eor     r0,r0,r11,ror#20
-       vadd.i32        q2,q2,q9
-       add     r10,r10,r2
-       ldr     r2,[sp,#40]
-       veor    d25,d25,d24
-       and     r12,r12,r3
-       add     r6,r6,r10
-       vshr.u32        d24,d3,#19
-       add     r10,r10,r0,ror#2
-       eor     r12,r12,r4
-       vsli.32 d24,d3,#13
-       add     r9,r9,r2
-       eor     r2,r7,r8
-       veor    d25,d25,d24
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12
-       vadd.i32        d4,d4,d25
-       and     r2,r2,r6
-       eor     r12,r0,r6,ror#19
-       vshr.u32        d24,d4,#17
-       eor     r0,r10,r10,ror#11
-       eor     r2,r2,r8
-       vsli.32 d24,d4,#15
-       add     r9,r9,r12,ror#6
-       eor     r12,r10,r11
-       vshr.u32        d25,d4,#10
-       eor     r0,r0,r10,ror#20
-       add     r9,r9,r2
-       veor    d25,d25,d24
-       ldr     r2,[sp,#44]
-       and     r3,r3,r12
-       vshr.u32        d24,d4,#19
-       add     r5,r5,r9
-       add     r9,r9,r0,ror#2
-       eor     r3,r3,r11
-       vld1.32 {q8},[r14,:128]!
-       add     r8,r8,r2
-       vsli.32 d24,d4,#13
-       eor     r2,r6,r7
-       eor     r0,r5,r5,ror#5
-       veor    d25,d25,d24
-       add     r9,r9,r3
-       and     r2,r2,r5
-       vadd.i32        d5,d5,d25
-       eor     r3,r0,r5,ror#19
-       eor     r0,r9,r9,ror#11
-       vadd.i32        q8,q8,q2
-       eor     r2,r2,r7
-       add     r8,r8,r3,ror#6
-       eor     r3,r9,r10
-       eor     r0,r0,r9,ror#20
-       add     r8,r8,r2
-       ldr     r2,[sp,#48]
-       and     r12,r12,r3
-       add     r4,r4,r8
-       vst1.32 {q8},[r1,:128]!
-       add     r8,r8,r0,ror#2
-       eor     r12,r12,r10
-       vext.8  q8,q3,q0,#4
-       add     r7,r7,r2
-       eor     r2,r5,r6
-       eor     r0,r4,r4,ror#5
-       vext.8  q9,q1,q2,#4
-       add     r8,r8,r12
-       and     r2,r2,r4
-       eor     r12,r0,r4,ror#19
-       vshr.u32        q10,q8,#7
-       eor     r0,r8,r8,ror#11
-       eor     r2,r2,r6
-       vadd.i32        q3,q3,q9
-       add     r7,r7,r12,ror#6
-       eor     r12,r8,r9
-       vshr.u32        q9,q8,#3
-       eor     r0,r0,r8,ror#20
-       add     r7,r7,r2
-       vsli.32 q10,q8,#25
-       ldr     r2,[sp,#52]
-       and     r3,r3,r12
-       vshr.u32        q11,q8,#18
-       add     r11,r11,r7
-       add     r7,r7,r0,ror#2
-       eor     r3,r3,r9
-       veor    q9,q9,q10
-       add     r6,r6,r2
-       vsli.32 q11,q8,#14
-       eor     r2,r4,r5
-       eor     r0,r11,r11,ror#5
-       vshr.u32        d24,d5,#17
-       add     r7,r7,r3
-       and     r2,r2,r11
-       veor    q9,q9,q11
-       eor     r3,r0,r11,ror#19
-       eor     r0,r7,r7,ror#11
-       vsli.32 d24,d5,#15
-       eor     r2,r2,r5
-       add     r6,r6,r3,ror#6
-       vshr.u32        d25,d5,#10
-       eor     r3,r7,r8
-       eor     r0,r0,r7,ror#20
-       vadd.i32        q3,q3,q9
-       add     r6,r6,r2
-       ldr     r2,[sp,#56]
-       veor    d25,d25,d24
-       and     r12,r12,r3
-       add     r10,r10,r6
-       vshr.u32        d24,d5,#19
-       add     r6,r6,r0,ror#2
-       eor     r12,r12,r8
-       vsli.32 d24,d5,#13
-       add     r5,r5,r2
-       eor     r2,r11,r4
-       veor    d25,d25,d24
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12
-       vadd.i32        d6,d6,d25
-       and     r2,r2,r10
-       eor     r12,r0,r10,ror#19
-       vshr.u32        d24,d6,#17
-       eor     r0,r6,r6,ror#11
-       eor     r2,r2,r4
-       vsli.32 d24,d6,#15
-       add     r5,r5,r12,ror#6
-       eor     r12,r6,r7
-       vshr.u32        d25,d6,#10
-       eor     r0,r0,r6,ror#20
-       add     r5,r5,r2
-       veor    d25,d25,d24
-       ldr     r2,[sp,#60]
-       and     r3,r3,r12
-       vshr.u32        d24,d6,#19
-       add     r9,r9,r5
-       add     r5,r5,r0,ror#2
-       eor     r3,r3,r7
-       vld1.32 {q8},[r14,:128]!
-       add     r4,r4,r2
-       vsli.32 d24,d6,#13
-       eor     r2,r10,r11
-       eor     r0,r9,r9,ror#5
-       veor    d25,d25,d24
-       add     r5,r5,r3
-       and     r2,r2,r9
-       vadd.i32        d7,d7,d25
-       eor     r3,r0,r9,ror#19
-       eor     r0,r5,r5,ror#11
-       vadd.i32        q8,q8,q3
-       eor     r2,r2,r11
-       add     r4,r4,r3,ror#6
-       eor     r3,r5,r6
-       eor     r0,r0,r5,ror#20
-       add     r4,r4,r2
-       ldr     r2,[r14]
-       and     r12,r12,r3
-       add     r8,r8,r4
-       vst1.32 {q8},[r1,:128]!
-       add     r4,r4,r0,ror#2
-       eor     r12,r12,r6
-       teq     r2,#0                           @ check for K256 terminator
-       ldr     r2,[sp,#0]
-       sub     r1,r1,#64
-       bne     .L_00_48
-
-       ldr             r1,[sp,#68]
-       ldr             r0,[sp,#72]
-       sub             r14,r14,#256    @ rewind r14
-       teq             r1,r0
-       it              eq
-       subeq           r1,r1,#64               @ avoid SEGV
-       vld1.8          {q0},[r1]!              @ load next input block
-       vld1.8          {q1},[r1]!
-       vld1.8          {q2},[r1]!
-       vld1.8          {q3},[r1]!
-       it              ne
-       strne           r1,[sp,#68]
-       mov             r1,sp
-       add     r11,r11,r2
-       eor     r2,r9,r10
-       eor     r0,r8,r8,ror#5
-       add     r4,r4,r12
-       vld1.32 {q8},[r14,:128]!
-       and     r2,r2,r8
-       eor     r12,r0,r8,ror#19
-       eor     r0,r4,r4,ror#11
-       eor     r2,r2,r10
-       vrev32.8        q0,q0
-       add     r11,r11,r12,ror#6
-       eor     r12,r4,r5
-       eor     r0,r0,r4,ror#20
-       add     r11,r11,r2
-       vadd.i32        q8,q8,q0
-       ldr     r2,[sp,#4]
-       and     r3,r3,r12
-       add     r7,r7,r11
-       add     r11,r11,r0,ror#2
-       eor     r3,r3,r5
-       add     r10,r10,r2
-       eor     r2,r8,r9
-       eor     r0,r7,r7,ror#5
-       add     r11,r11,r3
-       and     r2,r2,r7
-       eor     r3,r0,r7,ror#19
-       eor     r0,r11,r11,ror#11
-       eor     r2,r2,r9
-       add     r10,r10,r3,ror#6
-       eor     r3,r11,r4
-       eor     r0,r0,r11,ror#20
-       add     r10,r10,r2
-       ldr     r2,[sp,#8]
-       and     r12,r12,r3
-       add     r6,r6,r10
-       add     r10,r10,r0,ror#2
-       eor     r12,r12,r4
-       add     r9,r9,r2
-       eor     r2,r7,r8
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12
-       and     r2,r2,r6
-       eor     r12,r0,r6,ror#19
-       eor     r0,r10,r10,ror#11
-       eor     r2,r2,r8
-       add     r9,r9,r12,ror#6
-       eor     r12,r10,r11
-       eor     r0,r0,r10,ror#20
-       add     r9,r9,r2
-       ldr     r2,[sp,#12]
-       and     r3,r3,r12
-       add     r5,r5,r9
-       add     r9,r9,r0,ror#2
-       eor     r3,r3,r11
-       add     r8,r8,r2
-       eor     r2,r6,r7
-       eor     r0,r5,r5,ror#5
-       add     r9,r9,r3
-       and     r2,r2,r5
-       eor     r3,r0,r5,ror#19
-       eor     r0,r9,r9,ror#11
-       eor     r2,r2,r7
-       add     r8,r8,r3,ror#6
-       eor     r3,r9,r10
-       eor     r0,r0,r9,ror#20
-       add     r8,r8,r2
-       ldr     r2,[sp,#16]
-       and     r12,r12,r3
-       add     r4,r4,r8
-       add     r8,r8,r0,ror#2
-       eor     r12,r12,r10
-       vst1.32 {q8},[r1,:128]!
-       add     r7,r7,r2
-       eor     r2,r5,r6
-       eor     r0,r4,r4,ror#5
-       add     r8,r8,r12
-       vld1.32 {q8},[r14,:128]!
-       and     r2,r2,r4
-       eor     r12,r0,r4,ror#19
-       eor     r0,r8,r8,ror#11
-       eor     r2,r2,r6
-       vrev32.8        q1,q1
-       add     r7,r7,r12,ror#6
-       eor     r12,r8,r9
-       eor     r0,r0,r8,ror#20
-       add     r7,r7,r2
-       vadd.i32        q8,q8,q1
-       ldr     r2,[sp,#20]
-       and     r3,r3,r12
-       add     r11,r11,r7
-       add     r7,r7,r0,ror#2
-       eor     r3,r3,r9
-       add     r6,r6,r2
-       eor     r2,r4,r5
-       eor     r0,r11,r11,ror#5
-       add     r7,r7,r3
-       and     r2,r2,r11
-       eor     r3,r0,r11,ror#19
-       eor     r0,r7,r7,ror#11
-       eor     r2,r2,r5
-       add     r6,r6,r3,ror#6
-       eor     r3,r7,r8
-       eor     r0,r0,r7,ror#20
-       add     r6,r6,r2
-       ldr     r2,[sp,#24]
-       and     r12,r12,r3
-       add     r10,r10,r6
-       add     r6,r6,r0,ror#2
-       eor     r12,r12,r8
-       add     r5,r5,r2
-       eor     r2,r11,r4
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12
-       and     r2,r2,r10
-       eor     r12,r0,r10,ror#19
-       eor     r0,r6,r6,ror#11
-       eor     r2,r2,r4
-       add     r5,r5,r12,ror#6
-       eor     r12,r6,r7
-       eor     r0,r0,r6,ror#20
-       add     r5,r5,r2
-       ldr     r2,[sp,#28]
-       and     r3,r3,r12
-       add     r9,r9,r5
-       add     r5,r5,r0,ror#2
-       eor     r3,r3,r7
-       add     r4,r4,r2
-       eor     r2,r10,r11
-       eor     r0,r9,r9,ror#5
-       add     r5,r5,r3
-       and     r2,r2,r9
-       eor     r3,r0,r9,ror#19
-       eor     r0,r5,r5,ror#11
-       eor     r2,r2,r11
-       add     r4,r4,r3,ror#6
-       eor     r3,r5,r6
-       eor     r0,r0,r5,ror#20
-       add     r4,r4,r2
-       ldr     r2,[sp,#32]
-       and     r12,r12,r3
-       add     r8,r8,r4
-       add     r4,r4,r0,ror#2
-       eor     r12,r12,r6
-       vst1.32 {q8},[r1,:128]!
-       add     r11,r11,r2
-       eor     r2,r9,r10
-       eor     r0,r8,r8,ror#5
-       add     r4,r4,r12
-       vld1.32 {q8},[r14,:128]!
-       and     r2,r2,r8
-       eor     r12,r0,r8,ror#19
-       eor     r0,r4,r4,ror#11
-       eor     r2,r2,r10
-       vrev32.8        q2,q2
-       add     r11,r11,r12,ror#6
-       eor     r12,r4,r5
-       eor     r0,r0,r4,ror#20
-       add     r11,r11,r2
-       vadd.i32        q8,q8,q2
-       ldr     r2,[sp,#36]
-       and     r3,r3,r12
-       add     r7,r7,r11
-       add     r11,r11,r0,ror#2
-       eor     r3,r3,r5
-       add     r10,r10,r2
-       eor     r2,r8,r9
-       eor     r0,r7,r7,ror#5
-       add     r11,r11,r3
-       and     r2,r2,r7
-       eor     r3,r0,r7,ror#19
-       eor     r0,r11,r11,ror#11
-       eor     r2,r2,r9
-       add     r10,r10,r3,ror#6
-       eor     r3,r11,r4
-       eor     r0,r0,r11,ror#20
-       add     r10,r10,r2
-       ldr     r2,[sp,#40]
-       and     r12,r12,r3
-       add     r6,r6,r10
-       add     r10,r10,r0,ror#2
-       eor     r12,r12,r4
-       add     r9,r9,r2
-       eor     r2,r7,r8
-       eor     r0,r6,r6,ror#5
-       add     r10,r10,r12
-       and     r2,r2,r6
-       eor     r12,r0,r6,ror#19
-       eor     r0,r10,r10,ror#11
-       eor     r2,r2,r8
-       add     r9,r9,r12,ror#6
-       eor     r12,r10,r11
-       eor     r0,r0,r10,ror#20
-       add     r9,r9,r2
-       ldr     r2,[sp,#44]
-       and     r3,r3,r12
-       add     r5,r5,r9
-       add     r9,r9,r0,ror#2
-       eor     r3,r3,r11
-       add     r8,r8,r2
-       eor     r2,r6,r7
-       eor     r0,r5,r5,ror#5
-       add     r9,r9,r3
-       and     r2,r2,r5
-       eor     r3,r0,r5,ror#19
-       eor     r0,r9,r9,ror#11
-       eor     r2,r2,r7
-       add     r8,r8,r3,ror#6
-       eor     r3,r9,r10
-       eor     r0,r0,r9,ror#20
-       add     r8,r8,r2
-       ldr     r2,[sp,#48]
-       and     r12,r12,r3
-       add     r4,r4,r8
-       add     r8,r8,r0,ror#2
-       eor     r12,r12,r10
-       vst1.32 {q8},[r1,:128]!
-       add     r7,r7,r2
-       eor     r2,r5,r6
-       eor     r0,r4,r4,ror#5
-       add     r8,r8,r12
-       vld1.32 {q8},[r14,:128]!
-       and     r2,r2,r4
-       eor     r12,r0,r4,ror#19
-       eor     r0,r8,r8,ror#11
-       eor     r2,r2,r6
-       vrev32.8        q3,q3
-       add     r7,r7,r12,ror#6
-       eor     r12,r8,r9
-       eor     r0,r0,r8,ror#20
-       add     r7,r7,r2
-       vadd.i32        q8,q8,q3
-       ldr     r2,[sp,#52]
-       and     r3,r3,r12
-       add     r11,r11,r7
-       add     r7,r7,r0,ror#2
-       eor     r3,r3,r9
-       add     r6,r6,r2
-       eor     r2,r4,r5
-       eor     r0,r11,r11,ror#5
-       add     r7,r7,r3
-       and     r2,r2,r11
-       eor     r3,r0,r11,ror#19
-       eor     r0,r7,r7,ror#11
-       eor     r2,r2,r5
-       add     r6,r6,r3,ror#6
-       eor     r3,r7,r8
-       eor     r0,r0,r7,ror#20
-       add     r6,r6,r2
-       ldr     r2,[sp,#56]
-       and     r12,r12,r3
-       add     r10,r10,r6
-       add     r6,r6,r0,ror#2
-       eor     r12,r12,r8
-       add     r5,r5,r2
-       eor     r2,r11,r4
-       eor     r0,r10,r10,ror#5
-       add     r6,r6,r12
-       and     r2,r2,r10
-       eor     r12,r0,r10,ror#19
-       eor     r0,r6,r6,ror#11
-       eor     r2,r2,r4
-       add     r5,r5,r12,ror#6
-       eor     r12,r6,r7
-       eor     r0,r0,r6,ror#20
-       add     r5,r5,r2
-       ldr     r2,[sp,#60]
-       and     r3,r3,r12
-       add     r9,r9,r5
-       add     r5,r5,r0,ror#2
-       eor     r3,r3,r7
-       add     r4,r4,r2
-       eor     r2,r10,r11
-       eor     r0,r9,r9,ror#5
-       add     r5,r5,r3
-       and     r2,r2,r9
-       eor     r3,r0,r9,ror#19
-       eor     r0,r5,r5,ror#11
-       eor     r2,r2,r11
-       add     r4,r4,r3,ror#6
-       eor     r3,r5,r6
-       eor     r0,r0,r5,ror#20
-       add     r4,r4,r2
-       ldr     r2,[sp,#64]
-       and     r12,r12,r3
-       add     r8,r8,r4
-       add     r4,r4,r0,ror#2
-       eor     r12,r12,r6
-       vst1.32 {q8},[r1,:128]!
-       ldr     r0,[r2,#0]
-       add     r4,r4,r12                       @ h+=Maj(a,b,c) from the past
-       ldr     r12,[r2,#4]
-       ldr     r3,[r2,#8]
-       ldr     r1,[r2,#12]
-       add     r4,r4,r0                        @ accumulate
-       ldr     r0,[r2,#16]
-       add     r5,r5,r12
-       ldr     r12,[r2,#20]
-       add     r6,r6,r3
-       ldr     r3,[r2,#24]
-       add     r7,r7,r1
-       ldr     r1,[r2,#28]
-       add     r8,r8,r0
-       str     r4,[r2],#4
-       add     r9,r9,r12
-       str     r5,[r2],#4
-       add     r10,r10,r3
-       str     r6,[r2],#4
-       add     r11,r11,r1
-       str     r7,[r2],#4
-       stmia   r2,{r8-r11}
-
-       ittte   ne
-       movne   r1,sp
-       ldrne   r2,[sp,#0]
-       eorne   r12,r12,r12
-       ldreq   sp,[sp,#76]                     @ restore original sp
-       itt     ne
-       eorne   r3,r5,r6
-       bne     .L_00_48
-
-       ldmia   sp!,{r4-r12,pc}
-.size  sha256_block_data_order_neon,.-sha256_block_data_order_neon
-#endif
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-
-# ifdef __thumb2__
-#  define INST(a,b,c,d)        .byte   c,d|0xc,a,b
-# else
-#  define INST(a,b,c,d)        .byte   a,b,c,d
-# endif
-
-.type  sha256_block_data_order_armv8,%function
-.align 5
-sha256_block_data_order_armv8:
-.LARMv8:
-       vld1.32 {q0,q1},[r0]
-# ifdef __thumb2__
-       adr     r3,.LARMv8
-       sub     r3,r3,#.LARMv8-K256
-# else
-       adrl    r3,K256
-# endif
-       add     r2,r1,r2,lsl#6  @ len to point at the end of inp
-
-.Loop_v8:
-       vld1.8          {q8-q9},[r1]!
-       vld1.8          {q10-q11},[r1]!
-       vld1.32         {q12},[r3]!
-       vrev32.8        q8,q8
-       vrev32.8        q9,q9
-       vrev32.8        q10,q10
-       vrev32.8        q11,q11
-       vmov            q14,q0  @ offload
-       vmov            q15,q1
-       teq             r1,r2
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q8
-       INST(0xe2,0x03,0xfa,0xf3)       @ sha256su0 q8,q9
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe6,0x0c,0x64,0xf3)       @ sha256su1 q8,q10,q11
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q9
-       INST(0xe4,0x23,0xfa,0xf3)       @ sha256su0 q9,q10
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe0,0x2c,0x66,0xf3)       @ sha256su1 q9,q11,q8
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q10
-       INST(0xe6,0x43,0xfa,0xf3)       @ sha256su0 q10,q11
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe2,0x4c,0x60,0xf3)       @ sha256su1 q10,q8,q9
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q11
-       INST(0xe0,0x63,0xfa,0xf3)       @ sha256su0 q11,q8
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe4,0x6c,0x62,0xf3)       @ sha256su1 q11,q9,q10
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q8
-       INST(0xe2,0x03,0xfa,0xf3)       @ sha256su0 q8,q9
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe6,0x0c,0x64,0xf3)       @ sha256su1 q8,q10,q11
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q9
-       INST(0xe4,0x23,0xfa,0xf3)       @ sha256su0 q9,q10
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe0,0x2c,0x66,0xf3)       @ sha256su1 q9,q11,q8
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q10
-       INST(0xe6,0x43,0xfa,0xf3)       @ sha256su0 q10,q11
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe2,0x4c,0x60,0xf3)       @ sha256su1 q10,q8,q9
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q11
-       INST(0xe0,0x63,0xfa,0xf3)       @ sha256su0 q11,q8
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe4,0x6c,0x62,0xf3)       @ sha256su1 q11,q9,q10
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q8
-       INST(0xe2,0x03,0xfa,0xf3)       @ sha256su0 q8,q9
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe6,0x0c,0x64,0xf3)       @ sha256su1 q8,q10,q11
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q9
-       INST(0xe4,0x23,0xfa,0xf3)       @ sha256su0 q9,q10
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe0,0x2c,0x66,0xf3)       @ sha256su1 q9,q11,q8
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q10
-       INST(0xe6,0x43,0xfa,0xf3)       @ sha256su0 q10,q11
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-       INST(0xe2,0x4c,0x60,0xf3)       @ sha256su1 q10,q8,q9
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q11
-       INST(0xe0,0x63,0xfa,0xf3)       @ sha256su0 q11,q8
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-       INST(0xe4,0x6c,0x62,0xf3)       @ sha256su1 q11,q9,q10
-       vld1.32         {q13},[r3]!
-       vadd.i32        q12,q12,q8
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-
-       vld1.32         {q12},[r3]!
-       vadd.i32        q13,q13,q9
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-
-       vld1.32         {q13},[r3]
-       vadd.i32        q12,q12,q10
-       sub             r3,r3,#256-16   @ rewind
-       vmov            q2,q0
-       INST(0x68,0x0c,0x02,0xf3)       @ sha256h q0,q1,q12
-       INST(0x68,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q12
-
-       vadd.i32        q13,q13,q11
-       vmov            q2,q0
-       INST(0x6a,0x0c,0x02,0xf3)       @ sha256h q0,q1,q13
-       INST(0x6a,0x2c,0x14,0xf3)       @ sha256h2 q1,q2,q13
-
-       vadd.i32        q0,q0,q14
-       vadd.i32        q1,q1,q15
-       it              ne
-       bne             .Loop_v8
-
-       vst1.32         {q0,q1},[r0]
-
-       bx      lr              @ bx lr
-.size  sha256_block_data_order_armv8,.-sha256_block_data_order_armv8
-#endif
-.asciz  "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by <appro@openssl.org>"
-.align 2
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-.comm   OPENSSL_armcap_P,4,4
-#endif
diff --git a/arch/arm/crypto/sha512-core.S_shipped b/arch/arm/crypto/sha512-core.S_shipped
deleted file mode 100644 (file)
index 0301462..0000000
+++ /dev/null
@@ -1,1869 +0,0 @@
-@ SPDX-License-Identifier: GPL-2.0
-
-@ This code is taken from the OpenSSL project but the author (Andy Polyakov)
-@ has relicensed it under the GPLv2. Therefore 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.
-@
-@ The original headers, including the original license headers, are
-@ included below for completeness.
-
-@ ====================================================================
-@ Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
-@ project. The module is, however, dual licensed under OpenSSL and
-@ CRYPTOGAMS licenses depending on where you obtain it. For further
-@ details see https://www.openssl.org/~appro/cryptogams/.
-@ ====================================================================
-
-@ SHA512 block procedure for ARMv4. September 2007.
-
-@ This code is ~4.5 (four and a half) times faster than code generated
-@ by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue
-@ Xscale PXA250 core].
-@
-@ July 2010.
-@
-@ Rescheduling for dual-issue pipeline resulted in 6% improvement on
-@ Cortex A8 core and ~40 cycles per processed byte.
-
-@ February 2011.
-@
-@ Profiler-assisted and platform-specific optimization resulted in 7%
-@ improvement on Coxtex A8 core and ~38 cycles per byte.
-
-@ March 2011.
-@
-@ Add NEON implementation. On Cortex A8 it was measured to process
-@ one byte in 23.3 cycles or ~60% faster than integer-only code.
-
-@ August 2012.
-@
-@ Improve NEON performance by 12% on Snapdragon S4. In absolute
-@ terms it's 22.6 cycles per byte, which is disappointing result.
-@ Technical writers asserted that 3-way S4 pipeline can sustain
-@ multiple NEON instructions per cycle, but dual NEON issue could
-@ not be observed, see https://www.openssl.org/~appro/Snapdragon-S4.html
-@ for further details. On side note Cortex-A15 processes one byte in
-@ 16 cycles.
-
-@ Byte order [in]dependence. =========================================
-@
-@ Originally caller was expected to maintain specific *dword* order in
-@ h[0-7], namely with most significant dword at *lower* address, which
-@ was reflected in below two parameters as 0 and 4. Now caller is
-@ expected to maintain native byte order for whole 64-bit values.
-#ifndef __KERNEL__
-# include "arm_arch.h"
-# define VFP_ABI_PUSH  vstmdb  sp!,{d8-d15}
-# define VFP_ABI_POP   vldmia  sp!,{d8-d15}
-#else
-# define __ARM_ARCH__ __LINUX_ARM_ARCH__
-# define __ARM_MAX_ARCH__ 7
-# define VFP_ABI_PUSH
-# define VFP_ABI_POP
-#endif
-
-#ifdef __ARMEL__
-# define LO 0
-# define HI 4
-# define WORD64(hi0,lo0,hi1,lo1)       .word   lo0,hi0, lo1,hi1
-#else
-# define HI 0
-# define LO 4
-# define WORD64(hi0,lo0,hi1,lo1)       .word   hi0,lo0, hi1,lo1
-#endif
-
-.text
-#if __ARM_ARCH__<7
-.code  32
-#else
-.syntax unified
-# ifdef __thumb2__
-.thumb
-# else
-.code   32
-# endif
-#endif
-
-.type  K512,%object
-.align 5
-K512:
-WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd)
-WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc)
-WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019)
-WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118)
-WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe)
-WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2)
-WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1)
-WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694)
-WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3)
-WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65)
-WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483)
-WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5)
-WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210)
-WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4)
-WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725)
-WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70)
-WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926)
-WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df)
-WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8)
-WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b)
-WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001)
-WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30)
-WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910)
-WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8)
-WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53)
-WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8)
-WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb)
-WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3)
-WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60)
-WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec)
-WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9)
-WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b)
-WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207)
-WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178)
-WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6)
-WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b)
-WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493)
-WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c)
-WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
-WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
-.size  K512,.-K512
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-.LOPENSSL_armcap:
-.word  OPENSSL_armcap_P-sha512_block_data_order
-.skip  32-4
-#else
-.skip  32
-#endif
-
-.global        sha512_block_data_order
-.type  sha512_block_data_order,%function
-sha512_block_data_order:
-.Lsha512_block_data_order:
-#if __ARM_ARCH__<7
-       sub     r3,pc,#8                @ sha512_block_data_order
-#else
-       adr     r3,.Lsha512_block_data_order
-#endif
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-       ldr     r12,.LOPENSSL_armcap
-       ldr     r12,[r3,r12]            @ OPENSSL_armcap_P
-       tst     r12,#1
-       bne     .LNEON
-#endif
-       add     r2,r1,r2,lsl#7  @ len to point at the end of inp
-       stmdb   sp!,{r4-r12,lr}
-       sub     r14,r3,#672             @ K512
-       sub     sp,sp,#9*8
-
-       ldr     r7,[r0,#32+LO]
-       ldr     r8,[r0,#32+HI]
-       ldr     r9, [r0,#48+LO]
-       ldr     r10, [r0,#48+HI]
-       ldr     r11, [r0,#56+LO]
-       ldr     r12, [r0,#56+HI]
-.Loop:
-       str     r9, [sp,#48+0]
-       str     r10, [sp,#48+4]
-       str     r11, [sp,#56+0]
-       str     r12, [sp,#56+4]
-       ldr     r5,[r0,#0+LO]
-       ldr     r6,[r0,#0+HI]
-       ldr     r3,[r0,#8+LO]
-       ldr     r4,[r0,#8+HI]
-       ldr     r9, [r0,#16+LO]
-       ldr     r10, [r0,#16+HI]
-       ldr     r11, [r0,#24+LO]
-       ldr     r12, [r0,#24+HI]
-       str     r3,[sp,#8+0]
-       str     r4,[sp,#8+4]
-       str     r9, [sp,#16+0]
-       str     r10, [sp,#16+4]
-       str     r11, [sp,#24+0]
-       str     r12, [sp,#24+4]
-       ldr     r3,[r0,#40+LO]
-       ldr     r4,[r0,#40+HI]
-       str     r3,[sp,#40+0]
-       str     r4,[sp,#40+4]
-
-.L00_15:
-#if __ARM_ARCH__<7
-       ldrb    r3,[r1,#7]
-       ldrb    r9, [r1,#6]
-       ldrb    r10, [r1,#5]
-       ldrb    r11, [r1,#4]
-       ldrb    r4,[r1,#3]
-       ldrb    r12, [r1,#2]
-       orr     r3,r3,r9,lsl#8
-       ldrb    r9, [r1,#1]
-       orr     r3,r3,r10,lsl#16
-       ldrb    r10, [r1],#8
-       orr     r3,r3,r11,lsl#24
-       orr     r4,r4,r12,lsl#8
-       orr     r4,r4,r9,lsl#16
-       orr     r4,r4,r10,lsl#24
-#else
-       ldr     r3,[r1,#4]
-       ldr     r4,[r1],#8
-#ifdef __ARMEL__
-       rev     r3,r3
-       rev     r4,r4
-#endif
-#endif
-       @ Sigma1(x)     (ROTR((x),14) ^ ROTR((x),18)  ^ ROTR((x),41))
-       @ LO            lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
-       @ HI            hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
-       mov     r9,r7,lsr#14
-       str     r3,[sp,#64+0]
-       mov     r10,r8,lsr#14
-       str     r4,[sp,#64+4]
-       eor     r9,r9,r8,lsl#18
-       ldr     r11,[sp,#56+0]  @ h.lo
-       eor     r10,r10,r7,lsl#18
-       ldr     r12,[sp,#56+4]  @ h.hi
-       eor     r9,r9,r7,lsr#18
-       eor     r10,r10,r8,lsr#18
-       eor     r9,r9,r8,lsl#14
-       eor     r10,r10,r7,lsl#14
-       eor     r9,r9,r8,lsr#9
-       eor     r10,r10,r7,lsr#9
-       eor     r9,r9,r7,lsl#23
-       eor     r10,r10,r8,lsl#23       @ Sigma1(e)
-       adds    r3,r3,r9
-       ldr     r9,[sp,#40+0]   @ f.lo
-       adc     r4,r4,r10               @ T += Sigma1(e)
-       ldr     r10,[sp,#40+4]  @ f.hi
-       adds    r3,r3,r11
-       ldr     r11,[sp,#48+0]  @ g.lo
-       adc     r4,r4,r12               @ T += h
-       ldr     r12,[sp,#48+4]  @ g.hi
-
-       eor     r9,r9,r11
-       str     r7,[sp,#32+0]
-       eor     r10,r10,r12
-       str     r8,[sp,#32+4]
-       and     r9,r9,r7
-       str     r5,[sp,#0+0]
-       and     r10,r10,r8
-       str     r6,[sp,#0+4]
-       eor     r9,r9,r11
-       ldr     r11,[r14,#LO]   @ K[i].lo
-       eor     r10,r10,r12             @ Ch(e,f,g)
-       ldr     r12,[r14,#HI]   @ K[i].hi
-
-       adds    r3,r3,r9
-       ldr     r7,[sp,#24+0]   @ d.lo
-       adc     r4,r4,r10               @ T += Ch(e,f,g)
-       ldr     r8,[sp,#24+4]   @ d.hi
-       adds    r3,r3,r11
-       and     r9,r11,#0xff
-       adc     r4,r4,r12               @ T += K[i]
-       adds    r7,r7,r3
-       ldr     r11,[sp,#8+0]   @ b.lo
-       adc     r8,r8,r4                @ d += T
-       teq     r9,#148
-
-       ldr     r12,[sp,#16+0]  @ c.lo
-#if __ARM_ARCH__>=7
-       it      eq                      @ Thumb2 thing, sanity check in ARM
-#endif
-       orreq   r14,r14,#1
-       @ Sigma0(x)     (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
-       @ LO            lo>>28^hi<<4  ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
-       @ HI            hi>>28^lo<<4  ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
-       mov     r9,r5,lsr#28
-       mov     r10,r6,lsr#28
-       eor     r9,r9,r6,lsl#4
-       eor     r10,r10,r5,lsl#4
-       eor     r9,r9,r6,lsr#2
-       eor     r10,r10,r5,lsr#2
-       eor     r9,r9,r5,lsl#30
-       eor     r10,r10,r6,lsl#30
-       eor     r9,r9,r6,lsr#7
-       eor     r10,r10,r5,lsr#7
-       eor     r9,r9,r5,lsl#25
-       eor     r10,r10,r6,lsl#25       @ Sigma0(a)
-       adds    r3,r3,r9
-       and     r9,r5,r11
-       adc     r4,r4,r10               @ T += Sigma0(a)
-
-       ldr     r10,[sp,#8+4]   @ b.hi
-       orr     r5,r5,r11
-       ldr     r11,[sp,#16+4]  @ c.hi
-       and     r5,r5,r12
-       and     r12,r6,r10
-       orr     r6,r6,r10
-       orr     r5,r5,r9                @ Maj(a,b,c).lo
-       and     r6,r6,r11
-       adds    r5,r5,r3
-       orr     r6,r6,r12               @ Maj(a,b,c).hi
-       sub     sp,sp,#8
-       adc     r6,r6,r4                @ h += T
-       tst     r14,#1
-       add     r14,r14,#8
-       tst     r14,#1
-       beq     .L00_15
-       ldr     r9,[sp,#184+0]
-       ldr     r10,[sp,#184+4]
-       bic     r14,r14,#1
-.L16_79:
-       @ sigma0(x)     (ROTR((x),1)  ^ ROTR((x),8)  ^ ((x)>>7))
-       @ LO            lo>>1^hi<<31  ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
-       @ HI            hi>>1^lo<<31  ^ hi>>8^lo<<24 ^ hi>>7
-       mov     r3,r9,lsr#1
-       ldr     r11,[sp,#80+0]
-       mov     r4,r10,lsr#1
-       ldr     r12,[sp,#80+4]
-       eor     r3,r3,r10,lsl#31
-       eor     r4,r4,r9,lsl#31
-       eor     r3,r3,r9,lsr#8
-       eor     r4,r4,r10,lsr#8
-       eor     r3,r3,r10,lsl#24
-       eor     r4,r4,r9,lsl#24
-       eor     r3,r3,r9,lsr#7
-       eor     r4,r4,r10,lsr#7
-       eor     r3,r3,r10,lsl#25
-
-       @ sigma1(x)     (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
-       @ LO            lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
-       @ HI            hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
-       mov     r9,r11,lsr#19
-       mov     r10,r12,lsr#19
-       eor     r9,r9,r12,lsl#13
-       eor     r10,r10,r11,lsl#13
-       eor     r9,r9,r12,lsr#29
-       eor     r10,r10,r11,lsr#29
-       eor     r9,r9,r11,lsl#3
-       eor     r10,r10,r12,lsl#3
-       eor     r9,r9,r11,lsr#6
-       eor     r10,r10,r12,lsr#6
-       ldr     r11,[sp,#120+0]
-       eor     r9,r9,r12,lsl#26
-
-       ldr     r12,[sp,#120+4]
-       adds    r3,r3,r9
-       ldr     r9,[sp,#192+0]
-       adc     r4,r4,r10
-
-       ldr     r10,[sp,#192+4]
-       adds    r3,r3,r11
-       adc     r4,r4,r12
-       adds    r3,r3,r9
-       adc     r4,r4,r10
-       @ Sigma1(x)     (ROTR((x),14) ^ ROTR((x),18)  ^ ROTR((x),41))
-       @ LO            lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
-       @ HI            hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
-       mov     r9,r7,lsr#14
-       str     r3,[sp,#64+0]
-       mov     r10,r8,lsr#14
-       str     r4,[sp,#64+4]
-       eor     r9,r9,r8,lsl#18
-       ldr     r11,[sp,#56+0]  @ h.lo
-       eor     r10,r10,r7,lsl#18
-       ldr     r12,[sp,#56+4]  @ h.hi
-       eor     r9,r9,r7,lsr#18
-       eor     r10,r10,r8,lsr#18
-       eor     r9,r9,r8,lsl#14
-       eor     r10,r10,r7,lsl#14
-       eor     r9,r9,r8,lsr#9
-       eor     r10,r10,r7,lsr#9
-       eor     r9,r9,r7,lsl#23
-       eor     r10,r10,r8,lsl#23       @ Sigma1(e)
-       adds    r3,r3,r9
-       ldr     r9,[sp,#40+0]   @ f.lo
-       adc     r4,r4,r10               @ T += Sigma1(e)
-       ldr     r10,[sp,#40+4]  @ f.hi
-       adds    r3,r3,r11
-       ldr     r11,[sp,#48+0]  @ g.lo
-       adc     r4,r4,r12               @ T += h
-       ldr     r12,[sp,#48+4]  @ g.hi
-
-       eor     r9,r9,r11
-       str     r7,[sp,#32+0]
-       eor     r10,r10,r12
-       str     r8,[sp,#32+4]
-       and     r9,r9,r7
-       str     r5,[sp,#0+0]
-       and     r10,r10,r8
-       str     r6,[sp,#0+4]
-       eor     r9,r9,r11
-       ldr     r11,[r14,#LO]   @ K[i].lo
-       eor     r10,r10,r12             @ Ch(e,f,g)
-       ldr     r12,[r14,#HI]   @ K[i].hi
-
-       adds    r3,r3,r9
-       ldr     r7,[sp,#24+0]   @ d.lo
-       adc     r4,r4,r10               @ T += Ch(e,f,g)
-       ldr     r8,[sp,#24+4]   @ d.hi
-       adds    r3,r3,r11
-       and     r9,r11,#0xff
-       adc     r4,r4,r12               @ T += K[i]
-       adds    r7,r7,r3
-       ldr     r11,[sp,#8+0]   @ b.lo
-       adc     r8,r8,r4                @ d += T
-       teq     r9,#23
-
-       ldr     r12,[sp,#16+0]  @ c.lo
-#if __ARM_ARCH__>=7
-       it      eq                      @ Thumb2 thing, sanity check in ARM
-#endif
-       orreq   r14,r14,#1
-       @ Sigma0(x)     (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
-       @ LO            lo>>28^hi<<4  ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
-       @ HI            hi>>28^lo<<4  ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
-       mov     r9,r5,lsr#28
-       mov     r10,r6,lsr#28
-       eor     r9,r9,r6,lsl#4
-       eor     r10,r10,r5,lsl#4
-       eor     r9,r9,r6,lsr#2
-       eor     r10,r10,r5,lsr#2
-       eor     r9,r9,r5,lsl#30
-       eor     r10,r10,r6,lsl#30
-       eor     r9,r9,r6,lsr#7
-       eor     r10,r10,r5,lsr#7
-       eor     r9,r9,r5,lsl#25
-       eor     r10,r10,r6,lsl#25       @ Sigma0(a)
-       adds    r3,r3,r9
-       and     r9,r5,r11
-       adc     r4,r4,r10               @ T += Sigma0(a)
-
-       ldr     r10,[sp,#8+4]   @ b.hi
-       orr     r5,r5,r11
-       ldr     r11,[sp,#16+4]  @ c.hi
-       and     r5,r5,r12
-       and     r12,r6,r10
-       orr     r6,r6,r10
-       orr     r5,r5,r9                @ Maj(a,b,c).lo
-       and     r6,r6,r11
-       adds    r5,r5,r3
-       orr     r6,r6,r12               @ Maj(a,b,c).hi
-       sub     sp,sp,#8
-       adc     r6,r6,r4                @ h += T
-       tst     r14,#1
-       add     r14,r14,#8
-#if __ARM_ARCH__>=7
-       ittt    eq                      @ Thumb2 thing, sanity check in ARM
-#endif
-       ldreq   r9,[sp,#184+0]
-       ldreq   r10,[sp,#184+4]
-       beq     .L16_79
-       bic     r14,r14,#1
-
-       ldr     r3,[sp,#8+0]
-       ldr     r4,[sp,#8+4]
-       ldr     r9, [r0,#0+LO]
-       ldr     r10, [r0,#0+HI]
-       ldr     r11, [r0,#8+LO]
-       ldr     r12, [r0,#8+HI]
-       adds    r9,r5,r9
-       str     r9, [r0,#0+LO]
-       adc     r10,r6,r10
-       str     r10, [r0,#0+HI]
-       adds    r11,r3,r11
-       str     r11, [r0,#8+LO]
-       adc     r12,r4,r12
-       str     r12, [r0,#8+HI]
-
-       ldr     r5,[sp,#16+0]
-       ldr     r6,[sp,#16+4]
-       ldr     r3,[sp,#24+0]
-       ldr     r4,[sp,#24+4]
-       ldr     r9, [r0,#16+LO]
-       ldr     r10, [r0,#16+HI]
-       ldr     r11, [r0,#24+LO]
-       ldr     r12, [r0,#24+HI]
-       adds    r9,r5,r9
-       str     r9, [r0,#16+LO]
-       adc     r10,r6,r10
-       str     r10, [r0,#16+HI]
-       adds    r11,r3,r11
-       str     r11, [r0,#24+LO]
-       adc     r12,r4,r12
-       str     r12, [r0,#24+HI]
-
-       ldr     r3,[sp,#40+0]
-       ldr     r4,[sp,#40+4]
-       ldr     r9, [r0,#32+LO]
-       ldr     r10, [r0,#32+HI]
-       ldr     r11, [r0,#40+LO]
-       ldr     r12, [r0,#40+HI]
-       adds    r7,r7,r9
-       str     r7,[r0,#32+LO]
-       adc     r8,r8,r10
-       str     r8,[r0,#32+HI]
-       adds    r11,r3,r11
-       str     r11, [r0,#40+LO]
-       adc     r12,r4,r12
-       str     r12, [r0,#40+HI]
-
-       ldr     r5,[sp,#48+0]
-       ldr     r6,[sp,#48+4]
-       ldr     r3,[sp,#56+0]
-       ldr     r4,[sp,#56+4]
-       ldr     r9, [r0,#48+LO]
-       ldr     r10, [r0,#48+HI]
-       ldr     r11, [r0,#56+LO]
-       ldr     r12, [r0,#56+HI]
-       adds    r9,r5,r9
-       str     r9, [r0,#48+LO]
-       adc     r10,r6,r10
-       str     r10, [r0,#48+HI]
-       adds    r11,r3,r11
-       str     r11, [r0,#56+LO]
-       adc     r12,r4,r12
-       str     r12, [r0,#56+HI]
-
-       add     sp,sp,#640
-       sub     r14,r14,#640
-
-       teq     r1,r2
-       bne     .Loop
-
-       add     sp,sp,#8*9              @ destroy frame
-#if __ARM_ARCH__>=5
-       ldmia   sp!,{r4-r12,pc}
-#else
-       ldmia   sp!,{r4-r12,lr}
-       tst     lr,#1
-       moveq   pc,lr                   @ be binary compatible with V4, yet
-       .word   0xe12fff1e                      @ interoperable with Thumb ISA:-)
-#endif
-.size  sha512_block_data_order,.-sha512_block_data_order
-#if __ARM_MAX_ARCH__>=7
-.arch  armv7-a
-.fpu   neon
-
-.global        sha512_block_data_order_neon
-.type  sha512_block_data_order_neon,%function
-.align 4
-sha512_block_data_order_neon:
-.LNEON:
-       dmb                             @ errata #451034 on early Cortex A8
-       add     r2,r1,r2,lsl#7  @ len to point at the end of inp
-       VFP_ABI_PUSH
-       adr     r3,.Lsha512_block_data_order
-       sub     r3,r3,.Lsha512_block_data_order-K512
-       vldmia  r0,{d16-d23}            @ load context
-.Loop_neon:
-       vshr.u64        d24,d20,#14     @ 0
-#if 0<16
-       vld1.64         {d0},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d20,#18
-#if 0>0
-        vadd.i64       d16,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d20,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d20,#50
-       vsli.64         d25,d20,#46
-       vmov            d29,d20
-       vsli.64         d26,d20,#23
-#if 0<16 && defined(__ARMEL__)
-       vrev64.8        d0,d0
-#endif
-       veor            d25,d24
-       vbsl            d29,d21,d22             @ Ch(e,f,g)
-       vshr.u64        d24,d16,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d23
-       vshr.u64        d25,d16,#34
-       vsli.64         d24,d16,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d16,#39
-       vadd.i64        d28,d0
-       vsli.64         d25,d16,#30
-       veor            d30,d16,d17
-       vsli.64         d26,d16,#25
-       veor            d23,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d18,d17             @ Maj(a,b,c)
-       veor            d23,d26                 @ Sigma0(a)
-       vadd.i64        d19,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d23,d30
-       vshr.u64        d24,d19,#14     @ 1
-#if 1<16
-       vld1.64         {d1},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d19,#18
-#if 1>0
-        vadd.i64       d23,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d19,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d19,#50
-       vsli.64         d25,d19,#46
-       vmov            d29,d19
-       vsli.64         d26,d19,#23
-#if 1<16 && defined(__ARMEL__)
-       vrev64.8        d1,d1
-#endif
-       veor            d25,d24
-       vbsl            d29,d20,d21             @ Ch(e,f,g)
-       vshr.u64        d24,d23,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d22
-       vshr.u64        d25,d23,#34
-       vsli.64         d24,d23,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d23,#39
-       vadd.i64        d28,d1
-       vsli.64         d25,d23,#30
-       veor            d30,d23,d16
-       vsli.64         d26,d23,#25
-       veor            d22,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d17,d16             @ Maj(a,b,c)
-       veor            d22,d26                 @ Sigma0(a)
-       vadd.i64        d18,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d22,d30
-       vshr.u64        d24,d18,#14     @ 2
-#if 2<16
-       vld1.64         {d2},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d18,#18
-#if 2>0
-        vadd.i64       d22,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d18,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d18,#50
-       vsli.64         d25,d18,#46
-       vmov            d29,d18
-       vsli.64         d26,d18,#23
-#if 2<16 && defined(__ARMEL__)
-       vrev64.8        d2,d2
-#endif
-       veor            d25,d24
-       vbsl            d29,d19,d20             @ Ch(e,f,g)
-       vshr.u64        d24,d22,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d21
-       vshr.u64        d25,d22,#34
-       vsli.64         d24,d22,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d22,#39
-       vadd.i64        d28,d2
-       vsli.64         d25,d22,#30
-       veor            d30,d22,d23
-       vsli.64         d26,d22,#25
-       veor            d21,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d16,d23             @ Maj(a,b,c)
-       veor            d21,d26                 @ Sigma0(a)
-       vadd.i64        d17,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d21,d30
-       vshr.u64        d24,d17,#14     @ 3
-#if 3<16
-       vld1.64         {d3},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d17,#18
-#if 3>0
-        vadd.i64       d21,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d17,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d17,#50
-       vsli.64         d25,d17,#46
-       vmov            d29,d17
-       vsli.64         d26,d17,#23
-#if 3<16 && defined(__ARMEL__)
-       vrev64.8        d3,d3
-#endif
-       veor            d25,d24
-       vbsl            d29,d18,d19             @ Ch(e,f,g)
-       vshr.u64        d24,d21,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d20
-       vshr.u64        d25,d21,#34
-       vsli.64         d24,d21,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d21,#39
-       vadd.i64        d28,d3
-       vsli.64         d25,d21,#30
-       veor            d30,d21,d22
-       vsli.64         d26,d21,#25
-       veor            d20,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d23,d22             @ Maj(a,b,c)
-       veor            d20,d26                 @ Sigma0(a)
-       vadd.i64        d16,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d20,d30
-       vshr.u64        d24,d16,#14     @ 4
-#if 4<16
-       vld1.64         {d4},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d16,#18
-#if 4>0
-        vadd.i64       d20,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d16,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d16,#50
-       vsli.64         d25,d16,#46
-       vmov            d29,d16
-       vsli.64         d26,d16,#23
-#if 4<16 && defined(__ARMEL__)
-       vrev64.8        d4,d4
-#endif
-       veor            d25,d24
-       vbsl            d29,d17,d18             @ Ch(e,f,g)
-       vshr.u64        d24,d20,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d19
-       vshr.u64        d25,d20,#34
-       vsli.64         d24,d20,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d20,#39
-       vadd.i64        d28,d4
-       vsli.64         d25,d20,#30
-       veor            d30,d20,d21
-       vsli.64         d26,d20,#25
-       veor            d19,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d22,d21             @ Maj(a,b,c)
-       veor            d19,d26                 @ Sigma0(a)
-       vadd.i64        d23,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d19,d30
-       vshr.u64        d24,d23,#14     @ 5
-#if 5<16
-       vld1.64         {d5},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d23,#18
-#if 5>0
-        vadd.i64       d19,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d23,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d23,#50
-       vsli.64         d25,d23,#46
-       vmov            d29,d23
-       vsli.64         d26,d23,#23
-#if 5<16 && defined(__ARMEL__)
-       vrev64.8        d5,d5
-#endif
-       veor            d25,d24
-       vbsl            d29,d16,d17             @ Ch(e,f,g)
-       vshr.u64        d24,d19,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d18
-       vshr.u64        d25,d19,#34
-       vsli.64         d24,d19,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d19,#39
-       vadd.i64        d28,d5
-       vsli.64         d25,d19,#30
-       veor            d30,d19,d20
-       vsli.64         d26,d19,#25
-       veor            d18,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d21,d20             @ Maj(a,b,c)
-       veor            d18,d26                 @ Sigma0(a)
-       vadd.i64        d22,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d18,d30
-       vshr.u64        d24,d22,#14     @ 6
-#if 6<16
-       vld1.64         {d6},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d22,#18
-#if 6>0
-        vadd.i64       d18,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d22,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d22,#50
-       vsli.64         d25,d22,#46
-       vmov            d29,d22
-       vsli.64         d26,d22,#23
-#if 6<16 && defined(__ARMEL__)
-       vrev64.8        d6,d6
-#endif
-       veor            d25,d24
-       vbsl            d29,d23,d16             @ Ch(e,f,g)
-       vshr.u64        d24,d18,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d17
-       vshr.u64        d25,d18,#34
-       vsli.64         d24,d18,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d18,#39
-       vadd.i64        d28,d6
-       vsli.64         d25,d18,#30
-       veor            d30,d18,d19
-       vsli.64         d26,d18,#25
-       veor            d17,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d20,d19             @ Maj(a,b,c)
-       veor            d17,d26                 @ Sigma0(a)
-       vadd.i64        d21,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d17,d30
-       vshr.u64        d24,d21,#14     @ 7
-#if 7<16
-       vld1.64         {d7},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d21,#18
-#if 7>0
-        vadd.i64       d17,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d21,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d21,#50
-       vsli.64         d25,d21,#46
-       vmov            d29,d21
-       vsli.64         d26,d21,#23
-#if 7<16 && defined(__ARMEL__)
-       vrev64.8        d7,d7
-#endif
-       veor            d25,d24
-       vbsl            d29,d22,d23             @ Ch(e,f,g)
-       vshr.u64        d24,d17,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d16
-       vshr.u64        d25,d17,#34
-       vsli.64         d24,d17,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d17,#39
-       vadd.i64        d28,d7
-       vsli.64         d25,d17,#30
-       veor            d30,d17,d18
-       vsli.64         d26,d17,#25
-       veor            d16,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d19,d18             @ Maj(a,b,c)
-       veor            d16,d26                 @ Sigma0(a)
-       vadd.i64        d20,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d16,d30
-       vshr.u64        d24,d20,#14     @ 8
-#if 8<16
-       vld1.64         {d8},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d20,#18
-#if 8>0
-        vadd.i64       d16,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d20,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d20,#50
-       vsli.64         d25,d20,#46
-       vmov            d29,d20
-       vsli.64         d26,d20,#23
-#if 8<16 && defined(__ARMEL__)
-       vrev64.8        d8,d8
-#endif
-       veor            d25,d24
-       vbsl            d29,d21,d22             @ Ch(e,f,g)
-       vshr.u64        d24,d16,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d23
-       vshr.u64        d25,d16,#34
-       vsli.64         d24,d16,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d16,#39
-       vadd.i64        d28,d8
-       vsli.64         d25,d16,#30
-       veor            d30,d16,d17
-       vsli.64         d26,d16,#25
-       veor            d23,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d18,d17             @ Maj(a,b,c)
-       veor            d23,d26                 @ Sigma0(a)
-       vadd.i64        d19,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d23,d30
-       vshr.u64        d24,d19,#14     @ 9
-#if 9<16
-       vld1.64         {d9},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d19,#18
-#if 9>0
-        vadd.i64       d23,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d19,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d19,#50
-       vsli.64         d25,d19,#46
-       vmov            d29,d19
-       vsli.64         d26,d19,#23
-#if 9<16 && defined(__ARMEL__)
-       vrev64.8        d9,d9
-#endif
-       veor            d25,d24
-       vbsl            d29,d20,d21             @ Ch(e,f,g)
-       vshr.u64        d24,d23,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d22
-       vshr.u64        d25,d23,#34
-       vsli.64         d24,d23,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d23,#39
-       vadd.i64        d28,d9
-       vsli.64         d25,d23,#30
-       veor            d30,d23,d16
-       vsli.64         d26,d23,#25
-       veor            d22,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d17,d16             @ Maj(a,b,c)
-       veor            d22,d26                 @ Sigma0(a)
-       vadd.i64        d18,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d22,d30
-       vshr.u64        d24,d18,#14     @ 10
-#if 10<16
-       vld1.64         {d10},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d18,#18
-#if 10>0
-        vadd.i64       d22,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d18,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d18,#50
-       vsli.64         d25,d18,#46
-       vmov            d29,d18
-       vsli.64         d26,d18,#23
-#if 10<16 && defined(__ARMEL__)
-       vrev64.8        d10,d10
-#endif
-       veor            d25,d24
-       vbsl            d29,d19,d20             @ Ch(e,f,g)
-       vshr.u64        d24,d22,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d21
-       vshr.u64        d25,d22,#34
-       vsli.64         d24,d22,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d22,#39
-       vadd.i64        d28,d10
-       vsli.64         d25,d22,#30
-       veor            d30,d22,d23
-       vsli.64         d26,d22,#25
-       veor            d21,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d16,d23             @ Maj(a,b,c)
-       veor            d21,d26                 @ Sigma0(a)
-       vadd.i64        d17,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d21,d30
-       vshr.u64        d24,d17,#14     @ 11
-#if 11<16
-       vld1.64         {d11},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d17,#18
-#if 11>0
-        vadd.i64       d21,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d17,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d17,#50
-       vsli.64         d25,d17,#46
-       vmov            d29,d17
-       vsli.64         d26,d17,#23
-#if 11<16 && defined(__ARMEL__)
-       vrev64.8        d11,d11
-#endif
-       veor            d25,d24
-       vbsl            d29,d18,d19             @ Ch(e,f,g)
-       vshr.u64        d24,d21,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d20
-       vshr.u64        d25,d21,#34
-       vsli.64         d24,d21,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d21,#39
-       vadd.i64        d28,d11
-       vsli.64         d25,d21,#30
-       veor            d30,d21,d22
-       vsli.64         d26,d21,#25
-       veor            d20,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d23,d22             @ Maj(a,b,c)
-       veor            d20,d26                 @ Sigma0(a)
-       vadd.i64        d16,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d20,d30
-       vshr.u64        d24,d16,#14     @ 12
-#if 12<16
-       vld1.64         {d12},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d16,#18
-#if 12>0
-        vadd.i64       d20,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d16,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d16,#50
-       vsli.64         d25,d16,#46
-       vmov            d29,d16
-       vsli.64         d26,d16,#23
-#if 12<16 && defined(__ARMEL__)
-       vrev64.8        d12,d12
-#endif
-       veor            d25,d24
-       vbsl            d29,d17,d18             @ Ch(e,f,g)
-       vshr.u64        d24,d20,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d19
-       vshr.u64        d25,d20,#34
-       vsli.64         d24,d20,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d20,#39
-       vadd.i64        d28,d12
-       vsli.64         d25,d20,#30
-       veor            d30,d20,d21
-       vsli.64         d26,d20,#25
-       veor            d19,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d22,d21             @ Maj(a,b,c)
-       veor            d19,d26                 @ Sigma0(a)
-       vadd.i64        d23,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d19,d30
-       vshr.u64        d24,d23,#14     @ 13
-#if 13<16
-       vld1.64         {d13},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d23,#18
-#if 13>0
-        vadd.i64       d19,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d23,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d23,#50
-       vsli.64         d25,d23,#46
-       vmov            d29,d23
-       vsli.64         d26,d23,#23
-#if 13<16 && defined(__ARMEL__)
-       vrev64.8        d13,d13
-#endif
-       veor            d25,d24
-       vbsl            d29,d16,d17             @ Ch(e,f,g)
-       vshr.u64        d24,d19,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d18
-       vshr.u64        d25,d19,#34
-       vsli.64         d24,d19,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d19,#39
-       vadd.i64        d28,d13
-       vsli.64         d25,d19,#30
-       veor            d30,d19,d20
-       vsli.64         d26,d19,#25
-       veor            d18,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d21,d20             @ Maj(a,b,c)
-       veor            d18,d26                 @ Sigma0(a)
-       vadd.i64        d22,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d18,d30
-       vshr.u64        d24,d22,#14     @ 14
-#if 14<16
-       vld1.64         {d14},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d22,#18
-#if 14>0
-        vadd.i64       d18,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d22,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d22,#50
-       vsli.64         d25,d22,#46
-       vmov            d29,d22
-       vsli.64         d26,d22,#23
-#if 14<16 && defined(__ARMEL__)
-       vrev64.8        d14,d14
-#endif
-       veor            d25,d24
-       vbsl            d29,d23,d16             @ Ch(e,f,g)
-       vshr.u64        d24,d18,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d17
-       vshr.u64        d25,d18,#34
-       vsli.64         d24,d18,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d18,#39
-       vadd.i64        d28,d14
-       vsli.64         d25,d18,#30
-       veor            d30,d18,d19
-       vsli.64         d26,d18,#25
-       veor            d17,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d20,d19             @ Maj(a,b,c)
-       veor            d17,d26                 @ Sigma0(a)
-       vadd.i64        d21,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d17,d30
-       vshr.u64        d24,d21,#14     @ 15
-#if 15<16
-       vld1.64         {d15},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d21,#18
-#if 15>0
-        vadd.i64       d17,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d21,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d21,#50
-       vsli.64         d25,d21,#46
-       vmov            d29,d21
-       vsli.64         d26,d21,#23
-#if 15<16 && defined(__ARMEL__)
-       vrev64.8        d15,d15
-#endif
-       veor            d25,d24
-       vbsl            d29,d22,d23             @ Ch(e,f,g)
-       vshr.u64        d24,d17,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d16
-       vshr.u64        d25,d17,#34
-       vsli.64         d24,d17,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d17,#39
-       vadd.i64        d28,d15
-       vsli.64         d25,d17,#30
-       veor            d30,d17,d18
-       vsli.64         d26,d17,#25
-       veor            d16,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d19,d18             @ Maj(a,b,c)
-       veor            d16,d26                 @ Sigma0(a)
-       vadd.i64        d20,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d16,d30
-       mov             r12,#4
-.L16_79_neon:
-       subs            r12,#1
-       vshr.u64        q12,q7,#19
-       vshr.u64        q13,q7,#61
-        vadd.i64       d16,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q7,#6
-       vsli.64         q12,q7,#45
-       vext.8          q14,q0,q1,#8    @ X[i+1]
-       vsli.64         q13,q7,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q0,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q4,q5,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d20,#14             @ from NEON_00_15
-       vadd.i64        q0,q14
-       vshr.u64        d25,d20,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d20,#41             @ from NEON_00_15
-       vadd.i64        q0,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d20,#50
-       vsli.64         d25,d20,#46
-       vmov            d29,d20
-       vsli.64         d26,d20,#23
-#if 16<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d21,d22             @ Ch(e,f,g)
-       vshr.u64        d24,d16,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d23
-       vshr.u64        d25,d16,#34
-       vsli.64         d24,d16,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d16,#39
-       vadd.i64        d28,d0
-       vsli.64         d25,d16,#30
-       veor            d30,d16,d17
-       vsli.64         d26,d16,#25
-       veor            d23,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d18,d17             @ Maj(a,b,c)
-       veor            d23,d26                 @ Sigma0(a)
-       vadd.i64        d19,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d23,d30
-       vshr.u64        d24,d19,#14     @ 17
-#if 17<16
-       vld1.64         {d1},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d19,#18
-#if 17>0
-        vadd.i64       d23,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d19,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d19,#50
-       vsli.64         d25,d19,#46
-       vmov            d29,d19
-       vsli.64         d26,d19,#23
-#if 17<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d20,d21             @ Ch(e,f,g)
-       vshr.u64        d24,d23,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d22
-       vshr.u64        d25,d23,#34
-       vsli.64         d24,d23,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d23,#39
-       vadd.i64        d28,d1
-       vsli.64         d25,d23,#30
-       veor            d30,d23,d16
-       vsli.64         d26,d23,#25
-       veor            d22,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d17,d16             @ Maj(a,b,c)
-       veor            d22,d26                 @ Sigma0(a)
-       vadd.i64        d18,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d22,d30
-       vshr.u64        q12,q0,#19
-       vshr.u64        q13,q0,#61
-        vadd.i64       d22,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q0,#6
-       vsli.64         q12,q0,#45
-       vext.8          q14,q1,q2,#8    @ X[i+1]
-       vsli.64         q13,q0,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q1,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q5,q6,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d18,#14             @ from NEON_00_15
-       vadd.i64        q1,q14
-       vshr.u64        d25,d18,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d18,#41             @ from NEON_00_15
-       vadd.i64        q1,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d18,#50
-       vsli.64         d25,d18,#46
-       vmov            d29,d18
-       vsli.64         d26,d18,#23
-#if 18<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d19,d20             @ Ch(e,f,g)
-       vshr.u64        d24,d22,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d21
-       vshr.u64        d25,d22,#34
-       vsli.64         d24,d22,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d22,#39
-       vadd.i64        d28,d2
-       vsli.64         d25,d22,#30
-       veor            d30,d22,d23
-       vsli.64         d26,d22,#25
-       veor            d21,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d16,d23             @ Maj(a,b,c)
-       veor            d21,d26                 @ Sigma0(a)
-       vadd.i64        d17,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d21,d30
-       vshr.u64        d24,d17,#14     @ 19
-#if 19<16
-       vld1.64         {d3},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d17,#18
-#if 19>0
-        vadd.i64       d21,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d17,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d17,#50
-       vsli.64         d25,d17,#46
-       vmov            d29,d17
-       vsli.64         d26,d17,#23
-#if 19<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d18,d19             @ Ch(e,f,g)
-       vshr.u64        d24,d21,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d20
-       vshr.u64        d25,d21,#34
-       vsli.64         d24,d21,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d21,#39
-       vadd.i64        d28,d3
-       vsli.64         d25,d21,#30
-       veor            d30,d21,d22
-       vsli.64         d26,d21,#25
-       veor            d20,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d23,d22             @ Maj(a,b,c)
-       veor            d20,d26                 @ Sigma0(a)
-       vadd.i64        d16,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d20,d30
-       vshr.u64        q12,q1,#19
-       vshr.u64        q13,q1,#61
-        vadd.i64       d20,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q1,#6
-       vsli.64         q12,q1,#45
-       vext.8          q14,q2,q3,#8    @ X[i+1]
-       vsli.64         q13,q1,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q2,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q6,q7,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d16,#14             @ from NEON_00_15
-       vadd.i64        q2,q14
-       vshr.u64        d25,d16,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d16,#41             @ from NEON_00_15
-       vadd.i64        q2,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d16,#50
-       vsli.64         d25,d16,#46
-       vmov            d29,d16
-       vsli.64         d26,d16,#23
-#if 20<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d17,d18             @ Ch(e,f,g)
-       vshr.u64        d24,d20,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d19
-       vshr.u64        d25,d20,#34
-       vsli.64         d24,d20,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d20,#39
-       vadd.i64        d28,d4
-       vsli.64         d25,d20,#30
-       veor            d30,d20,d21
-       vsli.64         d26,d20,#25
-       veor            d19,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d22,d21             @ Maj(a,b,c)
-       veor            d19,d26                 @ Sigma0(a)
-       vadd.i64        d23,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d19,d30
-       vshr.u64        d24,d23,#14     @ 21
-#if 21<16
-       vld1.64         {d5},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d23,#18
-#if 21>0
-        vadd.i64       d19,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d23,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d23,#50
-       vsli.64         d25,d23,#46
-       vmov            d29,d23
-       vsli.64         d26,d23,#23
-#if 21<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d16,d17             @ Ch(e,f,g)
-       vshr.u64        d24,d19,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d18
-       vshr.u64        d25,d19,#34
-       vsli.64         d24,d19,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d19,#39
-       vadd.i64        d28,d5
-       vsli.64         d25,d19,#30
-       veor            d30,d19,d20
-       vsli.64         d26,d19,#25
-       veor            d18,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d21,d20             @ Maj(a,b,c)
-       veor            d18,d26                 @ Sigma0(a)
-       vadd.i64        d22,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d18,d30
-       vshr.u64        q12,q2,#19
-       vshr.u64        q13,q2,#61
-        vadd.i64       d18,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q2,#6
-       vsli.64         q12,q2,#45
-       vext.8          q14,q3,q4,#8    @ X[i+1]
-       vsli.64         q13,q2,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q3,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q7,q0,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d22,#14             @ from NEON_00_15
-       vadd.i64        q3,q14
-       vshr.u64        d25,d22,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d22,#41             @ from NEON_00_15
-       vadd.i64        q3,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d22,#50
-       vsli.64         d25,d22,#46
-       vmov            d29,d22
-       vsli.64         d26,d22,#23
-#if 22<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d23,d16             @ Ch(e,f,g)
-       vshr.u64        d24,d18,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d17
-       vshr.u64        d25,d18,#34
-       vsli.64         d24,d18,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d18,#39
-       vadd.i64        d28,d6
-       vsli.64         d25,d18,#30
-       veor            d30,d18,d19
-       vsli.64         d26,d18,#25
-       veor            d17,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d20,d19             @ Maj(a,b,c)
-       veor            d17,d26                 @ Sigma0(a)
-       vadd.i64        d21,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d17,d30
-       vshr.u64        d24,d21,#14     @ 23
-#if 23<16
-       vld1.64         {d7},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d21,#18
-#if 23>0
-        vadd.i64       d17,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d21,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d21,#50
-       vsli.64         d25,d21,#46
-       vmov            d29,d21
-       vsli.64         d26,d21,#23
-#if 23<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d22,d23             @ Ch(e,f,g)
-       vshr.u64        d24,d17,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d16
-       vshr.u64        d25,d17,#34
-       vsli.64         d24,d17,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d17,#39
-       vadd.i64        d28,d7
-       vsli.64         d25,d17,#30
-       veor            d30,d17,d18
-       vsli.64         d26,d17,#25
-       veor            d16,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d19,d18             @ Maj(a,b,c)
-       veor            d16,d26                 @ Sigma0(a)
-       vadd.i64        d20,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d16,d30
-       vshr.u64        q12,q3,#19
-       vshr.u64        q13,q3,#61
-        vadd.i64       d16,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q3,#6
-       vsli.64         q12,q3,#45
-       vext.8          q14,q4,q5,#8    @ X[i+1]
-       vsli.64         q13,q3,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q4,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q0,q1,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d20,#14             @ from NEON_00_15
-       vadd.i64        q4,q14
-       vshr.u64        d25,d20,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d20,#41             @ from NEON_00_15
-       vadd.i64        q4,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d20,#50
-       vsli.64         d25,d20,#46
-       vmov            d29,d20
-       vsli.64         d26,d20,#23
-#if 24<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d21,d22             @ Ch(e,f,g)
-       vshr.u64        d24,d16,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d23
-       vshr.u64        d25,d16,#34
-       vsli.64         d24,d16,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d16,#39
-       vadd.i64        d28,d8
-       vsli.64         d25,d16,#30
-       veor            d30,d16,d17
-       vsli.64         d26,d16,#25
-       veor            d23,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d18,d17             @ Maj(a,b,c)
-       veor            d23,d26                 @ Sigma0(a)
-       vadd.i64        d19,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d23,d30
-       vshr.u64        d24,d19,#14     @ 25
-#if 25<16
-       vld1.64         {d9},[r1]!      @ handles unaligned
-#endif
-       vshr.u64        d25,d19,#18
-#if 25>0
-        vadd.i64       d23,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d19,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d19,#50
-       vsli.64         d25,d19,#46
-       vmov            d29,d19
-       vsli.64         d26,d19,#23
-#if 25<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d20,d21             @ Ch(e,f,g)
-       vshr.u64        d24,d23,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d22
-       vshr.u64        d25,d23,#34
-       vsli.64         d24,d23,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d23,#39
-       vadd.i64        d28,d9
-       vsli.64         d25,d23,#30
-       veor            d30,d23,d16
-       vsli.64         d26,d23,#25
-       veor            d22,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d17,d16             @ Maj(a,b,c)
-       veor            d22,d26                 @ Sigma0(a)
-       vadd.i64        d18,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d22,d30
-       vshr.u64        q12,q4,#19
-       vshr.u64        q13,q4,#61
-        vadd.i64       d22,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q4,#6
-       vsli.64         q12,q4,#45
-       vext.8          q14,q5,q6,#8    @ X[i+1]
-       vsli.64         q13,q4,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q5,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q1,q2,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d18,#14             @ from NEON_00_15
-       vadd.i64        q5,q14
-       vshr.u64        d25,d18,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d18,#41             @ from NEON_00_15
-       vadd.i64        q5,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d18,#50
-       vsli.64         d25,d18,#46
-       vmov            d29,d18
-       vsli.64         d26,d18,#23
-#if 26<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d19,d20             @ Ch(e,f,g)
-       vshr.u64        d24,d22,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d21
-       vshr.u64        d25,d22,#34
-       vsli.64         d24,d22,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d22,#39
-       vadd.i64        d28,d10
-       vsli.64         d25,d22,#30
-       veor            d30,d22,d23
-       vsli.64         d26,d22,#25
-       veor            d21,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d16,d23             @ Maj(a,b,c)
-       veor            d21,d26                 @ Sigma0(a)
-       vadd.i64        d17,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d21,d30
-       vshr.u64        d24,d17,#14     @ 27
-#if 27<16
-       vld1.64         {d11},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d17,#18
-#if 27>0
-        vadd.i64       d21,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d17,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d17,#50
-       vsli.64         d25,d17,#46
-       vmov            d29,d17
-       vsli.64         d26,d17,#23
-#if 27<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d18,d19             @ Ch(e,f,g)
-       vshr.u64        d24,d21,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d20
-       vshr.u64        d25,d21,#34
-       vsli.64         d24,d21,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d21,#39
-       vadd.i64        d28,d11
-       vsli.64         d25,d21,#30
-       veor            d30,d21,d22
-       vsli.64         d26,d21,#25
-       veor            d20,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d23,d22             @ Maj(a,b,c)
-       veor            d20,d26                 @ Sigma0(a)
-       vadd.i64        d16,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d20,d30
-       vshr.u64        q12,q5,#19
-       vshr.u64        q13,q5,#61
-        vadd.i64       d20,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q5,#6
-       vsli.64         q12,q5,#45
-       vext.8          q14,q6,q7,#8    @ X[i+1]
-       vsli.64         q13,q5,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q6,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q2,q3,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d16,#14             @ from NEON_00_15
-       vadd.i64        q6,q14
-       vshr.u64        d25,d16,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d16,#41             @ from NEON_00_15
-       vadd.i64        q6,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d16,#50
-       vsli.64         d25,d16,#46
-       vmov            d29,d16
-       vsli.64         d26,d16,#23
-#if 28<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d17,d18             @ Ch(e,f,g)
-       vshr.u64        d24,d20,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d19
-       vshr.u64        d25,d20,#34
-       vsli.64         d24,d20,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d20,#39
-       vadd.i64        d28,d12
-       vsli.64         d25,d20,#30
-       veor            d30,d20,d21
-       vsli.64         d26,d20,#25
-       veor            d19,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d22,d21             @ Maj(a,b,c)
-       veor            d19,d26                 @ Sigma0(a)
-       vadd.i64        d23,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d19,d30
-       vshr.u64        d24,d23,#14     @ 29
-#if 29<16
-       vld1.64         {d13},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d23,#18
-#if 29>0
-        vadd.i64       d19,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d23,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d23,#50
-       vsli.64         d25,d23,#46
-       vmov            d29,d23
-       vsli.64         d26,d23,#23
-#if 29<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d16,d17             @ Ch(e,f,g)
-       vshr.u64        d24,d19,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d18
-       vshr.u64        d25,d19,#34
-       vsli.64         d24,d19,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d19,#39
-       vadd.i64        d28,d13
-       vsli.64         d25,d19,#30
-       veor            d30,d19,d20
-       vsli.64         d26,d19,#25
-       veor            d18,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d21,d20             @ Maj(a,b,c)
-       veor            d18,d26                 @ Sigma0(a)
-       vadd.i64        d22,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d18,d30
-       vshr.u64        q12,q6,#19
-       vshr.u64        q13,q6,#61
-        vadd.i64       d18,d30                 @ h+=Maj from the past
-       vshr.u64        q15,q6,#6
-       vsli.64         q12,q6,#45
-       vext.8          q14,q7,q0,#8    @ X[i+1]
-       vsli.64         q13,q6,#3
-       veor            q15,q12
-       vshr.u64        q12,q14,#1
-       veor            q15,q13                         @ sigma1(X[i+14])
-       vshr.u64        q13,q14,#8
-       vadd.i64        q7,q15
-       vshr.u64        q15,q14,#7
-       vsli.64         q12,q14,#63
-       vsli.64         q13,q14,#56
-       vext.8          q14,q3,q4,#8    @ X[i+9]
-       veor            q15,q12
-       vshr.u64        d24,d22,#14             @ from NEON_00_15
-       vadd.i64        q7,q14
-       vshr.u64        d25,d22,#18             @ from NEON_00_15
-       veor            q15,q13                         @ sigma0(X[i+1])
-       vshr.u64        d26,d22,#41             @ from NEON_00_15
-       vadd.i64        q7,q15
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d22,#50
-       vsli.64         d25,d22,#46
-       vmov            d29,d22
-       vsli.64         d26,d22,#23
-#if 30<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d23,d16             @ Ch(e,f,g)
-       vshr.u64        d24,d18,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d17
-       vshr.u64        d25,d18,#34
-       vsli.64         d24,d18,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d18,#39
-       vadd.i64        d28,d14
-       vsli.64         d25,d18,#30
-       veor            d30,d18,d19
-       vsli.64         d26,d18,#25
-       veor            d17,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d20,d19             @ Maj(a,b,c)
-       veor            d17,d26                 @ Sigma0(a)
-       vadd.i64        d21,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d17,d30
-       vshr.u64        d24,d21,#14     @ 31
-#if 31<16
-       vld1.64         {d15},[r1]!     @ handles unaligned
-#endif
-       vshr.u64        d25,d21,#18
-#if 31>0
-        vadd.i64       d17,d30                 @ h+=Maj from the past
-#endif
-       vshr.u64        d26,d21,#41
-       vld1.64         {d28},[r3,:64]! @ K[i++]
-       vsli.64         d24,d21,#50
-       vsli.64         d25,d21,#46
-       vmov            d29,d21
-       vsli.64         d26,d21,#23
-#if 31<16 && defined(__ARMEL__)
-       vrev64.8        ,
-#endif
-       veor            d25,d24
-       vbsl            d29,d22,d23             @ Ch(e,f,g)
-       vshr.u64        d24,d17,#28
-       veor            d26,d25                 @ Sigma1(e)
-       vadd.i64        d27,d29,d16
-       vshr.u64        d25,d17,#34
-       vsli.64         d24,d17,#36
-       vadd.i64        d27,d26
-       vshr.u64        d26,d17,#39
-       vadd.i64        d28,d15
-       vsli.64         d25,d17,#30
-       veor            d30,d17,d18
-       vsli.64         d26,d17,#25
-       veor            d16,d24,d25
-       vadd.i64        d27,d28
-       vbsl            d30,d19,d18             @ Maj(a,b,c)
-       veor            d16,d26                 @ Sigma0(a)
-       vadd.i64        d20,d27
-       vadd.i64        d30,d27
-       @ vadd.i64      d16,d30
-       bne             .L16_79_neon
-
-        vadd.i64       d16,d30         @ h+=Maj from the past
-       vldmia          r0,{d24-d31}    @ load context to temp
-       vadd.i64        q8,q12          @ vectorized accumulate
-       vadd.i64        q9,q13
-       vadd.i64        q10,q14
-       vadd.i64        q11,q15
-       vstmia          r0,{d16-d23}    @ save context
-       teq             r1,r2
-       sub             r3,#640 @ rewind K512
-       bne             .Loop_neon
-
-       VFP_ABI_POP
-       bx      lr                              @ .word 0xe12fff1e
-.size  sha512_block_data_order_neon,.-sha512_block_data_order_neon
-#endif
-.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro@openssl.org>"
-.align 2
-#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
-.comm  OPENSSL_armcap_P,4,4
-#endif
index 455eb19..db8512d 100644 (file)
@@ -22,8 +22,8 @@
  * strex/ldrex monitor on some implementations. The reason we can use it for
  * atomic_set() is the clrex or dummy strex done on every exception return.
  */
-#define atomic_read(v) READ_ONCE((v)->counter)
-#define atomic_set(v,i)        WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_read(v)    READ_ONCE((v)->counter)
+#define arch_atomic_set(v,i)   WRITE_ONCE(((v)->counter), (i))
 
 #if __LINUX_ARM_ARCH__ >= 6
 
@@ -34,7 +34,7 @@
  */
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -52,7 +52,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return_relaxed(int i, atomic_t *v)     \
+static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v)        \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -73,7 +73,7 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v)    \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v)      \
+static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
 {                                                                      \
        unsigned long tmp;                                              \
        int result, val;                                                \
@@ -93,17 +93,17 @@ static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v)   \
        return result;                                                  \
 }
 
-#define atomic_add_return_relaxed      atomic_add_return_relaxed
-#define atomic_sub_return_relaxed      atomic_sub_return_relaxed
-#define atomic_fetch_add_relaxed       atomic_fetch_add_relaxed
-#define atomic_fetch_sub_relaxed       atomic_fetch_sub_relaxed
+#define arch_atomic_add_return_relaxed         arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed         arch_atomic_sub_return_relaxed
+#define arch_atomic_fetch_add_relaxed          arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed          arch_atomic_fetch_sub_relaxed
 
-#define atomic_fetch_and_relaxed       atomic_fetch_and_relaxed
-#define atomic_fetch_andnot_relaxed    atomic_fetch_andnot_relaxed
-#define atomic_fetch_or_relaxed                atomic_fetch_or_relaxed
-#define atomic_fetch_xor_relaxed       atomic_fetch_xor_relaxed
+#define arch_atomic_fetch_and_relaxed          arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_andnot_relaxed       arch_atomic_fetch_andnot_relaxed
+#define arch_atomic_fetch_or_relaxed           arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed          arch_atomic_fetch_xor_relaxed
 
-static inline int atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new)
+static inline int arch_atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new)
 {
        int oldval;
        unsigned long res;
@@ -123,9 +123,9 @@ static inline int atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new)
 
        return oldval;
 }
-#define atomic_cmpxchg_relaxed         atomic_cmpxchg_relaxed
+#define arch_atomic_cmpxchg_relaxed            arch_atomic_cmpxchg_relaxed
 
-static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int oldval, newval;
        unsigned long tmp;
@@ -151,7 +151,7 @@ static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
 
        return oldval;
 }
-#define atomic_fetch_add_unless                atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless           arch_atomic_fetch_add_unless
 
 #else /* ARM_ARCH_6 */
 
@@ -160,7 +160,7 @@ static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
 #endif
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -170,7 +170,7 @@ static inline void atomic_##op(int i, atomic_t *v)                  \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long flags;                                            \
        int val;                                                        \
@@ -184,7 +184,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned long flags;                                            \
        int val;                                                        \
@@ -197,7 +197,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                     \
        return val;                                                     \
 }
 
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+static inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        int ret;
        unsigned long flags;
@@ -211,7 +211,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
        return ret;
 }
 
-#define atomic_fetch_andnot            atomic_fetch_andnot
+#define arch_atomic_fetch_andnot               arch_atomic_fetch_andnot
 
 #endif /* __LINUX_ARM_ARCH__ */
 
@@ -223,7 +223,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 ATOMIC_OPS(add, +=, add)
 ATOMIC_OPS(sub, -=, sub)
 
-#define atomic_andnot atomic_andnot
+#define arch_atomic_andnot arch_atomic_andnot
 
 #undef ATOMIC_OPS
 #define ATOMIC_OPS(op, c_op, asm_op)                                   \
@@ -240,7 +240,7 @@ ATOMIC_OPS(xor, ^=, eor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
 #ifndef CONFIG_GENERIC_ATOMIC64
 typedef struct {
@@ -250,7 +250,7 @@ typedef struct {
 #define ATOMIC64_INIT(i) { (i) }
 
 #ifdef CONFIG_ARM_LPAE
-static inline s64 atomic64_read(const atomic64_t *v)
+static inline s64 arch_atomic64_read(const atomic64_t *v)
 {
        s64 result;
 
@@ -263,7 +263,7 @@ static inline s64 atomic64_read(const atomic64_t *v)
        return result;
 }
 
-static inline void atomic64_set(atomic64_t *v, s64 i)
+static inline void arch_atomic64_set(atomic64_t *v, s64 i)
 {
        __asm__ __volatile__("@ atomic64_set\n"
 "      strd    %2, %H2, [%1]"
@@ -272,7 +272,7 @@ static inline void atomic64_set(atomic64_t *v, s64 i)
        );
 }
 #else
-static inline s64 atomic64_read(const atomic64_t *v)
+static inline s64 arch_atomic64_read(const atomic64_t *v)
 {
        s64 result;
 
@@ -285,7 +285,7 @@ static inline s64 atomic64_read(const atomic64_t *v)
        return result;
 }
 
-static inline void atomic64_set(atomic64_t *v, s64 i)
+static inline void arch_atomic64_set(atomic64_t *v, s64 i)
 {
        s64 tmp;
 
@@ -302,7 +302,7 @@ static inline void atomic64_set(atomic64_t *v, s64 i)
 #endif
 
 #define ATOMIC64_OP(op, op1, op2)                                      \
-static inline void atomic64_##op(s64 i, atomic64_t *v)                 \
+static inline void arch_atomic64_##op(s64 i, atomic64_t *v)            \
 {                                                                      \
        s64 result;                                                     \
        unsigned long tmp;                                              \
@@ -322,7 +322,7 @@ static inline void atomic64_##op(s64 i, atomic64_t *v)                      \
 
 #define ATOMIC64_OP_RETURN(op, op1, op2)                               \
 static inline s64                                                      \
-atomic64_##op##_return_relaxed(s64 i, atomic64_t *v)                   \
+arch_atomic64_##op##_return_relaxed(s64 i, atomic64_t *v)              \
 {                                                                      \
        s64 result;                                                     \
        unsigned long tmp;                                              \
@@ -345,7 +345,7 @@ atomic64_##op##_return_relaxed(s64 i, atomic64_t *v)                        \
 
 #define ATOMIC64_FETCH_OP(op, op1, op2)                                        \
 static inline s64                                                      \
-atomic64_fetch_##op##_relaxed(s64 i, atomic64_t *v)                    \
+arch_atomic64_fetch_##op##_relaxed(s64 i, atomic64_t *v)               \
 {                                                                      \
        s64 result, val;                                                \
        unsigned long tmp;                                              \
@@ -374,34 +374,34 @@ atomic64_fetch_##op##_relaxed(s64 i, atomic64_t *v)                       \
 ATOMIC64_OPS(add, adds, adc)
 ATOMIC64_OPS(sub, subs, sbc)
 
-#define atomic64_add_return_relaxed    atomic64_add_return_relaxed
-#define atomic64_sub_return_relaxed    atomic64_sub_return_relaxed
-#define atomic64_fetch_add_relaxed     atomic64_fetch_add_relaxed
-#define atomic64_fetch_sub_relaxed     atomic64_fetch_sub_relaxed
+#define arch_atomic64_add_return_relaxed       arch_atomic64_add_return_relaxed
+#define arch_atomic64_sub_return_relaxed       arch_atomic64_sub_return_relaxed
+#define arch_atomic64_fetch_add_relaxed                arch_atomic64_fetch_add_relaxed
+#define arch_atomic64_fetch_sub_relaxed                arch_atomic64_fetch_sub_relaxed
 
 #undef ATOMIC64_OPS
 #define ATOMIC64_OPS(op, op1, op2)                                     \
        ATOMIC64_OP(op, op1, op2)                                       \
        ATOMIC64_FETCH_OP(op, op1, op2)
 
-#define atomic64_andnot atomic64_andnot
+#define arch_atomic64_andnot arch_atomic64_andnot
 
 ATOMIC64_OPS(and, and, and)
 ATOMIC64_OPS(andnot, bic, bic)
 ATOMIC64_OPS(or,  orr, orr)
 ATOMIC64_OPS(xor, eor, eor)
 
-#define atomic64_fetch_and_relaxed     atomic64_fetch_and_relaxed
-#define atomic64_fetch_andnot_relaxed  atomic64_fetch_andnot_relaxed
-#define atomic64_fetch_or_relaxed      atomic64_fetch_or_relaxed
-#define atomic64_fetch_xor_relaxed     atomic64_fetch_xor_relaxed
+#define arch_atomic64_fetch_and_relaxed                arch_atomic64_fetch_and_relaxed
+#define arch_atomic64_fetch_andnot_relaxed     arch_atomic64_fetch_andnot_relaxed
+#define arch_atomic64_fetch_or_relaxed         arch_atomic64_fetch_or_relaxed
+#define arch_atomic64_fetch_xor_relaxed                arch_atomic64_fetch_xor_relaxed
 
 #undef ATOMIC64_OPS
 #undef ATOMIC64_FETCH_OP
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
-static inline s64 atomic64_cmpxchg_relaxed(atomic64_t *ptr, s64 old, s64 new)
+static inline s64 arch_atomic64_cmpxchg_relaxed(atomic64_t *ptr, s64 old, s64 new)
 {
        s64 oldval;
        unsigned long res;
@@ -422,9 +422,9 @@ static inline s64 atomic64_cmpxchg_relaxed(atomic64_t *ptr, s64 old, s64 new)
 
        return oldval;
 }
-#define atomic64_cmpxchg_relaxed       atomic64_cmpxchg_relaxed
+#define arch_atomic64_cmpxchg_relaxed  arch_atomic64_cmpxchg_relaxed
 
-static inline s64 atomic64_xchg_relaxed(atomic64_t *ptr, s64 new)
+static inline s64 arch_atomic64_xchg_relaxed(atomic64_t *ptr, s64 new)
 {
        s64 result;
        unsigned long tmp;
@@ -442,9 +442,9 @@ static inline s64 atomic64_xchg_relaxed(atomic64_t *ptr, s64 new)
 
        return result;
 }
-#define atomic64_xchg_relaxed          atomic64_xchg_relaxed
+#define arch_atomic64_xchg_relaxed             arch_atomic64_xchg_relaxed
 
-static inline s64 atomic64_dec_if_positive(atomic64_t *v)
+static inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
 {
        s64 result;
        unsigned long tmp;
@@ -470,9 +470,9 @@ static inline s64 atomic64_dec_if_positive(atomic64_t *v)
 
        return result;
 }
-#define atomic64_dec_if_positive atomic64_dec_if_positive
+#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
 
-static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+static inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        s64 oldval, newval;
        unsigned long tmp;
@@ -500,7 +500,7 @@ static inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 
        return oldval;
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
 
 #endif /* !CONFIG_GENERIC_ATOMIC64 */
 #endif
index 8b701f8..4dfe538 100644 (file)
@@ -114,7 +114,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
        return ret;
 }
 
-#define xchg_relaxed(ptr, x) ({                                                \
+#define arch_xchg_relaxed(ptr, x) ({                                   \
        (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr),           \
                                   sizeof(*(ptr)));                     \
 })
@@ -128,20 +128,20 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 #error "SMP is not supported on this platform"
 #endif
 
-#define xchg xchg_relaxed
+#define arch_xchg arch_xchg_relaxed
 
 /*
  * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
  * them available.
  */
-#define cmpxchg_local(ptr, o, n) ({                                    \
-       (__typeof(*ptr))__cmpxchg_local_generic((ptr),                  \
+#define arch_cmpxchg_local(ptr, o, n) ({                               \
+       (__typeof(*ptr))__generic_cmpxchg_local((ptr),                  \
                                                (unsigned long)(o),     \
                                                (unsigned long)(n),     \
                                                sizeof(*(ptr)));        \
 })
 
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 
 #include <asm-generic/cmpxchg.h>
 
@@ -207,7 +207,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        return oldval;
 }
 
-#define cmpxchg_relaxed(ptr,o,n) ({                                    \
+#define arch_cmpxchg_relaxed(ptr,o,n) ({                               \
        (__typeof__(*(ptr)))__cmpxchg((ptr),                            \
                                      (unsigned long)(o),               \
                                      (unsigned long)(n),               \
@@ -224,7 +224,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 #ifdef CONFIG_CPU_V6   /* min ARCH == ARMv6 */
        case 1:
        case 2:
-               ret = __cmpxchg_local_generic(ptr, old, new, size);
+               ret = __generic_cmpxchg_local(ptr, old, new, size);
                break;
 #endif
        default:
@@ -234,7 +234,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        return ret;
 }
 
-#define cmpxchg_local(ptr, o, n) ({                                    \
+#define arch_cmpxchg_local(ptr, o, n) ({                               \
        (__typeof(*ptr))__cmpxchg_local((ptr),                          \
                                        (unsigned long)(o),             \
                                        (unsigned long)(n),             \
@@ -266,13 +266,13 @@ static inline unsigned long long __cmpxchg64(unsigned long long *ptr,
        return oldval;
 }
 
-#define cmpxchg64_relaxed(ptr, o, n) ({                                        \
+#define arch_cmpxchg64_relaxed(ptr, o, n) ({                           \
        (__typeof__(*(ptr)))__cmpxchg64((ptr),                          \
                                        (unsigned long long)(o),        \
                                        (unsigned long long)(n));       \
 })
 
-#define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) arch_cmpxchg64_relaxed((ptr), (o), (n))
 
 #endif /* __LINUX_ARM_ARCH__ >= 6 */
 
index bc4ffa7..397be5e 100644 (file)
@@ -50,4 +50,9 @@ extern int arm_cpuidle_suspend(int index);
 
 extern int arm_cpuidle_init(int cpu);
 
+struct arm_cpuidle_irq_context { };
+
+#define arm_cpuidle_save_irq_context(c)                (void)c
+#define arm_cpuidle_restore_irq_context(c)     (void)c
+
 #endif
index 39ff217..6f5d627 100644 (file)
@@ -21,7 +21,7 @@
 #define sync_test_and_clear_bit(nr, p) _test_and_clear_bit(nr, p)
 #define sync_test_and_change_bit(nr, p)        _test_and_change_bit(nr, p)
 #define sync_test_bit(nr, addr)                test_bit(nr, addr)
-#define sync_cmpxchg                   cmpxchg
+#define arch_sync_cmpxchg              arch_cmpxchg
 
 
 #endif
index 698b6f6..20ab1e6 100644 (file)
@@ -63,7 +63,27 @@ int arch_show_interrupts(struct seq_file *p, int prec)
  */
 void handle_IRQ(unsigned int irq, struct pt_regs *regs)
 {
-       __handle_domain_irq(NULL, irq, false, regs);
+       struct pt_regs *old_regs = set_irq_regs(regs);
+       struct irq_desc *desc;
+
+       irq_enter();
+
+       /*
+        * Some hardware gives randomly wrong interrupts.  Rather
+        * than crashing, do something sensible.
+        */
+       if (unlikely(!irq || irq >= nr_irqs))
+               desc = NULL;
+       else
+               desc = irq_to_desc(irq);
+
+       if (likely(desc))
+               handle_irq_desc(desc);
+       else
+               ack_bad_irq(irq);
+
+       irq_exit();
+       set_irq_regs(old_regs);
 }
 
 /*
index 2924d79..eb21904 100644 (file)
@@ -773,10 +773,10 @@ static inline void armv7pmu_write_counter(struct perf_event *event, u64 value)
                pr_err("CPU%u writing wrong counter %d\n",
                        smp_processor_id(), idx);
        } else if (idx == ARMV7_IDX_CYCLE_COUNTER) {
-               asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
+               asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" ((u32)value));
        } else {
                armv7_pmnc_select_counter(idx);
-               asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
+               asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" ((u32)value));
        }
 }
 
index 6324f4d..fc9e8b3 100644 (file)
@@ -288,7 +288,7 @@ unsigned long get_wchan(struct task_struct *p)
        struct stackframe frame;
        unsigned long stack_page;
        int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        frame.fp = thread_saved_fp(p);
index 1a5edf5..73ca779 100644 (file)
@@ -545,9 +545,11 @@ void notrace cpu_init(void)
         * In Thumb-2, msr with an immediate value is not allowed.
         */
 #ifdef CONFIG_THUMB2_KERNEL
-#define PLC    "r"
+#define PLC_l  "l"
+#define PLC_r  "r"
 #else
-#define PLC    "I"
+#define PLC_l  "I"
+#define PLC_r  "I"
 #endif
 
        /*
@@ -569,15 +571,15 @@ void notrace cpu_init(void)
        "msr    cpsr_c, %9"
            :
            : "r" (stk),
-             PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+             PLC_r (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
              "I" (offsetof(struct stack, irq[0])),
-             PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+             PLC_r (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
              "I" (offsetof(struct stack, abt[0])),
-             PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+             PLC_r (PSR_F_BIT | PSR_I_BIT | UND_MODE),
              "I" (offsetof(struct stack, und[0])),
-             PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
+             PLC_r (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
              "I" (offsetof(struct stack, fiq[0])),
-             PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+             PLC_l (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
            : "r14");
 #endif
 }
index 7467924..c7bb168 100644 (file)
@@ -432,7 +432,6 @@ asmlinkage void secondary_start_kernel(void)
 #endif
        pr_debug("CPU%u: Booted secondary processor\n", cpu);
 
-       preempt_disable();
        trace_hardirqs_off();
 
        /*
index 000f672..007a444 100644 (file)
@@ -233,12 +233,38 @@ static struct platform_device *ixp46x_devices[] __initdata = {
 unsigned long ixp4xx_exp_bus_size;
 EXPORT_SYMBOL(ixp4xx_exp_bus_size);
 
+static struct platform_device_info ixp_dev_info __initdata = {
+       .name           = "ixp4xx_crypto",
+       .id             = 0,
+       .dma_mask       = DMA_BIT_MASK(32),
+};
+
+static int __init ixp_crypto_register(void)
+{
+       struct platform_device *pdev;
+
+       if (!(~(*IXP4XX_EXP_CFG2) & (IXP4XX_FEATURE_HASH |
+                               IXP4XX_FEATURE_AES | IXP4XX_FEATURE_DES))) {
+               printk(KERN_ERR "ixp_crypto: No HW crypto available\n");
+               return -ENODEV;
+       }
+
+       pdev = platform_device_register_full(&ixp_dev_info);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
+}
+
 void __init ixp4xx_sys_init(void)
 {
        ixp4xx_exp_bus_size = SZ_16M;
 
        platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));
 
+       if (IS_ENABLED(CONFIG_CRYPTO_DEV_IXP4XX))
+               ixp_crypto_register();
+
        if (cpu_is_ixp46x()) {
                int region;
 
index 43fb941..a56748d 100644 (file)
@@ -6,7 +6,7 @@ config ARCH_ZYNQ
        select ARCH_SUPPORTS_BIG_ENDIAN
        select ARM_AMBA
        select ARM_GIC
-       select ARM_GLOBAL_TIMER if !CPU_FREQ
+       select ARM_GLOBAL_TIMER
        select CADENCE_TTC_TIMER
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
index a965311..27e0af7 100644 (file)
@@ -348,29 +348,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
                        reset_current_kprobe();
                }
                break;
-
-       case KPROBE_HIT_ACTIVE:
-       case KPROBE_HIT_SSDONE:
-               /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
-                       return 1;
-               break;
-
-       default:
-               break;
        }
 
        return 0;
index 9f1d856..dabe9b8 100644 (file)
@@ -1481,12 +1481,6 @@ menu "ARMv8.3 architectural features"
 config ARM64_PTR_AUTH
        bool "Enable support for pointer authentication"
        default y
-       depends on (CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) && AS_HAS_PAC
-       # Modern compilers insert a .note.gnu.property section note for PAC
-       # which is only understood by binutils starting with version 2.33.1.
-       depends on LD_IS_LLD || LD_VERSION >= 23301 || (CC_IS_GCC && GCC_VERSION < 90100)
-       depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE
-       depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
        help
          Pointer authentication (part of the ARMv8.3 Extensions) provides
          instructions for signing and authenticating pointers against secret
@@ -1498,13 +1492,6 @@ config ARM64_PTR_AUTH
          for each process at exec() time, with these keys being
          context-switched along with the process.
 
-         If the compiler supports the -mbranch-protection or
-         -msign-return-address flag (e.g. GCC 7 or later), then this option
-         will also cause the kernel itself to be compiled with return address
-         protection. In this case, and if the target hardware is known to
-         support pointer authentication, then CONFIG_STACKPROTECTOR can be
-         disabled with minimal loss of protection.
-
          The feature is detected at runtime. If the feature is not present in
          hardware it will not be advertised to userspace/KVM guest nor will it
          be enabled.
@@ -1515,6 +1502,24 @@ config ARM64_PTR_AUTH
          but with the feature disabled. On such a system, this option should
          not be selected.
 
+config ARM64_PTR_AUTH_KERNEL
+       bool "Use pointer authentication for kernel"
+       default y
+       depends on ARM64_PTR_AUTH
+       depends on (CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) && AS_HAS_PAC
+       # Modern compilers insert a .note.gnu.property section note for PAC
+       # which is only understood by binutils starting with version 2.33.1.
+       depends on LD_IS_LLD || LD_VERSION >= 23301 || (CC_IS_GCC && GCC_VERSION < 90100)
+       depends on !CC_IS_CLANG || AS_HAS_CFI_NEGATE_RA_STATE
+       depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
+       help
+         If the compiler supports the -mbranch-protection or
+         -msign-return-address flag (e.g. GCC 7 or later), then this option
+         will cause the kernel itself to be compiled with return address
+         protection. In this case, and if the target hardware is known to
+         support pointer authentication, then CONFIG_STACKPROTECTOR can be
+         disabled with minimal loss of protection.
+
          This feature works with FUNCTION_GRAPH_TRACER option only if
          DYNAMIC_FTRACE_WITH_REGS is enabled.
 
@@ -1606,7 +1611,7 @@ config ARM64_BTI_KERNEL
        bool "Use Branch Target Identification for kernel"
        default y
        depends on ARM64_BTI
-       depends on ARM64_PTR_AUTH
+       depends on ARM64_PTR_AUTH_KERNEL
        depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI
        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
        depends on !CC_IS_GCC || GCC_VERSION >= 100100
index b52481f..3b5b1c4 100644 (file)
@@ -70,7 +70,7 @@ endif
 # off, this will be overridden if we are using branch protection.
 branch-prot-flags-y += $(call cc-option,-mbranch-protection=none)
 
-ifeq ($(CONFIG_ARM64_PTR_AUTH),y)
+ifeq ($(CONFIG_ARM64_PTR_AUTH_KERNEL),y)
 branch-prot-flags-$(CONFIG_CC_HAS_SIGN_RETURN_ADDRESS) := -msign-return-address=all
 # We enable additional protection for leaf functions as there is some
 # narrow potential for ROP protection benefits and no substantial
index d0901e6..09a805c 100644 (file)
@@ -68,19 +68,13 @@ CFLAGS_aes-glue-ce.o        := -DUSE_V8_CRYPTO_EXTENSIONS
 $(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE
        $(call if_changed_rule,cc_o_c)
 
-ifdef REGENERATE_ARM64_CRYPTO
 quiet_cmd_perlasm = PERLASM $@
       cmd_perlasm = $(PERL) $(<) void $(@)
 
-$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv8.pl
+$(obj)/%-core.S: $(src)/%-armv8.pl
        $(call cmd,perlasm)
 
-$(src)/sha256-core.S_shipped: $(src)/sha512-armv8.pl
+$(obj)/sha256-core.S: $(src)/sha512-armv8.pl
        $(call cmd,perlasm)
 
-$(src)/sha512-core.S_shipped: $(src)/sha512-armv8.pl
-       $(call cmd,perlasm)
-
-endif
-
 clean-files += poly1305-core.S sha256-core.S sha512-core.S
diff --git a/arch/arm64/crypto/poly1305-core.S_shipped b/arch/arm64/crypto/poly1305-core.S_shipped
deleted file mode 100644 (file)
index fb2822a..0000000
+++ /dev/null
@@ -1,835 +0,0 @@
-#ifndef __KERNEL__
-# include "arm_arch.h"
-.extern        OPENSSL_armcap_P
-#endif
-
-.text
-
-// forward "declarations" are required for Apple
-.globl poly1305_blocks
-.globl poly1305_emit
-
-.globl poly1305_init
-.type  poly1305_init,%function
-.align 5
-poly1305_init:
-       cmp     x1,xzr
-       stp     xzr,xzr,[x0]            // zero hash value
-       stp     xzr,xzr,[x0,#16]        // [along with is_base2_26]
-
-       csel    x0,xzr,x0,eq
-       b.eq    .Lno_key
-
-#ifndef        __KERNEL__
-       adrp    x17,OPENSSL_armcap_P
-       ldr     w17,[x17,#:lo12:OPENSSL_armcap_P]
-#endif
-
-       ldp     x7,x8,[x1]              // load key
-       mov     x9,#0xfffffffc0fffffff
-       movk    x9,#0x0fff,lsl#48
-#ifdef __AARCH64EB__
-       rev     x7,x7                   // flip bytes
-       rev     x8,x8
-#endif
-       and     x7,x7,x9                // &=0ffffffc0fffffff
-       and     x9,x9,#-4
-       and     x8,x8,x9                // &=0ffffffc0ffffffc
-       mov     w9,#-1
-       stp     x7,x8,[x0,#32]  // save key value
-       str     w9,[x0,#48]     // impossible key power value
-
-#ifndef        __KERNEL__
-       tst     w17,#ARMV7_NEON
-
-       adr     x12,.Lpoly1305_blocks
-       adr     x7,.Lpoly1305_blocks_neon
-       adr     x13,.Lpoly1305_emit
-
-       csel    x12,x12,x7,eq
-
-# ifdef        __ILP32__
-       stp     w12,w13,[x2]
-# else
-       stp     x12,x13,[x2]
-# endif
-#endif
-       mov     x0,#1
-.Lno_key:
-       ret
-.size  poly1305_init,.-poly1305_init
-
-.type  poly1305_blocks,%function
-.align 5
-poly1305_blocks:
-.Lpoly1305_blocks:
-       ands    x2,x2,#-16
-       b.eq    .Lno_data
-
-       ldp     x4,x5,[x0]              // load hash value
-       ldp     x6,x17,[x0,#16] // [along with is_base2_26]
-       ldp     x7,x8,[x0,#32]  // load key value
-
-#ifdef __AARCH64EB__
-       lsr     x12,x4,#32
-       mov     w13,w4
-       lsr     x14,x5,#32
-       mov     w15,w5
-       lsr     x16,x6,#32
-#else
-       mov     w12,w4
-       lsr     x13,x4,#32
-       mov     w14,w5
-       lsr     x15,x5,#32
-       mov     w16,w6
-#endif
-
-       add     x12,x12,x13,lsl#26      // base 2^26 -> base 2^64
-       lsr     x13,x14,#12
-       adds    x12,x12,x14,lsl#52
-       add     x13,x13,x15,lsl#14
-       adc     x13,x13,xzr
-       lsr     x14,x16,#24
-       adds    x13,x13,x16,lsl#40
-       adc     x14,x14,xzr
-
-       cmp     x17,#0                  // is_base2_26?
-       add     x9,x8,x8,lsr#2  // s1 = r1 + (r1 >> 2)
-       csel    x4,x4,x12,eq            // choose between radixes
-       csel    x5,x5,x13,eq
-       csel    x6,x6,x14,eq
-
-.Loop:
-       ldp     x10,x11,[x1],#16        // load input
-       sub     x2,x2,#16
-#ifdef __AARCH64EB__
-       rev     x10,x10
-       rev     x11,x11
-#endif
-       adds    x4,x4,x10               // accumulate input
-       adcs    x5,x5,x11
-
-       mul     x12,x4,x7               // h0*r0
-       adc     x6,x6,x3
-       umulh   x13,x4,x7
-
-       mul     x10,x5,x9               // h1*5*r1
-       umulh   x11,x5,x9
-
-       adds    x12,x12,x10
-       mul     x10,x4,x8               // h0*r1
-       adc     x13,x13,x11
-       umulh   x14,x4,x8
-
-       adds    x13,x13,x10
-       mul     x10,x5,x7               // h1*r0
-       adc     x14,x14,xzr
-       umulh   x11,x5,x7
-
-       adds    x13,x13,x10
-       mul     x10,x6,x9               // h2*5*r1
-       adc     x14,x14,x11
-       mul     x11,x6,x7               // h2*r0
-
-       adds    x13,x13,x10
-       adc     x14,x14,x11
-
-       and     x10,x14,#-4             // final reduction
-       and     x6,x14,#3
-       add     x10,x10,x14,lsr#2
-       adds    x4,x12,x10
-       adcs    x5,x13,xzr
-       adc     x6,x6,xzr
-
-       cbnz    x2,.Loop
-
-       stp     x4,x5,[x0]              // store hash value
-       stp     x6,xzr,[x0,#16] // [and clear is_base2_26]
-
-.Lno_data:
-       ret
-.size  poly1305_blocks,.-poly1305_blocks
-
-.type  poly1305_emit,%function
-.align 5
-poly1305_emit:
-.Lpoly1305_emit:
-       ldp     x4,x5,[x0]              // load hash base 2^64
-       ldp     x6,x7,[x0,#16]  // [along with is_base2_26]
-       ldp     x10,x11,[x2]    // load nonce
-
-#ifdef __AARCH64EB__
-       lsr     x12,x4,#32
-       mov     w13,w4
-       lsr     x14,x5,#32
-       mov     w15,w5
-       lsr     x16,x6,#32
-#else
-       mov     w12,w4
-       lsr     x13,x4,#32
-       mov     w14,w5
-       lsr     x15,x5,#32
-       mov     w16,w6
-#endif
-
-       add     x12,x12,x13,lsl#26      // base 2^26 -> base 2^64
-       lsr     x13,x14,#12
-       adds    x12,x12,x14,lsl#52
-       add     x13,x13,x15,lsl#14
-       adc     x13,x13,xzr
-       lsr     x14,x16,#24
-       adds    x13,x13,x16,lsl#40
-       adc     x14,x14,xzr
-
-       cmp     x7,#0                   // is_base2_26?
-       csel    x4,x4,x12,eq            // choose between radixes
-       csel    x5,x5,x13,eq
-       csel    x6,x6,x14,eq
-
-       adds    x12,x4,#5               // compare to modulus
-       adcs    x13,x5,xzr
-       adc     x14,x6,xzr
-
-       tst     x14,#-4                 // see if it's carried/borrowed
-
-       csel    x4,x4,x12,eq
-       csel    x5,x5,x13,eq
-
-#ifdef __AARCH64EB__
-       ror     x10,x10,#32             // flip nonce words
-       ror     x11,x11,#32
-#endif
-       adds    x4,x4,x10               // accumulate nonce
-       adc     x5,x5,x11
-#ifdef __AARCH64EB__
-       rev     x4,x4                   // flip output bytes
-       rev     x5,x5
-#endif
-       stp     x4,x5,[x1]              // write result
-
-       ret
-.size  poly1305_emit,.-poly1305_emit
-.type  poly1305_mult,%function
-.align 5
-poly1305_mult:
-       mul     x12,x4,x7               // h0*r0
-       umulh   x13,x4,x7
-
-       mul     x10,x5,x9               // h1*5*r1
-       umulh   x11,x5,x9
-
-       adds    x12,x12,x10
-       mul     x10,x4,x8               // h0*r1
-       adc     x13,x13,x11
-       umulh   x14,x4,x8
-
-       adds    x13,x13,x10
-       mul     x10,x5,x7               // h1*r0
-       adc     x14,x14,xzr
-       umulh   x11,x5,x7
-
-       adds    x13,x13,x10
-       mul     x10,x6,x9               // h2*5*r1
-       adc     x14,x14,x11
-       mul     x11,x6,x7               // h2*r0
-
-       adds    x13,x13,x10
-       adc     x14,x14,x11
-
-       and     x10,x14,#-4             // final reduction
-       and     x6,x14,#3
-       add     x10,x10,x14,lsr#2
-       adds    x4,x12,x10
-       adcs    x5,x13,xzr
-       adc     x6,x6,xzr
-
-       ret
-.size  poly1305_mult,.-poly1305_mult
-
-.type  poly1305_splat,%function
-.align 4
-poly1305_splat:
-       and     x12,x4,#0x03ffffff      // base 2^64 -> base 2^26
-       ubfx    x13,x4,#26,#26
-       extr    x14,x5,x4,#52
-       and     x14,x14,#0x03ffffff
-       ubfx    x15,x5,#14,#26
-       extr    x16,x6,x5,#40
-
-       str     w12,[x0,#16*0]  // r0
-       add     w12,w13,w13,lsl#2       // r1*5
-       str     w13,[x0,#16*1]  // r1
-       add     w13,w14,w14,lsl#2       // r2*5
-       str     w12,[x0,#16*2]  // s1
-       str     w14,[x0,#16*3]  // r2
-       add     w14,w15,w15,lsl#2       // r3*5
-       str     w13,[x0,#16*4]  // s2
-       str     w15,[x0,#16*5]  // r3
-       add     w15,w16,w16,lsl#2       // r4*5
-       str     w14,[x0,#16*6]  // s3
-       str     w16,[x0,#16*7]  // r4
-       str     w15,[x0,#16*8]  // s4
-
-       ret
-.size  poly1305_splat,.-poly1305_splat
-
-#ifdef __KERNEL__
-.globl poly1305_blocks_neon
-#endif
-.type  poly1305_blocks_neon,%function
-.align 5
-poly1305_blocks_neon:
-.Lpoly1305_blocks_neon:
-       ldr     x17,[x0,#24]
-       cmp     x2,#128
-       b.lo    .Lpoly1305_blocks
-
-       .inst   0xd503233f              // paciasp
-       stp     x29,x30,[sp,#-80]!
-       add     x29,sp,#0
-
-       stp     d8,d9,[sp,#16]          // meet ABI requirements
-       stp     d10,d11,[sp,#32]
-       stp     d12,d13,[sp,#48]
-       stp     d14,d15,[sp,#64]
-
-       cbz     x17,.Lbase2_64_neon
-
-       ldp     w10,w11,[x0]            // load hash value base 2^26
-       ldp     w12,w13,[x0,#8]
-       ldr     w14,[x0,#16]
-
-       tst     x2,#31
-       b.eq    .Leven_neon
-
-       ldp     x7,x8,[x0,#32]  // load key value
-
-       add     x4,x10,x11,lsl#26       // base 2^26 -> base 2^64
-       lsr     x5,x12,#12
-       adds    x4,x4,x12,lsl#52
-       add     x5,x5,x13,lsl#14
-       adc     x5,x5,xzr
-       lsr     x6,x14,#24
-       adds    x5,x5,x14,lsl#40
-       adc     x14,x6,xzr              // can be partially reduced...
-
-       ldp     x12,x13,[x1],#16        // load input
-       sub     x2,x2,#16
-       add     x9,x8,x8,lsr#2  // s1 = r1 + (r1 >> 2)
-
-#ifdef __AARCH64EB__
-       rev     x12,x12
-       rev     x13,x13
-#endif
-       adds    x4,x4,x12               // accumulate input
-       adcs    x5,x5,x13
-       adc     x6,x6,x3
-
-       bl      poly1305_mult
-
-       and     x10,x4,#0x03ffffff      // base 2^64 -> base 2^26
-       ubfx    x11,x4,#26,#26
-       extr    x12,x5,x4,#52
-       and     x12,x12,#0x03ffffff
-       ubfx    x13,x5,#14,#26
-       extr    x14,x6,x5,#40
-
-       b       .Leven_neon
-
-.align 4
-.Lbase2_64_neon:
-       ldp     x7,x8,[x0,#32]  // load key value
-
-       ldp     x4,x5,[x0]              // load hash value base 2^64
-       ldr     x6,[x0,#16]
-
-       tst     x2,#31
-       b.eq    .Linit_neon
-
-       ldp     x12,x13,[x1],#16        // load input
-       sub     x2,x2,#16
-       add     x9,x8,x8,lsr#2  // s1 = r1 + (r1 >> 2)
-#ifdef __AARCH64EB__
-       rev     x12,x12
-       rev     x13,x13
-#endif
-       adds    x4,x4,x12               // accumulate input
-       adcs    x5,x5,x13
-       adc     x6,x6,x3
-
-       bl      poly1305_mult
-
-.Linit_neon:
-       ldr     w17,[x0,#48]            // first table element
-       and     x10,x4,#0x03ffffff      // base 2^64 -> base 2^26
-       ubfx    x11,x4,#26,#26
-       extr    x12,x5,x4,#52
-       and     x12,x12,#0x03ffffff
-       ubfx    x13,x5,#14,#26
-       extr    x14,x6,x5,#40
-
-       cmp     w17,#-1                 // is value impossible?
-       b.ne    .Leven_neon
-
-       fmov    d24,x10
-       fmov    d25,x11
-       fmov    d26,x12
-       fmov    d27,x13
-       fmov    d28,x14
-
-       ////////////////////////////////// initialize r^n table
-       mov     x4,x7                   // r^1
-       add     x9,x8,x8,lsr#2  // s1 = r1 + (r1 >> 2)
-       mov     x5,x8
-       mov     x6,xzr
-       add     x0,x0,#48+12
-       bl      poly1305_splat
-
-       bl      poly1305_mult           // r^2
-       sub     x0,x0,#4
-       bl      poly1305_splat
-
-       bl      poly1305_mult           // r^3
-       sub     x0,x0,#4
-       bl      poly1305_splat
-
-       bl      poly1305_mult           // r^4
-       sub     x0,x0,#4
-       bl      poly1305_splat
-       sub     x0,x0,#48               // restore original x0
-       b       .Ldo_neon
-
-.align 4
-.Leven_neon:
-       fmov    d24,x10
-       fmov    d25,x11
-       fmov    d26,x12
-       fmov    d27,x13
-       fmov    d28,x14
-
-.Ldo_neon:
-       ldp     x8,x12,[x1,#32] // inp[2:3]
-       subs    x2,x2,#64
-       ldp     x9,x13,[x1,#48]
-       add     x16,x1,#96
-       adr     x17,.Lzeros
-
-       lsl     x3,x3,#24
-       add     x15,x0,#48
-
-#ifdef __AARCH64EB__
-       rev     x8,x8
-       rev     x12,x12
-       rev     x9,x9
-       rev     x13,x13
-#endif
-       and     x4,x8,#0x03ffffff       // base 2^64 -> base 2^26
-       and     x5,x9,#0x03ffffff
-       ubfx    x6,x8,#26,#26
-       ubfx    x7,x9,#26,#26
-       add     x4,x4,x5,lsl#32         // bfi  x4,x5,#32,#32
-       extr    x8,x12,x8,#52
-       extr    x9,x13,x9,#52
-       add     x6,x6,x7,lsl#32         // bfi  x6,x7,#32,#32
-       fmov    d14,x4
-       and     x8,x8,#0x03ffffff
-       and     x9,x9,#0x03ffffff
-       ubfx    x10,x12,#14,#26
-       ubfx    x11,x13,#14,#26
-       add     x12,x3,x12,lsr#40
-       add     x13,x3,x13,lsr#40
-       add     x8,x8,x9,lsl#32         // bfi  x8,x9,#32,#32
-       fmov    d15,x6
-       add     x10,x10,x11,lsl#32      // bfi  x10,x11,#32,#32
-       add     x12,x12,x13,lsl#32      // bfi  x12,x13,#32,#32
-       fmov    d16,x8
-       fmov    d17,x10
-       fmov    d18,x12
-
-       ldp     x8,x12,[x1],#16 // inp[0:1]
-       ldp     x9,x13,[x1],#48
-
-       ld1     {v0.4s,v1.4s,v2.4s,v3.4s},[x15],#64
-       ld1     {v4.4s,v5.4s,v6.4s,v7.4s},[x15],#64
-       ld1     {v8.4s},[x15]
-
-#ifdef __AARCH64EB__
-       rev     x8,x8
-       rev     x12,x12
-       rev     x9,x9
-       rev     x13,x13
-#endif
-       and     x4,x8,#0x03ffffff       // base 2^64 -> base 2^26
-       and     x5,x9,#0x03ffffff
-       ubfx    x6,x8,#26,#26
-       ubfx    x7,x9,#26,#26
-       add     x4,x4,x5,lsl#32         // bfi  x4,x5,#32,#32
-       extr    x8,x12,x8,#52
-       extr    x9,x13,x9,#52
-       add     x6,x6,x7,lsl#32         // bfi  x6,x7,#32,#32
-       fmov    d9,x4
-       and     x8,x8,#0x03ffffff
-       and     x9,x9,#0x03ffffff
-       ubfx    x10,x12,#14,#26
-       ubfx    x11,x13,#14,#26
-       add     x12,x3,x12,lsr#40
-       add     x13,x3,x13,lsr#40
-       add     x8,x8,x9,lsl#32         // bfi  x8,x9,#32,#32
-       fmov    d10,x6
-       add     x10,x10,x11,lsl#32      // bfi  x10,x11,#32,#32
-       add     x12,x12,x13,lsl#32      // bfi  x12,x13,#32,#32
-       movi    v31.2d,#-1
-       fmov    d11,x8
-       fmov    d12,x10
-       fmov    d13,x12
-       ushr    v31.2d,v31.2d,#38
-
-       b.ls    .Lskip_loop
-
-.align 4
-.Loop_neon:
-       ////////////////////////////////////////////////////////////////
-       // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
-       // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
-       //   ___________________/
-       // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
-       // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
-       //   ___________________/ ____________________/
-       //
-       // Note that we start with inp[2:3]*r^2. This is because it
-       // doesn't depend on reduction in previous iteration.
-       ////////////////////////////////////////////////////////////////
-       // d4 = h0*r4 + h1*r3   + h2*r2   + h3*r1   + h4*r0
-       // d3 = h0*r3 + h1*r2   + h2*r1   + h3*r0   + h4*5*r4
-       // d2 = h0*r2 + h1*r1   + h2*r0   + h3*5*r4 + h4*5*r3
-       // d1 = h0*r1 + h1*r0   + h2*5*r4 + h3*5*r3 + h4*5*r2
-       // d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
-
-       subs    x2,x2,#64
-       umull   v23.2d,v14.2s,v7.s[2]
-       csel    x16,x17,x16,lo
-       umull   v22.2d,v14.2s,v5.s[2]
-       umull   v21.2d,v14.2s,v3.s[2]
-        ldp    x8,x12,[x16],#16        // inp[2:3] (or zero)
-       umull   v20.2d,v14.2s,v1.s[2]
-        ldp    x9,x13,[x16],#48
-       umull   v19.2d,v14.2s,v0.s[2]
-#ifdef __AARCH64EB__
-        rev    x8,x8
-        rev    x12,x12
-        rev    x9,x9
-        rev    x13,x13
-#endif
-
-       umlal   v23.2d,v15.2s,v5.s[2]
-        and    x4,x8,#0x03ffffff       // base 2^64 -> base 2^26
-       umlal   v22.2d,v15.2s,v3.s[2]
-        and    x5,x9,#0x03ffffff
-       umlal   v21.2d,v15.2s,v1.s[2]
-        ubfx   x6,x8,#26,#26
-       umlal   v20.2d,v15.2s,v0.s[2]
-        ubfx   x7,x9,#26,#26
-       umlal   v19.2d,v15.2s,v8.s[2]
-        add    x4,x4,x5,lsl#32         // bfi  x4,x5,#32,#32
-
-       umlal   v23.2d,v16.2s,v3.s[2]
-        extr   x8,x12,x8,#52
-       umlal   v22.2d,v16.2s,v1.s[2]
-        extr   x9,x13,x9,#52
-       umlal   v21.2d,v16.2s,v0.s[2]
-        add    x6,x6,x7,lsl#32         // bfi  x6,x7,#32,#32
-       umlal   v20.2d,v16.2s,v8.s[2]
-        fmov   d14,x4
-       umlal   v19.2d,v16.2s,v6.s[2]
-        and    x8,x8,#0x03ffffff
-
-       umlal   v23.2d,v17.2s,v1.s[2]
-        and    x9,x9,#0x03ffffff
-       umlal   v22.2d,v17.2s,v0.s[2]
-        ubfx   x10,x12,#14,#26
-       umlal   v21.2d,v17.2s,v8.s[2]
-        ubfx   x11,x13,#14,#26
-       umlal   v20.2d,v17.2s,v6.s[2]
-        add    x8,x8,x9,lsl#32         // bfi  x8,x9,#32,#32
-       umlal   v19.2d,v17.2s,v4.s[2]
-        fmov   d15,x6
-
-       add     v11.2s,v11.2s,v26.2s
-        add    x12,x3,x12,lsr#40
-       umlal   v23.2d,v18.2s,v0.s[2]
-        add    x13,x3,x13,lsr#40
-       umlal   v22.2d,v18.2s,v8.s[2]
-        add    x10,x10,x11,lsl#32      // bfi  x10,x11,#32,#32
-       umlal   v21.2d,v18.2s,v6.s[2]
-        add    x12,x12,x13,lsl#32      // bfi  x12,x13,#32,#32
-       umlal   v20.2d,v18.2s,v4.s[2]
-        fmov   d16,x8
-       umlal   v19.2d,v18.2s,v2.s[2]
-        fmov   d17,x10
-
-       ////////////////////////////////////////////////////////////////
-       // (hash+inp[0:1])*r^4 and accumulate
-
-       add     v9.2s,v9.2s,v24.2s
-        fmov   d18,x12
-       umlal   v22.2d,v11.2s,v1.s[0]
-        ldp    x8,x12,[x1],#16 // inp[0:1]
-       umlal   v19.2d,v11.2s,v6.s[0]
-        ldp    x9,x13,[x1],#48
-       umlal   v23.2d,v11.2s,v3.s[0]
-       umlal   v20.2d,v11.2s,v8.s[0]
-       umlal   v21.2d,v11.2s,v0.s[0]
-#ifdef __AARCH64EB__
-        rev    x8,x8
-        rev    x12,x12
-        rev    x9,x9
-        rev    x13,x13
-#endif
-
-       add     v10.2s,v10.2s,v25.2s
-       umlal   v22.2d,v9.2s,v5.s[0]
-       umlal   v23.2d,v9.2s,v7.s[0]
-        and    x4,x8,#0x03ffffff       // base 2^64 -> base 2^26
-       umlal   v21.2d,v9.2s,v3.s[0]
-        and    x5,x9,#0x03ffffff
-       umlal   v19.2d,v9.2s,v0.s[0]
-        ubfx   x6,x8,#26,#26
-       umlal   v20.2d,v9.2s,v1.s[0]
-        ubfx   x7,x9,#26,#26
-
-       add     v12.2s,v12.2s,v27.2s
-        add    x4,x4,x5,lsl#32         // bfi  x4,x5,#32,#32
-       umlal   v22.2d,v10.2s,v3.s[0]
-        extr   x8,x12,x8,#52
-       umlal   v23.2d,v10.2s,v5.s[0]
-        extr   x9,x13,x9,#52
-       umlal   v19.2d,v10.2s,v8.s[0]
-        add    x6,x6,x7,lsl#32         // bfi  x6,x7,#32,#32
-       umlal   v21.2d,v10.2s,v1.s[0]
-        fmov   d9,x4
-       umlal   v20.2d,v10.2s,v0.s[0]
-        and    x8,x8,#0x03ffffff
-
-       add     v13.2s,v13.2s,v28.2s
-        and    x9,x9,#0x03ffffff
-       umlal   v22.2d,v12.2s,v0.s[0]
-        ubfx   x10,x12,#14,#26
-       umlal   v19.2d,v12.2s,v4.s[0]
-        ubfx   x11,x13,#14,#26
-       umlal   v23.2d,v12.2s,v1.s[0]
-        add    x8,x8,x9,lsl#32         // bfi  x8,x9,#32,#32
-       umlal   v20.2d,v12.2s,v6.s[0]
-        fmov   d10,x6
-       umlal   v21.2d,v12.2s,v8.s[0]
-        add    x12,x3,x12,lsr#40
-
-       umlal   v22.2d,v13.2s,v8.s[0]
-        add    x13,x3,x13,lsr#40
-       umlal   v19.2d,v13.2s,v2.s[0]
-        add    x10,x10,x11,lsl#32      // bfi  x10,x11,#32,#32
-       umlal   v23.2d,v13.2s,v0.s[0]
-        add    x12,x12,x13,lsl#32      // bfi  x12,x13,#32,#32
-       umlal   v20.2d,v13.2s,v4.s[0]
-        fmov   d11,x8
-       umlal   v21.2d,v13.2s,v6.s[0]
-        fmov   d12,x10
-        fmov   d13,x12
-
-       /////////////////////////////////////////////////////////////////
-       // lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
-       // and P. Schwabe
-       //
-       // [see discussion in poly1305-armv4 module]
-
-       ushr    v29.2d,v22.2d,#26
-       xtn     v27.2s,v22.2d
-        ushr   v30.2d,v19.2d,#26
-        and    v19.16b,v19.16b,v31.16b
-       add     v23.2d,v23.2d,v29.2d    // h3 -> h4
-       bic     v27.2s,#0xfc,lsl#24     // &=0x03ffffff
-        add    v20.2d,v20.2d,v30.2d    // h0 -> h1
-
-       ushr    v29.2d,v23.2d,#26
-       xtn     v28.2s,v23.2d
-        ushr   v30.2d,v20.2d,#26
-        xtn    v25.2s,v20.2d
-       bic     v28.2s,#0xfc,lsl#24
-        add    v21.2d,v21.2d,v30.2d    // h1 -> h2
-
-       add     v19.2d,v19.2d,v29.2d
-       shl     v29.2d,v29.2d,#2
-        shrn   v30.2s,v21.2d,#26
-        xtn    v26.2s,v21.2d
-       add     v19.2d,v19.2d,v29.2d    // h4 -> h0
-        bic    v25.2s,#0xfc,lsl#24
-        add    v27.2s,v27.2s,v30.2s            // h2 -> h3
-        bic    v26.2s,#0xfc,lsl#24
-
-       shrn    v29.2s,v19.2d,#26
-       xtn     v24.2s,v19.2d
-        ushr   v30.2s,v27.2s,#26
-        bic    v27.2s,#0xfc,lsl#24
-        bic    v24.2s,#0xfc,lsl#24
-       add     v25.2s,v25.2s,v29.2s            // h0 -> h1
-        add    v28.2s,v28.2s,v30.2s            // h3 -> h4
-
-       b.hi    .Loop_neon
-
-.Lskip_loop:
-       dup     v16.2d,v16.d[0]
-       add     v11.2s,v11.2s,v26.2s
-
-       ////////////////////////////////////////////////////////////////
-       // multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
-
-       adds    x2,x2,#32
-       b.ne    .Long_tail
-
-       dup     v16.2d,v11.d[0]
-       add     v14.2s,v9.2s,v24.2s
-       add     v17.2s,v12.2s,v27.2s
-       add     v15.2s,v10.2s,v25.2s
-       add     v18.2s,v13.2s,v28.2s
-
-.Long_tail:
-       dup     v14.2d,v14.d[0]
-       umull2  v19.2d,v16.4s,v6.4s
-       umull2  v22.2d,v16.4s,v1.4s
-       umull2  v23.2d,v16.4s,v3.4s
-       umull2  v21.2d,v16.4s,v0.4s
-       umull2  v20.2d,v16.4s,v8.4s
-
-       dup     v15.2d,v15.d[0]
-       umlal2  v19.2d,v14.4s,v0.4s
-       umlal2  v21.2d,v14.4s,v3.4s
-       umlal2  v22.2d,v14.4s,v5.4s
-       umlal2  v23.2d,v14.4s,v7.4s
-       umlal2  v20.2d,v14.4s,v1.4s
-
-       dup     v17.2d,v17.d[0]
-       umlal2  v19.2d,v15.4s,v8.4s
-       umlal2  v22.2d,v15.4s,v3.4s
-       umlal2  v21.2d,v15.4s,v1.4s
-       umlal2  v23.2d,v15.4s,v5.4s
-       umlal2  v20.2d,v15.4s,v0.4s
-
-       dup     v18.2d,v18.d[0]
-       umlal2  v22.2d,v17.4s,v0.4s
-       umlal2  v23.2d,v17.4s,v1.4s
-       umlal2  v19.2d,v17.4s,v4.4s
-       umlal2  v20.2d,v17.4s,v6.4s
-       umlal2  v21.2d,v17.4s,v8.4s
-
-       umlal2  v22.2d,v18.4s,v8.4s
-       umlal2  v19.2d,v18.4s,v2.4s
-       umlal2  v23.2d,v18.4s,v0.4s
-       umlal2  v20.2d,v18.4s,v4.4s
-       umlal2  v21.2d,v18.4s,v6.4s
-
-       b.eq    .Lshort_tail
-
-       ////////////////////////////////////////////////////////////////
-       // (hash+inp[0:1])*r^4:r^3 and accumulate
-
-       add     v9.2s,v9.2s,v24.2s
-       umlal   v22.2d,v11.2s,v1.2s
-       umlal   v19.2d,v11.2s,v6.2s
-       umlal   v23.2d,v11.2s,v3.2s
-       umlal   v20.2d,v11.2s,v8.2s
-       umlal   v21.2d,v11.2s,v0.2s
-
-       add     v10.2s,v10.2s,v25.2s
-       umlal   v22.2d,v9.2s,v5.2s
-       umlal   v19.2d,v9.2s,v0.2s
-       umlal   v23.2d,v9.2s,v7.2s
-       umlal   v20.2d,v9.2s,v1.2s
-       umlal   v21.2d,v9.2s,v3.2s
-
-       add     v12.2s,v12.2s,v27.2s
-       umlal   v22.2d,v10.2s,v3.2s
-       umlal   v19.2d,v10.2s,v8.2s
-       umlal   v23.2d,v10.2s,v5.2s
-       umlal   v20.2d,v10.2s,v0.2s
-       umlal   v21.2d,v10.2s,v1.2s
-
-       add     v13.2s,v13.2s,v28.2s
-       umlal   v22.2d,v12.2s,v0.2s
-       umlal   v19.2d,v12.2s,v4.2s
-       umlal   v23.2d,v12.2s,v1.2s
-       umlal   v20.2d,v12.2s,v6.2s
-       umlal   v21.2d,v12.2s,v8.2s
-
-       umlal   v22.2d,v13.2s,v8.2s
-       umlal   v19.2d,v13.2s,v2.2s
-       umlal   v23.2d,v13.2s,v0.2s
-       umlal   v20.2d,v13.2s,v4.2s
-       umlal   v21.2d,v13.2s,v6.2s
-
-.Lshort_tail:
-       ////////////////////////////////////////////////////////////////
-       // horizontal add
-
-       addp    v22.2d,v22.2d,v22.2d
-        ldp    d8,d9,[sp,#16]          // meet ABI requirements
-       addp    v19.2d,v19.2d,v19.2d
-        ldp    d10,d11,[sp,#32]
-       addp    v23.2d,v23.2d,v23.2d
-        ldp    d12,d13,[sp,#48]
-       addp    v20.2d,v20.2d,v20.2d
-        ldp    d14,d15,[sp,#64]
-       addp    v21.2d,v21.2d,v21.2d
-        ldr    x30,[sp,#8]
-
-       ////////////////////////////////////////////////////////////////
-       // lazy reduction, but without narrowing
-
-       ushr    v29.2d,v22.2d,#26
-       and     v22.16b,v22.16b,v31.16b
-        ushr   v30.2d,v19.2d,#26
-        and    v19.16b,v19.16b,v31.16b
-
-       add     v23.2d,v23.2d,v29.2d    // h3 -> h4
-        add    v20.2d,v20.2d,v30.2d    // h0 -> h1
-
-       ushr    v29.2d,v23.2d,#26
-       and     v23.16b,v23.16b,v31.16b
-        ushr   v30.2d,v20.2d,#26
-        and    v20.16b,v20.16b,v31.16b
-        add    v21.2d,v21.2d,v30.2d    // h1 -> h2
-
-       add     v19.2d,v19.2d,v29.2d
-       shl     v29.2d,v29.2d,#2
-        ushr   v30.2d,v21.2d,#26
-        and    v21.16b,v21.16b,v31.16b
-       add     v19.2d,v19.2d,v29.2d    // h4 -> h0
-        add    v22.2d,v22.2d,v30.2d    // h2 -> h3
-
-       ushr    v29.2d,v19.2d,#26
-       and     v19.16b,v19.16b,v31.16b
-        ushr   v30.2d,v22.2d,#26
-        and    v22.16b,v22.16b,v31.16b
-       add     v20.2d,v20.2d,v29.2d    // h0 -> h1
-        add    v23.2d,v23.2d,v30.2d    // h3 -> h4
-
-       ////////////////////////////////////////////////////////////////
-       // write the result, can be partially reduced
-
-       st4     {v19.s,v20.s,v21.s,v22.s}[0],[x0],#16
-       mov     x4,#1
-       st1     {v23.s}[0],[x0]
-       str     x4,[x0,#8]              // set is_base2_26
-
-       ldr     x29,[sp],#80
-        .inst  0xd50323bf              // autiasp
-       ret
-.size  poly1305_blocks_neon,.-poly1305_blocks_neon
-
-.align 5
-.Lzeros:
-.long  0,0,0,0,0,0,0,0
-.asciz "Poly1305 for ARMv8, CRYPTOGAMS by @dot-asm"
-.align 2
-#if !defined(__KERNEL__) && !defined(_WIN64)
-.comm  OPENSSL_armcap_P,4,4
-.hidden        OPENSSL_armcap_P
-#endif
diff --git a/arch/arm64/crypto/sha256-core.S_shipped b/arch/arm64/crypto/sha256-core.S_shipped
deleted file mode 100644 (file)
index 7c7ce2e..0000000
+++ /dev/null
@@ -1,2069 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-// This code is taken from the OpenSSL project but the author (Andy Polyakov)
-// has relicensed it under the GPLv2. Therefore 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.
-//
-// The original headers, including the original license headers, are
-// included below for completeness.
-
-// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
-//
-// Licensed under the OpenSSL license (the "License").  You may not use
-// this file except in compliance with the License.  You can obtain a copy
-// in the file LICENSE in the source distribution or at
-// https://www.openssl.org/source/license.html
-
-// ====================================================================
-// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
-// project. The module is, however, dual licensed under OpenSSL and
-// CRYPTOGAMS licenses depending on where you obtain it. For further
-// details see http://www.openssl.org/~appro/cryptogams/.
-// ====================================================================
-//
-// SHA256/512 for ARMv8.
-//
-// Performance in cycles per processed byte and improvement coefficient
-// over code generated with "default" compiler:
-//
-//             SHA256-hw       SHA256(*)       SHA512
-// Apple A7    1.97            10.5 (+33%)     6.73 (-1%(**))
-// Cortex-A53  2.38            15.5 (+115%)    10.0 (+150%(***))
-// Cortex-A57  2.31            11.6 (+86%)     7.51 (+260%(***))
-// Denver      2.01            10.5 (+26%)     6.70 (+8%)
-// X-Gene                      20.0 (+100%)    12.8 (+300%(***))
-// Mongoose    2.36            13.0 (+50%)     8.36 (+33%)
-//
-// (*) Software SHA256 results are of lesser relevance, presented
-//     mostly for informational purposes.
-// (**)        The result is a trade-off: it's possible to improve it by
-//     10% (or by 1 cycle per round), but at the cost of 20% loss
-//     on Cortex-A53 (or by 4 cycles per round).
-// (***)       Super-impressive coefficients over gcc-generated code are
-//     indication of some compiler "pathology", most notably code
-//     generated with -mgeneral-regs-only is significanty faster
-//     and the gap is only 40-90%.
-//
-// October 2016.
-//
-// Originally it was reckoned that it makes no sense to implement NEON
-// version of SHA256 for 64-bit processors. This is because performance
-// improvement on most wide-spread Cortex-A5x processors was observed
-// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
-// observed that 32-bit NEON SHA256 performs significantly better than
-// 64-bit scalar version on *some* of the more recent processors. As
-// result 64-bit NEON version of SHA256 was added to provide best
-// all-round performance. For example it executes ~30% faster on X-Gene
-// and Mongoose. [For reference, NEON version of SHA512 is bound to
-// deliver much less improvement, likely *negative* on Cortex-A5x.
-// Which is why NEON support is limited to SHA256.]
-
-#ifndef        __KERNEL__
-# include "arm_arch.h"
-#endif
-
-.text
-
-.extern        OPENSSL_armcap_P
-.globl sha256_block_data_order
-.type  sha256_block_data_order,%function
-.align 6
-sha256_block_data_order:
-#ifndef        __KERNEL__
-# ifdef        __ILP32__
-       ldrsw   x16,.LOPENSSL_armcap_P
-# else
-       ldr     x16,.LOPENSSL_armcap_P
-# endif
-       adr     x17,.LOPENSSL_armcap_P
-       add     x16,x16,x17
-       ldr     w16,[x16]
-       tst     w16,#ARMV8_SHA256
-       b.ne    .Lv8_entry
-       tst     w16,#ARMV7_NEON
-       b.ne    .Lneon_entry
-#endif
-       stp     x29,x30,[sp,#-128]!
-       add     x29,sp,#0
-
-       stp     x19,x20,[sp,#16]
-       stp     x21,x22,[sp,#32]
-       stp     x23,x24,[sp,#48]
-       stp     x25,x26,[sp,#64]
-       stp     x27,x28,[sp,#80]
-       sub     sp,sp,#4*4
-
-       ldp     w20,w21,[x0]                            // load context
-       ldp     w22,w23,[x0,#2*4]
-       ldp     w24,w25,[x0,#4*4]
-       add     x2,x1,x2,lsl#6  // end of input
-       ldp     w26,w27,[x0,#6*4]
-       adr     x30,.LK256
-       stp     x0,x2,[x29,#96]
-
-.Loop:
-       ldp     w3,w4,[x1],#2*4
-       ldr     w19,[x30],#4                    // *K++
-       eor     w28,w21,w22                             // magic seed
-       str     x1,[x29,#112]
-#ifndef        __AARCH64EB__
-       rev     w3,w3                   // 0
-#endif
-       ror     w16,w24,#6
-       add     w27,w27,w19                     // h+=K[i]
-       eor     w6,w24,w24,ror#14
-       and     w17,w25,w24
-       bic     w19,w26,w24
-       add     w27,w27,w3                      // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w20,w21                     // a^b, b^c in next round
-       eor     w16,w16,w6,ror#11       // Sigma1(e)
-       ror     w6,w20,#2
-       add     w27,w27,w17                     // h+=Ch(e,f,g)
-       eor     w17,w20,w20,ror#9
-       add     w27,w27,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w23,w23,w27                     // d+=h
-       eor     w28,w28,w21                     // Maj(a,b,c)
-       eor     w17,w6,w17,ror#13       // Sigma0(a)
-       add     w27,w27,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w27,w27,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w4,w4                   // 1
-#endif
-       ldp     w5,w6,[x1],#2*4
-       add     w27,w27,w17                     // h+=Sigma0(a)
-       ror     w16,w23,#6
-       add     w26,w26,w28                     // h+=K[i]
-       eor     w7,w23,w23,ror#14
-       and     w17,w24,w23
-       bic     w28,w25,w23
-       add     w26,w26,w4                      // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w27,w20                     // a^b, b^c in next round
-       eor     w16,w16,w7,ror#11       // Sigma1(e)
-       ror     w7,w27,#2
-       add     w26,w26,w17                     // h+=Ch(e,f,g)
-       eor     w17,w27,w27,ror#9
-       add     w26,w26,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w22,w22,w26                     // d+=h
-       eor     w19,w19,w20                     // Maj(a,b,c)
-       eor     w17,w7,w17,ror#13       // Sigma0(a)
-       add     w26,w26,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w26,w26,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w5,w5                   // 2
-#endif
-       add     w26,w26,w17                     // h+=Sigma0(a)
-       ror     w16,w22,#6
-       add     w25,w25,w19                     // h+=K[i]
-       eor     w8,w22,w22,ror#14
-       and     w17,w23,w22
-       bic     w19,w24,w22
-       add     w25,w25,w5                      // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w26,w27                     // a^b, b^c in next round
-       eor     w16,w16,w8,ror#11       // Sigma1(e)
-       ror     w8,w26,#2
-       add     w25,w25,w17                     // h+=Ch(e,f,g)
-       eor     w17,w26,w26,ror#9
-       add     w25,w25,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w21,w21,w25                     // d+=h
-       eor     w28,w28,w27                     // Maj(a,b,c)
-       eor     w17,w8,w17,ror#13       // Sigma0(a)
-       add     w25,w25,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w25,w25,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w6,w6                   // 3
-#endif
-       ldp     w7,w8,[x1],#2*4
-       add     w25,w25,w17                     // h+=Sigma0(a)
-       ror     w16,w21,#6
-       add     w24,w24,w28                     // h+=K[i]
-       eor     w9,w21,w21,ror#14
-       and     w17,w22,w21
-       bic     w28,w23,w21
-       add     w24,w24,w6                      // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w25,w26                     // a^b, b^c in next round
-       eor     w16,w16,w9,ror#11       // Sigma1(e)
-       ror     w9,w25,#2
-       add     w24,w24,w17                     // h+=Ch(e,f,g)
-       eor     w17,w25,w25,ror#9
-       add     w24,w24,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w20,w20,w24                     // d+=h
-       eor     w19,w19,w26                     // Maj(a,b,c)
-       eor     w17,w9,w17,ror#13       // Sigma0(a)
-       add     w24,w24,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w24,w24,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w7,w7                   // 4
-#endif
-       add     w24,w24,w17                     // h+=Sigma0(a)
-       ror     w16,w20,#6
-       add     w23,w23,w19                     // h+=K[i]
-       eor     w10,w20,w20,ror#14
-       and     w17,w21,w20
-       bic     w19,w22,w20
-       add     w23,w23,w7                      // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w24,w25                     // a^b, b^c in next round
-       eor     w16,w16,w10,ror#11      // Sigma1(e)
-       ror     w10,w24,#2
-       add     w23,w23,w17                     // h+=Ch(e,f,g)
-       eor     w17,w24,w24,ror#9
-       add     w23,w23,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w27,w27,w23                     // d+=h
-       eor     w28,w28,w25                     // Maj(a,b,c)
-       eor     w17,w10,w17,ror#13      // Sigma0(a)
-       add     w23,w23,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w23,w23,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w8,w8                   // 5
-#endif
-       ldp     w9,w10,[x1],#2*4
-       add     w23,w23,w17                     // h+=Sigma0(a)
-       ror     w16,w27,#6
-       add     w22,w22,w28                     // h+=K[i]
-       eor     w11,w27,w27,ror#14
-       and     w17,w20,w27
-       bic     w28,w21,w27
-       add     w22,w22,w8                      // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w23,w24                     // a^b, b^c in next round
-       eor     w16,w16,w11,ror#11      // Sigma1(e)
-       ror     w11,w23,#2
-       add     w22,w22,w17                     // h+=Ch(e,f,g)
-       eor     w17,w23,w23,ror#9
-       add     w22,w22,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w26,w26,w22                     // d+=h
-       eor     w19,w19,w24                     // Maj(a,b,c)
-       eor     w17,w11,w17,ror#13      // Sigma0(a)
-       add     w22,w22,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w22,w22,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w9,w9                   // 6
-#endif
-       add     w22,w22,w17                     // h+=Sigma0(a)
-       ror     w16,w26,#6
-       add     w21,w21,w19                     // h+=K[i]
-       eor     w12,w26,w26,ror#14
-       and     w17,w27,w26
-       bic     w19,w20,w26
-       add     w21,w21,w9                      // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w22,w23                     // a^b, b^c in next round
-       eor     w16,w16,w12,ror#11      // Sigma1(e)
-       ror     w12,w22,#2
-       add     w21,w21,w17                     // h+=Ch(e,f,g)
-       eor     w17,w22,w22,ror#9
-       add     w21,w21,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w25,w25,w21                     // d+=h
-       eor     w28,w28,w23                     // Maj(a,b,c)
-       eor     w17,w12,w17,ror#13      // Sigma0(a)
-       add     w21,w21,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w21,w21,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w10,w10                 // 7
-#endif
-       ldp     w11,w12,[x1],#2*4
-       add     w21,w21,w17                     // h+=Sigma0(a)
-       ror     w16,w25,#6
-       add     w20,w20,w28                     // h+=K[i]
-       eor     w13,w25,w25,ror#14
-       and     w17,w26,w25
-       bic     w28,w27,w25
-       add     w20,w20,w10                     // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w21,w22                     // a^b, b^c in next round
-       eor     w16,w16,w13,ror#11      // Sigma1(e)
-       ror     w13,w21,#2
-       add     w20,w20,w17                     // h+=Ch(e,f,g)
-       eor     w17,w21,w21,ror#9
-       add     w20,w20,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w24,w24,w20                     // d+=h
-       eor     w19,w19,w22                     // Maj(a,b,c)
-       eor     w17,w13,w17,ror#13      // Sigma0(a)
-       add     w20,w20,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w20,w20,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w11,w11                 // 8
-#endif
-       add     w20,w20,w17                     // h+=Sigma0(a)
-       ror     w16,w24,#6
-       add     w27,w27,w19                     // h+=K[i]
-       eor     w14,w24,w24,ror#14
-       and     w17,w25,w24
-       bic     w19,w26,w24
-       add     w27,w27,w11                     // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w20,w21                     // a^b, b^c in next round
-       eor     w16,w16,w14,ror#11      // Sigma1(e)
-       ror     w14,w20,#2
-       add     w27,w27,w17                     // h+=Ch(e,f,g)
-       eor     w17,w20,w20,ror#9
-       add     w27,w27,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w23,w23,w27                     // d+=h
-       eor     w28,w28,w21                     // Maj(a,b,c)
-       eor     w17,w14,w17,ror#13      // Sigma0(a)
-       add     w27,w27,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w27,w27,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w12,w12                 // 9
-#endif
-       ldp     w13,w14,[x1],#2*4
-       add     w27,w27,w17                     // h+=Sigma0(a)
-       ror     w16,w23,#6
-       add     w26,w26,w28                     // h+=K[i]
-       eor     w15,w23,w23,ror#14
-       and     w17,w24,w23
-       bic     w28,w25,w23
-       add     w26,w26,w12                     // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w27,w20                     // a^b, b^c in next round
-       eor     w16,w16,w15,ror#11      // Sigma1(e)
-       ror     w15,w27,#2
-       add     w26,w26,w17                     // h+=Ch(e,f,g)
-       eor     w17,w27,w27,ror#9
-       add     w26,w26,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w22,w22,w26                     // d+=h
-       eor     w19,w19,w20                     // Maj(a,b,c)
-       eor     w17,w15,w17,ror#13      // Sigma0(a)
-       add     w26,w26,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w26,w26,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w13,w13                 // 10
-#endif
-       add     w26,w26,w17                     // h+=Sigma0(a)
-       ror     w16,w22,#6
-       add     w25,w25,w19                     // h+=K[i]
-       eor     w0,w22,w22,ror#14
-       and     w17,w23,w22
-       bic     w19,w24,w22
-       add     w25,w25,w13                     // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w26,w27                     // a^b, b^c in next round
-       eor     w16,w16,w0,ror#11       // Sigma1(e)
-       ror     w0,w26,#2
-       add     w25,w25,w17                     // h+=Ch(e,f,g)
-       eor     w17,w26,w26,ror#9
-       add     w25,w25,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w21,w21,w25                     // d+=h
-       eor     w28,w28,w27                     // Maj(a,b,c)
-       eor     w17,w0,w17,ror#13       // Sigma0(a)
-       add     w25,w25,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w25,w25,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w14,w14                 // 11
-#endif
-       ldp     w15,w0,[x1],#2*4
-       add     w25,w25,w17                     // h+=Sigma0(a)
-       str     w6,[sp,#12]
-       ror     w16,w21,#6
-       add     w24,w24,w28                     // h+=K[i]
-       eor     w6,w21,w21,ror#14
-       and     w17,w22,w21
-       bic     w28,w23,w21
-       add     w24,w24,w14                     // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w25,w26                     // a^b, b^c in next round
-       eor     w16,w16,w6,ror#11       // Sigma1(e)
-       ror     w6,w25,#2
-       add     w24,w24,w17                     // h+=Ch(e,f,g)
-       eor     w17,w25,w25,ror#9
-       add     w24,w24,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w20,w20,w24                     // d+=h
-       eor     w19,w19,w26                     // Maj(a,b,c)
-       eor     w17,w6,w17,ror#13       // Sigma0(a)
-       add     w24,w24,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w24,w24,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w15,w15                 // 12
-#endif
-       add     w24,w24,w17                     // h+=Sigma0(a)
-       str     w7,[sp,#0]
-       ror     w16,w20,#6
-       add     w23,w23,w19                     // h+=K[i]
-       eor     w7,w20,w20,ror#14
-       and     w17,w21,w20
-       bic     w19,w22,w20
-       add     w23,w23,w15                     // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w24,w25                     // a^b, b^c in next round
-       eor     w16,w16,w7,ror#11       // Sigma1(e)
-       ror     w7,w24,#2
-       add     w23,w23,w17                     // h+=Ch(e,f,g)
-       eor     w17,w24,w24,ror#9
-       add     w23,w23,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w27,w27,w23                     // d+=h
-       eor     w28,w28,w25                     // Maj(a,b,c)
-       eor     w17,w7,w17,ror#13       // Sigma0(a)
-       add     w23,w23,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w23,w23,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w0,w0                   // 13
-#endif
-       ldp     w1,w2,[x1]
-       add     w23,w23,w17                     // h+=Sigma0(a)
-       str     w8,[sp,#4]
-       ror     w16,w27,#6
-       add     w22,w22,w28                     // h+=K[i]
-       eor     w8,w27,w27,ror#14
-       and     w17,w20,w27
-       bic     w28,w21,w27
-       add     w22,w22,w0                      // h+=X[i]
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w23,w24                     // a^b, b^c in next round
-       eor     w16,w16,w8,ror#11       // Sigma1(e)
-       ror     w8,w23,#2
-       add     w22,w22,w17                     // h+=Ch(e,f,g)
-       eor     w17,w23,w23,ror#9
-       add     w22,w22,w16                     // h+=Sigma1(e)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       add     w26,w26,w22                     // d+=h
-       eor     w19,w19,w24                     // Maj(a,b,c)
-       eor     w17,w8,w17,ror#13       // Sigma0(a)
-       add     w22,w22,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       //add   w22,w22,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w1,w1                   // 14
-#endif
-       ldr     w6,[sp,#12]
-       add     w22,w22,w17                     // h+=Sigma0(a)
-       str     w9,[sp,#8]
-       ror     w16,w26,#6
-       add     w21,w21,w19                     // h+=K[i]
-       eor     w9,w26,w26,ror#14
-       and     w17,w27,w26
-       bic     w19,w20,w26
-       add     w21,w21,w1                      // h+=X[i]
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w22,w23                     // a^b, b^c in next round
-       eor     w16,w16,w9,ror#11       // Sigma1(e)
-       ror     w9,w22,#2
-       add     w21,w21,w17                     // h+=Ch(e,f,g)
-       eor     w17,w22,w22,ror#9
-       add     w21,w21,w16                     // h+=Sigma1(e)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       add     w25,w25,w21                     // d+=h
-       eor     w28,w28,w23                     // Maj(a,b,c)
-       eor     w17,w9,w17,ror#13       // Sigma0(a)
-       add     w21,w21,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       //add   w21,w21,w17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     w2,w2                   // 15
-#endif
-       ldr     w7,[sp,#0]
-       add     w21,w21,w17                     // h+=Sigma0(a)
-       str     w10,[sp,#12]
-       ror     w16,w25,#6
-       add     w20,w20,w28                     // h+=K[i]
-       ror     w9,w4,#7
-       and     w17,w26,w25
-       ror     w8,w1,#17
-       bic     w28,w27,w25
-       ror     w10,w21,#2
-       add     w20,w20,w2                      // h+=X[i]
-       eor     w16,w16,w25,ror#11
-       eor     w9,w9,w4,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w21,w22                     // a^b, b^c in next round
-       eor     w16,w16,w25,ror#25      // Sigma1(e)
-       eor     w10,w10,w21,ror#13
-       add     w20,w20,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w8,w8,w1,ror#19
-       eor     w9,w9,w4,lsr#3  // sigma0(X[i+1])
-       add     w20,w20,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w22                     // Maj(a,b,c)
-       eor     w17,w10,w21,ror#22      // Sigma0(a)
-       eor     w8,w8,w1,lsr#10 // sigma1(X[i+14])
-       add     w3,w3,w12
-       add     w24,w24,w20                     // d+=h
-       add     w20,w20,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w3,w3,w9
-       add     w20,w20,w17                     // h+=Sigma0(a)
-       add     w3,w3,w8
-.Loop_16_xx:
-       ldr     w8,[sp,#4]
-       str     w11,[sp,#0]
-       ror     w16,w24,#6
-       add     w27,w27,w19                     // h+=K[i]
-       ror     w10,w5,#7
-       and     w17,w25,w24
-       ror     w9,w2,#17
-       bic     w19,w26,w24
-       ror     w11,w20,#2
-       add     w27,w27,w3                      // h+=X[i]
-       eor     w16,w16,w24,ror#11
-       eor     w10,w10,w5,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w20,w21                     // a^b, b^c in next round
-       eor     w16,w16,w24,ror#25      // Sigma1(e)
-       eor     w11,w11,w20,ror#13
-       add     w27,w27,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w9,w9,w2,ror#19
-       eor     w10,w10,w5,lsr#3        // sigma0(X[i+1])
-       add     w27,w27,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w21                     // Maj(a,b,c)
-       eor     w17,w11,w20,ror#22      // Sigma0(a)
-       eor     w9,w9,w2,lsr#10 // sigma1(X[i+14])
-       add     w4,w4,w13
-       add     w23,w23,w27                     // d+=h
-       add     w27,w27,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w4,w4,w10
-       add     w27,w27,w17                     // h+=Sigma0(a)
-       add     w4,w4,w9
-       ldr     w9,[sp,#8]
-       str     w12,[sp,#4]
-       ror     w16,w23,#6
-       add     w26,w26,w28                     // h+=K[i]
-       ror     w11,w6,#7
-       and     w17,w24,w23
-       ror     w10,w3,#17
-       bic     w28,w25,w23
-       ror     w12,w27,#2
-       add     w26,w26,w4                      // h+=X[i]
-       eor     w16,w16,w23,ror#11
-       eor     w11,w11,w6,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w27,w20                     // a^b, b^c in next round
-       eor     w16,w16,w23,ror#25      // Sigma1(e)
-       eor     w12,w12,w27,ror#13
-       add     w26,w26,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w10,w10,w3,ror#19
-       eor     w11,w11,w6,lsr#3        // sigma0(X[i+1])
-       add     w26,w26,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w20                     // Maj(a,b,c)
-       eor     w17,w12,w27,ror#22      // Sigma0(a)
-       eor     w10,w10,w3,lsr#10       // sigma1(X[i+14])
-       add     w5,w5,w14
-       add     w22,w22,w26                     // d+=h
-       add     w26,w26,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w5,w5,w11
-       add     w26,w26,w17                     // h+=Sigma0(a)
-       add     w5,w5,w10
-       ldr     w10,[sp,#12]
-       str     w13,[sp,#8]
-       ror     w16,w22,#6
-       add     w25,w25,w19                     // h+=K[i]
-       ror     w12,w7,#7
-       and     w17,w23,w22
-       ror     w11,w4,#17
-       bic     w19,w24,w22
-       ror     w13,w26,#2
-       add     w25,w25,w5                      // h+=X[i]
-       eor     w16,w16,w22,ror#11
-       eor     w12,w12,w7,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w26,w27                     // a^b, b^c in next round
-       eor     w16,w16,w22,ror#25      // Sigma1(e)
-       eor     w13,w13,w26,ror#13
-       add     w25,w25,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w11,w11,w4,ror#19
-       eor     w12,w12,w7,lsr#3        // sigma0(X[i+1])
-       add     w25,w25,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w27                     // Maj(a,b,c)
-       eor     w17,w13,w26,ror#22      // Sigma0(a)
-       eor     w11,w11,w4,lsr#10       // sigma1(X[i+14])
-       add     w6,w6,w15
-       add     w21,w21,w25                     // d+=h
-       add     w25,w25,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w6,w6,w12
-       add     w25,w25,w17                     // h+=Sigma0(a)
-       add     w6,w6,w11
-       ldr     w11,[sp,#0]
-       str     w14,[sp,#12]
-       ror     w16,w21,#6
-       add     w24,w24,w28                     // h+=K[i]
-       ror     w13,w8,#7
-       and     w17,w22,w21
-       ror     w12,w5,#17
-       bic     w28,w23,w21
-       ror     w14,w25,#2
-       add     w24,w24,w6                      // h+=X[i]
-       eor     w16,w16,w21,ror#11
-       eor     w13,w13,w8,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w25,w26                     // a^b, b^c in next round
-       eor     w16,w16,w21,ror#25      // Sigma1(e)
-       eor     w14,w14,w25,ror#13
-       add     w24,w24,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w12,w12,w5,ror#19
-       eor     w13,w13,w8,lsr#3        // sigma0(X[i+1])
-       add     w24,w24,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w26                     // Maj(a,b,c)
-       eor     w17,w14,w25,ror#22      // Sigma0(a)
-       eor     w12,w12,w5,lsr#10       // sigma1(X[i+14])
-       add     w7,w7,w0
-       add     w20,w20,w24                     // d+=h
-       add     w24,w24,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w7,w7,w13
-       add     w24,w24,w17                     // h+=Sigma0(a)
-       add     w7,w7,w12
-       ldr     w12,[sp,#4]
-       str     w15,[sp,#0]
-       ror     w16,w20,#6
-       add     w23,w23,w19                     // h+=K[i]
-       ror     w14,w9,#7
-       and     w17,w21,w20
-       ror     w13,w6,#17
-       bic     w19,w22,w20
-       ror     w15,w24,#2
-       add     w23,w23,w7                      // h+=X[i]
-       eor     w16,w16,w20,ror#11
-       eor     w14,w14,w9,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w24,w25                     // a^b, b^c in next round
-       eor     w16,w16,w20,ror#25      // Sigma1(e)
-       eor     w15,w15,w24,ror#13
-       add     w23,w23,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w13,w13,w6,ror#19
-       eor     w14,w14,w9,lsr#3        // sigma0(X[i+1])
-       add     w23,w23,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w25                     // Maj(a,b,c)
-       eor     w17,w15,w24,ror#22      // Sigma0(a)
-       eor     w13,w13,w6,lsr#10       // sigma1(X[i+14])
-       add     w8,w8,w1
-       add     w27,w27,w23                     // d+=h
-       add     w23,w23,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w8,w8,w14
-       add     w23,w23,w17                     // h+=Sigma0(a)
-       add     w8,w8,w13
-       ldr     w13,[sp,#8]
-       str     w0,[sp,#4]
-       ror     w16,w27,#6
-       add     w22,w22,w28                     // h+=K[i]
-       ror     w15,w10,#7
-       and     w17,w20,w27
-       ror     w14,w7,#17
-       bic     w28,w21,w27
-       ror     w0,w23,#2
-       add     w22,w22,w8                      // h+=X[i]
-       eor     w16,w16,w27,ror#11
-       eor     w15,w15,w10,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w23,w24                     // a^b, b^c in next round
-       eor     w16,w16,w27,ror#25      // Sigma1(e)
-       eor     w0,w0,w23,ror#13
-       add     w22,w22,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w14,w14,w7,ror#19
-       eor     w15,w15,w10,lsr#3       // sigma0(X[i+1])
-       add     w22,w22,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w24                     // Maj(a,b,c)
-       eor     w17,w0,w23,ror#22       // Sigma0(a)
-       eor     w14,w14,w7,lsr#10       // sigma1(X[i+14])
-       add     w9,w9,w2
-       add     w26,w26,w22                     // d+=h
-       add     w22,w22,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w9,w9,w15
-       add     w22,w22,w17                     // h+=Sigma0(a)
-       add     w9,w9,w14
-       ldr     w14,[sp,#12]
-       str     w1,[sp,#8]
-       ror     w16,w26,#6
-       add     w21,w21,w19                     // h+=K[i]
-       ror     w0,w11,#7
-       and     w17,w27,w26
-       ror     w15,w8,#17
-       bic     w19,w20,w26
-       ror     w1,w22,#2
-       add     w21,w21,w9                      // h+=X[i]
-       eor     w16,w16,w26,ror#11
-       eor     w0,w0,w11,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w22,w23                     // a^b, b^c in next round
-       eor     w16,w16,w26,ror#25      // Sigma1(e)
-       eor     w1,w1,w22,ror#13
-       add     w21,w21,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w15,w15,w8,ror#19
-       eor     w0,w0,w11,lsr#3 // sigma0(X[i+1])
-       add     w21,w21,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w23                     // Maj(a,b,c)
-       eor     w17,w1,w22,ror#22       // Sigma0(a)
-       eor     w15,w15,w8,lsr#10       // sigma1(X[i+14])
-       add     w10,w10,w3
-       add     w25,w25,w21                     // d+=h
-       add     w21,w21,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w10,w10,w0
-       add     w21,w21,w17                     // h+=Sigma0(a)
-       add     w10,w10,w15
-       ldr     w15,[sp,#0]
-       str     w2,[sp,#12]
-       ror     w16,w25,#6
-       add     w20,w20,w28                     // h+=K[i]
-       ror     w1,w12,#7
-       and     w17,w26,w25
-       ror     w0,w9,#17
-       bic     w28,w27,w25
-       ror     w2,w21,#2
-       add     w20,w20,w10                     // h+=X[i]
-       eor     w16,w16,w25,ror#11
-       eor     w1,w1,w12,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w21,w22                     // a^b, b^c in next round
-       eor     w16,w16,w25,ror#25      // Sigma1(e)
-       eor     w2,w2,w21,ror#13
-       add     w20,w20,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w0,w0,w9,ror#19
-       eor     w1,w1,w12,lsr#3 // sigma0(X[i+1])
-       add     w20,w20,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w22                     // Maj(a,b,c)
-       eor     w17,w2,w21,ror#22       // Sigma0(a)
-       eor     w0,w0,w9,lsr#10 // sigma1(X[i+14])
-       add     w11,w11,w4
-       add     w24,w24,w20                     // d+=h
-       add     w20,w20,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w11,w11,w1
-       add     w20,w20,w17                     // h+=Sigma0(a)
-       add     w11,w11,w0
-       ldr     w0,[sp,#4]
-       str     w3,[sp,#0]
-       ror     w16,w24,#6
-       add     w27,w27,w19                     // h+=K[i]
-       ror     w2,w13,#7
-       and     w17,w25,w24
-       ror     w1,w10,#17
-       bic     w19,w26,w24
-       ror     w3,w20,#2
-       add     w27,w27,w11                     // h+=X[i]
-       eor     w16,w16,w24,ror#11
-       eor     w2,w2,w13,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w20,w21                     // a^b, b^c in next round
-       eor     w16,w16,w24,ror#25      // Sigma1(e)
-       eor     w3,w3,w20,ror#13
-       add     w27,w27,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w1,w1,w10,ror#19
-       eor     w2,w2,w13,lsr#3 // sigma0(X[i+1])
-       add     w27,w27,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w21                     // Maj(a,b,c)
-       eor     w17,w3,w20,ror#22       // Sigma0(a)
-       eor     w1,w1,w10,lsr#10        // sigma1(X[i+14])
-       add     w12,w12,w5
-       add     w23,w23,w27                     // d+=h
-       add     w27,w27,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w12,w12,w2
-       add     w27,w27,w17                     // h+=Sigma0(a)
-       add     w12,w12,w1
-       ldr     w1,[sp,#8]
-       str     w4,[sp,#4]
-       ror     w16,w23,#6
-       add     w26,w26,w28                     // h+=K[i]
-       ror     w3,w14,#7
-       and     w17,w24,w23
-       ror     w2,w11,#17
-       bic     w28,w25,w23
-       ror     w4,w27,#2
-       add     w26,w26,w12                     // h+=X[i]
-       eor     w16,w16,w23,ror#11
-       eor     w3,w3,w14,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w27,w20                     // a^b, b^c in next round
-       eor     w16,w16,w23,ror#25      // Sigma1(e)
-       eor     w4,w4,w27,ror#13
-       add     w26,w26,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w2,w2,w11,ror#19
-       eor     w3,w3,w14,lsr#3 // sigma0(X[i+1])
-       add     w26,w26,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w20                     // Maj(a,b,c)
-       eor     w17,w4,w27,ror#22       // Sigma0(a)
-       eor     w2,w2,w11,lsr#10        // sigma1(X[i+14])
-       add     w13,w13,w6
-       add     w22,w22,w26                     // d+=h
-       add     w26,w26,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w13,w13,w3
-       add     w26,w26,w17                     // h+=Sigma0(a)
-       add     w13,w13,w2
-       ldr     w2,[sp,#12]
-       str     w5,[sp,#8]
-       ror     w16,w22,#6
-       add     w25,w25,w19                     // h+=K[i]
-       ror     w4,w15,#7
-       and     w17,w23,w22
-       ror     w3,w12,#17
-       bic     w19,w24,w22
-       ror     w5,w26,#2
-       add     w25,w25,w13                     // h+=X[i]
-       eor     w16,w16,w22,ror#11
-       eor     w4,w4,w15,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w26,w27                     // a^b, b^c in next round
-       eor     w16,w16,w22,ror#25      // Sigma1(e)
-       eor     w5,w5,w26,ror#13
-       add     w25,w25,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w3,w3,w12,ror#19
-       eor     w4,w4,w15,lsr#3 // sigma0(X[i+1])
-       add     w25,w25,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w27                     // Maj(a,b,c)
-       eor     w17,w5,w26,ror#22       // Sigma0(a)
-       eor     w3,w3,w12,lsr#10        // sigma1(X[i+14])
-       add     w14,w14,w7
-       add     w21,w21,w25                     // d+=h
-       add     w25,w25,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w14,w14,w4
-       add     w25,w25,w17                     // h+=Sigma0(a)
-       add     w14,w14,w3
-       ldr     w3,[sp,#0]
-       str     w6,[sp,#12]
-       ror     w16,w21,#6
-       add     w24,w24,w28                     // h+=K[i]
-       ror     w5,w0,#7
-       and     w17,w22,w21
-       ror     w4,w13,#17
-       bic     w28,w23,w21
-       ror     w6,w25,#2
-       add     w24,w24,w14                     // h+=X[i]
-       eor     w16,w16,w21,ror#11
-       eor     w5,w5,w0,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w25,w26                     // a^b, b^c in next round
-       eor     w16,w16,w21,ror#25      // Sigma1(e)
-       eor     w6,w6,w25,ror#13
-       add     w24,w24,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w4,w4,w13,ror#19
-       eor     w5,w5,w0,lsr#3  // sigma0(X[i+1])
-       add     w24,w24,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w26                     // Maj(a,b,c)
-       eor     w17,w6,w25,ror#22       // Sigma0(a)
-       eor     w4,w4,w13,lsr#10        // sigma1(X[i+14])
-       add     w15,w15,w8
-       add     w20,w20,w24                     // d+=h
-       add     w24,w24,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w15,w15,w5
-       add     w24,w24,w17                     // h+=Sigma0(a)
-       add     w15,w15,w4
-       ldr     w4,[sp,#4]
-       str     w7,[sp,#0]
-       ror     w16,w20,#6
-       add     w23,w23,w19                     // h+=K[i]
-       ror     w6,w1,#7
-       and     w17,w21,w20
-       ror     w5,w14,#17
-       bic     w19,w22,w20
-       ror     w7,w24,#2
-       add     w23,w23,w15                     // h+=X[i]
-       eor     w16,w16,w20,ror#11
-       eor     w6,w6,w1,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w24,w25                     // a^b, b^c in next round
-       eor     w16,w16,w20,ror#25      // Sigma1(e)
-       eor     w7,w7,w24,ror#13
-       add     w23,w23,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w5,w5,w14,ror#19
-       eor     w6,w6,w1,lsr#3  // sigma0(X[i+1])
-       add     w23,w23,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w25                     // Maj(a,b,c)
-       eor     w17,w7,w24,ror#22       // Sigma0(a)
-       eor     w5,w5,w14,lsr#10        // sigma1(X[i+14])
-       add     w0,w0,w9
-       add     w27,w27,w23                     // d+=h
-       add     w23,w23,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w0,w0,w6
-       add     w23,w23,w17                     // h+=Sigma0(a)
-       add     w0,w0,w5
-       ldr     w5,[sp,#8]
-       str     w8,[sp,#4]
-       ror     w16,w27,#6
-       add     w22,w22,w28                     // h+=K[i]
-       ror     w7,w2,#7
-       and     w17,w20,w27
-       ror     w6,w15,#17
-       bic     w28,w21,w27
-       ror     w8,w23,#2
-       add     w22,w22,w0                      // h+=X[i]
-       eor     w16,w16,w27,ror#11
-       eor     w7,w7,w2,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w23,w24                     // a^b, b^c in next round
-       eor     w16,w16,w27,ror#25      // Sigma1(e)
-       eor     w8,w8,w23,ror#13
-       add     w22,w22,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w6,w6,w15,ror#19
-       eor     w7,w7,w2,lsr#3  // sigma0(X[i+1])
-       add     w22,w22,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w24                     // Maj(a,b,c)
-       eor     w17,w8,w23,ror#22       // Sigma0(a)
-       eor     w6,w6,w15,lsr#10        // sigma1(X[i+14])
-       add     w1,w1,w10
-       add     w26,w26,w22                     // d+=h
-       add     w22,w22,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w1,w1,w7
-       add     w22,w22,w17                     // h+=Sigma0(a)
-       add     w1,w1,w6
-       ldr     w6,[sp,#12]
-       str     w9,[sp,#8]
-       ror     w16,w26,#6
-       add     w21,w21,w19                     // h+=K[i]
-       ror     w8,w3,#7
-       and     w17,w27,w26
-       ror     w7,w0,#17
-       bic     w19,w20,w26
-       ror     w9,w22,#2
-       add     w21,w21,w1                      // h+=X[i]
-       eor     w16,w16,w26,ror#11
-       eor     w8,w8,w3,ror#18
-       orr     w17,w17,w19                     // Ch(e,f,g)
-       eor     w19,w22,w23                     // a^b, b^c in next round
-       eor     w16,w16,w26,ror#25      // Sigma1(e)
-       eor     w9,w9,w22,ror#13
-       add     w21,w21,w17                     // h+=Ch(e,f,g)
-       and     w28,w28,w19                     // (b^c)&=(a^b)
-       eor     w7,w7,w0,ror#19
-       eor     w8,w8,w3,lsr#3  // sigma0(X[i+1])
-       add     w21,w21,w16                     // h+=Sigma1(e)
-       eor     w28,w28,w23                     // Maj(a,b,c)
-       eor     w17,w9,w22,ror#22       // Sigma0(a)
-       eor     w7,w7,w0,lsr#10 // sigma1(X[i+14])
-       add     w2,w2,w11
-       add     w25,w25,w21                     // d+=h
-       add     w21,w21,w28                     // h+=Maj(a,b,c)
-       ldr     w28,[x30],#4            // *K++, w19 in next round
-       add     w2,w2,w8
-       add     w21,w21,w17                     // h+=Sigma0(a)
-       add     w2,w2,w7
-       ldr     w7,[sp,#0]
-       str     w10,[sp,#12]
-       ror     w16,w25,#6
-       add     w20,w20,w28                     // h+=K[i]
-       ror     w9,w4,#7
-       and     w17,w26,w25
-       ror     w8,w1,#17
-       bic     w28,w27,w25
-       ror     w10,w21,#2
-       add     w20,w20,w2                      // h+=X[i]
-       eor     w16,w16,w25,ror#11
-       eor     w9,w9,w4,ror#18
-       orr     w17,w17,w28                     // Ch(e,f,g)
-       eor     w28,w21,w22                     // a^b, b^c in next round
-       eor     w16,w16,w25,ror#25      // Sigma1(e)
-       eor     w10,w10,w21,ror#13
-       add     w20,w20,w17                     // h+=Ch(e,f,g)
-       and     w19,w19,w28                     // (b^c)&=(a^b)
-       eor     w8,w8,w1,ror#19
-       eor     w9,w9,w4,lsr#3  // sigma0(X[i+1])
-       add     w20,w20,w16                     // h+=Sigma1(e)
-       eor     w19,w19,w22                     // Maj(a,b,c)
-       eor     w17,w10,w21,ror#22      // Sigma0(a)
-       eor     w8,w8,w1,lsr#10 // sigma1(X[i+14])
-       add     w3,w3,w12
-       add     w24,w24,w20                     // d+=h
-       add     w20,w20,w19                     // h+=Maj(a,b,c)
-       ldr     w19,[x30],#4            // *K++, w28 in next round
-       add     w3,w3,w9
-       add     w20,w20,w17                     // h+=Sigma0(a)
-       add     w3,w3,w8
-       cbnz    w19,.Loop_16_xx
-
-       ldp     x0,x2,[x29,#96]
-       ldr     x1,[x29,#112]
-       sub     x30,x30,#260            // rewind
-
-       ldp     w3,w4,[x0]
-       ldp     w5,w6,[x0,#2*4]
-       add     x1,x1,#14*4                     // advance input pointer
-       ldp     w7,w8,[x0,#4*4]
-       add     w20,w20,w3
-       ldp     w9,w10,[x0,#6*4]
-       add     w21,w21,w4
-       add     w22,w22,w5
-       add     w23,w23,w6
-       stp     w20,w21,[x0]
-       add     w24,w24,w7
-       add     w25,w25,w8
-       stp     w22,w23,[x0,#2*4]
-       add     w26,w26,w9
-       add     w27,w27,w10
-       cmp     x1,x2
-       stp     w24,w25,[x0,#4*4]
-       stp     w26,w27,[x0,#6*4]
-       b.ne    .Loop
-
-       ldp     x19,x20,[x29,#16]
-       add     sp,sp,#4*4
-       ldp     x21,x22,[x29,#32]
-       ldp     x23,x24,[x29,#48]
-       ldp     x25,x26,[x29,#64]
-       ldp     x27,x28,[x29,#80]
-       ldp     x29,x30,[sp],#128
-       ret
-.size  sha256_block_data_order,.-sha256_block_data_order
-
-.align 6
-.type  .LK256,%object
-.LK256:
-       .long   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
-       .long   0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
-       .long   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
-       .long   0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
-       .long   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
-       .long   0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
-       .long   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
-       .long   0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
-       .long   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
-       .long   0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
-       .long   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
-       .long   0xd192e819,0xd6990624,0xf40e3585,0x106aa070
-       .long   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
-       .long   0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
-       .long   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
-       .long   0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
-       .long   0       //terminator
-.size  .LK256,.-.LK256
-#ifndef        __KERNEL__
-.align 3
-.LOPENSSL_armcap_P:
-# ifdef        __ILP32__
-       .long   OPENSSL_armcap_P-.
-# else
-       .quad   OPENSSL_armcap_P-.
-# endif
-#endif
-.asciz "SHA256 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
-.align 2
-#ifndef        __KERNEL__
-.type  sha256_block_armv8,%function
-.align 6
-sha256_block_armv8:
-.Lv8_entry:
-       stp             x29,x30,[sp,#-16]!
-       add             x29,sp,#0
-
-       ld1             {v0.4s,v1.4s},[x0]
-       adr             x3,.LK256
-
-.Loop_hw:
-       ld1             {v4.16b-v7.16b},[x1],#64
-       sub             x2,x2,#1
-       ld1             {v16.4s},[x3],#16
-       rev32           v4.16b,v4.16b
-       rev32           v5.16b,v5.16b
-       rev32           v6.16b,v6.16b
-       rev32           v7.16b,v7.16b
-       orr             v18.16b,v0.16b,v0.16b           // offload
-       orr             v19.16b,v1.16b,v1.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v4.4s
-       .inst   0x5e2828a4      //sha256su0 v4.16b,v5.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e0760c4      //sha256su1 v4.16b,v6.16b,v7.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v5.4s
-       .inst   0x5e2828c5      //sha256su0 v5.16b,v6.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0460e5      //sha256su1 v5.16b,v7.16b,v4.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v6.4s
-       .inst   0x5e2828e6      //sha256su0 v6.16b,v7.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e056086      //sha256su1 v6.16b,v4.16b,v5.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v7.4s
-       .inst   0x5e282887      //sha256su0 v7.16b,v4.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0660a7      //sha256su1 v7.16b,v5.16b,v6.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v4.4s
-       .inst   0x5e2828a4      //sha256su0 v4.16b,v5.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e0760c4      //sha256su1 v4.16b,v6.16b,v7.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v5.4s
-       .inst   0x5e2828c5      //sha256su0 v5.16b,v6.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0460e5      //sha256su1 v5.16b,v7.16b,v4.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v6.4s
-       .inst   0x5e2828e6      //sha256su0 v6.16b,v7.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e056086      //sha256su1 v6.16b,v4.16b,v5.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v7.4s
-       .inst   0x5e282887      //sha256su0 v7.16b,v4.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0660a7      //sha256su1 v7.16b,v5.16b,v6.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v4.4s
-       .inst   0x5e2828a4      //sha256su0 v4.16b,v5.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e0760c4      //sha256su1 v4.16b,v6.16b,v7.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v5.4s
-       .inst   0x5e2828c5      //sha256su0 v5.16b,v6.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0460e5      //sha256su1 v5.16b,v7.16b,v4.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v6.4s
-       .inst   0x5e2828e6      //sha256su0 v6.16b,v7.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-       .inst   0x5e056086      //sha256su1 v6.16b,v4.16b,v5.16b
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v7.4s
-       .inst   0x5e282887      //sha256su0 v7.16b,v4.16b
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-       .inst   0x5e0660a7      //sha256su1 v7.16b,v5.16b,v6.16b
-       ld1             {v17.4s},[x3],#16
-       add             v16.4s,v16.4s,v4.4s
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-
-       ld1             {v16.4s},[x3],#16
-       add             v17.4s,v17.4s,v5.4s
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-
-       ld1             {v17.4s},[x3]
-       add             v16.4s,v16.4s,v6.4s
-       sub             x3,x3,#64*4-16  // rewind
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e104020      //sha256h v0.16b,v1.16b,v16.4s
-       .inst   0x5e105041      //sha256h2 v1.16b,v2.16b,v16.4s
-
-       add             v17.4s,v17.4s,v7.4s
-       orr             v2.16b,v0.16b,v0.16b
-       .inst   0x5e114020      //sha256h v0.16b,v1.16b,v17.4s
-       .inst   0x5e115041      //sha256h2 v1.16b,v2.16b,v17.4s
-
-       add             v0.4s,v0.4s,v18.4s
-       add             v1.4s,v1.4s,v19.4s
-
-       cbnz            x2,.Loop_hw
-
-       st1             {v0.4s,v1.4s},[x0]
-
-       ldr             x29,[sp],#16
-       ret
-.size  sha256_block_armv8,.-sha256_block_armv8
-#endif
-#ifdef __KERNEL__
-.globl sha256_block_neon
-#endif
-.type  sha256_block_neon,%function
-.align 4
-sha256_block_neon:
-.Lneon_entry:
-       stp     x29, x30, [sp, #-16]!
-       mov     x29, sp
-       sub     sp,sp,#16*4
-
-       adr     x16,.LK256
-       add     x2,x1,x2,lsl#6  // len to point at the end of inp
-
-       ld1     {v0.16b},[x1], #16
-       ld1     {v1.16b},[x1], #16
-       ld1     {v2.16b},[x1], #16
-       ld1     {v3.16b},[x1], #16
-       ld1     {v4.4s},[x16], #16
-       ld1     {v5.4s},[x16], #16
-       ld1     {v6.4s},[x16], #16
-       ld1     {v7.4s},[x16], #16
-       rev32   v0.16b,v0.16b           // yes, even on
-       rev32   v1.16b,v1.16b           // big-endian
-       rev32   v2.16b,v2.16b
-       rev32   v3.16b,v3.16b
-       mov     x17,sp
-       add     v4.4s,v4.4s,v0.4s
-       add     v5.4s,v5.4s,v1.4s
-       add     v6.4s,v6.4s,v2.4s
-       st1     {v4.4s-v5.4s},[x17], #32
-       add     v7.4s,v7.4s,v3.4s
-       st1     {v6.4s-v7.4s},[x17]
-       sub     x17,x17,#32
-
-       ldp     w3,w4,[x0]
-       ldp     w5,w6,[x0,#8]
-       ldp     w7,w8,[x0,#16]
-       ldp     w9,w10,[x0,#24]
-       ldr     w12,[sp,#0]
-       mov     w13,wzr
-       eor     w14,w4,w5
-       mov     w15,wzr
-       b       .L_00_48
-
-.align 4
-.L_00_48:
-       ext     v4.16b,v0.16b,v1.16b,#4
-       add     w10,w10,w12
-       add     w3,w3,w15
-       and     w12,w8,w7
-       bic     w15,w9,w7
-       ext     v7.16b,v2.16b,v3.16b,#4
-       eor     w11,w7,w7,ror#5
-       add     w3,w3,w13
-       mov     d19,v3.d[1]
-       orr     w12,w12,w15
-       eor     w11,w11,w7,ror#19
-       ushr    v6.4s,v4.4s,#7
-       eor     w15,w3,w3,ror#11
-       ushr    v5.4s,v4.4s,#3
-       add     w10,w10,w12
-       add     v0.4s,v0.4s,v7.4s
-       ror     w11,w11,#6
-       sli     v6.4s,v4.4s,#25
-       eor     w13,w3,w4
-       eor     w15,w15,w3,ror#20
-       ushr    v7.4s,v4.4s,#18
-       add     w10,w10,w11
-       ldr     w12,[sp,#4]
-       and     w14,w14,w13
-       eor     v5.16b,v5.16b,v6.16b
-       ror     w15,w15,#2
-       add     w6,w6,w10
-       sli     v7.4s,v4.4s,#14
-       eor     w14,w14,w4
-       ushr    v16.4s,v19.4s,#17
-       add     w9,w9,w12
-       add     w10,w10,w15
-       and     w12,w7,w6
-       eor     v5.16b,v5.16b,v7.16b
-       bic     w15,w8,w6
-       eor     w11,w6,w6,ror#5
-       sli     v16.4s,v19.4s,#15
-       add     w10,w10,w14
-       orr     w12,w12,w15
-       ushr    v17.4s,v19.4s,#10
-       eor     w11,w11,w6,ror#19
-       eor     w15,w10,w10,ror#11
-       ushr    v7.4s,v19.4s,#19
-       add     w9,w9,w12
-       ror     w11,w11,#6
-       add     v0.4s,v0.4s,v5.4s
-       eor     w14,w10,w3
-       eor     w15,w15,w10,ror#20
-       sli     v7.4s,v19.4s,#13
-       add     w9,w9,w11
-       ldr     w12,[sp,#8]
-       and     w13,w13,w14
-       eor     v17.16b,v17.16b,v16.16b
-       ror     w15,w15,#2
-       add     w5,w5,w9
-       eor     w13,w13,w3
-       eor     v17.16b,v17.16b,v7.16b
-       add     w8,w8,w12
-       add     w9,w9,w15
-       and     w12,w6,w5
-       add     v0.4s,v0.4s,v17.4s
-       bic     w15,w7,w5
-       eor     w11,w5,w5,ror#5
-       add     w9,w9,w13
-       ushr    v18.4s,v0.4s,#17
-       orr     w12,w12,w15
-       ushr    v19.4s,v0.4s,#10
-       eor     w11,w11,w5,ror#19
-       eor     w15,w9,w9,ror#11
-       sli     v18.4s,v0.4s,#15
-       add     w8,w8,w12
-       ushr    v17.4s,v0.4s,#19
-       ror     w11,w11,#6
-       eor     w13,w9,w10
-       eor     v19.16b,v19.16b,v18.16b
-       eor     w15,w15,w9,ror#20
-       add     w8,w8,w11
-       sli     v17.4s,v0.4s,#13
-       ldr     w12,[sp,#12]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       ld1     {v4.4s},[x16], #16
-       add     w4,w4,w8
-       eor     v19.16b,v19.16b,v17.16b
-       eor     w14,w14,w10
-       eor     v17.16b,v17.16b,v17.16b
-       add     w7,w7,w12
-       add     w8,w8,w15
-       and     w12,w5,w4
-       mov     v17.d[1],v19.d[0]
-       bic     w15,w6,w4
-       eor     w11,w4,w4,ror#5
-       add     w8,w8,w14
-       add     v0.4s,v0.4s,v17.4s
-       orr     w12,w12,w15
-       eor     w11,w11,w4,ror#19
-       eor     w15,w8,w8,ror#11
-       add     v4.4s,v4.4s,v0.4s
-       add     w7,w7,w12
-       ror     w11,w11,#6
-       eor     w14,w8,w9
-       eor     w15,w15,w8,ror#20
-       add     w7,w7,w11
-       ldr     w12,[sp,#16]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w3,w3,w7
-       eor     w13,w13,w9
-       st1     {v4.4s},[x17], #16
-       ext     v4.16b,v1.16b,v2.16b,#4
-       add     w6,w6,w12
-       add     w7,w7,w15
-       and     w12,w4,w3
-       bic     w15,w5,w3
-       ext     v7.16b,v3.16b,v0.16b,#4
-       eor     w11,w3,w3,ror#5
-       add     w7,w7,w13
-       mov     d19,v0.d[1]
-       orr     w12,w12,w15
-       eor     w11,w11,w3,ror#19
-       ushr    v6.4s,v4.4s,#7
-       eor     w15,w7,w7,ror#11
-       ushr    v5.4s,v4.4s,#3
-       add     w6,w6,w12
-       add     v1.4s,v1.4s,v7.4s
-       ror     w11,w11,#6
-       sli     v6.4s,v4.4s,#25
-       eor     w13,w7,w8
-       eor     w15,w15,w7,ror#20
-       ushr    v7.4s,v4.4s,#18
-       add     w6,w6,w11
-       ldr     w12,[sp,#20]
-       and     w14,w14,w13
-       eor     v5.16b,v5.16b,v6.16b
-       ror     w15,w15,#2
-       add     w10,w10,w6
-       sli     v7.4s,v4.4s,#14
-       eor     w14,w14,w8
-       ushr    v16.4s,v19.4s,#17
-       add     w5,w5,w12
-       add     w6,w6,w15
-       and     w12,w3,w10
-       eor     v5.16b,v5.16b,v7.16b
-       bic     w15,w4,w10
-       eor     w11,w10,w10,ror#5
-       sli     v16.4s,v19.4s,#15
-       add     w6,w6,w14
-       orr     w12,w12,w15
-       ushr    v17.4s,v19.4s,#10
-       eor     w11,w11,w10,ror#19
-       eor     w15,w6,w6,ror#11
-       ushr    v7.4s,v19.4s,#19
-       add     w5,w5,w12
-       ror     w11,w11,#6
-       add     v1.4s,v1.4s,v5.4s
-       eor     w14,w6,w7
-       eor     w15,w15,w6,ror#20
-       sli     v7.4s,v19.4s,#13
-       add     w5,w5,w11
-       ldr     w12,[sp,#24]
-       and     w13,w13,w14
-       eor     v17.16b,v17.16b,v16.16b
-       ror     w15,w15,#2
-       add     w9,w9,w5
-       eor     w13,w13,w7
-       eor     v17.16b,v17.16b,v7.16b
-       add     w4,w4,w12
-       add     w5,w5,w15
-       and     w12,w10,w9
-       add     v1.4s,v1.4s,v17.4s
-       bic     w15,w3,w9
-       eor     w11,w9,w9,ror#5
-       add     w5,w5,w13
-       ushr    v18.4s,v1.4s,#17
-       orr     w12,w12,w15
-       ushr    v19.4s,v1.4s,#10
-       eor     w11,w11,w9,ror#19
-       eor     w15,w5,w5,ror#11
-       sli     v18.4s,v1.4s,#15
-       add     w4,w4,w12
-       ushr    v17.4s,v1.4s,#19
-       ror     w11,w11,#6
-       eor     w13,w5,w6
-       eor     v19.16b,v19.16b,v18.16b
-       eor     w15,w15,w5,ror#20
-       add     w4,w4,w11
-       sli     v17.4s,v1.4s,#13
-       ldr     w12,[sp,#28]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       ld1     {v4.4s},[x16], #16
-       add     w8,w8,w4
-       eor     v19.16b,v19.16b,v17.16b
-       eor     w14,w14,w6
-       eor     v17.16b,v17.16b,v17.16b
-       add     w3,w3,w12
-       add     w4,w4,w15
-       and     w12,w9,w8
-       mov     v17.d[1],v19.d[0]
-       bic     w15,w10,w8
-       eor     w11,w8,w8,ror#5
-       add     w4,w4,w14
-       add     v1.4s,v1.4s,v17.4s
-       orr     w12,w12,w15
-       eor     w11,w11,w8,ror#19
-       eor     w15,w4,w4,ror#11
-       add     v4.4s,v4.4s,v1.4s
-       add     w3,w3,w12
-       ror     w11,w11,#6
-       eor     w14,w4,w5
-       eor     w15,w15,w4,ror#20
-       add     w3,w3,w11
-       ldr     w12,[sp,#32]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w7,w7,w3
-       eor     w13,w13,w5
-       st1     {v4.4s},[x17], #16
-       ext     v4.16b,v2.16b,v3.16b,#4
-       add     w10,w10,w12
-       add     w3,w3,w15
-       and     w12,w8,w7
-       bic     w15,w9,w7
-       ext     v7.16b,v0.16b,v1.16b,#4
-       eor     w11,w7,w7,ror#5
-       add     w3,w3,w13
-       mov     d19,v1.d[1]
-       orr     w12,w12,w15
-       eor     w11,w11,w7,ror#19
-       ushr    v6.4s,v4.4s,#7
-       eor     w15,w3,w3,ror#11
-       ushr    v5.4s,v4.4s,#3
-       add     w10,w10,w12
-       add     v2.4s,v2.4s,v7.4s
-       ror     w11,w11,#6
-       sli     v6.4s,v4.4s,#25
-       eor     w13,w3,w4
-       eor     w15,w15,w3,ror#20
-       ushr    v7.4s,v4.4s,#18
-       add     w10,w10,w11
-       ldr     w12,[sp,#36]
-       and     w14,w14,w13
-       eor     v5.16b,v5.16b,v6.16b
-       ror     w15,w15,#2
-       add     w6,w6,w10
-       sli     v7.4s,v4.4s,#14
-       eor     w14,w14,w4
-       ushr    v16.4s,v19.4s,#17
-       add     w9,w9,w12
-       add     w10,w10,w15
-       and     w12,w7,w6
-       eor     v5.16b,v5.16b,v7.16b
-       bic     w15,w8,w6
-       eor     w11,w6,w6,ror#5
-       sli     v16.4s,v19.4s,#15
-       add     w10,w10,w14
-       orr     w12,w12,w15
-       ushr    v17.4s,v19.4s,#10
-       eor     w11,w11,w6,ror#19
-       eor     w15,w10,w10,ror#11
-       ushr    v7.4s,v19.4s,#19
-       add     w9,w9,w12
-       ror     w11,w11,#6
-       add     v2.4s,v2.4s,v5.4s
-       eor     w14,w10,w3
-       eor     w15,w15,w10,ror#20
-       sli     v7.4s,v19.4s,#13
-       add     w9,w9,w11
-       ldr     w12,[sp,#40]
-       and     w13,w13,w14
-       eor     v17.16b,v17.16b,v16.16b
-       ror     w15,w15,#2
-       add     w5,w5,w9
-       eor     w13,w13,w3
-       eor     v17.16b,v17.16b,v7.16b
-       add     w8,w8,w12
-       add     w9,w9,w15
-       and     w12,w6,w5
-       add     v2.4s,v2.4s,v17.4s
-       bic     w15,w7,w5
-       eor     w11,w5,w5,ror#5
-       add     w9,w9,w13
-       ushr    v18.4s,v2.4s,#17
-       orr     w12,w12,w15
-       ushr    v19.4s,v2.4s,#10
-       eor     w11,w11,w5,ror#19
-       eor     w15,w9,w9,ror#11
-       sli     v18.4s,v2.4s,#15
-       add     w8,w8,w12
-       ushr    v17.4s,v2.4s,#19
-       ror     w11,w11,#6
-       eor     w13,w9,w10
-       eor     v19.16b,v19.16b,v18.16b
-       eor     w15,w15,w9,ror#20
-       add     w8,w8,w11
-       sli     v17.4s,v2.4s,#13
-       ldr     w12,[sp,#44]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       ld1     {v4.4s},[x16], #16
-       add     w4,w4,w8
-       eor     v19.16b,v19.16b,v17.16b
-       eor     w14,w14,w10
-       eor     v17.16b,v17.16b,v17.16b
-       add     w7,w7,w12
-       add     w8,w8,w15
-       and     w12,w5,w4
-       mov     v17.d[1],v19.d[0]
-       bic     w15,w6,w4
-       eor     w11,w4,w4,ror#5
-       add     w8,w8,w14
-       add     v2.4s,v2.4s,v17.4s
-       orr     w12,w12,w15
-       eor     w11,w11,w4,ror#19
-       eor     w15,w8,w8,ror#11
-       add     v4.4s,v4.4s,v2.4s
-       add     w7,w7,w12
-       ror     w11,w11,#6
-       eor     w14,w8,w9
-       eor     w15,w15,w8,ror#20
-       add     w7,w7,w11
-       ldr     w12,[sp,#48]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w3,w3,w7
-       eor     w13,w13,w9
-       st1     {v4.4s},[x17], #16
-       ext     v4.16b,v3.16b,v0.16b,#4
-       add     w6,w6,w12
-       add     w7,w7,w15
-       and     w12,w4,w3
-       bic     w15,w5,w3
-       ext     v7.16b,v1.16b,v2.16b,#4
-       eor     w11,w3,w3,ror#5
-       add     w7,w7,w13
-       mov     d19,v2.d[1]
-       orr     w12,w12,w15
-       eor     w11,w11,w3,ror#19
-       ushr    v6.4s,v4.4s,#7
-       eor     w15,w7,w7,ror#11
-       ushr    v5.4s,v4.4s,#3
-       add     w6,w6,w12
-       add     v3.4s,v3.4s,v7.4s
-       ror     w11,w11,#6
-       sli     v6.4s,v4.4s,#25
-       eor     w13,w7,w8
-       eor     w15,w15,w7,ror#20
-       ushr    v7.4s,v4.4s,#18
-       add     w6,w6,w11
-       ldr     w12,[sp,#52]
-       and     w14,w14,w13
-       eor     v5.16b,v5.16b,v6.16b
-       ror     w15,w15,#2
-       add     w10,w10,w6
-       sli     v7.4s,v4.4s,#14
-       eor     w14,w14,w8
-       ushr    v16.4s,v19.4s,#17
-       add     w5,w5,w12
-       add     w6,w6,w15
-       and     w12,w3,w10
-       eor     v5.16b,v5.16b,v7.16b
-       bic     w15,w4,w10
-       eor     w11,w10,w10,ror#5
-       sli     v16.4s,v19.4s,#15
-       add     w6,w6,w14
-       orr     w12,w12,w15
-       ushr    v17.4s,v19.4s,#10
-       eor     w11,w11,w10,ror#19
-       eor     w15,w6,w6,ror#11
-       ushr    v7.4s,v19.4s,#19
-       add     w5,w5,w12
-       ror     w11,w11,#6
-       add     v3.4s,v3.4s,v5.4s
-       eor     w14,w6,w7
-       eor     w15,w15,w6,ror#20
-       sli     v7.4s,v19.4s,#13
-       add     w5,w5,w11
-       ldr     w12,[sp,#56]
-       and     w13,w13,w14
-       eor     v17.16b,v17.16b,v16.16b
-       ror     w15,w15,#2
-       add     w9,w9,w5
-       eor     w13,w13,w7
-       eor     v17.16b,v17.16b,v7.16b
-       add     w4,w4,w12
-       add     w5,w5,w15
-       and     w12,w10,w9
-       add     v3.4s,v3.4s,v17.4s
-       bic     w15,w3,w9
-       eor     w11,w9,w9,ror#5
-       add     w5,w5,w13
-       ushr    v18.4s,v3.4s,#17
-       orr     w12,w12,w15
-       ushr    v19.4s,v3.4s,#10
-       eor     w11,w11,w9,ror#19
-       eor     w15,w5,w5,ror#11
-       sli     v18.4s,v3.4s,#15
-       add     w4,w4,w12
-       ushr    v17.4s,v3.4s,#19
-       ror     w11,w11,#6
-       eor     w13,w5,w6
-       eor     v19.16b,v19.16b,v18.16b
-       eor     w15,w15,w5,ror#20
-       add     w4,w4,w11
-       sli     v17.4s,v3.4s,#13
-       ldr     w12,[sp,#60]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       ld1     {v4.4s},[x16], #16
-       add     w8,w8,w4
-       eor     v19.16b,v19.16b,v17.16b
-       eor     w14,w14,w6
-       eor     v17.16b,v17.16b,v17.16b
-       add     w3,w3,w12
-       add     w4,w4,w15
-       and     w12,w9,w8
-       mov     v17.d[1],v19.d[0]
-       bic     w15,w10,w8
-       eor     w11,w8,w8,ror#5
-       add     w4,w4,w14
-       add     v3.4s,v3.4s,v17.4s
-       orr     w12,w12,w15
-       eor     w11,w11,w8,ror#19
-       eor     w15,w4,w4,ror#11
-       add     v4.4s,v4.4s,v3.4s
-       add     w3,w3,w12
-       ror     w11,w11,#6
-       eor     w14,w4,w5
-       eor     w15,w15,w4,ror#20
-       add     w3,w3,w11
-       ldr     w12,[x16]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w7,w7,w3
-       eor     w13,w13,w5
-       st1     {v4.4s},[x17], #16
-       cmp     w12,#0                          // check for K256 terminator
-       ldr     w12,[sp,#0]
-       sub     x17,x17,#64
-       bne     .L_00_48
-
-       sub     x16,x16,#256            // rewind x16
-       cmp     x1,x2
-       mov     x17, #64
-       csel    x17, x17, xzr, eq
-       sub     x1,x1,x17                       // avoid SEGV
-       mov     x17,sp
-       add     w10,w10,w12
-       add     w3,w3,w15
-       and     w12,w8,w7
-       ld1     {v0.16b},[x1],#16
-       bic     w15,w9,w7
-       eor     w11,w7,w7,ror#5
-       ld1     {v4.4s},[x16],#16
-       add     w3,w3,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w7,ror#19
-       eor     w15,w3,w3,ror#11
-       rev32   v0.16b,v0.16b
-       add     w10,w10,w12
-       ror     w11,w11,#6
-       eor     w13,w3,w4
-       eor     w15,w15,w3,ror#20
-       add     v4.4s,v4.4s,v0.4s
-       add     w10,w10,w11
-       ldr     w12,[sp,#4]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w6,w6,w10
-       eor     w14,w14,w4
-       add     w9,w9,w12
-       add     w10,w10,w15
-       and     w12,w7,w6
-       bic     w15,w8,w6
-       eor     w11,w6,w6,ror#5
-       add     w10,w10,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w6,ror#19
-       eor     w15,w10,w10,ror#11
-       add     w9,w9,w12
-       ror     w11,w11,#6
-       eor     w14,w10,w3
-       eor     w15,w15,w10,ror#20
-       add     w9,w9,w11
-       ldr     w12,[sp,#8]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w5,w5,w9
-       eor     w13,w13,w3
-       add     w8,w8,w12
-       add     w9,w9,w15
-       and     w12,w6,w5
-       bic     w15,w7,w5
-       eor     w11,w5,w5,ror#5
-       add     w9,w9,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w5,ror#19
-       eor     w15,w9,w9,ror#11
-       add     w8,w8,w12
-       ror     w11,w11,#6
-       eor     w13,w9,w10
-       eor     w15,w15,w9,ror#20
-       add     w8,w8,w11
-       ldr     w12,[sp,#12]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w4,w4,w8
-       eor     w14,w14,w10
-       add     w7,w7,w12
-       add     w8,w8,w15
-       and     w12,w5,w4
-       bic     w15,w6,w4
-       eor     w11,w4,w4,ror#5
-       add     w8,w8,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w4,ror#19
-       eor     w15,w8,w8,ror#11
-       add     w7,w7,w12
-       ror     w11,w11,#6
-       eor     w14,w8,w9
-       eor     w15,w15,w8,ror#20
-       add     w7,w7,w11
-       ldr     w12,[sp,#16]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w3,w3,w7
-       eor     w13,w13,w9
-       st1     {v4.4s},[x17], #16
-       add     w6,w6,w12
-       add     w7,w7,w15
-       and     w12,w4,w3
-       ld1     {v1.16b},[x1],#16
-       bic     w15,w5,w3
-       eor     w11,w3,w3,ror#5
-       ld1     {v4.4s},[x16],#16
-       add     w7,w7,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w3,ror#19
-       eor     w15,w7,w7,ror#11
-       rev32   v1.16b,v1.16b
-       add     w6,w6,w12
-       ror     w11,w11,#6
-       eor     w13,w7,w8
-       eor     w15,w15,w7,ror#20
-       add     v4.4s,v4.4s,v1.4s
-       add     w6,w6,w11
-       ldr     w12,[sp,#20]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w10,w10,w6
-       eor     w14,w14,w8
-       add     w5,w5,w12
-       add     w6,w6,w15
-       and     w12,w3,w10
-       bic     w15,w4,w10
-       eor     w11,w10,w10,ror#5
-       add     w6,w6,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w10,ror#19
-       eor     w15,w6,w6,ror#11
-       add     w5,w5,w12
-       ror     w11,w11,#6
-       eor     w14,w6,w7
-       eor     w15,w15,w6,ror#20
-       add     w5,w5,w11
-       ldr     w12,[sp,#24]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w9,w9,w5
-       eor     w13,w13,w7
-       add     w4,w4,w12
-       add     w5,w5,w15
-       and     w12,w10,w9
-       bic     w15,w3,w9
-       eor     w11,w9,w9,ror#5
-       add     w5,w5,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w9,ror#19
-       eor     w15,w5,w5,ror#11
-       add     w4,w4,w12
-       ror     w11,w11,#6
-       eor     w13,w5,w6
-       eor     w15,w15,w5,ror#20
-       add     w4,w4,w11
-       ldr     w12,[sp,#28]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w8,w8,w4
-       eor     w14,w14,w6
-       add     w3,w3,w12
-       add     w4,w4,w15
-       and     w12,w9,w8
-       bic     w15,w10,w8
-       eor     w11,w8,w8,ror#5
-       add     w4,w4,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w8,ror#19
-       eor     w15,w4,w4,ror#11
-       add     w3,w3,w12
-       ror     w11,w11,#6
-       eor     w14,w4,w5
-       eor     w15,w15,w4,ror#20
-       add     w3,w3,w11
-       ldr     w12,[sp,#32]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w7,w7,w3
-       eor     w13,w13,w5
-       st1     {v4.4s},[x17], #16
-       add     w10,w10,w12
-       add     w3,w3,w15
-       and     w12,w8,w7
-       ld1     {v2.16b},[x1],#16
-       bic     w15,w9,w7
-       eor     w11,w7,w7,ror#5
-       ld1     {v4.4s},[x16],#16
-       add     w3,w3,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w7,ror#19
-       eor     w15,w3,w3,ror#11
-       rev32   v2.16b,v2.16b
-       add     w10,w10,w12
-       ror     w11,w11,#6
-       eor     w13,w3,w4
-       eor     w15,w15,w3,ror#20
-       add     v4.4s,v4.4s,v2.4s
-       add     w10,w10,w11
-       ldr     w12,[sp,#36]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w6,w6,w10
-       eor     w14,w14,w4
-       add     w9,w9,w12
-       add     w10,w10,w15
-       and     w12,w7,w6
-       bic     w15,w8,w6
-       eor     w11,w6,w6,ror#5
-       add     w10,w10,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w6,ror#19
-       eor     w15,w10,w10,ror#11
-       add     w9,w9,w12
-       ror     w11,w11,#6
-       eor     w14,w10,w3
-       eor     w15,w15,w10,ror#20
-       add     w9,w9,w11
-       ldr     w12,[sp,#40]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w5,w5,w9
-       eor     w13,w13,w3
-       add     w8,w8,w12
-       add     w9,w9,w15
-       and     w12,w6,w5
-       bic     w15,w7,w5
-       eor     w11,w5,w5,ror#5
-       add     w9,w9,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w5,ror#19
-       eor     w15,w9,w9,ror#11
-       add     w8,w8,w12
-       ror     w11,w11,#6
-       eor     w13,w9,w10
-       eor     w15,w15,w9,ror#20
-       add     w8,w8,w11
-       ldr     w12,[sp,#44]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w4,w4,w8
-       eor     w14,w14,w10
-       add     w7,w7,w12
-       add     w8,w8,w15
-       and     w12,w5,w4
-       bic     w15,w6,w4
-       eor     w11,w4,w4,ror#5
-       add     w8,w8,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w4,ror#19
-       eor     w15,w8,w8,ror#11
-       add     w7,w7,w12
-       ror     w11,w11,#6
-       eor     w14,w8,w9
-       eor     w15,w15,w8,ror#20
-       add     w7,w7,w11
-       ldr     w12,[sp,#48]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w3,w3,w7
-       eor     w13,w13,w9
-       st1     {v4.4s},[x17], #16
-       add     w6,w6,w12
-       add     w7,w7,w15
-       and     w12,w4,w3
-       ld1     {v3.16b},[x1],#16
-       bic     w15,w5,w3
-       eor     w11,w3,w3,ror#5
-       ld1     {v4.4s},[x16],#16
-       add     w7,w7,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w3,ror#19
-       eor     w15,w7,w7,ror#11
-       rev32   v3.16b,v3.16b
-       add     w6,w6,w12
-       ror     w11,w11,#6
-       eor     w13,w7,w8
-       eor     w15,w15,w7,ror#20
-       add     v4.4s,v4.4s,v3.4s
-       add     w6,w6,w11
-       ldr     w12,[sp,#52]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w10,w10,w6
-       eor     w14,w14,w8
-       add     w5,w5,w12
-       add     w6,w6,w15
-       and     w12,w3,w10
-       bic     w15,w4,w10
-       eor     w11,w10,w10,ror#5
-       add     w6,w6,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w10,ror#19
-       eor     w15,w6,w6,ror#11
-       add     w5,w5,w12
-       ror     w11,w11,#6
-       eor     w14,w6,w7
-       eor     w15,w15,w6,ror#20
-       add     w5,w5,w11
-       ldr     w12,[sp,#56]
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w9,w9,w5
-       eor     w13,w13,w7
-       add     w4,w4,w12
-       add     w5,w5,w15
-       and     w12,w10,w9
-       bic     w15,w3,w9
-       eor     w11,w9,w9,ror#5
-       add     w5,w5,w13
-       orr     w12,w12,w15
-       eor     w11,w11,w9,ror#19
-       eor     w15,w5,w5,ror#11
-       add     w4,w4,w12
-       ror     w11,w11,#6
-       eor     w13,w5,w6
-       eor     w15,w15,w5,ror#20
-       add     w4,w4,w11
-       ldr     w12,[sp,#60]
-       and     w14,w14,w13
-       ror     w15,w15,#2
-       add     w8,w8,w4
-       eor     w14,w14,w6
-       add     w3,w3,w12
-       add     w4,w4,w15
-       and     w12,w9,w8
-       bic     w15,w10,w8
-       eor     w11,w8,w8,ror#5
-       add     w4,w4,w14
-       orr     w12,w12,w15
-       eor     w11,w11,w8,ror#19
-       eor     w15,w4,w4,ror#11
-       add     w3,w3,w12
-       ror     w11,w11,#6
-       eor     w14,w4,w5
-       eor     w15,w15,w4,ror#20
-       add     w3,w3,w11
-       and     w13,w13,w14
-       ror     w15,w15,#2
-       add     w7,w7,w3
-       eor     w13,w13,w5
-       st1     {v4.4s},[x17], #16
-       add     w3,w3,w15                       // h+=Sigma0(a) from the past
-       ldp     w11,w12,[x0,#0]
-       add     w3,w3,w13                       // h+=Maj(a,b,c) from the past
-       ldp     w13,w14,[x0,#8]
-       add     w3,w3,w11                       // accumulate
-       add     w4,w4,w12
-       ldp     w11,w12,[x0,#16]
-       add     w5,w5,w13
-       add     w6,w6,w14
-       ldp     w13,w14,[x0,#24]
-       add     w7,w7,w11
-       add     w8,w8,w12
-        ldr    w12,[sp,#0]
-       stp     w3,w4,[x0,#0]
-       add     w9,w9,w13
-        mov    w13,wzr
-       stp     w5,w6,[x0,#8]
-       add     w10,w10,w14
-       stp     w7,w8,[x0,#16]
-        eor    w14,w4,w5
-       stp     w9,w10,[x0,#24]
-        mov    w15,wzr
-        mov    x17,sp
-       b.ne    .L_00_48
-
-       ldr     x29,[x29]
-       add     sp,sp,#16*4+16
-       ret
-.size  sha256_block_neon,.-sha256_block_neon
-#ifndef        __KERNEL__
-.comm  OPENSSL_armcap_P,4,4
-#endif
diff --git a/arch/arm64/crypto/sha512-core.S_shipped b/arch/arm64/crypto/sha512-core.S_shipped
deleted file mode 100644 (file)
index e063a61..0000000
+++ /dev/null
@@ -1,1093 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-// This code is taken from the OpenSSL project but the author (Andy Polyakov)
-// has relicensed it under the GPLv2. Therefore 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.
-//
-// The original headers, including the original license headers, are
-// included below for completeness.
-
-// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
-//
-// Licensed under the OpenSSL license (the "License").  You may not use
-// this file except in compliance with the License.  You can obtain a copy
-// in the file LICENSE in the source distribution or at
-// https://www.openssl.org/source/license.html
-
-// ====================================================================
-// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
-// project. The module is, however, dual licensed under OpenSSL and
-// CRYPTOGAMS licenses depending on where you obtain it. For further
-// details see http://www.openssl.org/~appro/cryptogams/.
-// ====================================================================
-//
-// SHA256/512 for ARMv8.
-//
-// Performance in cycles per processed byte and improvement coefficient
-// over code generated with "default" compiler:
-//
-//             SHA256-hw       SHA256(*)       SHA512
-// Apple A7    1.97            10.5 (+33%)     6.73 (-1%(**))
-// Cortex-A53  2.38            15.5 (+115%)    10.0 (+150%(***))
-// Cortex-A57  2.31            11.6 (+86%)     7.51 (+260%(***))
-// Denver      2.01            10.5 (+26%)     6.70 (+8%)
-// X-Gene                      20.0 (+100%)    12.8 (+300%(***))
-// Mongoose    2.36            13.0 (+50%)     8.36 (+33%)
-//
-// (*) Software SHA256 results are of lesser relevance, presented
-//     mostly for informational purposes.
-// (**)        The result is a trade-off: it's possible to improve it by
-//     10% (or by 1 cycle per round), but at the cost of 20% loss
-//     on Cortex-A53 (or by 4 cycles per round).
-// (***)       Super-impressive coefficients over gcc-generated code are
-//     indication of some compiler "pathology", most notably code
-//     generated with -mgeneral-regs-only is significanty faster
-//     and the gap is only 40-90%.
-//
-// October 2016.
-//
-// Originally it was reckoned that it makes no sense to implement NEON
-// version of SHA256 for 64-bit processors. This is because performance
-// improvement on most wide-spread Cortex-A5x processors was observed
-// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
-// observed that 32-bit NEON SHA256 performs significantly better than
-// 64-bit scalar version on *some* of the more recent processors. As
-// result 64-bit NEON version of SHA256 was added to provide best
-// all-round performance. For example it executes ~30% faster on X-Gene
-// and Mongoose. [For reference, NEON version of SHA512 is bound to
-// deliver much less improvement, likely *negative* on Cortex-A5x.
-// Which is why NEON support is limited to SHA256.]
-
-#ifndef        __KERNEL__
-# include "arm_arch.h"
-#endif
-
-.text
-
-.extern        OPENSSL_armcap_P
-.globl sha512_block_data_order
-.type  sha512_block_data_order,%function
-.align 6
-sha512_block_data_order:
-       stp     x29,x30,[sp,#-128]!
-       add     x29,sp,#0
-
-       stp     x19,x20,[sp,#16]
-       stp     x21,x22,[sp,#32]
-       stp     x23,x24,[sp,#48]
-       stp     x25,x26,[sp,#64]
-       stp     x27,x28,[sp,#80]
-       sub     sp,sp,#4*8
-
-       ldp     x20,x21,[x0]                            // load context
-       ldp     x22,x23,[x0,#2*8]
-       ldp     x24,x25,[x0,#4*8]
-       add     x2,x1,x2,lsl#7  // end of input
-       ldp     x26,x27,[x0,#6*8]
-       adr     x30,.LK512
-       stp     x0,x2,[x29,#96]
-
-.Loop:
-       ldp     x3,x4,[x1],#2*8
-       ldr     x19,[x30],#8                    // *K++
-       eor     x28,x21,x22                             // magic seed
-       str     x1,[x29,#112]
-#ifndef        __AARCH64EB__
-       rev     x3,x3                   // 0
-#endif
-       ror     x16,x24,#14
-       add     x27,x27,x19                     // h+=K[i]
-       eor     x6,x24,x24,ror#23
-       and     x17,x25,x24
-       bic     x19,x26,x24
-       add     x27,x27,x3                      // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x20,x21                     // a^b, b^c in next round
-       eor     x16,x16,x6,ror#18       // Sigma1(e)
-       ror     x6,x20,#28
-       add     x27,x27,x17                     // h+=Ch(e,f,g)
-       eor     x17,x20,x20,ror#5
-       add     x27,x27,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x23,x23,x27                     // d+=h
-       eor     x28,x28,x21                     // Maj(a,b,c)
-       eor     x17,x6,x17,ror#34       // Sigma0(a)
-       add     x27,x27,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x27,x27,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x4,x4                   // 1
-#endif
-       ldp     x5,x6,[x1],#2*8
-       add     x27,x27,x17                     // h+=Sigma0(a)
-       ror     x16,x23,#14
-       add     x26,x26,x28                     // h+=K[i]
-       eor     x7,x23,x23,ror#23
-       and     x17,x24,x23
-       bic     x28,x25,x23
-       add     x26,x26,x4                      // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x27,x20                     // a^b, b^c in next round
-       eor     x16,x16,x7,ror#18       // Sigma1(e)
-       ror     x7,x27,#28
-       add     x26,x26,x17                     // h+=Ch(e,f,g)
-       eor     x17,x27,x27,ror#5
-       add     x26,x26,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x22,x22,x26                     // d+=h
-       eor     x19,x19,x20                     // Maj(a,b,c)
-       eor     x17,x7,x17,ror#34       // Sigma0(a)
-       add     x26,x26,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x26,x26,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x5,x5                   // 2
-#endif
-       add     x26,x26,x17                     // h+=Sigma0(a)
-       ror     x16,x22,#14
-       add     x25,x25,x19                     // h+=K[i]
-       eor     x8,x22,x22,ror#23
-       and     x17,x23,x22
-       bic     x19,x24,x22
-       add     x25,x25,x5                      // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x26,x27                     // a^b, b^c in next round
-       eor     x16,x16,x8,ror#18       // Sigma1(e)
-       ror     x8,x26,#28
-       add     x25,x25,x17                     // h+=Ch(e,f,g)
-       eor     x17,x26,x26,ror#5
-       add     x25,x25,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x21,x21,x25                     // d+=h
-       eor     x28,x28,x27                     // Maj(a,b,c)
-       eor     x17,x8,x17,ror#34       // Sigma0(a)
-       add     x25,x25,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x25,x25,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x6,x6                   // 3
-#endif
-       ldp     x7,x8,[x1],#2*8
-       add     x25,x25,x17                     // h+=Sigma0(a)
-       ror     x16,x21,#14
-       add     x24,x24,x28                     // h+=K[i]
-       eor     x9,x21,x21,ror#23
-       and     x17,x22,x21
-       bic     x28,x23,x21
-       add     x24,x24,x6                      // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x25,x26                     // a^b, b^c in next round
-       eor     x16,x16,x9,ror#18       // Sigma1(e)
-       ror     x9,x25,#28
-       add     x24,x24,x17                     // h+=Ch(e,f,g)
-       eor     x17,x25,x25,ror#5
-       add     x24,x24,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x20,x20,x24                     // d+=h
-       eor     x19,x19,x26                     // Maj(a,b,c)
-       eor     x17,x9,x17,ror#34       // Sigma0(a)
-       add     x24,x24,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x24,x24,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x7,x7                   // 4
-#endif
-       add     x24,x24,x17                     // h+=Sigma0(a)
-       ror     x16,x20,#14
-       add     x23,x23,x19                     // h+=K[i]
-       eor     x10,x20,x20,ror#23
-       and     x17,x21,x20
-       bic     x19,x22,x20
-       add     x23,x23,x7                      // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x24,x25                     // a^b, b^c in next round
-       eor     x16,x16,x10,ror#18      // Sigma1(e)
-       ror     x10,x24,#28
-       add     x23,x23,x17                     // h+=Ch(e,f,g)
-       eor     x17,x24,x24,ror#5
-       add     x23,x23,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x27,x27,x23                     // d+=h
-       eor     x28,x28,x25                     // Maj(a,b,c)
-       eor     x17,x10,x17,ror#34      // Sigma0(a)
-       add     x23,x23,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x23,x23,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x8,x8                   // 5
-#endif
-       ldp     x9,x10,[x1],#2*8
-       add     x23,x23,x17                     // h+=Sigma0(a)
-       ror     x16,x27,#14
-       add     x22,x22,x28                     // h+=K[i]
-       eor     x11,x27,x27,ror#23
-       and     x17,x20,x27
-       bic     x28,x21,x27
-       add     x22,x22,x8                      // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x23,x24                     // a^b, b^c in next round
-       eor     x16,x16,x11,ror#18      // Sigma1(e)
-       ror     x11,x23,#28
-       add     x22,x22,x17                     // h+=Ch(e,f,g)
-       eor     x17,x23,x23,ror#5
-       add     x22,x22,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x26,x26,x22                     // d+=h
-       eor     x19,x19,x24                     // Maj(a,b,c)
-       eor     x17,x11,x17,ror#34      // Sigma0(a)
-       add     x22,x22,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x22,x22,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x9,x9                   // 6
-#endif
-       add     x22,x22,x17                     // h+=Sigma0(a)
-       ror     x16,x26,#14
-       add     x21,x21,x19                     // h+=K[i]
-       eor     x12,x26,x26,ror#23
-       and     x17,x27,x26
-       bic     x19,x20,x26
-       add     x21,x21,x9                      // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x22,x23                     // a^b, b^c in next round
-       eor     x16,x16,x12,ror#18      // Sigma1(e)
-       ror     x12,x22,#28
-       add     x21,x21,x17                     // h+=Ch(e,f,g)
-       eor     x17,x22,x22,ror#5
-       add     x21,x21,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x25,x25,x21                     // d+=h
-       eor     x28,x28,x23                     // Maj(a,b,c)
-       eor     x17,x12,x17,ror#34      // Sigma0(a)
-       add     x21,x21,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x21,x21,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x10,x10                 // 7
-#endif
-       ldp     x11,x12,[x1],#2*8
-       add     x21,x21,x17                     // h+=Sigma0(a)
-       ror     x16,x25,#14
-       add     x20,x20,x28                     // h+=K[i]
-       eor     x13,x25,x25,ror#23
-       and     x17,x26,x25
-       bic     x28,x27,x25
-       add     x20,x20,x10                     // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x21,x22                     // a^b, b^c in next round
-       eor     x16,x16,x13,ror#18      // Sigma1(e)
-       ror     x13,x21,#28
-       add     x20,x20,x17                     // h+=Ch(e,f,g)
-       eor     x17,x21,x21,ror#5
-       add     x20,x20,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x24,x24,x20                     // d+=h
-       eor     x19,x19,x22                     // Maj(a,b,c)
-       eor     x17,x13,x17,ror#34      // Sigma0(a)
-       add     x20,x20,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x20,x20,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x11,x11                 // 8
-#endif
-       add     x20,x20,x17                     // h+=Sigma0(a)
-       ror     x16,x24,#14
-       add     x27,x27,x19                     // h+=K[i]
-       eor     x14,x24,x24,ror#23
-       and     x17,x25,x24
-       bic     x19,x26,x24
-       add     x27,x27,x11                     // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x20,x21                     // a^b, b^c in next round
-       eor     x16,x16,x14,ror#18      // Sigma1(e)
-       ror     x14,x20,#28
-       add     x27,x27,x17                     // h+=Ch(e,f,g)
-       eor     x17,x20,x20,ror#5
-       add     x27,x27,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x23,x23,x27                     // d+=h
-       eor     x28,x28,x21                     // Maj(a,b,c)
-       eor     x17,x14,x17,ror#34      // Sigma0(a)
-       add     x27,x27,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x27,x27,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x12,x12                 // 9
-#endif
-       ldp     x13,x14,[x1],#2*8
-       add     x27,x27,x17                     // h+=Sigma0(a)
-       ror     x16,x23,#14
-       add     x26,x26,x28                     // h+=K[i]
-       eor     x15,x23,x23,ror#23
-       and     x17,x24,x23
-       bic     x28,x25,x23
-       add     x26,x26,x12                     // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x27,x20                     // a^b, b^c in next round
-       eor     x16,x16,x15,ror#18      // Sigma1(e)
-       ror     x15,x27,#28
-       add     x26,x26,x17                     // h+=Ch(e,f,g)
-       eor     x17,x27,x27,ror#5
-       add     x26,x26,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x22,x22,x26                     // d+=h
-       eor     x19,x19,x20                     // Maj(a,b,c)
-       eor     x17,x15,x17,ror#34      // Sigma0(a)
-       add     x26,x26,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x26,x26,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x13,x13                 // 10
-#endif
-       add     x26,x26,x17                     // h+=Sigma0(a)
-       ror     x16,x22,#14
-       add     x25,x25,x19                     // h+=K[i]
-       eor     x0,x22,x22,ror#23
-       and     x17,x23,x22
-       bic     x19,x24,x22
-       add     x25,x25,x13                     // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x26,x27                     // a^b, b^c in next round
-       eor     x16,x16,x0,ror#18       // Sigma1(e)
-       ror     x0,x26,#28
-       add     x25,x25,x17                     // h+=Ch(e,f,g)
-       eor     x17,x26,x26,ror#5
-       add     x25,x25,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x21,x21,x25                     // d+=h
-       eor     x28,x28,x27                     // Maj(a,b,c)
-       eor     x17,x0,x17,ror#34       // Sigma0(a)
-       add     x25,x25,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x25,x25,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x14,x14                 // 11
-#endif
-       ldp     x15,x0,[x1],#2*8
-       add     x25,x25,x17                     // h+=Sigma0(a)
-       str     x6,[sp,#24]
-       ror     x16,x21,#14
-       add     x24,x24,x28                     // h+=K[i]
-       eor     x6,x21,x21,ror#23
-       and     x17,x22,x21
-       bic     x28,x23,x21
-       add     x24,x24,x14                     // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x25,x26                     // a^b, b^c in next round
-       eor     x16,x16,x6,ror#18       // Sigma1(e)
-       ror     x6,x25,#28
-       add     x24,x24,x17                     // h+=Ch(e,f,g)
-       eor     x17,x25,x25,ror#5
-       add     x24,x24,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x20,x20,x24                     // d+=h
-       eor     x19,x19,x26                     // Maj(a,b,c)
-       eor     x17,x6,x17,ror#34       // Sigma0(a)
-       add     x24,x24,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x24,x24,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x15,x15                 // 12
-#endif
-       add     x24,x24,x17                     // h+=Sigma0(a)
-       str     x7,[sp,#0]
-       ror     x16,x20,#14
-       add     x23,x23,x19                     // h+=K[i]
-       eor     x7,x20,x20,ror#23
-       and     x17,x21,x20
-       bic     x19,x22,x20
-       add     x23,x23,x15                     // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x24,x25                     // a^b, b^c in next round
-       eor     x16,x16,x7,ror#18       // Sigma1(e)
-       ror     x7,x24,#28
-       add     x23,x23,x17                     // h+=Ch(e,f,g)
-       eor     x17,x24,x24,ror#5
-       add     x23,x23,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x27,x27,x23                     // d+=h
-       eor     x28,x28,x25                     // Maj(a,b,c)
-       eor     x17,x7,x17,ror#34       // Sigma0(a)
-       add     x23,x23,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x23,x23,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x0,x0                   // 13
-#endif
-       ldp     x1,x2,[x1]
-       add     x23,x23,x17                     // h+=Sigma0(a)
-       str     x8,[sp,#8]
-       ror     x16,x27,#14
-       add     x22,x22,x28                     // h+=K[i]
-       eor     x8,x27,x27,ror#23
-       and     x17,x20,x27
-       bic     x28,x21,x27
-       add     x22,x22,x0                      // h+=X[i]
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x23,x24                     // a^b, b^c in next round
-       eor     x16,x16,x8,ror#18       // Sigma1(e)
-       ror     x8,x23,#28
-       add     x22,x22,x17                     // h+=Ch(e,f,g)
-       eor     x17,x23,x23,ror#5
-       add     x22,x22,x16                     // h+=Sigma1(e)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       add     x26,x26,x22                     // d+=h
-       eor     x19,x19,x24                     // Maj(a,b,c)
-       eor     x17,x8,x17,ror#34       // Sigma0(a)
-       add     x22,x22,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       //add   x22,x22,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x1,x1                   // 14
-#endif
-       ldr     x6,[sp,#24]
-       add     x22,x22,x17                     // h+=Sigma0(a)
-       str     x9,[sp,#16]
-       ror     x16,x26,#14
-       add     x21,x21,x19                     // h+=K[i]
-       eor     x9,x26,x26,ror#23
-       and     x17,x27,x26
-       bic     x19,x20,x26
-       add     x21,x21,x1                      // h+=X[i]
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x22,x23                     // a^b, b^c in next round
-       eor     x16,x16,x9,ror#18       // Sigma1(e)
-       ror     x9,x22,#28
-       add     x21,x21,x17                     // h+=Ch(e,f,g)
-       eor     x17,x22,x22,ror#5
-       add     x21,x21,x16                     // h+=Sigma1(e)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       add     x25,x25,x21                     // d+=h
-       eor     x28,x28,x23                     // Maj(a,b,c)
-       eor     x17,x9,x17,ror#34       // Sigma0(a)
-       add     x21,x21,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       //add   x21,x21,x17                     // h+=Sigma0(a)
-#ifndef        __AARCH64EB__
-       rev     x2,x2                   // 15
-#endif
-       ldr     x7,[sp,#0]
-       add     x21,x21,x17                     // h+=Sigma0(a)
-       str     x10,[sp,#24]
-       ror     x16,x25,#14
-       add     x20,x20,x28                     // h+=K[i]
-       ror     x9,x4,#1
-       and     x17,x26,x25
-       ror     x8,x1,#19
-       bic     x28,x27,x25
-       ror     x10,x21,#28
-       add     x20,x20,x2                      // h+=X[i]
-       eor     x16,x16,x25,ror#18
-       eor     x9,x9,x4,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x21,x22                     // a^b, b^c in next round
-       eor     x16,x16,x25,ror#41      // Sigma1(e)
-       eor     x10,x10,x21,ror#34
-       add     x20,x20,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x8,x8,x1,ror#61
-       eor     x9,x9,x4,lsr#7  // sigma0(X[i+1])
-       add     x20,x20,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x22                     // Maj(a,b,c)
-       eor     x17,x10,x21,ror#39      // Sigma0(a)
-       eor     x8,x8,x1,lsr#6  // sigma1(X[i+14])
-       add     x3,x3,x12
-       add     x24,x24,x20                     // d+=h
-       add     x20,x20,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x3,x3,x9
-       add     x20,x20,x17                     // h+=Sigma0(a)
-       add     x3,x3,x8
-.Loop_16_xx:
-       ldr     x8,[sp,#8]
-       str     x11,[sp,#0]
-       ror     x16,x24,#14
-       add     x27,x27,x19                     // h+=K[i]
-       ror     x10,x5,#1
-       and     x17,x25,x24
-       ror     x9,x2,#19
-       bic     x19,x26,x24
-       ror     x11,x20,#28
-       add     x27,x27,x3                      // h+=X[i]
-       eor     x16,x16,x24,ror#18
-       eor     x10,x10,x5,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x20,x21                     // a^b, b^c in next round
-       eor     x16,x16,x24,ror#41      // Sigma1(e)
-       eor     x11,x11,x20,ror#34
-       add     x27,x27,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x9,x9,x2,ror#61
-       eor     x10,x10,x5,lsr#7        // sigma0(X[i+1])
-       add     x27,x27,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x21                     // Maj(a,b,c)
-       eor     x17,x11,x20,ror#39      // Sigma0(a)
-       eor     x9,x9,x2,lsr#6  // sigma1(X[i+14])
-       add     x4,x4,x13
-       add     x23,x23,x27                     // d+=h
-       add     x27,x27,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x4,x4,x10
-       add     x27,x27,x17                     // h+=Sigma0(a)
-       add     x4,x4,x9
-       ldr     x9,[sp,#16]
-       str     x12,[sp,#8]
-       ror     x16,x23,#14
-       add     x26,x26,x28                     // h+=K[i]
-       ror     x11,x6,#1
-       and     x17,x24,x23
-       ror     x10,x3,#19
-       bic     x28,x25,x23
-       ror     x12,x27,#28
-       add     x26,x26,x4                      // h+=X[i]
-       eor     x16,x16,x23,ror#18
-       eor     x11,x11,x6,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x27,x20                     // a^b, b^c in next round
-       eor     x16,x16,x23,ror#41      // Sigma1(e)
-       eor     x12,x12,x27,ror#34
-       add     x26,x26,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x10,x10,x3,ror#61
-       eor     x11,x11,x6,lsr#7        // sigma0(X[i+1])
-       add     x26,x26,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x20                     // Maj(a,b,c)
-       eor     x17,x12,x27,ror#39      // Sigma0(a)
-       eor     x10,x10,x3,lsr#6        // sigma1(X[i+14])
-       add     x5,x5,x14
-       add     x22,x22,x26                     // d+=h
-       add     x26,x26,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x5,x5,x11
-       add     x26,x26,x17                     // h+=Sigma0(a)
-       add     x5,x5,x10
-       ldr     x10,[sp,#24]
-       str     x13,[sp,#16]
-       ror     x16,x22,#14
-       add     x25,x25,x19                     // h+=K[i]
-       ror     x12,x7,#1
-       and     x17,x23,x22
-       ror     x11,x4,#19
-       bic     x19,x24,x22
-       ror     x13,x26,#28
-       add     x25,x25,x5                      // h+=X[i]
-       eor     x16,x16,x22,ror#18
-       eor     x12,x12,x7,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x26,x27                     // a^b, b^c in next round
-       eor     x16,x16,x22,ror#41      // Sigma1(e)
-       eor     x13,x13,x26,ror#34
-       add     x25,x25,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x11,x11,x4,ror#61
-       eor     x12,x12,x7,lsr#7        // sigma0(X[i+1])
-       add     x25,x25,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x27                     // Maj(a,b,c)
-       eor     x17,x13,x26,ror#39      // Sigma0(a)
-       eor     x11,x11,x4,lsr#6        // sigma1(X[i+14])
-       add     x6,x6,x15
-       add     x21,x21,x25                     // d+=h
-       add     x25,x25,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x6,x6,x12
-       add     x25,x25,x17                     // h+=Sigma0(a)
-       add     x6,x6,x11
-       ldr     x11,[sp,#0]
-       str     x14,[sp,#24]
-       ror     x16,x21,#14
-       add     x24,x24,x28                     // h+=K[i]
-       ror     x13,x8,#1
-       and     x17,x22,x21
-       ror     x12,x5,#19
-       bic     x28,x23,x21
-       ror     x14,x25,#28
-       add     x24,x24,x6                      // h+=X[i]
-       eor     x16,x16,x21,ror#18
-       eor     x13,x13,x8,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x25,x26                     // a^b, b^c in next round
-       eor     x16,x16,x21,ror#41      // Sigma1(e)
-       eor     x14,x14,x25,ror#34
-       add     x24,x24,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x12,x12,x5,ror#61
-       eor     x13,x13,x8,lsr#7        // sigma0(X[i+1])
-       add     x24,x24,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x26                     // Maj(a,b,c)
-       eor     x17,x14,x25,ror#39      // Sigma0(a)
-       eor     x12,x12,x5,lsr#6        // sigma1(X[i+14])
-       add     x7,x7,x0
-       add     x20,x20,x24                     // d+=h
-       add     x24,x24,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x7,x7,x13
-       add     x24,x24,x17                     // h+=Sigma0(a)
-       add     x7,x7,x12
-       ldr     x12,[sp,#8]
-       str     x15,[sp,#0]
-       ror     x16,x20,#14
-       add     x23,x23,x19                     // h+=K[i]
-       ror     x14,x9,#1
-       and     x17,x21,x20
-       ror     x13,x6,#19
-       bic     x19,x22,x20
-       ror     x15,x24,#28
-       add     x23,x23,x7                      // h+=X[i]
-       eor     x16,x16,x20,ror#18
-       eor     x14,x14,x9,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x24,x25                     // a^b, b^c in next round
-       eor     x16,x16,x20,ror#41      // Sigma1(e)
-       eor     x15,x15,x24,ror#34
-       add     x23,x23,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x13,x13,x6,ror#61
-       eor     x14,x14,x9,lsr#7        // sigma0(X[i+1])
-       add     x23,x23,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x25                     // Maj(a,b,c)
-       eor     x17,x15,x24,ror#39      // Sigma0(a)
-       eor     x13,x13,x6,lsr#6        // sigma1(X[i+14])
-       add     x8,x8,x1
-       add     x27,x27,x23                     // d+=h
-       add     x23,x23,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x8,x8,x14
-       add     x23,x23,x17                     // h+=Sigma0(a)
-       add     x8,x8,x13
-       ldr     x13,[sp,#16]
-       str     x0,[sp,#8]
-       ror     x16,x27,#14
-       add     x22,x22,x28                     // h+=K[i]
-       ror     x15,x10,#1
-       and     x17,x20,x27
-       ror     x14,x7,#19
-       bic     x28,x21,x27
-       ror     x0,x23,#28
-       add     x22,x22,x8                      // h+=X[i]
-       eor     x16,x16,x27,ror#18
-       eor     x15,x15,x10,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x23,x24                     // a^b, b^c in next round
-       eor     x16,x16,x27,ror#41      // Sigma1(e)
-       eor     x0,x0,x23,ror#34
-       add     x22,x22,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x14,x14,x7,ror#61
-       eor     x15,x15,x10,lsr#7       // sigma0(X[i+1])
-       add     x22,x22,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x24                     // Maj(a,b,c)
-       eor     x17,x0,x23,ror#39       // Sigma0(a)
-       eor     x14,x14,x7,lsr#6        // sigma1(X[i+14])
-       add     x9,x9,x2
-       add     x26,x26,x22                     // d+=h
-       add     x22,x22,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x9,x9,x15
-       add     x22,x22,x17                     // h+=Sigma0(a)
-       add     x9,x9,x14
-       ldr     x14,[sp,#24]
-       str     x1,[sp,#16]
-       ror     x16,x26,#14
-       add     x21,x21,x19                     // h+=K[i]
-       ror     x0,x11,#1
-       and     x17,x27,x26
-       ror     x15,x8,#19
-       bic     x19,x20,x26
-       ror     x1,x22,#28
-       add     x21,x21,x9                      // h+=X[i]
-       eor     x16,x16,x26,ror#18
-       eor     x0,x0,x11,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x22,x23                     // a^b, b^c in next round
-       eor     x16,x16,x26,ror#41      // Sigma1(e)
-       eor     x1,x1,x22,ror#34
-       add     x21,x21,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x15,x15,x8,ror#61
-       eor     x0,x0,x11,lsr#7 // sigma0(X[i+1])
-       add     x21,x21,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x23                     // Maj(a,b,c)
-       eor     x17,x1,x22,ror#39       // Sigma0(a)
-       eor     x15,x15,x8,lsr#6        // sigma1(X[i+14])
-       add     x10,x10,x3
-       add     x25,x25,x21                     // d+=h
-       add     x21,x21,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x10,x10,x0
-       add     x21,x21,x17                     // h+=Sigma0(a)
-       add     x10,x10,x15
-       ldr     x15,[sp,#0]
-       str     x2,[sp,#24]
-       ror     x16,x25,#14
-       add     x20,x20,x28                     // h+=K[i]
-       ror     x1,x12,#1
-       and     x17,x26,x25
-       ror     x0,x9,#19
-       bic     x28,x27,x25
-       ror     x2,x21,#28
-       add     x20,x20,x10                     // h+=X[i]
-       eor     x16,x16,x25,ror#18
-       eor     x1,x1,x12,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x21,x22                     // a^b, b^c in next round
-       eor     x16,x16,x25,ror#41      // Sigma1(e)
-       eor     x2,x2,x21,ror#34
-       add     x20,x20,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x0,x0,x9,ror#61
-       eor     x1,x1,x12,lsr#7 // sigma0(X[i+1])
-       add     x20,x20,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x22                     // Maj(a,b,c)
-       eor     x17,x2,x21,ror#39       // Sigma0(a)
-       eor     x0,x0,x9,lsr#6  // sigma1(X[i+14])
-       add     x11,x11,x4
-       add     x24,x24,x20                     // d+=h
-       add     x20,x20,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x11,x11,x1
-       add     x20,x20,x17                     // h+=Sigma0(a)
-       add     x11,x11,x0
-       ldr     x0,[sp,#8]
-       str     x3,[sp,#0]
-       ror     x16,x24,#14
-       add     x27,x27,x19                     // h+=K[i]
-       ror     x2,x13,#1
-       and     x17,x25,x24
-       ror     x1,x10,#19
-       bic     x19,x26,x24
-       ror     x3,x20,#28
-       add     x27,x27,x11                     // h+=X[i]
-       eor     x16,x16,x24,ror#18
-       eor     x2,x2,x13,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x20,x21                     // a^b, b^c in next round
-       eor     x16,x16,x24,ror#41      // Sigma1(e)
-       eor     x3,x3,x20,ror#34
-       add     x27,x27,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x1,x1,x10,ror#61
-       eor     x2,x2,x13,lsr#7 // sigma0(X[i+1])
-       add     x27,x27,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x21                     // Maj(a,b,c)
-       eor     x17,x3,x20,ror#39       // Sigma0(a)
-       eor     x1,x1,x10,lsr#6 // sigma1(X[i+14])
-       add     x12,x12,x5
-       add     x23,x23,x27                     // d+=h
-       add     x27,x27,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x12,x12,x2
-       add     x27,x27,x17                     // h+=Sigma0(a)
-       add     x12,x12,x1
-       ldr     x1,[sp,#16]
-       str     x4,[sp,#8]
-       ror     x16,x23,#14
-       add     x26,x26,x28                     // h+=K[i]
-       ror     x3,x14,#1
-       and     x17,x24,x23
-       ror     x2,x11,#19
-       bic     x28,x25,x23
-       ror     x4,x27,#28
-       add     x26,x26,x12                     // h+=X[i]
-       eor     x16,x16,x23,ror#18
-       eor     x3,x3,x14,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x27,x20                     // a^b, b^c in next round
-       eor     x16,x16,x23,ror#41      // Sigma1(e)
-       eor     x4,x4,x27,ror#34
-       add     x26,x26,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x2,x2,x11,ror#61
-       eor     x3,x3,x14,lsr#7 // sigma0(X[i+1])
-       add     x26,x26,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x20                     // Maj(a,b,c)
-       eor     x17,x4,x27,ror#39       // Sigma0(a)
-       eor     x2,x2,x11,lsr#6 // sigma1(X[i+14])
-       add     x13,x13,x6
-       add     x22,x22,x26                     // d+=h
-       add     x26,x26,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x13,x13,x3
-       add     x26,x26,x17                     // h+=Sigma0(a)
-       add     x13,x13,x2
-       ldr     x2,[sp,#24]
-       str     x5,[sp,#16]
-       ror     x16,x22,#14
-       add     x25,x25,x19                     // h+=K[i]
-       ror     x4,x15,#1
-       and     x17,x23,x22
-       ror     x3,x12,#19
-       bic     x19,x24,x22
-       ror     x5,x26,#28
-       add     x25,x25,x13                     // h+=X[i]
-       eor     x16,x16,x22,ror#18
-       eor     x4,x4,x15,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x26,x27                     // a^b, b^c in next round
-       eor     x16,x16,x22,ror#41      // Sigma1(e)
-       eor     x5,x5,x26,ror#34
-       add     x25,x25,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x3,x3,x12,ror#61
-       eor     x4,x4,x15,lsr#7 // sigma0(X[i+1])
-       add     x25,x25,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x27                     // Maj(a,b,c)
-       eor     x17,x5,x26,ror#39       // Sigma0(a)
-       eor     x3,x3,x12,lsr#6 // sigma1(X[i+14])
-       add     x14,x14,x7
-       add     x21,x21,x25                     // d+=h
-       add     x25,x25,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x14,x14,x4
-       add     x25,x25,x17                     // h+=Sigma0(a)
-       add     x14,x14,x3
-       ldr     x3,[sp,#0]
-       str     x6,[sp,#24]
-       ror     x16,x21,#14
-       add     x24,x24,x28                     // h+=K[i]
-       ror     x5,x0,#1
-       and     x17,x22,x21
-       ror     x4,x13,#19
-       bic     x28,x23,x21
-       ror     x6,x25,#28
-       add     x24,x24,x14                     // h+=X[i]
-       eor     x16,x16,x21,ror#18
-       eor     x5,x5,x0,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x25,x26                     // a^b, b^c in next round
-       eor     x16,x16,x21,ror#41      // Sigma1(e)
-       eor     x6,x6,x25,ror#34
-       add     x24,x24,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x4,x4,x13,ror#61
-       eor     x5,x5,x0,lsr#7  // sigma0(X[i+1])
-       add     x24,x24,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x26                     // Maj(a,b,c)
-       eor     x17,x6,x25,ror#39       // Sigma0(a)
-       eor     x4,x4,x13,lsr#6 // sigma1(X[i+14])
-       add     x15,x15,x8
-       add     x20,x20,x24                     // d+=h
-       add     x24,x24,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x15,x15,x5
-       add     x24,x24,x17                     // h+=Sigma0(a)
-       add     x15,x15,x4
-       ldr     x4,[sp,#8]
-       str     x7,[sp,#0]
-       ror     x16,x20,#14
-       add     x23,x23,x19                     // h+=K[i]
-       ror     x6,x1,#1
-       and     x17,x21,x20
-       ror     x5,x14,#19
-       bic     x19,x22,x20
-       ror     x7,x24,#28
-       add     x23,x23,x15                     // h+=X[i]
-       eor     x16,x16,x20,ror#18
-       eor     x6,x6,x1,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x24,x25                     // a^b, b^c in next round
-       eor     x16,x16,x20,ror#41      // Sigma1(e)
-       eor     x7,x7,x24,ror#34
-       add     x23,x23,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x5,x5,x14,ror#61
-       eor     x6,x6,x1,lsr#7  // sigma0(X[i+1])
-       add     x23,x23,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x25                     // Maj(a,b,c)
-       eor     x17,x7,x24,ror#39       // Sigma0(a)
-       eor     x5,x5,x14,lsr#6 // sigma1(X[i+14])
-       add     x0,x0,x9
-       add     x27,x27,x23                     // d+=h
-       add     x23,x23,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x0,x0,x6
-       add     x23,x23,x17                     // h+=Sigma0(a)
-       add     x0,x0,x5
-       ldr     x5,[sp,#16]
-       str     x8,[sp,#8]
-       ror     x16,x27,#14
-       add     x22,x22,x28                     // h+=K[i]
-       ror     x7,x2,#1
-       and     x17,x20,x27
-       ror     x6,x15,#19
-       bic     x28,x21,x27
-       ror     x8,x23,#28
-       add     x22,x22,x0                      // h+=X[i]
-       eor     x16,x16,x27,ror#18
-       eor     x7,x7,x2,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x23,x24                     // a^b, b^c in next round
-       eor     x16,x16,x27,ror#41      // Sigma1(e)
-       eor     x8,x8,x23,ror#34
-       add     x22,x22,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x6,x6,x15,ror#61
-       eor     x7,x7,x2,lsr#7  // sigma0(X[i+1])
-       add     x22,x22,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x24                     // Maj(a,b,c)
-       eor     x17,x8,x23,ror#39       // Sigma0(a)
-       eor     x6,x6,x15,lsr#6 // sigma1(X[i+14])
-       add     x1,x1,x10
-       add     x26,x26,x22                     // d+=h
-       add     x22,x22,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x1,x1,x7
-       add     x22,x22,x17                     // h+=Sigma0(a)
-       add     x1,x1,x6
-       ldr     x6,[sp,#24]
-       str     x9,[sp,#16]
-       ror     x16,x26,#14
-       add     x21,x21,x19                     // h+=K[i]
-       ror     x8,x3,#1
-       and     x17,x27,x26
-       ror     x7,x0,#19
-       bic     x19,x20,x26
-       ror     x9,x22,#28
-       add     x21,x21,x1                      // h+=X[i]
-       eor     x16,x16,x26,ror#18
-       eor     x8,x8,x3,ror#8
-       orr     x17,x17,x19                     // Ch(e,f,g)
-       eor     x19,x22,x23                     // a^b, b^c in next round
-       eor     x16,x16,x26,ror#41      // Sigma1(e)
-       eor     x9,x9,x22,ror#34
-       add     x21,x21,x17                     // h+=Ch(e,f,g)
-       and     x28,x28,x19                     // (b^c)&=(a^b)
-       eor     x7,x7,x0,ror#61
-       eor     x8,x8,x3,lsr#7  // sigma0(X[i+1])
-       add     x21,x21,x16                     // h+=Sigma1(e)
-       eor     x28,x28,x23                     // Maj(a,b,c)
-       eor     x17,x9,x22,ror#39       // Sigma0(a)
-       eor     x7,x7,x0,lsr#6  // sigma1(X[i+14])
-       add     x2,x2,x11
-       add     x25,x25,x21                     // d+=h
-       add     x21,x21,x28                     // h+=Maj(a,b,c)
-       ldr     x28,[x30],#8            // *K++, x19 in next round
-       add     x2,x2,x8
-       add     x21,x21,x17                     // h+=Sigma0(a)
-       add     x2,x2,x7
-       ldr     x7,[sp,#0]
-       str     x10,[sp,#24]
-       ror     x16,x25,#14
-       add     x20,x20,x28                     // h+=K[i]
-       ror     x9,x4,#1
-       and     x17,x26,x25
-       ror     x8,x1,#19
-       bic     x28,x27,x25
-       ror     x10,x21,#28
-       add     x20,x20,x2                      // h+=X[i]
-       eor     x16,x16,x25,ror#18
-       eor     x9,x9,x4,ror#8
-       orr     x17,x17,x28                     // Ch(e,f,g)
-       eor     x28,x21,x22                     // a^b, b^c in next round
-       eor     x16,x16,x25,ror#41      // Sigma1(e)
-       eor     x10,x10,x21,ror#34
-       add     x20,x20,x17                     // h+=Ch(e,f,g)
-       and     x19,x19,x28                     // (b^c)&=(a^b)
-       eor     x8,x8,x1,ror#61
-       eor     x9,x9,x4,lsr#7  // sigma0(X[i+1])
-       add     x20,x20,x16                     // h+=Sigma1(e)
-       eor     x19,x19,x22                     // Maj(a,b,c)
-       eor     x17,x10,x21,ror#39      // Sigma0(a)
-       eor     x8,x8,x1,lsr#6  // sigma1(X[i+14])
-       add     x3,x3,x12
-       add     x24,x24,x20                     // d+=h
-       add     x20,x20,x19                     // h+=Maj(a,b,c)
-       ldr     x19,[x30],#8            // *K++, x28 in next round
-       add     x3,x3,x9
-       add     x20,x20,x17                     // h+=Sigma0(a)
-       add     x3,x3,x8
-       cbnz    x19,.Loop_16_xx
-
-       ldp     x0,x2,[x29,#96]
-       ldr     x1,[x29,#112]
-       sub     x30,x30,#648            // rewind
-
-       ldp     x3,x4,[x0]
-       ldp     x5,x6,[x0,#2*8]
-       add     x1,x1,#14*8                     // advance input pointer
-       ldp     x7,x8,[x0,#4*8]
-       add     x20,x20,x3
-       ldp     x9,x10,[x0,#6*8]
-       add     x21,x21,x4
-       add     x22,x22,x5
-       add     x23,x23,x6
-       stp     x20,x21,[x0]
-       add     x24,x24,x7
-       add     x25,x25,x8
-       stp     x22,x23,[x0,#2*8]
-       add     x26,x26,x9
-       add     x27,x27,x10
-       cmp     x1,x2
-       stp     x24,x25,[x0,#4*8]
-       stp     x26,x27,[x0,#6*8]
-       b.ne    .Loop
-
-       ldp     x19,x20,[x29,#16]
-       add     sp,sp,#4*8
-       ldp     x21,x22,[x29,#32]
-       ldp     x23,x24,[x29,#48]
-       ldp     x25,x26,[x29,#64]
-       ldp     x27,x28,[x29,#80]
-       ldp     x29,x30,[sp],#128
-       ret
-.size  sha512_block_data_order,.-sha512_block_data_order
-
-.align 6
-.type  .LK512,%object
-.LK512:
-       .quad   0x428a2f98d728ae22,0x7137449123ef65cd
-       .quad   0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
-       .quad   0x3956c25bf348b538,0x59f111f1b605d019
-       .quad   0x923f82a4af194f9b,0xab1c5ed5da6d8118
-       .quad   0xd807aa98a3030242,0x12835b0145706fbe
-       .quad   0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
-       .quad   0x72be5d74f27b896f,0x80deb1fe3b1696b1
-       .quad   0x9bdc06a725c71235,0xc19bf174cf692694
-       .quad   0xe49b69c19ef14ad2,0xefbe4786384f25e3
-       .quad   0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
-       .quad   0x2de92c6f592b0275,0x4a7484aa6ea6e483
-       .quad   0x5cb0a9dcbd41fbd4,0x76f988da831153b5
-       .quad   0x983e5152ee66dfab,0xa831c66d2db43210
-       .quad   0xb00327c898fb213f,0xbf597fc7beef0ee4
-       .quad   0xc6e00bf33da88fc2,0xd5a79147930aa725
-       .quad   0x06ca6351e003826f,0x142929670a0e6e70
-       .quad   0x27b70a8546d22ffc,0x2e1b21385c26c926
-       .quad   0x4d2c6dfc5ac42aed,0x53380d139d95b3df
-       .quad   0x650a73548baf63de,0x766a0abb3c77b2a8
-       .quad   0x81c2c92e47edaee6,0x92722c851482353b
-       .quad   0xa2bfe8a14cf10364,0xa81a664bbc423001
-       .quad   0xc24b8b70d0f89791,0xc76c51a30654be30
-       .quad   0xd192e819d6ef5218,0xd69906245565a910
-       .quad   0xf40e35855771202a,0x106aa07032bbd1b8
-       .quad   0x19a4c116b8d2d0c8,0x1e376c085141ab53
-       .quad   0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
-       .quad   0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
-       .quad   0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
-       .quad   0x748f82ee5defb2fc,0x78a5636f43172f60
-       .quad   0x84c87814a1f0ab72,0x8cc702081a6439ec
-       .quad   0x90befffa23631e28,0xa4506cebde82bde9
-       .quad   0xbef9a3f7b2c67915,0xc67178f2e372532b
-       .quad   0xca273eceea26619c,0xd186b8c721c0c207
-       .quad   0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
-       .quad   0x06f067aa72176fba,0x0a637dc5a2c898a6
-       .quad   0x113f9804bef90dae,0x1b710b35131c471b
-       .quad   0x28db77f523047d84,0x32caab7b40c72493
-       .quad   0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
-       .quad   0x4cc5d4becb3e42b6,0x597f299cfc657e2a
-       .quad   0x5fcb6fab3ad6faec,0x6c44198c4a475817
-       .quad   0       // terminator
-.size  .LK512,.-.LK512
-#ifndef        __KERNEL__
-.align 3
-.LOPENSSL_armcap_P:
-# ifdef        __ILP32__
-       .long   OPENSSL_armcap_P-.
-# else
-       .quad   OPENSSL_armcap_P-.
-# endif
-#endif
-.asciz "SHA512 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
-.align 2
-#ifndef        __KERNEL__
-.comm  OPENSSL_armcap_P,4,4
-#endif
index 8a078fc..7e157ab 100644 (file)
@@ -3,12 +3,10 @@
 #define __ASM_ALTERNATIVE_MACROS_H
 
 #include <asm/cpucaps.h>
+#include <asm/insn-def.h>
 
 #define ARM64_CB_PATCH ARM64_NCAPS
 
-/* A64 instructions are always 32 bits. */
-#define        AARCH64_INSN_SIZE               4
-
 #ifndef __ASSEMBLY__
 
 #include <linux/stringify.h>
@@ -197,11 +195,6 @@ alternative_endif
 #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...)  \
        alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
 
-.macro user_alt, label, oldinstr, newinstr, cond
-9999:  alternative_insn "\oldinstr", "\newinstr", \cond
-       _asm_extable 9999b, \label
-.endm
-
 #endif  /*  __ASSEMBLY__  */
 
 /*
index 934b9be..4ad22c3 100644 (file)
@@ -124,7 +124,8 @@ static inline u32 gic_read_rpr(void)
 #define gic_read_lpir(c)               readq_relaxed(c)
 #define gic_write_lpir(v, c)           writeq_relaxed(v, c)
 
-#define gic_flush_dcache_to_poc(a,l)   __flush_dcache_area((a), (l))
+#define gic_flush_dcache_to_poc(a,l)   \
+       dcache_clean_inval_poc((unsigned long)(a), (unsigned long)(a)+(l))
 
 #define gits_read_baser(c)             readq_relaxed(c)
 #define gits_write_baser(v, c)         writeq_relaxed(v, c)
index 1c9a3a0..ec1d965 100644 (file)
@@ -23,4 +23,10 @@ long long __ashlti3(long long a, int b);
 long long __ashrti3(long long a, int b);
 long long __lshrti3(long long a, int b);
 
+/*
+ * This function uses a custom calling convention and cannot be called from C so
+ * this prototype is not entirely accurate.
+ */
+void __hwasan_tag_mismatch(unsigned long addr, unsigned long access_info);
+
 #endif /* __ASM_PROTOTYPES_H */
index 8ca2dc0..f1bba5f 100644 (file)
@@ -7,19 +7,7 @@
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
 
-#ifdef CONFIG_ARM64_PTR_AUTH
-/*
- * thread.keys_user.ap* as offset exceeds the #imm offset range
- * so use the base value of ldp as thread.keys_user and offset as
- * thread.keys_user.ap*.
- */
-       .macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
-       mov     \tmp1, #THREAD_KEYS_USER
-       add     \tmp1, \tsk, \tmp1
-       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
-       msr_s   SYS_APIAKEYLO_EL1, \tmp2
-       msr_s   SYS_APIAKEYHI_EL1, \tmp3
-       .endm
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
 
        .macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
        mov     \tmp1, #THREAD_KEYS_KERNEL
@@ -42,6 +30,33 @@ alternative_if ARM64_HAS_ADDRESS_AUTH
 alternative_else_nop_endif
        .endm
 
+#else /* CONFIG_ARM64_PTR_AUTH_KERNEL */
+
+       .macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
+       .endm
+
+       .macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
+       .endm
+
+       .macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
+       .endm
+
+#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
+
+#ifdef CONFIG_ARM64_PTR_AUTH
+/*
+ * thread.keys_user.ap* as offset exceeds the #imm offset range
+ * so use the base value of ldp as thread.keys_user and offset as
+ * thread.keys_user.ap*.
+ */
+       .macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
+       mov     \tmp1, #THREAD_KEYS_USER
+       add     \tmp1, \tsk, \tmp1
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
+       msr_s   SYS_APIAKEYLO_EL1, \tmp2
+       msr_s   SYS_APIAKEYHI_EL1, \tmp3
+       .endm
+
        .macro __ptrauth_keys_init_cpu tsk, tmp1, tmp2, tmp3
        mrs     \tmp1, id_aa64isar1_el1
        ubfx    \tmp1, \tmp1, #ID_AA64ISAR1_APA_SHIFT, #8
@@ -64,17 +79,11 @@ alternative_else_nop_endif
 .Lno_addr_auth\@:
        .endm
 
-#else /* CONFIG_ARM64_PTR_AUTH */
+#else /* !CONFIG_ARM64_PTR_AUTH */
 
        .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
        .endm
 
-       .macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
-       .endm
-
-       .macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
-       .endm
-
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 #endif /* __ASM_ASM_POINTER_AUTH_H */
index 8418c1b..89faca0 100644 (file)
@@ -130,15 +130,27 @@ alternative_endif
        .endm
 
 /*
- * Emit an entry into the exception table
+ * Create an exception table entry for `insn`, which will branch to `fixup`
+ * when an unhandled fault is taken.
  */
-       .macro          _asm_extable, from, to
+       .macro          _asm_extable, insn, fixup
        .pushsection    __ex_table, "a"
        .align          3
-       .long           (\from - .), (\to - .)
+       .long           (\insn - .), (\fixup - .)
        .popsection
        .endm
 
+/*
+ * Create an exception table entry for `insn` if `fixup` is provided. Otherwise
+ * do nothing.
+ */
+       .macro          _cond_extable, insn, fixup
+       .ifnc           \fixup,
+       _asm_extable    \insn, \fixup
+       .endif
+       .endm
+
+
 #define USER(l, x...)                          \
 9999:  x;                                      \
        _asm_extable    9999b, l
@@ -232,17 +244,25 @@ lr        .req    x30             // link register
         * @dst: destination register
         */
 #if defined(__KVM_NVHE_HYPERVISOR__) || defined(__KVM_VHE_HYPERVISOR__)
-       .macro  this_cpu_offset, dst
+       .macro  get_this_cpu_offset, dst
        mrs     \dst, tpidr_el2
        .endm
 #else
-       .macro  this_cpu_offset, dst
+       .macro  get_this_cpu_offset, dst
 alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
        mrs     \dst, tpidr_el1
 alternative_else
        mrs     \dst, tpidr_el2
 alternative_endif
        .endm
+
+       .macro  set_this_cpu_offset, src
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
+       msr     tpidr_el1, \src
+alternative_else
+       msr     tpidr_el2, \src
+alternative_endif
+       .endm
 #endif
 
        /*
@@ -253,7 +273,7 @@ alternative_endif
        .macro adr_this_cpu, dst, sym, tmp
        adrp    \tmp, \sym
        add     \dst, \tmp, #:lo12:\sym
-       this_cpu_offset \tmp
+       get_this_cpu_offset \tmp
        add     \dst, \dst, \tmp
        .endm
 
@@ -264,7 +284,7 @@ alternative_endif
         */
        .macro ldr_this_cpu dst, sym, tmp
        adr_l   \dst, \sym
-       this_cpu_offset \tmp
+       get_this_cpu_offset \tmp
        ldr     \dst, [\dst, \tmp]
        .endm
 
@@ -375,51 +395,53 @@ alternative_cb_end
        bfi     \tcr, \tmp0, \pos, #3
        .endm
 
+       .macro __dcache_op_workaround_clean_cache, op, addr
+alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
+       dc      \op, \addr
+alternative_else
+       dc      civac, \addr
+alternative_endif
+       .endm
+
 /*
  * Macro to perform a data cache maintenance for the interval
- * [kaddr, kaddr + size)
+ * [start, end)
  *
  *     op:             operation passed to dc instruction
  *     domain:         domain used in dsb instruciton
- *     kaddr:          starting virtual address of the region
- *     size:           size of the region
- *     Corrupts:       kaddr, size, tmp1, tmp2
+ *     start:          starting virtual address of the region
+ *     end:            end virtual address of the region
+ *     fixup:          optional label to branch to on user fault
+ *     Corrupts:       start, end, tmp1, tmp2
  */
-       .macro __dcache_op_workaround_clean_cache, op, kaddr
-alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
-       dc      \op, \kaddr
-alternative_else
-       dc      civac, \kaddr
-alternative_endif
-       .endm
-
-       .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+       .macro dcache_by_line_op op, domain, start, end, tmp1, tmp2, fixup
        dcache_line_size \tmp1, \tmp2
-       add     \size, \kaddr, \size
        sub     \tmp2, \tmp1, #1
-       bic     \kaddr, \kaddr, \tmp2
-9998:
+       bic     \start, \start, \tmp2
+.Ldcache_op\@:
        .ifc    \op, cvau
-       __dcache_op_workaround_clean_cache \op, \kaddr
+       __dcache_op_workaround_clean_cache \op, \start
        .else
        .ifc    \op, cvac
-       __dcache_op_workaround_clean_cache \op, \kaddr
+       __dcache_op_workaround_clean_cache \op, \start
        .else
        .ifc    \op, cvap
-       sys     3, c7, c12, 1, \kaddr   // dc cvap
+       sys     3, c7, c12, 1, \start   // dc cvap
        .else
        .ifc    \op, cvadp
-       sys     3, c7, c13, 1, \kaddr   // dc cvadp
+       sys     3, c7, c13, 1, \start   // dc cvadp
        .else
-       dc      \op, \kaddr
+       dc      \op, \start
        .endif
        .endif
        .endif
        .endif
-       add     \kaddr, \kaddr, \tmp1
-       cmp     \kaddr, \size
-       b.lo    9998b
+       add     \start, \start, \tmp1
+       cmp     \start, \end
+       b.lo    .Ldcache_op\@
        dsb     \domain
+
+       _cond_extable .Ldcache_op\@, \fixup
        .endm
 
 /*
@@ -427,20 +449,22 @@ alternative_endif
  * [start, end)
  *
  *     start, end:     virtual addresses describing the region
- *     label:          A label to branch to on user fault.
+ *     fixup:          optional label to branch to on user fault
  *     Corrupts:       tmp1, tmp2
  */
-       .macro invalidate_icache_by_line start, end, tmp1, tmp2, label
+       .macro invalidate_icache_by_line start, end, tmp1, tmp2, fixup
        icache_line_size \tmp1, \tmp2
        sub     \tmp2, \tmp1, #1
        bic     \tmp2, \start, \tmp2
-9997:
-USER(\label, ic        ivau, \tmp2)                    // invalidate I line PoU
+.Licache_op\@:
+       ic      ivau, \tmp2                     // invalidate I line PoU
        add     \tmp2, \tmp2, \tmp1
        cmp     \tmp2, \end
-       b.lo    9997b
+       b.lo    .Licache_op\@
        dsb     ish
        isb
+
+       _cond_extable .Licache_op\@, \fixup
        .endm
 
 /*
@@ -745,7 +769,7 @@ USER(\label, ic     ivau, \tmp2)                    // invalidate I line PoU
        cbz             \tmp, \lbl
 #endif
        adr_l           \tmp, irq_stat + IRQ_CPUSTAT_SOFTIRQ_PENDING
-       this_cpu_offset \tmp2
+       get_this_cpu_offset     \tmp2
        ldr             w\tmp, [\tmp, \tmp2]
        cbnz            w\tmp, \lbl     // yield on pending softirq in task context
 .Lnoyield_\@:
index b56a4b2..c997927 100644 (file)
@@ -223,6 +223,4 @@ static __always_inline long arch_atomic64_dec_if_positive(atomic64_t *v)
 
 #define arch_atomic64_dec_if_positive          arch_atomic64_dec_if_positive
 
-#define ARCH_ATOMIC
-
 #endif /* __ASM_ATOMIC_H */
index a074459..a9c0716 100644 (file)
@@ -47,7 +47,7 @@
  * cache before the transfer is done, causing old data to be seen by
  * the CPU.
  */
-#define ARCH_DMA_MINALIGN      (128)
+#define ARCH_DMA_MINALIGN      L1_CACHE_BYTES
 
 #ifdef CONFIG_KASAN_SW_TAGS
 #define ARCH_SLAB_MINALIGN     (1ULL << KASAN_SHADOW_SCALE_SHIFT)
index 52e5c16..543c997 100644 (file)
  *     the implementation assumes non-aliasing VIPT D-cache and (aliasing)
  *     VIPT I-cache.
  *
- *     flush_icache_range(start, end)
+ *     All functions below apply to the interval [start, end)
+ *             - start  - virtual start address (inclusive)
+ *             - end    - virtual end address (exclusive)
  *
- *             Ensure coherency between the I-cache and the D-cache in the
- *             region described by start, end.
- *             - start  - virtual start address
- *             - end    - virtual end address
+ *     caches_clean_inval_pou(start, end)
  *
- *     invalidate_icache_range(start, end)
+ *             Ensure coherency between the I-cache and the D-cache region to
+ *             the Point of Unification.
  *
- *             Invalidate the I-cache in the region described by start, end.
- *             - start  - virtual start address
- *             - end    - virtual end address
+ *     caches_clean_inval_user_pou(start, end)
  *
- *     __flush_cache_user_range(start, end)
+ *             Ensure coherency between the I-cache and the D-cache region to
+ *             the Point of Unification.
+ *             Use only if the region might access user memory.
  *
- *             Ensure coherency between the I-cache and the D-cache in the
- *             region described by start, end.
- *             - start  - virtual start address
- *             - end    - virtual end address
+ *     icache_inval_pou(start, end)
  *
- *     __flush_dcache_area(kaddr, size)
+ *             Invalidate I-cache region to the Point of Unification.
  *
- *             Ensure that the data held in page is written back.
- *             - kaddr  - page address
- *             - size   - region size
+ *     dcache_clean_inval_poc(start, end)
+ *
+ *             Clean and invalidate D-cache region to the Point of Coherency.
+ *
+ *     dcache_inval_poc(start, end)
+ *
+ *             Invalidate D-cache region to the Point of Coherency.
+ *
+ *     dcache_clean_poc(start, end)
+ *
+ *             Clean D-cache region to the Point of Coherency.
+ *
+ *     dcache_clean_pop(start, end)
+ *
+ *             Clean D-cache region to the Point of Persistence.
+ *
+ *     dcache_clean_pou(start, end)
+ *
+ *             Clean D-cache region to the Point of Unification.
  */
-extern void __flush_icache_range(unsigned long start, unsigned long end);
-extern int  invalidate_icache_range(unsigned long start, unsigned long end);
-extern void __flush_dcache_area(void *addr, size_t len);
-extern void __inval_dcache_area(void *addr, size_t len);
-extern void __clean_dcache_area_poc(void *addr, size_t len);
-extern void __clean_dcache_area_pop(void *addr, size_t len);
-extern void __clean_dcache_area_pou(void *addr, size_t len);
-extern long __flush_cache_user_range(unsigned long start, unsigned long end);
-extern void sync_icache_aliases(void *kaddr, unsigned long len);
+extern void caches_clean_inval_pou(unsigned long start, unsigned long end);
+extern void icache_inval_pou(unsigned long start, unsigned long end);
+extern void dcache_clean_inval_poc(unsigned long start, unsigned long end);
+extern void dcache_inval_poc(unsigned long start, unsigned long end);
+extern void dcache_clean_poc(unsigned long start, unsigned long end);
+extern void dcache_clean_pop(unsigned long start, unsigned long end);
+extern void dcache_clean_pou(unsigned long start, unsigned long end);
+extern long caches_clean_inval_user_pou(unsigned long start, unsigned long end);
+extern void sync_icache_aliases(unsigned long start, unsigned long end);
 
 static inline void flush_icache_range(unsigned long start, unsigned long end)
 {
-       __flush_icache_range(start, end);
+       caches_clean_inval_pou(start, end);
 
        /*
         * IPI all online CPUs so that they undergo a context synchronization
@@ -122,7 +135,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static __always_inline void __flush_icache_all(void)
+static __always_inline void icache_inval_all_pou(void)
 {
        if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
                return;
index 7faae6f..0f6d16f 100644 (file)
 /*
  * Records attributes of an individual CPU.
  */
-struct cpuinfo_arm64 {
-       struct cpu      cpu;
-       struct kobject  kobj;
-       u32             reg_ctr;
-       u32             reg_cntfrq;
-       u32             reg_dczid;
-       u32             reg_midr;
-       u32             reg_revidr;
-
-       u64             reg_id_aa64dfr0;
-       u64             reg_id_aa64dfr1;
-       u64             reg_id_aa64isar0;
-       u64             reg_id_aa64isar1;
-       u64             reg_id_aa64mmfr0;
-       u64             reg_id_aa64mmfr1;
-       u64             reg_id_aa64mmfr2;
-       u64             reg_id_aa64pfr0;
-       u64             reg_id_aa64pfr1;
-       u64             reg_id_aa64zfr0;
-
+struct cpuinfo_32bit {
        u32             reg_id_dfr0;
        u32             reg_id_dfr1;
        u32             reg_id_isar0;
@@ -54,6 +35,30 @@ struct cpuinfo_arm64 {
        u32             reg_mvfr0;
        u32             reg_mvfr1;
        u32             reg_mvfr2;
+};
+
+struct cpuinfo_arm64 {
+       struct cpu      cpu;
+       struct kobject  kobj;
+       u64             reg_ctr;
+       u64             reg_cntfrq;
+       u64             reg_dczid;
+       u64             reg_midr;
+       u64             reg_revidr;
+       u64             reg_gmid;
+
+       u64             reg_id_aa64dfr0;
+       u64             reg_id_aa64dfr1;
+       u64             reg_id_aa64isar0;
+       u64             reg_id_aa64isar1;
+       u64             reg_id_aa64mmfr0;
+       u64             reg_id_aa64mmfr1;
+       u64             reg_id_aa64mmfr2;
+       u64             reg_id_aa64pfr0;
+       u64             reg_id_aa64pfr1;
+       u64             reg_id_aa64zfr0;
+
+       struct cpuinfo_32bit    aarch32;
 
        /* pseudo-ZCR for recording maximum ZCR_EL1 LEN value: */
        u64             reg_zcr;
index 338840c..9bb9d11 100644 (file)
@@ -619,6 +619,13 @@ static inline bool id_aa64pfr0_sve(u64 pfr0)
        return val > 0;
 }
 
+static inline bool id_aa64pfr1_mte(u64 pfr1)
+{
+       u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_MTE_SHIFT);
+
+       return val >= ID_AA64PFR1_MTE;
+}
+
 void __init setup_cpu_features(void);
 void check_local_cpu_capabilities(void);
 
@@ -630,9 +637,15 @@ static inline bool cpu_supports_mixed_endian_el0(void)
        return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
 }
 
+const struct cpumask *system_32bit_el0_cpumask(void);
+DECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
+
 static inline bool system_supports_32bit_el0(void)
 {
-       return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
+       u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+       return static_branch_unlikely(&arm64_mismatched_32bit_el0) ||
+              id_aa64pfr0_32bit_el0(pfr0);
 }
 
 static inline bool system_supports_4kb_granule(void)
index 3c5ddb4..14a19d1 100644 (file)
@@ -18,4 +18,39 @@ static inline int arm_cpuidle_suspend(int index)
        return -EOPNOTSUPP;
 }
 #endif
+
+#ifdef CONFIG_ARM64_PSEUDO_NMI
+#include <asm/arch_gicv3.h>
+
+struct arm_cpuidle_irq_context {
+       unsigned long pmr;
+       unsigned long daif_bits;
+};
+
+#define arm_cpuidle_save_irq_context(__c)                              \
+       do {                                                            \
+               struct arm_cpuidle_irq_context *c = __c;                \
+               if (system_uses_irq_prio_masking()) {                   \
+                       c->daif_bits = read_sysreg(daif);               \
+                       write_sysreg(c->daif_bits | PSR_I_BIT | PSR_F_BIT, \
+                                    daif);                             \
+                       c->pmr = gic_read_pmr();                        \
+                       gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); \
+               }                                                       \
+       } while (0)
+
+#define arm_cpuidle_restore_irq_context(__c)                           \
+       do {                                                            \
+               struct arm_cpuidle_irq_context *c = __c;                \
+               if (system_uses_irq_prio_masking()) {                   \
+                       gic_write_pmr(c->pmr);                          \
+                       write_sysreg(c->daif_bits, daif);               \
+               }                                                       \
+       } while (0)
+#else
+struct arm_cpuidle_irq_context { };
+
+#define arm_cpuidle_save_irq_context(c)                (void)c
+#define arm_cpuidle_restore_irq_context(c)     (void)c
+#endif
 #endif
index 3578aba..1bed37e 100644 (file)
@@ -137,7 +137,7 @@ void efi_virtmap_unload(void);
 
 static inline void efi_capsule_flush_cache_range(void *addr, int size)
 {
-       __flush_dcache_area(addr, size);
+       dcache_clean_inval_poc((unsigned long)addr, (unsigned long)addr + size);
 }
 
 #endif /* _ASM_EFI_H */
index 6546158..4afbc45 100644 (file)
@@ -31,20 +31,35 @@ static inline u32 disr_to_esr(u64 disr)
        return esr;
 }
 
-asmlinkage void el1_sync_handler(struct pt_regs *regs);
-asmlinkage void el0_sync_handler(struct pt_regs *regs);
-asmlinkage void el0_sync_compat_handler(struct pt_regs *regs);
+asmlinkage void handle_bad_stack(struct pt_regs *regs);
 
-asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs);
-asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs);
+asmlinkage void el1t_64_sync_handler(struct pt_regs *regs);
+asmlinkage void el1t_64_irq_handler(struct pt_regs *regs);
+asmlinkage void el1t_64_fiq_handler(struct pt_regs *regs);
+asmlinkage void el1t_64_error_handler(struct pt_regs *regs);
+
+asmlinkage void el1h_64_sync_handler(struct pt_regs *regs);
+asmlinkage void el1h_64_irq_handler(struct pt_regs *regs);
+asmlinkage void el1h_64_fiq_handler(struct pt_regs *regs);
+asmlinkage void el1h_64_error_handler(struct pt_regs *regs);
+
+asmlinkage void el0t_64_sync_handler(struct pt_regs *regs);
+asmlinkage void el0t_64_irq_handler(struct pt_regs *regs);
+asmlinkage void el0t_64_fiq_handler(struct pt_regs *regs);
+asmlinkage void el0t_64_error_handler(struct pt_regs *regs);
+
+asmlinkage void el0t_32_sync_handler(struct pt_regs *regs);
+asmlinkage void el0t_32_irq_handler(struct pt_regs *regs);
+asmlinkage void el0t_32_fiq_handler(struct pt_regs *regs);
+asmlinkage void el0t_32_error_handler(struct pt_regs *regs);
+
+asmlinkage void call_on_irq_stack(struct pt_regs *regs,
+                                 void (*func)(struct pt_regs *));
 asmlinkage void enter_from_user_mode(void);
 asmlinkage void exit_to_user_mode(void);
-void arm64_enter_nmi(struct pt_regs *regs);
-void arm64_exit_nmi(struct pt_regs *regs);
 void do_mem_abort(unsigned long far, unsigned int esr, struct pt_regs *regs);
 void do_undefinstr(struct pt_regs *regs);
 void do_bti(struct pt_regs *regs);
-asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);
 void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
                        struct pt_regs *regs);
 void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs);
@@ -57,4 +72,7 @@ void do_cp15instr(unsigned int esr, struct pt_regs *regs);
 void do_el0_svc(struct pt_regs *regs);
 void do_el0_svc_compat(struct pt_regs *regs);
 void do_ptrauth_fault(struct pt_regs *regs, unsigned int esr);
+void do_serror(struct pt_regs *regs, unsigned int esr);
+
+void panic_bad_stack(struct pt_regs *regs, unsigned int esr, unsigned long far);
 #endif /* __ASM_EXCEPTION_H */
index 2599504..c072161 100644 (file)
@@ -69,7 +69,7 @@ static inline void *sve_pffr(struct thread_struct *thread)
 extern void sve_save_state(void *state, u32 *pfpsr);
 extern void sve_load_state(void const *state, u32 const *pfpsr,
                           unsigned long vq_minus_1);
-extern void sve_flush_live(void);
+extern void sve_flush_live(unsigned long vq_minus_1);
 extern void sve_load_from_fpsimd_state(struct user_fpsimd_state const *state,
                                       unsigned long vq_minus_1);
 extern unsigned int sve_get_vl(void);
index a256399..0592044 100644 (file)
        mov     v\nz\().16b, v\nz\().16b
 .endm
 
-.macro sve_flush
+.macro sve_flush_z
  _for n, 0, 31, _sve_flush_z   \n
+.endm
+.macro sve_flush_p_ffr
  _for n, 0, 15, _sve_pfalse    \n
                _sve_wrffr      0
 .endm
diff --git a/arch/arm64/include/asm/insn-def.h b/arch/arm64/include/asm/insn-def.h
new file mode 100644 (file)
index 0000000..2c075f6
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_INSN_DEF_H
+#define __ASM_INSN_DEF_H
+
+/* A64 instructions are always 32 bits. */
+#define        AARCH64_INSN_SIZE               4
+
+#endif /* __ASM_INSN_DEF_H */
index 4ebb9c0..6b776c8 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/build_bug.h>
 #include <linux/types.h>
 
-#include <asm/alternative.h>
+#include <asm/insn-def.h>
 
 #ifndef __ASSEMBLY__
 /*
@@ -30,6 +30,7 @@
  */
 enum aarch64_insn_encoding_class {
        AARCH64_INSN_CLS_UNKNOWN,       /* UNALLOCATED */
+       AARCH64_INSN_CLS_SVE,           /* SVE instructions */
        AARCH64_INSN_CLS_DP_IMM,        /* Data processing - immediate */
        AARCH64_INSN_CLS_DP_REG,        /* Data processing - register */
        AARCH64_INSN_CLS_DP_FPSIMD,     /* Data processing - SIMD and FP */
@@ -294,6 +295,12 @@ __AARCH64_INSN_FUNCS(adr,  0x9F000000, 0x10000000)
 __AARCH64_INSN_FUNCS(adrp,     0x9F000000, 0x90000000)
 __AARCH64_INSN_FUNCS(prfm,     0x3FC00000, 0x39800000)
 __AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
+__AARCH64_INSN_FUNCS(store_imm,        0x3FC00000, 0x39000000)
+__AARCH64_INSN_FUNCS(load_imm, 0x3FC00000, 0x39400000)
+__AARCH64_INSN_FUNCS(store_pre,        0x3FE00C00, 0x38000C00)
+__AARCH64_INSN_FUNCS(load_pre, 0x3FE00C00, 0x38400C00)
+__AARCH64_INSN_FUNCS(store_post,       0x3FE00C00, 0x38000400)
+__AARCH64_INSN_FUNCS(load_post,        0x3FE00C00, 0x38400400)
 __AARCH64_INSN_FUNCS(str_reg,  0x3FE0EC00, 0x38206800)
 __AARCH64_INSN_FUNCS(ldadd,    0x3F20FC00, 0x38200000)
 __AARCH64_INSN_FUNCS(ldr_reg,  0x3FE0EC00, 0x38606800)
@@ -302,6 +309,8 @@ __AARCH64_INSN_FUNCS(ldrsw_lit,     0xFF000000, 0x98000000)
 __AARCH64_INSN_FUNCS(exclusive,        0x3F800000, 0x08000000)
 __AARCH64_INSN_FUNCS(load_ex,  0x3F400000, 0x08400000)
 __AARCH64_INSN_FUNCS(store_ex, 0x3F400000, 0x08000000)
+__AARCH64_INSN_FUNCS(stp,      0x7FC00000, 0x29000000)
+__AARCH64_INSN_FUNCS(ldp,      0x7FC00000, 0x29400000)
 __AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
 __AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
 __AARCH64_INSN_FUNCS(stp_pre,  0x7FC00000, 0x29800000)
@@ -334,6 +343,7 @@ __AARCH64_INSN_FUNCS(rev64, 0x7FFFFC00, 0x5AC00C00)
 __AARCH64_INSN_FUNCS(and,      0x7F200000, 0x0A000000)
 __AARCH64_INSN_FUNCS(bic,      0x7F200000, 0x0A200000)
 __AARCH64_INSN_FUNCS(orr,      0x7F200000, 0x2A000000)
+__AARCH64_INSN_FUNCS(mov_reg,  0x7FE0FFE0, 0x2A0003E0)
 __AARCH64_INSN_FUNCS(orn,      0x7F200000, 0x2A200000)
 __AARCH64_INSN_FUNCS(eor,      0x7F200000, 0x4A000000)
 __AARCH64_INSN_FUNCS(eon,      0x7F200000, 0x4A200000)
@@ -368,6 +378,14 @@ __AARCH64_INSN_FUNCS(eret_auth,    0xFFFFFBFF, 0xD69F0BFF)
 __AARCH64_INSN_FUNCS(mrs,      0xFFF00000, 0xD5300000)
 __AARCH64_INSN_FUNCS(msr_imm,  0xFFF8F01F, 0xD500401F)
 __AARCH64_INSN_FUNCS(msr_reg,  0xFFF00000, 0xD5100000)
+__AARCH64_INSN_FUNCS(dmb,      0xFFFFF0FF, 0xD50330BF)
+__AARCH64_INSN_FUNCS(dsb_base, 0xFFFFF0FF, 0xD503309F)
+__AARCH64_INSN_FUNCS(dsb_nxs,  0xFFFFF3FF, 0xD503323F)
+__AARCH64_INSN_FUNCS(isb,      0xFFFFF0FF, 0xD50330DF)
+__AARCH64_INSN_FUNCS(sb,       0xFFFFFFFF, 0xD50330FF)
+__AARCH64_INSN_FUNCS(clrex,    0xFFFFF0FF, 0xD503305F)
+__AARCH64_INSN_FUNCS(ssbb,     0xFFFFFFFF, 0xD503309F)
+__AARCH64_INSN_FUNCS(pssbb,    0xFFFFFFFF, 0xD503349F)
 
 #undef __AARCH64_INSN_FUNCS
 
@@ -379,8 +397,47 @@ static inline bool aarch64_insn_is_adr_adrp(u32 insn)
        return aarch64_insn_is_adr(insn) || aarch64_insn_is_adrp(insn);
 }
 
-int aarch64_insn_read(void *addr, u32 *insnp);
-int aarch64_insn_write(void *addr, u32 insn);
+static inline bool aarch64_insn_is_dsb(u32 insn)
+{
+       return aarch64_insn_is_dsb_base(insn) || aarch64_insn_is_dsb_nxs(insn);
+}
+
+static inline bool aarch64_insn_is_barrier(u32 insn)
+{
+       return aarch64_insn_is_dmb(insn) || aarch64_insn_is_dsb(insn) ||
+              aarch64_insn_is_isb(insn) || aarch64_insn_is_sb(insn) ||
+              aarch64_insn_is_clrex(insn) || aarch64_insn_is_ssbb(insn) ||
+              aarch64_insn_is_pssbb(insn);
+}
+
+static inline bool aarch64_insn_is_store_single(u32 insn)
+{
+       return aarch64_insn_is_store_imm(insn) ||
+              aarch64_insn_is_store_pre(insn) ||
+              aarch64_insn_is_store_post(insn);
+}
+
+static inline bool aarch64_insn_is_store_pair(u32 insn)
+{
+       return aarch64_insn_is_stp(insn) ||
+              aarch64_insn_is_stp_pre(insn) ||
+              aarch64_insn_is_stp_post(insn);
+}
+
+static inline bool aarch64_insn_is_load_single(u32 insn)
+{
+       return aarch64_insn_is_load_imm(insn) ||
+              aarch64_insn_is_load_pre(insn) ||
+              aarch64_insn_is_load_post(insn);
+}
+
+static inline bool aarch64_insn_is_load_pair(u32 insn)
+{
+       return aarch64_insn_is_ldp(insn) ||
+              aarch64_insn_is_ldp_pre(insn) ||
+              aarch64_insn_is_ldp_post(insn);
+}
+
 enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
 bool aarch64_insn_uses_literal(u32 insn);
 bool aarch64_insn_is_branch(u32 insn);
@@ -487,9 +544,6 @@ u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
 s32 aarch64_get_branch_offset(u32 insn);
 u32 aarch64_set_branch_offset(u32 insn, s32 offset);
 
-int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
-int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
-
 s32 aarch64_insn_adrp_get_offset(u32 insn);
 u32 aarch64_insn_adrp_set_offset(u32 insn, s32 offset);
 
@@ -506,6 +560,7 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn);
 
 typedef bool (pstate_check_t)(unsigned long);
 extern pstate_check_t * const aarch32_opcode_cond_checks[16];
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_INSN_H */
index d44df9d..3512184 100644 (file)
@@ -18,9 +18,9 @@
  * 64K (section size = 512M).
  */
 #ifdef CONFIG_ARM64_4K_PAGES
-#define ARM64_SWAPPER_USES_SECTION_MAPS 1
+#define ARM64_KERNEL_USES_PMD_MAPS 1
 #else
-#define ARM64_SWAPPER_USES_SECTION_MAPS 0
+#define ARM64_KERNEL_USES_PMD_MAPS 0
 #endif
 
 /*
@@ -33,7 +33,7 @@
  * VA range, so pages required to map highest possible PA are reserved in all
  * cases.
  */
-#if ARM64_SWAPPER_USES_SECTION_MAPS
+#if ARM64_KERNEL_USES_PMD_MAPS
 #define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS - 1)
 #define IDMAP_PGTABLE_LEVELS   (ARM64_HW_PGTABLE_LEVELS(PHYS_MASK_SHIFT) - 1)
 #else
@@ -90,9 +90,9 @@
 #define IDMAP_DIR_SIZE         (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
 
 /* Initial memory map size */
-#if ARM64_SWAPPER_USES_SECTION_MAPS
-#define SWAPPER_BLOCK_SHIFT    SECTION_SHIFT
-#define SWAPPER_BLOCK_SIZE     SECTION_SIZE
+#if ARM64_KERNEL_USES_PMD_MAPS
+#define SWAPPER_BLOCK_SHIFT    PMD_SHIFT
+#define SWAPPER_BLOCK_SIZE     PMD_SIZE
 #define SWAPPER_TABLE_SHIFT    PUD_SHIFT
 #else
 #define SWAPPER_BLOCK_SHIFT    PAGE_SHIFT
 #define SWAPPER_TABLE_SHIFT    PMD_SHIFT
 #endif
 
-/* The size of the initial kernel direct mapping */
-#define SWAPPER_INIT_MAP_SIZE  (_AC(1, UL) << SWAPPER_TABLE_SHIFT)
-
 /*
  * Initial memory map attributes.
  */
 #define SWAPPER_PTE_FLAGS      (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define SWAPPER_PMD_FLAGS      (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
-#if ARM64_SWAPPER_USES_SECTION_MAPS
+#if ARM64_KERNEL_USES_PMD_MAPS
 #define SWAPPER_MM_MMUFLAGS    (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
 #else
 #define SWAPPER_MM_MMUFLAGS    (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
 #if defined(CONFIG_ARM64_4K_PAGES)
 #define ARM64_MEMSTART_SHIFT           PUD_SHIFT
 #elif defined(CONFIG_ARM64_16K_PAGES)
-#define ARM64_MEMSTART_SHIFT           (PMD_SHIFT + 5)
+#define ARM64_MEMSTART_SHIFT           CONT_PMD_SHIFT
 #else
 #define ARM64_MEMSTART_SHIFT           PMD_SHIFT
 #endif
index 692c904..d436831 100644 (file)
@@ -12,7 +12,8 @@
 #include <asm/types.h>
 
 /* Hyp Configuration Register (HCR) bits */
-#define HCR_ATA                (UL(1) << 56)
+#define HCR_ATA_SHIFT  56
+#define HCR_ATA                (UL(1) << HCR_ATA_SHIFT)
 #define HCR_FWB                (UL(1) << 46)
 #define HCR_API                (UL(1) << 41)
 #define HCR_APK                (UL(1) << 40)
index 5e9b33c..9f0bf21 100644 (file)
@@ -8,6 +8,7 @@
 #define __ARM_KVM_ASM_H__
 
 #include <asm/hyp_image.h>
+#include <asm/insn.h>
 #include <asm/virt.h>
 
 #define ARM_EXIT_WITH_SERROR_BIT  31
index 01b9857..fd41895 100644 (file)
@@ -84,6 +84,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
        if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) ||
            vcpu_el1_is_32bit(vcpu))
                vcpu->arch.hcr_el2 |= HCR_TID2;
+
+       if (kvm_has_mte(vcpu->kvm))
+               vcpu->arch.hcr_el2 |= HCR_ATA;
 }
 
 static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
index 7cd7d5c..4191158 100644 (file)
@@ -46,6 +46,7 @@
 #define KVM_REQ_VCPU_RESET     KVM_ARCH_REQ(2)
 #define KVM_REQ_RECORD_STEAL   KVM_ARCH_REQ(3)
 #define KVM_REQ_RELOAD_GICv4   KVM_ARCH_REQ(4)
+#define KVM_REQ_RELOAD_PMU     KVM_ARCH_REQ(5)
 
 #define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
                                     KVM_DIRTY_LOG_INITIALLY_SET)
@@ -132,6 +133,9 @@ struct kvm_arch {
 
        u8 pfr0_csv2;
        u8 pfr0_csv3;
+
+       /* Memory Tagging Extension enabled for the guest */
+       bool mte_enabled;
 };
 
 struct kvm_vcpu_fault_info {
@@ -206,6 +210,12 @@ enum vcpu_sysreg {
        CNTP_CVAL_EL0,
        CNTP_CTL_EL0,
 
+       /* Memory Tagging Extension registers */
+       RGSR_EL1,       /* Random Allocation Tag Seed Register */
+       GCR_EL1,        /* Tag Control Register */
+       TFSR_EL1,       /* Tag Fault Status Register (EL1) */
+       TFSRE0_EL1,     /* Tag Fault Status Register (EL0) */
+
        /* 32bit specific registers. Keep them at the end of the range */
        DACR32_EL2,     /* Domain Access Control Register */
        IFSR32_EL2,     /* Instruction Fault Status Register */
@@ -556,16 +566,11 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
 }
 
 struct kvm_vm_stat {
-       ulong remote_tlb_flush;
+       struct kvm_vm_stat_generic generic;
 };
 
 struct kvm_vcpu_stat {
-       u64 halt_successful_poll;
-       u64 halt_attempted_poll;
-       u64 halt_poll_success_ns;
-       u64 halt_poll_fail_ns;
-       u64 halt_poll_invalid;
-       u64 halt_wakeup;
+       struct kvm_vcpu_stat_generic generic;
        u64 hvc_exit_stat;
        u64 wfe_exit_stat;
        u64 wfi_exit_stat;
@@ -721,6 +726,9 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
 int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
                               struct kvm_device_attr *attr);
 
+long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
+                               struct kvm_arm_copy_mte_tags *copy_tags);
+
 /* Guest/host FPSIMD coordination helpers */
 int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu);
@@ -769,6 +777,7 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
 #define kvm_arm_vcpu_sve_finalized(vcpu) \
        ((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
 
+#define kvm_has_mte(kvm) (system_supports_mte() && (kvm)->arch.mte_enabled)
 #define kvm_vcpu_has_pmu(vcpu)                                 \
        (test_bit(KVM_ARM_VCPU_PMU_V3, (vcpu)->arch.features))
 
index 25ed956..b52c5c4 100644 (file)
@@ -180,17 +180,16 @@ static inline void *__kvm_vector_slot2addr(void *base,
 
 struct kvm;
 
-#define kvm_flush_dcache_to_poc(a,l)   __flush_dcache_area((a), (l))
+#define kvm_flush_dcache_to_poc(a,l)   \
+       dcache_clean_inval_poc((unsigned long)(a), (unsigned long)(a)+(l))
 
 static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
 {
        return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
 }
 
-static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
+static inline void __clean_dcache_guest_page(void *va, size_t size)
 {
-       void *va = page_address(pfn_to_page(pfn));
-
        /*
         * With FWB, we ensure that the guest always accesses memory using
         * cacheable attributes, and we don't have to clean to PoC when
@@ -203,18 +202,14 @@ static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
        kvm_flush_dcache_to_poc(va, size);
 }
 
-static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn,
-                                                 unsigned long size)
+static inline void __invalidate_icache_guest_page(void *va, size_t size)
 {
        if (icache_is_aliasing()) {
                /* any kind of VIPT cache */
-               __flush_icache_all();
+               icache_inval_all_pou();
        } else if (is_kernel_in_hyp_mode() || !icache_is_vpipt()) {
                /* PIPT or VPIPT at EL2 (see comment in __kvm_tlb_flush_vmid_ipa) */
-               void *va = page_address(pfn_to_page(pfn));
-
-               invalidate_icache_range((unsigned long)va,
-                                       (unsigned long)va + size);
+               icache_inval_pou((unsigned long)va, (unsigned long)va + size);
        }
 }
 
diff --git a/arch/arm64/include/asm/kvm_mte.h b/arch/arm64/include/asm/kvm_mte.h
new file mode 100644 (file)
index 0000000..de00263
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 ARM Ltd.
+ */
+#ifndef __ASM_KVM_MTE_H
+#define __ASM_KVM_MTE_H
+
+#ifdef __ASSEMBLY__
+
+#include <asm/sysreg.h>
+
+#ifdef CONFIG_ARM64_MTE
+
+.macro mte_switch_to_guest g_ctxt, h_ctxt, reg1
+alternative_if_not ARM64_MTE
+       b       .L__skip_switch\@
+alternative_else_nop_endif
+       mrs     \reg1, hcr_el2
+       tbz     \reg1, #(HCR_ATA_SHIFT), .L__skip_switch\@
+
+       mrs_s   \reg1, SYS_RGSR_EL1
+       str     \reg1, [\h_ctxt, #CPU_RGSR_EL1]
+       mrs_s   \reg1, SYS_GCR_EL1
+       str     \reg1, [\h_ctxt, #CPU_GCR_EL1]
+
+       ldr     \reg1, [\g_ctxt, #CPU_RGSR_EL1]
+       msr_s   SYS_RGSR_EL1, \reg1
+       ldr     \reg1, [\g_ctxt, #CPU_GCR_EL1]
+       msr_s   SYS_GCR_EL1, \reg1
+
+.L__skip_switch\@:
+.endm
+
+.macro mte_switch_to_hyp g_ctxt, h_ctxt, reg1
+alternative_if_not ARM64_MTE
+       b       .L__skip_switch\@
+alternative_else_nop_endif
+       mrs     \reg1, hcr_el2
+       tbz     \reg1, #(HCR_ATA_SHIFT), .L__skip_switch\@
+
+       mrs_s   \reg1, SYS_RGSR_EL1
+       str     \reg1, [\g_ctxt, #CPU_RGSR_EL1]
+       mrs_s   \reg1, SYS_GCR_EL1
+       str     \reg1, [\g_ctxt, #CPU_GCR_EL1]
+
+       ldr     \reg1, [\h_ctxt, #CPU_RGSR_EL1]
+       msr_s   SYS_RGSR_EL1, \reg1
+       ldr     \reg1, [\h_ctxt, #CPU_GCR_EL1]
+       msr_s   SYS_GCR_EL1, \reg1
+
+       isb
+
+.L__skip_switch\@:
+.endm
+
+#else /* !CONFIG_ARM64_MTE */
+
+.macro mte_switch_to_guest g_ctxt, h_ctxt, reg1
+.endm
+
+.macro mte_switch_to_hyp g_ctxt, h_ctxt, reg1
+.endm
+
+#endif /* CONFIG_ARM64_MTE */
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_KVM_MTE_H */
index c3674c4..f004c01 100644 (file)
@@ -27,23 +27,29 @@ typedef u64 kvm_pte_t;
 
 /**
  * struct kvm_pgtable_mm_ops - Memory management callbacks.
- * @zalloc_page:       Allocate a single zeroed memory page. The @arg parameter
- *                     can be used by the walker to pass a memcache. The
- *                     initial refcount of the page is 1.
- * @zalloc_pages_exact:        Allocate an exact number of zeroed memory pages. The
- *                     @size parameter is in bytes, and is rounded-up to the
- *                     next page boundary. The resulting allocation is
- *                     physically contiguous.
- * @free_pages_exact:  Free an exact number of memory pages previously
- *                     allocated by zalloc_pages_exact.
- * @get_page:          Increment the refcount on a page.
- * @put_page:          Decrement the refcount on a page. When the refcount
- *                     reaches 0 the page is automatically freed.
- * @page_count:                Return the refcount of a page.
- * @phys_to_virt:      Convert a physical address into a virtual address mapped
- *                     in the current context.
- * @virt_to_phys:      Convert a virtual address mapped in the current context
- *                     into a physical address.
+ * @zalloc_page:               Allocate a single zeroed memory page.
+ *                             The @arg parameter can be used by the walker
+ *                             to pass a memcache. The initial refcount of
+ *                             the page is 1.
+ * @zalloc_pages_exact:                Allocate an exact number of zeroed memory pages.
+ *                             The @size parameter is in bytes, and is rounded
+ *                             up to the next page boundary. The resulting
+ *                             allocation is physically contiguous.
+ * @free_pages_exact:          Free an exact number of memory pages previously
+ *                             allocated by zalloc_pages_exact.
+ * @get_page:                  Increment the refcount on a page.
+ * @put_page:                  Decrement the refcount on a page. When the
+ *                             refcount reaches 0 the page is automatically
+ *                             freed.
+ * @page_count:                        Return the refcount of a page.
+ * @phys_to_virt:              Convert a physical address into a virtual
+ *                             address mapped in the current context.
+ * @virt_to_phys:              Convert a virtual address mapped in the current
+ *                             context into a physical address.
+ * @dcache_clean_inval_poc:    Clean and invalidate the data cache to the PoC
+ *                             for the specified memory address range.
+ * @icache_inval_pou:          Invalidate the instruction cache to the PoU
+ *                             for the specified memory address range.
  */
 struct kvm_pgtable_mm_ops {
        void*           (*zalloc_page)(void *arg);
@@ -54,6 +60,8 @@ struct kvm_pgtable_mm_ops {
        int             (*page_count)(void *addr);
        void*           (*phys_to_virt)(phys_addr_t phys);
        phys_addr_t     (*virt_to_phys)(void *addr);
+       void            (*dcache_clean_inval_poc)(void *addr, size_t size);
+       void            (*icache_inval_pou)(void *addr, size_t size);
 };
 
 /**
index ba89a9a..9906541 100644 (file)
                SYM_FUNC_START_ALIAS(__pi_##x); \
                SYM_FUNC_START_WEAK(x)
 
+#define SYM_FUNC_START_WEAK_ALIAS_PI(x)                \
+               SYM_FUNC_START_ALIAS(__pi_##x); \
+               SYM_START(x, SYM_L_WEAK, SYM_A_ALIGN)
+
 #define SYM_FUNC_END_PI(x)                     \
                SYM_FUNC_END(x);                \
                SYM_FUNC_END_ALIAS(__pi_##x)
 
+#define SYM_FUNC_END_ALIAS_PI(x)               \
+               SYM_FUNC_END_ALIAS(x);          \
+               SYM_FUNC_END_ALIAS(__pi_##x)
+
 #endif
index 87b90dc..7b36096 100644 (file)
 #define MT_NORMAL              0
 #define MT_NORMAL_TAGGED       1
 #define MT_NORMAL_NC           2
-#define MT_NORMAL_WT           3
-#define MT_DEVICE_nGnRnE       4
-#define MT_DEVICE_nGnRE                5
-#define MT_DEVICE_GRE          6
+#define MT_DEVICE_nGnRnE       3
+#define MT_DEVICE_nGnRE                4
 
 /*
  * Memory types for Stage-2 translation
index d3cef91..eeb2109 100644 (file)
@@ -177,9 +177,9 @@ static inline void update_saved_ttbr0(struct task_struct *tsk,
                return;
 
        if (mm == &init_mm)
-               ttbr = __pa_symbol(reserved_pg_dir);
+               ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
        else
-               ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
+               ttbr = phys_to_ttbr(virt_to_phys(mm->pgd)) | ASID(mm) << 48;
 
        WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr);
 }
index 8100456..a11ccad 100644 (file)
@@ -1,7 +1,20 @@
-#ifdef CONFIG_ARM64_MODULE_PLTS
 SECTIONS {
+#ifdef CONFIG_ARM64_MODULE_PLTS
        .plt 0 (NOLOAD) : { BYTE(0) }
        .init.plt 0 (NOLOAD) : { BYTE(0) }
        .text.ftrace_trampoline 0 (NOLOAD) : { BYTE(0) }
-}
 #endif
+
+#ifdef CONFIG_KASAN_SW_TAGS
+       /*
+        * Outlined checks go into comdat-deduplicated sections named .text.hot.
+        * Because they are in comdats they are not combined by the linker and
+        * we otherwise end up with multiple sections with the same .text.hot
+        * name in the .ko file. The kernel module loader warns if it sees
+        * multiple sections with the same name so we use this sections
+        * directive to force them into a single section and silence the
+        * warning.
+        */
+       .text.hot : { *(.text.hot) }
+#endif
+}
index cf241b0..626d359 100644 (file)
@@ -7,6 +7,7 @@
 
 #define MTE_GRANULE_SIZE       UL(16)
 #define MTE_GRANULE_MASK       (~(MTE_GRANULE_SIZE - 1))
+#define MTE_GRANULES_PER_PAGE  (PAGE_SIZE / MTE_GRANULE_SIZE)
 #define MTE_TAG_SHIFT          56
 #define MTE_TAG_SIZE           4
 #define MTE_TAG_MASK           GENMASK((MTE_TAG_SHIFT + (MTE_TAG_SIZE - 1)), MTE_TAG_SHIFT)
index ddd4d17..d952352 100644 (file)
@@ -48,43 +48,84 @@ static inline u8 mte_get_random_tag(void)
        return mte_get_ptr_tag(addr);
 }
 
+static inline u64 __stg_post(u64 p)
+{
+       asm volatile(__MTE_PREAMBLE "stg %0, [%0], #16"
+                    : "+r"(p)
+                    :
+                    : "memory");
+       return p;
+}
+
+static inline u64 __stzg_post(u64 p)
+{
+       asm volatile(__MTE_PREAMBLE "stzg %0, [%0], #16"
+                    : "+r"(p)
+                    :
+                    : "memory");
+       return p;
+}
+
+static inline void __dc_gva(u64 p)
+{
+       asm volatile(__MTE_PREAMBLE "dc gva, %0" : : "r"(p) : "memory");
+}
+
+static inline void __dc_gzva(u64 p)
+{
+       asm volatile(__MTE_PREAMBLE "dc gzva, %0" : : "r"(p) : "memory");
+}
+
 /*
  * Assign allocation tags for a region of memory based on the pointer tag.
  * Note: The address must be non-NULL and MTE_GRANULE_SIZE aligned and
- * size must be non-zero and MTE_GRANULE_SIZE aligned.
+ * size must be MTE_GRANULE_SIZE aligned.
  */
-static inline void mte_set_mem_tag_range(void *addr, size_t size,
-                                               u8 tag, bool init)
+static inline void mte_set_mem_tag_range(void *addr, size_t size, u8 tag,
+                                        bool init)
 {
-       u64 curr, end;
+       u64 curr, mask, dczid_bs, end1, end2, end3;
 
-       if (!size)
-               return;
+       /* Read DC G(Z)VA block size from the system register. */
+       dczid_bs = 4ul << (read_cpuid(DCZID_EL0) & 0xf);
 
        curr = (u64)__tag_set(addr, tag);
-       end = curr + size;
+       mask = dczid_bs - 1;
+       /* STG/STZG up to the end of the first block. */
+       end1 = curr | mask;
+       end3 = curr + size;
+       /* DC GVA / GZVA in [end1, end2) */
+       end2 = end3 & ~mask;
 
        /*
-        * 'asm volatile' is required to prevent the compiler to move
-        * the statement outside of the loop.
+        * The following code uses STG on the first DC GVA block even if the
+        * start address is aligned - it appears to be faster than an alignment
+        * check + conditional branch. Also, if the range size is at least 2 DC
+        * GVA blocks, the first two loops can use post-condition to save one
+        * branch each.
         */
-       if (init) {
-               do {
-                       asm volatile(__MTE_PREAMBLE "stzg %0, [%0]"
-                                    :
-                                    : "r" (curr)
-                                    : "memory");
-                       curr += MTE_GRANULE_SIZE;
-               } while (curr != end);
-       } else {
-               do {
-                       asm volatile(__MTE_PREAMBLE "stg %0, [%0]"
-                                    :
-                                    : "r" (curr)
-                                    : "memory");
-                       curr += MTE_GRANULE_SIZE;
-               } while (curr != end);
-       }
+#define SET_MEMTAG_RANGE(stg_post, dc_gva)             \
+       do {                                            \
+               if (size >= 2 * dczid_bs) {             \
+                       do {                            \
+                               curr = stg_post(curr);  \
+                       } while (curr < end1);          \
+                                                       \
+                       do {                            \
+                               dc_gva(curr);           \
+                               curr += dczid_bs;       \
+                       } while (curr < end2);          \
+               }                                       \
+                                                       \
+               while (curr < end3)                     \
+                       curr = stg_post(curr);          \
+       } while (0)
+
+       if (init)
+               SET_MEMTAG_RANGE(__stzg_post, __dc_gzva);
+       else
+               SET_MEMTAG_RANGE(__stg_post, __dc_gva);
+#undef SET_MEMTAG_RANGE
 }
 
 void mte_enable_kernel_sync(void);
index bc88a1c..58c7f80 100644 (file)
@@ -37,7 +37,8 @@ void mte_free_tag_storage(char *storage);
 /* track which pages have valid allocation tags */
 #define PG_mte_tagged  PG_arch_2
 
-void mte_sync_tags(pte_t *ptep, pte_t pte);
+void mte_zero_clear_page_tags(void *addr);
+void mte_sync_tags(pte_t old_pte, pte_t pte);
 void mte_copy_page_tags(void *kto, const void *kfrom);
 void mte_thread_init_user(void);
 void mte_thread_switch(struct task_struct *next);
@@ -53,7 +54,10 @@ int mte_ptrace_copy_tags(struct task_struct *child, long request,
 /* unused if !CONFIG_ARM64_MTE, silence the compiler */
 #define PG_mte_tagged  0
 
-static inline void mte_sync_tags(pte_t *ptep, pte_t pte)
+static inline void mte_zero_clear_page_tags(void *addr)
+{
+}
+static inline void mte_sync_tags(pte_t old_pte, pte_t pte)
 {
 }
 static inline void mte_copy_page_tags(void *kto, const void *kfrom)
index 012cffc..ed1b9dc 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/personality.h> /* for READ_IMPLIES_EXEC */
+#include <linux/types.h> /* for gfp_t */
 #include <asm/pgtable-types.h>
 
 struct page;
@@ -28,9 +29,12 @@ void copy_user_highpage(struct page *to, struct page *from,
 void copy_highpage(struct page *to, struct page *from);
 #define __HAVE_ARCH_COPY_HIGHPAGE
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+                                               unsigned long vaddr);
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
+
+void tag_clear_highpage(struct page *to);
+#define __HAVE_ARCH_TAG_CLEAR_HIGHPAGE
 
 #define clear_user_page(page, vaddr, pg)       clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
diff --git a/arch/arm64/include/asm/patching.h b/arch/arm64/include/asm/patching.h
new file mode 100644 (file)
index 0000000..6bf5adc
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef        __ASM_PATCHING_H
+#define        __ASM_PATCHING_H
+
+#include <linux/types.h>
+
+int aarch64_insn_read(void *addr, u32 *insnp);
+int aarch64_insn_write(void *addr, u32 insn);
+
+int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
+int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
+
+#endif /* __ASM_PATCHING_H */
index 60731f6..4ef6f19 100644 (file)
 /* PMMIR_EL1.SLOTS mask */
 #define ARMV8_PMU_SLOTS_MASK   0xff
 
+#define ARMV8_PMU_BUS_SLOTS_SHIFT 8
+#define ARMV8_PMU_BUS_SLOTS_MASK 0xff
+#define ARMV8_PMU_BUS_WIDTH_SHIFT 16
+#define ARMV8_PMU_BUS_WIDTH_MASK 0xf
+
 #ifdef CONFIG_PERF_EVENTS
 struct pt_regs;
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
index b82575a..40085e5 100644 (file)
 #define PTRS_PER_PGD           (1 << (VA_BITS - PGDIR_SHIFT))
 
 /*
- * Section address mask and size definitions.
- */
-#define SECTION_SHIFT          PMD_SHIFT
-#define SECTION_SIZE           (_AC(1, UL) << SECTION_SHIFT)
-#define SECTION_MASK           (~(SECTION_SIZE-1))
-
-/*
  * Contiguous page definitions.
  */
 #define CONT_PTE_SHIFT         (CONFIG_ARM64_CONT_PTE_SHIFT + PAGE_SHIFT)
index 938092d..7032f04 100644 (file)
@@ -55,7 +55,6 @@ extern bool arm64_use_ng_mappings;
 #define PROT_DEVICE_nGnRnE     (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
 #define PROT_DEVICE_nGnRE      (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
-#define PROT_NORMAL_WT         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
 #define PROT_NORMAL            (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
 #define PROT_NORMAL_TAGGED     (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_TAGGED))
 
index 0b10204..c0ba8cd 100644 (file)
@@ -314,9 +314,25 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
                __sync_icache_dcache(pte);
 
-       if (system_supports_mte() &&
-           pte_present(pte) && pte_tagged(pte) && !pte_special(pte))
-               mte_sync_tags(ptep, pte);
+       /*
+        * If the PTE would provide user space access to the tags associated
+        * with it then ensure that the MTE tags are synchronised.  Although
+        * pte_access_permitted() returns false for exec only mappings, they
+        * don't expose tags (instruction fetches don't check tags).
+        */
+       if (system_supports_mte() && pte_access_permitted(pte, false) &&
+           !pte_special(pte)) {
+               pte_t old_pte = READ_ONCE(*ptep);
+               /*
+                * We only need to synchronise if the new PTE has tags enabled
+                * or if swapping in (in which case another mapping may have
+                * set tags in the past even if this PTE isn't tagged).
+                * (!pte_none() && !pte_present()) is an open coded version of
+                * is_swap_pte()
+                */
+               if (pte_tagged(pte) || (!pte_none(old_pte) && !pte_present(old_pte)))
+                       mte_sync_tags(old_pte, pte);
+       }
 
        __check_racy_pte_update(mm, ptep, pte);
 
@@ -511,13 +527,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 
 #define pmd_none(pmd)          (!pmd_val(pmd))
 
-#define pmd_bad(pmd)           (!(pmd_val(pmd) & PMD_TABLE_BIT))
-
 #define pmd_table(pmd)         ((pmd_val(pmd) & PMD_TYPE_MASK) == \
                                 PMD_TYPE_TABLE)
 #define pmd_sect(pmd)          ((pmd_val(pmd) & PMD_TYPE_MASK) == \
                                 PMD_TYPE_SECT)
 #define pmd_leaf(pmd)          pmd_sect(pmd)
+#define pmd_bad(pmd)           (!pmd_table(pmd))
 
 #define pmd_leaf_size(pmd)     (pmd_cont(pmd) ? CONT_PMD_SIZE : PMD_SIZE)
 #define pte_leaf_size(pte)     (pte_cont(pte) ? CONT_PTE_SIZE : PAGE_SIZE)
@@ -604,7 +619,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
        pr_err("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
 
 #define pud_none(pud)          (!pud_val(pud))
-#define pud_bad(pud)           (!(pud_val(pud) & PUD_TABLE_BIT))
+#define pud_bad(pud)           (!pud_table(pud))
 #define pud_present(pud)       pte_present(pud_pte(pud))
 #define pud_leaf(pud)          pud_sect(pud)
 #define pud_valid(pud)         pte_valid(pud_pte(pud))
index d50416b..28a78b6 100644 (file)
@@ -31,10 +31,6 @@ struct ptrauth_keys_user {
        struct ptrauth_key apga;
 };
 
-struct ptrauth_keys_kernel {
-       struct ptrauth_key apia;
-};
-
 #define __ptrauth_key_install_nosync(k, v)                     \
 do {                                                           \
        struct ptrauth_key __pki_v = (v);                       \
@@ -42,6 +38,29 @@ do {                                                         \
        write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);     \
 } while (0)
 
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
+
+struct ptrauth_keys_kernel {
+       struct ptrauth_key apia;
+};
+
+static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
+{
+       if (system_supports_address_auth())
+               get_random_bytes(&keys->apia, sizeof(keys->apia));
+}
+
+static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
+{
+       if (!system_supports_address_auth())
+               return;
+
+       __ptrauth_key_install_nosync(APIA, keys->apia);
+       isb();
+}
+
+#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
+
 static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys)
 {
        if (system_supports_address_auth()) {
@@ -69,21 +88,6 @@ static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
        ptrauth_keys_install_user(keys);
 }
 
-static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
-{
-       if (system_supports_address_auth())
-               get_random_bytes(&keys->apia, sizeof(keys->apia));
-}
-
-static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
-{
-       if (!system_supports_address_auth())
-               return;
-
-       __ptrauth_key_install_nosync(APIA, keys->apia);
-       isb();
-}
-
 extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
 
 extern int ptrauth_set_enabled_keys(struct task_struct *tsk, unsigned long keys,
@@ -121,11 +125,6 @@ static __always_inline void ptrauth_enable(void)
 #define ptrauth_thread_switch_user(tsk)                                        \
        ptrauth_keys_install_user(&(tsk)->thread.keys_user)
 
-#define ptrauth_thread_init_kernel(tsk)                                        \
-       ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
-#define ptrauth_thread_switch_kernel(tsk)                              \
-       ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
-
 #else /* CONFIG_ARM64_PTR_AUTH */
 #define ptrauth_enable()
 #define ptrauth_prctl_reset_keys(tsk, arg)     (-EINVAL)
@@ -134,11 +133,19 @@ static __always_inline void ptrauth_enable(void)
 #define ptrauth_strip_insn_pac(lr)     (lr)
 #define ptrauth_suspend_exit()
 #define ptrauth_thread_init_user()
-#define ptrauth_thread_init_kernel(tsk)
 #define ptrauth_thread_switch_user(tsk)
-#define ptrauth_thread_switch_kernel(tsk)
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
+#define ptrauth_thread_init_kernel(tsk)                                        \
+       ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
+#define ptrauth_thread_switch_kernel(tsk)                              \
+       ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
+#else
+#define ptrauth_thread_init_kernel(tsk)
+#define ptrauth_thread_switch_kernel(tsk)
+#endif /* CONFIG_ARM64_PTR_AUTH_KERNEL */
+
 #define PR_PAC_ENABLED_KEYS_MASK                                               \
        (PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY)
 
index 80e946b..e83f098 100644 (file)
@@ -23,7 +23,7 @@ static inline void preempt_count_set(u64 pc)
 } while (0)
 
 #define init_idle_preempt_count(p, cpu) do { \
-       task_thread_info(p)->preempt_count = PREEMPT_ENABLED; \
+       task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \
 } while (0)
 
 static inline void set_preempt_need_resched(void)
index 9df3fee..b6517fd 100644 (file)
@@ -148,8 +148,10 @@ struct thread_struct {
        struct debug_info       debug;          /* debugging */
 #ifdef CONFIG_ARM64_PTR_AUTH
        struct ptrauth_keys_user        keys_user;
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
        struct ptrauth_keys_kernel      keys_kernel;
 #endif
+#endif
 #ifdef CONFIG_ARM64_MTE
        u64                     gcr_user_excl;
 #endif
@@ -257,8 +259,6 @@ void set_task_sctlr_el1(u64 sctlr);
 extern struct task_struct *cpu_switch_to(struct task_struct *prev,
                                         struct task_struct *next);
 
-asmlinkage void arm64_preempt_schedule_irq(void);
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1)
 
@@ -329,13 +329,13 @@ long get_tagged_addr_ctrl(struct task_struct *task);
  * of header definitions for the use of task_stack_page.
  */
 
-#define current_top_of_stack()                                                 \
-({                                                                             \
-       struct stack_info _info;                                                \
-       BUG_ON(!on_accessible_stack(current, current_stack_pointer, &_info));   \
-       _info.high;                                                             \
+#define current_top_of_stack()                                                         \
+({                                                                                     \
+       struct stack_info _info;                                                        \
+       BUG_ON(!on_accessible_stack(current, current_stack_pointer, 1, &_info));        \
+       _info.high;                                                                     \
 })
-#define on_thread_stack()      (on_task_stack(current, current_stack_pointer, NULL))
+#define on_thread_stack()      (on_task_stack(current, current_stack_pointer, 1, NULL))
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_PROCESSOR_H */
index eaa2cd9..8297bcc 100644 (file)
@@ -9,18 +9,18 @@
 #ifdef CONFIG_SHADOW_CALL_STACK
        scs_sp  .req    x18
 
-       .macro scs_load tsk, tmp
+       .macro scs_load tsk
        ldr     scs_sp, [\tsk, #TSK_TI_SCS_SP]
        .endm
 
-       .macro scs_save tsk, tmp
+       .macro scs_save tsk
        str     scs_sp, [\tsk, #TSK_TI_SCS_SP]
        .endm
 #else
-       .macro scs_load tsk, tmp
+       .macro scs_load tsk
        .endm
 
-       .macro scs_save tsk, tmp
+       .macro scs_save tsk
        .endm
 #endif /* CONFIG_SHADOW_CALL_STACK */
 
index 63e0b92..7bea1d7 100644 (file)
@@ -37,13 +37,17 @@ struct sdei_registered_event;
 asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
                                        struct sdei_registered_event *arg);
 
+unsigned long do_sdei_event(struct pt_regs *regs,
+                           struct sdei_registered_event *arg);
+
 unsigned long sdei_arch_get_entry_point(int conduit);
 #define sdei_arch_get_entry_point(x)   sdei_arch_get_entry_point(x)
 
 struct stack_info;
 
-bool _on_sdei_stack(unsigned long sp, struct stack_info *info);
-static inline bool on_sdei_stack(unsigned long sp,
+bool _on_sdei_stack(unsigned long sp, unsigned long size,
+                   struct stack_info *info);
+static inline bool on_sdei_stack(unsigned long sp, unsigned long size,
                                struct stack_info *info)
 {
        if (!IS_ENABLED(CONFIG_VMAP_STACK))
@@ -51,7 +55,7 @@ static inline bool on_sdei_stack(unsigned long sp,
        if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
                return false;
        if (in_nmi())
-               return _on_sdei_stack(sp, info);
+               return _on_sdei_stack(sp, size, info);
 
        return false;
 }
index 0e35775..fc55f5a 100644 (file)
@@ -73,12 +73,10 @@ asmlinkage void secondary_start_kernel(void);
 
 /*
  * Initial data for bringing up a secondary CPU.
- * @stack  - sp for the secondary CPU
  * @status - Result passed back from the secondary CPU to
  *           indicate failure.
  */
 struct secondary_data {
-       void *stack;
        struct task_struct *task;
        long status;
 };
index 4b33ca6..1801399 100644 (file)
@@ -69,14 +69,14 @@ extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
 
 DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
 
-static inline bool on_stack(unsigned long sp, unsigned long low,
-                               unsigned long high, enum stack_type type,
-                               struct stack_info *info)
+static inline bool on_stack(unsigned long sp, unsigned long size,
+                           unsigned long low, unsigned long high,
+                           enum stack_type type, struct stack_info *info)
 {
        if (!low)
                return false;
 
-       if (sp < low || sp >= high)
+       if (sp < low || sp + size < sp || sp + size > high)
                return false;
 
        if (info) {
@@ -87,38 +87,38 @@ static inline bool on_stack(unsigned long sp, unsigned long low,
        return true;
 }
 
-static inline bool on_irq_stack(unsigned long sp,
+static inline bool on_irq_stack(unsigned long sp, unsigned long size,
                                struct stack_info *info)
 {
        unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
        unsigned long high = low + IRQ_STACK_SIZE;
 
-       return on_stack(sp, low, high, STACK_TYPE_IRQ, info);
+       return on_stack(sp, size, low, high, STACK_TYPE_IRQ, info);
 }
 
 static inline bool on_task_stack(const struct task_struct *tsk,
-                                unsigned long sp,
+                                unsigned long sp, unsigned long size,
                                 struct stack_info *info)
 {
        unsigned long low = (unsigned long)task_stack_page(tsk);
        unsigned long high = low + THREAD_SIZE;
 
-       return on_stack(sp, low, high, STACK_TYPE_TASK, info);
+       return on_stack(sp, size, low, high, STACK_TYPE_TASK, info);
 }
 
 #ifdef CONFIG_VMAP_STACK
 DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
 
-static inline bool on_overflow_stack(unsigned long sp,
+static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
                                struct stack_info *info)
 {
        unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
        unsigned long high = low + OVERFLOW_STACK_SIZE;
 
-       return on_stack(sp, low, high, STACK_TYPE_OVERFLOW, info);
+       return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info);
 }
 #else
-static inline bool on_overflow_stack(unsigned long sp,
+static inline bool on_overflow_stack(unsigned long sp, unsigned long size,
                        struct stack_info *info) { return false; }
 #endif
 
@@ -128,21 +128,21 @@ static inline bool on_overflow_stack(unsigned long sp,
  * context.
  */
 static inline bool on_accessible_stack(const struct task_struct *tsk,
-                                      unsigned long sp,
+                                      unsigned long sp, unsigned long size,
                                       struct stack_info *info)
 {
        if (info)
                info->type = STACK_TYPE_UNKNOWN;
 
-       if (on_task_stack(tsk, sp, info))
+       if (on_task_stack(tsk, sp, size, info))
                return true;
        if (tsk != current || preemptible())
                return false;
-       if (on_irq_stack(sp, info))
+       if (on_irq_stack(sp, size, info))
                return true;
-       if (on_overflow_stack(sp, info))
+       if (on_overflow_stack(sp, size, info))
                return true;
-       if (on_sdei_stack(sp, info))
+       if (on_sdei_stack(sp, size, info))
                return true;
 
        return false;
index 65d1570..7b9c3ac 100644 (file)
 
 #define INIT_SCTLR_EL2_MMU_ON                                          \
        (SCTLR_ELx_M  | SCTLR_ELx_C | SCTLR_ELx_SA | SCTLR_ELx_I |      \
-        SCTLR_ELx_IESB | SCTLR_ELx_WXN | ENDIAN_SET_EL2 | SCTLR_EL2_RES1)
+        SCTLR_ELx_IESB | SCTLR_ELx_WXN | ENDIAN_SET_EL2 |              \
+        SCTLR_ELx_ITFSB | SCTLR_EL2_RES1)
 
 #define INIT_SCTLR_EL2_MMU_OFF \
        (SCTLR_EL2_RES1 | ENDIAN_SET_EL2)
 /* MAIR_ELx memory attributes (used by Linux) */
 #define MAIR_ATTR_DEVICE_nGnRnE                UL(0x00)
 #define MAIR_ATTR_DEVICE_nGnRE         UL(0x04)
-#define MAIR_ATTR_DEVICE_GRE           UL(0x0c)
 #define MAIR_ATTR_NORMAL_NC            UL(0x44)
-#define MAIR_ATTR_NORMAL_WT            UL(0xbb)
 #define MAIR_ATTR_NORMAL_TAGGED                UL(0xf0)
 #define MAIR_ATTR_NORMAL               UL(0xff)
 #define MAIR_ATTR_MASK                 UL(0xff)
index 61c97d3..c995d1f 100644 (file)
@@ -28,6 +28,10 @@ static void tlb_flush(struct mmu_gather *tlb);
  */
 static inline int tlb_get_level(struct mmu_gather *tlb)
 {
+       /* The TTL field is only valid for the leaf entry. */
+       if (tlb->freed_tables)
+               return 0;
+
        if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
                                   tlb->cleared_puds ||
                                   tlb->cleared_p4ds))
index 24223ad..b3edde6 100644 (file)
@@ -184,6 +184,17 @@ struct kvm_vcpu_events {
        __u32 reserved[12];
 };
 
+struct kvm_arm_copy_mte_tags {
+       __u64 guest_ipa;
+       __u64 length;
+       void __user *addr;
+       __u64 flags;
+       __u64 reserved[2];
+};
+
+#define KVM_ARM_TAGS_TO_GUEST          0
+#define KVM_ARM_TAGS_FROM_GUEST                1
+
 /* If you need to interpret the index values, here is the key: */
 #define KVM_REG_ARM_COPROC_MASK                0x000000000FFF0000
 #define KVM_REG_ARM_COPROC_SHIFT       16
index 6cc9773..cce3085 100644 (file)
@@ -14,15 +14,22 @@ CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_syscall.o         = -fstack-protector -fstack-protector-strong
 CFLAGS_syscall.o       += -fno-stack-protector
 
+# It's not safe to invoke KCOV when portions of the kernel environment aren't
+# available or are out-of-sync with HW state. Since `noinstr` doesn't always
+# inhibit KCOV instrumentation, disable it for the entire compilation unit.
+KCOV_INSTRUMENT_entry.o := n
+KCOV_INSTRUMENT_idle.o := n
+
 # Object file lists.
 obj-y                  := debug-monitors.o entry.o irq.o fpsimd.o              \
                           entry-common.o entry-fpsimd.o process.o ptrace.o     \
                           setup.o signal.o sys.o stacktrace.o time.o traps.o   \
-                          io.o vdso.o hyp-stub.o psci.o cpu_ops.o insn.o       \
+                          io.o vdso.o hyp-stub.o psci.o cpu_ops.o              \
                           return_address.o cpuinfo.o cpu_errata.o              \
                           cpufeature.o alternative.o cacheinfo.o               \
                           smp.o smp_spin_table.o topology.o smccc-call.o       \
-                          syscall.o proton-pack.o idreg-override.o
+                          syscall.o proton-pack.o idreg-override.o idle.o      \
+                          patching.o
 
 targets                        += efi-entry.o
 
index cada0b8..f385172 100644 (file)
@@ -239,6 +239,18 @@ done:
        }
 }
 
+static pgprot_t __acpi_get_writethrough_mem_attribute(void)
+{
+       /*
+        * Although UEFI specifies the use of Normal Write-through for
+        * EFI_MEMORY_WT, it is seldom used in practice and not implemented
+        * by most (all?) CPUs. Rather than allocate a MAIR just for this
+        * purpose, emit a warning and use Normal Non-cacheable instead.
+        */
+       pr_warn_once("No MAIR allocation for EFI_MEMORY_WT; treating as Normal Non-cacheable\n");
+       return __pgprot(PROT_NORMAL_NC);
+}
+
 pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
 {
        /*
@@ -246,7 +258,7 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
         * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is
         * mapped to a corresponding MAIR attribute encoding.
         * The EFI memory attribute advises all possible capabilities
-        * of a memory region. We use the most efficient capability.
+        * of a memory region.
         */
 
        u64 attr;
@@ -254,10 +266,10 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
        attr = efi_mem_attributes(addr);
        if (attr & EFI_MEMORY_WB)
                return PAGE_KERNEL;
-       if (attr & EFI_MEMORY_WT)
-               return __pgprot(PROT_NORMAL_WT);
        if (attr & EFI_MEMORY_WC)
                return __pgprot(PROT_NORMAL_NC);
+       if (attr & EFI_MEMORY_WT)
+               return __acpi_get_writethrough_mem_attribute();
        return __pgprot(PROT_DEVICE_nGnRnE);
 }
 
@@ -340,10 +352,10 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                default:
                        if (region->attribute & EFI_MEMORY_WB)
                                prot = PAGE_KERNEL;
-                       else if (region->attribute & EFI_MEMORY_WT)
-                               prot = __pgprot(PROT_NORMAL_WT);
                        else if (region->attribute & EFI_MEMORY_WC)
                                prot = __pgprot(PROT_NORMAL_NC);
+                       else if (region->attribute & EFI_MEMORY_WT)
+                               prot = __acpi_get_writethrough_mem_attribute();
                }
        }
        return __ioremap(phys, size, prot);
index c906d20..3fb79b7 100644 (file)
@@ -181,7 +181,7 @@ static void __nocfi __apply_alternatives(struct alt_region *region, bool is_modu
         */
        if (!is_module) {
                dsb(ish);
-               __flush_icache_all();
+               icache_inval_all_pou();
                isb();
 
                /* Ignore ARM64_CB bit from feature mask */
index 0cb34cc..c856706 100644 (file)
@@ -27,6 +27,7 @@
 int main(void)
 {
   DEFINE(TSK_ACTIVE_MM,                offsetof(struct task_struct, active_mm));
+  DEFINE(TSK_CPU,              offsetof(struct task_struct, cpu));
   BLANK();
   DEFINE(TSK_TI_FLAGS,         offsetof(struct task_struct, thread_info.flags));
   DEFINE(TSK_TI_PREEMPT,       offsetof(struct task_struct, thread_info.preempt_count));
@@ -46,6 +47,8 @@ int main(void)
   DEFINE(THREAD_SCTLR_USER,    offsetof(struct task_struct, thread.sctlr_user));
 #ifdef CONFIG_ARM64_PTR_AUTH
   DEFINE(THREAD_KEYS_USER,     offsetof(struct task_struct, thread.keys_user));
+#endif
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
   DEFINE(THREAD_KEYS_KERNEL,   offsetof(struct task_struct, thread.keys_kernel));
 #endif
 #ifdef CONFIG_ARM64_MTE
@@ -99,7 +102,6 @@ int main(void)
   DEFINE(SOFTIRQ_SHIFT, SOFTIRQ_SHIFT);
   DEFINE(IRQ_CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
   BLANK();
-  DEFINE(CPU_BOOT_STACK,       offsetof(struct secondary_data, stack));
   DEFINE(CPU_BOOT_TASK,                offsetof(struct secondary_data, task));
   BLANK();
   DEFINE(FTR_OVR_VAL_OFFSET,   offsetof(struct arm64_ftr_override, val));
@@ -111,6 +113,8 @@ int main(void)
   DEFINE(VCPU_WORKAROUND_FLAGS,        offsetof(struct kvm_vcpu, arch.workaround_flags));
   DEFINE(VCPU_HCR_EL2,         offsetof(struct kvm_vcpu, arch.hcr_el2));
   DEFINE(CPU_USER_PT_REGS,     offsetof(struct kvm_cpu_context, regs));
+  DEFINE(CPU_RGSR_EL1,         offsetof(struct kvm_cpu_context, sys_regs[RGSR_EL1]));
+  DEFINE(CPU_GCR_EL1,          offsetof(struct kvm_cpu_context, sys_regs[GCR_EL1]));
   DEFINE(CPU_APIAKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APIAKEYLO_EL1]));
   DEFINE(CPU_APIBKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APIBKEYLO_EL1]));
   DEFINE(CPU_APDAKEYLO_EL1,    offsetof(struct kvm_cpu_context, sys_regs[APDAKEYLO_EL1]));
@@ -138,6 +142,15 @@ int main(void)
   DEFINE(ARM_SMCCC_RES_X2_OFFS,                offsetof(struct arm_smccc_res, a2));
   DEFINE(ARM_SMCCC_QUIRK_ID_OFFS,      offsetof(struct arm_smccc_quirk, id));
   DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS,   offsetof(struct arm_smccc_quirk, state));
+  DEFINE(ARM_SMCCC_1_2_REGS_X0_OFFS,   offsetof(struct arm_smccc_1_2_regs, a0));
+  DEFINE(ARM_SMCCC_1_2_REGS_X2_OFFS,   offsetof(struct arm_smccc_1_2_regs, a2));
+  DEFINE(ARM_SMCCC_1_2_REGS_X4_OFFS,   offsetof(struct arm_smccc_1_2_regs, a4));
+  DEFINE(ARM_SMCCC_1_2_REGS_X6_OFFS,   offsetof(struct arm_smccc_1_2_regs, a6));
+  DEFINE(ARM_SMCCC_1_2_REGS_X8_OFFS,   offsetof(struct arm_smccc_1_2_regs, a8));
+  DEFINE(ARM_SMCCC_1_2_REGS_X10_OFFS,  offsetof(struct arm_smccc_1_2_regs, a10));
+  DEFINE(ARM_SMCCC_1_2_REGS_X12_OFFS,  offsetof(struct arm_smccc_1_2_regs, a12));
+  DEFINE(ARM_SMCCC_1_2_REGS_X14_OFFS,  offsetof(struct arm_smccc_1_2_regs, a14));
+  DEFINE(ARM_SMCCC_1_2_REGS_X16_OFFS,  offsetof(struct arm_smccc_1_2_regs, a16));
   BLANK();
   DEFINE(HIBERN_PBE_ORIG,      offsetof(struct pbe, orig_address));
   DEFINE(HIBERN_PBE_ADDR,      offsetof(struct pbe, address));
@@ -153,7 +166,9 @@ int main(void)
 #endif
 #ifdef CONFIG_ARM64_PTR_AUTH
   DEFINE(PTRAUTH_USER_KEY_APIA,                offsetof(struct ptrauth_keys_user, apia));
+#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL
   DEFINE(PTRAUTH_KERNEL_KEY_APIA,      offsetof(struct ptrauth_keys_kernel, apia));
+#endif
   BLANK();
 #endif
   return 0;
index efed283..125d5c9 100644 (file)
@@ -76,6 +76,7 @@
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/fpsimd.h>
+#include <asm/insn.h>
 #include <asm/kvm_host.h>
 #include <asm/mmu_context.h>
 #include <asm/mte.h>
@@ -108,6 +109,24 @@ bool arm64_use_ng_mappings = false;
 EXPORT_SYMBOL(arm64_use_ng_mappings);
 
 /*
+ * Permit PER_LINUX32 and execve() of 32-bit binaries even if not all CPUs
+ * support it?
+ */
+static bool __read_mostly allow_mismatched_32bit_el0;
+
+/*
+ * Static branch enabled only if allow_mismatched_32bit_el0 is set and we have
+ * seen at least one CPU capable of 32-bit EL0.
+ */
+DEFINE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
+
+/*
+ * Mask of CPUs supporting 32-bit EL0.
+ * Only valid if arm64_mismatched_32bit_el0 is enabled.
+ */
+static cpumask_var_t cpu_32bit_el0_mask __cpumask_var_read_mostly;
+
+/*
  * Flag to indicate if we have computed the system wide
  * capabilities based on the boot time active CPUs. This
  * will be used to determine if a new booting CPU should
@@ -400,6 +419,11 @@ static const struct arm64_ftr_bits ftr_dczid[] = {
        ARM64_FTR_END,
 };
 
+static const struct arm64_ftr_bits ftr_gmid[] = {
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, SYS_GMID_EL1_BS_SHIFT, 4, 0),
+       ARM64_FTR_END,
+};
+
 static const struct arm64_ftr_bits ftr_id_isar0[] = {
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_DIVIDE_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR0_DEBUG_SHIFT, 4, 0),
@@ -617,6 +641,9 @@ static const struct __ftr_reg_entry {
        /* Op1 = 0, CRn = 1, CRm = 2 */
        ARM64_FTR_REG(SYS_ZCR_EL1, ftr_zcr),
 
+       /* Op1 = 1, CRn = 0, CRm = 0 */
+       ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid),
+
        /* Op1 = 3, CRn = 0, CRm = 0 */
        { SYS_CTR_EL0, &arm64_ftr_reg_ctrel0 },
        ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid),
@@ -767,7 +794,7 @@ static void __init sort_ftr_regs(void)
  * Any bits that are not covered by an arm64_ftr_bits entry are considered
  * RES0 for the system-wide value, and must strictly match.
  */
-static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
+static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
 {
        u64 val = 0;
        u64 strict_mask = ~0x0ULL;
@@ -863,6 +890,31 @@ static void __init init_cpu_hwcaps_indirect_list(void)
 
 static void __init setup_boot_cpu_capabilities(void);
 
+static void init_32bit_cpu_features(struct cpuinfo_32bit *info)
+{
+       init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
+       init_cpu_ftr_reg(SYS_ID_DFR1_EL1, info->reg_id_dfr1);
+       init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
+       init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
+       init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
+       init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
+       init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
+       init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
+       init_cpu_ftr_reg(SYS_ID_ISAR6_EL1, info->reg_id_isar6);
+       init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
+       init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
+       init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
+       init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
+       init_cpu_ftr_reg(SYS_ID_MMFR4_EL1, info->reg_id_mmfr4);
+       init_cpu_ftr_reg(SYS_ID_MMFR5_EL1, info->reg_id_mmfr5);
+       init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
+       init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
+       init_cpu_ftr_reg(SYS_ID_PFR2_EL1, info->reg_id_pfr2);
+       init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
+       init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
+       init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
+}
+
 void __init init_cpu_features(struct cpuinfo_arm64 *info)
 {
        /* Before we start using the tables, make sure it is sorted */
@@ -882,35 +934,17 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
        init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
        init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0);
 
-       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
-               init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
-               init_cpu_ftr_reg(SYS_ID_DFR1_EL1, info->reg_id_dfr1);
-               init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
-               init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
-               init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
-               init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
-               init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
-               init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
-               init_cpu_ftr_reg(SYS_ID_ISAR6_EL1, info->reg_id_isar6);
-               init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
-               init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
-               init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
-               init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
-               init_cpu_ftr_reg(SYS_ID_MMFR4_EL1, info->reg_id_mmfr4);
-               init_cpu_ftr_reg(SYS_ID_MMFR5_EL1, info->reg_id_mmfr5);
-               init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
-               init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
-               init_cpu_ftr_reg(SYS_ID_PFR2_EL1, info->reg_id_pfr2);
-               init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
-               init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
-               init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
-       }
+       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
+               init_32bit_cpu_features(&info->aarch32);
 
        if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
                init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
                sve_init_vq_map();
        }
 
+       if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
+               init_cpu_ftr_reg(SYS_GMID_EL1, info->reg_gmid);
+
        /*
         * Initialize the indirect array of CPU hwcaps capabilities pointers
         * before we handle the boot CPU below.
@@ -975,21 +1009,29 @@ static void relax_cpu_ftr_reg(u32 sys_id, int field)
        WARN_ON(!ftrp->width);
 }
 
-static int update_32bit_cpu_features(int cpu, struct cpuinfo_arm64 *info,
-                                    struct cpuinfo_arm64 *boot)
+static void lazy_init_32bit_cpu_features(struct cpuinfo_arm64 *info,
+                                        struct cpuinfo_arm64 *boot)
+{
+       static bool boot_cpu_32bit_regs_overridden = false;
+
+       if (!allow_mismatched_32bit_el0 || boot_cpu_32bit_regs_overridden)
+               return;
+
+       if (id_aa64pfr0_32bit_el0(boot->reg_id_aa64pfr0))
+               return;
+
+       boot->aarch32 = info->aarch32;
+       init_32bit_cpu_features(&boot->aarch32);
+       boot_cpu_32bit_regs_overridden = true;
+}
+
+static int update_32bit_cpu_features(int cpu, struct cpuinfo_32bit *info,
+                                    struct cpuinfo_32bit *boot)
 {
        int taint = 0;
        u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
 
        /*
-        * If we don't have AArch32 at all then skip the checks entirely
-        * as the register values may be UNKNOWN and we're not going to be
-        * using them for anything.
-        */
-       if (!id_aa64pfr0_32bit_el0(pfr0))
-               return taint;
-
-       /*
         * If we don't have AArch32 at EL1, then relax the strictness of
         * EL1-dependent register fields to avoid spurious sanity check fails.
         */
@@ -1135,10 +1177,29 @@ void update_cpu_features(int cpu,
        }
 
        /*
+        * The kernel uses the LDGM/STGM instructions and the number of tags
+        * they read/write depends on the GMID_EL1.BS field. Check that the
+        * value is the same on all CPUs.
+        */
+       if (IS_ENABLED(CONFIG_ARM64_MTE) &&
+           id_aa64pfr1_mte(info->reg_id_aa64pfr1)) {
+               taint |= check_update_ftr_reg(SYS_GMID_EL1, cpu,
+                                             info->reg_gmid, boot->reg_gmid);
+       }
+
+       /*
+        * If we don't have AArch32 at all then skip the checks entirely
+        * as the register values may be UNKNOWN and we're not going to be
+        * using them for anything.
+        *
         * This relies on a sanitised view of the AArch64 ID registers
         * (e.g. SYS_ID_AA64PFR0_EL1), so we call it last.
         */
-       taint |= update_32bit_cpu_features(cpu, info, boot);
+       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
+               lazy_init_32bit_cpu_features(info, boot);
+               taint |= update_32bit_cpu_features(cpu, &info->aarch32,
+                                                  &boot->aarch32);
+       }
 
        /*
         * Mismatched CPU features are a recipe for disaster. Don't even
@@ -1248,6 +1309,28 @@ has_cpuid_feature(const struct arm64_cpu_capabilities *entry, int scope)
        return feature_matches(val, entry);
 }
 
+const struct cpumask *system_32bit_el0_cpumask(void)
+{
+       if (!system_supports_32bit_el0())
+               return cpu_none_mask;
+
+       if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
+               return cpu_32bit_el0_mask;
+
+       return cpu_possible_mask;
+}
+
+static bool has_32bit_el0(const struct arm64_cpu_capabilities *entry, int scope)
+{
+       if (!has_cpuid_feature(entry, scope))
+               return allow_mismatched_32bit_el0;
+
+       if (scope == SCOPE_SYSTEM)
+               pr_info("detected: 32-bit EL0 Support\n");
+
+       return true;
+}
+
 static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry, int scope)
 {
        bool has_sre;
@@ -1866,10 +1949,9 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .cpu_enable = cpu_copy_el2regs,
        },
        {
-               .desc = "32-bit EL0 Support",
-               .capability = ARM64_HAS_32BIT_EL0,
+               .capability = ARM64_HAS_32BIT_EL0_DO_NOT_USE,
                .type = ARM64_CPUCAP_SYSTEM_FEATURE,
-               .matches = has_cpuid_feature,
+               .matches = has_32bit_el0,
                .sys_reg = SYS_ID_AA64PFR0_EL1,
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64PFR0_EL0_SHIFT,
@@ -2378,7 +2460,7 @@ static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = {
        {},
 };
 
-static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap)
+static void cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap)
 {
        switch (cap->hwcap_type) {
        case CAP_HWCAP:
@@ -2423,7 +2505,7 @@ static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
        return rc;
 }
 
-static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
+static void setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
 {
        /* We support emulation of accesses to CPU ID feature registers */
        cpu_set_named_feature(CPUID);
@@ -2598,7 +2680,7 @@ static void check_early_cpu_features(void)
 }
 
 static void
-verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
+__verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
 {
 
        for (; caps->matches; caps++)
@@ -2609,6 +2691,14 @@ verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
                }
 }
 
+static void verify_local_elf_hwcaps(void)
+{
+       __verify_local_elf_hwcaps(arm64_elf_hwcaps);
+
+       if (id_aa64pfr0_32bit_el0(read_cpuid(ID_AA64PFR0_EL1)))
+               __verify_local_elf_hwcaps(compat_elf_hwcaps);
+}
+
 static void verify_sve_features(void)
 {
        u64 safe_zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
@@ -2673,11 +2763,7 @@ static void verify_local_cpu_capabilities(void)
         * on all secondary CPUs.
         */
        verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU);
-
-       verify_local_elf_hwcaps(arm64_elf_hwcaps);
-
-       if (system_supports_32bit_el0())
-               verify_local_elf_hwcaps(compat_elf_hwcaps);
+       verify_local_elf_hwcaps();
 
        if (system_supports_sve())
                verify_sve_features();
@@ -2812,6 +2898,34 @@ void __init setup_cpu_features(void)
                        ARCH_DMA_MINALIGN);
 }
 
+static int enable_mismatched_32bit_el0(unsigned int cpu)
+{
+       struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
+       bool cpu_32bit = id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0);
+
+       if (cpu_32bit) {
+               cpumask_set_cpu(cpu, cpu_32bit_el0_mask);
+               static_branch_enable_cpuslocked(&arm64_mismatched_32bit_el0);
+               setup_elf_hwcaps(compat_elf_hwcaps);
+       }
+
+       return 0;
+}
+
+static int __init init_32bit_el0_mask(void)
+{
+       if (!allow_mismatched_32bit_el0)
+               return 0;
+
+       if (!zalloc_cpumask_var(&cpu_32bit_el0_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+                                "arm64/mismatched_32bit_el0:online",
+                                enable_mismatched_32bit_el0, NULL);
+}
+subsys_initcall_sync(init_32bit_el0_mask);
+
 static void __maybe_unused cpu_enable_cnp(struct arm64_cpu_capabilities const *cap)
 {
        cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
@@ -2905,8 +3019,8 @@ static int emulate_mrs(struct pt_regs *regs, u32 insn)
 }
 
 static struct undef_hook mrs_hook = {
-       .instr_mask = 0xfff00000,
-       .instr_val  = 0xd5300000,
+       .instr_mask = 0xffff0000,
+       .instr_val  = 0xd5380000,
        .pstate_mask = PSR_AA32_MODE_MASK,
        .pstate_val = PSR_MODE_EL0t,
        .fn = emulate_mrs,
index 51fcf99..87731fe 100644 (file)
@@ -246,7 +246,7 @@ static struct kobj_type cpuregs_kobj_type = {
                struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj);             \
                                                                                \
                if (info->reg_midr)                                             \
-                       return sprintf(buf, "0x%016x\n", info->reg_##_field);   \
+                       return sprintf(buf, "0x%016llx\n", info->reg_##_field); \
                else                                                            \
                        return 0;                                               \
        }                                                                       \
@@ -344,6 +344,32 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
        pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
 }
 
+static void __cpuinfo_store_cpu_32bit(struct cpuinfo_32bit *info)
+{
+       info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
+       info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1);
+       info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
+       info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
+       info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
+       info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
+       info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
+       info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
+       info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
+       info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
+       info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
+       info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
+       info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
+       info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1);
+       info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1);
+       info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
+       info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
+       info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1);
+
+       info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
+       info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
+       info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
+}
+
 static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
 {
        info->reg_cntfrq = arch_timer_get_cntfrq();
@@ -371,31 +397,11 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
        info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
        info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
 
-       /* Update the 32bit ID registers only if AArch32 is implemented */
-       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
-               info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
-               info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1);
-               info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
-               info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
-               info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
-               info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
-               info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
-               info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
-               info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
-               info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
-               info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
-               info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
-               info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
-               info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1);
-               info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1);
-               info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
-               info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
-               info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1);
-
-               info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
-               info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
-               info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
-       }
+       if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
+               info->reg_gmid = read_cpuid(GMID_EL1);
+
+       if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
+               __cpuinfo_store_cpu_32bit(&info->aarch32);
 
        if (IS_ENABLED(CONFIG_ARM64_SVE) &&
            id_aa64pfr0_sve(info->reg_id_aa64pfr0))
index 0073b24..61a87fa 100644 (file)
@@ -28,7 +28,8 @@ SYM_CODE_START(efi_enter_kernel)
         * stale icache entries from before relocation.
         */
        ldr     w1, =kernel_size
-       bl      __clean_dcache_area_poc
+       add     x1, x0, x1
+       bl      dcache_clean_poc
        ic      ialluis
 
        /*
@@ -36,8 +37,8 @@ SYM_CODE_START(efi_enter_kernel)
         * so that we can safely disable the MMU and caches.
         */
        adr     x0, 0f
-       ldr     w1, 3f
-       bl      __clean_dcache_area_poc
+       adr     x1, 3f
+       bl      dcache_clean_poc
 0:
        /* Turn off Dcache and MMU */
        mrs     x0, CurrentEL
@@ -64,5 +65,5 @@ SYM_CODE_START(efi_enter_kernel)
        mov     x2, xzr
        mov     x3, xzr
        br      x19
+3:
 SYM_CODE_END(efi_enter_kernel)
-3:     .long   . - 0b
index 340d04e..12ce14a 100644 (file)
@@ -6,7 +6,11 @@
  */
 
 #include <linux/context_tracking.h>
+#include <linux/linkage.h>
+#include <linux/lockdep.h>
 #include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
 #include <linux/thread_info.h>
 
 #include <asm/cpufeature.h>
 #include <asm/exception.h>
 #include <asm/kprobes.h>
 #include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/sdei.h>
+#include <asm/stacktrace.h>
 #include <asm/sysreg.h>
+#include <asm/system_misc.h>
 
 /*
  * This is intended to match the logic in irqentry_enter(), handling the kernel
@@ -67,7 +75,7 @@ static void noinstr exit_to_kernel_mode(struct pt_regs *regs)
        }
 }
 
-void noinstr arm64_enter_nmi(struct pt_regs *regs)
+static void noinstr arm64_enter_nmi(struct pt_regs *regs)
 {
        regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
 
@@ -80,7 +88,7 @@ void noinstr arm64_enter_nmi(struct pt_regs *regs)
        ftrace_nmi_enter();
 }
 
-void noinstr arm64_exit_nmi(struct pt_regs *regs)
+static void noinstr arm64_exit_nmi(struct pt_regs *regs)
 {
        bool restore = regs->lockdep_hardirqs;
 
@@ -97,7 +105,7 @@ void noinstr arm64_exit_nmi(struct pt_regs *regs)
        __nmi_exit();
 }
 
-asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs)
+static void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
                arm64_enter_nmi(regs);
@@ -105,7 +113,7 @@ asmlinkage void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs)
                enter_from_kernel_mode(regs);
 }
 
-asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
+static void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
                arm64_exit_nmi(regs);
@@ -113,6 +121,65 @@ asmlinkage void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
                exit_to_kernel_mode(regs);
 }
 
+static void __sched arm64_preempt_schedule_irq(void)
+{
+       lockdep_assert_irqs_disabled();
+
+       /*
+        * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC
+        * priority masking is used the GIC irqchip driver will clear DAIF.IF
+        * using gic_arch_enable_irqs() for normal IRQs. If anything is set in
+        * DAIF we must have handled an NMI, so skip preemption.
+        */
+       if (system_uses_irq_prio_masking() && read_sysreg(daif))
+               return;
+
+       /*
+        * Preempting a task from an IRQ means we leave copies of PSTATE
+        * on the stack. cpufeature's enable calls may modify PSTATE, but
+        * resuming one of these preempted tasks would undo those changes.
+        *
+        * Only allow a task to be preempted once cpufeatures have been
+        * enabled.
+        */
+       if (system_capabilities_finalized())
+               preempt_schedule_irq();
+}
+
+static void do_interrupt_handler(struct pt_regs *regs,
+                                void (*handler)(struct pt_regs *))
+{
+       if (on_thread_stack())
+               call_on_irq_stack(regs, handler);
+       else
+               handler(regs);
+}
+
+extern void (*handle_arch_irq)(struct pt_regs *);
+extern void (*handle_arch_fiq)(struct pt_regs *);
+
+static void noinstr __panic_unhandled(struct pt_regs *regs, const char *vector,
+                                     unsigned int esr)
+{
+       arm64_enter_nmi(regs);
+
+       console_verbose();
+
+       pr_crit("Unhandled %s exception on CPU%d, ESR 0x%08x -- %s\n",
+               vector, smp_processor_id(), esr,
+               esr_get_class_string(esr));
+
+       __show_regs(regs);
+       panic("Unhandled exception");
+}
+
+#define UNHANDLED(el, regsize, vector)                                                 \
+asmlinkage void noinstr el##_##regsize##_##vector##_handler(struct pt_regs *regs)      \
+{                                                                                      \
+       const char *desc = #regsize "-bit " #el " " #vector;                            \
+       __panic_unhandled(regs, desc, read_sysreg(esr_el1));                            \
+}
+
 #ifdef CONFIG_ARM64_ERRATUM_1463225
 static DEFINE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
 
@@ -162,6 +229,11 @@ static bool cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
 }
 #endif /* CONFIG_ARM64_ERRATUM_1463225 */
 
+UNHANDLED(el1t, 64, sync)
+UNHANDLED(el1t, 64, irq)
+UNHANDLED(el1t, 64, fiq)
+UNHANDLED(el1t, 64, error)
+
 static void noinstr el1_abort(struct pt_regs *regs, unsigned long esr)
 {
        unsigned long far = read_sysreg(far_el1);
@@ -193,15 +265,6 @@ static void noinstr el1_undef(struct pt_regs *regs)
        exit_to_kernel_mode(regs);
 }
 
-static void noinstr el1_inv(struct pt_regs *regs, unsigned long esr)
-{
-       enter_from_kernel_mode(regs);
-       local_daif_inherit(regs);
-       bad_mode(regs, 0, esr);
-       local_daif_mask();
-       exit_to_kernel_mode(regs);
-}
-
 static void noinstr arm64_enter_el1_dbg(struct pt_regs *regs)
 {
        regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
@@ -245,7 +308,7 @@ static void noinstr el1_fpac(struct pt_regs *regs, unsigned long esr)
        exit_to_kernel_mode(regs);
 }
 
-asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs)
+asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs)
 {
        unsigned long esr = read_sysreg(esr_el1);
 
@@ -275,10 +338,50 @@ asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs)
                el1_fpac(regs, esr);
                break;
        default:
-               el1_inv(regs, esr);
+               __panic_unhandled(regs, "64-bit el1h sync", esr);
        }
 }
 
+static void noinstr el1_interrupt(struct pt_regs *regs,
+                                 void (*handler)(struct pt_regs *))
+{
+       write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
+
+       enter_el1_irq_or_nmi(regs);
+       do_interrupt_handler(regs, handler);
+
+       /*
+        * Note: thread_info::preempt_count includes both thread_info::count
+        * and thread_info::need_resched, and is not equivalent to
+        * preempt_count().
+        */
+       if (IS_ENABLED(CONFIG_PREEMPTION) &&
+           READ_ONCE(current_thread_info()->preempt_count) == 0)
+               arm64_preempt_schedule_irq();
+
+       exit_el1_irq_or_nmi(regs);
+}
+
+asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs)
+{
+       el1_interrupt(regs, handle_arch_irq);
+}
+
+asmlinkage void noinstr el1h_64_fiq_handler(struct pt_regs *regs)
+{
+       el1_interrupt(regs, handle_arch_fiq);
+}
+
+asmlinkage void noinstr el1h_64_error_handler(struct pt_regs *regs)
+{
+       unsigned long esr = read_sysreg(esr_el1);
+
+       local_daif_restore(DAIF_ERRCTX);
+       arm64_enter_nmi(regs);
+       do_serror(regs, esr);
+       arm64_exit_nmi(regs);
+}
+
 asmlinkage void noinstr enter_from_user_mode(void)
 {
        lockdep_hardirqs_off(CALLER_ADDR0);
@@ -398,7 +501,7 @@ static void noinstr el0_dbg(struct pt_regs *regs, unsigned long esr)
 
        enter_from_user_mode();
        do_debug_exception(far, esr, regs);
-       local_daif_restore(DAIF_PROCCTX_NOIRQ);
+       local_daif_restore(DAIF_PROCCTX);
 }
 
 static void noinstr el0_svc(struct pt_regs *regs)
@@ -415,7 +518,7 @@ static void noinstr el0_fpac(struct pt_regs *regs, unsigned long esr)
        do_ptrauth_fault(regs, esr);
 }
 
-asmlinkage void noinstr el0_sync_handler(struct pt_regs *regs)
+asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs)
 {
        unsigned long esr = read_sysreg(esr_el1);
 
@@ -468,6 +571,56 @@ asmlinkage void noinstr el0_sync_handler(struct pt_regs *regs)
        }
 }
 
+static void noinstr el0_interrupt(struct pt_regs *regs,
+                                 void (*handler)(struct pt_regs *))
+{
+       enter_from_user_mode();
+
+       write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
+
+       if (regs->pc & BIT(55))
+               arm64_apply_bp_hardening();
+
+       do_interrupt_handler(regs, handler);
+}
+
+static void noinstr __el0_irq_handler_common(struct pt_regs *regs)
+{
+       el0_interrupt(regs, handle_arch_irq);
+}
+
+asmlinkage void noinstr el0t_64_irq_handler(struct pt_regs *regs)
+{
+       __el0_irq_handler_common(regs);
+}
+
+static void noinstr __el0_fiq_handler_common(struct pt_regs *regs)
+{
+       el0_interrupt(regs, handle_arch_fiq);
+}
+
+asmlinkage void noinstr el0t_64_fiq_handler(struct pt_regs *regs)
+{
+       __el0_fiq_handler_common(regs);
+}
+
+static void __el0_error_handler_common(struct pt_regs *regs)
+{
+       unsigned long esr = read_sysreg(esr_el1);
+
+       enter_from_user_mode();
+       local_daif_restore(DAIF_ERRCTX);
+       arm64_enter_nmi(regs);
+       do_serror(regs, esr);
+       arm64_exit_nmi(regs);
+       local_daif_restore(DAIF_PROCCTX);
+}
+
+asmlinkage void noinstr el0t_64_error_handler(struct pt_regs *regs)
+{
+       __el0_error_handler_common(regs);
+}
+
 #ifdef CONFIG_COMPAT
 static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr)
 {
@@ -483,7 +636,7 @@ static void noinstr el0_svc_compat(struct pt_regs *regs)
        do_el0_svc_compat(regs);
 }
 
-asmlinkage void noinstr el0_sync_compat_handler(struct pt_regs *regs)
+asmlinkage void noinstr el0t_32_sync_handler(struct pt_regs *regs)
 {
        unsigned long esr = read_sysreg(esr_el1);
 
@@ -526,4 +679,71 @@ asmlinkage void noinstr el0_sync_compat_handler(struct pt_regs *regs)
                el0_inv(regs, esr);
        }
 }
+
+asmlinkage void noinstr el0t_32_irq_handler(struct pt_regs *regs)
+{
+       __el0_irq_handler_common(regs);
+}
+
+asmlinkage void noinstr el0t_32_fiq_handler(struct pt_regs *regs)
+{
+       __el0_fiq_handler_common(regs);
+}
+
+asmlinkage void noinstr el0t_32_error_handler(struct pt_regs *regs)
+{
+       __el0_error_handler_common(regs);
+}
+#else /* CONFIG_COMPAT */
+UNHANDLED(el0t, 32, sync)
+UNHANDLED(el0t, 32, irq)
+UNHANDLED(el0t, 32, fiq)
+UNHANDLED(el0t, 32, error)
 #endif /* CONFIG_COMPAT */
+
+#ifdef CONFIG_VMAP_STACK
+asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
+{
+       unsigned int esr = read_sysreg(esr_el1);
+       unsigned long far = read_sysreg(far_el1);
+
+       arm64_enter_nmi(regs);
+       panic_bad_stack(regs, esr, far);
+}
+#endif /* CONFIG_VMAP_STACK */
+
+#ifdef CONFIG_ARM_SDE_INTERFACE
+asmlinkage noinstr unsigned long
+__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
+{
+       unsigned long ret;
+
+       /*
+        * We didn't take an exception to get here, so the HW hasn't
+        * set/cleared bits in PSTATE that we may rely on.
+        *
+        * The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
+        * whether PSTATE bits are inherited unchanged or generated from
+        * scratch, and the TF-A implementation always clears PAN and always
+        * clears UAO. There are no other known implementations.
+        *
+        * Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
+        * PSTATE is modified upon architectural exceptions, and so PAN is
+        * either inherited or set per SCTLR_ELx.SPAN, and UAO is always
+        * cleared.
+        *
+        * We must explicitly reset PAN to the expected state, including
+        * clearing it when the host isn't using it, in case a VM had it set.
+        */
+       if (system_uses_hw_pan())
+               set_pstate_pan(1);
+       else if (cpu_has_pan())
+               set_pstate_pan(0);
+
+       arm64_enter_nmi(regs);
+       ret = do_sdei_event(regs, arg);
+       arm64_exit_nmi(regs);
+
+       return ret;
+}
+#endif /* CONFIG_ARM_SDE_INTERFACE */
index 3ecec60..0a7a647 100644 (file)
@@ -63,16 +63,24 @@ SYM_FUNC_END(sve_set_vq)
  * and the rest zeroed. All the other SVE registers will be zeroed.
  */
 SYM_FUNC_START(sve_load_from_fpsimd_state)
-               sve_load_vq     x1, x2, x3
-               fpsimd_restore  x0, 8
- _for n, 0, 15, _sve_pfalse    \n
-               _sve_wrffr      0
-               ret
+       sve_load_vq     x1, x2, x3
+       fpsimd_restore  x0, 8
+       sve_flush_p_ffr
+       ret
 SYM_FUNC_END(sve_load_from_fpsimd_state)
 
-/* Zero all SVE registers but the first 128-bits of each vector */
+/*
+ * Zero all SVE registers but the first 128-bits of each vector
+ *
+ * VQ must already be configured by caller, any further updates of VQ
+ * will need to ensure that the register state remains valid.
+ *
+ * x0 = VQ - 1
+ */
 SYM_FUNC_START(sve_flush_live)
-       sve_flush
+       cbz             x0, 1f  // A VQ-1 of 0 is 128 bits so no extra Z state
+       sve_flush_z
+1:     sve_flush_p_ffr
        ret
 SYM_FUNC_END(sve_flush_live)
 
index 3513984..863d44f 100644 (file)
  * Context tracking and irqflag tracing need to instrument transitions between
  * user and kernel mode.
  */
-       .macro user_exit_irqoff
-#if defined(CONFIG_CONTEXT_TRACKING) || defined(CONFIG_TRACE_IRQFLAGS)
-       bl      enter_from_user_mode
-#endif
-       .endm
-
        .macro user_enter_irqoff
 #if defined(CONFIG_CONTEXT_TRACKING) || defined(CONFIG_TRACE_IRQFLAGS)
        bl      exit_to_user_mode
        .endr
        .endm
 
-/*
- * Bad Abort numbers
- *-----------------
- */
-#define BAD_SYNC       0
-#define BAD_IRQ                1
-#define BAD_FIQ                2
-#define BAD_ERROR      3
-
-       .macro kernel_ventry, el, label, regsize = 64
+       .macro kernel_ventry, el:req, ht:req, regsize:req, label:req
        .align 7
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
        .if     \el == 0
@@ -87,7 +72,7 @@ alternative_else_nop_endif
        tbnz    x0, #THREAD_SHIFT, 0f
        sub     x0, sp, x0                      // x0'' = sp' - x0' = (sp + x0) - sp = x0
        sub     sp, sp, x0                      // sp'' = sp' - x0 = (sp + x0) - x0 = sp
-       b       el\()\el\()_\label
+       b       el\el\ht\()_\regsize\()_\label
 
 0:
        /*
@@ -119,7 +104,7 @@ alternative_else_nop_endif
        sub     sp, sp, x0
        mrs     x0, tpidrro_el0
 #endif
-       b       el\()\el\()_\label
+       b       el\el\ht\()_\regsize\()_\label
        .endm
 
        .macro tramp_alias, dst, sym
@@ -275,7 +260,7 @@ alternative_else_nop_endif
 
        mte_set_kernel_gcr x22, x23
 
-       scs_load tsk, x20
+       scs_load tsk
        .else
        add     x21, sp, #PT_REGS_SIZE
        get_current_task tsk
@@ -285,7 +270,7 @@ alternative_else_nop_endif
        stp     lr, x21, [sp, #S_LR]
 
        /*
-        * For exceptions from EL0, create a terminal frame record.
+        * For exceptions from EL0, create a final frame record.
         * For exceptions from EL1, create a synthetic frame record so the
         * interrupted code shows up in the backtrace.
         */
@@ -375,7 +360,7 @@ alternative_if ARM64_WORKAROUND_845719
 alternative_else_nop_endif
 #endif
 3:
-       scs_save tsk, x0
+       scs_save tsk
 
 #ifdef CONFIG_ARM64_PTR_AUTH
 alternative_if ARM64_HAS_ADDRESS_AUTH
@@ -486,63 +471,12 @@ SYM_CODE_START_LOCAL(__swpan_exit_el0)
 SYM_CODE_END(__swpan_exit_el0)
 #endif
 
-       .macro  irq_stack_entry
-       mov     x19, sp                 // preserve the original sp
-#ifdef CONFIG_SHADOW_CALL_STACK
-       mov     x24, scs_sp             // preserve the original shadow stack
-#endif
-
-       /*
-        * Compare sp with the base of the task stack.
-        * If the top ~(THREAD_SIZE - 1) bits match, we are on a task stack,
-        * and should switch to the irq stack.
-        */
-       ldr     x25, [tsk, TSK_STACK]
-       eor     x25, x25, x19
-       and     x25, x25, #~(THREAD_SIZE - 1)
-       cbnz    x25, 9998f
-
-       ldr_this_cpu x25, irq_stack_ptr, x26
-       mov     x26, #IRQ_STACK_SIZE
-       add     x26, x25, x26
-
-       /* switch to the irq stack */
-       mov     sp, x26
-
-#ifdef CONFIG_SHADOW_CALL_STACK
-       /* also switch to the irq shadow stack */
-       ldr_this_cpu scs_sp, irq_shadow_call_stack_ptr, x26
-#endif
-
-9998:
-       .endm
-
-       /*
-        * The callee-saved regs (x19-x29) should be preserved between
-        * irq_stack_entry and irq_stack_exit, but note that kernel_entry
-        * uses x20-x23 to store data for later use.
-        */
-       .macro  irq_stack_exit
-       mov     sp, x19
-#ifdef CONFIG_SHADOW_CALL_STACK
-       mov     scs_sp, x24
-#endif
-       .endm
-
 /* GPRs used by entry code */
 tsk    .req    x28             // current thread_info
 
 /*
  * Interrupt handling.
  */
-       .macro  irq_handler, handler:req
-       ldr_l   x1, \handler
-       mov     x0, sp
-       irq_stack_entry
-       blr     x1
-       irq_stack_exit
-       .endm
-
        .macro  gic_prio_kentry_setup, tmp:req
 #ifdef CONFIG_ARM64_PSEUDO_NMI
        alternative_if ARM64_HAS_IRQ_PRIO_MASKING
@@ -552,45 +486,6 @@ tsk        .req    x28             // current thread_info
 #endif
        .endm
 
-       .macro el1_interrupt_handler, handler:req
-       enable_da
-
-       mov     x0, sp
-       bl      enter_el1_irq_or_nmi
-
-       irq_handler     \handler
-
-#ifdef CONFIG_PREEMPTION
-       ldr     x24, [tsk, #TSK_TI_PREEMPT]     // get preempt count
-alternative_if ARM64_HAS_IRQ_PRIO_MASKING
-       /*
-        * DA were cleared at start of handling, and IF are cleared by
-        * the GIC irqchip driver using gic_arch_enable_irqs() for
-        * normal IRQs. If anything is set, it means we come back from
-        * an NMI instead of a normal IRQ, so skip preemption
-        */
-       mrs     x0, daif
-       orr     x24, x24, x0
-alternative_else_nop_endif
-       cbnz    x24, 1f                         // preempt count != 0 || NMI return path
-       bl      arm64_preempt_schedule_irq      // irq en/disable is done inside
-1:
-#endif
-
-       mov     x0, sp
-       bl      exit_el1_irq_or_nmi
-       .endm
-
-       .macro el0_interrupt_handler, handler:req
-       user_exit_irqoff
-       enable_da
-
-       tbz     x22, #55, 1f
-       bl      do_el0_irq_bp_hardening
-1:
-       irq_handler     \handler
-       .endm
-
        .text
 
 /*
@@ -600,32 +495,25 @@ alternative_else_nop_endif
 
        .align  11
 SYM_CODE_START(vectors)
-       kernel_ventry   1, sync_invalid                 // Synchronous EL1t
-       kernel_ventry   1, irq_invalid                  // IRQ EL1t
-       kernel_ventry   1, fiq_invalid                  // FIQ EL1t
-       kernel_ventry   1, error_invalid                // Error EL1t
-
-       kernel_ventry   1, sync                         // Synchronous EL1h
-       kernel_ventry   1, irq                          // IRQ EL1h
-       kernel_ventry   1, fiq                          // FIQ EL1h
-       kernel_ventry   1, error                        // Error EL1h
-
-       kernel_ventry   0, sync                         // Synchronous 64-bit EL0
-       kernel_ventry   0, irq                          // IRQ 64-bit EL0
-       kernel_ventry   0, fiq                          // FIQ 64-bit EL0
-       kernel_ventry   0, error                        // Error 64-bit EL0
-
-#ifdef CONFIG_COMPAT
-       kernel_ventry   0, sync_compat, 32              // Synchronous 32-bit EL0
-       kernel_ventry   0, irq_compat, 32               // IRQ 32-bit EL0
-       kernel_ventry   0, fiq_compat, 32               // FIQ 32-bit EL0
-       kernel_ventry   0, error_compat, 32             // Error 32-bit EL0
-#else
-       kernel_ventry   0, sync_invalid, 32             // Synchronous 32-bit EL0
-       kernel_ventry   0, irq_invalid, 32              // IRQ 32-bit EL0
-       kernel_ventry   0, fiq_invalid, 32              // FIQ 32-bit EL0
-       kernel_ventry   0, error_invalid, 32            // Error 32-bit EL0
-#endif
+       kernel_ventry   1, t, 64, sync          // Synchronous EL1t
+       kernel_ventry   1, t, 64, irq           // IRQ EL1t
+       kernel_ventry   1, t, 64, fiq           // FIQ EL1h
+       kernel_ventry   1, t, 64, error         // Error EL1t
+
+       kernel_ventry   1, h, 64, sync          // Synchronous EL1h
+       kernel_ventry   1, h, 64, irq           // IRQ EL1h
+       kernel_ventry   1, h, 64, fiq           // FIQ EL1h
+       kernel_ventry   1, h, 64, error         // Error EL1h
+
+       kernel_ventry   0, t, 64, sync          // Synchronous 64-bit EL0
+       kernel_ventry   0, t, 64, irq           // IRQ 64-bit EL0
+       kernel_ventry   0, t, 64, fiq           // FIQ 64-bit EL0
+       kernel_ventry   0, t, 64, error         // Error 64-bit EL0
+
+       kernel_ventry   0, t, 32, sync          // Synchronous 32-bit EL0
+       kernel_ventry   0, t, 32, irq           // IRQ 32-bit EL0
+       kernel_ventry   0, t, 32, fiq           // FIQ 32-bit EL0
+       kernel_ventry   0, t, 32, error         // Error 32-bit EL0
 SYM_CODE_END(vectors)
 
 #ifdef CONFIG_VMAP_STACK
@@ -656,147 +544,46 @@ __bad_stack:
        ASM_BUG()
 #endif /* CONFIG_VMAP_STACK */
 
-/*
- * Invalid mode handlers
- */
-       .macro  inv_entry, el, reason, regsize = 64
+
+       .macro entry_handler el:req, ht:req, regsize:req, label:req
+SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)
        kernel_entry \el, \regsize
        mov     x0, sp
-       mov     x1, #\reason
-       mrs     x2, esr_el1
-       bl      bad_mode
-       ASM_BUG()
+       bl      el\el\ht\()_\regsize\()_\label\()_handler
+       .if \el == 0
+       b       ret_to_user
+       .else
+       b       ret_to_kernel
+       .endif
+SYM_CODE_END(el\el\ht\()_\regsize\()_\label)
        .endm
 
-SYM_CODE_START_LOCAL(el0_sync_invalid)
-       inv_entry 0, BAD_SYNC
-SYM_CODE_END(el0_sync_invalid)
-
-SYM_CODE_START_LOCAL(el0_irq_invalid)
-       inv_entry 0, BAD_IRQ
-SYM_CODE_END(el0_irq_invalid)
-
-SYM_CODE_START_LOCAL(el0_fiq_invalid)
-       inv_entry 0, BAD_FIQ
-SYM_CODE_END(el0_fiq_invalid)
-
-SYM_CODE_START_LOCAL(el0_error_invalid)
-       inv_entry 0, BAD_ERROR
-SYM_CODE_END(el0_error_invalid)
-
-SYM_CODE_START_LOCAL(el1_sync_invalid)
-       inv_entry 1, BAD_SYNC
-SYM_CODE_END(el1_sync_invalid)
-
-SYM_CODE_START_LOCAL(el1_irq_invalid)
-       inv_entry 1, BAD_IRQ
-SYM_CODE_END(el1_irq_invalid)
-
-SYM_CODE_START_LOCAL(el1_fiq_invalid)
-       inv_entry 1, BAD_FIQ
-SYM_CODE_END(el1_fiq_invalid)
-
-SYM_CODE_START_LOCAL(el1_error_invalid)
-       inv_entry 1, BAD_ERROR
-SYM_CODE_END(el1_error_invalid)
-
 /*
- * EL1 mode handlers.
+ * Early exception handlers
  */
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el1_sync)
-       kernel_entry 1
-       mov     x0, sp
-       bl      el1_sync_handler
-       kernel_exit 1
-SYM_CODE_END(el1_sync)
-
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
-       kernel_entry 1
-       el1_interrupt_handler handle_arch_irq
-       kernel_exit 1
-SYM_CODE_END(el1_irq)
-
-SYM_CODE_START_LOCAL_NOALIGN(el1_fiq)
-       kernel_entry 1
-       el1_interrupt_handler handle_arch_fiq
-       kernel_exit 1
-SYM_CODE_END(el1_fiq)
-
-/*
- * EL0 mode handlers.
- */
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el0_sync)
-       kernel_entry 0
-       mov     x0, sp
-       bl      el0_sync_handler
-       b       ret_to_user
-SYM_CODE_END(el0_sync)
-
-#ifdef CONFIG_COMPAT
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el0_sync_compat)
-       kernel_entry 0, 32
-       mov     x0, sp
-       bl      el0_sync_compat_handler
-       b       ret_to_user
-SYM_CODE_END(el0_sync_compat)
-
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
-       kernel_entry 0, 32
-       b       el0_irq_naked
-SYM_CODE_END(el0_irq_compat)
-
-SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat)
-       kernel_entry 0, 32
-       b       el0_fiq_naked
-SYM_CODE_END(el0_fiq_compat)
-
-SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
-       kernel_entry 0, 32
-       b       el0_error_naked
-SYM_CODE_END(el0_error_compat)
-#endif
-
-       .align  6
-SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
-       kernel_entry 0
-el0_irq_naked:
-       el0_interrupt_handler handle_arch_irq
-       b       ret_to_user
-SYM_CODE_END(el0_irq)
-
-SYM_CODE_START_LOCAL_NOALIGN(el0_fiq)
-       kernel_entry 0
-el0_fiq_naked:
-       el0_interrupt_handler handle_arch_fiq
-       b       ret_to_user
-SYM_CODE_END(el0_fiq)
-
-SYM_CODE_START_LOCAL(el1_error)
-       kernel_entry 1
-       mrs     x1, esr_el1
-       enable_dbg
-       mov     x0, sp
-       bl      do_serror
+       entry_handler   1, t, 64, sync
+       entry_handler   1, t, 64, irq
+       entry_handler   1, t, 64, fiq
+       entry_handler   1, t, 64, error
+
+       entry_handler   1, h, 64, sync
+       entry_handler   1, h, 64, irq
+       entry_handler   1, h, 64, fiq
+       entry_handler   1, h, 64, error
+
+       entry_handler   0, t, 64, sync
+       entry_handler   0, t, 64, irq
+       entry_handler   0, t, 64, fiq
+       entry_handler   0, t, 64, error
+
+       entry_handler   0, t, 32, sync
+       entry_handler   0, t, 32, irq
+       entry_handler   0, t, 32, fiq
+       entry_handler   0, t, 32, error
+
+SYM_CODE_START_LOCAL(ret_to_kernel)
        kernel_exit 1
-SYM_CODE_END(el1_error)
-
-SYM_CODE_START_LOCAL(el0_error)
-       kernel_entry 0
-el0_error_naked:
-       mrs     x25, esr_el1
-       user_exit_irqoff
-       enable_dbg
-       mov     x0, sp
-       mov     x1, x25
-       bl      do_serror
-       enable_da
-       b       ret_to_user
-SYM_CODE_END(el0_error)
+SYM_CODE_END(ret_to_kernel)
 
 /*
  * "slow" syscall return path.
@@ -979,8 +766,8 @@ SYM_FUNC_START(cpu_switch_to)
        mov     sp, x9
        msr     sp_el0, x1
        ptrauth_keys_install_kernel x1, x8, x9, x10
-       scs_save x0, x8
-       scs_load x1, x8
+       scs_save x0
+       scs_load x1
        ret
 SYM_FUNC_END(cpu_switch_to)
 NOKPROBE(cpu_switch_to)
@@ -998,6 +785,42 @@ SYM_CODE_START(ret_from_fork)
 SYM_CODE_END(ret_from_fork)
 NOKPROBE(ret_from_fork)
 
+/*
+ * void call_on_irq_stack(struct pt_regs *regs,
+ *                       void (*func)(struct pt_regs *));
+ *
+ * Calls func(regs) using this CPU's irq stack and shadow irq stack.
+ */
+SYM_FUNC_START(call_on_irq_stack)
+#ifdef CONFIG_SHADOW_CALL_STACK
+       stp     scs_sp, xzr, [sp, #-16]!
+       ldr_this_cpu scs_sp, irq_shadow_call_stack_ptr, x17
+#endif
+       /* Create a frame record to save our LR and SP (implicit in FP) */
+       stp     x29, x30, [sp, #-16]!
+       mov     x29, sp
+
+       ldr_this_cpu x16, irq_stack_ptr, x17
+       mov     x15, #IRQ_STACK_SIZE
+       add     x16, x16, x15
+
+       /* Move to the new stack and call the function there */
+       mov     sp, x16
+       blr     x1
+
+       /*
+        * Restore the SP from the FP, and restore the FP and LR from the frame
+        * record.
+        */
+       mov     sp, x29
+       ldp     x29, x30, [sp], #16
+#ifdef CONFIG_SHADOW_CALL_STACK
+       ldp     scs_sp, xzr, [sp], #16
+#endif
+       ret
+SYM_FUNC_END(call_on_irq_stack)
+NOKPROBE(call_on_irq_stack)
+
 #ifdef CONFIG_ARM_SDE_INTERFACE
 
 #include <asm/sdei.h>
index ad3dd34..e57b23f 100644 (file)
@@ -957,8 +957,10 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
         * disabling the trap, otherwise update our in-memory copy.
         */
        if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
-               sve_set_vq(sve_vq_from_vl(current->thread.sve_vl) - 1);
-               sve_flush_live();
+               unsigned long vq_minus_one =
+                       sve_vq_from_vl(current->thread.sve_vl) - 1;
+               sve_set_vq(vq_minus_one);
+               sve_flush_live(vq_minus_one);
                fpsimd_bind_task_to_cpu();
        } else {
                fpsimd_to_sve(current);
index b5d3dda..7f467bd 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/debug-monitors.h>
 #include <asm/ftrace.h>
 #include <asm/insn.h>
+#include <asm/patching.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 /*
index 96873df..c5c994a 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/asm_pointer_auth.h>
 #include <asm/assembler.h>
 #include <asm/boot.h>
+#include <asm/bug.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
@@ -117,8 +118,8 @@ SYM_CODE_START_LOCAL(preserve_boot_args)
        dmb     sy                              // needed before dc ivac with
                                                // MMU off
 
-       mov     x1, #0x20                       // 4 x 8 bytes
-       b       __inval_dcache_area             // tail call
+       add     x1, x0, #0x20                   // 4 x 8 bytes
+       b       dcache_inval_poc                // tail call
 SYM_CODE_END(preserve_boot_args)
 
 /*
@@ -195,7 +196,7 @@ SYM_CODE_END(preserve_boot_args)
        and     \iend, \iend, \istart   // iend = (vend >> shift) & (ptrs - 1)
        mov     \istart, \ptrs
        mul     \istart, \istart, \count
-       add     \iend, \iend, \istart   // iend += (count - 1) * ptrs
+       add     \iend, \iend, \istart   // iend += count * ptrs
                                        // our entries span multiple tables
 
        lsr     \istart, \vstart, \shift
@@ -268,8 +269,7 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
         */
        adrp    x0, init_pg_dir
        adrp    x1, init_pg_end
-       sub     x1, x1, x0
-       bl      __inval_dcache_area
+       bl      dcache_inval_poc
 
        /*
         * Clear the init page tables.
@@ -354,7 +354,6 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
 #endif
 1:
        ldr_l   x4, idmap_ptrs_per_pgd
-       mov     x5, x3                          // __pa(__idmap_text_start)
        adr_l   x6, __idmap_text_end            // __pa(__idmap_text_end)
 
        map_memory x0, x1, x3, x6, x7, x3, x4, x10, x11, x12, x13, x14
@@ -382,39 +381,57 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
 
        adrp    x0, idmap_pg_dir
        adrp    x1, idmap_pg_end
-       sub     x1, x1, x0
-       bl      __inval_dcache_area
+       bl      dcache_inval_poc
 
        adrp    x0, init_pg_dir
        adrp    x1, init_pg_end
-       sub     x1, x1, x0
-       bl      __inval_dcache_area
+       bl      dcache_inval_poc
 
        ret     x28
 SYM_FUNC_END(__create_page_tables)
 
+       /*
+        * Initialize CPU registers with task-specific and cpu-specific context.
+        *
+        * Create a final frame record at task_pt_regs(current)->stackframe, so
+        * that the unwinder can identify the final frame record of any task by
+        * its location in the task stack. We reserve the entire pt_regs space
+        * for consistency with user tasks and kthreads.
+        */
+       .macro  init_cpu_task tsk, tmp1, tmp2
+       msr     sp_el0, \tsk
+
+       ldr     \tmp1, [\tsk, #TSK_STACK]
+       add     sp, \tmp1, #THREAD_SIZE
+       sub     sp, sp, #PT_REGS_SIZE
+
+       stp     xzr, xzr, [sp, #S_STACKFRAME]
+       add     x29, sp, #S_STACKFRAME
+
+       scs_load \tsk
+
+       adr_l   \tmp1, __per_cpu_offset
+       ldr     w\tmp2, [\tsk, #TSK_CPU]
+       ldr     \tmp1, [\tmp1, \tmp2, lsl #3]
+       set_this_cpu_offset \tmp1
+       .endm
+
 /*
  * The following fragment of code is executed with the MMU enabled.
  *
  *   x0 = __PHYS_OFFSET
  */
 SYM_FUNC_START_LOCAL(__primary_switched)
-       adrp    x4, init_thread_union
-       add     sp, x4, #THREAD_SIZE
-       adr_l   x5, init_task
-       msr     sp_el0, x5                      // Save thread_info
+       adr_l   x4, init_task
+       init_cpu_task x4, x5, x6
 
        adr_l   x8, vectors                     // load VBAR_EL1 with virtual
        msr     vbar_el1, x8                    // vector table address
        isb
 
-       stp     xzr, x30, [sp, #-16]!
+       stp     x29, x30, [sp, #-16]!
        mov     x29, sp
 
-#ifdef CONFIG_SHADOW_CALL_STACK
-       adr_l   scs_sp, init_shadow_call_stack  // Set shadow call stack
-#endif
-
        str_l   x21, __fdt_pointer, x5          // Save FDT pointer
 
        ldr_l   x4, kimage_vaddr                // Save the offset between
@@ -446,10 +463,9 @@ SYM_FUNC_START_LOCAL(__primary_switched)
 0:
 #endif
        bl      switch_to_vhe                   // Prefer VHE if possible
-       add     sp, sp, #16
-       mov     x29, #0
-       mov     x30, #0
-       b       start_kernel
+       ldp     x29, x30, [sp], #16
+       bl      start_kernel
+       ASM_BUG()
 SYM_FUNC_END(__primary_switched)
 
        .pushsection ".rodata", "a"
@@ -551,7 +567,7 @@ SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
        cmp     w0, #BOOT_CPU_MODE_EL2
        b.ne    1f
        add     x1, x1, #4
-1:     str     w0, [x1]                        // This CPU has booted in EL1
+1:     str     w0, [x1]                        // Save CPU boot mode
        dmb     sy
        dc      ivac, x1                        // Invalidate potentially stale cache line
        ret
@@ -632,21 +648,17 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
        isb
 
        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
-       scs_load x2, x3
-       mov     x29, #0
-       mov     x30, #0
+
+       init_cpu_task x2, x1, x3
 
 #ifdef CONFIG_ARM64_PTR_AUTH
        ptrauth_keys_init_cpu x2, x3, x4, x5
 #endif
 
-       b       secondary_start_kernel
+       bl      secondary_start_kernel
+       ASM_BUG()
 SYM_FUNC_END(__secondary_switched)
 
 SYM_FUNC_START_LOCAL(__secondary_too_slow)
index 8ccca66..81c0186 100644 (file)
@@ -45,7 +45,7 @@
  * Because this code has to be copied to a 'safe' page, it can't call out to
  * other functions by PC-relative address. Also remember that it may be
  * mid-way through over-writing other functions. For this reason it contains
- * code from flush_icache_range() and uses the copy_page() macro.
+ * code from caches_clean_inval_pou() and uses the copy_page() macro.
  *
  * This 'safe' page is mapped via ttbr0, and executed from there. This function
  * switches to a copy of the linear map in ttbr1, performs the restore, then
@@ -87,11 +87,12 @@ SYM_CODE_START(swsusp_arch_suspend_exit)
        copy_page       x0, x1, x2, x3, x4, x5, x6, x7, x8, x9
 
        add     x1, x10, #PAGE_SIZE
-       /* Clean the copied page to PoU - based on flush_icache_range() */
+       /* Clean the copied page to PoU - based on caches_clean_inval_pou() */
        raw_dcache_line_size x2, x3
        sub     x3, x2, #1
        bic     x4, x10, x3
-2:     dc      cvau, x4        /* clean D line / unified line */
+2:     /* clean D line / unified line */
+alternative_insn "dc cvau, x4",  "dc civac, x4",  ARM64_WORKAROUND_CLEAN_CACHE
        add     x4, x4, x2
        cmp     x4, x1
        b.lo    2b
index b1cef37..46a0b4d 100644 (file)
@@ -210,7 +210,7 @@ static int create_safe_exec_page(void *src_start, size_t length,
                return -ENOMEM;
 
        memcpy(page, src_start, length);
-       __flush_icache_range((unsigned long)page, (unsigned long)page + length);
+       caches_clean_inval_pou((unsigned long)page, (unsigned long)page + length);
        rc = trans_pgd_idmap_page(&trans_info, &trans_ttbr0, &t0sz, page);
        if (rc)
                return rc;
@@ -240,8 +240,6 @@ static int create_safe_exec_page(void *src_start, size_t length,
        return 0;
 }
 
-#define dcache_clean_range(start, end) __flush_dcache_area(start, (end - start))
-
 #ifdef CONFIG_ARM64_MTE
 
 static DEFINE_XARRAY(mte_pages);
@@ -383,13 +381,18 @@ int swsusp_arch_suspend(void)
                ret = swsusp_save();
        } else {
                /* Clean kernel core startup/idle code to PoC*/
-               dcache_clean_range(__mmuoff_data_start, __mmuoff_data_end);
-               dcache_clean_range(__idmap_text_start, __idmap_text_end);
+               dcache_clean_inval_poc((unsigned long)__mmuoff_data_start,
+                                   (unsigned long)__mmuoff_data_end);
+               dcache_clean_inval_poc((unsigned long)__idmap_text_start,
+                                   (unsigned long)__idmap_text_end);
 
                /* Clean kvm setup code to PoC? */
                if (el2_reset_needed()) {
-                       dcache_clean_range(__hyp_idmap_text_start, __hyp_idmap_text_end);
-                       dcache_clean_range(__hyp_text_start, __hyp_text_end);
+                       dcache_clean_inval_poc(
+                               (unsigned long)__hyp_idmap_text_start,
+                               (unsigned long)__hyp_idmap_text_end);
+                       dcache_clean_inval_poc((unsigned long)__hyp_text_start,
+                                           (unsigned long)__hyp_text_end);
                }
 
                swsusp_mte_restore_tags();
@@ -474,7 +477,8 @@ int swsusp_arch_resume(void)
         * The hibernate exit text contains a set of el2 vectors, that will
         * be executed at el2 with the mmu off in order to reload hyp-stub.
         */
-       __flush_dcache_area(hibernate_exit, exit_size);
+       dcache_clean_inval_poc((unsigned long)hibernate_exit,
+                           (unsigned long)hibernate_exit + exit_size);
 
        /*
         * KASLR will cause the el2 vectors to be in a different location in
diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
new file mode 100644 (file)
index 0000000..a2cfbac
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Low-level idle sequences
+ */
+
+#include <linux/cpu.h>
+#include <linux/irqflags.h>
+
+#include <asm/barrier.h>
+#include <asm/cpuidle.h>
+#include <asm/cpufeature.h>
+#include <asm/sysreg.h>
+
+/*
+ *     cpu_do_idle()
+ *
+ *     Idle the processor (wait for interrupt).
+ *
+ *     If the CPU supports priority masking we must do additional work to
+ *     ensure that interrupts are not masked at the PMR (because the core will
+ *     not wake up if we block the wake up signal in the interrupt controller).
+ */
+void noinstr cpu_do_idle(void)
+{
+       struct arm_cpuidle_irq_context context;
+
+       arm_cpuidle_save_irq_context(&context);
+
+       dsb(sy);
+       wfi();
+
+       arm_cpuidle_restore_irq_context(&context);
+}
+
+/*
+ * This is our default idle handler.
+ */
+void noinstr arch_cpu_idle(void)
+{
+       /*
+        * This should do all the clock switching and wait for interrupt
+        * tricks
+        */
+       cpu_do_idle();
+       raw_local_irq_enable();
+}
index e628c8c..53a381a 100644 (file)
@@ -237,7 +237,8 @@ asmlinkage void __init init_feature_override(void)
 
        for (i = 0; i < ARRAY_SIZE(regs); i++) {
                if (regs[i]->override)
-                       __flush_dcache_area(regs[i]->override,
+                       dcache_clean_inval_poc((unsigned long)regs[i]->override,
+                                           (unsigned long)regs[i]->override +
                                            sizeof(*regs[i]->override));
        }
 }
index bcf3c27..c96a9a0 100644 (file)
@@ -35,7 +35,7 @@ __efistub_strnlen             = __pi_strnlen;
 __efistub_strcmp               = __pi_strcmp;
 __efistub_strncmp              = __pi_strncmp;
 __efistub_strrchr              = __pi_strrchr;
-__efistub___clean_dcache_area_poc = __pi___clean_dcache_area_poc;
+__efistub_dcache_clean_poc = __pi_dcache_clean_poc;
 
 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
 __efistub___memcpy             = __pi_memcpy;
index 9a8a0ae..fc98037 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/kernel.h>
 #include <linux/jump_label.h>
 #include <asm/insn.h>
+#include <asm/patching.h>
 
 void arch_jump_label_transform(struct jump_entry *entry,
                               enum jump_label_type type)
index 341342b..cfa2cfd 100644 (file)
@@ -72,7 +72,9 @@ u64 __init kaslr_early_init(void)
         * we end up running with module randomization disabled.
         */
        module_alloc_base = (u64)_etext - MODULES_VSIZE;
-       __flush_dcache_area(&module_alloc_base, sizeof(module_alloc_base));
+       dcache_clean_inval_poc((unsigned long)&module_alloc_base,
+                           (unsigned long)&module_alloc_base +
+                                   sizeof(module_alloc_base));
 
        /*
         * Try to map the FDT early. If this fails, we simply bail,
@@ -170,8 +172,12 @@ u64 __init kaslr_early_init(void)
        module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
        module_alloc_base &= PAGE_MASK;
 
-       __flush_dcache_area(&module_alloc_base, sizeof(module_alloc_base));
-       __flush_dcache_area(&memstart_offset_seed, sizeof(memstart_offset_seed));
+       dcache_clean_inval_poc((unsigned long)&module_alloc_base,
+                           (unsigned long)&module_alloc_base +
+                                   sizeof(module_alloc_base));
+       dcache_clean_inval_poc((unsigned long)&memstart_offset_seed,
+                           (unsigned long)&memstart_offset_seed +
+                                   sizeof(memstart_offset_seed));
 
        return offset;
 }
index 1a157ca..2aede78 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/debug-monitors.h>
 #include <asm/insn.h>
+#include <asm/patching.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
index 90a335c..03ceabe 100644 (file)
@@ -68,10 +68,16 @@ int machine_kexec_post_load(struct kimage *kimage)
        kimage->arch.kern_reloc = __pa(reloc_code);
        kexec_image_info(kimage);
 
-       /* Flush the reloc_code in preparation for its execution. */
-       __flush_dcache_area(reloc_code, arm64_relocate_new_kernel_size);
-       flush_icache_range((uintptr_t)reloc_code, (uintptr_t)reloc_code +
-                          arm64_relocate_new_kernel_size);
+       /*
+        * For execution with the MMU off, reloc_code needs to be cleaned to the
+        * PoC and invalidated from the I-cache.
+        */
+       dcache_clean_inval_poc((unsigned long)reloc_code,
+                           (unsigned long)reloc_code +
+                                   arm64_relocate_new_kernel_size);
+       icache_inval_pou((uintptr_t)reloc_code,
+                               (uintptr_t)reloc_code +
+                                       arm64_relocate_new_kernel_size);
 
        return 0;
 }
@@ -102,16 +108,18 @@ static void kexec_list_flush(struct kimage *kimage)
 
        for (entry = &kimage->head; ; entry++) {
                unsigned int flag;
-               void *addr;
+               unsigned long addr;
 
                /* flush the list entries. */
-               __flush_dcache_area(entry, sizeof(kimage_entry_t));
+               dcache_clean_inval_poc((unsigned long)entry,
+                                   (unsigned long)entry +
+                                           sizeof(kimage_entry_t));
 
                flag = *entry & IND_FLAGS;
                if (flag == IND_DONE)
                        break;
 
-               addr = phys_to_virt(*entry & PAGE_MASK);
+               addr = (unsigned long)phys_to_virt(*entry & PAGE_MASK);
 
                switch (flag) {
                case IND_INDIRECTION:
@@ -120,7 +128,7 @@ static void kexec_list_flush(struct kimage *kimage)
                        break;
                case IND_SOURCE:
                        /* flush the source pages. */
-                       __flush_dcache_area(addr, PAGE_SIZE);
+                       dcache_clean_inval_poc(addr, addr + PAGE_SIZE);
                        break;
                case IND_DESTINATION:
                        break;
@@ -147,8 +155,10 @@ static void kexec_segment_flush(const struct kimage *kimage)
                        kimage->segment[i].memsz,
                        kimage->segment[i].memsz /  PAGE_SIZE);
 
-               __flush_dcache_area(phys_to_virt(kimage->segment[i].mem),
-                       kimage->segment[i].memsz);
+               dcache_clean_inval_poc(
+                       (unsigned long)phys_to_virt(kimage->segment[i].mem),
+                       (unsigned long)phys_to_virt(kimage->segment[i].mem) +
+                               kimage->segment[i].memsz);
        }
 }
 
index 125a10e..69b3fde 100644 (file)
@@ -32,10 +32,9 @@ DEFINE_STATIC_KEY_FALSE(mte_async_mode);
 EXPORT_SYMBOL_GPL(mte_async_mode);
 #endif
 
-static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap)
+static void mte_sync_page_tags(struct page *page, pte_t old_pte,
+                              bool check_swap, bool pte_is_tagged)
 {
-       pte_t old_pte = READ_ONCE(*ptep);
-
        if (check_swap && is_swap_pte(old_pte)) {
                swp_entry_t entry = pte_to_swp_entry(old_pte);
 
@@ -43,6 +42,9 @@ static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap)
                        return;
        }
 
+       if (!pte_is_tagged)
+               return;
+
        page_kasan_tag_reset(page);
        /*
         * We need smp_wmb() in between setting the flags and clearing the
@@ -55,16 +57,22 @@ static void mte_sync_page_tags(struct page *page, pte_t *ptep, bool check_swap)
        mte_clear_page_tags(page_address(page));
 }
 
-void mte_sync_tags(pte_t *ptep, pte_t pte)
+void mte_sync_tags(pte_t old_pte, pte_t pte)
 {
        struct page *page = pte_page(pte);
        long i, nr_pages = compound_nr(page);
        bool check_swap = nr_pages == 1;
+       bool pte_is_tagged = pte_tagged(pte);
+
+       /* Early out if there's nothing to do */
+       if (!check_swap && !pte_is_tagged)
+               return;
 
        /* if PG_mte_tagged is set, tags have already been initialised */
        for (i = 0; i < nr_pages; i++, page++) {
                if (!test_and_set_bit(PG_mte_tagged, &page->flags))
-                       mte_sync_page_tags(page, ptep, check_swap);
+                       mte_sync_page_tags(page, old_pte, check_swap,
+                                          pte_is_tagged);
        }
 }
 
diff --git a/arch/arm64/kernel/patching.c b/arch/arm64/kernel/patching.c
new file mode 100644 (file)
index 0000000..771f543
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/stop_machine.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+#include <asm/insn.h>
+#include <asm/kprobes.h>
+#include <asm/patching.h>
+#include <asm/sections.h>
+
+static DEFINE_RAW_SPINLOCK(patch_lock);
+
+static bool is_exit_text(unsigned long addr)
+{
+       /* discarded with init text/data */
+       return system_state < SYSTEM_RUNNING &&
+               addr >= (unsigned long)__exittext_begin &&
+               addr < (unsigned long)__exittext_end;
+}
+
+static bool is_image_text(unsigned long addr)
+{
+       return core_kernel_text(addr) || is_exit_text(addr);
+}
+
+static void __kprobes *patch_map(void *addr, int fixmap)
+{
+       unsigned long uintaddr = (uintptr_t) addr;
+       bool image = is_image_text(uintaddr);
+       struct page *page;
+
+       if (image)
+               page = phys_to_page(__pa_symbol(addr));
+       else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+               page = vmalloc_to_page(addr);
+       else
+               return addr;
+
+       BUG_ON(!page);
+       return (void *)set_fixmap_offset(fixmap, page_to_phys(page) +
+                       (uintaddr & ~PAGE_MASK));
+}
+
+static void __kprobes patch_unmap(int fixmap)
+{
+       clear_fixmap(fixmap);
+}
+/*
+ * In ARMv8-A, A64 instructions have a fixed length of 32 bits and are always
+ * little-endian.
+ */
+int __kprobes aarch64_insn_read(void *addr, u32 *insnp)
+{
+       int ret;
+       __le32 val;
+
+       ret = copy_from_kernel_nofault(&val, addr, AARCH64_INSN_SIZE);
+       if (!ret)
+               *insnp = le32_to_cpu(val);
+
+       return ret;
+}
+
+static int __kprobes __aarch64_insn_write(void *addr, __le32 insn)
+{
+       void *waddr = addr;
+       unsigned long flags = 0;
+       int ret;
+
+       raw_spin_lock_irqsave(&patch_lock, flags);
+       waddr = patch_map(addr, FIX_TEXT_POKE0);
+
+       ret = copy_to_kernel_nofault(waddr, &insn, AARCH64_INSN_SIZE);
+
+       patch_unmap(FIX_TEXT_POKE0);
+       raw_spin_unlock_irqrestore(&patch_lock, flags);
+
+       return ret;
+}
+
+int __kprobes aarch64_insn_write(void *addr, u32 insn)
+{
+       return __aarch64_insn_write(addr, cpu_to_le32(insn));
+}
+
+int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn)
+{
+       u32 *tp = addr;
+       int ret;
+
+       /* A64 instructions must be word aligned */
+       if ((uintptr_t)tp & 0x3)
+               return -EINVAL;
+
+       ret = aarch64_insn_write(tp, insn);
+       if (ret == 0)
+               caches_clean_inval_pou((uintptr_t)tp,
+                                    (uintptr_t)tp + AARCH64_INSN_SIZE);
+
+       return ret;
+}
+
+struct aarch64_insn_patch {
+       void            **text_addrs;
+       u32             *new_insns;
+       int             insn_cnt;
+       atomic_t        cpu_count;
+};
+
+static int __kprobes aarch64_insn_patch_text_cb(void *arg)
+{
+       int i, ret = 0;
+       struct aarch64_insn_patch *pp = arg;
+
+       /* The first CPU becomes master */
+       if (atomic_inc_return(&pp->cpu_count) == 1) {
+               for (i = 0; ret == 0 && i < pp->insn_cnt; i++)
+                       ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i],
+                                                            pp->new_insns[i]);
+               /* Notify other processors with an additional increment. */
+               atomic_inc(&pp->cpu_count);
+       } else {
+               while (atomic_read(&pp->cpu_count) <= num_online_cpus())
+                       cpu_relax();
+               isb();
+       }
+
+       return ret;
+}
+
+int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
+{
+       struct aarch64_insn_patch patch = {
+               .text_addrs = addrs,
+               .new_insns = insns,
+               .insn_cnt = cnt,
+               .cpu_count = ATOMIC_INIT(0),
+       };
+
+       if (cnt <= 0)
+               return -EINVAL;
+
+       return stop_machine_cpuslocked(aarch64_insn_patch_text_cb, &patch,
+                                      cpu_online_mask);
+}
index 88ff471..4a72c27 100644 (file)
@@ -116,7 +116,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
                tail = (struct frame_tail __user *)regs->regs[29];
 
                while (entry->nr < entry->max_stack &&
-                      tail && !((unsigned long)tail & 0xf))
+                      tail && !((unsigned long)tail & 0x7))
                        tail = user_backtrace(tail, entry);
        } else {
 #ifdef CONFIG_COMPAT
index f594957..d07788d 100644 (file)
@@ -165,10 +165,7 @@ armv8pmu_events_sysfs_show(struct device *dev,
 }
 
 #define ARMV8_EVENT_ATTR(name, config)                                         \
-       (&((struct perf_pmu_events_attr) {                                      \
-               .attr = __ATTR(name, 0444, armv8pmu_events_sysfs_show, NULL),   \
-               .id = config,                                                   \
-       }).attr.attr)
+       PMU_EVENT_ATTR_ID(name, armv8pmu_events_sysfs_show, config)
 
 static struct attribute *armv8_pmuv3_event_attrs[] = {
        ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_SW_INCR),
@@ -312,13 +309,46 @@ static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
        struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
        u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK;
 
-       return snprintf(page, PAGE_SIZE, "0x%08x\n", slots);
+       return sysfs_emit(page, "0x%08x\n", slots);
 }
 
 static DEVICE_ATTR_RO(slots);
 
+static ssize_t bus_slots_show(struct device *dev, struct device_attribute *attr,
+                             char *page)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+       struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
+       u32 bus_slots = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_SLOTS_SHIFT)
+                       & ARMV8_PMU_BUS_SLOTS_MASK;
+
+       return sysfs_emit(page, "0x%08x\n", bus_slots);
+}
+
+static DEVICE_ATTR_RO(bus_slots);
+
+static ssize_t bus_width_show(struct device *dev, struct device_attribute *attr,
+                             char *page)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+       struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
+       u32 bus_width = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_WIDTH_SHIFT)
+                       & ARMV8_PMU_BUS_WIDTH_MASK;
+       u32 val = 0;
+
+       /* Encoded as Log2(number of bytes), plus one */
+       if (bus_width > 2 && bus_width < 13)
+               val = 1 << (bus_width - 1);
+
+       return sysfs_emit(page, "0x%08x\n", val);
+}
+
+static DEVICE_ATTR_RO(bus_width);
+
 static struct attribute *armv8_pmuv3_caps_attrs[] = {
        &dev_attr_slots.attr,
+       &dev_attr_bus_slots.attr,
+       &dev_attr_bus_width.attr,
        NULL,
 };
 
index d607c99..6dbcc89 100644 (file)
@@ -7,26 +7,28 @@
  * Copyright (C) 2013 Linaro Limited.
  * Author: Sandeepa Prabhu <sandeepa.prabhu@linaro.org>
  */
+#include <linux/extable.h>
 #include <linux/kasan.h>
 #include <linux/kernel.h>
 #include <linux/kprobes.h>
-#include <linux/extable.h>
-#include <linux/slab.h>
-#include <linux/stop_machine.h>
 #include <linux/sched/debug.h>
 #include <linux/set_memory.h>
+#include <linux/slab.h>
+#include <linux/stop_machine.h>
 #include <linux/stringify.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
-#include <asm/traps.h>
-#include <asm/ptrace.h>
+
 #include <asm/cacheflush.h>
-#include <asm/debug-monitors.h>
 #include <asm/daifflags.h>
-#include <asm/system_misc.h>
+#include <asm/debug-monitors.h>
 #include <asm/insn.h>
-#include <linux/uaccess.h>
 #include <asm/irq.h>
+#include <asm/patching.h>
+#include <asm/ptrace.h>
 #include <asm/sections.h>
+#include <asm/system_misc.h>
+#include <asm/traps.h>
 
 #include "decode-insn.h"
 
@@ -277,23 +279,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 25f67ec..22d0b32 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kprobes.h>
 
 #include <asm/ptrace.h>
+#include <asm/traps.h>
 
 #include "simulate-insn.h"
 
index 2c24763..9be668f 100644 (file)
@@ -21,7 +21,7 @@ void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
        memcpy(dst, src, len);
 
        /* flush caches (dcache/icache) */
-       sync_icache_aliases(dst, len);
+       sync_icache_aliases((unsigned long)dst, (unsigned long)dst + len);
 
        kunmap_atomic(xol_page_kaddr);
 }
index b4bb67f..5ba0ed0 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/sched/task.h>
 #include <linux/sched/task_stack.h>
 #include <linux/kernel.h>
-#include <linux/lockdep.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/nospec.h>
@@ -46,7 +45,6 @@
 #include <linux/prctl.h>
 
 #include <asm/alternative.h>
-#include <asm/arch_gicv3.h>
 #include <asm/compat.h>
 #include <asm/cpufeature.h>
 #include <asm/cacheflush.h>
@@ -74,63 +72,6 @@ EXPORT_SYMBOL_GPL(pm_power_off);
 
 void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 
-static void noinstr __cpu_do_idle(void)
-{
-       dsb(sy);
-       wfi();
-}
-
-static void noinstr __cpu_do_idle_irqprio(void)
-{
-       unsigned long pmr;
-       unsigned long daif_bits;
-
-       daif_bits = read_sysreg(daif);
-       write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif);
-
-       /*
-        * Unmask PMR before going idle to make sure interrupts can
-        * be raised.
-        */
-       pmr = gic_read_pmr();
-       gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
-
-       __cpu_do_idle();
-
-       gic_write_pmr(pmr);
-       write_sysreg(daif_bits, daif);
-}
-
-/*
- *     cpu_do_idle()
- *
- *     Idle the processor (wait for interrupt).
- *
- *     If the CPU supports priority masking we must do additional work to
- *     ensure that interrupts are not masked at the PMR (because the core will
- *     not wake up if we block the wake up signal in the interrupt controller).
- */
-void noinstr cpu_do_idle(void)
-{
-       if (system_uses_irq_prio_masking())
-               __cpu_do_idle_irqprio();
-       else
-               __cpu_do_idle();
-}
-
-/*
- * This is our default idle handler.
- */
-void noinstr arch_cpu_idle(void)
-{
-       /*
-        * This should do all the clock switching and wait for interrupt
-        * tricks
-        */
-       cpu_do_idle();
-       raw_local_irq_enable();
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
 void arch_cpu_idle_dead(void)
 {
@@ -435,6 +376,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
        }
        p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
        p->thread.cpu_context.sp = (unsigned long)childregs;
+       /*
+        * For the benefit of the unwinder, set up childregs->stackframe
+        * as the final frame for the new task.
+        */
+       p->thread.cpu_context.fp = (unsigned long)childregs->stackframe;
 
        ptrace_hw_copy_thread(p);
 
@@ -527,6 +473,15 @@ static void erratum_1418040_thread_switch(struct task_struct *prev,
        write_sysreg(val, cntkctl_el1);
 }
 
+static void compat_thread_switch(struct task_struct *next)
+{
+       if (!is_compat_thread(task_thread_info(next)))
+               return;
+
+       if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
+               set_tsk_thread_flag(next, TIF_NOTIFY_RESUME);
+}
+
 static void update_sctlr_el1(u64 sctlr)
 {
        /*
@@ -568,6 +523,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
        ssbs_thread_switch(next);
        erratum_1418040_thread_switch(prev, next);
        ptrauth_thread_switch_user(next);
+       compat_thread_switch(next);
 
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
@@ -598,7 +554,7 @@ unsigned long get_wchan(struct task_struct *p)
        struct stackframe frame;
        unsigned long stack_page, ret = 0;
        int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long)try_get_task_stack(p);
@@ -633,8 +589,15 @@ unsigned long arch_align_stack(unsigned long sp)
  */
 void arch_setup_new_exec(void)
 {
-       current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
+       unsigned long mmflags = 0;
+
+       if (is_compat_task()) {
+               mmflags = MMCF_AARCH32;
+               if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
+                       set_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
+       }
 
+       current->mm->context.flags = mmflags;
        ptrauth_thread_init_user();
        mte_thread_init_user();
 
@@ -724,22 +687,6 @@ static int __init tagged_addr_init(void)
 core_initcall(tagged_addr_init);
 #endif /* CONFIG_ARM64_TAGGED_ADDR_ABI */
 
-asmlinkage void __sched arm64_preempt_schedule_irq(void)
-{
-       lockdep_assert_irqs_disabled();
-
-       /*
-        * Preempting a task from an IRQ means we leave copies of PSTATE
-        * on the stack. cpufeature's enable calls may modify PSTATE, but
-        * resuming one of these preempted tasks would undo those changes.
-        *
-        * Only allow a task to be preempted once cpufeatures have been
-        * enabled.
-        */
-       if (system_capabilities_finalized())
-               preempt_schedule_irq();
-}
-
 #ifdef CONFIG_BINFMT_ELF
 int arch_elf_adjust_prot(int prot, const struct arch_elf_state *state,
                         bool has_interp, bool is_interp)
index eb2f739..499b6b2 100644 (file)
@@ -122,7 +122,7 @@ static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
 {
        return ((addr & ~(THREAD_SIZE - 1))  ==
                (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))) ||
-               on_irq_stack(addr, NULL);
+               on_irq_stack(addr, sizeof(unsigned long), NULL);
 }
 
 /**
index 2c7ca44..47f77d1 100644 (file)
@@ -162,31 +162,33 @@ static int init_sdei_scs(void)
        return err;
 }
 
-static bool on_sdei_normal_stack(unsigned long sp, struct stack_info *info)
+static bool on_sdei_normal_stack(unsigned long sp, unsigned long size,
+                                struct stack_info *info)
 {
        unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_normal_ptr);
        unsigned long high = low + SDEI_STACK_SIZE;
 
-       return on_stack(sp, low, high, STACK_TYPE_SDEI_NORMAL, info);
+       return on_stack(sp, size, low, high, STACK_TYPE_SDEI_NORMAL, info);
 }
 
-static bool on_sdei_critical_stack(unsigned long sp, struct stack_info *info)
+static bool on_sdei_critical_stack(unsigned long sp, unsigned long size,
+                                  struct stack_info *info)
 {
        unsigned long low = (unsigned long)raw_cpu_read(sdei_stack_critical_ptr);
        unsigned long high = low + SDEI_STACK_SIZE;
 
-       return on_stack(sp, low, high, STACK_TYPE_SDEI_CRITICAL, info);
+       return on_stack(sp, size, low, high, STACK_TYPE_SDEI_CRITICAL, info);
 }
 
-bool _on_sdei_stack(unsigned long sp, struct stack_info *info)
+bool _on_sdei_stack(unsigned long sp, unsigned long size, struct stack_info *info)
 {
        if (!IS_ENABLED(CONFIG_VMAP_STACK))
                return false;
 
-       if (on_sdei_critical_stack(sp, info))
+       if (on_sdei_critical_stack(sp, size, info))
                return true;
 
-       if (on_sdei_normal_stack(sp, info))
+       if (on_sdei_normal_stack(sp, size, info))
                return true;
 
        return false;
@@ -231,13 +233,13 @@ out_err:
 }
 
 /*
- * __sdei_handler() returns one of:
+ * do_sdei_event() returns one of:
  *  SDEI_EV_HANDLED -  success, return to the interrupted context.
  *  SDEI_EV_FAILED  -  failure, return this error code to firmare.
  *  virtual-address -  success, return to this address.
  */
-static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
-                                            struct sdei_registered_event *arg)
+unsigned long __kprobes do_sdei_event(struct pt_regs *regs,
+                                     struct sdei_registered_event *arg)
 {
        u32 mode;
        int i, err = 0;
@@ -292,45 +294,3 @@ static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,
 
        return vbar + 0x480;
 }
-
-static void __kprobes notrace __sdei_pstate_entry(void)
-{
-       /*
-        * The original SDEI spec (ARM DEN 0054A) can be read ambiguously as to
-        * whether PSTATE bits are inherited unchanged or generated from
-        * scratch, and the TF-A implementation always clears PAN and always
-        * clears UAO. There are no other known implementations.
-        *
-        * Subsequent revisions (ARM DEN 0054B) follow the usual rules for how
-        * PSTATE is modified upon architectural exceptions, and so PAN is
-        * either inherited or set per SCTLR_ELx.SPAN, and UAO is always
-        * cleared.
-        *
-        * We must explicitly reset PAN to the expected state, including
-        * clearing it when the host isn't using it, in case a VM had it set.
-        */
-       if (system_uses_hw_pan())
-               set_pstate_pan(1);
-       else if (cpu_has_pan())
-               set_pstate_pan(0);
-}
-
-asmlinkage noinstr unsigned long
-__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
-{
-       unsigned long ret;
-
-       /*
-        * We didn't take an exception to get here, so the HW hasn't
-        * set/cleared bits in PSTATE that we may rely on. Initialize PAN.
-        */
-       __sdei_pstate_entry();
-
-       arm64_enter_nmi(regs);
-
-       ret = _sdei_handler(regs, arg);
-
-       arm64_exit_nmi(regs);
-
-       return ret;
-}
index 61845c0..8ed6614 100644 (file)
@@ -87,12 +87,6 @@ void __init smp_setup_processor_id(void)
        u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
        set_cpu_logical_map(0, mpidr);
 
-       /*
-        * clear __my_cpu_offset on boot CPU to avoid hang caused by
-        * using percpu variable early, for example, lockdep will
-        * access percpu variable inside lock_release
-        */
-       set_my_cpu_offset(0);
        pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n",
                (unsigned long)mpidr, read_cpuid_id());
 }
@@ -381,7 +375,7 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
         * faults in case uaccess_enable() is inadvertently called by the init
         * thread.
         */
-       init_task.thread_info.ttbr0 = __pa_symbol(reserved_pg_dir);
+       init_task.thread_info.ttbr0 = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
 #endif
 
        if (boot_args[1] || boot_args[2] || boot_args[3]) {
index 6237486..f8192f4 100644 (file)
@@ -911,6 +911,19 @@ static void do_signal(struct pt_regs *regs)
        restore_saved_sigmask();
 }
 
+static bool cpu_affinity_invalid(struct pt_regs *regs)
+{
+       if (!compat_user_mode(regs))
+               return false;
+
+       /*
+        * We're preemptible, but a reschedule will cause us to check the
+        * affinity again.
+        */
+       return !cpumask_test_cpu(raw_smp_processor_id(),
+                                system_32bit_el0_cpumask());
+}
+
 asmlinkage void do_notify_resume(struct pt_regs *regs,
                                 unsigned long thread_flags)
 {
@@ -938,6 +951,19 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
                        if (thread_flags & _TIF_NOTIFY_RESUME) {
                                tracehook_notify_resume(regs);
                                rseq_handle_notify_resume(NULL, regs);
+
+                               /*
+                                * If we reschedule after checking the affinity
+                                * then we must ensure that TIF_NOTIFY_RESUME
+                                * is set so that we check the affinity again.
+                                * Since tracehook_notify_resume() clears the
+                                * flag, ensure that the compiler doesn't move
+                                * it after the affinity check.
+                                */
+                               barrier();
+
+                               if (cpu_affinity_invalid(regs))
+                                       force_sig(SIGKILL);
                        }
 
                        if (thread_flags & _TIF_FOREIGN_FPSTATE)
index d624479..d3d37f9 100644 (file)
@@ -7,8 +7,34 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
+#include <asm/thread_info.h>
+
+/*
+ * If we have SMCCC v1.3 and (as is likely) no SVE state in
+ * the registers then set the SMCCC hint bit to say there's no
+ * need to preserve it.  Do this by directly adjusting the SMCCC
+ * function value which is already stored in x0 ready to be called.
+ */
+SYM_FUNC_START(__arm_smccc_sve_check)
+
+       ldr_l   x16, smccc_has_sve_hint
+       cbz     x16, 2f
+
+       get_current_task x16
+       ldr     x16, [x16, #TSK_TI_FLAGS]
+       tbnz    x16, #TIF_FOREIGN_FPSTATE, 1f   // Any live FP state?
+       tbnz    x16, #TIF_SVE, 2f               // Does that state include SVE?
+
+1:     orr     x0, x0, ARM_SMCCC_1_3_SVE_HINT
+
+2:     ret
+SYM_FUNC_END(__arm_smccc_sve_check)
+EXPORT_SYMBOL(__arm_smccc_sve_check)
 
        .macro SMCCC instr
+alternative_if ARM64_SVE
+       bl      __arm_smccc_sve_check
+alternative_else_nop_endif
        \instr  #0
        ldr     x4, [sp]
        stp     x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
@@ -43,3 +69,60 @@ SYM_FUNC_START(__arm_smccc_hvc)
        SMCCC   hvc
 SYM_FUNC_END(__arm_smccc_hvc)
 EXPORT_SYMBOL(__arm_smccc_hvc)
+
+       .macro SMCCC_1_2 instr
+       /* Save `res` and free a GPR that won't be clobbered */
+       stp     x1, x19, [sp, #-16]!
+
+       /* Ensure `args` won't be clobbered while loading regs in next step */
+       mov     x19, x0
+
+       /* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */
+       ldp     x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
+       ldp     x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
+       ldp     x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
+       ldp     x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
+       ldp     x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
+       ldp     x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
+       ldp     x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
+       ldp     x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
+       ldp     x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
+
+       \instr #0
+
+       /* Load the `res` from the stack */
+       ldr     x19, [sp]
+
+       /* Store the registers x0 - x17 into the result structure */
+       stp     x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
+       stp     x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
+       stp     x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
+       stp     x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
+       stp     x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
+       stp     x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
+       stp     x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
+       stp     x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
+       stp     x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
+
+       /* Restore original x19 */
+       ldp     xzr, x19, [sp], #16
+       ret
+.endm
+
+/*
+ * void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args,
+ *                       struct arm_smccc_1_2_regs *res);
+ */
+SYM_FUNC_START(arm_smccc_1_2_hvc)
+       SMCCC_1_2 hvc
+SYM_FUNC_END(arm_smccc_1_2_hvc)
+EXPORT_SYMBOL(arm_smccc_1_2_hvc)
+
+/*
+ * void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
+ *                       struct arm_smccc_1_2_regs *res);
+ */
+SYM_FUNC_START(arm_smccc_1_2_smc)
+       SMCCC_1_2 smc
+SYM_FUNC_END(arm_smccc_1_2_smc)
+EXPORT_SYMBOL(arm_smccc_1_2_smc)
index dcd7041..6f6ff07 100644 (file)
@@ -120,9 +120,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
         * page tables.
         */
        secondary_data.task = idle;
-       secondary_data.stack = task_stack_page(idle) + THREAD_SIZE;
        update_cpu_boot_status(CPU_MMU_OFF);
-       __flush_dcache_area(&secondary_data, sizeof(secondary_data));
 
        /* Now bring the CPU into our world */
        ret = boot_secondary(cpu, idle);
@@ -142,8 +140,6 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 
        pr_crit("CPU%u: failed to come online\n", cpu);
        secondary_data.task = NULL;
-       secondary_data.stack = NULL;
-       __flush_dcache_area(&secondary_data, sizeof(secondary_data));
        status = READ_ONCE(secondary_data.status);
        if (status == CPU_MMU_OFF)
                status = READ_ONCE(__early_cpu_boot_status);
@@ -202,10 +198,7 @@ asmlinkage notrace void secondary_start_kernel(void)
        u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
        struct mm_struct *mm = &init_mm;
        const struct cpu_operations *ops;
-       unsigned int cpu;
-
-       cpu = task_cpu(current);
-       set_my_cpu_offset(per_cpu_offset(cpu));
+       unsigned int cpu = smp_processor_id();
 
        /*
         * All kernel threads share the same mm context; grab a
@@ -224,7 +217,6 @@ asmlinkage notrace void secondary_start_kernel(void)
                init_gic_priority_masking();
 
        rcu_cpu_starting(cpu);
-       preempt_disable();
        trace_hardirqs_off();
 
        /*
@@ -352,7 +344,7 @@ void __cpu_die(unsigned int cpu)
                pr_crit("CPU%u: cpu didn't die\n", cpu);
                return;
        }
-       pr_notice("CPU%u: shutdown\n", cpu);
+       pr_debug("CPU%u: shutdown\n", cpu);
 
        /*
         * Now that the dying CPU is beyond the point of no return w.r.t.
@@ -452,6 +444,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
 
 void __init smp_prepare_boot_cpu(void)
 {
+       /*
+        * The runtime per-cpu areas have been allocated by
+        * setup_per_cpu_areas(), and CPU0's boot time per-cpu area will be
+        * freed shortly, so we must move over to the runtime per-cpu area.
+        */
        set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
        cpuinfo_store_boot_cpu();
 
index c45a835..7e1624e 100644 (file)
@@ -36,7 +36,7 @@ static void write_pen_release(u64 val)
        unsigned long size = sizeof(secondary_holding_pen_release);
 
        secondary_holding_pen_release = val;
-       __flush_dcache_area(start, size);
+       dcache_clean_inval_poc((unsigned long)start, (unsigned long)start + size);
 }
 
 
@@ -90,8 +90,9 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu)
         * the boot protocol.
         */
        writeq_relaxed(pa_holding_pen, release_addr);
-       __flush_dcache_area((__force void *)release_addr,
-                           sizeof(*release_addr));
+       dcache_clean_inval_poc((__force unsigned long)release_addr,
+                           (__force unsigned long)release_addr +
+                                   sizeof(*release_addr));
 
        /*
         * Send an event to wake up the secondary CPU.
index de07147..b189de5 100644 (file)
@@ -68,13 +68,17 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
        unsigned long fp = frame->fp;
        struct stack_info info;
 
-       if (fp & 0xf)
-               return -EINVAL;
-
        if (!tsk)
                tsk = current;
 
-       if (!on_accessible_stack(tsk, fp, &info))
+       /* Final frame; nothing to unwind */
+       if (fp == (unsigned long)task_pt_regs(tsk)->stackframe)
+               return -ENOENT;
+
+       if (fp & 0x7)
+               return -EINVAL;
+
+       if (!on_accessible_stack(tsk, fp, 16, &info))
                return -EINVAL;
 
        if (test_bit(info.type, frame->stacks_done))
@@ -128,12 +132,6 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 
        frame->pc = ptrauth_strip_insn_pac(frame->pc);
 
-       /*
-        * This is a terminal record, so we have finished unwinding.
-        */
-       if (!frame->fp && !frame->pc)
-               return -ENOENT;
-
        return 0;
 }
 NOKPROBE_SYMBOL(unwind_frame);
index e3f72df..938ce6f 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/alternative.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
+#include <asm/cpuidle.h>
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
 #include <asm/exec.h>
@@ -91,6 +92,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
        int ret = 0;
        unsigned long flags;
        struct sleep_stack_data state;
+       struct arm_cpuidle_irq_context context;
 
        /* Report any MTE async fault before going to suspend */
        mte_suspend_enter();
@@ -103,12 +105,18 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
        flags = local_daif_save();
 
        /*
-        * Function graph tracer state gets incosistent when the kernel
+        * Function graph tracer state gets inconsistent when the kernel
         * calls functions that never return (aka suspend finishers) hence
         * disable graph tracing during their execution.
         */
        pause_graph_tracing();
 
+       /*
+        * Switch to using DAIF.IF instead of PMR in order to reliably
+        * resume if we're using pseudo-NMIs.
+        */
+       arm_cpuidle_save_irq_context(&context);
+
        if (__cpu_suspend_enter(&state)) {
                /* Call the suspend finisher */
                ret = fn(arg);
@@ -126,6 +134,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
                RCU_NONIDLE(__cpu_suspend_exit());
        }
 
+       arm_cpuidle_restore_irq_context(&context);
+
        unpause_graph_tracing();
 
        /*
index 265fe3e..db5159a 100644 (file)
@@ -41,7 +41,7 @@ __do_compat_cache_op(unsigned long start, unsigned long end)
                        dsb(ish);
                }
 
-               ret = __flush_cache_user_range(start, start + chunk);
+               ret = caches_clean_inval_user_pou(start, start + chunk);
                if (ret)
                        return ret;
 
index a05d34f..b03e383 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/extable.h>
 #include <asm/insn.h>
 #include <asm/kprobes.h>
+#include <asm/patching.h>
 #include <asm/traps.h>
 #include <asm/smp.h>
 #include <asm/stack_pointer.h>
 #include <asm/system_misc.h>
 #include <asm/sysreg.h>
 
-static const char *handler[] = {
-       "Synchronous Abort",
-       "IRQ",
-       "FIQ",
-       "Error"
+static bool __kprobes __check_eq(unsigned long pstate)
+{
+       return (pstate & PSR_Z_BIT) != 0;
+}
+
+static bool __kprobes __check_ne(unsigned long pstate)
+{
+       return (pstate & PSR_Z_BIT) == 0;
+}
+
+static bool __kprobes __check_cs(unsigned long pstate)
+{
+       return (pstate & PSR_C_BIT) != 0;
+}
+
+static bool __kprobes __check_cc(unsigned long pstate)
+{
+       return (pstate & PSR_C_BIT) == 0;
+}
+
+static bool __kprobes __check_mi(unsigned long pstate)
+{
+       return (pstate & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_pl(unsigned long pstate)
+{
+       return (pstate & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_vs(unsigned long pstate)
+{
+       return (pstate & PSR_V_BIT) != 0;
+}
+
+static bool __kprobes __check_vc(unsigned long pstate)
+{
+       return (pstate & PSR_V_BIT) == 0;
+}
+
+static bool __kprobes __check_hi(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (pstate & PSR_C_BIT) != 0;
+}
+
+static bool __kprobes __check_ls(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (pstate & PSR_C_BIT) == 0;
+}
+
+static bool __kprobes __check_ge(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return (pstate & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_lt(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return (pstate & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_gt(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return (temp & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_le(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return (temp & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_al(unsigned long pstate)
+{
+       return true;
+}
+
+/*
+ * Note that the ARMv8 ARM calls condition code 0b1111 "nv", but states that
+ * it behaves identically to 0b1110 ("al").
+ */
+pstate_check_t * const aarch32_opcode_cond_checks[16] = {
+       __check_eq, __check_ne, __check_cs, __check_cc,
+       __check_mi, __check_pl, __check_vs, __check_vc,
+       __check_hi, __check_ls, __check_ge, __check_lt,
+       __check_gt, __check_le, __check_al, __check_al
 };
 
 int show_unhandled_signals = 0;
@@ -751,27 +843,8 @@ const char *esr_get_class_string(u32 esr)
 }
 
 /*
- * bad_mode handles the impossible case in the exception vector. This is always
- * fatal.
- */
-asmlinkage void notrace bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
-{
-       arm64_enter_nmi(regs);
-
-       console_verbose();
-
-       pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %s\n",
-               handler[reason], smp_processor_id(), esr,
-               esr_get_class_string(esr));
-
-       __show_regs(regs);
-       local_daif_mask();
-       panic("bad mode");
-}
-
-/*
  * bad_el0_sync handles unexpected, but potentially recoverable synchronous
- * exceptions taken from EL0. Unlike bad_mode, this returns.
+ * exceptions taken from EL0.
  */
 void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
 {
@@ -789,15 +862,11 @@ void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
 DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
        __aligned(16);
 
-asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs)
+void panic_bad_stack(struct pt_regs *regs, unsigned int esr, unsigned long far)
 {
        unsigned long tsk_stk = (unsigned long)current->stack;
        unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr);
        unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
-       unsigned int esr = read_sysreg(esr_el1);
-       unsigned long far = read_sysreg(far_el1);
-
-       arm64_enter_nmi(regs);
 
        console_verbose();
        pr_emerg("Insufficient stack space to handle exception!");
@@ -870,15 +939,11 @@ bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr)
        }
 }
 
-asmlinkage void noinstr do_serror(struct pt_regs *regs, unsigned int esr)
+void do_serror(struct pt_regs *regs, unsigned int esr)
 {
-       arm64_enter_nmi(regs);
-
        /* non-RAS errors are not containable */
        if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(regs, esr))
                arm64_serror_panic(regs, esr);
-
-       arm64_exit_nmi(regs);
 }
 
 /* GENERIC_BUG traps */
index 3964acf..a4eba09 100644 (file)
@@ -20,8 +20,6 @@ if VIRTUALIZATION
 menuconfig KVM
        bool "Kernel-based Virtual Machine (KVM) support"
        depends on OF
-       # for TASKSTATS/TASK_DELAY_ACCT:
-       depends on NET && MULTIUSER
        select MMU_NOTIFIER
        select PREEMPT_NOTIFIERS
        select HAVE_KVM_CPU_RELAX_INTERCEPT
@@ -38,8 +36,7 @@ menuconfig KVM
        select IRQ_BYPASS_MANAGER
        select HAVE_KVM_IRQ_BYPASS
        select HAVE_KVM_VCPU_RUN_PID_CHANGE
-       select TASKSTATS
-       select TASK_DELAY_ACCT
+       select SCHED_INFO
        help
          Support hosting virtualized guest machines.
 
index 5899213..989bb5d 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_KVM) += kvm.o
 obj-$(CONFIG_KVM) += hyp/
 
 kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
-        $(KVM)/vfio.o $(KVM)/irqchip.o \
+        $(KVM)/vfio.o $(KVM)/irqchip.o $(KVM)/binary_stats.o \
         arm.o mmu.o mmio.o psci.o perf.o hypercalls.o pvtime.o \
         inject_fault.o va_layout.o handle_exit.o \
         guest.o debug.o reset.o sys_regs.o \
index 74e0699..3df67c1 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/uaccess.h>
 
 #include <clocksource/arm_arch_timer.h>
@@ -973,36 +974,154 @@ static int kvm_timer_dying_cpu(unsigned int cpu)
        return 0;
 }
 
-int kvm_timer_hyp_init(bool has_gic)
+static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 {
-       struct arch_timer_kvm_info *info;
-       int err;
+       if (vcpu)
+               irqd_set_forwarded_to_vcpu(d);
+       else
+               irqd_clr_forwarded_to_vcpu(d);
 
-       info = arch_timer_get_kvm_info();
-       timecounter = &info->timecounter;
+       return 0;
+}
 
-       if (!timecounter->cc) {
-               kvm_err("kvm_arch_timer: uninitialized timecounter\n");
-               return -ENODEV;
+static int timer_irq_set_irqchip_state(struct irq_data *d,
+                                      enum irqchip_irq_state which, bool val)
+{
+       if (which != IRQCHIP_STATE_ACTIVE || !irqd_is_forwarded_to_vcpu(d))
+               return irq_chip_set_parent_state(d, which, val);
+
+       if (val)
+               irq_chip_mask_parent(d);
+       else
+               irq_chip_unmask_parent(d);
+
+       return 0;
+}
+
+static void timer_irq_eoi(struct irq_data *d)
+{
+       if (!irqd_is_forwarded_to_vcpu(d))
+               irq_chip_eoi_parent(d);
+}
+
+static void timer_irq_ack(struct irq_data *d)
+{
+       d = d->parent_data;
+       if (d->chip->irq_ack)
+               d->chip->irq_ack(d);
+}
+
+static struct irq_chip timer_chip = {
+       .name                   = "KVM",
+       .irq_ack                = timer_irq_ack,
+       .irq_mask               = irq_chip_mask_parent,
+       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_eoi                = timer_irq_eoi,
+       .irq_set_type           = irq_chip_set_type_parent,
+       .irq_set_vcpu_affinity  = timer_irq_set_vcpu_affinity,
+       .irq_set_irqchip_state  = timer_irq_set_irqchip_state,
+};
+
+static int timer_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                                 unsigned int nr_irqs, void *arg)
+{
+       irq_hw_number_t hwirq = (uintptr_t)arg;
+
+       return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+                                            &timer_chip, NULL);
+}
+
+static void timer_irq_domain_free(struct irq_domain *domain, unsigned int virq,
+                                 unsigned int nr_irqs)
+{
+}
+
+static const struct irq_domain_ops timer_domain_ops = {
+       .alloc  = timer_irq_domain_alloc,
+       .free   = timer_irq_domain_free,
+};
+
+static struct irq_ops arch_timer_irq_ops = {
+       .get_input_level = kvm_arch_timer_get_input_level,
+};
+
+static void kvm_irq_fixup_flags(unsigned int virq, u32 *flags)
+{
+       *flags = irq_get_trigger_type(virq);
+       if (*flags != IRQF_TRIGGER_HIGH && *flags != IRQF_TRIGGER_LOW) {
+               kvm_err("Invalid trigger for timer IRQ%d, assuming level low\n",
+                       virq);
+               *flags = IRQF_TRIGGER_LOW;
        }
+}
 
-       /* First, do the virtual EL1 timer irq */
+static int kvm_irq_init(struct arch_timer_kvm_info *info)
+{
+       struct irq_domain *domain = NULL;
 
        if (info->virtual_irq <= 0) {
                kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
                        info->virtual_irq);
                return -ENODEV;
        }
+
        host_vtimer_irq = info->virtual_irq;
+       kvm_irq_fixup_flags(host_vtimer_irq, &host_vtimer_irq_flags);
+
+       if (kvm_vgic_global_state.no_hw_deactivation) {
+               struct fwnode_handle *fwnode;
+               struct irq_data *data;
+
+               fwnode = irq_domain_alloc_named_fwnode("kvm-timer");
+               if (!fwnode)
+                       return -ENOMEM;
+
+               /* Assume both vtimer and ptimer in the same parent */
+               data = irq_get_irq_data(host_vtimer_irq);
+               domain = irq_domain_create_hierarchy(data->domain, 0,
+                                                    NR_KVM_TIMERS, fwnode,
+                                                    &timer_domain_ops, NULL);
+               if (!domain) {
+                       irq_domain_free_fwnode(fwnode);
+                       return -ENOMEM;
+               }
+
+               arch_timer_irq_ops.flags |= VGIC_IRQ_SW_RESAMPLE;
+               WARN_ON(irq_domain_push_irq(domain, host_vtimer_irq,
+                                           (void *)TIMER_VTIMER));
+       }
 
-       host_vtimer_irq_flags = irq_get_trigger_type(host_vtimer_irq);
-       if (host_vtimer_irq_flags != IRQF_TRIGGER_HIGH &&
-           host_vtimer_irq_flags != IRQF_TRIGGER_LOW) {
-               kvm_err("Invalid trigger for vtimer IRQ%d, assuming level low\n",
-                       host_vtimer_irq);
-               host_vtimer_irq_flags = IRQF_TRIGGER_LOW;
+       if (info->physical_irq > 0) {
+               host_ptimer_irq = info->physical_irq;
+               kvm_irq_fixup_flags(host_ptimer_irq, &host_ptimer_irq_flags);
+
+               if (domain)
+                       WARN_ON(irq_domain_push_irq(domain, host_ptimer_irq,
+                                                   (void *)TIMER_PTIMER));
        }
 
+       return 0;
+}
+
+int kvm_timer_hyp_init(bool has_gic)
+{
+       struct arch_timer_kvm_info *info;
+       int err;
+
+       info = arch_timer_get_kvm_info();
+       timecounter = &info->timecounter;
+
+       if (!timecounter->cc) {
+               kvm_err("kvm_arch_timer: uninitialized timecounter\n");
+               return -ENODEV;
+       }
+
+       err = kvm_irq_init(info);
+       if (err)
+               return err;
+
+       /* First, do the virtual EL1 timer irq */
+
        err = request_percpu_irq(host_vtimer_irq, kvm_arch_timer_handler,
                                 "kvm guest vtimer", kvm_get_running_vcpus());
        if (err) {
@@ -1027,15 +1146,6 @@ int kvm_timer_hyp_init(bool has_gic)
        /* Now let's do the physical EL1 timer irq */
 
        if (info->physical_irq > 0) {
-               host_ptimer_irq = info->physical_irq;
-               host_ptimer_irq_flags = irq_get_trigger_type(host_ptimer_irq);
-               if (host_ptimer_irq_flags != IRQF_TRIGGER_HIGH &&
-                   host_ptimer_irq_flags != IRQF_TRIGGER_LOW) {
-                       kvm_err("Invalid trigger for ptimer IRQ%d, assuming level low\n",
-                               host_ptimer_irq);
-                       host_ptimer_irq_flags = IRQF_TRIGGER_LOW;
-               }
-
                err = request_percpu_irq(host_ptimer_irq, kvm_arch_timer_handler,
                                         "kvm guest ptimer", kvm_get_running_vcpus());
                if (err) {
@@ -1143,7 +1253,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
        ret = kvm_vgic_map_phys_irq(vcpu,
                                    map.direct_vtimer->host_timer_irq,
                                    map.direct_vtimer->irq.irq,
-                                   kvm_arch_timer_get_input_level);
+                                   &arch_timer_irq_ops);
        if (ret)
                return ret;
 
@@ -1151,7 +1261,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
                ret = kvm_vgic_map_phys_irq(vcpu,
                                            map.direct_ptimer->host_timer_irq,
                                            map.direct_ptimer->irq.irq,
-                                           kvm_arch_timer_get_input_level);
+                                           &arch_timer_irq_ops);
        }
 
        if (ret)
index e720148..e9a2b8f 100644 (file)
@@ -93,6 +93,12 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
                r = 0;
                kvm->arch.return_nisv_io_abort_to_user = true;
                break;
+       case KVM_CAP_ARM_MTE:
+               if (!system_supports_mte() || kvm->created_vcpus)
+                       return -EINVAL;
+               r = 0;
+               kvm->arch.mte_enabled = true;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -237,6 +243,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                 */
                r = 1;
                break;
+       case KVM_CAP_ARM_MTE:
+               r = system_supports_mte();
+               break;
        case KVM_CAP_STEAL_TIME:
                r = kvm_arm_pvtime_supported();
                break;
@@ -689,9 +698,22 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu)
                        vgic_v4_load(vcpu);
                        preempt_enable();
                }
+
+               if (kvm_check_request(KVM_REQ_RELOAD_PMU, vcpu))
+                       kvm_pmu_handle_pmcr(vcpu,
+                                           __vcpu_sys_reg(vcpu, PMCR_EL0));
        }
 }
 
+static bool vcpu_mode_is_bad_32bit(struct kvm_vcpu *vcpu)
+{
+       if (likely(!vcpu_mode_is_32bit(vcpu)))
+               return false;
+
+       return !system_supports_32bit_el0() ||
+               static_branch_unlikely(&arm64_mismatched_32bit_el0);
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:      The VCPU pointer
@@ -877,7 +899,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                 * with the asymmetric AArch32 case), return to userspace with
                 * a fatal error.
                 */
-               if (!system_supports_32bit_el0() && vcpu_mode_is_32bit(vcpu)) {
+               if (vcpu_mode_is_bad_32bit(vcpu)) {
                        /*
                         * As we have caught the guest red-handed, decide that
                         * it isn't fit for purpose anymore by making the vcpu
@@ -1078,7 +1100,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
                if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
                        stage2_unmap_vm(vcpu->kvm);
                else
-                       __flush_icache_all();
+                       icache_inval_all_pou();
        }
 
        vcpu_reset_hcr(vcpu);
@@ -1350,6 +1372,13 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
                return 0;
        }
+       case KVM_ARM_MTE_COPY_TAGS: {
+               struct kvm_arm_copy_mte_tags copy_tags;
+
+               if (copy_from_user(&copy_tags, argp, sizeof(copy_tags)))
+                       return -EFAULT;
+               return kvm_vm_ioctl_mte_copy_tags(kvm, &copy_tags);
+       }
        default:
                return -EINVAL;
        }
index 5cb4a1c..1dfb835 100644 (file)
 
 #include "trace.h"
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("hvc_exit_stat", hvc_exit_stat),
-       VCPU_STAT("wfe_exit_stat", wfe_exit_stat),
-       VCPU_STAT("wfi_exit_stat", wfi_exit_stat),
-       VCPU_STAT("mmio_exit_user", mmio_exit_user),
-       VCPU_STAT("mmio_exit_kernel", mmio_exit_kernel),
-       VCPU_STAT("exits", exits),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       { NULL }
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS()
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset =  sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, hvc_exit_stat),
+       STATS_DESC_COUNTER(VCPU, wfe_exit_stat),
+       STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
+       STATS_DESC_COUNTER(VCPU, mmio_exit_user),
+       STATS_DESC_COUNTER(VCPU, mmio_exit_kernel),
+       STATS_DESC_COUNTER(VCPU, exits)
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 static bool core_reg_offset_is_vreg(u64 off)
@@ -995,3 +1015,89 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
 
        return ret;
 }
+
+long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
+                               struct kvm_arm_copy_mte_tags *copy_tags)
+{
+       gpa_t guest_ipa = copy_tags->guest_ipa;
+       size_t length = copy_tags->length;
+       void __user *tags = copy_tags->addr;
+       gpa_t gfn;
+       bool write = !(copy_tags->flags & KVM_ARM_TAGS_FROM_GUEST);
+       int ret = 0;
+
+       if (!kvm_has_mte(kvm))
+               return -EINVAL;
+
+       if (copy_tags->reserved[0] || copy_tags->reserved[1])
+               return -EINVAL;
+
+       if (copy_tags->flags & ~KVM_ARM_TAGS_FROM_GUEST)
+               return -EINVAL;
+
+       if (length & ~PAGE_MASK || guest_ipa & ~PAGE_MASK)
+               return -EINVAL;
+
+       gfn = gpa_to_gfn(guest_ipa);
+
+       mutex_lock(&kvm->slots_lock);
+
+       while (length > 0) {
+               kvm_pfn_t pfn = gfn_to_pfn_prot(kvm, gfn, write, NULL);
+               void *maddr;
+               unsigned long num_tags;
+               struct page *page;
+
+               if (is_error_noslot_pfn(pfn)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               page = pfn_to_online_page(pfn);
+               if (!page) {
+                       /* Reject ZONE_DEVICE memory */
+                       ret = -EFAULT;
+                       goto out;
+               }
+               maddr = page_address(page);
+
+               if (!write) {
+                       if (test_bit(PG_mte_tagged, &page->flags))
+                               num_tags = mte_copy_tags_to_user(tags, maddr,
+                                                       MTE_GRANULES_PER_PAGE);
+                       else
+                               /* No tags in memory, so write zeros */
+                               num_tags = MTE_GRANULES_PER_PAGE -
+                                       clear_user(tags, MTE_GRANULES_PER_PAGE);
+                       kvm_release_pfn_clean(pfn);
+               } else {
+                       num_tags = mte_copy_tags_from_user(maddr, tags,
+                                                       MTE_GRANULES_PER_PAGE);
+
+                       /*
+                        * Set the flag after checking the write
+                        * completed fully
+                        */
+                       if (num_tags == MTE_GRANULES_PER_PAGE)
+                               set_bit(PG_mte_tagged, &page->flags);
+
+                       kvm_release_pfn_dirty(pfn);
+               }
+
+               if (num_tags != MTE_GRANULES_PER_PAGE) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               gfn++;
+               tags += num_tags;
+               length -= PAGE_SIZE;
+       }
+
+out:
+       mutex_unlock(&kvm->slots_lock);
+       /* If some data has been copied report the number of bytes copied */
+       if (length != copy_tags->length)
+               return copy_tags->length - length;
+       return ret;
+}
index e831d3d..435346e 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_mte.h>
 #include <asm/kvm_ptrauth.h>
 
        .text
@@ -51,6 +52,9 @@ alternative_else_nop_endif
 
        add     x29, x0, #VCPU_CONTEXT
 
+       // mte_switch_to_guest(g_ctxt, h_ctxt, tmp1)
+       mte_switch_to_guest x29, x1, x2
+
        // Macro ptrauth_switch_to_guest format:
        //      ptrauth_switch_to_guest(guest cxt, tmp1, tmp2, tmp3)
        // The below macro to restore guest keys is not implemented in C code
@@ -142,6 +146,9 @@ SYM_INNER_LABEL(__guest_exit, SYM_L_GLOBAL)
        // when this feature is enabled for kernel code.
        ptrauth_switch_to_hyp x1, x2, x3, x4, x5
 
+       // mte_switch_to_hyp(g_ctxt, h_ctxt, reg1)
+       mte_switch_to_hyp x1, x2, x3
+
        // Restore hyp's sp_el0
        restore_sp_el0 x2, x3
 
index 11541b9..0418399 100644 (file)
@@ -112,7 +112,8 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
        new |= (old & PSR_C_BIT);
        new |= (old & PSR_V_BIT);
 
-       // TODO: TCO (if/when ARMv8.5-MemTag is exposed to guests)
+       if (kvm_has_mte(vcpu->kvm))
+               new |= PSR_TCO_BIT;
 
        new |= (old & PSR_DIT_BIT);
 
index 5f49df4..9aa9b73 100644 (file)
@@ -76,6 +76,7 @@ el1_trap:
        b       __guest_exit
 
 el1_irq:
+el1_fiq:
        get_vcpu_ptr    x1, x0
        mov     x0, #ARM_EXCEPTION_IRQ
        b       __guest_exit
@@ -131,7 +132,6 @@ SYM_CODE_END(\label)
        invalid_vector  el2t_error_invalid
        invalid_vector  el2h_irq_invalid
        invalid_vector  el2h_fiq_invalid
-       invalid_vector  el1_fiq_invalid
 
        .ltorg
 
@@ -179,12 +179,12 @@ SYM_CODE_START(__kvm_hyp_vector)
 
        valid_vect      el1_sync                // Synchronous 64-bit EL1
        valid_vect      el1_irq                 // IRQ 64-bit EL1
-       invalid_vect    el1_fiq_invalid         // FIQ 64-bit EL1
+       valid_vect      el1_fiq                 // FIQ 64-bit EL1
        valid_vect      el1_error               // Error 64-bit EL1
 
        valid_vect      el1_sync                // Synchronous 32-bit EL1
        valid_vect      el1_irq                 // IRQ 32-bit EL1
-       invalid_vect    el1_fiq_invalid         // FIQ 32-bit EL1
+       valid_vect      el1_fiq                 // FIQ 32-bit EL1
        valid_vect      el1_error               // Error 32-bit EL1
 SYM_CODE_END(__kvm_hyp_vector)
 
index cce43bf..de7e14c 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_mmu.h>
 
 static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
@@ -26,6 +27,16 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
        ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0);
 }
 
+static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
+{
+       struct kvm_vcpu *vcpu = ctxt->__hyp_running_vcpu;
+
+       if (!vcpu)
+               vcpu = container_of(ctxt, struct kvm_vcpu, arch.ctxt);
+
+       return kvm_has_mte(kern_hyp_va(vcpu->kvm));
+}
+
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
        ctxt_sys_reg(ctxt, CSSELR_EL1)  = read_sysreg(csselr_el1);
@@ -46,6 +57,11 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
        ctxt_sys_reg(ctxt, PAR_EL1)     = read_sysreg_par();
        ctxt_sys_reg(ctxt, TPIDR_EL1)   = read_sysreg(tpidr_el1);
 
+       if (ctxt_has_mte(ctxt)) {
+               ctxt_sys_reg(ctxt, TFSR_EL1) = read_sysreg_el1(SYS_TFSR);
+               ctxt_sys_reg(ctxt, TFSRE0_EL1) = read_sysreg_s(SYS_TFSRE0_EL1);
+       }
+
        ctxt_sys_reg(ctxt, SP_EL1)      = read_sysreg(sp_el1);
        ctxt_sys_reg(ctxt, ELR_EL1)     = read_sysreg_el1(SYS_ELR);
        ctxt_sys_reg(ctxt, SPSR_EL1)    = read_sysreg_el1(SYS_SPSR);
@@ -107,6 +123,11 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
        write_sysreg(ctxt_sys_reg(ctxt, PAR_EL1),       par_el1);
        write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL1),     tpidr_el1);
 
+       if (ctxt_has_mte(ctxt)) {
+               write_sysreg_el1(ctxt_sys_reg(ctxt, TFSR_EL1), SYS_TFSR);
+               write_sysreg_s(ctxt_sys_reg(ctxt, TFSRE0_EL1), SYS_TFSRE0_EL1);
+       }
+
        if (!has_vhe() &&
            cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT) &&
            ctxt->__hyp_running_vcpu) {
index 18a4494..fb0f523 100644 (file)
@@ -7,7 +7,7 @@
 #include <nvhe/memory.h>
 #include <nvhe/spinlock.h>
 
-#define HYP_NO_ORDER   UINT_MAX
+#define HYP_NO_ORDER   USHRT_MAX
 
 struct hyp_pool {
        /*
@@ -19,48 +19,13 @@ struct hyp_pool {
        struct list_head free_area[MAX_ORDER];
        phys_addr_t range_start;
        phys_addr_t range_end;
-       unsigned int max_order;
+       unsigned short max_order;
 };
 
-static inline void hyp_page_ref_inc(struct hyp_page *p)
-{
-       struct hyp_pool *pool = hyp_page_to_pool(p);
-
-       hyp_spin_lock(&pool->lock);
-       p->refcount++;
-       hyp_spin_unlock(&pool->lock);
-}
-
-static inline int hyp_page_ref_dec_and_test(struct hyp_page *p)
-{
-       struct hyp_pool *pool = hyp_page_to_pool(p);
-       int ret;
-
-       hyp_spin_lock(&pool->lock);
-       p->refcount--;
-       ret = (p->refcount == 0);
-       hyp_spin_unlock(&pool->lock);
-
-       return ret;
-}
-
-static inline void hyp_set_page_refcounted(struct hyp_page *p)
-{
-       struct hyp_pool *pool = hyp_page_to_pool(p);
-
-       hyp_spin_lock(&pool->lock);
-       if (p->refcount) {
-               hyp_spin_unlock(&pool->lock);
-               BUG();
-       }
-       p->refcount = 1;
-       hyp_spin_unlock(&pool->lock);
-}
-
 /* Allocation */
-void *hyp_alloc_pages(struct hyp_pool *pool, unsigned int order);
-void hyp_get_page(void *addr);
-void hyp_put_page(void *addr);
+void *hyp_alloc_pages(struct hyp_pool *pool, unsigned short order);
+void hyp_get_page(struct hyp_pool *pool, void *addr);
+void hyp_put_page(struct hyp_pool *pool, void *addr);
 
 /* Used pages cannot be freed */
 int hyp_pool_init(struct hyp_pool *pool, u64 pfn, unsigned int nr_pages,
index 42d81ec..9c227d8 100644 (file)
@@ -23,7 +23,7 @@ extern struct host_kvm host_kvm;
 int __pkvm_prot_finalize(void);
 int __pkvm_mark_hyp(phys_addr_t start, phys_addr_t end);
 
-int kvm_host_prepare_stage2(void *mem_pgt_pool, void *dev_pgt_pool);
+int kvm_host_prepare_stage2(void *pgt_pool_base);
 void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt);
 
 static __always_inline void __load_host_stage2(void)
index fd78bde..592b7ed 100644 (file)
@@ -7,12 +7,9 @@
 
 #include <linux/types.h>
 
-struct hyp_pool;
 struct hyp_page {
-       unsigned int refcount;
-       unsigned int order;
-       struct hyp_pool *pool;
-       struct list_head node;
+       unsigned short refcount;
+       unsigned short order;
 };
 
 extern u64 __hyp_vmemmap;
index 0095f62..8ec3a5a 100644 (file)
@@ -78,19 +78,20 @@ static inline unsigned long hyp_s1_pgtable_pages(void)
        return res;
 }
 
-static inline unsigned long host_s2_mem_pgtable_pages(void)
+static inline unsigned long host_s2_pgtable_pages(void)
 {
+       unsigned long res;
+
        /*
         * Include an extra 16 pages to safely upper-bound the worst case of
         * concatenated pgds.
         */
-       return __hyp_pgtable_total_pages() + 16;
-}
+       res = __hyp_pgtable_total_pages() + 16;
 
-static inline unsigned long host_s2_dev_pgtable_pages(void)
-{
        /* Allow 1 GiB for MMIO mappings */
-       return __hyp_pgtable_max_pages(SZ_1G >> PAGE_SHIFT);
+       res += __hyp_pgtable_max_pages(SZ_1G >> PAGE_SHIFT);
+
+       return res;
 }
 
 #endif /* __KVM_HYP_MM_H */
index 36cef69..958734f 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/assembler.h>
 #include <asm/alternative.h>
 
-SYM_FUNC_START_PI(__flush_dcache_area)
+SYM_FUNC_START_PI(dcache_clean_inval_poc)
        dcache_by_line_op civac, sy, x0, x1, x2, x3
        ret
-SYM_FUNC_END_PI(__flush_dcache_area)
+SYM_FUNC_END_PI(dcache_clean_inval_poc)
index 4b60c00..d938ce9 100644 (file)
@@ -23,8 +23,7 @@
 extern unsigned long hyp_nr_cpus;
 struct host_kvm host_kvm;
 
-static struct hyp_pool host_s2_mem;
-static struct hyp_pool host_s2_dev;
+static struct hyp_pool host_s2_pool;
 
 /*
  * Copies of the host's CPU features registers holding sanitized values.
@@ -36,7 +35,7 @@ static const u8 pkvm_hyp_id = 1;
 
 static void *host_s2_zalloc_pages_exact(size_t size)
 {
-       return hyp_alloc_pages(&host_s2_mem, get_order(size));
+       return hyp_alloc_pages(&host_s2_pool, get_order(size));
 }
 
 static void *host_s2_zalloc_page(void *pool)
@@ -44,20 +43,24 @@ static void *host_s2_zalloc_page(void *pool)
        return hyp_alloc_pages(pool, 0);
 }
 
-static int prepare_s2_pools(void *mem_pgt_pool, void *dev_pgt_pool)
+static void host_s2_get_page(void *addr)
+{
+       hyp_get_page(&host_s2_pool, addr);
+}
+
+static void host_s2_put_page(void *addr)
+{
+       hyp_put_page(&host_s2_pool, addr);
+}
+
+static int prepare_s2_pool(void *pgt_pool_base)
 {
        unsigned long nr_pages, pfn;
        int ret;
 
-       pfn = hyp_virt_to_pfn(mem_pgt_pool);
-       nr_pages = host_s2_mem_pgtable_pages();
-       ret = hyp_pool_init(&host_s2_mem, pfn, nr_pages, 0);
-       if (ret)
-               return ret;
-
-       pfn = hyp_virt_to_pfn(dev_pgt_pool);
-       nr_pages = host_s2_dev_pgtable_pages();
-       ret = hyp_pool_init(&host_s2_dev, pfn, nr_pages, 0);
+       pfn = hyp_virt_to_pfn(pgt_pool_base);
+       nr_pages = host_s2_pgtable_pages();
+       ret = hyp_pool_init(&host_s2_pool, pfn, nr_pages, 0);
        if (ret)
                return ret;
 
@@ -67,8 +70,8 @@ static int prepare_s2_pools(void *mem_pgt_pool, void *dev_pgt_pool)
                .phys_to_virt = hyp_phys_to_virt,
                .virt_to_phys = hyp_virt_to_phys,
                .page_count = hyp_page_count,
-               .get_page = hyp_get_page,
-               .put_page = hyp_put_page,
+               .get_page = host_s2_get_page,
+               .put_page = host_s2_put_page,
        };
 
        return 0;
@@ -86,7 +89,7 @@ static void prepare_host_vtcr(void)
                                          id_aa64mmfr1_el1_sys_val, phys_shift);
 }
 
-int kvm_host_prepare_stage2(void *mem_pgt_pool, void *dev_pgt_pool)
+int kvm_host_prepare_stage2(void *pgt_pool_base)
 {
        struct kvm_s2_mmu *mmu = &host_kvm.arch.mmu;
        int ret;
@@ -94,7 +97,7 @@ int kvm_host_prepare_stage2(void *mem_pgt_pool, void *dev_pgt_pool)
        prepare_host_vtcr();
        hyp_spin_lock_init(&host_kvm.lock);
 
-       ret = prepare_s2_pools(mem_pgt_pool, dev_pgt_pool);
+       ret = prepare_s2_pool(pgt_pool_base);
        if (ret)
                return ret;
 
@@ -199,11 +202,10 @@ static bool range_is_memory(u64 start, u64 end)
 }
 
 static inline int __host_stage2_idmap(u64 start, u64 end,
-                                     enum kvm_pgtable_prot prot,
-                                     struct hyp_pool *pool)
+                                     enum kvm_pgtable_prot prot)
 {
        return kvm_pgtable_stage2_map(&host_kvm.pgt, start, end - start, start,
-                                     prot, pool);
+                                     prot, &host_s2_pool);
 }
 
 static int host_stage2_idmap(u64 addr)
@@ -211,7 +213,6 @@ static int host_stage2_idmap(u64 addr)
        enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R | KVM_PGTABLE_PROT_W;
        struct kvm_mem_range range;
        bool is_memory = find_mem_range(addr, &range);
-       struct hyp_pool *pool = is_memory ? &host_s2_mem : &host_s2_dev;
        int ret;
 
        if (is_memory)
@@ -222,22 +223,21 @@ static int host_stage2_idmap(u64 addr)
        if (ret)
                goto unlock;
 
-       ret = __host_stage2_idmap(range.start, range.end, prot, pool);
-       if (is_memory || ret != -ENOMEM)
+       ret = __host_stage2_idmap(range.start, range.end, prot);
+       if (ret != -ENOMEM)
                goto unlock;
 
        /*
-        * host_s2_mem has been provided with enough pages to cover all of
-        * memory with page granularity, so we should never hit the ENOMEM case.
-        * However, it is difficult to know how much of the MMIO range we will
-        * need to cover upfront, so we may need to 'recycle' the pages if we
-        * run out.
+        * The pool has been provided with enough pages to cover all of memory
+        * with page granularity, but it is difficult to know how much of the
+        * MMIO range we will need to cover upfront, so we may need to 'recycle'
+        * the pages if we run out.
         */
        ret = host_stage2_unmap_dev_all();
        if (ret)
                goto unlock;
 
-       ret = __host_stage2_idmap(range.start, range.end, prot, pool);
+       ret = __host_stage2_idmap(range.start, range.end, prot);
 
 unlock:
        hyp_spin_unlock(&host_kvm.lock);
@@ -258,7 +258,7 @@ int __pkvm_mark_hyp(phys_addr_t start, phys_addr_t end)
 
        hyp_spin_lock(&host_kvm.lock);
        ret = kvm_pgtable_stage2_set_owner(&host_kvm.pgt, start, end - start,
-                                          &host_s2_mem, pkvm_hyp_id);
+                                          &host_s2_pool, pkvm_hyp_id);
        hyp_spin_unlock(&host_kvm.lock);
 
        return ret != -EAGAIN ? ret : 0;
index 237e03b..41fc25b 100644 (file)
@@ -32,7 +32,7 @@ u64 __hyp_vmemmap;
  */
 static struct hyp_page *__find_buddy_nocheck(struct hyp_pool *pool,
                                             struct hyp_page *p,
-                                            unsigned int order)
+                                            unsigned short order)
 {
        phys_addr_t addr = hyp_page_to_phys(p);
 
@@ -51,21 +51,49 @@ static struct hyp_page *__find_buddy_nocheck(struct hyp_pool *pool,
 /* Find a buddy page currently available for allocation */
 static struct hyp_page *__find_buddy_avail(struct hyp_pool *pool,
                                           struct hyp_page *p,
-                                          unsigned int order)
+                                          unsigned short order)
 {
        struct hyp_page *buddy = __find_buddy_nocheck(pool, p, order);
 
-       if (!buddy || buddy->order != order || list_empty(&buddy->node))
+       if (!buddy || buddy->order != order || buddy->refcount)
                return NULL;
 
        return buddy;
 
 }
 
+/*
+ * Pages that are available for allocation are tracked in free-lists, so we use
+ * the pages themselves to store the list nodes to avoid wasting space. As the
+ * allocator always returns zeroed pages (which are zeroed on the hyp_put_page()
+ * path to optimize allocation speed), we also need to clean-up the list node in
+ * each page when we take it out of the list.
+ */
+static inline void page_remove_from_list(struct hyp_page *p)
+{
+       struct list_head *node = hyp_page_to_virt(p);
+
+       __list_del_entry(node);
+       memset(node, 0, sizeof(*node));
+}
+
+static inline void page_add_to_list(struct hyp_page *p, struct list_head *head)
+{
+       struct list_head *node = hyp_page_to_virt(p);
+
+       INIT_LIST_HEAD(node);
+       list_add_tail(node, head);
+}
+
+static inline struct hyp_page *node_to_page(struct list_head *node)
+{
+       return hyp_virt_to_page(node);
+}
+
 static void __hyp_attach_page(struct hyp_pool *pool,
                              struct hyp_page *p)
 {
-       unsigned int order = p->order;
+       unsigned short order = p->order;
        struct hyp_page *buddy;
 
        memset(hyp_page_to_virt(p), 0, PAGE_SIZE << p->order);
@@ -83,32 +111,23 @@ static void __hyp_attach_page(struct hyp_pool *pool,
                        break;
 
                /* Take the buddy out of its list, and coallesce with @p */
-               list_del_init(&buddy->node);
+               page_remove_from_list(buddy);
                buddy->order = HYP_NO_ORDER;
                p = min(p, buddy);
        }
 
        /* Mark the new head, and insert it */
        p->order = order;
-       list_add_tail(&p->node, &pool->free_area[order]);
-}
-
-static void hyp_attach_page(struct hyp_page *p)
-{
-       struct hyp_pool *pool = hyp_page_to_pool(p);
-
-       hyp_spin_lock(&pool->lock);
-       __hyp_attach_page(pool, p);
-       hyp_spin_unlock(&pool->lock);
+       page_add_to_list(p, &pool->free_area[order]);
 }
 
 static struct hyp_page *__hyp_extract_page(struct hyp_pool *pool,
                                           struct hyp_page *p,
-                                          unsigned int order)
+                                          unsigned short order)
 {
        struct hyp_page *buddy;
 
-       list_del_init(&p->node);
+       page_remove_from_list(p);
        while (p->order > order) {
                /*
                 * The buddy of order n - 1 currently has HYP_NO_ORDER as it
@@ -119,30 +138,64 @@ static struct hyp_page *__hyp_extract_page(struct hyp_pool *pool,
                p->order--;
                buddy = __find_buddy_nocheck(pool, p, p->order);
                buddy->order = p->order;
-               list_add_tail(&buddy->node, &pool->free_area[buddy->order]);
+               page_add_to_list(buddy, &pool->free_area[buddy->order]);
        }
 
        return p;
 }
 
-void hyp_put_page(void *addr)
+static inline void hyp_page_ref_inc(struct hyp_page *p)
 {
-       struct hyp_page *p = hyp_virt_to_page(addr);
+       BUG_ON(p->refcount == USHRT_MAX);
+       p->refcount++;
+}
 
+static inline int hyp_page_ref_dec_and_test(struct hyp_page *p)
+{
+       p->refcount--;
+       return (p->refcount == 0);
+}
+
+static inline void hyp_set_page_refcounted(struct hyp_page *p)
+{
+       BUG_ON(p->refcount);
+       p->refcount = 1;
+}
+
+static void __hyp_put_page(struct hyp_pool *pool, struct hyp_page *p)
+{
        if (hyp_page_ref_dec_and_test(p))
-               hyp_attach_page(p);
+               __hyp_attach_page(pool, p);
+}
+
+/*
+ * Changes to the buddy tree and page refcounts must be done with the hyp_pool
+ * lock held. If a refcount change requires an update to the buddy tree (e.g.
+ * hyp_put_page()), both operations must be done within the same critical
+ * section to guarantee transient states (e.g. a page with null refcount but
+ * not yet attached to a free list) can't be observed by well-behaved readers.
+ */
+void hyp_put_page(struct hyp_pool *pool, void *addr)
+{
+       struct hyp_page *p = hyp_virt_to_page(addr);
+
+       hyp_spin_lock(&pool->lock);
+       __hyp_put_page(pool, p);
+       hyp_spin_unlock(&pool->lock);
 }
 
-void hyp_get_page(void *addr)
+void hyp_get_page(struct hyp_pool *pool, void *addr)
 {
        struct hyp_page *p = hyp_virt_to_page(addr);
 
+       hyp_spin_lock(&pool->lock);
        hyp_page_ref_inc(p);
+       hyp_spin_unlock(&pool->lock);
 }
 
-void *hyp_alloc_pages(struct hyp_pool *pool, unsigned int order)
+void *hyp_alloc_pages(struct hyp_pool *pool, unsigned short order)
 {
-       unsigned int i = order;
+       unsigned short i = order;
        struct hyp_page *p;
 
        hyp_spin_lock(&pool->lock);
@@ -156,11 +209,11 @@ void *hyp_alloc_pages(struct hyp_pool *pool, unsigned int order)
        }
 
        /* Extract it from the tree at the right order */
-       p = list_first_entry(&pool->free_area[i], struct hyp_page, node);
+       p = node_to_page(pool->free_area[i].next);
        p = __hyp_extract_page(pool, p, order);
 
-       hyp_spin_unlock(&pool->lock);
        hyp_set_page_refcounted(p);
+       hyp_spin_unlock(&pool->lock);
 
        return hyp_page_to_virt(p);
 }
@@ -181,15 +234,14 @@ int hyp_pool_init(struct hyp_pool *pool, u64 pfn, unsigned int nr_pages,
 
        /* Init the vmemmap portion */
        p = hyp_phys_to_page(phys);
-       memset(p, 0, sizeof(*p) * nr_pages);
        for (i = 0; i < nr_pages; i++) {
-               p[i].pool = pool;
-               INIT_LIST_HEAD(&p[i].node);
+               p[i].order = 0;
+               hyp_set_page_refcounted(&p[i]);
        }
 
        /* Attach the unused pages to the buddy tree */
        for (i = reserved_pages; i < nr_pages; i++)
-               __hyp_attach_page(pool, &p[i]);
+               __hyp_put_page(pool, &p[i]);
 
        return 0;
 }
index a3d3a27..0b574d1 100644 (file)
@@ -24,8 +24,7 @@ unsigned long hyp_nr_cpus;
 
 static void *vmemmap_base;
 static void *hyp_pgt_base;
-static void *host_s2_mem_pgt_base;
-static void *host_s2_dev_pgt_base;
+static void *host_s2_pgt_base;
 static struct kvm_pgtable_mm_ops pkvm_pgtable_mm_ops;
 
 static int divide_memory_pool(void *virt, unsigned long size)
@@ -45,14 +44,9 @@ static int divide_memory_pool(void *virt, unsigned long size)
        if (!hyp_pgt_base)
                return -ENOMEM;
 
-       nr_pages = host_s2_mem_pgtable_pages();
-       host_s2_mem_pgt_base = hyp_early_alloc_contig(nr_pages);
-       if (!host_s2_mem_pgt_base)
-               return -ENOMEM;
-
-       nr_pages = host_s2_dev_pgtable_pages();
-       host_s2_dev_pgt_base = hyp_early_alloc_contig(nr_pages);
-       if (!host_s2_dev_pgt_base)
+       nr_pages = host_s2_pgtable_pages();
+       host_s2_pgt_base = hyp_early_alloc_contig(nr_pages);
+       if (!host_s2_pgt_base)
                return -ENOMEM;
 
        return 0;
@@ -134,7 +128,8 @@ static void update_nvhe_init_params(void)
        for (i = 0; i < hyp_nr_cpus; i++) {
                params = per_cpu_ptr(&kvm_init_params, i);
                params->pgd_pa = __hyp_pa(pkvm_pgtable.pgd);
-               __flush_dcache_area(params, sizeof(*params));
+               dcache_clean_inval_poc((unsigned long)params,
+                                   (unsigned long)params + sizeof(*params));
        }
 }
 
@@ -143,6 +138,16 @@ static void *hyp_zalloc_hyp_page(void *arg)
        return hyp_alloc_pages(&hpool, 0);
 }
 
+static void hpool_get_page(void *addr)
+{
+       hyp_get_page(&hpool, addr);
+}
+
+static void hpool_put_page(void *addr)
+{
+       hyp_put_page(&hpool, addr);
+}
+
 void __noreturn __pkvm_init_finalise(void)
 {
        struct kvm_host_data *host_data = this_cpu_ptr(&kvm_host_data);
@@ -158,7 +163,7 @@ void __noreturn __pkvm_init_finalise(void)
        if (ret)
                goto out;
 
-       ret = kvm_host_prepare_stage2(host_s2_mem_pgt_base, host_s2_dev_pgt_base);
+       ret = kvm_host_prepare_stage2(host_s2_pgt_base);
        if (ret)
                goto out;
 
@@ -166,8 +171,8 @@ void __noreturn __pkvm_init_finalise(void)
                .zalloc_page = hyp_zalloc_hyp_page,
                .phys_to_virt = hyp_phys_to_virt,
                .virt_to_phys = hyp_virt_to_phys,
-               .get_page = hyp_get_page,
-               .put_page = hyp_put_page,
+               .get_page = hpool_get_page,
+               .put_page = hpool_put_page,
        };
        pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops;
 
index 83dc3b2..38ed0f6 100644 (file)
@@ -104,7 +104,7 @@ void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,
         * you should be running with VHE enabled.
         */
        if (icache_is_vpipt())
-               __flush_icache_all();
+               icache_inval_all_pou();
 
        __tlb_switch_to_host(&cxt);
 }
index c37c1dc..05321f4 100644 (file)
@@ -577,12 +577,24 @@ static void stage2_put_pte(kvm_pte_t *ptep, struct kvm_s2_mmu *mmu, u64 addr,
        mm_ops->put_page(ptep);
 }
 
+static bool stage2_pte_cacheable(struct kvm_pgtable *pgt, kvm_pte_t pte)
+{
+       u64 memattr = pte & KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR;
+       return memattr == KVM_S2_MEMATTR(pgt, NORMAL);
+}
+
+static bool stage2_pte_executable(kvm_pte_t pte)
+{
+       return !(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN);
+}
+
 static int stage2_map_walker_try_leaf(u64 addr, u64 end, u32 level,
                                      kvm_pte_t *ptep,
                                      struct stage2_map_data *data)
 {
        kvm_pte_t new, old = *ptep;
        u64 granule = kvm_granule_size(level), phys = data->phys;
+       struct kvm_pgtable *pgt = data->mmu->pgt;
        struct kvm_pgtable_mm_ops *mm_ops = data->mm_ops;
 
        if (!kvm_block_mapping_supported(addr, end, phys, level))
@@ -606,6 +618,14 @@ static int stage2_map_walker_try_leaf(u64 addr, u64 end, u32 level,
                stage2_put_pte(ptep, data->mmu, addr, level, mm_ops);
        }
 
+       /* Perform CMOs before installation of the guest stage-2 PTE */
+       if (mm_ops->dcache_clean_inval_poc && stage2_pte_cacheable(pgt, new))
+               mm_ops->dcache_clean_inval_poc(kvm_pte_follow(new, mm_ops),
+                                               granule);
+
+       if (mm_ops->icache_inval_pou && stage2_pte_executable(new))
+               mm_ops->icache_inval_pou(kvm_pte_follow(new, mm_ops), granule);
+
        smp_store_release(ptep, new);
        if (stage2_pte_is_counted(new))
                mm_ops->get_page(ptep);
@@ -798,12 +818,6 @@ int kvm_pgtable_stage2_set_owner(struct kvm_pgtable *pgt, u64 addr, u64 size,
        return ret;
 }
 
-static bool stage2_pte_cacheable(struct kvm_pgtable *pgt, kvm_pte_t pte)
-{
-       u64 memattr = pte & KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR;
-       return memattr == KVM_S2_MEMATTR(pgt, NORMAL);
-}
-
 static int stage2_unmap_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
                               enum kvm_pgtable_walk_flags flag,
                               void * const arg)
@@ -839,8 +853,11 @@ static int stage2_unmap_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
        stage2_put_pte(ptep, mmu, addr, level, mm_ops);
 
        if (need_flush) {
-               __flush_dcache_area(kvm_pte_follow(pte, mm_ops),
-                                   kvm_granule_size(level));
+               kvm_pte_t *pte_follow = kvm_pte_follow(pte, mm_ops);
+
+               dcache_clean_inval_poc((unsigned long)pte_follow,
+                                   (unsigned long)pte_follow +
+                                           kvm_granule_size(level));
        }
 
        if (childp)
@@ -861,10 +878,11 @@ int kvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
 }
 
 struct stage2_attr_data {
-       kvm_pte_t       attr_set;
-       kvm_pte_t       attr_clr;
-       kvm_pte_t       pte;
-       u32             level;
+       kvm_pte_t                       attr_set;
+       kvm_pte_t                       attr_clr;
+       kvm_pte_t                       pte;
+       u32                             level;
+       struct kvm_pgtable_mm_ops       *mm_ops;
 };
 
 static int stage2_attr_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
@@ -873,6 +891,7 @@ static int stage2_attr_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
 {
        kvm_pte_t pte = *ptep;
        struct stage2_attr_data *data = arg;
+       struct kvm_pgtable_mm_ops *mm_ops = data->mm_ops;
 
        if (!kvm_pte_valid(pte))
                return 0;
@@ -887,8 +906,17 @@ static int stage2_attr_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
         * but worst-case the access flag update gets lost and will be
         * set on the next access instead.
         */
-       if (data->pte != pte)
+       if (data->pte != pte) {
+               /*
+                * Invalidate instruction cache before updating the guest
+                * stage-2 PTE if we are going to add executable permission.
+                */
+               if (mm_ops->icache_inval_pou &&
+                   stage2_pte_executable(pte) && !stage2_pte_executable(*ptep))
+                       mm_ops->icache_inval_pou(kvm_pte_follow(pte, mm_ops),
+                                                 kvm_granule_size(level));
                WRITE_ONCE(*ptep, pte);
+       }
 
        return 0;
 }
@@ -903,6 +931,7 @@ static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
        struct stage2_attr_data data = {
                .attr_set       = attr_set & attr_mask,
                .attr_clr       = attr_clr & attr_mask,
+               .mm_ops         = pgt->mm_ops,
        };
        struct kvm_pgtable_walker walker = {
                .cb             = stage2_attr_walker,
@@ -988,11 +1017,15 @@ static int stage2_flush_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
        struct kvm_pgtable *pgt = arg;
        struct kvm_pgtable_mm_ops *mm_ops = pgt->mm_ops;
        kvm_pte_t pte = *ptep;
+       kvm_pte_t *pte_follow;
 
        if (!kvm_pte_valid(pte) || !stage2_pte_cacheable(pgt, pte))
                return 0;
 
-       __flush_dcache_area(kvm_pte_follow(pte, mm_ops), kvm_granule_size(level));
+       pte_follow = kvm_pte_follow(pte, mm_ops);
+       dcache_clean_inval_poc((unsigned long)pte_follow,
+                           (unsigned long)pte_follow +
+                                   kvm_granule_size(level));
        return 0;
 }
 
index 83ca23a..d654921 100644 (file)
@@ -71,8 +71,7 @@ void __init kvm_hyp_reserve(void)
        }
 
        hyp_mem_pages += hyp_s1_pgtable_pages();
-       hyp_mem_pages += host_s2_mem_pgtable_pages();
-       hyp_mem_pages += host_s2_dev_pgtable_pages();
+       hyp_mem_pages += host_s2_pgtable_pages();
 
        /*
         * The hyp_vmemmap needs to be backed by pages, but these pages
index c10207f..57292dc 100644 (file)
@@ -126,6 +126,16 @@ static void *kvm_host_va(phys_addr_t phys)
        return __va(phys);
 }
 
+static void clean_dcache_guest_page(void *va, size_t size)
+{
+       __clean_dcache_guest_page(va, size);
+}
+
+static void invalidate_icache_guest_page(void *va, size_t size)
+{
+       __invalidate_icache_guest_page(va, size);
+}
+
 /*
  * Unmapping vs dcache management:
  *
@@ -432,6 +442,8 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops = {
        .page_count             = kvm_host_page_count,
        .phys_to_virt           = kvm_host_va,
        .virt_to_phys           = kvm_host_pa,
+       .dcache_clean_inval_poc = clean_dcache_guest_page,
+       .icache_inval_pou       = invalidate_icache_guest_page,
 };
 
 /**
@@ -693,16 +705,6 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
        kvm_mmu_write_protect_pt_masked(kvm, slot, gfn_offset, mask);
 }
 
-static void clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
-{
-       __clean_dcache_guest_page(pfn, size);
-}
-
-static void invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size)
-{
-       __invalidate_icache_guest_page(pfn, size);
-}
-
 static void kvm_send_hwpoison_signal(unsigned long address, short lsb)
 {
        send_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, current);
@@ -822,6 +824,74 @@ transparent_hugepage_adjust(struct kvm_memory_slot *memslot,
        return PAGE_SIZE;
 }
 
+static int get_vma_page_shift(struct vm_area_struct *vma, unsigned long hva)
+{
+       unsigned long pa;
+
+       if (is_vm_hugetlb_page(vma) && !(vma->vm_flags & VM_PFNMAP))
+               return huge_page_shift(hstate_vma(vma));
+
+       if (!(vma->vm_flags & VM_PFNMAP))
+               return PAGE_SHIFT;
+
+       VM_BUG_ON(is_vm_hugetlb_page(vma));
+
+       pa = (vma->vm_pgoff << PAGE_SHIFT) + (hva - vma->vm_start);
+
+#ifndef __PAGETABLE_PMD_FOLDED
+       if ((hva & (PUD_SIZE - 1)) == (pa & (PUD_SIZE - 1)) &&
+           ALIGN_DOWN(hva, PUD_SIZE) >= vma->vm_start &&
+           ALIGN(hva, PUD_SIZE) <= vma->vm_end)
+               return PUD_SHIFT;
+#endif
+
+       if ((hva & (PMD_SIZE - 1)) == (pa & (PMD_SIZE - 1)) &&
+           ALIGN_DOWN(hva, PMD_SIZE) >= vma->vm_start &&
+           ALIGN(hva, PMD_SIZE) <= vma->vm_end)
+               return PMD_SHIFT;
+
+       return PAGE_SHIFT;
+}
+
+/*
+ * The page will be mapped in stage 2 as Normal Cacheable, so the VM will be
+ * able to see the page's tags and therefore they must be initialised first. If
+ * PG_mte_tagged is set, tags have already been initialised.
+ *
+ * The race in the test/set of the PG_mte_tagged flag is handled by:
+ * - preventing VM_SHARED mappings in a memslot with MTE preventing two VMs
+ *   racing to santise the same page
+ * - mmap_lock protects between a VM faulting a page in and the VMM performing
+ *   an mprotect() to add VM_MTE
+ */
+static int sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn,
+                            unsigned long size)
+{
+       unsigned long i, nr_pages = size >> PAGE_SHIFT;
+       struct page *page;
+
+       if (!kvm_has_mte(kvm))
+               return 0;
+
+       /*
+        * pfn_to_online_page() is used to reject ZONE_DEVICE pages
+        * that may not support tags.
+        */
+       page = pfn_to_online_page(pfn);
+
+       if (!page)
+               return -EFAULT;
+
+       for (i = 0; i < nr_pages; i++, page++) {
+               if (!test_bit(PG_mte_tagged, &page->flags)) {
+                       mte_clear_page_tags(page_address(page));
+                       set_bit(PG_mte_tagged, &page->flags);
+               }
+       }
+
+       return 0;
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                          struct kvm_memory_slot *memslot, unsigned long hva,
                          unsigned long fault_status)
@@ -830,6 +900,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        bool write_fault, writable, force_pte = false;
        bool exec_fault;
        bool device = false;
+       bool shared;
        unsigned long mmu_seq;
        struct kvm *kvm = vcpu->kvm;
        struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
@@ -853,7 +924,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                return -EFAULT;
        }
 
-       /* Let's check if we will get back a huge page backed by hugetlbfs */
+       /*
+        * Let's check if we will get back a huge page backed by hugetlbfs, or
+        * get block mapping for device MMIO region.
+        */
        mmap_read_lock(current->mm);
        vma = find_vma_intersection(current->mm, hva, hva + 1);
        if (unlikely(!vma)) {
@@ -862,17 +936,19 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                return -EFAULT;
        }
 
-       if (is_vm_hugetlb_page(vma))
-               vma_shift = huge_page_shift(hstate_vma(vma));
-       else
-               vma_shift = PAGE_SHIFT;
-
-       if (logging_active ||
-           (vma->vm_flags & VM_PFNMAP)) {
+       /*
+        * logging_active is guaranteed to never be true for VM_PFNMAP
+        * memslots.
+        */
+       if (logging_active) {
                force_pte = true;
                vma_shift = PAGE_SHIFT;
+       } else {
+               vma_shift = get_vma_page_shift(vma, hva);
        }
 
+       shared = (vma->vm_flags & VM_PFNMAP);
+
        switch (vma_shift) {
 #ifndef __PAGETABLE_PMD_FOLDED
        case PUD_SHIFT:
@@ -943,8 +1019,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                return -EFAULT;
 
        if (kvm_is_device_pfn(pfn)) {
+               /*
+                * If the page was identified as device early by looking at
+                * the VMA flags, vma_pagesize is already representing the
+                * largest quantity we can map.  If instead it was mapped
+                * via gfn_to_pfn_prot(), vma_pagesize is set to PAGE_SIZE
+                * and must not be upgraded.
+                *
+                * In both cases, we don't let transparent_hugepage_adjust()
+                * change things at the last minute.
+                */
                device = true;
-               force_pte = true;
        } else if (logging_active && !write_fault) {
                /*
                 * Only actually map the page as writable if this was a write
@@ -965,19 +1050,25 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
         * If we are not forced to use page mapping, check if we are
         * backed by a THP and thus use block mapping if possible.
         */
-       if (vma_pagesize == PAGE_SIZE && !force_pte)
+       if (vma_pagesize == PAGE_SIZE && !(force_pte || device))
                vma_pagesize = transparent_hugepage_adjust(memslot, hva,
                                                           &pfn, &fault_ipa);
+
+       if (fault_status != FSC_PERM && !device && kvm_has_mte(kvm)) {
+               /* Check the VMM hasn't introduced a new VM_SHARED VMA */
+               if (!shared)
+                       ret = sanitise_mte_tags(kvm, pfn, vma_pagesize);
+               else
+                       ret = -EFAULT;
+               if (ret)
+                       goto out_unlock;
+       }
+
        if (writable)
                prot |= KVM_PGTABLE_PROT_W;
 
-       if (fault_status != FSC_PERM && !device)
-               clean_dcache_guest_page(pfn, vma_pagesize);
-
-       if (exec_fault) {
+       if (exec_fault)
                prot |= KVM_PGTABLE_PROT_X;
-               invalidate_icache_guest_page(pfn, vma_pagesize);
-       }
 
        if (device)
                prot |= KVM_PGTABLE_PROT_DEVICE;
@@ -1168,19 +1259,22 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
 bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 {
        kvm_pfn_t pfn = pte_pfn(range->pte);
+       int ret;
 
        if (!kvm->arch.mmu.pgt)
                return false;
 
        WARN_ON(range->end - range->start != 1);
 
-       /*
-        * We've moved a page around, probably through CoW, so let's treat it
-        * just like a translation fault and clean the cache to the PoC.
-        */
-       clean_dcache_guest_page(pfn, PAGE_SIZE);
+       ret = sanitise_mte_tags(kvm, pfn, PAGE_SIZE);
+       if (ret)
+               return false;
 
        /*
+        * We've moved a page around, probably through CoW, so let's treat
+        * it just like a translation fault and the map handler will clean
+        * the cache to the PoC.
+        *
         * The MMU notifiers will have unmapped a huge PMD before calling
         * ->change_pte() (which in turn calls kvm_set_spte_gfn()) and
         * therefore we never need to clear out a huge PMD through this
@@ -1346,7 +1440,6 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 {
        hva_t hva = mem->userspace_addr;
        hva_t reg_end = hva + mem->memory_size;
-       bool writable = !(mem->flags & KVM_MEM_READONLY);
        int ret = 0;
 
        if (change != KVM_MR_CREATE && change != KVM_MR_MOVE &&
@@ -1363,8 +1456,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
        mmap_read_lock(current->mm);
        /*
         * A memory region could potentially cover multiple VMAs, and any holes
-        * between them, so iterate over all of them to find out if we can map
-        * any of them right now.
+        * between them, so iterate over all of them.
         *
         *     +--------------------------------------------+
         * +---------------+----------------+   +----------------+
@@ -1375,51 +1467,29 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
         */
        do {
                struct vm_area_struct *vma;
-               hva_t vm_start, vm_end;
 
                vma = find_vma_intersection(current->mm, hva, reg_end);
                if (!vma)
                        break;
 
                /*
-                * Take the intersection of this VMA with the memory region
+                * VM_SHARED mappings are not allowed with MTE to avoid races
+                * when updating the PG_mte_tagged page flag, see
+                * sanitise_mte_tags for more details.
                 */
-               vm_start = max(hva, vma->vm_start);
-               vm_end = min(reg_end, vma->vm_end);
+               if (kvm_has_mte(kvm) && vma->vm_flags & VM_SHARED)
+                       return -EINVAL;
 
                if (vma->vm_flags & VM_PFNMAP) {
-                       gpa_t gpa = mem->guest_phys_addr +
-                                   (vm_start - mem->userspace_addr);
-                       phys_addr_t pa;
-
-                       pa = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
-                       pa += vm_start - vma->vm_start;
-
                        /* IO region dirty page logging not allowed */
                        if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES) {
                                ret = -EINVAL;
-                               goto out;
-                       }
-
-                       ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
-                                                   vm_end - vm_start,
-                                                   writable);
-                       if (ret)
                                break;
+                       }
                }
-               hva = vm_end;
+               hva = min(reg_end, vma->vm_end);
        } while (hva < reg_end);
 
-       if (change == KVM_MR_FLAGS_ONLY)
-               goto out;
-
-       spin_lock(&kvm->mmu_lock);
-       if (ret)
-               unmap_stage2_range(&kvm->arch.mmu, mem->guest_phys_addr, mem->memory_size);
-       else if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
-               stage2_flush_memslot(kvm, memslot);
-       spin_unlock(&kvm->mmu_lock);
-out:
        mmap_read_unlock(current->mm);
        return ret;
 }
index fd167d4..f33825c 100644 (file)
@@ -578,6 +578,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
                kvm_pmu_set_counter_value(vcpu, ARMV8_PMU_CYCLE_IDX, 0);
 
        if (val & ARMV8_PMU_PMCR_P) {
+               mask &= ~BIT(ARMV8_PMU_CYCLE_IDX);
                for_each_set_bit(i, &mask, 32)
                        kvm_pmu_set_counter_value(vcpu, i, 0);
        }
@@ -850,6 +851,9 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
                   return -EINVAL;
        }
 
+       /* One-off reload of the PMU on first run */
+       kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu);
+
        return 0;
 }
 
index d37ebee..cba7872 100644 (file)
@@ -176,6 +176,10 @@ static bool vcpu_allowed_register_width(struct kvm_vcpu *vcpu)
        if (!cpus_have_const_cap(ARM64_HAS_32BIT_EL1) && is32bit)
                return false;
 
+       /* MTE is incompatible with AArch32 */
+       if (kvm_has_mte(vcpu->kvm) && is32bit)
+               return false;
+
        /* Check that the vcpus are either all 32bit or all 64bit */
        kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
                if (vcpu_has_feature(tmp, KVM_ARM_VCPU_EL1_32BIT) != is32bit)
index 1a7968a..f6f126e 100644 (file)
@@ -1047,6 +1047,13 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                break;
        case SYS_ID_AA64PFR1_EL1:
                val &= ~FEATURE(ID_AA64PFR1_MTE);
+               if (kvm_has_mte(vcpu->kvm)) {
+                       u64 pfr, mte;
+
+                       pfr = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
+                       mte = cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR1_MTE_SHIFT);
+                       val |= FIELD_PREP(FEATURE(ID_AA64PFR1_MTE), mte);
+               }
                break;
        case SYS_ID_AA64ISAR1_EL1:
                if (!vcpu_has_ptrauth(vcpu))
@@ -1302,6 +1309,23 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        return true;
 }
 
+static unsigned int mte_visibility(const struct kvm_vcpu *vcpu,
+                                  const struct sys_reg_desc *rd)
+{
+       if (kvm_has_mte(vcpu->kvm))
+               return 0;
+
+       return REG_HIDDEN;
+}
+
+#define MTE_REG(name) {                                \
+       SYS_DESC(SYS_##name),                   \
+       .access = undef_access,                 \
+       .reset = reset_unknown,                 \
+       .reg = name,                            \
+       .visibility = mte_visibility,           \
+}
+
 /* sys_reg_desc initialiser for known cpufeature ID registers */
 #define ID_SANITISED(name) {                   \
        SYS_DESC(SYS_##name),                   \
@@ -1470,8 +1494,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 },
        { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
 
-       { SYS_DESC(SYS_RGSR_EL1), undef_access },
-       { SYS_DESC(SYS_GCR_EL1), undef_access },
+       MTE_REG(RGSR_EL1),
+       MTE_REG(GCR_EL1),
 
        { SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
        { SYS_DESC(SYS_TRFCR_EL1), undef_access },
@@ -1498,8 +1522,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi },
        { SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi },
 
-       { SYS_DESC(SYS_TFSR_EL1), undef_access },
-       { SYS_DESC(SYS_TFSRE0_EL1), undef_access },
+       MTE_REG(TFSR_EL1),
+       MTE_REG(TFSRE0_EL1),
 
        { SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
        { SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
index 58cbda0..340c51d 100644 (file)
@@ -482,6 +482,16 @@ static irqreturn_t vgic_maintenance_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+static struct gic_kvm_info *gic_kvm_info;
+
+void __init vgic_set_kvm_info(const struct gic_kvm_info *info)
+{
+       BUG_ON(gic_kvm_info != NULL);
+       gic_kvm_info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (gic_kvm_info)
+               *gic_kvm_info = *info;
+}
+
 /**
  * kvm_vgic_init_cpu_hardware - initialize the GIC VE hardware
  *
@@ -509,18 +519,29 @@ void kvm_vgic_init_cpu_hardware(void)
  */
 int kvm_vgic_hyp_init(void)
 {
-       const struct gic_kvm_info *gic_kvm_info;
+       bool has_mask;
        int ret;
 
-       gic_kvm_info = gic_get_kvm_info();
        if (!gic_kvm_info)
                return -ENODEV;
 
-       if (!gic_kvm_info->maint_irq) {
+       has_mask = !gic_kvm_info->no_maint_irq_mask;
+
+       if (has_mask && !gic_kvm_info->maint_irq) {
                kvm_err("No vgic maintenance irq\n");
                return -ENXIO;
        }
 
+       /*
+        * If we get one of these oddball non-GICs, taint the kernel,
+        * as we have no idea of how they *really* behave.
+        */
+       if (gic_kvm_info->no_hw_deactivation) {
+               kvm_info("Non-architectural vgic, tainting kernel\n");
+               add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+               kvm_vgic_global_state.no_hw_deactivation = true;
+       }
+
        switch (gic_kvm_info->type) {
        case GIC_V2:
                ret = vgic_v2_probe(gic_kvm_info);
@@ -536,10 +557,17 @@ int kvm_vgic_hyp_init(void)
                ret = -ENODEV;
        }
 
+       kvm_vgic_global_state.maint_irq = gic_kvm_info->maint_irq;
+
+       kfree(gic_kvm_info);
+       gic_kvm_info = NULL;
+
        if (ret)
                return ret;
 
-       kvm_vgic_global_state.maint_irq = gic_kvm_info->maint_irq;
+       if (!has_mask)
+               return 0;
+
        ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
                                 vgic_maintenance_handler,
                                 "vgic", kvm_get_running_vcpus());
index 11934c2..2c58020 100644 (file)
@@ -108,11 +108,22 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
                 * If this causes us to lower the level, we have to also clear
                 * the physical active state, since we will otherwise never be
                 * told when the interrupt becomes asserted again.
+                *
+                * Another case is when the interrupt requires a helping hand
+                * on deactivation (no HW deactivation, for example).
                 */
-               if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
-                       irq->line_level = vgic_get_phys_line_level(irq);
+               if (vgic_irq_is_mapped_level(irq)) {
+                       bool resample = false;
+
+                       if (val & GICH_LR_PENDING_BIT) {
+                               irq->line_level = vgic_get_phys_line_level(irq);
+                               resample = !irq->line_level;
+                       } else if (vgic_irq_needs_resampling(irq) &&
+                                  !(irq->active || irq->pending_latch)) {
+                               resample = true;
+                       }
 
-                       if (!irq->line_level)
+                       if (resample)
                                vgic_irq_set_phys_active(irq, false);
                }
 
@@ -152,7 +163,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
        if (irq->group)
                val |= GICH_LR_GROUP1;
 
-       if (irq->hw) {
+       if (irq->hw && !vgic_irq_needs_resampling(irq)) {
                val |= GICH_LR_HW;
                val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
                /*
index 41ecf21..66004f6 100644 (file)
@@ -101,11 +101,22 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
                 * If this causes us to lower the level, we have to also clear
                 * the physical active state, since we will otherwise never be
                 * told when the interrupt becomes asserted again.
+                *
+                * Another case is when the interrupt requires a helping hand
+                * on deactivation (no HW deactivation, for example).
                 */
-               if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
-                       irq->line_level = vgic_get_phys_line_level(irq);
+               if (vgic_irq_is_mapped_level(irq)) {
+                       bool resample = false;
+
+                       if (val & ICH_LR_PENDING_BIT) {
+                               irq->line_level = vgic_get_phys_line_level(irq);
+                               resample = !irq->line_level;
+                       } else if (vgic_irq_needs_resampling(irq) &&
+                                  !(irq->active || irq->pending_latch)) {
+                               resample = true;
+                       }
 
-                       if (!irq->line_level)
+                       if (resample)
                                vgic_irq_set_phys_active(irq, false);
                }
 
@@ -136,7 +147,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
                }
        }
 
-       if (irq->hw) {
+       if (irq->hw && !vgic_irq_needs_resampling(irq)) {
                val |= ICH_LR_HW;
                val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
                /*
index 15b6662..111bff4 100644 (file)
@@ -182,8 +182,8 @@ bool vgic_get_phys_line_level(struct vgic_irq *irq)
 
        BUG_ON(!irq->hw);
 
-       if (irq->get_input_level)
-               return irq->get_input_level(irq->intid);
+       if (irq->ops && irq->ops->get_input_level)
+               return irq->ops->get_input_level(irq->intid);
 
        WARN_ON(irq_get_irqchip_state(irq->host_irq,
                                      IRQCHIP_STATE_PENDING,
@@ -480,7 +480,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 /* @irq->irq_lock must be held */
 static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
                            unsigned int host_irq,
-                           bool (*get_input_level)(int vindid))
+                           struct irq_ops *ops)
 {
        struct irq_desc *desc;
        struct irq_data *data;
@@ -500,7 +500,7 @@ static int kvm_vgic_map_irq(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
        irq->hw = true;
        irq->host_irq = host_irq;
        irq->hwintid = data->hwirq;
-       irq->get_input_level = get_input_level;
+       irq->ops = ops;
        return 0;
 }
 
@@ -509,11 +509,11 @@ static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq)
 {
        irq->hw = false;
        irq->hwintid = 0;
-       irq->get_input_level = NULL;
+       irq->ops = NULL;
 }
 
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-                         u32 vintid, bool (*get_input_level)(int vindid))
+                         u32 vintid, struct irq_ops *ops)
 {
        struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
        unsigned long flags;
@@ -522,7 +522,7 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
        BUG_ON(!irq);
 
        raw_spin_lock_irqsave(&irq->irq_lock, flags);
-       ret = kvm_vgic_map_irq(vcpu, irq, host_irq, get_input_level);
+       ret = kvm_vgic_map_irq(vcpu, irq, host_irq, ops);
        raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
        vgic_put_irq(vcpu->kvm, irq);
 
index d31e116..6dd56a4 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 lib-y          := clear_user.o delay.o copy_from_user.o                \
                   copy_to_user.o copy_in_user.o copy_page.o            \
-                  clear_page.o csum.o memchr.o memcpy.o memmove.o      \
+                  clear_page.o csum.o insn.o memchr.o memcpy.o         \
                   memset.o memcmp.o strcmp.o strncmp.o strlen.o        \
                   strnlen.o strchr.o strrchr.o tishift.o
 
@@ -18,3 +18,5 @@ obj-$(CONFIG_CRC32) += crc32.o
 obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
 
 obj-$(CONFIG_ARM64_MTE) += mte.o
+
+obj-$(CONFIG_KASAN_SW_TAGS) += kasan_sw_tags.o
index af9afcb..a7efb2a 100644 (file)
@@ -1,12 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Based on arch/arm/lib/clear_user.S
- *
- * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2021 Arm Ltd.
  */
-#include <linux/linkage.h>
 
-#include <asm/asm-uaccess.h>
+#include <linux/linkage.h>
 #include <asm/assembler.h>
 
        .text
  *
  * Alignment fixed up by hardware.
  */
+
+       .p2align 4
+       // Alignment is for the loop, but since the prologue (including BTI)
+       // is also 16 bytes we can keep any padding outside the function
 SYM_FUNC_START(__arch_clear_user)
-       mov     x2, x1                  // save the size for fixup return
+       add     x2, x0, x1
        subs    x1, x1, #8
        b.mi    2f
 1:
-user_ldst 9f, sttr, xzr, x0, 8
+USER(9f, sttr  xzr, [x0])
+       add     x0, x0, #8
        subs    x1, x1, #8
-       b.pl    1b
-2:     adds    x1, x1, #4
-       b.mi    3f
-user_ldst 9f, sttr, wzr, x0, 4
-       sub     x1, x1, #4
-3:     adds    x1, x1, #2
-       b.mi    4f
-user_ldst 9f, sttrh, wzr, x0, 2
-       sub     x1, x1, #2
-4:     adds    x1, x1, #1
-       b.mi    5f
-user_ldst 9f, sttrb, wzr, x0, 0
+       b.hi    1b
+USER(9f, sttr  xzr, [x2, #-8])
+       mov     x0, #0
+       ret
+
+2:     tbz     x1, #2, 3f
+USER(9f, sttr  wzr, [x0])
+USER(8f, sttr  wzr, [x2, #-4])
+       mov     x0, #0
+       ret
+
+3:     tbz     x1, #1, 4f
+USER(9f, sttrh wzr, [x0])
+4:     tbz     x1, #0, 5f
+USER(7f, sttrb wzr, [x2, #-1])
 5:     mov     x0, #0
        ret
 SYM_FUNC_END(__arch_clear_user)
@@ -45,6 +50,8 @@ EXPORT_SYMBOL(__arch_clear_user)
 
        .section .fixup,"ax"
        .align  2
-9:     mov     x0, x2                  // return the original size
+7:     sub     x0, x2, #5      // Adjust for faulting on the final byte...
+8:     add     x0, x0, #4      // ...or the second word of the 4-7 byte case
+9:     sub     x0, x2, x0
        ret
        .previous
similarity index 86%
rename from arch/arm64/kernel/insn.c
rename to arch/arm64/lib/insn.c
index 6c0de2f..b506a4b 100644 (file)
@@ -7,21 +7,14 @@
  */
 #include <linux/bitops.h>
 #include <linux/bug.h>
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/stop_machine.h>
+#include <linux/printk.h>
+#include <linux/sizes.h>
 #include <linux/types.h>
-#include <linux/uaccess.h>
 
-#include <asm/cacheflush.h>
 #include <asm/debug-monitors.h>
-#include <asm/fixmap.h>
+#include <asm/errno.h>
 #include <asm/insn.h>
 #include <asm/kprobes.h>
-#include <asm/sections.h>
 
 #define AARCH64_INSN_SF_BIT    BIT(31)
 #define AARCH64_INSN_N_BIT     BIT(22)
@@ -30,7 +23,7 @@
 static const int aarch64_insn_encoding_class[] = {
        AARCH64_INSN_CLS_UNKNOWN,
        AARCH64_INSN_CLS_UNKNOWN,
-       AARCH64_INSN_CLS_UNKNOWN,
+       AARCH64_INSN_CLS_SVE,
        AARCH64_INSN_CLS_UNKNOWN,
        AARCH64_INSN_CLS_LDST,
        AARCH64_INSN_CLS_DP_REG,
@@ -83,81 +76,6 @@ bool aarch64_insn_is_branch_imm(u32 insn)
                aarch64_insn_is_bcond(insn));
 }
 
-static DEFINE_RAW_SPINLOCK(patch_lock);
-
-static bool is_exit_text(unsigned long addr)
-{
-       /* discarded with init text/data */
-       return system_state < SYSTEM_RUNNING &&
-               addr >= (unsigned long)__exittext_begin &&
-               addr < (unsigned long)__exittext_end;
-}
-
-static bool is_image_text(unsigned long addr)
-{
-       return core_kernel_text(addr) || is_exit_text(addr);
-}
-
-static void __kprobes *patch_map(void *addr, int fixmap)
-{
-       unsigned long uintaddr = (uintptr_t) addr;
-       bool image = is_image_text(uintaddr);
-       struct page *page;
-
-       if (image)
-               page = phys_to_page(__pa_symbol(addr));
-       else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
-               page = vmalloc_to_page(addr);
-       else
-               return addr;
-
-       BUG_ON(!page);
-       return (void *)set_fixmap_offset(fixmap, page_to_phys(page) +
-                       (uintaddr & ~PAGE_MASK));
-}
-
-static void __kprobes patch_unmap(int fixmap)
-{
-       clear_fixmap(fixmap);
-}
-/*
- * In ARMv8-A, A64 instructions have a fixed length of 32 bits and are always
- * little-endian.
- */
-int __kprobes aarch64_insn_read(void *addr, u32 *insnp)
-{
-       int ret;
-       __le32 val;
-
-       ret = copy_from_kernel_nofault(&val, addr, AARCH64_INSN_SIZE);
-       if (!ret)
-               *insnp = le32_to_cpu(val);
-
-       return ret;
-}
-
-static int __kprobes __aarch64_insn_write(void *addr, __le32 insn)
-{
-       void *waddr = addr;
-       unsigned long flags = 0;
-       int ret;
-
-       raw_spin_lock_irqsave(&patch_lock, flags);
-       waddr = patch_map(addr, FIX_TEXT_POKE0);
-
-       ret = copy_to_kernel_nofault(waddr, &insn, AARCH64_INSN_SIZE);
-
-       patch_unmap(FIX_TEXT_POKE0);
-       raw_spin_unlock_irqrestore(&patch_lock, flags);
-
-       return ret;
-}
-
-int __kprobes aarch64_insn_write(void *addr, u32 insn)
-{
-       return __aarch64_insn_write(addr, cpu_to_le32(insn));
-}
-
 bool __kprobes aarch64_insn_uses_literal(u32 insn)
 {
        /* ldr/ldrsw (literal), prfm */
@@ -187,67 +105,6 @@ bool __kprobes aarch64_insn_is_branch(u32 insn)
                aarch64_insn_is_bcond(insn);
 }
 
-int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn)
-{
-       u32 *tp = addr;
-       int ret;
-
-       /* A64 instructions must be word aligned */
-       if ((uintptr_t)tp & 0x3)
-               return -EINVAL;
-
-       ret = aarch64_insn_write(tp, insn);
-       if (ret == 0)
-               __flush_icache_range((uintptr_t)tp,
-                                    (uintptr_t)tp + AARCH64_INSN_SIZE);
-
-       return ret;
-}
-
-struct aarch64_insn_patch {
-       void            **text_addrs;
-       u32             *new_insns;
-       int             insn_cnt;
-       atomic_t        cpu_count;
-};
-
-static int __kprobes aarch64_insn_patch_text_cb(void *arg)
-{
-       int i, ret = 0;
-       struct aarch64_insn_patch *pp = arg;
-
-       /* The first CPU becomes master */
-       if (atomic_inc_return(&pp->cpu_count) == 1) {
-               for (i = 0; ret == 0 && i < pp->insn_cnt; i++)
-                       ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i],
-                                                            pp->new_insns[i]);
-               /* Notify other processors with an additional increment. */
-               atomic_inc(&pp->cpu_count);
-       } else {
-               while (atomic_read(&pp->cpu_count) <= num_online_cpus())
-                       cpu_relax();
-               isb();
-       }
-
-       return ret;
-}
-
-int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
-{
-       struct aarch64_insn_patch patch = {
-               .text_addrs = addrs,
-               .new_insns = insns,
-               .insn_cnt = cnt,
-               .cpu_count = ATOMIC_INIT(0),
-       };
-
-       if (cnt <= 0)
-               return -EINVAL;
-
-       return stop_machine_cpuslocked(aarch64_insn_patch_text_cb, &patch,
-                                      cpu_online_mask);
-}
-
 static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
                                                u32 *maskp, int *shiftp)
 {
@@ -1432,104 +1289,6 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn)
        return insn & CRM_MASK;
 }
 
-static bool __kprobes __check_eq(unsigned long pstate)
-{
-       return (pstate & PSR_Z_BIT) != 0;
-}
-
-static bool __kprobes __check_ne(unsigned long pstate)
-{
-       return (pstate & PSR_Z_BIT) == 0;
-}
-
-static bool __kprobes __check_cs(unsigned long pstate)
-{
-       return (pstate & PSR_C_BIT) != 0;
-}
-
-static bool __kprobes __check_cc(unsigned long pstate)
-{
-       return (pstate & PSR_C_BIT) == 0;
-}
-
-static bool __kprobes __check_mi(unsigned long pstate)
-{
-       return (pstate & PSR_N_BIT) != 0;
-}
-
-static bool __kprobes __check_pl(unsigned long pstate)
-{
-       return (pstate & PSR_N_BIT) == 0;
-}
-
-static bool __kprobes __check_vs(unsigned long pstate)
-{
-       return (pstate & PSR_V_BIT) != 0;
-}
-
-static bool __kprobes __check_vc(unsigned long pstate)
-{
-       return (pstate & PSR_V_BIT) == 0;
-}
-
-static bool __kprobes __check_hi(unsigned long pstate)
-{
-       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return (pstate & PSR_C_BIT) != 0;
-}
-
-static bool __kprobes __check_ls(unsigned long pstate)
-{
-       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
-       return (pstate & PSR_C_BIT) == 0;
-}
-
-static bool __kprobes __check_ge(unsigned long pstate)
-{
-       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
-       return (pstate & PSR_N_BIT) == 0;
-}
-
-static bool __kprobes __check_lt(unsigned long pstate)
-{
-       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
-       return (pstate & PSR_N_BIT) != 0;
-}
-
-static bool __kprobes __check_gt(unsigned long pstate)
-{
-       /*PSR_N_BIT ^= PSR_V_BIT */
-       unsigned long temp = pstate ^ (pstate << 3);
-
-       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
-       return (temp & PSR_N_BIT) == 0;
-}
-
-static bool __kprobes __check_le(unsigned long pstate)
-{
-       /*PSR_N_BIT ^= PSR_V_BIT */
-       unsigned long temp = pstate ^ (pstate << 3);
-
-       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
-       return (temp & PSR_N_BIT) != 0;
-}
-
-static bool __kprobes __check_al(unsigned long pstate)
-{
-       return true;
-}
-
-/*
- * Note that the ARMv8 ARM calls condition code 0b1111 "nv", but states that
- * it behaves identically to 0b1110 ("al").
- */
-pstate_check_t * const aarch32_opcode_cond_checks[16] = {
-       __check_eq, __check_ne, __check_cs, __check_cc,
-       __check_mi, __check_pl, __check_vs, __check_vc,
-       __check_hi, __check_ls, __check_ge, __check_lt,
-       __check_gt, __check_le, __check_al, __check_al
-};
-
 static bool range_of_ones(u64 val)
 {
        /* Doesn't handle full ones or full zeroes */
diff --git a/arch/arm64/lib/kasan_sw_tags.S b/arch/arm64/lib/kasan_sw_tags.S
new file mode 100644 (file)
index 0000000..5b04464
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 Google LLC
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Report a tag mismatch detected by tag-based KASAN.
+ *
+ * A compiler-generated thunk calls this with a non-AAPCS calling
+ * convention. Upon entry to this function, registers are as follows:
+ *
+ * x0:         fault address (see below for restore)
+ * x1:         fault description (see below for restore)
+ * x2 to x15:  callee-saved
+ * x16 to x17: safe to clobber
+ * x18 to x30: callee-saved
+ * sp:         pre-decremented by 256 bytes (see below for restore)
+ *
+ * The caller has decremented the SP by 256 bytes, and created a
+ * structure on the stack as follows:
+ *
+ * sp + 0..15:    x0 and x1 to be restored
+ * sp + 16..231:  free for use
+ * sp + 232..247: x29 and x30 (same as in GPRs)
+ * sp + 248..255: free for use
+ *
+ * Note that this is not a struct pt_regs.
+ *
+ * To call a regular AAPCS function we must save x2 to x15 (which we can
+ * store in the gaps), and create a frame record (for which we can use
+ * x29 and x30 spilled by the caller as those match the GPRs).
+ *
+ * The caller expects x0 and x1 to be restored from the structure, and
+ * for the structure to be removed from the stack (i.e. the SP must be
+ * incremented by 256 prior to return).
+ */
+SYM_CODE_START(__hwasan_tag_mismatch)
+#ifdef BTI_C
+       BTI_C
+#endif
+       add     x29, sp, #232
+       stp     x2, x3, [sp, #8 * 2]
+       stp     x4, x5, [sp, #8 * 4]
+       stp     x6, x7, [sp, #8 * 6]
+       stp     x8, x9, [sp, #8 * 8]
+       stp     x10, x11, [sp, #8 * 10]
+       stp     x12, x13, [sp, #8 * 12]
+       stp     x14, x15, [sp, #8 * 14]
+#ifndef CONFIG_SHADOW_CALL_STACK
+       str     x18, [sp, #8 * 18]
+#endif
+
+       mov     x2, x30
+       bl      kasan_tag_mismatch
+
+       ldp     x0, x1, [sp]
+       ldp     x2, x3, [sp, #8 * 2]
+       ldp     x4, x5, [sp, #8 * 4]
+       ldp     x6, x7, [sp, #8 * 6]
+       ldp     x8, x9, [sp, #8 * 8]
+       ldp     x10, x11, [sp, #8 * 10]
+       ldp     x12, x13, [sp, #8 * 12]
+       ldp     x14, x15, [sp, #8 * 14]
+#ifndef CONFIG_SHADOW_CALL_STACK
+       ldr     x18, [sp, #8 * 18]
+#endif
+       ldp     x29, x30, [sp, #8 * 29]
+
+       /* remove the structure from the stack */
+       add     sp, sp, #256
+       ret
+SYM_CODE_END(__hwasan_tag_mismatch)
+EXPORT_SYMBOL(__hwasan_tag_mismatch)
index edf6b97..7c2276f 100644 (file)
@@ -1,9 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Based on arch/arm/lib/memchr.S
- *
- * Copyright (C) 1995-2000 Russell King
- * Copyright (C) 2013 ARM Ltd.
+ * Copyright (C) 2021 Arm Ltd.
  */
 
 #include <linux/linkage.h>
  * Returns:
  *     x0 - address of first occurrence of 'c' or 0
  */
+
+#define L(label) .L ## label
+
+#define REP8_01 0x0101010101010101
+#define REP8_7f 0x7f7f7f7f7f7f7f7f
+
+#define srcin          x0
+#define chrin          w1
+#define cntin          x2
+
+#define result         x0
+
+#define wordcnt                x3
+#define rep01          x4
+#define repchr         x5
+#define cur_word       x6
+#define cur_byte       w6
+#define tmp            x7
+#define tmp2           x8
+
+       .p2align 4
+       nop
 SYM_FUNC_START_WEAK_PI(memchr)
-       and     w1, w1, #0xff
-1:     subs    x2, x2, #1
-       b.mi    2f
-       ldrb    w3, [x0], #1
-       cmp     w3, w1
-       b.ne    1b
-       sub     x0, x0, #1
+       and     chrin, chrin, #0xff
+       lsr     wordcnt, cntin, #3
+       cbz     wordcnt, L(byte_loop)
+       mov     rep01, #REP8_01
+       mul     repchr, x1, rep01
+       and     cntin, cntin, #7
+L(word_loop):
+       ldr     cur_word, [srcin], #8
+       sub     wordcnt, wordcnt, #1
+       eor     cur_word, cur_word, repchr
+       sub     tmp, cur_word, rep01
+       orr     tmp2, cur_word, #REP8_7f
+       bics    tmp, tmp, tmp2
+       b.ne    L(found_word)
+       cbnz    wordcnt, L(word_loop)
+L(byte_loop):
+       cbz     cntin, L(not_found)
+       ldrb    cur_byte, [srcin], #1
+       sub     cntin, cntin, #1
+       cmp     cur_byte, chrin
+       b.ne    L(byte_loop)
+       sub     srcin, srcin, #1
+       ret
+L(found_word):
+CPU_LE(        rev     tmp, tmp)
+       clz     tmp, tmp
+       sub     tmp, tmp, #64
+       add     result, srcin, tmp, asr #3
        ret
-2:     mov     x0, #0
+L(not_found):
+       mov     result, #0
        ret
 SYM_FUNC_END_PI(memchr)
 EXPORT_SYMBOL_NOKASAN(memchr)
index c0671e7..7d95638 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
+ * Copyright (c) 2013-2021, Arm Limited.
  *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
+ * Adapted from the original at:
+ * https://github.com/ARM-software/optimized-routines/blob/e823e3abf5f89ecb/string/aarch64/memcmp.S
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-/*
-* compare memory areas(when two memory areas' offset are different,
-* alignment handled by the hardware)
-*
-* Parameters:
-*  x0 - const memory area 1 pointer
-*  x1 - const memory area 2 pointer
-*  x2 - the maximal compare byte length
-* Returns:
-*  x0 - a compare result, maybe less than, equal to, or greater than ZERO
-*/
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses.
+ */
+
+#define L(label) .L ## label
 
 /* Parameters and result.  */
-src1           .req    x0
-src2           .req    x1
-limit          .req    x2
-result         .req    x0
+#define src1           x0
+#define src2           x1
+#define limit          x2
+#define result         w0
 
 /* Internal variables.  */
-data1          .req    x3
-data1w         .req    w3
-data2          .req    x4
-data2w         .req    w4
-has_nul                .req    x5
-diff           .req    x6
-endloop                .req    x7
-tmp1           .req    x8
-tmp2           .req    x9
-tmp3           .req    x10
-pos            .req    x11
-limit_wd       .req    x12
-mask           .req    x13
+#define data1          x3
+#define data1w         w3
+#define data1h         x4
+#define data2          x5
+#define data2w         w5
+#define data2h         x6
+#define tmp1           x7
+#define tmp2           x8
 
 SYM_FUNC_START_WEAK_PI(memcmp)
-       cbz     limit, .Lret0
-       eor     tmp1, src1, src2
-       tst     tmp1, #7
-       b.ne    .Lmisaligned8
-       ands    tmp1, src1, #7
-       b.ne    .Lmutual_align
-       sub     limit_wd, limit, #1 /* limit != 0, so no underflow.  */
-       lsr     limit_wd, limit_wd, #3 /* Convert to Dwords.  */
-       /*
-       * The input source addresses are at alignment boundary.
-       * Directly compare eight bytes each time.
-       */
-.Lloop_aligned:
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
-.Lstart_realigned:
-       subs    limit_wd, limit_wd, #1
-       eor     diff, data1, data2      /* Non-zero if differences found.  */
-       csinv   endloop, diff, xzr, cs  /* Last Dword or differences.  */
-       cbz     endloop, .Lloop_aligned
-
-       /* Not reached the limit, must have found a diff.  */
-       tbz     limit_wd, #63, .Lnot_limit
-
-       /* Limit % 8 == 0 => the diff is in the last 8 bytes. */
-       ands    limit, limit, #7
-       b.eq    .Lnot_limit
-       /*
-       * The remained bytes less than 8. It is needed to extract valid data
-       * from last eight bytes of the intended memory range.
-       */
-       lsl     limit, limit, #3        /* bytes-> bits.  */
-       mov     mask, #~0
-CPU_BE( lsr    mask, mask, limit )
-CPU_LE( lsl    mask, mask, limit )
-       bic     data1, data1, mask
-       bic     data2, data2, mask
-
-       orr     diff, diff, mask
-       b       .Lnot_limit
-
-.Lmutual_align:
-       /*
-       * Sources are mutually aligned, but are not currently at an
-       * alignment boundary. Round down the addresses and then mask off
-       * the bytes that precede the start point.
-       */
-       bic     src1, src1, #7
-       bic     src2, src2, #7
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
-       /*
-       * We can not add limit with alignment offset(tmp1) here. Since the
-       * addition probably make the limit overflown.
-       */
-       sub     limit_wd, limit, #1/*limit != 0, so no underflow.*/
-       and     tmp3, limit_wd, #7
-       lsr     limit_wd, limit_wd, #3
-       add     tmp3, tmp3, tmp1
-       add     limit_wd, limit_wd, tmp3, lsr #3
-       add     limit, limit, tmp1/* Adjust the limit for the extra.  */
-
-       lsl     tmp1, tmp1, #3/* Bytes beyond alignment -> bits.*/
-       neg     tmp1, tmp1/* Bits to alignment -64.  */
-       mov     tmp2, #~0
-       /*mask off the non-intended bytes before the start address.*/
-CPU_BE( lsl    tmp2, tmp2, tmp1 )/*Big-endian.Early bytes are at MSB*/
-       /* Little-endian.  Early bytes are at LSB.  */
-CPU_LE( lsr    tmp2, tmp2, tmp1 )
-
-       orr     data1, data1, tmp2
-       orr     data2, data2, tmp2
-       b       .Lstart_realigned
-
-       /*src1 and src2 have different alignment offset.*/
-.Lmisaligned8:
-       cmp     limit, #8
-       b.lo    .Ltiny8proc /*limit < 8: compare byte by byte*/
-
-       and     tmp1, src1, #7
-       neg     tmp1, tmp1
-       add     tmp1, tmp1, #8/*valid length in the first 8 bytes of src1*/
-       and     tmp2, src2, #7
-       neg     tmp2, tmp2
-       add     tmp2, tmp2, #8/*valid length in the first 8 bytes of src2*/
-       subs    tmp3, tmp1, tmp2
-       csel    pos, tmp1, tmp2, hi /*Choose the maximum.*/
-
-       sub     limit, limit, pos
-       /*compare the proceeding bytes in the first 8 byte segment.*/
-.Ltinycmp:
-       ldrb    data1w, [src1], #1
-       ldrb    data2w, [src2], #1
-       subs    pos, pos, #1
-       ccmp    data1w, data2w, #0, ne  /* NZCV = 0b0000.  */
-       b.eq    .Ltinycmp
-       cbnz    pos, 1f /*diff occurred before the last byte.*/
-       cmp     data1w, data2w
-       b.eq    .Lstart_align
-1:
-       sub     result, data1, data2
+       subs    limit, limit, 8
+       b.lo    L(less8)
+
+       ldr     data1, [src1], 8
+       ldr     data2, [src2], 8
+       cmp     data1, data2
+       b.ne    L(return)
+
+       subs    limit, limit, 8
+       b.gt    L(more16)
+
+       ldr     data1, [src1, limit]
+       ldr     data2, [src2, limit]
+       b       L(return)
+
+L(more16):
+       ldr     data1, [src1], 8
+       ldr     data2, [src2], 8
+       cmp     data1, data2
+       bne     L(return)
+
+       /* Jump directly to comparing the last 16 bytes for 32 byte (or less)
+          strings.  */
+       subs    limit, limit, 16
+       b.ls    L(last_bytes)
+
+       /* We overlap loads between 0-32 bytes at either side of SRC1 when we
+          try to align, so limit it only to strings larger than 128 bytes.  */
+       cmp     limit, 96
+       b.ls    L(loop16)
+
+       /* Align src1 and adjust src2 with bytes not yet done.  */
+       and     tmp1, src1, 15
+       add     limit, limit, tmp1
+       sub     src1, src1, tmp1
+       sub     src2, src2, tmp1
+
+       /* Loop performing 16 bytes per iteration using aligned src1.
+          Limit is pre-decremented by 16 and must be larger than zero.
+          Exit if <= 16 bytes left to do or if the data is not equal.  */
+       .p2align 4
+L(loop16):
+       ldp     data1, data1h, [src1], 16
+       ldp     data2, data2h, [src2], 16
+       subs    limit, limit, 16
+       ccmp    data1, data2, 0, hi
+       ccmp    data1h, data2h, 0, eq
+       b.eq    L(loop16)
+
+       cmp     data1, data2
+       bne     L(return)
+       mov     data1, data1h
+       mov     data2, data2h
+       cmp     data1, data2
+       bne     L(return)
+
+       /* Compare last 1-16 bytes using unaligned access.  */
+L(last_bytes):
+       add     src1, src1, limit
+       add     src2, src2, limit
+       ldp     data1, data1h, [src1]
+       ldp     data2, data2h, [src2]
+       cmp     data1, data2
+       bne     L(return)
+       mov     data1, data1h
+       mov     data2, data2h
+       cmp     data1, data2
+
+       /* Compare data bytes and set return value to 0, -1 or 1.  */
+L(return):
+#ifndef __AARCH64EB__
+       rev     data1, data1
+       rev     data2, data2
+#endif
+       cmp     data1, data2
+L(ret_eq):
+       cset    result, ne
+       cneg    result, result, lo
        ret
 
-.Lstart_align:
-       lsr     limit_wd, limit, #3
-       cbz     limit_wd, .Lremain8
-
-       ands    xzr, src1, #7
-       b.eq    .Lrecal_offset
-       /*process more leading bytes to make src1 aligned...*/
-       add     src1, src1, tmp3 /*backwards src1 to alignment boundary*/
-       add     src2, src2, tmp3
-       sub     limit, limit, tmp3
-       lsr     limit_wd, limit, #3
-       cbz     limit_wd, .Lremain8
-       /*load 8 bytes from aligned SRC1..*/
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
-
-       subs    limit_wd, limit_wd, #1
-       eor     diff, data1, data2  /*Non-zero if differences found.*/
-       csinv   endloop, diff, xzr, ne
-       cbnz    endloop, .Lunequal_proc
-       /*How far is the current SRC2 from the alignment boundary...*/
-       and     tmp3, tmp3, #7
-
-.Lrecal_offset:/*src1 is aligned now..*/
-       neg     pos, tmp3
-.Lloopcmp_proc:
-       /*
-       * Divide the eight bytes into two parts. First,backwards the src2
-       * to an alignment boundary,load eight bytes and compare from
-       * the SRC2 alignment boundary. If all 8 bytes are equal,then start
-       * the second part's comparison. Otherwise finish the comparison.
-       * This special handle can garantee all the accesses are in the
-       * thread/task space in avoid to overrange access.
-       */
-       ldr     data1, [src1,pos]
-       ldr     data2, [src2,pos]
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       cbnz    diff, .Lnot_limit
-
-       /*The second part process*/
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       subs    limit_wd, limit_wd, #1
-       csinv   endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
-       cbz     endloop, .Lloopcmp_proc
-.Lunequal_proc:
-       cbz     diff, .Lremain8
-
-/* There is difference occurred in the latest comparison. */
-.Lnot_limit:
-/*
-* For little endian,reverse the low significant equal bits into MSB,then
-* following CLZ can find how many equal bits exist.
-*/
-CPU_LE( rev    diff, diff )
-CPU_LE( rev    data1, data1 )
-CPU_LE( rev    data2, data2 )
-
-       /*
-       * The MS-non-zero bit of DIFF marks either the first bit
-       * that is different, or the end of the significant data.
-       * Shifting left now will bring the critical information into the
-       * top bits.
-       */
-       clz     pos, diff
-       lsl     data1, data1, pos
-       lsl     data2, data2, pos
-       /*
-       * We need to zero-extend (char is unsigned) the value and then
-       * perform a signed subtraction.
-       */
-       lsr     data1, data1, #56
-       sub     result, data1, data2, lsr #56
+       .p2align 4
+       /* Compare up to 8 bytes.  Limit is [-8..-1].  */
+L(less8):
+       adds    limit, limit, 4
+       b.lo    L(less4)
+       ldr     data1w, [src1], 4
+       ldr     data2w, [src2], 4
+       cmp     data1w, data2w
+       b.ne    L(return)
+       sub     limit, limit, 4
+L(less4):
+       adds    limit, limit, 4
+       beq     L(ret_eq)
+L(byte_loop):
+       ldrb    data1w, [src1], 1
+       ldrb    data2w, [src2], 1
+       subs    limit, limit, 1
+       ccmp    data1w, data2w, 0, ne   /* NZCV = 0b0000.  */
+       b.eq    L(byte_loop)
+       sub     result, data1w, data2w
        ret
 
-.Lremain8:
-       /* Limit % 8 == 0 =>. all data are equal.*/
-       ands    limit, limit, #7
-       b.eq    .Lret0
-
-.Ltiny8proc:
-       ldrb    data1w, [src1], #1
-       ldrb    data2w, [src2], #1
-       subs    limit, limit, #1
-
-       ccmp    data1w, data2w, #0, ne  /* NZCV = 0b0000. */
-       b.eq    .Ltiny8proc
-       sub     result, data1, data2
-       ret
-.Lret0:
-       mov     result, #0
-       ret
 SYM_FUNC_END_PI(memcmp)
 EXPORT_SYMBOL_NOKASAN(memcmp)
index dc8d2a2..b82fd64 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
+ * Copyright (c) 2012-2021, Arm Limited.
  *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
+ * Adapted from the original at:
+ * https://github.com/ARM-software/optimized-routines/blob/afd6244a1f8d9229/string/aarch64/memcpy.S
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/cache.h>
 
-/*
- * Copy a buffer from src to dest (alignment handled by the hardware)
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, unaligned accesses.
  *
- * Parameters:
- *     x0 - dest
- *     x1 - src
- *     x2 - n
- * Returns:
- *     x0 - dest
  */
-       .macro ldrb1 reg, ptr, val
-       ldrb  \reg, [\ptr], \val
-       .endm
-
-       .macro strb1 reg, ptr, val
-       strb \reg, [\ptr], \val
-       .endm
 
-       .macro ldrh1 reg, ptr, val
-       ldrh  \reg, [\ptr], \val
-       .endm
+#define L(label) .L ## label
 
-       .macro strh1 reg, ptr, val
-       strh \reg, [\ptr], \val
-       .endm
+#define dstin  x0
+#define src    x1
+#define count  x2
+#define dst    x3
+#define srcend x4
+#define dstend x5
+#define A_l    x6
+#define A_lw   w6
+#define A_h    x7
+#define B_l    x8
+#define B_lw   w8
+#define B_h    x9
+#define C_l    x10
+#define C_lw   w10
+#define C_h    x11
+#define D_l    x12
+#define D_h    x13
+#define E_l    x14
+#define E_h    x15
+#define F_l    x16
+#define F_h    x17
+#define G_l    count
+#define G_h    dst
+#define H_l    src
+#define H_h    srcend
+#define tmp1   x14
 
-       .macro ldr1 reg, ptr, val
-       ldr \reg, [\ptr], \val
-       .endm
+/* This implementation handles overlaps and supports both memcpy and memmove
+   from a single entry point.  It uses unaligned accesses and branchless
+   sequences to keep the code small, simple and improve performance.
 
-       .macro str1 reg, ptr, val
-       str \reg, [\ptr], \val
-       .endm
+   Copies are split into 3 main cases: small copies of up to 32 bytes, medium
+   copies of up to 128 bytes, and large copies.  The overhead of the overlap
+   check is negligible since it is only required for large copies.
 
-       .macro ldp1 reg1, reg2, ptr, val
-       ldp \reg1, \reg2, [\ptr], \val
-       .endm
-
-       .macro stp1 reg1, reg2, ptr, val
-       stp \reg1, \reg2, [\ptr], \val
-       .endm
+   Large copies use a software pipelined loop processing 64 bytes per iteration.
+   The destination pointer is 16-byte aligned to minimize unaligned accesses.
+   The loop tail is handled by always copying 64 bytes from the end.
+*/
 
+SYM_FUNC_START_ALIAS(__memmove)
+SYM_FUNC_START_WEAK_ALIAS_PI(memmove)
 SYM_FUNC_START_ALIAS(__memcpy)
 SYM_FUNC_START_WEAK_PI(memcpy)
-#include "copy_template.S"
+       add     srcend, src, count
+       add     dstend, dstin, count
+       cmp     count, 128
+       b.hi    L(copy_long)
+       cmp     count, 32
+       b.hi    L(copy32_128)
+
+       /* Small copies: 0..32 bytes.  */
+       cmp     count, 16
+       b.lo    L(copy16)
+       ldp     A_l, A_h, [src]
+       ldp     D_l, D_h, [srcend, -16]
+       stp     A_l, A_h, [dstin]
+       stp     D_l, D_h, [dstend, -16]
+       ret
+
+       /* Copy 8-15 bytes.  */
+L(copy16):
+       tbz     count, 3, L(copy8)
+       ldr     A_l, [src]
+       ldr     A_h, [srcend, -8]
+       str     A_l, [dstin]
+       str     A_h, [dstend, -8]
+       ret
+
+       .p2align 3
+       /* Copy 4-7 bytes.  */
+L(copy8):
+       tbz     count, 2, L(copy4)
+       ldr     A_lw, [src]
+       ldr     B_lw, [srcend, -4]
+       str     A_lw, [dstin]
+       str     B_lw, [dstend, -4]
+       ret
+
+       /* Copy 0..3 bytes using a branchless sequence.  */
+L(copy4):
+       cbz     count, L(copy0)
+       lsr     tmp1, count, 1
+       ldrb    A_lw, [src]
+       ldrb    C_lw, [srcend, -1]
+       ldrb    B_lw, [src, tmp1]
+       strb    A_lw, [dstin]
+       strb    B_lw, [dstin, tmp1]
+       strb    C_lw, [dstend, -1]
+L(copy0):
+       ret
+
+       .p2align 4
+       /* Medium copies: 33..128 bytes.  */
+L(copy32_128):
+       ldp     A_l, A_h, [src]
+       ldp     B_l, B_h, [src, 16]
+       ldp     C_l, C_h, [srcend, -32]
+       ldp     D_l, D_h, [srcend, -16]
+       cmp     count, 64
+       b.hi    L(copy128)
+       stp     A_l, A_h, [dstin]
+       stp     B_l, B_h, [dstin, 16]
+       stp     C_l, C_h, [dstend, -32]
+       stp     D_l, D_h, [dstend, -16]
        ret
+
+       .p2align 4
+       /* Copy 65..128 bytes.  */
+L(copy128):
+       ldp     E_l, E_h, [src, 32]
+       ldp     F_l, F_h, [src, 48]
+       cmp     count, 96
+       b.ls    L(copy96)
+       ldp     G_l, G_h, [srcend, -64]
+       ldp     H_l, H_h, [srcend, -48]
+       stp     G_l, G_h, [dstend, -64]
+       stp     H_l, H_h, [dstend, -48]
+L(copy96):
+       stp     A_l, A_h, [dstin]
+       stp     B_l, B_h, [dstin, 16]
+       stp     E_l, E_h, [dstin, 32]
+       stp     F_l, F_h, [dstin, 48]
+       stp     C_l, C_h, [dstend, -32]
+       stp     D_l, D_h, [dstend, -16]
+       ret
+
+       .p2align 4
+       /* Copy more than 128 bytes.  */
+L(copy_long):
+       /* Use backwards copy if there is an overlap.  */
+       sub     tmp1, dstin, src
+       cbz     tmp1, L(copy0)
+       cmp     tmp1, count
+       b.lo    L(copy_long_backwards)
+
+       /* Copy 16 bytes and then align dst to 16-byte alignment.  */
+
+       ldp     D_l, D_h, [src]
+       and     tmp1, dstin, 15
+       bic     dst, dstin, 15
+       sub     src, src, tmp1
+       add     count, count, tmp1      /* Count is now 16 too large.  */
+       ldp     A_l, A_h, [src, 16]
+       stp     D_l, D_h, [dstin]
+       ldp     B_l, B_h, [src, 32]
+       ldp     C_l, C_h, [src, 48]
+       ldp     D_l, D_h, [src, 64]!
+       subs    count, count, 128 + 16  /* Test and readjust count.  */
+       b.ls    L(copy64_from_end)
+
+L(loop64):
+       stp     A_l, A_h, [dst, 16]
+       ldp     A_l, A_h, [src, 16]
+       stp     B_l, B_h, [dst, 32]
+       ldp     B_l, B_h, [src, 32]
+       stp     C_l, C_h, [dst, 48]
+       ldp     C_l, C_h, [src, 48]
+       stp     D_l, D_h, [dst, 64]!
+       ldp     D_l, D_h, [src, 64]!
+       subs    count, count, 64
+       b.hi    L(loop64)
+
+       /* Write the last iteration and copy 64 bytes from the end.  */
+L(copy64_from_end):
+       ldp     E_l, E_h, [srcend, -64]
+       stp     A_l, A_h, [dst, 16]
+       ldp     A_l, A_h, [srcend, -48]
+       stp     B_l, B_h, [dst, 32]
+       ldp     B_l, B_h, [srcend, -32]
+       stp     C_l, C_h, [dst, 48]
+       ldp     C_l, C_h, [srcend, -16]
+       stp     D_l, D_h, [dst, 64]
+       stp     E_l, E_h, [dstend, -64]
+       stp     A_l, A_h, [dstend, -48]
+       stp     B_l, B_h, [dstend, -32]
+       stp     C_l, C_h, [dstend, -16]
+       ret
+
+       .p2align 4
+
+       /* Large backwards copy for overlapping copies.
+          Copy 16 bytes and then align dst to 16-byte alignment.  */
+L(copy_long_backwards):
+       ldp     D_l, D_h, [srcend, -16]
+       and     tmp1, dstend, 15
+       sub     srcend, srcend, tmp1
+       sub     count, count, tmp1
+       ldp     A_l, A_h, [srcend, -16]
+       stp     D_l, D_h, [dstend, -16]
+       ldp     B_l, B_h, [srcend, -32]
+       ldp     C_l, C_h, [srcend, -48]
+       ldp     D_l, D_h, [srcend, -64]!
+       sub     dstend, dstend, tmp1
+       subs    count, count, 128
+       b.ls    L(copy64_from_start)
+
+L(loop64_backwards):
+       stp     A_l, A_h, [dstend, -16]
+       ldp     A_l, A_h, [srcend, -16]
+       stp     B_l, B_h, [dstend, -32]
+       ldp     B_l, B_h, [srcend, -32]
+       stp     C_l, C_h, [dstend, -48]
+       ldp     C_l, C_h, [srcend, -48]
+       stp     D_l, D_h, [dstend, -64]!
+       ldp     D_l, D_h, [srcend, -64]!
+       subs    count, count, 64
+       b.hi    L(loop64_backwards)
+
+       /* Write the last iteration and copy 64 bytes from the start.  */
+L(copy64_from_start):
+       ldp     G_l, G_h, [src, 48]
+       stp     A_l, A_h, [dstend, -16]
+       ldp     A_l, A_h, [src, 32]
+       stp     B_l, B_h, [dstend, -32]
+       ldp     B_l, B_h, [src, 16]
+       stp     C_l, C_h, [dstend, -48]
+       ldp     C_l, C_h, [src]
+       stp     D_l, D_h, [dstend, -64]
+       stp     G_l, G_h, [dstin, 48]
+       stp     A_l, A_h, [dstin, 32]
+       stp     B_l, B_h, [dstin, 16]
+       stp     C_l, C_h, [dstin]
+       ret
+
 SYM_FUNC_END_PI(memcpy)
 EXPORT_SYMBOL(memcpy)
 SYM_FUNC_END_ALIAS(__memcpy)
 EXPORT_SYMBOL(__memcpy)
+SYM_FUNC_END_ALIAS_PI(memmove)
+EXPORT_SYMBOL(memmove)
+SYM_FUNC_END_ALIAS(__memmove)
+EXPORT_SYMBOL(__memmove)
diff --git a/arch/arm64/lib/memmove.S b/arch/arm64/lib/memmove.S
deleted file mode 100644 (file)
index 1035dce..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
- *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
- */
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <asm/cache.h>
-
-/*
- * Move a buffer from src to test (alignment handled by the hardware).
- * If dest <= src, call memcpy, otherwise copy in reverse order.
- *
- * Parameters:
- *     x0 - dest
- *     x1 - src
- *     x2 - n
- * Returns:
- *     x0 - dest
- */
-dstin  .req    x0
-src    .req    x1
-count  .req    x2
-tmp1   .req    x3
-tmp1w  .req    w3
-tmp2   .req    x4
-tmp2w  .req    w4
-tmp3   .req    x5
-tmp3w  .req    w5
-dst    .req    x6
-
-A_l    .req    x7
-A_h    .req    x8
-B_l    .req    x9
-B_h    .req    x10
-C_l    .req    x11
-C_h    .req    x12
-D_l    .req    x13
-D_h    .req    x14
-
-SYM_FUNC_START_ALIAS(__memmove)
-SYM_FUNC_START_WEAK_PI(memmove)
-       cmp     dstin, src
-       b.lo    __memcpy
-       add     tmp1, src, count
-       cmp     dstin, tmp1
-       b.hs    __memcpy                /* No overlap.  */
-
-       add     dst, dstin, count
-       add     src, src, count
-       cmp     count, #16
-       b.lo    .Ltail15  /*probably non-alignment accesses.*/
-
-       ands    tmp2, src, #15     /* Bytes to reach alignment.  */
-       b.eq    .LSrcAligned
-       sub     count, count, tmp2
-       /*
-       * process the aligned offset length to make the src aligned firstly.
-       * those extra instructions' cost is acceptable. It also make the
-       * coming accesses are based on aligned address.
-       */
-       tbz     tmp2, #0, 1f
-       ldrb    tmp1w, [src, #-1]!
-       strb    tmp1w, [dst, #-1]!
-1:
-       tbz     tmp2, #1, 2f
-       ldrh    tmp1w, [src, #-2]!
-       strh    tmp1w, [dst, #-2]!
-2:
-       tbz     tmp2, #2, 3f
-       ldr     tmp1w, [src, #-4]!
-       str     tmp1w, [dst, #-4]!
-3:
-       tbz     tmp2, #3, .LSrcAligned
-       ldr     tmp1, [src, #-8]!
-       str     tmp1, [dst, #-8]!
-
-.LSrcAligned:
-       cmp     count, #64
-       b.ge    .Lcpy_over64
-
-       /*
-       * Deal with small copies quickly by dropping straight into the
-       * exit block.
-       */
-.Ltail63:
-       /*
-       * Copy up to 48 bytes of data. At this point we only need the
-       * bottom 6 bits of count to be accurate.
-       */
-       ands    tmp1, count, #0x30
-       b.eq    .Ltail15
-       cmp     tmp1w, #0x20
-       b.eq    1f
-       b.lt    2f
-       ldp     A_l, A_h, [src, #-16]!
-       stp     A_l, A_h, [dst, #-16]!
-1:
-       ldp     A_l, A_h, [src, #-16]!
-       stp     A_l, A_h, [dst, #-16]!
-2:
-       ldp     A_l, A_h, [src, #-16]!
-       stp     A_l, A_h, [dst, #-16]!
-
-.Ltail15:
-       tbz     count, #3, 1f
-       ldr     tmp1, [src, #-8]!
-       str     tmp1, [dst, #-8]!
-1:
-       tbz     count, #2, 2f
-       ldr     tmp1w, [src, #-4]!
-       str     tmp1w, [dst, #-4]!
-2:
-       tbz     count, #1, 3f
-       ldrh    tmp1w, [src, #-2]!
-       strh    tmp1w, [dst, #-2]!
-3:
-       tbz     count, #0, .Lexitfunc
-       ldrb    tmp1w, [src, #-1]
-       strb    tmp1w, [dst, #-1]
-
-.Lexitfunc:
-       ret
-
-.Lcpy_over64:
-       subs    count, count, #128
-       b.ge    .Lcpy_body_large
-       /*
-       * Less than 128 bytes to copy, so handle 64 bytes here and then jump
-       * to the tail.
-       */
-       ldp     A_l, A_h, [src, #-16]
-       stp     A_l, A_h, [dst, #-16]
-       ldp     B_l, B_h, [src, #-32]
-       ldp     C_l, C_h, [src, #-48]
-       stp     B_l, B_h, [dst, #-32]
-       stp     C_l, C_h, [dst, #-48]
-       ldp     D_l, D_h, [src, #-64]!
-       stp     D_l, D_h, [dst, #-64]!
-
-       tst     count, #0x3f
-       b.ne    .Ltail63
-       ret
-
-       /*
-       * Critical loop. Start at a new cache line boundary. Assuming
-       * 64 bytes per line this ensures the entire loop is in one line.
-       */
-       .p2align        L1_CACHE_SHIFT
-.Lcpy_body_large:
-       /* pre-load 64 bytes data. */
-       ldp     A_l, A_h, [src, #-16]
-       ldp     B_l, B_h, [src, #-32]
-       ldp     C_l, C_h, [src, #-48]
-       ldp     D_l, D_h, [src, #-64]!
-1:
-       /*
-       * interlace the load of next 64 bytes data block with store of the last
-       * loaded 64 bytes data.
-       */
-       stp     A_l, A_h, [dst, #-16]
-       ldp     A_l, A_h, [src, #-16]
-       stp     B_l, B_h, [dst, #-32]
-       ldp     B_l, B_h, [src, #-32]
-       stp     C_l, C_h, [dst, #-48]
-       ldp     C_l, C_h, [src, #-48]
-       stp     D_l, D_h, [dst, #-64]!
-       ldp     D_l, D_h, [src, #-64]!
-       subs    count, count, #64
-       b.ge    1b
-       stp     A_l, A_h, [dst, #-16]
-       stp     B_l, B_h, [dst, #-32]
-       stp     C_l, C_h, [dst, #-48]
-       stp     D_l, D_h, [dst, #-64]!
-
-       tst     count, #0x3f
-       b.ne    .Ltail63
-       ret
-SYM_FUNC_END_PI(memmove)
-EXPORT_SYMBOL(memmove)
-SYM_FUNC_END_ALIAS(__memmove)
-EXPORT_SYMBOL(__memmove)
index 351537c..e83643b 100644 (file)
@@ -37,6 +37,26 @@ SYM_FUNC_START(mte_clear_page_tags)
 SYM_FUNC_END(mte_clear_page_tags)
 
 /*
+ * Zero the page and tags at the same time
+ *
+ * Parameters:
+ *     x0 - address to the beginning of the page
+ */
+SYM_FUNC_START(mte_zero_clear_page_tags)
+       mrs     x1, dczid_el0
+       and     w1, w1, #0xf
+       mov     x2, #4
+       lsl     x1, x2, x1
+       and     x0, x0, #(1 << MTE_TAG_SHIFT) - 1       // clear the tag
+
+1:     dc      gzva, x0
+       add     x0, x0, x1
+       tst     x0, #(PAGE_SIZE - 1)
+       b.ne    1b
+       ret
+SYM_FUNC_END(mte_zero_clear_page_tags)
+
+/*
  * Copy the tags from the source page to the destination one
  *   x0 - address of the destination page
  *   x1 - address of the source page
index 4e79566..d7bee21 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
+ * Copyright (c) 2012-2021, Arm Limited.
  *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
+ * Adapted from the original at:
+ * https://github.com/ARM-software/optimized-routines/blob/afd6244a1f8d9229/string/aarch64/strcmp.S
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-/*
- * compare two strings
+/* Assumptions:
  *
- * Parameters:
- *     x0 - const string 1 pointer
- *    x1 - const string 2 pointer
- * Returns:
- * x0 - an integer less than, equal to, or greater than zero
- * if  s1  is  found, respectively, to be less than, to match,
- * or be greater than s2.
+ * ARMv8-a, AArch64
  */
 
+#define L(label) .L ## label
+
 #define REP8_01 0x0101010101010101
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
 /* Parameters and result.  */
-src1           .req    x0
-src2           .req    x1
-result         .req    x0
+#define src1           x0
+#define src2           x1
+#define result         x0
 
 /* Internal variables.  */
-data1          .req    x2
-data1w         .req    w2
-data2          .req    x3
-data2w         .req    w3
-has_nul                .req    x4
-diff           .req    x5
-syndrome       .req    x6
-tmp1           .req    x7
-tmp2           .req    x8
-tmp3           .req    x9
-zeroones       .req    x10
-pos            .req    x11
-
+#define data1          x2
+#define data1w         w2
+#define data2          x3
+#define data2w         w3
+#define has_nul                x4
+#define diff           x5
+#define syndrome       x6
+#define tmp1           x7
+#define tmp2           x8
+#define tmp3           x9
+#define zeroones       x10
+#define pos            x11
+
+       /* Start of performance-critical section  -- one 64B cache line.  */
+       .align 6
 SYM_FUNC_START_WEAK_PI(strcmp)
        eor     tmp1, src1, src2
        mov     zeroones, #REP8_01
        tst     tmp1, #7
-       b.ne    .Lmisaligned8
+       b.ne    L(misaligned8)
        ands    tmp1, src1, #7
-       b.ne    .Lmutual_align
-
-       /*
-       * NUL detection works on the principle that (X - 1) & (~X) & 0x80
-       * (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
-       * can be done in parallel across the entire word.
-       */
-.Lloop_aligned:
+       b.ne    L(mutual_align)
+       /* NUL detection works on the principle that (X - 1) & (~X) & 0x80
+          (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
+          can be done in parallel across the entire word.  */
+L(loop_aligned):
        ldr     data1, [src1], #8
        ldr     data2, [src2], #8
-.Lstart_realigned:
+L(start_realigned):
        sub     tmp1, data1, zeroones
        orr     tmp2, data1, #REP8_7f
        eor     diff, data1, data2      /* Non-zero if differences found.  */
        bic     has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
        orr     syndrome, diff, has_nul
-       cbz     syndrome, .Lloop_aligned
-       b       .Lcal_cmpresult
+       cbz     syndrome, L(loop_aligned)
+       /* End of performance-critical section  -- one 64B cache line.  */
+
+L(end):
+#ifndef        __AARCH64EB__
+       rev     syndrome, syndrome
+       rev     data1, data1
+       /* The MS-non-zero bit of the syndrome marks either the first bit
+          that is different, or the top bit of the first zero byte.
+          Shifting left now will bring the critical information into the
+          top bits.  */
+       clz     pos, syndrome
+       rev     data2, data2
+       lsl     data1, data1, pos
+       lsl     data2, data2, pos
+       /* But we need to zero-extend (char is unsigned) the value and then
+          perform a signed 32-bit subtraction.  */
+       lsr     data1, data1, #56
+       sub     result, data1, data2, lsr #56
+       ret
+#else
+       /* For big-endian we cannot use the trick with the syndrome value
+          as carry-propagation can corrupt the upper bits if the trailing
+          bytes in the string contain 0x01.  */
+       /* However, if there is no NUL byte in the dword, we can generate
+          the result directly.  We can't just subtract the bytes as the
+          MSB might be significant.  */
+       cbnz    has_nul, 1f
+       cmp     data1, data2
+       cset    result, ne
+       cneg    result, result, lo
+       ret
+1:
+       /* Re-compute the NUL-byte detection, using a byte-reversed value.  */
+       rev     tmp3, data1
+       sub     tmp1, tmp3, zeroones
+       orr     tmp2, tmp3, #REP8_7f
+       bic     has_nul, tmp1, tmp2
+       rev     has_nul, has_nul
+       orr     syndrome, diff, has_nul
+       clz     pos, syndrome
+       /* The MS-non-zero bit of the syndrome marks either the first bit
+          that is different, or the top bit of the first zero byte.
+          Shifting left now will bring the critical information into the
+          top bits.  */
+       lsl     data1, data1, pos
+       lsl     data2, data2, pos
+       /* But we need to zero-extend (char is unsigned) the value and then
+          perform a signed 32-bit subtraction.  */
+       lsr     data1, data1, #56
+       sub     result, data1, data2, lsr #56
+       ret
+#endif
 
-.Lmutual_align:
-       /*
-       * Sources are mutually aligned, but are not currently at an
-       * alignment boundary.  Round down the addresses and then mask off
-       * the bytes that preceed the start point.
-       */
+L(mutual_align):
+       /* Sources are mutually aligned, but are not currently at an
+          alignment boundary.  Round down the addresses and then mask off
+          the bytes that preceed the start point.  */
        bic     src1, src1, #7
        bic     src2, src2, #7
        lsl     tmp1, tmp1, #3          /* Bytes beyond alignment -> bits.  */
@@ -86,138 +125,52 @@ SYM_FUNC_START_WEAK_PI(strcmp)
        neg     tmp1, tmp1              /* Bits to alignment -64.  */
        ldr     data2, [src2], #8
        mov     tmp2, #~0
+#ifdef __AARCH64EB__
        /* Big-endian.  Early bytes are at MSB.  */
-CPU_BE( lsl    tmp2, tmp2, tmp1 )      /* Shift (tmp1 & 63).  */
+       lsl     tmp2, tmp2, tmp1        /* Shift (tmp1 & 63).  */
+#else
        /* Little-endian.  Early bytes are at LSB.  */
-CPU_LE( lsr    tmp2, tmp2, tmp1 )      /* Shift (tmp1 & 63).  */
-
+       lsr     tmp2, tmp2, tmp1        /* Shift (tmp1 & 63).  */
+#endif
        orr     data1, data1, tmp2
        orr     data2, data2, tmp2
-       b       .Lstart_realigned
-
-.Lmisaligned8:
-       /*
-       * Get the align offset length to compare per byte first.
-       * After this process, one string's address will be aligned.
-       */
-       and     tmp1, src1, #7
-       neg     tmp1, tmp1
-       add     tmp1, tmp1, #8
-       and     tmp2, src2, #7
-       neg     tmp2, tmp2
-       add     tmp2, tmp2, #8
-       subs    tmp3, tmp1, tmp2
-       csel    pos, tmp1, tmp2, hi /*Choose the maximum. */
-.Ltinycmp:
+       b       L(start_realigned)
+
+L(misaligned8):
+       /* Align SRC1 to 8 bytes and then compare 8 bytes at a time, always
+          checking to make sure that we don't access beyond page boundary in
+          SRC2.  */
+       tst     src1, #7
+       b.eq    L(loop_misaligned)
+L(do_misaligned):
        ldrb    data1w, [src1], #1
        ldrb    data2w, [src2], #1
-       subs    pos, pos, #1
-       ccmp    data1w, #1, #0, ne  /* NZCV = 0b0000.  */
-       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
-       b.eq    .Ltinycmp
-       cbnz    pos, 1f /*find the null or unequal...*/
        cmp     data1w, #1
-       ccmp    data1w, data2w, #0, cs
-       b.eq    .Lstart_align /*the last bytes are equal....*/
-1:
-       sub     result, data1, data2
-       ret
-
-.Lstart_align:
-       ands    xzr, src1, #7
-       b.eq    .Lrecal_offset
-       /*process more leading bytes to make str1 aligned...*/
-       add     src1, src1, tmp3
-       add     src2, src2, tmp3
-       /*load 8 bytes from aligned str1 and non-aligned str2..*/
+       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
+       b.ne    L(done)
+       tst     src1, #7
+       b.ne    L(do_misaligned)
+
+L(loop_misaligned):
+       /* Test if we are within the last dword of the end of a 4K page.  If
+          yes then jump back to the misaligned loop to copy a byte at a time.  */
+       and     tmp1, src2, #0xff8
+       eor     tmp1, tmp1, #0xff8
+       cbz     tmp1, L(do_misaligned)
        ldr     data1, [src1], #8
        ldr     data2, [src2], #8
 
        sub     tmp1, data1, zeroones
        orr     tmp2, data1, #REP8_7f
-       bic     has_nul, tmp1, tmp2
-       eor     diff, data1, data2 /* Non-zero if differences found.  */
-       orr     syndrome, diff, has_nul
-       cbnz    syndrome, .Lcal_cmpresult
-       /*How far is the current str2 from the alignment boundary...*/
-       and     tmp3, tmp3, #7
-.Lrecal_offset:
-       neg     pos, tmp3
-.Lloopcmp_proc:
-       /*
-       * Divide the eight bytes into two parts. First,backwards the src2
-       * to an alignment boundary,load eight bytes from the SRC2 alignment
-       * boundary,then compare with the relative bytes from SRC1.
-       * If all 8 bytes are equal,then start the second part's comparison.
-       * Otherwise finish the comparison.
-       * This special handle can garantee all the accesses are in the
-       * thread/task space in avoid to overrange access.
-       */
-       ldr     data1, [src1,pos]
-       ldr     data2, [src2,pos]
-       sub     tmp1, data1, zeroones
-       orr     tmp2, data1, #REP8_7f
-       bic     has_nul, tmp1, tmp2
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       orr     syndrome, diff, has_nul
-       cbnz    syndrome, .Lcal_cmpresult
-
-       /*The second part process*/
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
-       sub     tmp1, data1, zeroones
-       orr     tmp2, data1, #REP8_7f
-       bic     has_nul, tmp1, tmp2
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
+       eor     diff, data1, data2      /* Non-zero if differences found.  */
+       bic     has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
        orr     syndrome, diff, has_nul
-       cbz     syndrome, .Lloopcmp_proc
+       cbz     syndrome, L(loop_misaligned)
+       b       L(end)
 
-.Lcal_cmpresult:
-       /*
-       * reversed the byte-order as big-endian,then CLZ can find the most
-       * significant zero bits.
-       */
-CPU_LE( rev    syndrome, syndrome )
-CPU_LE( rev    data1, data1 )
-CPU_LE( rev    data2, data2 )
-
-       /*
-       * For big-endian we cannot use the trick with the syndrome value
-       * as carry-propagation can corrupt the upper bits if the trailing
-       * bytes in the string contain 0x01.
-       * However, if there is no NUL byte in the dword, we can generate
-       * the result directly.  We cannot just subtract the bytes as the
-       * MSB might be significant.
-       */
-CPU_BE( cbnz   has_nul, 1f )
-CPU_BE( cmp    data1, data2 )
-CPU_BE( cset   result, ne )
-CPU_BE( cneg   result, result, lo )
-CPU_BE( ret )
-CPU_BE( 1: )
-       /*Re-compute the NUL-byte detection, using a byte-reversed value. */
-CPU_BE(        rev     tmp3, data1 )
-CPU_BE(        sub     tmp1, tmp3, zeroones )
-CPU_BE(        orr     tmp2, tmp3, #REP8_7f )
-CPU_BE(        bic     has_nul, tmp1, tmp2 )
-CPU_BE(        rev     has_nul, has_nul )
-CPU_BE(        orr     syndrome, diff, has_nul )
-
-       clz     pos, syndrome
-       /*
-       * The MS-non-zero bit of the syndrome marks either the first bit
-       * that is different, or the top bit of the first zero byte.
-       * Shifting left now will bring the critical information into the
-       * top bits.
-       */
-       lsl     data1, data1, pos
-       lsl     data2, data2, pos
-       /*
-       * But we need to zero-extend (char is unsigned) the value and then
-       * perform a signed 32-bit subtraction.
-       */
-       lsr     data1, data1, #56
-       sub     result, data1, data2, lsr #56
+L(done):
+       sub     result, data1, data2
        ret
+
 SYM_FUNC_END_PI(strcmp)
 EXPORT_SYMBOL_NOKASAN(strcmp)
index ee3ed88..35fbdb7 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
+ * Copyright (c) 2013-2021, Arm Limited.
  *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
+ * Adapted from the original at:
+ * https://github.com/ARM-software/optimized-routines/blob/98e4d6a5c13c8e54/string/aarch64/strlen.S
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-/*
- * calculate the length of a string
+/* Assumptions:
  *
- * Parameters:
- *     x0 - const string pointer
- * Returns:
- *     x0 - the return length of specific string
+ * ARMv8-a, AArch64, unaligned accesses, min page size 4k.
  */
 
+#define L(label) .L ## label
+
 /* Arguments and results.  */
-srcin          .req    x0
-len            .req    x0
+#define srcin          x0
+#define len            x0
 
 /* Locals and temporaries.  */
-src            .req    x1
-data1          .req    x2
-data2          .req    x3
-data2a         .req    x4
-has_nul1       .req    x5
-has_nul2       .req    x6
-tmp1           .req    x7
-tmp2           .req    x8
-tmp3           .req    x9
-tmp4           .req    x10
-zeroones       .req    x11
-pos            .req    x12
+#define src            x1
+#define data1          x2
+#define data2          x3
+#define has_nul1       x4
+#define has_nul2       x5
+#define tmp1           x4
+#define tmp2           x5
+#define tmp3           x6
+#define tmp4           x7
+#define zeroones       x8
+
+       /* NUL detection works on the principle that (X - 1) & (~X) & 0x80
+          (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
+          can be done in parallel across the entire word. A faster check
+          (X - 1) & 0x80 is zero for non-NUL ASCII characters, but gives
+          false hits for characters 129..255.  */
 
 #define REP8_01 0x0101010101010101
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
+#define MIN_PAGE_SIZE 4096
+
+       /* Since strings are short on average, we check the first 16 bytes
+          of the string for a NUL character.  In order to do an unaligned ldp
+          safely we have to do a page cross check first.  If there is a NUL
+          byte we calculate the length from the 2 8-byte words using
+          conditional select to reduce branch mispredictions (it is unlikely
+          strlen will be repeatedly called on strings with the same length).
+
+          If the string is longer than 16 bytes, we align src so don't need
+          further page cross checks, and process 32 bytes per iteration
+          using the fast NUL check.  If we encounter non-ASCII characters,
+          fallback to a second loop using the full NUL check.
+
+          If the page cross check fails, we read 16 bytes from an aligned
+          address, remove any characters before the string, and continue
+          in the main loop using aligned loads.  Since strings crossing a
+          page in the first 16 bytes are rare (probability of
+          16/MIN_PAGE_SIZE ~= 0.4%), this case does not need to be optimized.
+
+          AArch64 systems have a minimum page size of 4k.  We don't bother
+          checking for larger page sizes - the cost of setting up the correct
+          page size is just not worth the extra gain from a small reduction in
+          the cases taking the slow path.  Note that we only care about
+          whether the first fetch, which may be misaligned, crosses a page
+          boundary.  */
+
 SYM_FUNC_START_WEAK_PI(strlen)
-       mov     zeroones, #REP8_01
-       bic     src, srcin, #15
-       ands    tmp1, srcin, #15
-       b.ne    .Lmisaligned
-       /*
-       * NUL detection works on the principle that (X - 1) & (~X) & 0x80
-       * (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
-       * can be done in parallel across the entire word.
-       */
-       /*
-       * The inner loop deals with two Dwords at a time. This has a
-       * slightly higher start-up cost, but we should win quite quickly,
-       * especially on cores with a high number of issue slots per
-       * cycle, as we get much better parallelism out of the operations.
-       */
-.Lloop:
-       ldp     data1, data2, [src], #16
-.Lrealigned:
+       and     tmp1, srcin, MIN_PAGE_SIZE - 1
+       mov     zeroones, REP8_01
+       cmp     tmp1, MIN_PAGE_SIZE - 16
+       b.gt    L(page_cross)
+       ldp     data1, data2, [srcin]
+#ifdef __AARCH64EB__
+       /* For big-endian, carry propagation (if the final byte in the
+          string is 0x01) means we cannot use has_nul1/2 directly.
+          Since we expect strings to be small and early-exit,
+          byte-swap the data now so has_null1/2 will be correct.  */
+       rev     data1, data1
+       rev     data2, data2
+#endif
        sub     tmp1, data1, zeroones
-       orr     tmp2, data1, #REP8_7f
+       orr     tmp2, data1, REP8_7f
        sub     tmp3, data2, zeroones
-       orr     tmp4, data2, #REP8_7f
-       bic     has_nul1, tmp1, tmp2
-       bics    has_nul2, tmp3, tmp4
-       ccmp    has_nul1, #0, #0, eq    /* NZCV = 0000  */
-       b.eq    .Lloop
+       orr     tmp4, data2, REP8_7f
+       bics    has_nul1, tmp1, tmp2
+       bic     has_nul2, tmp3, tmp4
+       ccmp    has_nul2, 0, 0, eq
+       beq     L(main_loop_entry)
+
+       /* Enter with C = has_nul1 == 0.  */
+       csel    has_nul1, has_nul1, has_nul2, cc
+       mov     len, 8
+       rev     has_nul1, has_nul1
+       clz     tmp1, has_nul1
+       csel    len, xzr, len, cc
+       add     len, len, tmp1, lsr 3
+       ret
 
+       /* The inner loop processes 32 bytes per iteration and uses the fast
+          NUL check.  If we encounter non-ASCII characters, use a second
+          loop with the accurate NUL check.  */
+       .p2align 4
+L(main_loop_entry):
+       bic     src, srcin, 15
+       sub     src, src, 16
+L(main_loop):
+       ldp     data1, data2, [src, 32]!
+L(page_cross_entry):
+       sub     tmp1, data1, zeroones
+       sub     tmp3, data2, zeroones
+       orr     tmp2, tmp1, tmp3
+       tst     tmp2, zeroones, lsl 7
+       bne     1f
+       ldp     data1, data2, [src, 16]
+       sub     tmp1, data1, zeroones
+       sub     tmp3, data2, zeroones
+       orr     tmp2, tmp1, tmp3
+       tst     tmp2, zeroones, lsl 7
+       beq     L(main_loop)
+       add     src, src, 16
+1:
+       /* The fast check failed, so do the slower, accurate NUL check.  */
+       orr     tmp2, data1, REP8_7f
+       orr     tmp4, data2, REP8_7f
+       bics    has_nul1, tmp1, tmp2
+       bic     has_nul2, tmp3, tmp4
+       ccmp    has_nul2, 0, 0, eq
+       beq     L(nonascii_loop)
+
+       /* Enter with C = has_nul1 == 0.  */
+L(tail):
+#ifdef __AARCH64EB__
+       /* For big-endian, carry propagation (if the final byte in the
+          string is 0x01) means we cannot use has_nul1/2 directly.  The
+          easiest way to get the correct byte is to byte-swap the data
+          and calculate the syndrome a second time.  */
+       csel    data1, data1, data2, cc
+       rev     data1, data1
+       sub     tmp1, data1, zeroones
+       orr     tmp2, data1, REP8_7f
+       bic     has_nul1, tmp1, tmp2
+#else
+       csel    has_nul1, has_nul1, has_nul2, cc
+#endif
        sub     len, src, srcin
-       cbz     has_nul1, .Lnul_in_data2
-CPU_BE(        mov     data2, data1 )  /*prepare data to re-calculate the syndrome*/
-       sub     len, len, #8
-       mov     has_nul2, has_nul1
-.Lnul_in_data2:
-       /*
-       * For big-endian, carry propagation (if the final byte in the
-       * string is 0x01) means we cannot use has_nul directly.  The
-       * easiest way to get the correct byte is to byte-swap the data
-       * and calculate the syndrome a second time.
-       */
-CPU_BE( rev    data2, data2 )
-CPU_BE( sub    tmp1, data2, zeroones )
-CPU_BE( orr    tmp2, data2, #REP8_7f )
-CPU_BE( bic    has_nul2, tmp1, tmp2 )
-
-       sub     len, len, #8
-       rev     has_nul2, has_nul2
-       clz     pos, has_nul2
-       add     len, len, pos, lsr #3           /* Bits to bytes.  */
+       rev     has_nul1, has_nul1
+       add     tmp2, len, 8
+       clz     tmp1, has_nul1
+       csel    len, len, tmp2, cc
+       add     len, len, tmp1, lsr 3
        ret
 
-.Lmisaligned:
-       cmp     tmp1, #8
-       neg     tmp1, tmp1
-       ldp     data1, data2, [src], #16
-       lsl     tmp1, tmp1, #3          /* Bytes beyond alignment -> bits.  */
-       mov     tmp2, #~0
-       /* Big-endian.  Early bytes are at MSB.  */
-CPU_BE( lsl    tmp2, tmp2, tmp1 )      /* Shift (tmp1 & 63).  */
+L(nonascii_loop):
+       ldp     data1, data2, [src, 16]!
+       sub     tmp1, data1, zeroones
+       orr     tmp2, data1, REP8_7f
+       sub     tmp3, data2, zeroones
+       orr     tmp4, data2, REP8_7f
+       bics    has_nul1, tmp1, tmp2
+       bic     has_nul2, tmp3, tmp4
+       ccmp    has_nul2, 0, 0, eq
+       bne     L(tail)
+       ldp     data1, data2, [src, 16]!
+       sub     tmp1, data1, zeroones
+       orr     tmp2, data1, REP8_7f
+       sub     tmp3, data2, zeroones
+       orr     tmp4, data2, REP8_7f
+       bics    has_nul1, tmp1, tmp2
+       bic     has_nul2, tmp3, tmp4
+       ccmp    has_nul2, 0, 0, eq
+       beq     L(nonascii_loop)
+       b       L(tail)
+
+       /* Load 16 bytes from [srcin & ~15] and force the bytes that precede
+          srcin to 0x7f, so we ignore any NUL bytes before the string.
+          Then continue in the aligned loop.  */
+L(page_cross):
+       bic     src, srcin, 15
+       ldp     data1, data2, [src]
+       lsl     tmp1, srcin, 3
+       mov     tmp4, -1
+#ifdef __AARCH64EB__
+       /* Big-endian.  Early bytes are at MSB.  */
+       lsr     tmp1, tmp4, tmp1        /* Shift (tmp1 & 63).  */
+#else
        /* Little-endian.  Early bytes are at LSB.  */
-CPU_LE( lsr    tmp2, tmp2, tmp1 )      /* Shift (tmp1 & 63).  */
+       lsl     tmp1, tmp4, tmp1        /* Shift (tmp1 & 63).  */
+#endif
+       orr     tmp1, tmp1, REP8_80
+       orn     data1, data1, tmp1
+       orn     tmp2, data2, tmp1
+       tst     srcin, 8
+       csel    data1, data1, tmp4, eq
+       csel    data2, data2, tmp2, eq
+       b       L(page_cross_entry)
 
-       orr     data1, data1, tmp2
-       orr     data2a, data2, tmp2
-       csinv   data1, data1, xzr, le
-       csel    data2, data2, data2a, le
-       b       .Lrealigned
 SYM_FUNC_END_PI(strlen)
 EXPORT_SYMBOL_NOKASAN(strlen)
index 2a7ee94..48d44f7 100644 (file)
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (C) 2013 ARM Ltd.
- * Copyright (C) 2013 Linaro.
+ * Copyright (c) 2013-2021, Arm Limited.
  *
- * This code is based on glibc cortex strings work originally authored by Linaro
- * be found @
- *
- * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
- * files/head:/src/aarch64/
+ * Adapted from the original at:
+ * https://github.com/ARM-software/optimized-routines/blob/e823e3abf5f89ecb/string/aarch64/strncmp.S
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-/*
- * compare two strings
+/* Assumptions:
  *
- * Parameters:
- *  x0 - const string 1 pointer
- *  x1 - const string 2 pointer
- *  x2 - the maximal length to be compared
- * Returns:
- *  x0 - an integer less than, equal to, or greater than zero if s1 is found,
- *     respectively, to be less than, to match, or be greater than s2.
+ * ARMv8-a, AArch64
  */
 
+#define L(label) .L ## label
+
 #define REP8_01 0x0101010101010101
 #define REP8_7f 0x7f7f7f7f7f7f7f7f
 #define REP8_80 0x8080808080808080
 
 /* Parameters and result.  */
-src1           .req    x0
-src2           .req    x1
-limit          .req    x2
-result         .req    x0
+#define src1           x0
+#define src2           x1
+#define limit          x2
+#define result         x0
 
 /* Internal variables.  */
-data1          .req    x3
-data1w         .req    w3
-data2          .req    x4
-data2w         .req    w4
-has_nul                .req    x5
-diff           .req    x6
-syndrome       .req    x7
-tmp1           .req    x8
-tmp2           .req    x9
-tmp3           .req    x10
-zeroones       .req    x11
-pos            .req    x12
-limit_wd       .req    x13
-mask           .req    x14
-endloop                .req    x15
+#define data1          x3
+#define data1w         w3
+#define data2          x4
+#define data2w         w4
+#define has_nul                x5
+#define diff           x6
+#define syndrome       x7
+#define tmp1           x8
+#define tmp2           x9
+#define tmp3           x10
+#define zeroones       x11
+#define pos            x12
+#define limit_wd       x13
+#define mask           x14
+#define endloop                x15
+#define count          mask
 
 SYM_FUNC_START_WEAK_PI(strncmp)
-       cbz     limit, .Lret0
+       cbz     limit, L(ret0)
        eor     tmp1, src1, src2
        mov     zeroones, #REP8_01
        tst     tmp1, #7
-       b.ne    .Lmisaligned8
-       ands    tmp1, src1, #7
-       b.ne    .Lmutual_align
+       and     count, src1, #7
+       b.ne    L(misaligned8)
+       cbnz    count, L(mutual_align)
        /* Calculate the number of full and partial words -1.  */
-       /*
-       * when limit is mulitply of 8, if not sub 1,
-       * the judgement of last dword will wrong.
-       */
-       sub     limit_wd, limit, #1 /* limit != 0, so no underflow.  */
-       lsr     limit_wd, limit_wd, #3  /* Convert to Dwords.  */
+       sub     limit_wd, limit, #1     /* limit != 0, so no underflow.  */
+       lsr     limit_wd, limit_wd, #3  /* Convert to Dwords.  */
 
-       /*
-       * NUL detection works on the principle that (X - 1) & (~X) & 0x80
-       * (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
-       * can be done in parallel across the entire word.
-       */
-.Lloop_aligned:
+       /* NUL detection works on the principle that (X - 1) & (~X) & 0x80
+          (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
+          can be done in parallel across the entire word.  */
+       .p2align 4
+L(loop_aligned):
        ldr     data1, [src1], #8
        ldr     data2, [src2], #8
-.Lstart_realigned:
+L(start_realigned):
        subs    limit_wd, limit_wd, #1
        sub     tmp1, data1, zeroones
        orr     tmp2, data1, #REP8_7f
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       csinv   endloop, diff, xzr, pl  /* Last Dword or differences.*/
-       bics    has_nul, tmp1, tmp2 /* Non-zero if NUL terminator.  */
+       eor     diff, data1, data2      /* Non-zero if differences found.  */
+       csinv   endloop, diff, xzr, pl  /* Last Dword or differences.  */
+       bics    has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
        ccmp    endloop, #0, #0, eq
-       b.eq    .Lloop_aligned
+       b.eq    L(loop_aligned)
+       /* End of main loop */
 
-       /*Not reached the limit, must have found the end or a diff.  */
-       tbz     limit_wd, #63, .Lnot_limit
+       /* Not reached the limit, must have found the end or a diff.  */
+       tbz     limit_wd, #63, L(not_limit)
 
        /* Limit % 8 == 0 => all bytes significant.  */
        ands    limit, limit, #7
-       b.eq    .Lnot_limit
+       b.eq    L(not_limit)
 
-       lsl     limit, limit, #3    /* Bits -> bytes.  */
+       lsl     limit, limit, #3        /* Bits -> bytes.  */
        mov     mask, #~0
-CPU_BE( lsr    mask, mask, limit )
-CPU_LE( lsl    mask, mask, limit )
+#ifdef __AARCH64EB__
+       lsr     mask, mask, limit
+#else
+       lsl     mask, mask, limit
+#endif
        bic     data1, data1, mask
        bic     data2, data2, mask
 
        /* Make sure that the NUL byte is marked in the syndrome.  */
        orr     has_nul, has_nul, mask
 
-.Lnot_limit:
+L(not_limit):
        orr     syndrome, diff, has_nul
-       b       .Lcal_cmpresult
 
-.Lmutual_align:
-       /*
-       * Sources are mutually aligned, but are not currently at an
-       * alignment boundary.  Round down the addresses and then mask off
-       * the bytes that precede the start point.
-       * We also need to adjust the limit calculations, but without
-       * overflowing if the limit is near ULONG_MAX.
-       */
+#ifndef        __AARCH64EB__
+       rev     syndrome, syndrome
+       rev     data1, data1
+       /* The MS-non-zero bit of the syndrome marks either the first bit
+          that is different, or the top bit of the first zero byte.
+          Shifting left now will bring the critical information into the
+          top bits.  */
+       clz     pos, syndrome
+       rev     data2, data2
+       lsl     data1, data1, pos
+       lsl     data2, data2, pos
+       /* But we need to zero-extend (char is unsigned) the value and then
+          perform a signed 32-bit subtraction.  */
+       lsr     data1, data1, #56
+       sub     result, data1, data2, lsr #56
+       ret
+#else
+       /* For big-endian we cannot use the trick with the syndrome value
+          as carry-propagation can corrupt the upper bits if the trailing
+          bytes in the string contain 0x01.  */
+       /* However, if there is no NUL byte in the dword, we can generate
+          the result directly.  We can't just subtract the bytes as the
+          MSB might be significant.  */
+       cbnz    has_nul, 1f
+       cmp     data1, data2
+       cset    result, ne
+       cneg    result, result, lo
+       ret
+1:
+       /* Re-compute the NUL-byte detection, using a byte-reversed value.  */
+       rev     tmp3, data1
+       sub     tmp1, tmp3, zeroones
+       orr     tmp2, tmp3, #REP8_7f
+       bic     has_nul, tmp1, tmp2
+       rev     has_nul, has_nul
+       orr     syndrome, diff, has_nul
+       clz     pos, syndrome
+       /* The MS-non-zero bit of the syndrome marks either the first bit
+          that is different, or the top bit of the first zero byte.
+          Shifting left now will bring the critical information into the
+          top bits.  */
+       lsl     data1, data1, pos
+       lsl     data2, data2, pos
+       /* But we need to zero-extend (char is unsigned) the value and then
+          perform a signed 32-bit subtraction.  */
+       lsr     data1, data1, #56
+       sub     result, data1, data2, lsr #56
+       ret
+#endif
+
+L(mutual_align):
+       /* Sources are mutually aligned, but are not currently at an
+          alignment boundary.  Round down the addresses and then mask off
+          the bytes that precede the start point.
+          We also need to adjust the limit calculations, but without
+          overflowing if the limit is near ULONG_MAX.  */
        bic     src1, src1, #7
        bic     src2, src2, #7
        ldr     data1, [src1], #8
-       neg     tmp3, tmp1, lsl #3  /* 64 - bits(bytes beyond align). */
+       neg     tmp3, count, lsl #3     /* 64 - bits(bytes beyond align). */
        ldr     data2, [src2], #8
        mov     tmp2, #~0
-       sub     limit_wd, limit, #1 /* limit != 0, so no underflow.  */
+       sub     limit_wd, limit, #1     /* limit != 0, so no underflow.  */
+#ifdef __AARCH64EB__
        /* Big-endian.  Early bytes are at MSB.  */
-CPU_BE( lsl    tmp2, tmp2, tmp3 )      /* Shift (tmp1 & 63).  */
+       lsl     tmp2, tmp2, tmp3        /* Shift (count & 63).  */
+#else
        /* Little-endian.  Early bytes are at LSB.  */
-CPU_LE( lsr    tmp2, tmp2, tmp3 )      /* Shift (tmp1 & 63).  */
-
+       lsr     tmp2, tmp2, tmp3        /* Shift (count & 63).  */
+#endif
        and     tmp3, limit_wd, #7
        lsr     limit_wd, limit_wd, #3
-       /* Adjust the limit. Only low 3 bits used, so overflow irrelevant.*/
-       add     limit, limit, tmp1
-       add     tmp3, tmp3, tmp1
+       /* Adjust the limit. Only low 3 bits used, so overflow irrelevant.  */
+       add     limit, limit, count
+       add     tmp3, tmp3, count
        orr     data1, data1, tmp2
        orr     data2, data2, tmp2
        add     limit_wd, limit_wd, tmp3, lsr #3
-       b       .Lstart_realigned
+       b       L(start_realigned)
+
+       .p2align 4
+       /* Don't bother with dwords for up to 16 bytes.  */
+L(misaligned8):
+       cmp     limit, #16
+       b.hs    L(try_misaligned_words)
 
-/*when src1 offset is not equal to src2 offset...*/
-.Lmisaligned8:
-       cmp     limit, #8
-       b.lo    .Ltiny8proc /*limit < 8... */
-       /*
-       * Get the align offset length to compare per byte first.
-       * After this process, one string's address will be aligned.*/
-       and     tmp1, src1, #7
-       neg     tmp1, tmp1
-       add     tmp1, tmp1, #8
-       and     tmp2, src2, #7
-       neg     tmp2, tmp2
-       add     tmp2, tmp2, #8
-       subs    tmp3, tmp1, tmp2
-       csel    pos, tmp1, tmp2, hi /*Choose the maximum. */
-       /*
-       * Here, limit is not less than 8, so directly run .Ltinycmp
-       * without checking the limit.*/
-       sub     limit, limit, pos
-.Ltinycmp:
+L(byte_loop):
+       /* Perhaps we can do better than this.  */
        ldrb    data1w, [src1], #1
        ldrb    data2w, [src2], #1
-       subs    pos, pos, #1
-       ccmp    data1w, #1, #0, ne  /* NZCV = 0b0000.  */
-       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
-       b.eq    .Ltinycmp
-       cbnz    pos, 1f /*find the null or unequal...*/
-       cmp     data1w, #1
-       ccmp    data1w, data2w, #0, cs
-       b.eq    .Lstart_align /*the last bytes are equal....*/
-1:
+       subs    limit, limit, #1
+       ccmp    data1w, #1, #0, hi      /* NZCV = 0b0000.  */
+       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
+       b.eq    L(byte_loop)
+L(done):
        sub     result, data1, data2
        ret
-
-.Lstart_align:
+       /* Align the SRC1 to a dword by doing a bytewise compare and then do
+          the dword loop.  */
+L(try_misaligned_words):
        lsr     limit_wd, limit, #3
-       cbz     limit_wd, .Lremain8
-       /*process more leading bytes to make str1 aligned...*/
-       ands    xzr, src1, #7
-       b.eq    .Lrecal_offset
-       add     src1, src1, tmp3        /*tmp3 is positive in this branch.*/
-       add     src2, src2, tmp3
-       ldr     data1, [src1], #8
-       ldr     data2, [src2], #8
+       cbz     count, L(do_misaligned)
 
-       sub     limit, limit, tmp3
+       neg     count, count
+       and     count, count, #7
+       sub     limit, limit, count
        lsr     limit_wd, limit, #3
-       subs    limit_wd, limit_wd, #1
 
-       sub     tmp1, data1, zeroones
-       orr     tmp2, data1, #REP8_7f
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       csinv   endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
-       bics    has_nul, tmp1, tmp2
-       ccmp    endloop, #0, #0, eq /*has_null is ZERO: no null byte*/
-       b.ne    .Lunequal_proc
-       /*How far is the current str2 from the alignment boundary...*/
-       and     tmp3, tmp3, #7
-.Lrecal_offset:
-       neg     pos, tmp3
-.Lloopcmp_proc:
-       /*
-       * Divide the eight bytes into two parts. First,backwards the src2
-       * to an alignment boundary,load eight bytes from the SRC2 alignment
-       * boundary,then compare with the relative bytes from SRC1.
-       * If all 8 bytes are equal,then start the second part's comparison.
-       * Otherwise finish the comparison.
-       * This special handle can garantee all the accesses are in the
-       * thread/task space in avoid to overrange access.
-       */
-       ldr     data1, [src1,pos]
-       ldr     data2, [src2,pos]
-       sub     tmp1, data1, zeroones
-       orr     tmp2, data1, #REP8_7f
-       bics    has_nul, tmp1, tmp2 /* Non-zero if NUL terminator.  */
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       csinv   endloop, diff, xzr, eq
-       cbnz    endloop, .Lunequal_proc
+L(page_end_loop):
+       ldrb    data1w, [src1], #1
+       ldrb    data2w, [src2], #1
+       cmp     data1w, #1
+       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
+       b.ne    L(done)
+       subs    count, count, #1
+       b.hi    L(page_end_loop)
+
+L(do_misaligned):
+       /* Prepare ourselves for the next page crossing.  Unlike the aligned
+          loop, we fetch 1 less dword because we risk crossing bounds on
+          SRC2.  */
+       mov     count, #8
+       subs    limit_wd, limit_wd, #1
+       b.lo    L(done_loop)
+L(loop_misaligned):
+       and     tmp2, src2, #0xff8
+       eor     tmp2, tmp2, #0xff8
+       cbz     tmp2, L(page_end_loop)
 
-       /*The second part process*/
        ldr     data1, [src1], #8
        ldr     data2, [src2], #8
-       subs    limit_wd, limit_wd, #1
        sub     tmp1, data1, zeroones
        orr     tmp2, data1, #REP8_7f
-       eor     diff, data1, data2  /* Non-zero if differences found.  */
-       csinv   endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
-       bics    has_nul, tmp1, tmp2
-       ccmp    endloop, #0, #0, eq /*has_null is ZERO: no null byte*/
-       b.eq    .Lloopcmp_proc
-
-.Lunequal_proc:
-       orr     syndrome, diff, has_nul
-       cbz     syndrome, .Lremain8
-.Lcal_cmpresult:
-       /*
-       * reversed the byte-order as big-endian,then CLZ can find the most
-       * significant zero bits.
-       */
-CPU_LE( rev    syndrome, syndrome )
-CPU_LE( rev    data1, data1 )
-CPU_LE( rev    data2, data2 )
-       /*
-       * For big-endian we cannot use the trick with the syndrome value
-       * as carry-propagation can corrupt the upper bits if the trailing
-       * bytes in the string contain 0x01.
-       * However, if there is no NUL byte in the dword, we can generate
-       * the result directly.  We can't just subtract the bytes as the
-       * MSB might be significant.
-       */
-CPU_BE( cbnz   has_nul, 1f )
-CPU_BE( cmp    data1, data2 )
-CPU_BE( cset   result, ne )
-CPU_BE( cneg   result, result, lo )
-CPU_BE( ret )
-CPU_BE( 1: )
-       /* Re-compute the NUL-byte detection, using a byte-reversed value.*/
-CPU_BE( rev    tmp3, data1 )
-CPU_BE( sub    tmp1, tmp3, zeroones )
-CPU_BE( orr    tmp2, tmp3, #REP8_7f )
-CPU_BE( bic    has_nul, tmp1, tmp2 )
-CPU_BE( rev    has_nul, has_nul )
-CPU_BE( orr    syndrome, diff, has_nul )
-       /*
-       * The MS-non-zero bit of the syndrome marks either the first bit
-       * that is different, or the top bit of the first zero byte.
-       * Shifting left now will bring the critical information into the
-       * top bits.
-       */
-       clz     pos, syndrome
-       lsl     data1, data1, pos
-       lsl     data2, data2, pos
-       /*
-       * But we need to zero-extend (char is unsigned) the value and then
-       * perform a signed 32-bit subtraction.
-       */
-       lsr     data1, data1, #56
-       sub     result, data1, data2, lsr #56
-       ret
-
-.Lremain8:
-       /* Limit % 8 == 0 => all bytes significant.  */
-       ands    limit, limit, #7
-       b.eq    .Lret0
-.Ltiny8proc:
-       ldrb    data1w, [src1], #1
-       ldrb    data2w, [src2], #1
-       subs    limit, limit, #1
+       eor     diff, data1, data2      /* Non-zero if differences found.  */
+       bics    has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
+       ccmp    diff, #0, #0, eq
+       b.ne    L(not_limit)
+       subs    limit_wd, limit_wd, #1
+       b.pl    L(loop_misaligned)
 
-       ccmp    data1w, #1, #0, ne  /* NZCV = 0b0000.  */
-       ccmp    data1w, data2w, #0, cs  /* NZCV = 0b0000.  */
-       b.eq    .Ltiny8proc
-       sub     result, data1, data2
-       ret
+L(done_loop):
+       /* We found a difference or a NULL before the limit was reached.  */
+       and     limit, limit, #7
+       cbz     limit, L(not_limit)
+       /* Read the last word.  */
+       sub     src1, src1, 8
+       sub     src2, src2, 8
+       ldr     data1, [src1, limit]
+       ldr     data2, [src2, limit]
+       sub     tmp1, data1, zeroones
+       orr     tmp2, data1, #REP8_7f
+       eor     diff, data1, data2      /* Non-zero if differences found.  */
+       bics    has_nul, tmp1, tmp2     /* Non-zero if NUL terminator.  */
+       ccmp    diff, #0, #0, eq
+       b.ne    L(not_limit)
 
-.Lret0:
+L(ret0):
        mov     result, #0
        ret
+
 SYM_FUNC_END_PI(strncmp)
 EXPORT_SYMBOL_NOKASAN(strncmp)
index c83bb5a..baee229 100644 (file)
@@ -15,7 +15,7 @@ void memcpy_flushcache(void *dst, const void *src, size_t cnt)
         * barrier to order the cache maintenance against the memcpy.
         */
        memcpy(dst, src, cnt);
-       __clean_dcache_area_pop(dst, cnt);
+       dcache_clean_pop((unsigned long)dst, (unsigned long)dst + cnt);
 }
 EXPORT_SYMBOL_GPL(memcpy_flushcache);
 
@@ -33,6 +33,6 @@ unsigned long __copy_user_flushcache(void *to, const void __user *from,
        rc = raw_copy_from_user(to, from, n);
 
        /* See above */
-       __clean_dcache_area_pop(to, n - rc);
+       dcache_clean_pop((unsigned long)to, (unsigned long)to + n - rc);
        return rc;
 }
index 2d881f3..5051b3c 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/asm-uaccess.h>
 
 /*
- *     flush_icache_range(start,end)
+ *     caches_clean_inval_pou_macro(start,end) [fixup]
  *
  *     Ensure that the I and D caches are coherent within specified region.
  *     This is typically used when code has been written to a memory region,
  *
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
+ *     - fixup   - optional label to branch to on user fault
  */
-SYM_FUNC_START(__flush_icache_range)
-       /* FALLTHROUGH */
+.macro caches_clean_inval_pou_macro, fixup
+alternative_if ARM64_HAS_CACHE_IDC
+       dsb     ishst
+       b       .Ldc_skip_\@
+alternative_else_nop_endif
+       mov     x2, x0
+       mov     x3, x1
+       dcache_by_line_op cvau, ish, x2, x3, x4, x5, \fixup
+.Ldc_skip_\@:
+alternative_if ARM64_HAS_CACHE_DIC
+       isb
+       b       .Lic_skip_\@
+alternative_else_nop_endif
+       invalidate_icache_by_line x0, x1, x2, x3, \fixup
+.Lic_skip_\@:
+.endm
 
 /*
- *     __flush_cache_user_range(start,end)
+ *     caches_clean_inval_pou(start,end)
  *
  *     Ensure that the I and D caches are coherent within specified region.
  *     This is typically used when code has been written to a memory region,
@@ -37,117 +52,103 @@ SYM_FUNC_START(__flush_icache_range)
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-SYM_FUNC_START(__flush_cache_user_range)
+SYM_FUNC_START(caches_clean_inval_pou)
+       caches_clean_inval_pou_macro
+       ret
+SYM_FUNC_END(caches_clean_inval_pou)
+
+/*
+ *     caches_clean_inval_user_pou(start,end)
+ *
+ *     Ensure that the I and D caches are coherent within specified region.
+ *     This is typically used when code has been written to a memory region,
+ *     and will be executed.
+ *
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+SYM_FUNC_START(caches_clean_inval_user_pou)
        uaccess_ttbr0_enable x2, x3, x4
-alternative_if ARM64_HAS_CACHE_IDC
-       dsb     ishst
-       b       7f
-alternative_else_nop_endif
-       dcache_line_size x2, x3
-       sub     x3, x2, #1
-       bic     x4, x0, x3
-1:
-user_alt 9f, "dc cvau, x4",  "dc civac, x4",  ARM64_WORKAROUND_CLEAN_CACHE
-       add     x4, x4, x2
-       cmp     x4, x1
-       b.lo    1b
-       dsb     ish
 
-7:
-alternative_if ARM64_HAS_CACHE_DIC
-       isb
-       b       8f
-alternative_else_nop_endif
-       invalidate_icache_by_line x0, x1, x2, x3, 9f
-8:     mov     x0, #0
+       caches_clean_inval_pou_macro 2f
+       mov     x0, xzr
 1:
        uaccess_ttbr0_disable x1, x2
        ret
-9:
+2:
        mov     x0, #-EFAULT
        b       1b
-SYM_FUNC_END(__flush_icache_range)
-SYM_FUNC_END(__flush_cache_user_range)
+SYM_FUNC_END(caches_clean_inval_user_pou)
 
 /*
- *     invalidate_icache_range(start,end)
+ *     icache_inval_pou(start,end)
  *
  *     Ensure that the I cache is invalid within specified region.
  *
  *     - start   - virtual start address of region
  *     - end     - virtual end address of region
  */
-SYM_FUNC_START(invalidate_icache_range)
+SYM_FUNC_START(icache_inval_pou)
 alternative_if ARM64_HAS_CACHE_DIC
-       mov     x0, xzr
        isb
        ret
 alternative_else_nop_endif
 
-       uaccess_ttbr0_enable x2, x3, x4
-
-       invalidate_icache_by_line x0, x1, x2, x3, 2f
-       mov     x0, xzr
-1:
-       uaccess_ttbr0_disable x1, x2
+       invalidate_icache_by_line x0, x1, x2, x3
        ret
-2:
-       mov     x0, #-EFAULT
-       b       1b
-SYM_FUNC_END(invalidate_icache_range)
+SYM_FUNC_END(icache_inval_pou)
 
 /*
- *     __flush_dcache_area(kaddr, size)
+ *     dcache_clean_inval_poc(start, end)
  *
- *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     Ensure that any D-cache lines for the interval [start, end)
  *     are cleaned and invalidated to the PoC.
  *
- *     - kaddr   - kernel address
- *     - size    - size in question
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
  */
-SYM_FUNC_START_PI(__flush_dcache_area)
+SYM_FUNC_START_PI(dcache_clean_inval_poc)
        dcache_by_line_op civac, sy, x0, x1, x2, x3
        ret
-SYM_FUNC_END_PI(__flush_dcache_area)
+SYM_FUNC_END_PI(dcache_clean_inval_poc)
 
 /*
- *     __clean_dcache_area_pou(kaddr, size)
+ *     dcache_clean_pou(start, end)
  *
- *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     Ensure that any D-cache lines for the interval [start, end)
  *     are cleaned to the PoU.
  *
- *     - kaddr   - kernel address
- *     - size    - size in question
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
  */
-SYM_FUNC_START(__clean_dcache_area_pou)
+SYM_FUNC_START(dcache_clean_pou)
 alternative_if ARM64_HAS_CACHE_IDC
        dsb     ishst
        ret
 alternative_else_nop_endif
        dcache_by_line_op cvau, ish, x0, x1, x2, x3
        ret
-SYM_FUNC_END(__clean_dcache_area_pou)
+SYM_FUNC_END(dcache_clean_pou)
 
 /*
- *     __inval_dcache_area(kaddr, size)
+ *     dcache_inval_poc(start, end)
  *
- *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     Ensure that any D-cache lines for the interval [start, end)
  *     are invalidated. Any partial lines at the ends of the interval are
  *     also cleaned to PoC to prevent data loss.
  *
- *     - kaddr   - kernel address
- *     - size    - size in question
+ *     - start   - kernel start address of region
+ *     - end     - kernel end address of region
  */
 SYM_FUNC_START_LOCAL(__dma_inv_area)
-SYM_FUNC_START_PI(__inval_dcache_area)
+SYM_FUNC_START_PI(dcache_inval_poc)
        /* FALLTHROUGH */
 
 /*
- *     __dma_inv_area(start, size)
+ *     __dma_inv_area(start, end)
  *     - start   - virtual start address of region
- *     - size    - size in question
+ *     - end     - virtual end address of region
  */
-       add     x1, x1, x0
        dcache_line_size x2, x3
        sub     x3, x2, #1
        tst     x1, x3                          // end cache line aligned?
@@ -165,48 +166,48 @@ SYM_FUNC_START_PI(__inval_dcache_area)
        b.lo    2b
        dsb     sy
        ret
-SYM_FUNC_END_PI(__inval_dcache_area)
+SYM_FUNC_END_PI(dcache_inval_poc)
 SYM_FUNC_END(__dma_inv_area)
 
 /*
- *     __clean_dcache_area_poc(kaddr, size)
+ *     dcache_clean_poc(start, end)
  *
- *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     Ensure that any D-cache lines for the interval [start, end)
  *     are cleaned to the PoC.
  *
- *     - kaddr   - kernel address
- *     - size    - size in question
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
  */
 SYM_FUNC_START_LOCAL(__dma_clean_area)
-SYM_FUNC_START_PI(__clean_dcache_area_poc)
+SYM_FUNC_START_PI(dcache_clean_poc)
        /* FALLTHROUGH */
 
 /*
- *     __dma_clean_area(start, size)
+ *     __dma_clean_area(start, end)
  *     - start   - virtual start address of region
- *     - size    - size in question
+ *     - end     - virtual end address of region
  */
        dcache_by_line_op cvac, sy, x0, x1, x2, x3
        ret
-SYM_FUNC_END_PI(__clean_dcache_area_poc)
+SYM_FUNC_END_PI(dcache_clean_poc)
 SYM_FUNC_END(__dma_clean_area)
 
 /*
- *     __clean_dcache_area_pop(kaddr, size)
+ *     dcache_clean_pop(start, end)
  *
- *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     Ensure that any D-cache lines for the interval [start, end)
  *     are cleaned to the PoP.
  *
- *     - kaddr   - kernel address
- *     - size    - size in question
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
  */
-SYM_FUNC_START_PI(__clean_dcache_area_pop)
+SYM_FUNC_START_PI(dcache_clean_pop)
        alternative_if_not ARM64_HAS_DCPOP
-       b       __clean_dcache_area_poc
+       b       dcache_clean_poc
        alternative_else_nop_endif
        dcache_by_line_op cvap, sy, x0, x1, x2, x3
        ret
-SYM_FUNC_END_PI(__clean_dcache_area_pop)
+SYM_FUNC_END_PI(dcache_clean_pop)
 
 /*
  *     __dma_flush_area(start, size)
@@ -217,6 +218,7 @@ SYM_FUNC_END_PI(__clean_dcache_area_pop)
  *     - size    - size in question
  */
 SYM_FUNC_START_PI(__dma_flush_area)
+       add     x1, x0, x1
        dcache_by_line_op civac, sy, x0, x1, x2, x3
        ret
 SYM_FUNC_END_PI(__dma_flush_area)
@@ -228,6 +230,7 @@ SYM_FUNC_END_PI(__dma_flush_area)
  *     - dir   - DMA direction
  */
 SYM_FUNC_START_PI(__dma_map_area)
+       add     x1, x0, x1
        cmp     w2, #DMA_FROM_DEVICE
        b.eq    __dma_inv_area
        b       __dma_clean_area
@@ -240,6 +243,7 @@ SYM_FUNC_END_PI(__dma_map_area)
  *     - dir   - DMA direction
  */
 SYM_FUNC_START_PI(__dma_unmap_area)
+       add     x1, x0, x1
        cmp     w2, #DMA_TO_DEVICE
        b.ne    __dma_inv_area
        ret
index 001737a..cd72576 100644 (file)
@@ -402,14 +402,12 @@ static int asids_init(void)
 {
        asid_bits = get_cpu_asid_bits();
        atomic64_set(&asid_generation, ASID_FIRST_VERSION);
-       asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS), sizeof(*asid_map),
-                          GFP_KERNEL);
+       asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
        if (!asid_map)
                panic("Failed to allocate bitmap for %lu ASIDs\n",
                      NUM_USER_ASIDS);
 
-       pinned_asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS),
-                                 sizeof(*pinned_asid_map), GFP_KERNEL);
+       pinned_asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
        nr_pinned_asids = 0;
 
        /*
index 871c82a..349c488 100644 (file)
@@ -99,6 +99,8 @@ static void mem_abort_decode(unsigned int esr)
        pr_alert("  EA = %lu, S1PTW = %lu\n",
                 (esr & ESR_ELx_EA) >> ESR_ELx_EA_SHIFT,
                 (esr & ESR_ELx_S1PTW) >> ESR_ELx_S1PTW_SHIFT);
+       pr_alert("  FSC = 0x%02x: %s\n", (esr & ESR_ELx_FSC),
+                esr_to_fault_info(esr)->name);
 
        if (esr_is_data_abort(esr))
                data_abort_decode(esr);
@@ -232,13 +234,17 @@ static bool is_el1_instruction_abort(unsigned int esr)
        return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_CUR;
 }
 
+static bool is_el1_data_abort(unsigned int esr)
+{
+       return ESR_ELx_EC(esr) == ESR_ELx_EC_DABT_CUR;
+}
+
 static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr,
                                           struct pt_regs *regs)
 {
-       unsigned int ec       = ESR_ELx_EC(esr);
        unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
 
-       if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR)
+       if (!is_el1_data_abort(esr) && !is_el1_instruction_abort(esr))
                return false;
 
        if (fsc_type == ESR_ELx_FSC_PERM)
@@ -258,7 +264,7 @@ static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr,
        unsigned long flags;
        u64 par, dfsc;
 
-       if (ESR_ELx_EC(esr) != ESR_ELx_EC_DABT_CUR ||
+       if (!is_el1_data_abort(esr) ||
            (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT)
                return false;
 
@@ -346,10 +352,9 @@ static void do_tag_recovery(unsigned long addr, unsigned int esr,
 
 static bool is_el1_mte_sync_tag_check_fault(unsigned int esr)
 {
-       unsigned int ec = ESR_ELx_EC(esr);
        unsigned int fsc = esr & ESR_ELx_FSC;
 
-       if (ec != ESR_ELx_EC_DABT_CUR)
+       if (!is_el1_data_abort(esr))
                return false;
 
        if (fsc == ESR_ELx_FSC_MTE)
@@ -504,7 +509,7 @@ static vm_fault_t __do_page_fault(struct mm_struct *mm, unsigned long addr,
         */
        if (!(vma->vm_flags & vm_flags))
                return VM_FAULT_BADACCESS;
-       return handle_mm_fault(vma, addr & PAGE_MASK, mm_flags, regs);
+       return handle_mm_fault(vma, addr, mm_flags, regs);
 }
 
 static bool is_el0_instruction_abort(unsigned int esr)
@@ -836,13 +841,6 @@ void do_mem_abort(unsigned long far, unsigned int esr, struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(do_mem_abort);
 
-void do_el0_irq_bp_hardening(void)
-{
-       /* PC has already been checked in entry.S */
-       arm64_apply_bp_hardening();
-}
-NOKPROBE_SYMBOL(do_el0_irq_bp_hardening);
-
 void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 {
        arm64_notify_die("SP/PC alignment exception", regs, SIGBUS, BUS_ADRALN,
@@ -921,3 +919,29 @@ void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
        debug_exception_exit(regs);
 }
 NOKPROBE_SYMBOL(do_debug_exception);
+
+/*
+ * Used during anonymous page fault handling.
+ */
+struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+                                               unsigned long vaddr)
+{
+       gfp_t flags = GFP_HIGHUSER_MOVABLE | __GFP_ZERO;
+
+       /*
+        * If the page is mapped with PROT_MTE, initialise the tags at the
+        * point of allocation and page zeroing as this is usually faster than
+        * separate DC ZVA and STGM.
+        */
+       if (vma->vm_flags & VM_MTE)
+               flags |= __GFP_ZEROTAGS;
+
+       return alloc_page_vma(flags, vma, vaddr);
+}
+
+void tag_clear_highpage(struct page *page)
+{
+       mte_zero_clear_page_tags(page_address(page));
+       page_kasan_tag_reset(page);
+       set_bit(PG_mte_tagged, &page->flags);
+}
index 6d44c02..2aaf950 100644 (file)
 #include <asm/cache.h>
 #include <asm/tlbflush.h>
 
-void sync_icache_aliases(void *kaddr, unsigned long len)
+void sync_icache_aliases(unsigned long start, unsigned long end)
 {
-       unsigned long addr = (unsigned long)kaddr;
-
        if (icache_is_aliasing()) {
-               __clean_dcache_area_pou(kaddr, len);
-               __flush_icache_all();
+               dcache_clean_pou(start, end);
+               icache_inval_all_pou();
        } else {
                /*
                 * Don't issue kick_all_cpus_sync() after I-cache invalidation
                 * for user mappings.
                 */
-               __flush_icache_range(addr, addr + len);
+               caches_clean_inval_pou(start, end);
        }
 }
 
-static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
-                               unsigned long uaddr, void *kaddr,
-                               unsigned long len)
+static void flush_ptrace_access(struct vm_area_struct *vma, unsigned long start,
+                               unsigned long end)
 {
        if (vma->vm_flags & VM_EXEC)
-               sync_icache_aliases(kaddr, len);
+               sync_icache_aliases(start, end);
 }
 
 /*
@@ -48,7 +45,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
                       unsigned long len)
 {
        memcpy(dst, src, len);
-       flush_ptrace_access(vma, page, uaddr, dst, len);
+       flush_ptrace_access(vma, (unsigned long)dst, (unsigned long)dst + len);
 }
 
 void __sync_icache_dcache(pte_t pte)
@@ -56,7 +53,9 @@ void __sync_icache_dcache(pte_t pte)
        struct page *page = pte_page(pte);
 
        if (!test_bit(PG_dcache_clean, &page->flags)) {
-               sync_icache_aliases(page_address(page), page_size(page));
+               sync_icache_aliases((unsigned long)page_address(page),
+                                   (unsigned long)page_address(page) +
+                                           page_size(page));
                set_bit(PG_dcache_clean, &page->flags);
        }
 }
@@ -77,20 +76,20 @@ EXPORT_SYMBOL(flush_dcache_page);
 /*
  * Additional functions defined in assembly.
  */
-EXPORT_SYMBOL(__flush_icache_range);
+EXPORT_SYMBOL(caches_clean_inval_pou);
 
 #ifdef CONFIG_ARCH_HAS_PMEM_API
 void arch_wb_cache_pmem(void *addr, size_t size)
 {
        /* Ensure order against any prior non-cacheable writes */
        dmb(osh);
-       __clean_dcache_area_pop(addr, size);
+       dcache_clean_pop((unsigned long)addr, (unsigned long)addr + size);
 }
 EXPORT_SYMBOL_GPL(arch_wb_cache_pmem);
 
 void arch_invalidate_pmem(void *addr, size_t size)
 {
-       __inval_dcache_area(addr, size);
+       dcache_inval_poc((unsigned long)addr, (unsigned long)addr + size);
 }
 EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
 #endif
index e55409c..6e1ca04 100644 (file)
@@ -499,6 +499,13 @@ void __init mem_init(void)
        BUILD_BUG_ON(TASK_SIZE_32 > DEFAULT_MAP_WINDOW_64);
 #endif
 
+       /*
+        * Selected page table levels should match when derived from
+        * scratch using the virtual address range and page size.
+        */
+       BUILD_BUG_ON(ARM64_HW_PGTABLE_LEVELS(CONFIG_ARM64_VA_BITS) !=
+                    CONFIG_PGTABLE_LEVELS);
+
        if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
                extern int sysctl_overcommit_memory;
                /*
index 89b66ef..0b28cc2 100644 (file)
@@ -228,7 +228,7 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
                next = pmd_addr_end(addr, end);
 
                /* try section mapping first */
-               if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
+               if (((addr | next | phys) & ~PMD_MASK) == 0 &&
                    (flags & NO_BLOCK_MAPPINGS) == 0) {
                        pmd_set_huge(pmdp, phys, prot);
 
@@ -1114,14 +1114,14 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
 }
 #endif
 
-#if !ARM64_SWAPPER_USES_SECTION_MAPS
+#if !ARM64_KERNEL_USES_PMD_MAPS
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
                struct vmem_altmap *altmap)
 {
        WARN_ON((start < VMEMMAP_START) || (end > VMEMMAP_END));
        return vmemmap_populate_basepages(start, end, node, altmap);
 }
-#else  /* !ARM64_SWAPPER_USES_SECTION_MAPS */
+#else  /* !ARM64_KERNEL_USES_PMD_MAPS */
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
                struct vmem_altmap *altmap)
 {
@@ -1166,17 +1166,18 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 
        return 0;
 }
-#endif /* !ARM64_SWAPPER_USES_SECTION_MAPS */
+#endif /* !ARM64_KERNEL_USES_PMD_MAPS */
+
+#ifdef CONFIG_MEMORY_HOTPLUG
 void vmemmap_free(unsigned long start, unsigned long end,
                struct vmem_altmap *altmap)
 {
-#ifdef CONFIG_MEMORY_HOTPLUG
        WARN_ON((start < VMEMMAP_START) || (end > VMEMMAP_END));
 
        unmap_hotplug_range(start, end, true, altmap);
        free_empty_tables(start, end, VMEMMAP_START, VMEMMAP_END);
-#endif
 }
+#endif /* CONFIG_MEMORY_HOTPLUG */
 
 static inline pud_t *fixmap_pud(unsigned long addr)
 {
index 97d7bcd..35936c5 100644 (file)
 #endif
 
 #ifdef CONFIG_KASAN_HW_TAGS
-#define TCR_KASAN_HW_FLAGS SYS_TCR_EL1_TCMA1 | TCR_TBI1 | TCR_TBID1
+#define TCR_MTE_FLAGS SYS_TCR_EL1_TCMA1 | TCR_TBI1 | TCR_TBID1
 #else
-#define TCR_KASAN_HW_FLAGS 0
+/*
+ * The mte_zero_clear_page_tags() implementation uses DC GZVA, which relies on
+ * TBI being enabled at EL1.
+ */
+#define TCR_MTE_FLAGS TCR_TBI1 | TCR_TBID1
 #endif
 
 /*
 #define MAIR_EL1_SET                                                   \
        (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) |      \
         MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) |        \
-        MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) |            \
         MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) |              \
         MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) |                    \
-        MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT) |              \
         MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED))
 
 #ifdef CONFIG_CPU_PM
@@ -83,11 +85,7 @@ SYM_FUNC_START(cpu_do_suspend)
        mrs     x9, mdscr_el1
        mrs     x10, oslsr_el1
        mrs     x11, sctlr_el1
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
-       mrs     x12, tpidr_el1
-alternative_else
-       mrs     x12, tpidr_el2
-alternative_endif
+       get_this_cpu_offset x12
        mrs     x13, sp_el0
        stp     x2, x3, [x0]
        stp     x4, x5, [x0, #16]
@@ -145,11 +143,7 @@ SYM_FUNC_START(cpu_do_resume)
        msr     mdscr_el1, x10
 
        msr     sctlr_el1, x12
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
-       msr     tpidr_el1, x13
-alternative_else
-       msr     tpidr_el2, x13
-alternative_endif
+       set_this_cpu_offset x13
        msr     sp_el0, x14
        /*
         * Restore oslsr_el1 by writing oslar_el1
@@ -464,7 +458,7 @@ SYM_FUNC_START(__cpu_setup)
        msr_s   SYS_TFSRE0_EL1, xzr
 
        /* set the TCR_EL1 bits */
-       mov_q   x10, TCR_KASAN_HW_FLAGS
+       mov_q   x10, TCR_MTE_FLAGS
        orr     tcr, tcr, x10
 1:
 #endif
index a1937df..1c40353 100644 (file)
@@ -159,10 +159,6 @@ static const struct prot_bits pte_bits[] = {
                .set    = "DEVICE/nGnRE",
        }, {
                .mask   = PTE_ATTRINDX_MASK,
-               .val    = PTE_ATTRINDX(MT_DEVICE_GRE),
-               .set    = "DEVICE/GRE",
-       }, {
-               .mask   = PTE_ATTRINDX_MASK,
                .val    = PTE_ATTRINDX(MT_NORMAL_NC),
                .set    = "MEM/NORMAL-NC",
        }, {
index f7b1948..dd5000d 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/byteorder.h>
 #include <asm/cacheflush.h>
 #include <asm/debug-monitors.h>
+#include <asm/insn.h>
 #include <asm/set_memory.h>
 
 #include "bpf_jit.h"
index 21fbdda..49305c2 100644 (file)
@@ -3,7 +3,8 @@
 # Internal CPU capabilities constants, keep this list sorted
 
 BTI
-HAS_32BIT_EL0
+# Unreliable: use system_supports_32bit_el0() instead.
+HAS_32BIT_EL0_DO_NOT_USE
 HAS_32BIT_EL1
 HAS_ADDRESS_AUTH
 HAS_ADDRESS_AUTH_ARCH
index dabc8e4..d1bef11 100644 (file)
@@ -31,7 +31,7 @@ extern void __bad_xchg(void);
        __ret;                                                  \
 })
 
-#define xchg_relaxed(ptr, x) \
+#define arch_xchg_relaxed(ptr, x) \
                (__xchg_relaxed((x), (ptr), sizeof(*(ptr))))
 
 #define __cmpxchg_relaxed(ptr, old, new, size)                 \
@@ -61,14 +61,14 @@ extern void __bad_xchg(void);
        __ret;                                                  \
 })
 
-#define cmpxchg_relaxed(ptr, o, n) \
+#define arch_cmpxchg_relaxed(ptr, o, n) \
        (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
 
-#define cmpxchg(ptr, o, n)                                     \
+#define arch_cmpxchg(ptr, o, n)                                \
 ({                                                             \
        __typeof__(*(ptr)) __ret;                               \
        __smp_release_fence();                                  \
-       __ret = cmpxchg_relaxed(ptr, o, n);                     \
+       __ret = arch_cmpxchg_relaxed(ptr, o, n);                \
        __smp_acquire_fence();                                  \
        __ret;                                                  \
 })
index 1747986..1cbcba4 100644 (file)
@@ -9,7 +9,6 @@
 int main(void)
 {
        /* offsets into the task struct */
-       DEFINE(TASK_STATE,        offsetof(struct task_struct, state));
        DEFINE(TASK_THREAD_INFO,  offsetof(struct task_struct, stack));
        DEFINE(TASK_FLAGS,        offsetof(struct task_struct, flags));
        DEFINE(TASK_PTRACE,       offsetof(struct task_struct, ptrace));
index 589f090..68b22b4 100644 (file)
@@ -295,23 +295,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 0f9f5ee..e299353 100644 (file)
@@ -281,7 +281,6 @@ void csky_start_secondary(void)
        pr_info("CPU%u Online: %s...\n", cpu, __func__);
 
        local_irq_enable();
-       preempt_disable();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
index 16ae20a..1b280ef 100644 (file)
@@ -115,7 +115,7 @@ unsigned long get_wchan(struct task_struct *task)
 {
        unsigned long pc = 0;
 
-       if (likely(task && task != current && task->state != TASK_RUNNING))
+       if (likely(task && task != current && !task_is_running(task)))
                walk_stackframe(task, NULL, save_wchan, &pc);
        return pc;
 }
index 60ee7f0..e23139c 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 generic-y += asm-offsets.h
+generic-y += cmpxchg.h
 generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h
deleted file mode 100644 (file)
index a990d15..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ARCH_H8300_ATOMIC__
-#define __ARCH_H8300_ATOMIC__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <asm/cmpxchg.h>
-#include <asm/irqflags.h>
-
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic_set(v, i)       WRITE_ONCE(((v)->counter), (i))
-
-#define ATOMIC_OP_RETURN(op, c_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t *v)     \
-{                                                              \
-       h8300flags flags;                                       \
-       int ret;                                                \
-                                                               \
-       flags = arch_local_irq_save();                          \
-       ret = v->counter c_op i;                                \
-       arch_local_irq_restore(flags);                          \
-       return ret;                                             \
-}
-
-#define ATOMIC_FETCH_OP(op, c_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                \
-{                                                              \
-       h8300flags flags;                                       \
-       int ret;                                                \
-                                                               \
-       flags = arch_local_irq_save();                          \
-       ret = v->counter;                                       \
-       v->counter c_op i;                                      \
-       arch_local_irq_restore(flags);                          \
-       return ret;                                             \
-}
-
-#define ATOMIC_OP(op, c_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)             \
-{                                                              \
-       h8300flags flags;                                       \
-                                                               \
-       flags = arch_local_irq_save();                          \
-       v->counter c_op i;                                      \
-       arch_local_irq_restore(flags);                          \
-}
-
-ATOMIC_OP_RETURN(add, +=)
-ATOMIC_OP_RETURN(sub, -=)
-
-#define ATOMIC_OPS(op, c_op)                                   \
-       ATOMIC_OP(op, c_op)                                     \
-       ATOMIC_FETCH_OP(op, c_op)
-
-ATOMIC_OPS(and, &=)
-ATOMIC_OPS(or,  |=)
-ATOMIC_OPS(xor, ^=)
-ATOMIC_OPS(add, +=)
-ATOMIC_OPS(sub, -=)
-
-#undef ATOMIC_OPS
-#undef ATOMIC_OP_RETURN
-#undef ATOMIC_OP
-
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-       int ret;
-       h8300flags flags;
-
-       flags = arch_local_irq_save();
-       ret = v->counter;
-       if (likely(ret == old))
-               v->counter = new;
-       arch_local_irq_restore(flags);
-       return ret;
-}
-
-static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
-{
-       int ret;
-       h8300flags flags;
-
-       flags = arch_local_irq_save();
-       ret = v->counter;
-       if (ret != u)
-               v->counter += a;
-       arch_local_irq_restore(flags);
-       return ret;
-}
-#define atomic_fetch_add_unless                atomic_fetch_add_unless
-
-#endif /* __ARCH_H8300_ATOMIC __ */
diff --git a/arch/h8300/include/asm/cmpxchg.h b/arch/h8300/include/asm/cmpxchg.h
deleted file mode 100644 (file)
index c64bb38..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ARCH_H8300_CMPXCHG__
-#define __ARCH_H8300_CMPXCHG__
-
-#include <linux/irqflags.h>
-
-#define xchg(ptr, x) \
-       ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
-                                   sizeof(*(ptr))))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-
-static inline unsigned long __xchg(unsigned long x,
-                                  volatile void *ptr, int size)
-{
-       unsigned long tmp, flags;
-
-       local_irq_save(flags);
-
-       switch (size) {
-       case 1:
-               __asm__ __volatile__
-                       ("mov.b %2,%0\n\t"
-                        "mov.b %1,%2"
-                        : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
-               break;
-       case 2:
-               __asm__ __volatile__
-                       ("mov.w %2,%0\n\t"
-                        "mov.w %1,%2"
-                        : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
-               break;
-       case 4:
-               __asm__ __volatile__
-                       ("mov.l %2,%0\n\t"
-                        "mov.l %1,%2"
-                        : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
-               break;
-       default:
-               tmp = 0;
-       }
-       local_irq_restore(flags);
-       return tmp;
-}
-
-#include <asm-generic/cmpxchg-local.h>
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)                                        \
-       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),              \
-                                                    (unsigned long)(o), \
-                                                    (unsigned long)(n), \
-                                                    sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#ifndef CONFIG_SMP
-#include <asm-generic/cmpxchg.h>
-#endif
-
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-
-#endif /* __ARCH_H8300_CMPXCHG__ */
index d4b53af..65571ee 100644 (file)
@@ -21,7 +21,6 @@
 int main(void)
 {
        /* offsets into the task struct */
-       OFFSET(TASK_STATE, task_struct, state);
        OFFSET(TASK_FLAGS, task_struct, flags);
        OFFSET(TASK_PTRACE, task_struct, ptrace);
        OFFSET(TASK_BLOCKED, task_struct, blocked);
index 46b1342..2ac27e4 100644 (file)
@@ -134,7 +134,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long stack_page;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long)p;
index 4ab895d..6e94f8d 100644 (file)
@@ -14,7 +14,7 @@
 
 /*  Normal writes in our arch don't clear lock reservations  */
 
-static inline void atomic_set(atomic_t *v, int new)
+static inline void arch_atomic_set(atomic_t *v, int new)
 {
        asm volatile(
                "1:     r6 = memw_locked(%0);\n"
@@ -26,26 +26,26 @@ static inline void atomic_set(atomic_t *v, int new)
        );
 }
 
-#define atomic_set_release(v, i)       atomic_set((v), (i))
+#define arch_atomic_set_release(v, i)  arch_atomic_set((v), (i))
 
 /**
- * atomic_read - reads a word, atomically
+ * arch_atomic_read - reads a word, atomically
  * @v: pointer to atomic value
  *
  * Assumes all word reads on our architecture are atomic.
  */
-#define atomic_read(v)         READ_ONCE((v)->counter)
+#define arch_atomic_read(v)            READ_ONCE((v)->counter)
 
 /**
- * atomic_xchg - atomic
+ * arch_atomic_xchg - atomic
  * @v: pointer to memory to change
  * @new: new value (technically passed in a register -- see xchg)
  */
-#define atomic_xchg(v, new)    (xchg(&((v)->counter), (new)))
+#define arch_atomic_xchg(v, new)       (arch_xchg(&((v)->counter), (new)))
 
 
 /**
- * atomic_cmpxchg - atomic compare-and-exchange values
+ * arch_atomic_cmpxchg - atomic compare-and-exchange values
  * @v: pointer to value to change
  * @old:  desired old value to match
  * @new:  new value to put in
@@ -61,7 +61,7 @@ static inline void atomic_set(atomic_t *v, int new)
  *
  * "old" is "expected" old val, __oldval is actual old value
  */
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+static inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        int __oldval;
 
@@ -81,7 +81,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 }
 
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        int output;                                                     \
                                                                        \
@@ -97,7 +97,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        int output;                                                     \
                                                                        \
@@ -114,7 +114,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        int output, val;                                                \
                                                                        \
@@ -148,7 +148,7 @@ ATOMIC_OPS(xor)
 #undef ATOMIC_OP
 
 /**
- * atomic_fetch_add_unless - add unless the number is a given value
+ * arch_atomic_fetch_add_unless - add unless the number is a given value
  * @v: pointer to value
  * @a: amount to add
  * @u: unless value is equal to u
@@ -157,7 +157,7 @@ ATOMIC_OPS(xor)
  *
  */
 
-static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int __oldval;
        register int tmp;
@@ -180,6 +180,6 @@ static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
        );
        return __oldval;
 }
-#define atomic_fetch_add_unless atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
 
 #endif
index 92b8a02..cdb705e 100644 (file)
@@ -42,7 +42,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
  * Atomically swap the contents of a register with memory.  Should be atomic
  * between multiple CPU's and within interrupts on the same CPU.
  */
-#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
+#define arch_xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
        sizeof(*(ptr))))
 
 /*
@@ -51,7 +51,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
  *  variable casting.
  */
 
-#define cmpxchg(ptr, old, new)                                 \
+#define arch_cmpxchg(ptr, old, new)                            \
 ({                                                             \
        __typeof__(ptr) __ptr = (ptr);                          \
        __typeof__(*(ptr)) __old = (old);                       \
index c61165c..6a6835f 100644 (file)
@@ -135,7 +135,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long fp, pc;
        unsigned long stack_page;
        int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long)task_stack_page(p);
index f267d95..266c429 100644 (file)
 
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic64_read(v)       READ_ONCE((v)->counter)
+#define arch_atomic_read(v)    READ_ONCE((v)->counter)
+#define arch_atomic64_read(v)  READ_ONCE((v)->counter)
 
-#define atomic_set(v,i)                WRITE_ONCE(((v)->counter), (i))
-#define atomic64_set(v,i)      WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_set(v,i)   WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic64_set(v,i) WRITE_ONCE(((v)->counter), (i))
 
 #define ATOMIC_OP(op, c_op)                                            \
 static __inline__ int                                                  \
@@ -36,7 +36,7 @@ ia64_atomic_##op (int i, atomic_t *v)                                 \
                                                                        \
        do {                                                            \
                CMPXCHG_BUGCHECK(v);                                    \
-               old = atomic_read(v);                                   \
+               old = arch_atomic_read(v);                              \
                new = old c_op i;                                       \
        } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
        return new;                                                     \
@@ -51,7 +51,7 @@ ia64_atomic_fetch_##op (int i, atomic_t *v)                           \
                                                                        \
        do {                                                            \
                CMPXCHG_BUGCHECK(v);                                    \
-               old = atomic_read(v);                                   \
+               old = arch_atomic_read(v);                              \
                new = old c_op i;                                       \
        } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \
        return old;                                                     \
@@ -74,7 +74,7 @@ ATOMIC_OPS(sub, -)
 #define __ia64_atomic_const(i) 0
 #endif
 
-#define atomic_add_return(i,v)                                         \
+#define arch_atomic_add_return(i,v)                                    \
 ({                                                                     \
        int __ia64_aar_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -82,7 +82,7 @@ ATOMIC_OPS(sub, -)
                : ia64_atomic_add(__ia64_aar_i, v);                     \
 })
 
-#define atomic_sub_return(i,v)                                         \
+#define arch_atomic_sub_return(i,v)                                    \
 ({                                                                     \
        int __ia64_asr_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -90,7 +90,7 @@ ATOMIC_OPS(sub, -)
                : ia64_atomic_sub(__ia64_asr_i, v);                     \
 })
 
-#define atomic_fetch_add(i,v)                                          \
+#define arch_atomic_fetch_add(i,v)                                     \
 ({                                                                     \
        int __ia64_aar_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -98,7 +98,7 @@ ATOMIC_OPS(sub, -)
                : ia64_atomic_fetch_add(__ia64_aar_i, v);               \
 })
 
-#define atomic_fetch_sub(i,v)                                          \
+#define arch_atomic_fetch_sub(i,v)                                     \
 ({                                                                     \
        int __ia64_asr_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -110,13 +110,13 @@ ATOMIC_FETCH_OP(and, &)
 ATOMIC_FETCH_OP(or, |)
 ATOMIC_FETCH_OP(xor, ^)
 
-#define atomic_and(i,v)        (void)ia64_atomic_fetch_and(i,v)
-#define atomic_or(i,v) (void)ia64_atomic_fetch_or(i,v)
-#define atomic_xor(i,v)        (void)ia64_atomic_fetch_xor(i,v)
+#define arch_atomic_and(i,v)   (void)ia64_atomic_fetch_and(i,v)
+#define arch_atomic_or(i,v)    (void)ia64_atomic_fetch_or(i,v)
+#define arch_atomic_xor(i,v)   (void)ia64_atomic_fetch_xor(i,v)
 
-#define atomic_fetch_and(i,v)  ia64_atomic_fetch_and(i,v)
-#define atomic_fetch_or(i,v)   ia64_atomic_fetch_or(i,v)
-#define atomic_fetch_xor(i,v)  ia64_atomic_fetch_xor(i,v)
+#define arch_atomic_fetch_and(i,v)     ia64_atomic_fetch_and(i,v)
+#define arch_atomic_fetch_or(i,v)      ia64_atomic_fetch_or(i,v)
+#define arch_atomic_fetch_xor(i,v)     ia64_atomic_fetch_xor(i,v)
 
 #undef ATOMIC_OPS
 #undef ATOMIC_FETCH_OP
@@ -131,7 +131,7 @@ ia64_atomic64_##op (s64 i, atomic64_t *v)                           \
                                                                        \
        do {                                                            \
                CMPXCHG_BUGCHECK(v);                                    \
-               old = atomic64_read(v);                                 \
+               old = arch_atomic64_read(v);                            \
                new = old c_op i;                                       \
        } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
        return new;                                                     \
@@ -146,7 +146,7 @@ ia64_atomic64_fetch_##op (s64 i, atomic64_t *v)                             \
                                                                        \
        do {                                                            \
                CMPXCHG_BUGCHECK(v);                                    \
-               old = atomic64_read(v);                                 \
+               old = arch_atomic64_read(v);                            \
                new = old c_op i;                                       \
        } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \
        return old;                                                     \
@@ -159,7 +159,7 @@ ia64_atomic64_fetch_##op (s64 i, atomic64_t *v)                             \
 ATOMIC64_OPS(add, +)
 ATOMIC64_OPS(sub, -)
 
-#define atomic64_add_return(i,v)                                       \
+#define arch_atomic64_add_return(i,v)                                  \
 ({                                                                     \
        s64 __ia64_aar_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -167,7 +167,7 @@ ATOMIC64_OPS(sub, -)
                : ia64_atomic64_add(__ia64_aar_i, v);                   \
 })
 
-#define atomic64_sub_return(i,v)                                       \
+#define arch_atomic64_sub_return(i,v)                                  \
 ({                                                                     \
        s64 __ia64_asr_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -175,7 +175,7 @@ ATOMIC64_OPS(sub, -)
                : ia64_atomic64_sub(__ia64_asr_i, v);                   \
 })
 
-#define atomic64_fetch_add(i,v)                                                \
+#define arch_atomic64_fetch_add(i,v)                                   \
 ({                                                                     \
        s64 __ia64_aar_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -183,7 +183,7 @@ ATOMIC64_OPS(sub, -)
                : ia64_atomic64_fetch_add(__ia64_aar_i, v);             \
 })
 
-#define atomic64_fetch_sub(i,v)                                                \
+#define arch_atomic64_fetch_sub(i,v)                                   \
 ({                                                                     \
        s64 __ia64_asr_i = (i);                                         \
        __ia64_atomic_const(i)                                          \
@@ -195,29 +195,29 @@ ATOMIC64_FETCH_OP(and, &)
 ATOMIC64_FETCH_OP(or, |)
 ATOMIC64_FETCH_OP(xor, ^)
 
-#define atomic64_and(i,v)      (void)ia64_atomic64_fetch_and(i,v)
-#define atomic64_or(i,v)       (void)ia64_atomic64_fetch_or(i,v)
-#define atomic64_xor(i,v)      (void)ia64_atomic64_fetch_xor(i,v)
+#define arch_atomic64_and(i,v) (void)ia64_atomic64_fetch_and(i,v)
+#define arch_atomic64_or(i,v)  (void)ia64_atomic64_fetch_or(i,v)
+#define arch_atomic64_xor(i,v) (void)ia64_atomic64_fetch_xor(i,v)
 
-#define atomic64_fetch_and(i,v)        ia64_atomic64_fetch_and(i,v)
-#define atomic64_fetch_or(i,v) ia64_atomic64_fetch_or(i,v)
-#define atomic64_fetch_xor(i,v)        ia64_atomic64_fetch_xor(i,v)
+#define arch_atomic64_fetch_and(i,v)   ia64_atomic64_fetch_and(i,v)
+#define arch_atomic64_fetch_or(i,v)    ia64_atomic64_fetch_or(i,v)
+#define arch_atomic64_fetch_xor(i,v)   ia64_atomic64_fetch_xor(i,v)
 
 #undef ATOMIC64_OPS
 #undef ATOMIC64_FETCH_OP
 #undef ATOMIC64_OP
 
-#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, old, new) (arch_cmpxchg(&((v)->counter), old, new))
+#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
-#define atomic64_cmpxchg(v, old, new) \
-       (cmpxchg(&((v)->counter), old, new))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic64_cmpxchg(v, old, new) \
+       (arch_cmpxchg(&((v)->counter), old, new))
+#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
-#define atomic_add(i,v)                        (void)atomic_add_return((i), (v))
-#define atomic_sub(i,v)                        (void)atomic_sub_return((i), (v))
+#define arch_atomic_add(i,v)           (void)arch_atomic_add_return((i), (v))
+#define arch_atomic_sub(i,v)           (void)arch_atomic_sub_return((i), (v))
 
-#define atomic64_add(i,v)              (void)atomic64_add_return((i), (v))
-#define atomic64_sub(i,v)              (void)atomic64_sub_return((i), (v))
+#define arch_atomic64_add(i,v)         (void)arch_atomic64_add_return((i), (v))
+#define arch_atomic64_sub(i,v)         (void)arch_atomic64_sub_return((i), (v))
 
 #endif /* _ASM_IA64_ATOMIC_H */
diff --git a/arch/ia64/include/asm/cmpxchg.h b/arch/ia64/include/asm/cmpxchg.h
new file mode 100644 (file)
index 0000000..94ef844
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_IA64_CMPXCHG_H
+#define _ASM_IA64_CMPXCHG_H
+
+#include <uapi/asm/cmpxchg.h>
+
+#define arch_xchg(ptr, x)      \
+({(__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));})
+
+#define arch_cmpxchg(ptr, o, n)                cmpxchg_acq((ptr), (o), (n))
+#define arch_cmpxchg64(ptr, o, n)      cmpxchg_acq((ptr), (o), (n))
+
+#define arch_cmpxchg_local             arch_cmpxchg
+#define arch_cmpxchg64_local           arch_cmpxchg64
+
+#endif /* _ASM_IA64_CMPXCHG_H */
index f4dc81f..1b99046 100644 (file)
@@ -82,16 +82,16 @@ do {                                                \
 } while (0)
 
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr)         \
+#define alloc_zeroed_user_highpage_movable(vma, vaddr)                 \
 ({                                                                     \
        struct page *page = alloc_page_vma(                             \
-               GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr);  \
+               GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr);         \
        if (page)                                                       \
                flush_dcache_page(page);                                \
        page;                                                           \
 })
 
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
index 5d90307..926c6cb 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _ASM_IA64_CMPXCHG_H
-#define _ASM_IA64_CMPXCHG_H
+#ifndef _UAPI_ASM_IA64_CMPXCHG_H
+#define _UAPI_ASM_IA64_CMPXCHG_H
 
 /*
  * Compare/Exchange, forked from asm/intrinsics.h
@@ -53,8 +53,10 @@ extern void ia64_xchg_called_with_bad_pointer(void);
        __xchg_result;                                                  \
 })
 
+#ifndef __KERNEL__
 #define xchg(ptr, x)                                                   \
 ({(__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));})
+#endif
 
 /*
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
@@ -126,12 +128,14 @@ extern long ia64_cmpxchg_called_with_bad_pointer(void);
  * we had to back-pedal and keep the "legacy" behavior of a full fence :-(
  */
 
+#ifndef __KERNEL__
 /* for compatibility with other platforms: */
 #define cmpxchg(ptr, o, n)     cmpxchg_acq((ptr), (o), (n))
 #define cmpxchg64(ptr, o, n)   cmpxchg_acq((ptr), (o), (n))
 
 #define cmpxchg_local          cmpxchg
 #define cmpxchg64_local                cmpxchg64
+#endif
 
 #ifdef CONFIG_IA64_DEBUG_CMPXCHG
 # define CMPXCHG_BUGCHECK_DECL int _cmpxchg_bugcheck_count = 128;
@@ -152,4 +156,4 @@ do {                                                                        \
 
 #endif /* !__ASSEMBLY__ */
 
-#endif /* _ASM_IA64_CMPXCHG_H */
+#endif /* _UAPI_ASM_IA64_CMPXCHG_H */
index fc1ff8a..441ed04 100644 (file)
@@ -844,22 +844,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index cdbac4b..e628a88 100644 (file)
@@ -1788,7 +1788,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset,
        ti->task = p;
        ti->cpu = cpu;
        p->stack = ti;
-       p->state = TASK_UNINTERRUPTIBLE;
+       p->__state = TASK_UNINTERRUPTIBLE;
        cpumask_set_cpu(cpu, &p->cpus_mask);
        INIT_LIST_HEAD(&p->tasks);
        p->parent = p->real_parent = p->group_leader = p;
index 7e1a152..e56d63f 100644 (file)
@@ -529,7 +529,7 @@ get_wchan (struct task_struct *p)
        unsigned long ip;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        /*
@@ -542,7 +542,7 @@ get_wchan (struct task_struct *p)
         */
        unw_init_from_blocked_task(&info, p);
        do {
-               if (p->state == TASK_RUNNING)
+               if (task_is_running(p))
                        return 0;
                if (unw_unwind(&info) < 0)
                        return 0;
index e14f565..df28c7d 100644 (file)
@@ -641,11 +641,11 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
        read_lock(&tasklist_lock);
        if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
-               if (child->state == TASK_STOPPED &&
+               if (READ_ONCE(child->__state) == TASK_STOPPED &&
                    !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) {
                        set_notify_resume(child);
 
-                       child->state = TASK_TRACED;
+                       WRITE_ONCE(child->__state, TASK_TRACED);
                        stopped = 1;
                }
                spin_unlock_irq(&child->sighand->siglock);
@@ -665,9 +665,9 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
        read_lock(&tasklist_lock);
        if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
-               if (child->state == TASK_TRACED &&
+               if (READ_ONCE(child->__state) == TASK_TRACED &&
                    (child->signal->flags & SIGNAL_STOP_STOPPED)) {
-                       child->state = TASK_STOPPED;
+                       WRITE_ONCE(child->__state, TASK_STOPPED);
                }
                spin_unlock_irq(&child->sighand->siglock);
        }
index 49b4885..d10f780 100644 (file)
@@ -441,7 +441,6 @@ start_secondary (void *unused)
 #endif
        efi_map_pal_code();
        cpu_init();
-       preempt_disable();
        smp_callin();
 
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
index 4d59ec2..d964c1f 100644 (file)
@@ -25,6 +25,9 @@ config ATARI
          this kernel on an Atari, say Y here and browse the material
          available in <file:Documentation/m68k>; otherwise say N.
 
+config ATARI_KBD_CORE
+       bool
+
 config MAC
        bool "Macintosh support"
        depends on MMU
index 82620f1..c54055a 100644 (file)
@@ -66,8 +66,7 @@ KBUILD_CFLAGS += $(cpuflags-y)
 KBUILD_CFLAGS += -pipe -ffreestanding
 
 ifdef CONFIG_MMU
-# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
-KBUILD_CFLAGS += -fno-strength-reduce -ffixed-a2
+KBUILD_CFLAGS += -ffixed-a2
 else
 # we can use a m68k-linux-gcc toolchain with these in place
 KBUILD_CPPFLAGS += -DUTS_SYSNAME=\"uClinux\"
index 44f9b52..261a0f5 100644 (file)
@@ -875,16 +875,8 @@ static const struct resource atari_scsi_tt_rsrc[] __initconst = {
 #define FALCON_IDE_BASE        0xfff00000
 
 static const struct resource atari_falconide_rsrc[] __initconst = {
-       {
-               .flags = IORESOURCE_MEM,
-               .start = FALCON_IDE_BASE,
-               .end   = FALCON_IDE_BASE + 0x39,
-       },
-       {
-               .flags = IORESOURCE_IRQ,
-               .start = IRQ_MFP_FSCSI,
-               .end   = IRQ_MFP_FSCSI,
-       },
+       DEFINE_RES_MEM(FALCON_IDE_BASE, 0x38),
+       DEFINE_RES_MEM(FALCON_IDE_BASE + 0x38, 2),
 };
 
 int __init atari_platform_init(void)
index 59b727b..0a2cacf 100644 (file)
@@ -85,7 +85,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -207,6 +206,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -253,7 +253,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -323,11 +322,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_DUMMY_IRQ=m
-CONFIG_IDE=y
-CONFIG_IDE_GD_ATAPI=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_GAYLE=y
-CONFIG_BLK_DEV_BUDDHA=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -344,6 +338,11 @@ CONFIG_GVP11_SCSI=y
 CONFIG_SCSI_A4000T=y
 CONFIG_SCSI_ZORRO7XX=y
 CONFIG_SCSI_ZORRO_ESP=y
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_GAYLE=y
+CONFIG_PATA_BUDDHA=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
@@ -563,6 +562,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -627,6 +627,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 8d4ddce..4dc6dcf 100644 (file)
@@ -81,7 +81,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -203,6 +202,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -249,7 +249,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -519,6 +518,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -583,6 +583,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 9cc9f1a..23d910a 100644 (file)
@@ -88,7 +88,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -210,6 +209,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -256,7 +256,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -324,10 +323,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_DUMMY_IRQ=m
-CONFIG_IDE=y
-CONFIG_IDE_GD_ATAPI=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_FALCON_IDE=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -339,6 +334,10 @@ CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_ATARI_SCSI=y
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_FALCON=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
@@ -541,6 +540,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -605,6 +605,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index c3f3f46..2c3f428 100644 (file)
@@ -78,7 +78,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -200,6 +199,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -246,7 +246,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -512,6 +511,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -576,6 +576,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 8c908fc..5b1898d 100644 (file)
@@ -80,7 +80,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -202,6 +201,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -248,7 +248,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -521,6 +520,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -585,6 +585,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 4e68b72..9606ccd 100644 (file)
@@ -79,7 +79,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -201,6 +200,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -247,7 +247,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -315,11 +314,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_DUMMY_IRQ=m
-CONFIG_IDE=y
-CONFIG_IDE_GD_ATAPI=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_PLATFORM=y
-CONFIG_BLK_DEV_MAC_IDE=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -332,6 +326,10 @@ CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
 CONFIG_MAC_SCSI=y
 CONFIG_SCSI_MAC_ESP=y
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_PLATFORM=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
@@ -544,6 +542,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -608,6 +607,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index d318962..3175ba5 100644 (file)
@@ -99,7 +99,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -221,6 +220,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -267,7 +267,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -344,15 +343,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_DUMMY_IRQ=m
-CONFIG_IDE=y
-CONFIG_IDE_GD_ATAPI=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_PLATFORM=y
-CONFIG_BLK_DEV_GAYLE=y
-CONFIG_BLK_DEV_BUDDHA=y
-CONFIG_BLK_DEV_FALCON_IDE=y
-CONFIG_BLK_DEV_MAC_IDE=y
-CONFIG_BLK_DEV_Q40IDE=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -376,6 +366,13 @@ CONFIG_MVME147_SCSI=y
 CONFIG_MVME16x_SCSI=y
 CONFIG_BVME6000_SCSI=y
 CONFIG_SUN3X_ESP=y
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_FALCON=y
+CONFIG_PATA_GAYLE=y
+CONFIG_PATA_BUDDHA=y
+CONFIG_PATA_PLATFORM=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
@@ -630,6 +627,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -694,6 +692,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index c7442f9..793085f 100644 (file)
@@ -77,7 +77,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -199,6 +198,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -245,7 +245,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -511,6 +510,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -575,6 +575,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 233b82e..56fbac7 100644 (file)
@@ -78,7 +78,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -200,6 +199,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -246,7 +246,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -512,6 +511,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -576,6 +576,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 664025a..0e15431 100644 (file)
@@ -79,7 +79,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -201,6 +200,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -247,7 +247,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -314,10 +313,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_DUMMY_IRQ=m
-CONFIG_IDE=y
-CONFIG_IDE_GD_ATAPI=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_Q40IDE=y
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -328,6 +323,10 @@ CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_ISCSI_TCP=m
 CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_FALCON=y
 CONFIG_MD=y
 CONFIG_MD_LINEAR=m
 CONFIG_BLK_DEV_DM=m
@@ -530,6 +529,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -594,6 +594,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 73293a0..3490a05 100644 (file)
@@ -75,7 +75,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -197,6 +196,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -243,7 +243,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -514,6 +513,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -577,6 +577,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index bca8a6f..4e92c8c 100644 (file)
@@ -75,7 +75,6 @@ CONFIG_IPV6_VTI=m
 CONFIG_IPV6_GRE=m
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
-CONFIG_NF_LOG_NETDEV=m
 CONFIG_NF_CONNTRACK_ZONES=y
 # CONFIG_NF_CONNTRACK_PROCFS is not set
 # CONFIG_NF_CT_PROTO_DCCP is not set
@@ -197,6 +196,7 @@ CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_NF_FLOW_TABLE_IPV4=m
 CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
@@ -243,7 +243,6 @@ CONFIG_IP6_NF_TARGET_NPT=m
 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
@@ -513,6 +512,7 @@ CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_RSA=m
 CONFIG_CRYPTO_DH=m
 CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
 CONFIG_CRYPTO_ECRDSA=m
 CONFIG_CRYPTO_SM2=m
 CONFIG_CRYPTO_CURVE25519=m
@@ -577,6 +577,7 @@ CONFIG_KUNIT_ALL_TESTS=m
 CONFIG_TEST_LIST_SORT=m
 CONFIG_TEST_MIN_HEAP=m
 CONFIG_TEST_SORT=m
+CONFIG_TEST_DIV64=m
 CONFIG_REED_SOLOMON_TEST=m
 CONFIG_ATOMIC64_SELFTEST=m
 CONFIG_ASYNC_RAID6_TEST=m
index 756c5cc..8637bf8 100644 (file)
@@ -16,8 +16,8 @@
  * We do not have SMP m68k systems, so we don't have to deal with that.
  */
 
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic_set(v, i)       WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_read(v)    READ_ONCE((v)->counter)
+#define arch_atomic_set(v, i)  WRITE_ONCE(((v)->counter), (i))
 
 /*
  * The ColdFire parts cannot do some immediate to memory operations,
@@ -30,7 +30,7 @@
 #endif
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        __asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\
 }                                                                      \
@@ -38,7 +38,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 #ifdef CONFIG_RMW_INSNS
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        int t, tmp;                                                     \
                                                                        \
@@ -48,12 +48,12 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
                        "       casl %2,%1,%0\n"                        \
                        "       jne 1b"                                 \
                        : "+m" (*v), "=&d" (t), "=&d" (tmp)             \
-                       : "g" (i), "2" (atomic_read(v)));               \
+                       : "g" (i), "2" (arch_atomic_read(v)));          \
        return t;                                                       \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        int t, tmp;                                                     \
                                                                        \
@@ -63,14 +63,14 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                     \
                        "       casl %2,%1,%0\n"                        \
                        "       jne 1b"                                 \
                        : "+m" (*v), "=&d" (t), "=&d" (tmp)             \
-                       : "g" (i), "2" (atomic_read(v)));               \
+                       : "g" (i), "2" (arch_atomic_read(v)));          \
        return tmp;                                                     \
 }
 
 #else
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
-static inline int atomic_##op##_return(int i, atomic_t * v)            \
+static inline int arch_atomic_##op##_return(int i, atomic_t * v)       \
 {                                                                      \
        unsigned long flags;                                            \
        int t;                                                          \
@@ -83,7 +83,7 @@ static inline int atomic_##op##_return(int i, atomic_t * v)           \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op, asm_op)                              \
-static inline int atomic_fetch_##op(int i, atomic_t * v)               \
+static inline int arch_atomic_fetch_##op(int i, atomic_t * v)          \
 {                                                                      \
        unsigned long flags;                                            \
        int t;                                                          \
@@ -120,27 +120,27 @@ ATOMIC_OPS(xor, ^=, eor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-static inline void atomic_inc(atomic_t *v)
+static inline void arch_atomic_inc(atomic_t *v)
 {
        __asm__ __volatile__("addql #1,%0" : "+m" (*v));
 }
-#define atomic_inc atomic_inc
+#define arch_atomic_inc arch_atomic_inc
 
-static inline void atomic_dec(atomic_t *v)
+static inline void arch_atomic_dec(atomic_t *v)
 {
        __asm__ __volatile__("subql #1,%0" : "+m" (*v));
 }
-#define atomic_dec atomic_dec
+#define arch_atomic_dec arch_atomic_dec
 
-static inline int atomic_dec_and_test(atomic_t *v)
+static inline int arch_atomic_dec_and_test(atomic_t *v)
 {
        char c;
        __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
        return c != 0;
 }
-#define atomic_dec_and_test atomic_dec_and_test
+#define arch_atomic_dec_and_test arch_atomic_dec_and_test
 
-static inline int atomic_dec_and_test_lt(atomic_t *v)
+static inline int arch_atomic_dec_and_test_lt(atomic_t *v)
 {
        char c;
        __asm__ __volatile__(
@@ -150,49 +150,49 @@ static inline int atomic_dec_and_test_lt(atomic_t *v)
        return c != 0;
 }
 
-static inline int atomic_inc_and_test(atomic_t *v)
+static inline int arch_atomic_inc_and_test(atomic_t *v)
 {
        char c;
        __asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
        return c != 0;
 }
-#define atomic_inc_and_test atomic_inc_and_test
+#define arch_atomic_inc_and_test arch_atomic_inc_and_test
 
 #ifdef CONFIG_RMW_INSNS
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, o, n) ((int)arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
 #else /* !CONFIG_RMW_INSNS */
 
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+static inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        unsigned long flags;
        int prev;
 
        local_irq_save(flags);
-       prev = atomic_read(v);
+       prev = arch_atomic_read(v);
        if (prev == old)
-               atomic_set(v, new);
+               arch_atomic_set(v, new);
        local_irq_restore(flags);
        return prev;
 }
 
-static inline int atomic_xchg(atomic_t *v, int new)
+static inline int arch_atomic_xchg(atomic_t *v, int new)
 {
        unsigned long flags;
        int prev;
 
        local_irq_save(flags);
-       prev = atomic_read(v);
-       atomic_set(v, new);
+       prev = arch_atomic_read(v);
+       arch_atomic_set(v, new);
        local_irq_restore(flags);
        return prev;
 }
 
 #endif /* !CONFIG_RMW_INSNS */
 
-static inline int atomic_sub_and_test(int i, atomic_t *v)
+static inline int arch_atomic_sub_and_test(int i, atomic_t *v)
 {
        char c;
        __asm__ __volatile__("subl %2,%1; seq %0"
@@ -200,9 +200,9 @@ static inline int atomic_sub_and_test(int i, atomic_t *v)
                             : ASM_DI (i));
        return c != 0;
 }
-#define atomic_sub_and_test atomic_sub_and_test
+#define arch_atomic_sub_and_test arch_atomic_sub_and_test
 
-static inline int atomic_add_negative(int i, atomic_t *v)
+static inline int arch_atomic_add_negative(int i, atomic_t *v)
 {
        char c;
        __asm__ __volatile__("addl %2,%1; smi %0"
@@ -210,6 +210,6 @@ static inline int atomic_add_negative(int i, atomic_t *v)
                             : ASM_DI (i));
        return c != 0;
 }
-#define atomic_add_negative atomic_add_negative
+#define arch_atomic_add_negative arch_atomic_add_negative
 
 #endif /* __ARCH_M68K_ATOMIC __ */
index a4aa820..e8ca4b0 100644 (file)
@@ -76,11 +76,11 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 }
 #endif
 
-#define xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
+#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
 
 #include <asm-generic/cmpxchg-local.h>
 
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 
 extern unsigned long __invalid_cmpxchg_size(volatile void *,
                                            unsigned long, unsigned long, int);
@@ -118,14 +118,14 @@ static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
        return old;
 }
 
-#define cmpxchg(ptr, o, n)                                                 \
+#define arch_cmpxchg(ptr, o, n)                                                    \
        ({(__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),          \
                        (unsigned long)(n), sizeof(*(ptr)));})
-#define cmpxchg_local(ptr, o, n)                                           \
+#define arch_cmpxchg_local(ptr, o, n)                                      \
        ({(__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),          \
                        (unsigned long)(n), sizeof(*(ptr)));})
 
-#define cmpxchg64(ptr, o, n)   cmpxchg64_local((ptr), (o), (n))
+#define arch_cmpxchg64(ptr, o, n)      arch_cmpxchg64_local((ptr), (o), (n))
 
 #else
 
index a5d3588..8ed6ac1 100644 (file)
@@ -31,7 +31,7 @@ static inline void get_mmu_context(struct mm_struct *mm)
 
        if (mm->context != NO_CONTEXT)
                return;
-       while (atomic_dec_and_test_lt(&nr_free_contexts)) {
+       while (arch_atomic_dec_and_test_lt(&nr_free_contexts)) {
                atomic_inc(&nr_free_contexts);
                steal_context();
        }
index 8d0f862..c9d0d84 100644 (file)
@@ -13,9 +13,9 @@ extern unsigned long memory_end;
 #define clear_user_page(page, vaddr, pg)       clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 
 #define __pa(vaddr)            ((unsigned long)(vaddr))
 #define __va(paddr)            ((void *)((unsigned long)(paddr)))
index 1c1b875..2e192a5 100644 (file)
@@ -34,9 +34,6 @@ pgprot_t pgprot_dmacoherent(pgprot_t prot)
        return prot;
 }
 #else
-
-#include <asm/cacheflush.h>
-
 void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs)
 {
index da83cc8..db49f90 100644 (file)
@@ -268,7 +268,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long fp, pc;
        unsigned long stack_page;
        int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long)task_stack_page(p);
index 1cdac95..5d16f9b 100644 (file)
@@ -933,13 +933,15 @@ static const struct resource mac_scsi_ccl_rsrc[] __initconst = {
        },
 };
 
-static const struct resource mac_ide_quadra_rsrc[] __initconst = {
-       DEFINE_RES_MEM(0x50F1A000, 0x104),
+static const struct resource mac_pata_quadra_rsrc[] __initconst = {
+       DEFINE_RES_MEM(0x50F1A000, 0x38),
+       DEFINE_RES_MEM(0x50F1A038, 0x04),
        DEFINE_RES_IRQ(IRQ_NUBUS_F),
 };
 
-static const struct resource mac_ide_pb_rsrc[] __initconst = {
-       DEFINE_RES_MEM(0x50F1A000, 0x104),
+static const struct resource mac_pata_pb_rsrc[] __initconst = {
+       DEFINE_RES_MEM(0x50F1A000, 0x38),
+       DEFINE_RES_MEM(0x50F1A038, 0x04),
        DEFINE_RES_IRQ(IRQ_NUBUS_C),
 };
 
@@ -949,7 +951,7 @@ static const struct resource mac_pata_baboon_rsrc[] __initconst = {
        DEFINE_RES_IRQ(IRQ_BABOON_1),
 };
 
-static const struct pata_platform_info mac_pata_baboon_data __initconst = {
+static const struct pata_platform_info mac_pata_data __initconst = {
        .ioport_shift = 2,
 };
 
@@ -1067,17 +1069,19 @@ int __init mac_platform_init(void)
 
        switch (macintosh_config->ide_type) {
        case MAC_IDE_QUADRA:
-               platform_device_register_simple("mac_ide", -1,
-                       mac_ide_quadra_rsrc, ARRAY_SIZE(mac_ide_quadra_rsrc));
+               platform_device_register_resndata(NULL, "pata_platform", -1,
+                       mac_pata_quadra_rsrc, ARRAY_SIZE(mac_pata_quadra_rsrc),
+                       &mac_pata_data, sizeof(mac_pata_data));
                break;
        case MAC_IDE_PB:
-               platform_device_register_simple("mac_ide", -1,
-                       mac_ide_pb_rsrc, ARRAY_SIZE(mac_ide_pb_rsrc));
+               platform_device_register_resndata(NULL, "pata_platform", -1,
+                       mac_pata_pb_rsrc, ARRAY_SIZE(mac_pata_pb_rsrc),
+                       &mac_pata_data, sizeof(mac_pata_data));
                break;
        case MAC_IDE_BABOON:
                platform_device_register_resndata(NULL, "pata_platform", -1,
                        mac_pata_baboon_rsrc, ARRAY_SIZE(mac_pata_baboon_rsrc),
-                       &mac_pata_baboon_data, sizeof(mac_pata_baboon_data));
+                       &mac_pata_data, sizeof(mac_pata_data));
                break;
        }
 
index d6a4238..5caf1e5 100644 (file)
@@ -286,14 +286,39 @@ static int q40_set_rtc_pll(struct rtc_pll_info *pll)
                return -EINVAL;
 }
 
-static __init int q40_add_kbd_device(void)
-{
-       struct platform_device *pdev;
+#define PCIDE_BASE1    0x1f0
+#define PCIDE_BASE2    0x170
+#define PCIDE_CTL      0x206
+
+static const struct resource q40_pata_rsrc_0[] __initconst = {
+       DEFINE_RES_MEM(q40_isa_io_base + PCIDE_BASE1 * 4, 0x38),
+       DEFINE_RES_MEM(q40_isa_io_base + (PCIDE_BASE1 + PCIDE_CTL) * 4, 2),
+       DEFINE_RES_IO(PCIDE_BASE1, 8),
+       DEFINE_RES_IO(PCIDE_BASE1 + PCIDE_CTL, 1),
+       DEFINE_RES_IRQ(14),
+};
 
+static const struct resource q40_pata_rsrc_1[] __initconst = {
+       DEFINE_RES_MEM(q40_isa_io_base + PCIDE_BASE2 * 4, 0x38),
+       DEFINE_RES_MEM(q40_isa_io_base + (PCIDE_BASE2 + PCIDE_CTL) * 4, 2),
+       DEFINE_RES_IO(PCIDE_BASE2, 8),
+       DEFINE_RES_IO(PCIDE_BASE2 + PCIDE_CTL, 1),
+       DEFINE_RES_IRQ(15),
+};
+
+static __init int q40_platform_init(void)
+{
        if (!MACH_IS_Q40)
                return -ENODEV;
 
-       pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
-       return PTR_ERR_OR_ZERO(pdev);
+       platform_device_register_simple("q40kbd", -1, NULL, 0);
+
+       platform_device_register_simple("atari-falcon-ide", 0, q40_pata_rsrc_0,
+                                       ARRAY_SIZE(q40_pata_rsrc_0));
+
+       platform_device_register_simple("atari-falcon-ide", 1, q40_pata_rsrc_1,
+                                       ARRAY_SIZE(q40_pata_rsrc_1));
+
+       return 0;
 }
-arch_initcall(q40_add_kbd_device);
+arch_initcall(q40_platform_init);
index 29b0e55..a055f5d 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 generated-y += syscall_table.h
+generic-y += cmpxchg.h
 generic-y += extable.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
diff --git a/arch/microblaze/include/asm/atomic.h b/arch/microblaze/include/asm/atomic.h
deleted file mode 100644 (file)
index 41e9aff..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_MICROBLAZE_ATOMIC_H
-#define _ASM_MICROBLAZE_ATOMIC_H
-
-#include <asm/cmpxchg.h>
-#include <asm-generic/atomic.h>
-#include <asm-generic/atomic64.h>
-
-/*
- * Atomically test *v and decrement if it is greater than 0.
- * The function returns the old value of *v minus 1.
- */
-static inline int atomic_dec_if_positive(atomic_t *v)
-{
-       unsigned long flags;
-       int res;
-
-       local_irq_save(flags);
-       res = v->counter - 1;
-       if (res >= 0)
-               v->counter = res;
-       local_irq_restore(flags);
-
-       return res;
-}
-#define atomic_dec_if_positive atomic_dec_if_positive
-
-#endif /* _ASM_MICROBLAZE_ATOMIC_H */
diff --git a/arch/microblaze/include/asm/cmpxchg.h b/arch/microblaze/include/asm/cmpxchg.h
deleted file mode 100644 (file)
index 3523b51..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_MICROBLAZE_CMPXCHG_H
-#define _ASM_MICROBLAZE_CMPXCHG_H
-
-#ifndef CONFIG_SMP
-# include <asm-generic/cmpxchg.h>
-#endif
-
-#endif /* _ASM_MICROBLAZE_CMPXCHG_H */
index 6c69ce7..b77dd18 100644 (file)
@@ -70,7 +70,6 @@ int main(int argc, char *argv[])
 
        /* struct task_struct */
        DEFINE(TS_THREAD_INFO, offsetof(struct task_struct, stack));
-       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
index 27ad767..95e1f7f 100644 (file)
 #include <asm/war.h>
 
 #define ATOMIC_OPS(pfx, type)                                          \
-static __always_inline type pfx##_read(const pfx##_t *v)               \
+static __always_inline type arch_##pfx##_read(const pfx##_t *v)                \
 {                                                                      \
        return READ_ONCE(v->counter);                                   \
 }                                                                      \
                                                                        \
-static __always_inline void pfx##_set(pfx##_t *v, type i)              \
+static __always_inline void arch_##pfx##_set(pfx##_t *v, type i)       \
 {                                                                      \
        WRITE_ONCE(v->counter, i);                                      \
 }                                                                      \
                                                                        \
-static __always_inline type pfx##_cmpxchg(pfx##_t *v, type o, type n)  \
+static __always_inline type                                            \
+arch_##pfx##_cmpxchg(pfx##_t *v, type o, type n)                       \
 {                                                                      \
-       return cmpxchg(&v->counter, o, n);                              \
+       return arch_cmpxchg(&v->counter, o, n);                         \
 }                                                                      \
                                                                        \
-static __always_inline type pfx##_xchg(pfx##_t *v, type n)             \
+static __always_inline type arch_##pfx##_xchg(pfx##_t *v, type n)      \
 {                                                                      \
-       return xchg(&v->counter, n);                                    \
+       return arch_xchg(&v->counter, n);                               \
 }
 
 ATOMIC_OPS(atomic, int)
@@ -53,7 +54,7 @@ ATOMIC_OPS(atomic64, s64)
 #endif
 
 #define ATOMIC_OP(pfx, op, type, c_op, asm_op, ll, sc)                 \
-static __inline__ void pfx##_##op(type i, pfx##_t * v)                 \
+static __inline__ void arch_##pfx##_##op(type i, pfx##_t * v)          \
 {                                                                      \
        type temp;                                                      \
                                                                        \
@@ -80,7 +81,8 @@ static __inline__ void pfx##_##op(type i, pfx##_t * v)                        \
 }
 
 #define ATOMIC_OP_RETURN(pfx, op, type, c_op, asm_op, ll, sc)          \
-static __inline__ type pfx##_##op##_return_relaxed(type i, pfx##_t * v)        \
+static __inline__ type                                                 \
+arch_##pfx##_##op##_return_relaxed(type i, pfx##_t * v)                        \
 {                                                                      \
        type temp, result;                                              \
                                                                        \
@@ -113,7 +115,8 @@ static __inline__ type pfx##_##op##_return_relaxed(type i, pfx##_t * v)     \
 }
 
 #define ATOMIC_FETCH_OP(pfx, op, type, c_op, asm_op, ll, sc)           \
-static __inline__ type pfx##_fetch_##op##_relaxed(type i, pfx##_t * v) \
+static __inline__ type                                                 \
+arch_##pfx##_fetch_##op##_relaxed(type i, pfx##_t * v)                 \
 {                                                                      \
        int temp, result;                                               \
                                                                        \
@@ -153,18 +156,18 @@ static __inline__ type pfx##_fetch_##op##_relaxed(type i, pfx##_t * v)    \
 ATOMIC_OPS(atomic, add, int, +=, addu, ll, sc)
 ATOMIC_OPS(atomic, sub, int, -=, subu, ll, sc)
 
-#define atomic_add_return_relaxed      atomic_add_return_relaxed
-#define atomic_sub_return_relaxed      atomic_sub_return_relaxed
-#define atomic_fetch_add_relaxed       atomic_fetch_add_relaxed
-#define atomic_fetch_sub_relaxed       atomic_fetch_sub_relaxed
+#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
+#define arch_atomic_fetch_add_relaxed  arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed  arch_atomic_fetch_sub_relaxed
 
 #ifdef CONFIG_64BIT
 ATOMIC_OPS(atomic64, add, s64, +=, daddu, lld, scd)
 ATOMIC_OPS(atomic64, sub, s64, -=, dsubu, lld, scd)
-# define atomic64_add_return_relaxed   atomic64_add_return_relaxed
-# define atomic64_sub_return_relaxed   atomic64_sub_return_relaxed
-# define atomic64_fetch_add_relaxed    atomic64_fetch_add_relaxed
-# define atomic64_fetch_sub_relaxed    atomic64_fetch_sub_relaxed
+# define arch_atomic64_add_return_relaxed      arch_atomic64_add_return_relaxed
+# define arch_atomic64_sub_return_relaxed      arch_atomic64_sub_return_relaxed
+# define arch_atomic64_fetch_add_relaxed       arch_atomic64_fetch_add_relaxed
+# define arch_atomic64_fetch_sub_relaxed       arch_atomic64_fetch_sub_relaxed
 #endif /* CONFIG_64BIT */
 
 #undef ATOMIC_OPS
@@ -176,17 +179,17 @@ ATOMIC_OPS(atomic, and, int, &=, and, ll, sc)
 ATOMIC_OPS(atomic, or, int, |=, or, ll, sc)
 ATOMIC_OPS(atomic, xor, int, ^=, xor, ll, sc)
 
-#define atomic_fetch_and_relaxed       atomic_fetch_and_relaxed
-#define atomic_fetch_or_relaxed                atomic_fetch_or_relaxed
-#define atomic_fetch_xor_relaxed       atomic_fetch_xor_relaxed
+#define arch_atomic_fetch_and_relaxed  arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_or_relaxed   arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed  arch_atomic_fetch_xor_relaxed
 
 #ifdef CONFIG_64BIT
 ATOMIC_OPS(atomic64, and, s64, &=, and, lld, scd)
 ATOMIC_OPS(atomic64, or, s64, |=, or, lld, scd)
 ATOMIC_OPS(atomic64, xor, s64, ^=, xor, lld, scd)
-# define atomic64_fetch_and_relaxed    atomic64_fetch_and_relaxed
-# define atomic64_fetch_or_relaxed     atomic64_fetch_or_relaxed
-# define atomic64_fetch_xor_relaxed    atomic64_fetch_xor_relaxed
+# define arch_atomic64_fetch_and_relaxed       arch_atomic64_fetch_and_relaxed
+# define arch_atomic64_fetch_or_relaxed                arch_atomic64_fetch_or_relaxed
+# define arch_atomic64_fetch_xor_relaxed       arch_atomic64_fetch_xor_relaxed
 #endif
 
 #undef ATOMIC_OPS
@@ -203,7 +206,7 @@ ATOMIC_OPS(atomic64, xor, s64, ^=, xor, lld, scd)
  * The function returns the old value of @v minus @i.
  */
 #define ATOMIC_SIP_OP(pfx, type, op, ll, sc)                           \
-static __inline__ int pfx##_sub_if_positive(type i, pfx##_t * v)       \
+static __inline__ int arch_##pfx##_sub_if_positive(type i, pfx##_t * v)        \
 {                                                                      \
        type temp, result;                                              \
                                                                        \
@@ -255,11 +258,11 @@ static __inline__ int pfx##_sub_if_positive(type i, pfx##_t * v)  \
 }
 
 ATOMIC_SIP_OP(atomic, int, subu, ll, sc)
-#define atomic_dec_if_positive(v)      atomic_sub_if_positive(1, v)
+#define arch_atomic_dec_if_positive(v) arch_atomic_sub_if_positive(1, v)
 
 #ifdef CONFIG_64BIT
 ATOMIC_SIP_OP(atomic64, s64, dsubu, lld, scd)
-#define atomic64_dec_if_positive(v)    atomic64_sub_if_positive(1, v)
+#define arch_atomic64_dec_if_positive(v)       arch_atomic64_sub_if_positive(1, v)
 #endif
 
 #undef ATOMIC_SIP_OP
index ed8f3f3..0b98380 100644 (file)
@@ -90,7 +90,7 @@ unsigned long __xchg(volatile void *ptr, unsigned long x, int size)
        }
 }
 
-#define xchg(ptr, x)                                                   \
+#define arch_xchg(ptr, x)                                              \
 ({                                                                     \
        __typeof__(*(ptr)) __res;                                       \
                                                                        \
@@ -175,14 +175,14 @@ unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        }
 }
 
-#define cmpxchg_local(ptr, old, new)                                   \
+#define arch_cmpxchg_local(ptr, old, new)                              \
        ((__typeof__(*(ptr)))                                           \
                __cmpxchg((ptr),                                        \
                          (unsigned long)(__typeof__(*(ptr)))(old),     \
                          (unsigned long)(__typeof__(*(ptr)))(new),     \
                          sizeof(*(ptr))))
 
-#define cmpxchg(ptr, old, new)                                         \
+#define arch_cmpxchg(ptr, old, new)                                    \
 ({                                                                     \
        __typeof__(*(ptr)) __res;                                       \
                                                                        \
@@ -194,7 +194,7 @@ unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        if (__SYNC_loongson3_war == 0)                                  \
                smp_mb__before_llsc();                                  \
                                                                        \
-       __res = cmpxchg_local((ptr), (old), (new));                     \
+       __res = arch_cmpxchg_local((ptr), (old), (new));                \
                                                                        \
        /*                                                              \
         * In the Loongson3 workaround case __cmpxchg_asm() already     \
@@ -208,21 +208,21 @@ unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 })
 
 #ifdef CONFIG_64BIT
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
   ({                                                                   \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_local((ptr), (o), (n));                                 \
+       arch_cmpxchg_local((ptr), (o), (n));                            \
   })
 
-#define cmpxchg64(ptr, o, n)                                           \
+#define arch_cmpxchg64(ptr, o, n)                                      \
   ({                                                                   \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg((ptr), (o), (n));                                       \
+       arch_cmpxchg((ptr), (o), (n));                                  \
   })
 #else
 
 # include <asm-generic/cmpxchg-local.h>
-# define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+# define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 
 # ifdef CONFIG_SMP
 
@@ -294,7 +294,7 @@ static inline unsigned long __cmpxchg64(volatile void *ptr,
        return ret;
 }
 
-#  define cmpxchg64(ptr, o, n) ({                                      \
+#  define arch_cmpxchg64(ptr, o, n) ({                                 \
        unsigned long long __old = (__typeof__(*(ptr)))(o);             \
        unsigned long long __new = (__typeof__(*(ptr)))(n);             \
        __typeof__(*(ptr)) __res;                                       \
@@ -317,7 +317,7 @@ static inline unsigned long __cmpxchg64(volatile void *ptr,
 })
 
 # else /* !CONFIG_SMP */
-#  define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
+#  define arch_cmpxchg64(ptr, o, n) arch_cmpxchg64_local((ptr), (o), (n))
 # endif /* !CONFIG_SMP */
 #endif /* !CONFIG_64BIT */
 
index f021de6..d1477ec 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/linkage.h>
 #include <linux/smp.h>
-#include <linux/irqdomain.h>
 
 #include <asm/mipsmtregs.h>
 
index fca4547..696f6b0 100644 (file)
@@ -109,10 +109,11 @@ static inline bool kvm_is_error_hva(unsigned long addr)
 }
 
 struct kvm_vm_stat {
-       ulong remote_tlb_flush;
+       struct kvm_vm_stat_generic generic;
 };
 
 struct kvm_vcpu_stat {
+       struct kvm_vcpu_stat_generic generic;
        u64 wait_exits;
        u64 cache_exits;
        u64 signal_exits;
@@ -142,12 +143,6 @@ struct kvm_vcpu_stat {
 #ifdef CONFIG_CPU_LOONGSON64
        u64 vz_cpucfg_exits;
 #endif
-       u64 halt_successful_poll;
-       u64 halt_attempted_poll;
-       u64 halt_poll_success_ns;
-       u64 halt_poll_fail_ns;
-       u64 halt_poll_invalid;
-       u64 halt_wakeup;
 };
 
 struct kvm_arch_memory_slot {
index 5735b2c..04ca752 100644 (file)
@@ -78,7 +78,6 @@ void output_ptreg_defines(void)
 void output_task_defines(void)
 {
        COMMENT("MIPS task_struct offsets.");
-       OFFSET(TASK_STATE, task_struct, state);
        OFFSET(TASK_THREAD_INFO, task_struct, stack);
        OFFSET(TASK_FLAGS, task_struct, flags);
        OFFSET(TASK_MM, task_struct, mm);
index 89107de..ac9c8cf 100644 (file)
@@ -41,7 +41,7 @@ unsigned long __xchg_small(volatile void *ptr, unsigned long val, unsigned int s
        do {
                old32 = load32;
                new32 = (load32 & ~mask) | (val << shift);
-               load32 = cmpxchg(ptr32, old32, new32);
+               load32 = arch_cmpxchg(ptr32, old32, new32);
        } while (load32 != old32);
 
        return (load32 & mask) >> shift;
@@ -97,7 +97,7 @@ unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
                 */
                old32 = (load32 & ~mask) | (old << shift);
                new32 = (load32 & ~mask) | (new << shift);
-               load32 = cmpxchg(ptr32, old32, new32);
+               load32 = arch_cmpxchg(ptr32, old32, new32);
                if (load32 == old32)
                        return old;
        }
index 54dfba8..75bff0f 100644 (file)
@@ -403,9 +403,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        struct kprobe *cur = kprobe_running();
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
-       if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-               return 1;
-
        if (kcb->kprobe_status & KPROBE_HIT_SS) {
                resume_execution(cur, regs, kcb);
                regs->cp0_status |= kcb->kprobe_old_SR;
index bff080d..73c8e79 100644 (file)
@@ -662,7 +662,7 @@ unsigned long get_wchan(struct task_struct *task)
        unsigned long ra = 0;
 #endif
 
-       if (!task || task == current || task->state == TASK_RUNNING)
+       if (!task || task == current || task_is_running(task))
                goto out;
        if (!task_stack_page(task))
                goto out;
index ef86fba..d542fb7 100644 (file)
@@ -348,7 +348,6 @@ asmlinkage void start_secondary(void)
         */
 
        calibrate_delay();
-       preempt_disable();
        cpu = smp_processor_id();
        cpu_data[cpu].udelay_val = loops_per_jiffy;
 
index 30cc060..c67250a 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for KVM support for MIPS
 #
 
-common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o eventfd.o)
+common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o eventfd.o binary_stats.o)
 
 EXTRA_CFLAGS += -Ivirt/kvm -Iarch/mips/kvm
 
index 4d4af97..af9dd02 100644 (file)
 #define VECTORSPACING 0x100    /* for EI/VI mode */
 #endif
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("wait", wait_exits),
-       VCPU_STAT("cache", cache_exits),
-       VCPU_STAT("signal", signal_exits),
-       VCPU_STAT("interrupt", int_exits),
-       VCPU_STAT("cop_unusable", cop_unusable_exits),
-       VCPU_STAT("tlbmod", tlbmod_exits),
-       VCPU_STAT("tlbmiss_ld", tlbmiss_ld_exits),
-       VCPU_STAT("tlbmiss_st", tlbmiss_st_exits),
-       VCPU_STAT("addrerr_st", addrerr_st_exits),
-       VCPU_STAT("addrerr_ld", addrerr_ld_exits),
-       VCPU_STAT("syscall", syscall_exits),
-       VCPU_STAT("resvd_inst", resvd_inst_exits),
-       VCPU_STAT("break_inst", break_inst_exits),
-       VCPU_STAT("trap_inst", trap_inst_exits),
-       VCPU_STAT("msa_fpe", msa_fpe_exits),
-       VCPU_STAT("fpe", fpe_exits),
-       VCPU_STAT("msa_disabled", msa_disabled_exits),
-       VCPU_STAT("flush_dcache", flush_dcache_exits),
-       VCPU_STAT("vz_gpsi", vz_gpsi_exits),
-       VCPU_STAT("vz_gsfc", vz_gsfc_exits),
-       VCPU_STAT("vz_hc", vz_hc_exits),
-       VCPU_STAT("vz_grr", vz_grr_exits),
-       VCPU_STAT("vz_gva", vz_gva_exits),
-       VCPU_STAT("vz_ghfc", vz_ghfc_exits),
-       VCPU_STAT("vz_gpa", vz_gpa_exits),
-       VCPU_STAT("vz_resvd", vz_resvd_exits),
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS()
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, wait_exits),
+       STATS_DESC_COUNTER(VCPU, cache_exits),
+       STATS_DESC_COUNTER(VCPU, signal_exits),
+       STATS_DESC_COUNTER(VCPU, int_exits),
+       STATS_DESC_COUNTER(VCPU, cop_unusable_exits),
+       STATS_DESC_COUNTER(VCPU, tlbmod_exits),
+       STATS_DESC_COUNTER(VCPU, tlbmiss_ld_exits),
+       STATS_DESC_COUNTER(VCPU, tlbmiss_st_exits),
+       STATS_DESC_COUNTER(VCPU, addrerr_st_exits),
+       STATS_DESC_COUNTER(VCPU, addrerr_ld_exits),
+       STATS_DESC_COUNTER(VCPU, syscall_exits),
+       STATS_DESC_COUNTER(VCPU, resvd_inst_exits),
+       STATS_DESC_COUNTER(VCPU, break_inst_exits),
+       STATS_DESC_COUNTER(VCPU, trap_inst_exits),
+       STATS_DESC_COUNTER(VCPU, msa_fpe_exits),
+       STATS_DESC_COUNTER(VCPU, fpe_exits),
+       STATS_DESC_COUNTER(VCPU, msa_disabled_exits),
+       STATS_DESC_COUNTER(VCPU, flush_dcache_exits),
+       STATS_DESC_COUNTER(VCPU, vz_gpsi_exits),
+       STATS_DESC_COUNTER(VCPU, vz_gsfc_exits),
+       STATS_DESC_COUNTER(VCPU, vz_hc_exits),
+       STATS_DESC_COUNTER(VCPU, vz_grr_exits),
+       STATS_DESC_COUNTER(VCPU, vz_gva_exits),
+       STATS_DESC_COUNTER(VCPU, vz_ghfc_exits),
+       STATS_DESC_COUNTER(VCPU, vz_gpa_exits),
+       STATS_DESC_COUNTER(VCPU, vz_resvd_exits),
 #ifdef CONFIG_CPU_LOONGSON64
-       VCPU_STAT("vz_cpucfg", vz_cpucfg_exits),
+       STATS_DESC_COUNTER(VCPU, vz_cpucfg_exits),
 #endif
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       {NULL}
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 bool kvm_trace_guest_mode_change;
index aeb1b98..63dccb2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/spinlock.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/of.h>
 
 #include <lantiq_soc.h>
 #include <xway_dma.h>
index aebd496..c48e23c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_pci.h>
index d221694..ab9bedb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/platform_data/xtalk-bridge.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/crc16.h>
+#include <linux/irqdomain.h>
 
 #include <asm/pci/bridge.h>
 #include <asm/paccess.h>
index 42df9fa..95c1bff 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
index e8374e4..ba87704 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <linux/tick.h>
index c1327e5..391895b 100644 (file)
@@ -239,7 +239,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long stack_start, stack_end;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        if (IS_ENABLED(CONFIG_FRAME_POINTER)) {
index 13ce372..c52c948 100644 (file)
@@ -10,6 +10,5 @@
 #define NIOS2_CPU_NR_IRQS      32
 
 #include <asm-generic/irq.h>
-#include <linux/irqdomain.h>
 
 #endif
index 5f3555c..c6a1a9f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/of.h>
 
 static u32 ienable;
index c5f916c..9ff37ba 100644 (file)
@@ -223,7 +223,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long stack_page;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long)p;
index b589fac..326167e 100644 (file)
@@ -13,7 +13,7 @@
 
 /* Atomically perform op with v->counter and i */
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        int tmp;                                                        \
                                                                        \
@@ -30,7 +30,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 
 /* Atomically perform op with v->counter and i, return the result */
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        int tmp;                                                        \
                                                                        \
@@ -49,7 +49,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 
 /* Atomically perform op with v->counter and i, return orig v->counter */
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        int tmp, old;                                                   \
                                                                        \
@@ -75,6 +75,8 @@ ATOMIC_FETCH_OP(and)
 ATOMIC_FETCH_OP(or)
 ATOMIC_FETCH_OP(xor)
 
+ATOMIC_OP(add)
+ATOMIC_OP(sub)
 ATOMIC_OP(and)
 ATOMIC_OP(or)
 ATOMIC_OP(xor)
@@ -83,16 +85,18 @@ ATOMIC_OP(xor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define atomic_add_return      atomic_add_return
-#define atomic_sub_return      atomic_sub_return
-#define atomic_fetch_add       atomic_fetch_add
-#define atomic_fetch_sub       atomic_fetch_sub
-#define atomic_fetch_and       atomic_fetch_and
-#define atomic_fetch_or                atomic_fetch_or
-#define atomic_fetch_xor       atomic_fetch_xor
-#define atomic_and     atomic_and
-#define atomic_or      atomic_or
-#define atomic_xor     atomic_xor
+#define arch_atomic_add_return arch_atomic_add_return
+#define arch_atomic_sub_return arch_atomic_sub_return
+#define arch_atomic_fetch_add  arch_atomic_fetch_add
+#define arch_atomic_fetch_sub  arch_atomic_fetch_sub
+#define arch_atomic_fetch_and  arch_atomic_fetch_and
+#define arch_atomic_fetch_or   arch_atomic_fetch_or
+#define arch_atomic_fetch_xor  arch_atomic_fetch_xor
+#define arch_atomic_add                arch_atomic_add
+#define arch_atomic_sub                arch_atomic_sub
+#define arch_atomic_and                arch_atomic_and
+#define arch_atomic_or         arch_atomic_or
+#define arch_atomic_xor                arch_atomic_xor
 
 /*
  * Atomically add a to v->counter as long as v is not already u.
@@ -100,7 +104,7 @@ ATOMIC_OP(xor)
  *
  * This is often used through atomic_inc_not_zero()
  */
-static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int old, tmp;
 
@@ -119,8 +123,14 @@ static inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
 
        return old;
 }
-#define atomic_fetch_add_unless        atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless   arch_atomic_fetch_add_unless
 
-#include <asm-generic/atomic.h>
+#define arch_atomic_read(v)            READ_ONCE((v)->counter)
+#define arch_atomic_set(v,i)           WRITE_ONCE((v)->counter, (i))
+
+#include <asm/cmpxchg.h>
+
+#define arch_atomic_xchg(ptr, v)               (arch_xchg(&(ptr)->counter, (v)))
+#define arch_atomic_cmpxchg(v, old, new)       (arch_cmpxchg(&((v)->counter), (old), (new)))
 
 #endif /* __ASM_OPENRISC_ATOMIC_H */
index f9cd43a..79fd161 100644 (file)
@@ -132,7 +132,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        }
 }
 
-#define cmpxchg(ptr, o, n)                                             \
+#define arch_cmpxchg(ptr, o, n)                                                \
        ({                                                              \
                (__typeof__(*(ptr))) __cmpxchg((ptr),                   \
                                               (unsigned long)(o),      \
@@ -161,7 +161,7 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long with,
        }
 }
 
-#define xchg(ptr, with)                                                \
+#define arch_xchg(ptr, with)                                           \
        ({                                                              \
                (__typeof__(*(ptr))) __xchg((ptr),                      \
                                            (unsigned long)(with),      \
index 18c703d..710651d 100644 (file)
@@ -37,7 +37,6 @@
 int main(void)
 {
        /* offsets into the task_struct */
-       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
index 48e1092..415e209 100644 (file)
@@ -145,8 +145,6 @@ asmlinkage __init void secondary_start_kernel(void)
        set_cpu_online(cpu, true);
 
        local_irq_enable();
-
-       preempt_disable();
        /*
         * OK, it's off to the idle thread for us
         */
index 21b375c..dd5a299 100644 (file)
@@ -56,7 +56,7 @@ extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
  * are atomic, so a reader never sees inconsistent values.
  */
 
-static __inline__ void atomic_set(atomic_t *v, int i)
+static __inline__ void arch_atomic_set(atomic_t *v, int i)
 {
        unsigned long flags;
        _atomic_spin_lock_irqsave(v, flags);
@@ -66,19 +66,19 @@ static __inline__ void atomic_set(atomic_t *v, int i)
        _atomic_spin_unlock_irqrestore(v, flags);
 }
 
-#define atomic_set_release(v, i)       atomic_set((v), (i))
+#define arch_atomic_set_release(v, i)  arch_atomic_set((v), (i))
 
-static __inline__ int atomic_read(const atomic_t *v)
+static __inline__ int arch_atomic_read(const atomic_t *v)
 {
        return READ_ONCE((v)->counter);
 }
 
 /* exported interface */
-#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, o, n)   (arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_xchg(v, new)       (arch_xchg(&((v)->counter), new))
 
 #define ATOMIC_OP(op, c_op)                                            \
-static __inline__ void atomic_##op(int i, atomic_t *v)                 \
+static __inline__ void arch_atomic_##op(int i, atomic_t *v)            \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -88,7 +88,7 @@ static __inline__ void atomic_##op(int i, atomic_t *v)                        \
 }
 
 #define ATOMIC_OP_RETURN(op, c_op)                                     \
-static __inline__ int atomic_##op##_return(int i, atomic_t *v)         \
+static __inline__ int arch_atomic_##op##_return(int i, atomic_t *v)    \
 {                                                                      \
        unsigned long flags;                                            \
        int ret;                                                        \
@@ -101,7 +101,7 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v)              \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op)                                      \
-static __inline__ int atomic_fetch_##op(int i, atomic_t *v)            \
+static __inline__ int arch_atomic_fetch_##op(int i, atomic_t *v)       \
 {                                                                      \
        unsigned long flags;                                            \
        int ret;                                                        \
@@ -141,7 +141,7 @@ ATOMIC_OPS(xor, ^=)
 #define ATOMIC64_INIT(i) { (i) }
 
 #define ATOMIC64_OP(op, c_op)                                          \
-static __inline__ void atomic64_##op(s64 i, atomic64_t *v)             \
+static __inline__ void arch_atomic64_##op(s64 i, atomic64_t *v)                \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -151,7 +151,7 @@ static __inline__ void atomic64_##op(s64 i, atomic64_t *v)          \
 }
 
 #define ATOMIC64_OP_RETURN(op, c_op)                                   \
-static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v)     \
+static __inline__ s64 arch_atomic64_##op##_return(s64 i, atomic64_t *v)        \
 {                                                                      \
        unsigned long flags;                                            \
        s64 ret;                                                        \
@@ -164,7 +164,7 @@ static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v)  \
 }
 
 #define ATOMIC64_FETCH_OP(op, c_op)                                    \
-static __inline__ s64 atomic64_fetch_##op(s64 i, atomic64_t *v)                \
+static __inline__ s64 arch_atomic64_fetch_##op(s64 i, atomic64_t *v)   \
 {                                                                      \
        unsigned long flags;                                            \
        s64 ret;                                                        \
@@ -200,7 +200,7 @@ ATOMIC64_OPS(xor, ^=)
 #undef ATOMIC64_OP
 
 static __inline__ void
-atomic64_set(atomic64_t *v, s64 i)
+arch_atomic64_set(atomic64_t *v, s64 i)
 {
        unsigned long flags;
        _atomic_spin_lock_irqsave(v, flags);
@@ -210,18 +210,18 @@ atomic64_set(atomic64_t *v, s64 i)
        _atomic_spin_unlock_irqrestore(v, flags);
 }
 
-#define atomic64_set_release(v, i)     atomic64_set((v), (i))
+#define arch_atomic64_set_release(v, i)        arch_atomic64_set((v), (i))
 
 static __inline__ s64
-atomic64_read(const atomic64_t *v)
+arch_atomic64_read(const atomic64_t *v)
 {
        return READ_ONCE((v)->counter);
 }
 
 /* exported interface */
-#define atomic64_cmpxchg(v, o, n) \
-       ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic64_cmpxchg(v, o, n) \
+       ((__typeof__((v)->counter))arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
 #endif /* !CONFIG_64BIT */
 
index 84ee232..5f274be 100644 (file)
@@ -44,7 +44,7 @@ __xchg(unsigned long x, volatile void *ptr, int size)
 **             if (((unsigned long)p & 0xf) == 0)
 **                     return __ldcw(p);
 */
-#define xchg(ptr, x)                                                   \
+#define arch_xchg(ptr, x)                                              \
 ({                                                                     \
        __typeof__(*(ptr)) __ret;                                       \
        __typeof__(*(ptr)) _x_ = (x);                                   \
@@ -78,7 +78,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
        return old;
 }
 
-#define cmpxchg(ptr, o, n)                                              \
+#define arch_cmpxchg(ptr, o, n)                                                 \
 ({                                                                      \
        __typeof__(*(ptr)) _o_ = (o);                                    \
        __typeof__(*(ptr)) _n_ = (n);                                    \
@@ -98,7 +98,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 #endif
        case 4: return __cmpxchg_u32(ptr, old, new_);
        default:
-               return __cmpxchg_local_generic(ptr, old, new_, size);
+               return __generic_cmpxchg_local(ptr, old, new_, size);
        }
 }
 
@@ -106,19 +106,19 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
  * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
  * them available.
  */
-#define cmpxchg_local(ptr, o, n)                                       \
+#define arch_cmpxchg_local(ptr, o, n)                                  \
        ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
                        (unsigned long)(n), sizeof(*(ptr))))
 #ifdef CONFIG_64BIT
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg_local((ptr), (o), (n));                                 \
 })
 #else
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 #endif
 
-#define cmpxchg64(ptr, o, n) __cmpxchg_u64(ptr, o, n)
+#define arch_cmpxchg64(ptr, o, n) __cmpxchg_u64(ptr, o, n)
 
 #endif /* _ASM_PARISC_CMPXCHG_H_ */
index cd2cc1b..33113ba 100644 (file)
@@ -42,7 +42,6 @@
 int main(void)
 {
        DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
-       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
index b144fbe..184ec3c 100644 (file)
@@ -249,7 +249,7 @@ get_wchan(struct task_struct *p)
        unsigned long ip;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        /*
@@ -260,7 +260,7 @@ get_wchan(struct task_struct *p)
        do {
                if (unwind_once(&info) < 0)
                        return 0;
-               if (p->state == TASK_RUNNING)
+               if (task_is_running(p))
                         return 0;
                ip = info.ip;
                if (!in_sched_functions(ip))
index 10227f6..1405b60 100644 (file)
@@ -302,7 +302,6 @@ void __init smp_callin(unsigned long pdce_proc)
 #endif
 
        smp_cpu_init(slave_id);
-       preempt_disable();
 
        flush_cache_all_local(); /* start with known state */
        flush_tlb_all_local(NULL);
index 1c7b758..02ee6f5 100644 (file)
@@ -120,6 +120,7 @@ extern s32 patch__call_flush_branch_caches3;
 extern s32 patch__flush_count_cache_return;
 extern s32 patch__flush_link_stack_return;
 extern s32 patch__call_kvm_flush_link_stack;
+extern s32 patch__call_kvm_flush_link_stack_p9;
 extern s32 patch__memset_nocache, patch__memcpy_nocache;
 
 extern long flush_branch_caches;
@@ -140,7 +141,7 @@ void kvmhv_load_host_pmu(void);
 void kvmhv_save_guest_pmu(struct kvm_vcpu *vcpu, bool pmu_in_use);
 void kvmhv_load_guest_pmu(struct kvm_vcpu *vcpu);
 
-int __kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu);
+void kvmppc_p9_enter_guest(struct kvm_vcpu *vcpu);
 
 long kvmppc_h_set_dabr(struct kvm_vcpu *vcpu, unsigned long dabr);
 long kvmppc_h_set_xdabr(struct kvm_vcpu *vcpu, unsigned long dabr,
index 61c6e8b..a1732a7 100644 (file)
@@ -23,7 +23,7 @@
 #define __atomic_release_fence()                                       \
        __asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory")
 
-static __inline__ int atomic_read(const atomic_t *v)
+static __inline__ int arch_atomic_read(const atomic_t *v)
 {
        int t;
 
@@ -32,13 +32,13 @@ static __inline__ int atomic_read(const atomic_t *v)
        return t;
 }
 
-static __inline__ void atomic_set(atomic_t *v, int i)
+static __inline__ void arch_atomic_set(atomic_t *v, int i)
 {
        __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"UPD_CONSTR(v->counter) : "r"(i));
 }
 
 #define ATOMIC_OP(op, asm_op)                                          \
-static __inline__ void atomic_##op(int a, atomic_t *v)                 \
+static __inline__ void arch_atomic_##op(int a, atomic_t *v)            \
 {                                                                      \
        int t;                                                          \
                                                                        \
@@ -53,7 +53,7 @@ static __inline__ void atomic_##op(int a, atomic_t *v)                        \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN_RELAXED(op, asm_op)                           \
-static inline int atomic_##op##_return_relaxed(int a, atomic_t *v)     \
+static inline int arch_atomic_##op##_return_relaxed(int a, atomic_t *v)        \
 {                                                                      \
        int t;                                                          \
                                                                        \
@@ -70,7 +70,7 @@ static inline int atomic_##op##_return_relaxed(int a, atomic_t *v)    \
 }
 
 #define ATOMIC_FETCH_OP_RELAXED(op, asm_op)                            \
-static inline int atomic_fetch_##op##_relaxed(int a, atomic_t *v)      \
+static inline int arch_atomic_fetch_##op##_relaxed(int a, atomic_t *v) \
 {                                                                      \
        int res, t;                                                     \
                                                                        \
@@ -94,11 +94,11 @@ static inline int atomic_fetch_##op##_relaxed(int a, atomic_t *v)   \
 ATOMIC_OPS(add, add)
 ATOMIC_OPS(sub, subf)
 
-#define atomic_add_return_relaxed atomic_add_return_relaxed
-#define atomic_sub_return_relaxed atomic_sub_return_relaxed
+#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
 
-#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
-#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
+#define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
 
 #undef ATOMIC_OPS
 #define ATOMIC_OPS(op, asm_op)                                         \
@@ -109,16 +109,16 @@ ATOMIC_OPS(and, and)
 ATOMIC_OPS(or, or)
 ATOMIC_OPS(xor, xor)
 
-#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
-#define atomic_fetch_or_relaxed  atomic_fetch_or_relaxed
-#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
+#define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_or_relaxed  arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
 
 #undef ATOMIC_OPS
 #undef ATOMIC_FETCH_OP_RELAXED
 #undef ATOMIC_OP_RETURN_RELAXED
 #undef ATOMIC_OP
 
-static __inline__ void atomic_inc(atomic_t *v)
+static __inline__ void arch_atomic_inc(atomic_t *v)
 {
        int t;
 
@@ -131,9 +131,9 @@ static __inline__ void atomic_inc(atomic_t *v)
        : "r" (&v->counter)
        : "cc", "xer");
 }
-#define atomic_inc atomic_inc
+#define arch_atomic_inc arch_atomic_inc
 
-static __inline__ int atomic_inc_return_relaxed(atomic_t *v)
+static __inline__ int arch_atomic_inc_return_relaxed(atomic_t *v)
 {
        int t;
 
@@ -149,7 +149,7 @@ static __inline__ int atomic_inc_return_relaxed(atomic_t *v)
        return t;
 }
 
-static __inline__ void atomic_dec(atomic_t *v)
+static __inline__ void arch_atomic_dec(atomic_t *v)
 {
        int t;
 
@@ -162,9 +162,9 @@ static __inline__ void atomic_dec(atomic_t *v)
        : "r" (&v->counter)
        : "cc", "xer");
 }
-#define atomic_dec atomic_dec
+#define arch_atomic_dec arch_atomic_dec
 
-static __inline__ int atomic_dec_return_relaxed(atomic_t *v)
+static __inline__ int arch_atomic_dec_return_relaxed(atomic_t *v)
 {
        int t;
 
@@ -180,17 +180,20 @@ static __inline__ int atomic_dec_return_relaxed(atomic_t *v)
        return t;
 }
 
-#define atomic_inc_return_relaxed atomic_inc_return_relaxed
-#define atomic_dec_return_relaxed atomic_dec_return_relaxed
+#define arch_atomic_inc_return_relaxed arch_atomic_inc_return_relaxed
+#define arch_atomic_dec_return_relaxed arch_atomic_dec_return_relaxed
 
-#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_cmpxchg_relaxed(v, o, n) \
-       cmpxchg_relaxed(&((v)->counter), (o), (n))
-#define atomic_cmpxchg_acquire(v, o, n) \
-       cmpxchg_acquire(&((v)->counter), (o), (n))
+#define arch_atomic_cmpxchg(v, o, n) \
+       (arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_cmpxchg_relaxed(v, o, n) \
+       arch_cmpxchg_relaxed(&((v)->counter), (o), (n))
+#define arch_atomic_cmpxchg_acquire(v, o, n) \
+       arch_cmpxchg_acquire(&((v)->counter), (o), (n))
 
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
+#define arch_atomic_xchg(v, new) \
+       (arch_xchg(&((v)->counter), new))
+#define arch_atomic_xchg_relaxed(v, new) \
+       arch_xchg_relaxed(&((v)->counter), (new))
 
 /*
  * Don't want to override the generic atomic_try_cmpxchg_acquire, because
@@ -199,7 +202,7 @@ static __inline__ int atomic_dec_return_relaxed(atomic_t *v)
  * would be a surprise).
  */
 static __always_inline bool
-atomic_try_cmpxchg_lock(atomic_t *v, int *old, int new)
+arch_atomic_try_cmpxchg_lock(atomic_t *v, int *old, int new)
 {
        int r, o = *old;
 
@@ -229,7 +232,7 @@ atomic_try_cmpxchg_lock(atomic_t *v, int *old, int new)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns the old value of @v.
  */
-static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static __inline__ int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int t;
 
@@ -250,7 +253,7 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
 
        return t;
 }
-#define atomic_fetch_add_unless atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
 
 /**
  * atomic_inc_not_zero - increment unless the number is zero
@@ -259,7 +262,7 @@ static __inline__ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
-static __inline__ int atomic_inc_not_zero(atomic_t *v)
+static __inline__ int arch_atomic_inc_not_zero(atomic_t *v)
 {
        int t1, t2;
 
@@ -280,14 +283,14 @@ static __inline__ int atomic_inc_not_zero(atomic_t *v)
 
        return t1;
 }
-#define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
+#define arch_atomic_inc_not_zero(v) arch_atomic_inc_not_zero((v))
 
 /*
  * Atomically test *v and decrement if it is greater than 0.
  * The function returns the old value of *v minus 1, even if
  * the atomic variable, v, was not decremented.
  */
-static __inline__ int atomic_dec_if_positive(atomic_t *v)
+static __inline__ int arch_atomic_dec_if_positive(atomic_t *v)
 {
        int t;
 
@@ -307,13 +310,13 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
 
        return t;
 }
-#define atomic_dec_if_positive atomic_dec_if_positive
+#define arch_atomic_dec_if_positive arch_atomic_dec_if_positive
 
 #ifdef __powerpc64__
 
 #define ATOMIC64_INIT(i)       { (i) }
 
-static __inline__ s64 atomic64_read(const atomic64_t *v)
+static __inline__ s64 arch_atomic64_read(const atomic64_t *v)
 {
        s64 t;
 
@@ -322,13 +325,13 @@ static __inline__ s64 atomic64_read(const atomic64_t *v)
        return t;
 }
 
-static __inline__ void atomic64_set(atomic64_t *v, s64 i)
+static __inline__ void arch_atomic64_set(atomic64_t *v, s64 i)
 {
        __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"UPD_CONSTR(v->counter) : "r"(i));
 }
 
 #define ATOMIC64_OP(op, asm_op)                                                \
-static __inline__ void atomic64_##op(s64 a, atomic64_t *v)             \
+static __inline__ void arch_atomic64_##op(s64 a, atomic64_t *v)                \
 {                                                                      \
        s64 t;                                                          \
                                                                        \
@@ -344,7 +347,7 @@ static __inline__ void atomic64_##op(s64 a, atomic64_t *v)          \
 
 #define ATOMIC64_OP_RETURN_RELAXED(op, asm_op)                         \
 static inline s64                                                      \
-atomic64_##op##_return_relaxed(s64 a, atomic64_t *v)                   \
+arch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v)              \
 {                                                                      \
        s64 t;                                                          \
                                                                        \
@@ -362,7 +365,7 @@ atomic64_##op##_return_relaxed(s64 a, atomic64_t *v)                        \
 
 #define ATOMIC64_FETCH_OP_RELAXED(op, asm_op)                          \
 static inline s64                                                      \
-atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v)                    \
+arch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v)               \
 {                                                                      \
        s64 res, t;                                                     \
                                                                        \
@@ -386,11 +389,11 @@ atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v)                       \
 ATOMIC64_OPS(add, add)
 ATOMIC64_OPS(sub, subf)
 
-#define atomic64_add_return_relaxed atomic64_add_return_relaxed
-#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
+#define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed
+#define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed
 
-#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
-#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
+#define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed
+#define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed
 
 #undef ATOMIC64_OPS
 #define ATOMIC64_OPS(op, asm_op)                                       \
@@ -401,16 +404,16 @@ ATOMIC64_OPS(and, and)
 ATOMIC64_OPS(or, or)
 ATOMIC64_OPS(xor, xor)
 
-#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
-#define atomic64_fetch_or_relaxed  atomic64_fetch_or_relaxed
-#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
+#define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed
+#define arch_atomic64_fetch_or_relaxed  arch_atomic64_fetch_or_relaxed
+#define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed
 
 #undef ATOPIC64_OPS
 #undef ATOMIC64_FETCH_OP_RELAXED
 #undef ATOMIC64_OP_RETURN_RELAXED
 #undef ATOMIC64_OP
 
-static __inline__ void atomic64_inc(atomic64_t *v)
+static __inline__ void arch_atomic64_inc(atomic64_t *v)
 {
        s64 t;
 
@@ -423,9 +426,9 @@ static __inline__ void atomic64_inc(atomic64_t *v)
        : "r" (&v->counter)
        : "cc", "xer");
 }
-#define atomic64_inc atomic64_inc
+#define arch_atomic64_inc arch_atomic64_inc
 
-static __inline__ s64 atomic64_inc_return_relaxed(atomic64_t *v)
+static __inline__ s64 arch_atomic64_inc_return_relaxed(atomic64_t *v)
 {
        s64 t;
 
@@ -441,7 +444,7 @@ static __inline__ s64 atomic64_inc_return_relaxed(atomic64_t *v)
        return t;
 }
 
-static __inline__ void atomic64_dec(atomic64_t *v)
+static __inline__ void arch_atomic64_dec(atomic64_t *v)
 {
        s64 t;
 
@@ -454,9 +457,9 @@ static __inline__ void atomic64_dec(atomic64_t *v)
        : "r" (&v->counter)
        : "cc", "xer");
 }
-#define atomic64_dec atomic64_dec
+#define arch_atomic64_dec arch_atomic64_dec
 
-static __inline__ s64 atomic64_dec_return_relaxed(atomic64_t *v)
+static __inline__ s64 arch_atomic64_dec_return_relaxed(atomic64_t *v)
 {
        s64 t;
 
@@ -472,14 +475,14 @@ static __inline__ s64 atomic64_dec_return_relaxed(atomic64_t *v)
        return t;
 }
 
-#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
-#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
+#define arch_atomic64_inc_return_relaxed arch_atomic64_inc_return_relaxed
+#define arch_atomic64_dec_return_relaxed arch_atomic64_dec_return_relaxed
 
 /*
  * Atomically test *v and decrement if it is greater than 0.
  * The function returns the old value of *v minus 1.
  */
-static __inline__ s64 atomic64_dec_if_positive(atomic64_t *v)
+static __inline__ s64 arch_atomic64_dec_if_positive(atomic64_t *v)
 {
        s64 t;
 
@@ -498,16 +501,19 @@ static __inline__ s64 atomic64_dec_if_positive(atomic64_t *v)
 
        return t;
 }
-#define atomic64_dec_if_positive atomic64_dec_if_positive
+#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
 
-#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
-#define atomic64_cmpxchg_relaxed(v, o, n) \
-       cmpxchg_relaxed(&((v)->counter), (o), (n))
-#define atomic64_cmpxchg_acquire(v, o, n) \
-       cmpxchg_acquire(&((v)->counter), (o), (n))
+#define arch_atomic64_cmpxchg(v, o, n) \
+       (arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic64_cmpxchg_relaxed(v, o, n) \
+       arch_cmpxchg_relaxed(&((v)->counter), (o), (n))
+#define arch_atomic64_cmpxchg_acquire(v, o, n) \
+       arch_cmpxchg_acquire(&((v)->counter), (o), (n))
 
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic64_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
+#define arch_atomic64_xchg(v, new) \
+       (arch_xchg(&((v)->counter), new))
+#define arch_atomic64_xchg_relaxed(v, new) \
+       arch_xchg_relaxed(&((v)->counter), (new))
 
 /**
  * atomic64_fetch_add_unless - add unless the number is a given value
@@ -518,7 +524,7 @@ static __inline__ s64 atomic64_dec_if_positive(atomic64_t *v)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns the old value of @v.
  */
-static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+static __inline__ s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        s64 t;
 
@@ -539,7 +545,7 @@ static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 
        return t;
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
 
 /**
  * atomic_inc64_not_zero - increment unless the number is zero
@@ -548,7 +554,7 @@ static __inline__ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
  * Atomically increments @v by 1, so long as @v is non-zero.
  * Returns non-zero if @v was non-zero, and zero otherwise.
  */
-static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
+static __inline__ int arch_atomic64_inc_not_zero(atomic64_t *v)
 {
        s64 t1, t2;
 
@@ -569,7 +575,7 @@ static __inline__ int atomic64_inc_not_zero(atomic64_t *v)
 
        return t1 != 0;
 }
-#define atomic64_inc_not_zero(v) atomic64_inc_not_zero((v))
+#define arch_atomic64_inc_not_zero(v) arch_atomic64_inc_not_zero((v))
 
 #endif /* __powerpc64__ */
 
index eace8c3..c02f42d 100644 (file)
@@ -19,6 +19,7 @@ struct mmu_psize_def {
        int             penc[MMU_PAGE_COUNT];   /* HPTE encoding */
        unsigned int    tlbiel; /* tlbiel supported for that page size */
        unsigned long   avpnm;  /* bits to mask out in AVPN in the HPTE */
+       unsigned long   h_rpt_pgsize; /* H_RPT_INVALIDATE page size encoding */
        union {
                unsigned long   sllp;   /* SLB L||LP (exact mask to use in slbmte) */
                unsigned long ap;       /* Ap encoding used by PowerISA 3.0 */
index 8b33601..a46fd37 100644 (file)
@@ -4,6 +4,10 @@
 
 #include <asm/hvcall.h>
 
+#define RIC_FLUSH_TLB 0
+#define RIC_FLUSH_PWC 1
+#define RIC_FLUSH_ALL 2
+
 struct vm_area_struct;
 struct mm_struct;
 struct mmu_gather;
index cf091c4..05f246c 100644 (file)
@@ -185,14 +185,14 @@ __xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
        BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local");
        return x;
 }
-#define xchg_local(ptr,x)                                                   \
+#define arch_xchg_local(ptr,x)                                              \
   ({                                                                        \
      __typeof__(*(ptr)) _x_ = (x);                                          \
      (__typeof__(*(ptr))) __xchg_local((ptr),                               \
                (unsigned long)_x_, sizeof(*(ptr)));                         \
   })
 
-#define xchg_relaxed(ptr, x)                                           \
+#define arch_xchg_relaxed(ptr, x)                                      \
 ({                                                                     \
        __typeof__(*(ptr)) _x_ = (x);                                   \
        (__typeof__(*(ptr))) __xchg_relaxed((ptr),                      \
@@ -467,7 +467,7 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
        BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_acquire");
        return old;
 }
-#define cmpxchg(ptr, o, n)                                              \
+#define arch_cmpxchg(ptr, o, n)                                                 \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -476,7 +476,7 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
   })
 
 
-#define cmpxchg_local(ptr, o, n)                                        \
+#define arch_cmpxchg_local(ptr, o, n)                                   \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -484,7 +484,7 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
                                    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
-#define cmpxchg_relaxed(ptr, o, n)                                     \
+#define arch_cmpxchg_relaxed(ptr, o, n)                                        \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
@@ -493,7 +493,7 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
                        sizeof(*(ptr)));                                \
 })
 
-#define cmpxchg_acquire(ptr, o, n)                                     \
+#define arch_cmpxchg_acquire(ptr, o, n)                                        \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
@@ -502,29 +502,29 @@ __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
                        sizeof(*(ptr)));                                \
 })
 #ifdef CONFIG_PPC64
-#define cmpxchg64(ptr, o, n)                                           \
+#define arch_cmpxchg64(ptr, o, n)                                      \
   ({                                                                   \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg((ptr), (o), (n));                                       \
+       arch_cmpxchg((ptr), (o), (n));                                  \
   })
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
   ({                                                                   \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_local((ptr), (o), (n));                                 \
+       arch_cmpxchg_local((ptr), (o), (n));                            \
   })
-#define cmpxchg64_relaxed(ptr, o, n)                                   \
+#define arch_cmpxchg64_relaxed(ptr, o, n)                              \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_relaxed((ptr), (o), (n));                               \
+       arch_cmpxchg_relaxed((ptr), (o), (n));                          \
 })
-#define cmpxchg64_acquire(ptr, o, n)                                   \
+#define arch_cmpxchg64_acquire(ptr, o, n)                              \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_acquire((ptr), (o), (n));                               \
+       arch_cmpxchg_acquire((ptr), (o), (n));                          \
 })
 #else
 #include <asm-generic/cmpxchg-local.h>
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 #endif
 
 #endif /* __KERNEL__ */
index 98c8bd1..b167186 100644 (file)
@@ -98,6 +98,36 @@ static inline int cpu_last_thread_sibling(int cpu)
        return cpu | (threads_per_core - 1);
 }
 
+/*
+ * tlb_thread_siblings are siblings which share a TLB. This is not
+ * architected, is not something a hypervisor could emulate and a future
+ * CPU may change behaviour even in compat mode, so this should only be
+ * used on PowerNV, and only with care.
+ */
+static inline int cpu_first_tlb_thread_sibling(int cpu)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+               return cpu & ~0x6;      /* Big Core */
+       else
+               return cpu_first_thread_sibling(cpu);
+}
+
+static inline int cpu_last_tlb_thread_sibling(int cpu)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+               return cpu | 0x6;       /* Big Core */
+       else
+               return cpu_last_thread_sibling(cpu);
+}
+
+static inline int cpu_tlb_thread_sibling_step(void)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_300) && (threads_per_core == 8))
+               return 2;               /* Big Core */
+       else
+               return 1;
+}
+
 static inline u32 get_tensr(void)
 {
 #ifdef CONFIG_BOOKE
index c1a8aac..bb6f78f 100644 (file)
 /* PACA save area size in u64 units (exgen, exmc, etc) */
 #define EX_SIZE                10
 
+/* PACA save area offsets */
+#define EX_R9          0
+#define EX_R10         8
+#define EX_R11         16
+#define EX_R12         24
+#define EX_R13         32
+#define EX_DAR         40
+#define EX_DSISR       48
+#define EX_CCR         52
+#define EX_CFAR                56
+#define EX_PPR         64
+#define EX_CTR         72
+
 /*
  * maximum recursive depth of MCE exceptions
  */
index e3b29ed..7e4b2ce 100644 (file)
 #define H_RPTI_TYPE_NESTED     0x0001  /* Invalidate nested guest partition-scope */
 #define H_RPTI_TYPE_TLB                0x0002  /* Invalidate TLB */
 #define H_RPTI_TYPE_PWC                0x0004  /* Invalidate Page Walk Cache */
-/* Invalidate Process Table Entries if H_RPTI_TYPE_NESTED is clear */
+/* Invalidate caching of Process Table Entries if H_RPTI_TYPE_NESTED is clear */
 #define H_RPTI_TYPE_PRT                0x0008
-/* Invalidate Partition Table Entries if H_RPTI_TYPE_NESTED is set */
+/* Invalidate caching of Partition Table Entries if H_RPTI_TYPE_NESTED is set */
 #define H_RPTI_TYPE_PAT                0x0008
 #define H_RPTI_TYPE_ALL                (H_RPTI_TYPE_TLB | H_RPTI_TYPE_PWC | \
                                 H_RPTI_TYPE_PRT)
index b2bd588..4982f37 100644 (file)
@@ -6,7 +6,6 @@
 /*
  */
 
-#include <linux/irqdomain.h>
 #include <linux/threads.h>
 #include <linux/list.h>
 #include <linux/radix-tree.h>
@@ -23,8 +22,8 @@ extern atomic_t ppc_n_lost_interrupts;
 /* Total number of virq in the platform */
 #define NR_IRQS                CONFIG_NR_IRQS
 
-/* Same thing, used by the generic IRQ code */
-#define NR_IRQS_LEGACY         NUM_ISA_INTERRUPTS
+/* Number of irqs reserved for a legacy isa controller */
+#define NR_IRQS_LEGACY         16
 
 extern irq_hw_number_t virq_to_hw(unsigned int virq);
 
index 2d5c6be..93ce3ec 100644 (file)
@@ -50,7 +50,7 @@ l_yes:
 1098:  nop;                                    \
        .pushsection __jump_table, "aw";        \
        .long 1098b - ., LABEL - .;             \
-       FTR_ENTRY_LONG KEY;                     \
+       FTR_ENTRY_LONG KEY - .;                 \
        .popsection
 #endif
 
index a363356..fbbf3ce 100644 (file)
 #define KVM_GUEST_MODE_SKIP    2
 #define KVM_GUEST_MODE_GUEST_HV        3
 #define KVM_GUEST_MODE_HOST_HV 4
+#define KVM_GUEST_MODE_HV_P9   5 /* ISA >= v3.0 path */
 
 #define KVM_INST_FETCH_FAILED  -1
 
index e6b53c6..caaa0f5 100644 (file)
@@ -307,6 +307,9 @@ void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1);
 void kvmhv_release_all_nested(struct kvm *kvm);
 long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu);
 long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu);
+long do_h_rpt_invalidate_pat(struct kvm_vcpu *vcpu, unsigned long lpid,
+                            unsigned long type, unsigned long pg_sizes,
+                            unsigned long start, unsigned long end);
 int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu,
                          u64 time_limit, unsigned long lpcr);
 void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr);
index 9bb9bb3..eaf3a56 100644 (file)
@@ -153,10 +153,18 @@ static inline bool kvmhv_vcpu_is_radix(struct kvm_vcpu *vcpu)
        return radix;
 }
 
+int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr);
+
 #define KVM_DEFAULT_HPT_ORDER  24      /* 16MB HPT by default */
 #endif
 
 /*
+ * Invalid HDSISR value which is used to indicate when HW has not set the reg.
+ * Used to work around an errata.
+ */
+#define HDSISR_CANARY  0x7fff
+
+/*
  * We use a lock bit in HPTE dword 0 to synchronize updates and
  * accesses to each HPTE, and another bit to indicate non-present
  * HPTEs.
index 7f2e90d..9f52f28 100644 (file)
@@ -81,12 +81,13 @@ struct kvmppc_book3s_shadow_vcpu;
 struct kvm_nested_guest;
 
 struct kvm_vm_stat {
-       ulong remote_tlb_flush;
-       ulong num_2M_pages;
-       ulong num_1G_pages;
+       struct kvm_vm_stat_generic generic;
+       u64 num_2M_pages;
+       u64 num_1G_pages;
 };
 
 struct kvm_vcpu_stat {
+       struct kvm_vcpu_stat_generic generic;
        u64 sum_exits;
        u64 mmio_exits;
        u64 signal_exits;
@@ -102,14 +103,8 @@ struct kvm_vcpu_stat {
        u64 emulated_inst_exits;
        u64 dec_exits;
        u64 ext_intr_exits;
-       u64 halt_poll_success_ns;
-       u64 halt_poll_fail_ns;
        u64 halt_wait_ns;
-       u64 halt_successful_poll;
-       u64 halt_attempted_poll;
        u64 halt_successful_wait;
-       u64 halt_poll_invalid;
-       u64 halt_wakeup;
        u64 dbell_exits;
        u64 gdbell_exits;
        u64 ld;
@@ -298,7 +293,6 @@ struct kvm_arch {
        u8 fwnmi_enabled;
        u8 secure_guest;
        u8 svm_enabled;
-       bool threads_indep;
        bool nested_enable;
        bool dawr1_enabled;
        pgd_t *pgtable;
@@ -684,7 +678,12 @@ struct kvm_vcpu_arch {
        ulong fault_dar;
        u32 fault_dsisr;
        unsigned long intr_msr;
-       ulong fault_gpa;        /* guest real address of page fault (POWER9) */
+       /*
+        * POWER9 and later: fault_gpa contains the guest real address of page
+        * fault for a radix guest, or segment descriptor (equivalent to result
+        * from slbmfev of SLB entry that translated the EA) for hash guests.
+        */
+       ulong fault_gpa;
 #endif
 
 #ifdef CONFIG_BOOKE
index 5bf8ae9..2d88944 100644 (file)
@@ -129,6 +129,7 @@ extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong flags);
+extern void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags);
 extern void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu);
@@ -606,6 +607,7 @@ extern void kvmppc_free_pimap(struct kvm *kvm);
 extern int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall);
 extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
 extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
+extern int kvmppc_xive_xics_hcall(struct kvm_vcpu *vcpu, u32 req);
 extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu);
 extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
 extern int kvmppc_xics_connect_vcpu(struct kvm_device *dev,
@@ -638,6 +640,8 @@ static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu)
 static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { }
 static inline int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd)
        { return 0; }
+static inline int kvmppc_xive_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
+       { return 0; }
 #endif
 
 #ifdef CONFIG_KVM_XIVE
@@ -655,8 +659,6 @@ extern int kvmppc_xive_get_xive(struct kvm *kvm, u32 irq, u32 *server,
                                u32 *priority);
 extern int kvmppc_xive_int_on(struct kvm *kvm, u32 irq);
 extern int kvmppc_xive_int_off(struct kvm *kvm, u32 irq);
-extern void kvmppc_xive_init_module(void);
-extern void kvmppc_xive_exit_module(void);
 
 extern int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
                                    struct kvm_vcpu *vcpu, u32 cpu);
@@ -671,6 +673,8 @@ extern int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
 extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
                               int level, bool line_status);
 extern void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu);
+extern void kvmppc_xive_pull_vcpu(struct kvm_vcpu *vcpu);
+extern void kvmppc_xive_rearm_escalation(struct kvm_vcpu *vcpu);
 
 static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
 {
@@ -680,8 +684,6 @@ static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
 extern int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
                                           struct kvm_vcpu *vcpu, u32 cpu);
 extern void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu);
-extern void kvmppc_xive_native_init_module(void);
-extern void kvmppc_xive_native_exit_module(void);
 extern int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
                                     union kvmppc_one_reg *val);
 extern int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu,
@@ -695,8 +697,6 @@ static inline int kvmppc_xive_get_xive(struct kvm *kvm, u32 irq, u32 *server,
                                       u32 *priority) { return -1; }
 static inline int kvmppc_xive_int_on(struct kvm *kvm, u32 irq) { return -1; }
 static inline int kvmppc_xive_int_off(struct kvm *kvm, u32 irq) { return -1; }
-static inline void kvmppc_xive_init_module(void) { }
-static inline void kvmppc_xive_exit_module(void) { }
 
 static inline int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
                                           struct kvm_vcpu *vcpu, u32 cpu) { return -EBUSY; }
@@ -711,14 +711,14 @@ static inline int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { retur
 static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
                                      int level, bool line_status) { return -ENODEV; }
 static inline void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu) { }
+static inline void kvmppc_xive_pull_vcpu(struct kvm_vcpu *vcpu) { }
+static inline void kvmppc_xive_rearm_escalation(struct kvm_vcpu *vcpu) { }
 
 static inline int kvmppc_xive_enabled(struct kvm_vcpu *vcpu)
        { return 0; }
 static inline int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
                          struct kvm_vcpu *vcpu, u32 cpu) { return -EBUSY; }
 static inline void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu) { }
-static inline void kvmppc_xive_native_init_module(void) { }
-static inline void kvmppc_xive_native_exit_module(void) { }
 static inline int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
                                            union kvmppc_one_reg *val)
 { return 0; }
@@ -754,7 +754,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
                           unsigned long tce_value, unsigned long npages);
 long int kvmppc_rm_h_confer(struct kvm_vcpu *vcpu, int target,
                             unsigned int yield_count);
-long kvmppc_h_random(struct kvm_vcpu *vcpu);
+long kvmppc_rm_h_random(struct kvm_vcpu *vcpu);
 void kvmhv_commence_exit(int trap);
 void kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu);
 void kvmppc_subcore_enter_guest(void);
index 4bc45d3..db186c5 100644 (file)
@@ -122,12 +122,6 @@ static inline bool need_extra_context(struct mm_struct *mm, unsigned long ea)
 }
 #endif
 
-#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) && defined(CONFIG_PPC_RADIX_MMU)
-extern void radix_kvm_prefetch_workaround(struct mm_struct *mm);
-#else
-static inline void radix_kvm_prefetch_workaround(struct mm_struct *mm) { }
-#endif
-
 extern void switch_cop(struct mm_struct *next);
 extern int use_cop(unsigned long acop, struct mm_struct *mm);
 extern void drop_cop(unsigned long acop, struct mm_struct *mm);
@@ -222,6 +216,18 @@ static inline void mm_context_add_copro(struct mm_struct *mm) { }
 static inline void mm_context_remove_copro(struct mm_struct *mm) { }
 #endif
 
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) && defined(CONFIG_PPC_RADIX_MMU)
+void do_h_rpt_invalidate_prt(unsigned long pid, unsigned long lpid,
+                            unsigned long type, unsigned long pg_sizes,
+                            unsigned long start, unsigned long end);
+#else
+static inline void do_h_rpt_invalidate_prt(unsigned long pid,
+                                          unsigned long lpid,
+                                          unsigned long type,
+                                          unsigned long pg_sizes,
+                                          unsigned long start,
+                                          unsigned long end) { }
+#endif
 
 extern void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
                               struct task_struct *tsk);
index 07318bc..b676c4f 100644 (file)
@@ -37,7 +37,7 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)
 {
        u32 val = 0;
 
-       if (likely(atomic_try_cmpxchg_lock(&lock->val, &val, _Q_LOCKED_VAL)))
+       if (likely(arch_atomic_try_cmpxchg_lock(&lock->val, &val, _Q_LOCKED_VAL)))
                return;
 
        queued_spin_lock_slowpath(lock, val);
index 8dd3cdb..8c2c3dd 100644 (file)
@@ -97,6 +97,18 @@ extern void div128_by_32(u64 dividend_high, u64 dividend_low,
 extern void secondary_cpu_time_init(void);
 extern void __init time_init(void);
 
+#ifdef CONFIG_PPC64
+static inline unsigned long test_irq_work_pending(void)
+{
+       unsigned long x;
+
+       asm volatile("lbz %0,%1(13)"
+               : "=r" (x)
+               : "i" (offsetof(struct paca_struct, irq_work_pending)));
+       return x;
+}
+#endif
+
 DECLARE_PER_CPU(u64, decrementers_next_tb);
 
 /* Convert timebase ticks to nanoseconds */
index 28af4ef..aa267d1 100644 (file)
@@ -534,7 +534,6 @@ int main(void)
        OFFSET(VCPU_SLB_NR, kvm_vcpu, arch.slb_nr);
        OFFSET(VCPU_FAULT_DSISR, kvm_vcpu, arch.fault_dsisr);
        OFFSET(VCPU_FAULT_DAR, kvm_vcpu, arch.fault_dar);
-       OFFSET(VCPU_FAULT_GPA, kvm_vcpu, arch.fault_gpa);
        OFFSET(VCPU_INTR_MSR, kvm_vcpu, arch.intr_msr);
        OFFSET(VCPU_LAST_INST, kvm_vcpu, arch.last_inst);
        OFFSET(VCPU_TRAP, kvm_vcpu, arch.trap);
index fa8e52a..f7fc6e0 100644 (file)
 #include <asm/feature-fixups.h>
 #include <asm/kup.h>
 
-/* PACA save area offsets (exgen, exmc, etc) */
-#define EX_R9          0
-#define EX_R10         8
-#define EX_R11         16
-#define EX_R12         24
-#define EX_R13         32
-#define EX_DAR         40
-#define EX_DSISR       48
-#define EX_CCR         52
-#define EX_CFAR                56
-#define EX_PPR         64
-#define EX_CTR         72
-.if EX_SIZE != 10
-       .error "EX_SIZE is wrong"
-.endif
-
 /*
  * Following are fixed section helper macros.
  *
@@ -133,7 +117,6 @@ name:
 #define IBRANCH_TO_COMMON      .L_IBRANCH_TO_COMMON_\name\() /* ENTRY branch to common */
 #define IREALMODE_COMMON       .L_IREALMODE_COMMON_\name\() /* Common runs in realmode */
 #define IMASK          .L_IMASK_\name\()       /* IRQ soft-mask bit */
-#define IKVM_SKIP      .L_IKVM_SKIP_\name\()   /* Generate KVM skip handler */
 #define IKVM_REAL      .L_IKVM_REAL_\name\()   /* Real entry tests KVM */
 #define __IKVM_REAL(name)      .L_IKVM_REAL_ ## name
 #define IKVM_VIRT      .L_IKVM_VIRT_\name\()   /* Virt entry tests KVM */
@@ -190,9 +173,6 @@ do_define_int n
        .ifndef IMASK
                IMASK=0
        .endif
-       .ifndef IKVM_SKIP
-               IKVM_SKIP=0
-       .endif
        .ifndef IKVM_REAL
                IKVM_REAL=0
        .endif
@@ -207,8 +187,6 @@ do_define_int n
        .endif
 .endm
 
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 /*
  * All interrupts which set HSRR registers, as well as SRESET and MCE and
  * syscall when invoked with "sc 1" switch to MSR[HV]=1 (HVMODE) to be taken,
@@ -238,88 +216,28 @@ do_define_int n
 
 /*
  * If an interrupt is taken while a guest is running, it is immediately routed
- * to KVM to handle. If both HV and PR KVM arepossible, KVM interrupts go first
- * to kvmppc_interrupt_hv, which handles the PR guest case.
+ * to KVM to handle.
  */
-#define kvmppc_interrupt kvmppc_interrupt_hv
-#else
-#define kvmppc_interrupt kvmppc_interrupt_pr
-#endif
 
-.macro KVMTEST name
+.macro KVMTEST name handler
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
        lbz     r10,HSTATE_IN_GUEST(r13)
        cmpwi   r10,0
-       bne     \name\()_kvm
-.endm
-
-.macro GEN_KVM name
-       .balign IFETCH_ALIGN_BYTES
-\name\()_kvm:
-
-       .if IKVM_SKIP
-       cmpwi   r10,KVM_GUEST_MODE_SKIP
-       beq     89f
-       .else
-BEGIN_FTR_SECTION
-       ld      r10,IAREA+EX_CFAR(r13)
-       std     r10,HSTATE_CFAR(r13)
-END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
-       .endif
-
-       ld      r10,IAREA+EX_CTR(r13)
-       mtctr   r10
-BEGIN_FTR_SECTION
-       ld      r10,IAREA+EX_PPR(r13)
-       std     r10,HSTATE_PPR(r13)
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
-       ld      r11,IAREA+EX_R11(r13)
-       ld      r12,IAREA+EX_R12(r13)
-       std     r12,HSTATE_SCRATCH0(r13)
-       sldi    r12,r9,32
-       ld      r9,IAREA+EX_R9(r13)
-       ld      r10,IAREA+EX_R10(r13)
        /* HSRR variants have the 0x2 bit added to their trap number */
        .if IHSRR_IF_HVMODE
        BEGIN_FTR_SECTION
-       ori     r12,r12,(IVEC + 0x2)
-       FTR_SECTION_ELSE
-       ori     r12,r12,(IVEC)
-       ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
-       .elseif IHSRR
-       ori     r12,r12,(IVEC+ 0x2)
-       .else
-       ori     r12,r12,(IVEC)
-       .endif
-       b       kvmppc_interrupt
-
-       .if IKVM_SKIP
-89:    mtocrf  0x80,r9
-       ld      r10,IAREA+EX_CTR(r13)
-       mtctr   r10
-       ld      r9,IAREA+EX_R9(r13)
-       ld      r10,IAREA+EX_R10(r13)
-       ld      r11,IAREA+EX_R11(r13)
-       ld      r12,IAREA+EX_R12(r13)
-       .if IHSRR_IF_HVMODE
-       BEGIN_FTR_SECTION
-       b       kvmppc_skip_Hinterrupt
+       li      r10,(IVEC + 0x2)
        FTR_SECTION_ELSE
-       b       kvmppc_skip_interrupt
+       li      r10,(IVEC)
        ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
        .elseif IHSRR
-       b       kvmppc_skip_Hinterrupt
+       li      r10,(IVEC + 0x2)
        .else
-       b       kvmppc_skip_interrupt
+       li      r10,(IVEC)
        .endif
-       .endif
-.endm
-
-#else
-.macro KVMTEST name
-.endm
-.macro GEN_KVM name
-.endm
+       bne     \handler
 #endif
+.endm
 
 /*
  * This is the BOOK3S interrupt entry code macro.
@@ -461,7 +379,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
 DEFINE_FIXED_SYMBOL(\name\()_common_real)
 \name\()_common_real:
        .if IKVM_REAL
-               KVMTEST \name
+               KVMTEST \name kvm_interrupt
        .endif
 
        ld      r10,PACAKMSR(r13)       /* get MSR value for kernel */
@@ -484,7 +402,7 @@ DEFINE_FIXED_SYMBOL(\name\()_common_real)
 DEFINE_FIXED_SYMBOL(\name\()_common_virt)
 \name\()_common_virt:
        .if IKVM_VIRT
-               KVMTEST \name
+               KVMTEST \name kvm_interrupt
 1:
        .endif
        .endif /* IVIRT */
@@ -498,7 +416,7 @@ DEFINE_FIXED_SYMBOL(\name\()_common_virt)
 DEFINE_FIXED_SYMBOL(\name\()_common_real)
 \name\()_common_real:
        .if IKVM_REAL
-               KVMTEST \name
+               KVMTEST \name kvm_interrupt
        .endif
 .endm
 
@@ -1000,8 +918,6 @@ EXC_COMMON_BEGIN(system_reset_common)
        EXCEPTION_RESTORE_REGS
        RFI_TO_USER_OR_KERNEL
 
-       GEN_KVM system_reset
-
 
 /**
  * Interrupt 0x200 - Machine Check Interrupt (MCE).
@@ -1070,7 +986,6 @@ INT_DEFINE_BEGIN(machine_check)
        ISET_RI=0
        IDAR=1
        IDSISR=1
-       IKVM_SKIP=1
        IKVM_REAL=1
 INT_DEFINE_END(machine_check)
 
@@ -1166,7 +1081,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
        /*
         * Check if we are coming from guest. If yes, then run the normal
         * exception handler which will take the
-        * machine_check_kvm->kvmppc_interrupt branch to deliver the MC event
+        * machine_check_kvm->kvm_interrupt branch to deliver the MC event
         * to guest.
         */
        lbz     r11,HSTATE_IN_GUEST(r13)
@@ -1236,8 +1151,6 @@ EXC_COMMON_BEGIN(machine_check_common)
        bl      machine_check_exception
        b       interrupt_return
 
-       GEN_KVM machine_check
-
 
 #ifdef CONFIG_PPC_P7_NAP
 /*
@@ -1342,7 +1255,6 @@ INT_DEFINE_BEGIN(data_access)
        IVEC=0x300
        IDAR=1
        IDSISR=1
-       IKVM_SKIP=1
        IKVM_REAL=1
 INT_DEFINE_END(data_access)
 
@@ -1373,8 +1285,6 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
        REST_NVGPRS(r1)
        b       interrupt_return
 
-       GEN_KVM data_access
-
 
 /**
  * Interrupt 0x380 - Data Segment Interrupt (DSLB).
@@ -1396,7 +1306,6 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 INT_DEFINE_BEGIN(data_access_slb)
        IVEC=0x380
        IDAR=1
-       IKVM_SKIP=1
        IKVM_REAL=1
 INT_DEFINE_END(data_access_slb)
 
@@ -1425,8 +1334,6 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
        bl      do_bad_slb_fault
        b       interrupt_return
 
-       GEN_KVM data_access_slb
-
 
 /**
  * Interrupt 0x400 - Instruction Storage Interrupt (ISI).
@@ -1463,8 +1370,6 @@ MMU_FTR_SECTION_ELSE
 ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
        b       interrupt_return
 
-       GEN_KVM instruction_access
-
 
 /**
  * Interrupt 0x480 - Instruction Segment Interrupt (ISLB).
@@ -1509,8 +1414,6 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
        bl      do_bad_slb_fault
        b       interrupt_return
 
-       GEN_KVM instruction_access_slb
-
 
 /**
  * Interrupt 0x500 - External Interrupt.
@@ -1555,8 +1458,6 @@ EXC_COMMON_BEGIN(hardware_interrupt_common)
        bl      do_IRQ
        b       interrupt_return
 
-       GEN_KVM hardware_interrupt
-
 
 /**
  * Interrupt 0x600 - Alignment Interrupt
@@ -1584,8 +1485,6 @@ EXC_COMMON_BEGIN(alignment_common)
        REST_NVGPRS(r1) /* instruction emulation may change GPRs */
        b       interrupt_return
 
-       GEN_KVM alignment
-
 
 /**
  * Interrupt 0x700 - Program Interrupt (program check).
@@ -1693,8 +1592,6 @@ EXC_COMMON_BEGIN(program_check_common)
        REST_NVGPRS(r1) /* instruction emulation may change GPRs */
        b       interrupt_return
 
-       GEN_KVM program_check
-
 
 /*
  * Interrupt 0x800 - Floating-Point Unavailable Interrupt.
@@ -1744,8 +1641,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
        b       interrupt_return
 #endif
 
-       GEN_KVM fp_unavailable
-
 
 /**
  * Interrupt 0x900 - Decrementer Interrupt.
@@ -1784,8 +1679,6 @@ EXC_COMMON_BEGIN(decrementer_common)
        bl      timer_interrupt
        b       interrupt_return
 
-       GEN_KVM decrementer
-
 
 /**
  * Interrupt 0x980 - Hypervisor Decrementer Interrupt.
@@ -1831,8 +1724,6 @@ EXC_COMMON_BEGIN(hdecrementer_common)
        ld      r13,PACA_EXGEN+EX_R13(r13)
        HRFI_TO_KERNEL
 
-       GEN_KVM hdecrementer
-
 
 /**
  * Interrupt 0xa00 - Directed Privileged Doorbell Interrupt.
@@ -1872,8 +1763,6 @@ EXC_COMMON_BEGIN(doorbell_super_common)
 #endif
        b       interrupt_return
 
-       GEN_KVM doorbell_super
-
 
 EXC_REAL_NONE(0xb00, 0x100)
 EXC_VIRT_NONE(0x4b00, 0x100)
@@ -1923,7 +1812,7 @@ INT_DEFINE_END(system_call)
        GET_PACA(r13)
        std     r10,PACA_EXGEN+EX_R10(r13)
        INTERRUPT_TO_KERNEL
-       KVMTEST system_call /* uses r10, branch to system_call_kvm */
+       KVMTEST system_call kvm_hcall /* uses r10, branch to kvm_hcall */
        mfctr   r9
 #else
        mr      r9,r13
@@ -1979,14 +1868,16 @@ EXC_VIRT_BEGIN(system_call, 0x4c00, 0x100)
 EXC_VIRT_END(system_call, 0x4c00, 0x100)
 
 #ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-TRAMP_REAL_BEGIN(system_call_kvm)
-       /*
-        * This is a hcall, so register convention is as above, with these
-        * differences:
-        * r13 = PACA
-        * ctr = orig r13
-        * orig r10 saved in PACA
-        */
+TRAMP_REAL_BEGIN(kvm_hcall)
+       std     r9,PACA_EXGEN+EX_R9(r13)
+       std     r11,PACA_EXGEN+EX_R11(r13)
+       std     r12,PACA_EXGEN+EX_R12(r13)
+       mfcr    r9
+       mfctr   r10
+       std     r10,PACA_EXGEN+EX_R13(r13)
+       li      r10,0
+       std     r10,PACA_EXGEN+EX_CFAR(r13)
+       std     r10,PACA_EXGEN+EX_CTR(r13)
         /*
          * Save the PPR (on systems that support it) before changing to
          * HMT_MEDIUM. That allows the KVM code to save that value into the
@@ -1994,31 +1885,24 @@ TRAMP_REAL_BEGIN(system_call_kvm)
          */
 BEGIN_FTR_SECTION
        mfspr   r10,SPRN_PPR
-       std     r10,HSTATE_PPR(r13)
+       std     r10,PACA_EXGEN+EX_PPR(r13)
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+
        HMT_MEDIUM
-       mfctr   r10
-       SET_SCRATCH0(r10)
-       mfcr    r10
-       std     r12,HSTATE_SCRATCH0(r13)
-       sldi    r12,r10,32
-       ori     r12,r12,0xc00
+
 #ifdef CONFIG_RELOCATABLE
        /*
-        * Requires __LOAD_FAR_HANDLER beause kvmppc_interrupt lives
+        * Requires __LOAD_FAR_HANDLER beause kvmppc_hcall lives
         * outside the head section.
         */
-       __LOAD_FAR_HANDLER(r10, kvmppc_interrupt)
+       __LOAD_FAR_HANDLER(r10, kvmppc_hcall)
        mtctr   r10
-       ld      r10,PACA_EXGEN+EX_R10(r13)
        bctr
 #else
-       ld      r10,PACA_EXGEN+EX_R10(r13)
-       b       kvmppc_interrupt
+       b       kvmppc_hcall
 #endif
 #endif
 
-
 /**
  * Interrupt 0xd00 - Trace Interrupt.
  * This is a synchronous interrupt in response to instruction step or
@@ -2043,8 +1927,6 @@ EXC_COMMON_BEGIN(single_step_common)
        bl      single_step_exception
        b       interrupt_return
 
-       GEN_KVM single_step
-
 
 /**
  * Interrupt 0xe00 - Hypervisor Data Storage Interrupt (HDSI).
@@ -2063,7 +1945,6 @@ INT_DEFINE_BEGIN(h_data_storage)
        IHSRR=1
        IDAR=1
        IDSISR=1
-       IKVM_SKIP=1
        IKVM_REAL=1
        IKVM_VIRT=1
 INT_DEFINE_END(h_data_storage)
@@ -2084,8 +1965,6 @@ MMU_FTR_SECTION_ELSE
 ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_TYPE_RADIX)
        b       interrupt_return
 
-       GEN_KVM h_data_storage
-
 
 /**
  * Interrupt 0xe20 - Hypervisor Instruction Storage Interrupt (HISI).
@@ -2111,8 +1990,6 @@ EXC_COMMON_BEGIN(h_instr_storage_common)
        bl      unknown_exception
        b       interrupt_return
 
-       GEN_KVM h_instr_storage
-
 
 /**
  * Interrupt 0xe40 - Hypervisor Emulation Assistance Interrupt.
@@ -2137,8 +2014,6 @@ EXC_COMMON_BEGIN(emulation_assist_common)
        REST_NVGPRS(r1) /* instruction emulation may change GPRs */
        b       interrupt_return
 
-       GEN_KVM emulation_assist
-
 
 /**
  * Interrupt 0xe60 - Hypervisor Maintenance Interrupt (HMI).
@@ -2210,16 +2085,12 @@ EXC_COMMON_BEGIN(hmi_exception_early_common)
        EXCEPTION_RESTORE_REGS hsrr=1
        GEN_INT_ENTRY hmi_exception, virt=0
 
-       GEN_KVM hmi_exception_early
-
 EXC_COMMON_BEGIN(hmi_exception_common)
        GEN_COMMON hmi_exception
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      handle_hmi_exception
        b       interrupt_return
 
-       GEN_KVM hmi_exception
-
 
 /**
  * Interrupt 0xe80 - Directed Hypervisor Doorbell Interrupt.
@@ -2250,8 +2121,6 @@ EXC_COMMON_BEGIN(h_doorbell_common)
 #endif
        b       interrupt_return
 
-       GEN_KVM h_doorbell
-
 
 /**
  * Interrupt 0xea0 - Hypervisor Virtualization Interrupt.
@@ -2278,8 +2147,6 @@ EXC_COMMON_BEGIN(h_virt_irq_common)
        bl      do_IRQ
        b       interrupt_return
 
-       GEN_KVM h_virt_irq
-
 
 EXC_REAL_NONE(0xec0, 0x20)
 EXC_VIRT_NONE(0x4ec0, 0x20)
@@ -2323,8 +2190,6 @@ EXC_COMMON_BEGIN(performance_monitor_common)
        bl      performance_monitor_exception
        b       interrupt_return
 
-       GEN_KVM performance_monitor
-
 
 /**
  * Interrupt 0xf20 - Vector Unavailable Interrupt.
@@ -2374,8 +2239,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        bl      altivec_unavailable_exception
        b       interrupt_return
 
-       GEN_KVM altivec_unavailable
-
 
 /**
  * Interrupt 0xf40 - VSX Unavailable Interrupt.
@@ -2424,8 +2287,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        bl      vsx_unavailable_exception
        b       interrupt_return
 
-       GEN_KVM vsx_unavailable
-
 
 /**
  * Interrupt 0xf60 - Facility Unavailable Interrupt.
@@ -2454,8 +2315,6 @@ EXC_COMMON_BEGIN(facility_unavailable_common)
        REST_NVGPRS(r1) /* instruction emulation may change GPRs */
        b       interrupt_return
 
-       GEN_KVM facility_unavailable
-
 
 /**
  * Interrupt 0xf60 - Hypervisor Facility Unavailable Interrupt.
@@ -2484,8 +2343,6 @@ EXC_COMMON_BEGIN(h_facility_unavailable_common)
        REST_NVGPRS(r1) /* XXX Shouldn't be necessary in practice */
        b       interrupt_return
 
-       GEN_KVM h_facility_unavailable
-
 
 EXC_REAL_NONE(0xfa0, 0x20)
 EXC_VIRT_NONE(0x4fa0, 0x20)
@@ -2515,8 +2372,6 @@ EXC_COMMON_BEGIN(cbe_system_error_common)
        bl      cbe_system_error_exception
        b       interrupt_return
 
-       GEN_KVM cbe_system_error
-
 #else /* CONFIG_CBE_RAS */
 EXC_REAL_NONE(0x1200, 0x100)
 EXC_VIRT_NONE(0x5200, 0x100)
@@ -2548,8 +2403,6 @@ EXC_COMMON_BEGIN(instruction_breakpoint_common)
        bl      instruction_breakpoint_exception
        b       interrupt_return
 
-       GEN_KVM instruction_breakpoint
-
 
 EXC_REAL_NONE(0x1400, 0x100)
 EXC_VIRT_NONE(0x5400, 0x100)
@@ -2670,8 +2523,6 @@ EXC_COMMON_BEGIN(denorm_exception_common)
        bl      unknown_exception
        b       interrupt_return
 
-       GEN_KVM denorm_exception
-
 
 #ifdef CONFIG_CBE_RAS
 INT_DEFINE_BEGIN(cbe_maintenance)
@@ -2689,8 +2540,6 @@ EXC_COMMON_BEGIN(cbe_maintenance_common)
        bl      cbe_maintenance_exception
        b       interrupt_return
 
-       GEN_KVM cbe_maintenance
-
 #else /* CONFIG_CBE_RAS */
 EXC_REAL_NONE(0x1600, 0x100)
 EXC_VIRT_NONE(0x5600, 0x100)
@@ -2721,8 +2570,6 @@ EXC_COMMON_BEGIN(altivec_assist_common)
 #endif
        b       interrupt_return
 
-       GEN_KVM altivec_assist
-
 
 #ifdef CONFIG_CBE_RAS
 INT_DEFINE_BEGIN(cbe_thermal)
@@ -2740,8 +2587,6 @@ EXC_COMMON_BEGIN(cbe_thermal_common)
        bl      cbe_thermal_exception
        b       interrupt_return
 
-       GEN_KVM cbe_thermal
-
 #else /* CONFIG_CBE_RAS */
 EXC_REAL_NONE(0x1800, 0x100)
 EXC_VIRT_NONE(0x5800, 0x100)
@@ -2994,6 +2839,15 @@ TRAMP_REAL_BEGIN(rfscv_flush_fallback)
 
 USE_TEXT_SECTION()
 
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+kvm_interrupt:
+       /*
+        * The conditional branch in KVMTEST can't reach all the way,
+        * make a stub.
+        */
+       b       kvmppc_interrupt
+#endif
+
 _GLOBAL(do_uaccess_flush)
        UACCESS_FLUSH_FIXUP_SECTION
        nop
@@ -3009,32 +2863,6 @@ EXPORT_SYMBOL(do_uaccess_flush)
 MASKED_INTERRUPT
 MASKED_INTERRUPT hsrr=1
 
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-kvmppc_skip_interrupt:
-       /*
-        * Here all GPRs are unchanged from when the interrupt happened
-        * except for r13, which is saved in SPRG_SCRATCH0.
-        */
-       mfspr   r13, SPRN_SRR0
-       addi    r13, r13, 4
-       mtspr   SPRN_SRR0, r13
-       GET_SCRATCH0(r13)
-       RFI_TO_KERNEL
-       b       .
-
-kvmppc_skip_Hinterrupt:
-       /*
-        * Here all GPRs are unchanged from when the interrupt happened
-        * except for r13, which is saved in SPRG_SCRATCH0.
-        */
-       mfspr   r13, SPRN_HSRR0
-       addi    r13, r13, 4
-       mtspr   SPRN_HSRR0, r13
-       GET_SCRATCH0(r13)
-       HRFI_TO_KERNEL
-       b       .
-#endif
-
        /*
         * Relocation-on interrupts: A subset of the interrupts can be delivered
         * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
index e8c2a63..c64a5fe 100644 (file)
@@ -502,23 +502,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 9a3c2a8..15e7b49 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/extable.h>
 #include <linux/ftrace.h>
 #include <linux/memblock.h>
+#include <linux/of.h>
 
 #include <asm/interrupt.h>
 #include <asm/machdep.h>
index 89e34aa..8935c56 100644 (file)
@@ -2084,7 +2084,7 @@ static unsigned long __get_wchan(struct task_struct *p)
        unsigned long ip, sp;
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        sp = p->thread.ksp;
@@ -2094,7 +2094,7 @@ static unsigned long __get_wchan(struct task_struct *p)
        do {
                sp = *(unsigned long *)sp;
                if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD) ||
-                   p->state == TASK_RUNNING)
+                   task_is_running(p))
                        return 0;
                if (count > 0) {
                        ip = ((unsigned long *)sp)[STACK_FRAME_LR_SAVE];
index 0fdfcdd..c17d1c9 100644 (file)
@@ -432,16 +432,19 @@ device_initcall(stf_barrier_debugfs_init);
 
 static void update_branch_cache_flush(void)
 {
-       u32 *site;
+       u32 *site, __maybe_unused *site2;
 
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        site = &patch__call_kvm_flush_link_stack;
+       site2 = &patch__call_kvm_flush_link_stack_p9;
        // This controls the branch from guest_exit_cont to kvm_flush_link_stack
        if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {
                patch_instruction_site(site, ppc_inst(PPC_INST_NOP));
+               patch_instruction_site(site2, ppc_inst(PPC_INST_NOP));
        } else {
                // Could use HW flush, but that could also flush count cache
                patch_branch_site(site, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
+               patch_branch_site(site2, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);
        }
 #endif
 
index dca6648..f9e1f54 100644 (file)
@@ -902,6 +902,10 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
        unsafe_copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set), badframe_block);
        user_write_access_end();
 
+       /* Save the siginfo outside of the unsafe block. */
+       if (copy_siginfo_to_user(&frame->info, &ksig->info))
+               goto badframe;
+
        /* Make sure signal handler doesn't get spurious FP exceptions */
        tsk->thread.fp_state.fpscr = 0;
 
@@ -915,11 +919,6 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
                regs->nip = (unsigned long) &frame->tramp[0];
        }
 
-
-       /* Save the siginfo outside of the unsafe block. */
-       if (copy_siginfo_to_user(&frame->info, &ksig->info))
-               goto badframe;
-
        /* Allocate a dummy caller frame for the signal handler. */
        newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
        err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
index 2e05c78..6c6e4d9 100644 (file)
@@ -1547,7 +1547,6 @@ void start_secondary(void *unused)
        smp_store_cpu_info(cpu);
        set_dec(tb_ticks_per_jiffy);
        rcu_cpu_starting(cpu);
-       preempt_disable();
        cpu_callin_map[cpu] = 1;
 
        if (smp_ops->setup_cpu)
index b67d93a..da995c5 100644 (file)
@@ -508,16 +508,6 @@ EXPORT_SYMBOL(profile_pc);
  * 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
  */
 #ifdef CONFIG_PPC64
-static inline unsigned long test_irq_work_pending(void)
-{
-       unsigned long x;
-
-       asm volatile("lbz %0,%1(13)"
-               : "=r" (x)
-               : "i" (offsetof(struct paca_struct, irq_work_pending)));
-       return x;
-}
-
 static inline void set_irq_work_pending_flag(void)
 {
        asm volatile("stb %0,%1(13)" : :
index 2bfeaa1..583c14e 100644 (file)
@@ -6,7 +6,7 @@
 ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
 KVM := ../../../virt/kvm
 
-common-objs-y = $(KVM)/kvm_main.o $(KVM)/eventfd.o
+common-objs-y = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o
 common-objs-$(CONFIG_KVM_VFIO) += $(KVM)/vfio.o
 common-objs-$(CONFIG_KVM_MMIO) += $(KVM)/coalesced_mmio.o
 
@@ -57,6 +57,7 @@ kvm-pr-y := \
        book3s_32_mmu.o
 
 kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
+       book3s_64_entry.o \
        tm.o
 
 ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
@@ -86,6 +87,7 @@ kvm-book3s_64-builtin-tm-objs-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
 ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
        book3s_hv_hmi.o \
+       book3s_hv_p9_entry.o \
        book3s_hv_rmhandlers.o \
        book3s_hv_rm_mmu.o \
        book3s_hv_ras.o \
index 2b691f4..79833f7 100644 (file)
 
 /* #define EXIT_DEBUG */
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("exits", sum_exits),
-       VCPU_STAT("mmio", mmio_exits),
-       VCPU_STAT("sig", signal_exits),
-       VCPU_STAT("sysc", syscall_exits),
-       VCPU_STAT("inst_emu", emulated_inst_exits),
-       VCPU_STAT("dec", dec_exits),
-       VCPU_STAT("ext_intr", ext_intr_exits),
-       VCPU_STAT("queue_intr", queue_intr),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       VCPU_STAT("halt_wait_ns", halt_wait_ns),
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_successful_wait", halt_successful_wait),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("pf_storage", pf_storage),
-       VCPU_STAT("sp_storage", sp_storage),
-       VCPU_STAT("pf_instruc", pf_instruc),
-       VCPU_STAT("sp_instruc", sp_instruc),
-       VCPU_STAT("ld", ld),
-       VCPU_STAT("ld_slow", ld_slow),
-       VCPU_STAT("st", st),
-       VCPU_STAT("st_slow", st_slow),
-       VCPU_STAT("pthru_all", pthru_all),
-       VCPU_STAT("pthru_host", pthru_host),
-       VCPU_STAT("pthru_bad_aff", pthru_bad_aff),
-       VM_STAT("largepages_2M", num_2M_pages, .mode = 0444),
-       VM_STAT("largepages_1G", num_1G_pages, .mode = 0444),
-       { NULL }
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS(),
+       STATS_DESC_ICOUNTER(VM, num_2M_pages),
+       STATS_DESC_ICOUNTER(VM, num_1G_pages)
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, sum_exits),
+       STATS_DESC_COUNTER(VCPU, mmio_exits),
+       STATS_DESC_COUNTER(VCPU, signal_exits),
+       STATS_DESC_COUNTER(VCPU, light_exits),
+       STATS_DESC_COUNTER(VCPU, itlb_real_miss_exits),
+       STATS_DESC_COUNTER(VCPU, itlb_virt_miss_exits),
+       STATS_DESC_COUNTER(VCPU, dtlb_real_miss_exits),
+       STATS_DESC_COUNTER(VCPU, dtlb_virt_miss_exits),
+       STATS_DESC_COUNTER(VCPU, syscall_exits),
+       STATS_DESC_COUNTER(VCPU, isi_exits),
+       STATS_DESC_COUNTER(VCPU, dsi_exits),
+       STATS_DESC_COUNTER(VCPU, emulated_inst_exits),
+       STATS_DESC_COUNTER(VCPU, dec_exits),
+       STATS_DESC_COUNTER(VCPU, ext_intr_exits),
+       STATS_DESC_TIME_NSEC(VCPU, halt_wait_ns),
+       STATS_DESC_COUNTER(VCPU, halt_successful_wait),
+       STATS_DESC_COUNTER(VCPU, dbell_exits),
+       STATS_DESC_COUNTER(VCPU, gdbell_exits),
+       STATS_DESC_COUNTER(VCPU, ld),
+       STATS_DESC_COUNTER(VCPU, st),
+       STATS_DESC_COUNTER(VCPU, pf_storage),
+       STATS_DESC_COUNTER(VCPU, pf_instruc),
+       STATS_DESC_COUNTER(VCPU, sp_storage),
+       STATS_DESC_COUNTER(VCPU, sp_instruc),
+       STATS_DESC_COUNTER(VCPU, queue_intr),
+       STATS_DESC_COUNTER(VCPU, ld_slow),
+       STATS_DESC_COUNTER(VCPU, st_slow),
+       STATS_DESC_COUNTER(VCPU, pthru_all),
+       STATS_DESC_COUNTER(VCPU, pthru_host),
+       STATS_DESC_COUNTER(VCPU, pthru_bad_aff)
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
@@ -171,6 +200,12 @@ void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong flags)
 }
 EXPORT_SYMBOL_GPL(kvmppc_core_queue_machine_check);
 
+void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu)
+{
+       kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_SYSCALL, 0);
+}
+EXPORT_SYMBOL(kvmppc_core_queue_syscall);
+
 void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags)
 {
        /* might as well deliver this straight away */
@@ -1044,13 +1079,10 @@ static int kvmppc_book3s_init(void)
 #ifdef CONFIG_KVM_XICS
 #ifdef CONFIG_KVM_XIVE
        if (xics_on_xive()) {
-               kvmppc_xive_init_module();
                kvm_register_device_ops(&kvm_xive_ops, KVM_DEV_TYPE_XICS);
-               if (kvmppc_xive_native_supported()) {
-                       kvmppc_xive_native_init_module();
+               if (kvmppc_xive_native_supported())
                        kvm_register_device_ops(&kvm_xive_native_ops,
                                                KVM_DEV_TYPE_XIVE);
-               }
        } else
 #endif
                kvm_register_device_ops(&kvm_xics_ops, KVM_DEV_TYPE_XICS);
@@ -1060,12 +1092,6 @@ static int kvmppc_book3s_init(void)
 
 static void kvmppc_book3s_exit(void)
 {
-#ifdef CONFIG_KVM_XICS
-       if (xics_on_xive()) {
-               kvmppc_xive_exit_module();
-               kvmppc_xive_native_exit_module();
-       }
-#endif
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
        kvmppc_book3s_exit_pr();
 #endif
diff --git a/arch/powerpc/kvm/book3s_64_entry.S b/arch/powerpc/kvm/book3s_64_entry.S
new file mode 100644 (file)
index 0000000..983b8c1
--- /dev/null
@@ -0,0 +1,416 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm/asm-offsets.h>
+#include <asm/cache.h>
+#include <asm/code-patching-asm.h>
+#include <asm/exception-64s.h>
+#include <asm/export.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_book3s_asm.h>
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/ptrace.h>
+#include <asm/reg.h>
+#include <asm/ultravisor-api.h>
+
+/*
+ * These are branched to from interrupt handlers in exception-64s.S which set
+ * IKVM_REAL or IKVM_VIRT, if HSTATE_IN_GUEST was found to be non-zero.
+ */
+
+/*
+ * This is a hcall, so register convention is as
+ * Documentation/powerpc/papr_hcalls.rst.
+ *
+ * This may also be a syscall from PR-KVM userspace that is to be
+ * reflected to the PR guest kernel, so registers may be set up for
+ * a system call rather than hcall. We don't currently clobber
+ * anything here, but the 0xc00 handler has already clobbered CTR
+ * and CR0, so PR-KVM can not support a guest kernel that preserves
+ * those registers across its system calls.
+ *
+ * The state of registers is as kvmppc_interrupt, except CFAR is not
+ * saved, R13 is not in SCRATCH0, and R10 does not contain the trap.
+ */
+.global        kvmppc_hcall
+.balign IFETCH_ALIGN_BYTES
+kvmppc_hcall:
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       lbz     r10,HSTATE_IN_GUEST(r13)
+       cmpwi   r10,KVM_GUEST_MODE_HV_P9
+       beq     kvmppc_p9_exit_hcall
+#endif
+       ld      r10,PACA_EXGEN+EX_R13(r13)
+       SET_SCRATCH0(r10)
+       li      r10,0xc00
+       /* Now we look like kvmppc_interrupt */
+       li      r11,PACA_EXGEN
+       b       .Lgot_save_area
+
+/*
+ * KVM interrupt entry occurs after GEN_INT_ENTRY runs, and follows that
+ * call convention:
+ *
+ * guest R9-R13, CTR, CFAR, PPR saved in PACA EX_xxx save area
+ * guest (H)DAR, (H)DSISR are also in the save area for relevant interrupts
+ * guest R13 also saved in SCRATCH0
+ * R13         = PACA
+ * R11         = (H)SRR0
+ * R12         = (H)SRR1
+ * R9          = guest CR
+ * PPR is set to medium
+ *
+ * With the addition for KVM:
+ * R10         = trap vector
+ */
+.global        kvmppc_interrupt
+.balign IFETCH_ALIGN_BYTES
+kvmppc_interrupt:
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       std     r10,HSTATE_SCRATCH0(r13)
+       lbz     r10,HSTATE_IN_GUEST(r13)
+       cmpwi   r10,KVM_GUEST_MODE_HV_P9
+       beq     kvmppc_p9_exit_interrupt
+       ld      r10,HSTATE_SCRATCH0(r13)
+#endif
+       li      r11,PACA_EXGEN
+       cmpdi   r10,0x200
+       bgt+    .Lgot_save_area
+       li      r11,PACA_EXMC
+       beq     .Lgot_save_area
+       li      r11,PACA_EXNMI
+.Lgot_save_area:
+       add     r11,r11,r13
+BEGIN_FTR_SECTION
+       ld      r12,EX_CFAR(r11)
+       std     r12,HSTATE_CFAR(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+       ld      r12,EX_CTR(r11)
+       mtctr   r12
+BEGIN_FTR_SECTION
+       ld      r12,EX_PPR(r11)
+       std     r12,HSTATE_PPR(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+       ld      r12,EX_R12(r11)
+       std     r12,HSTATE_SCRATCH0(r13)
+       sldi    r12,r9,32
+       or      r12,r12,r10
+       ld      r9,EX_R9(r11)
+       ld      r10,EX_R10(r11)
+       ld      r11,EX_R11(r11)
+
+       /*
+        * Hcalls and other interrupts come here after normalising register
+        * contents and save locations:
+        *
+        * R12          = (guest CR << 32) | interrupt vector
+        * R13          = PACA
+        * guest R12 saved in shadow HSTATE_SCRATCH0
+        * guest R13 saved in SPRN_SCRATCH0
+        */
+       std     r9,HSTATE_SCRATCH2(r13)
+       lbz     r9,HSTATE_IN_GUEST(r13)
+       cmpwi   r9,KVM_GUEST_MODE_SKIP
+       beq-    .Lmaybe_skip
+.Lno_skip:
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
+       cmpwi   r9,KVM_GUEST_MODE_GUEST
+       beq     kvmppc_interrupt_pr
+#endif
+       b       kvmppc_interrupt_hv
+#else
+       b       kvmppc_interrupt_pr
+#endif
+
+/*
+ * "Skip" interrupts are part of a trick KVM uses a with hash guests to load
+ * the faulting instruction in guest memory from the the hypervisor without
+ * walking page tables.
+ *
+ * When the guest takes a fault that requires the hypervisor to load the
+ * instruction (e.g., MMIO emulation), KVM is running in real-mode with HV=1
+ * and the guest MMU context loaded. It sets KVM_GUEST_MODE_SKIP, and sets
+ * MSR[DR]=1 while leaving MSR[IR]=0, so it continues to fetch HV instructions
+ * but loads and stores will access the guest context. This is used to load
+ * the faulting instruction using the faulting guest effective address.
+ *
+ * However the guest context may not be able to translate, or it may cause a
+ * machine check or other issue, which results in a fault in the host
+ * (even with KVM-HV).
+ *
+ * These faults come here because KVM_GUEST_MODE_SKIP was set, so if they
+ * are (or are likely) caused by that load, the instruction is skipped by
+ * just returning with the PC advanced +4, where it is noticed the load did
+ * not execute and it goes to the slow path which walks the page tables to
+ * read guest memory.
+ */
+.Lmaybe_skip:
+       cmpwi   r12,BOOK3S_INTERRUPT_MACHINE_CHECK
+       beq     1f
+       cmpwi   r12,BOOK3S_INTERRUPT_DATA_STORAGE
+       beq     1f
+       cmpwi   r12,BOOK3S_INTERRUPT_DATA_SEGMENT
+       beq     1f
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       /* HSRR interrupts get 2 added to interrupt number */
+       cmpwi   r12,BOOK3S_INTERRUPT_H_DATA_STORAGE | 0x2
+       beq     2f
+#endif
+       b       .Lno_skip
+1:     mfspr   r9,SPRN_SRR0
+       addi    r9,r9,4
+       mtspr   SPRN_SRR0,r9
+       ld      r12,HSTATE_SCRATCH0(r13)
+       ld      r9,HSTATE_SCRATCH2(r13)
+       GET_SCRATCH0(r13)
+       RFI_TO_KERNEL
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+2:     mfspr   r9,SPRN_HSRR0
+       addi    r9,r9,4
+       mtspr   SPRN_HSRR0,r9
+       ld      r12,HSTATE_SCRATCH0(r13)
+       ld      r9,HSTATE_SCRATCH2(r13)
+       GET_SCRATCH0(r13)
+       HRFI_TO_KERNEL
+#endif
+
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+
+/* Stack frame offsets for kvmppc_p9_enter_guest */
+#define SFS                    (144 + STACK_FRAME_MIN_SIZE)
+#define STACK_SLOT_NVGPRS      (SFS - 144)     /* 18 gprs */
+
+/*
+ * void kvmppc_p9_enter_guest(struct vcpu *vcpu);
+ *
+ * Enter the guest on a ISAv3.0 or later system.
+ */
+.balign        IFETCH_ALIGN_BYTES
+_GLOBAL(kvmppc_p9_enter_guest)
+EXPORT_SYMBOL_GPL(kvmppc_p9_enter_guest)
+       mflr    r0
+       std     r0,PPC_LR_STKOFF(r1)
+       stdu    r1,-SFS(r1)
+
+       std     r1,HSTATE_HOST_R1(r13)
+
+       mfcr    r4
+       stw     r4,SFS+8(r1)
+
+       reg = 14
+       .rept   18
+       std     reg,STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
+       reg = reg + 1
+       .endr
+
+       ld      r4,VCPU_LR(r3)
+       mtlr    r4
+       ld      r4,VCPU_CTR(r3)
+       mtctr   r4
+       ld      r4,VCPU_XER(r3)
+       mtspr   SPRN_XER,r4
+
+       ld      r1,VCPU_CR(r3)
+
+BEGIN_FTR_SECTION
+       ld      r4,VCPU_CFAR(r3)
+       mtspr   SPRN_CFAR,r4
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+BEGIN_FTR_SECTION
+       ld      r4,VCPU_PPR(r3)
+       mtspr   SPRN_PPR,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+
+       reg = 4
+       .rept   28
+       ld      reg,__VCPU_GPR(reg)(r3)
+       reg = reg + 1
+       .endr
+
+       ld      r4,VCPU_KVM(r3)
+       lbz     r4,KVM_SECURE_GUEST(r4)
+       cmpdi   r4,0
+       ld      r4,VCPU_GPR(R4)(r3)
+       bne     .Lret_to_ultra
+
+       mtcr    r1
+
+       ld      r0,VCPU_GPR(R0)(r3)
+       ld      r1,VCPU_GPR(R1)(r3)
+       ld      r2,VCPU_GPR(R2)(r3)
+       ld      r3,VCPU_GPR(R3)(r3)
+
+       HRFI_TO_GUEST
+       b       .
+
+       /*
+        * Use UV_RETURN ultracall to return control back to the Ultravisor
+        * after processing an hypercall or interrupt that was forwarded
+        * (a.k.a. reflected) to the Hypervisor.
+        *
+        * All registers have already been reloaded except the ucall requires:
+        *   R0 = hcall result
+        *   R2 = SRR1, so UV can detect a synthesized interrupt (if any)
+        *   R3 = UV_RETURN
+        */
+.Lret_to_ultra:
+       mtcr    r1
+       ld      r1,VCPU_GPR(R1)(r3)
+
+       ld      r0,VCPU_GPR(R3)(r3)
+       mfspr   r2,SPRN_SRR1
+       LOAD_REG_IMMEDIATE(r3, UV_RETURN)
+       sc      2
+
+/*
+ * kvmppc_p9_exit_hcall and kvmppc_p9_exit_interrupt are branched to from
+ * above if the interrupt was taken for a guest that was entered via
+ * kvmppc_p9_enter_guest().
+ *
+ * The exit code recovers the host stack and vcpu pointer, saves all guest GPRs
+ * and CR, LR, XER as well as guest MSR and NIA into the VCPU, then re-
+ * establishes the host stack and registers to return from the
+ * kvmppc_p9_enter_guest() function, which saves CTR and other guest registers
+ * (SPRs and FP, VEC, etc).
+ */
+.balign        IFETCH_ALIGN_BYTES
+kvmppc_p9_exit_hcall:
+       mfspr   r11,SPRN_SRR0
+       mfspr   r12,SPRN_SRR1
+       li      r10,0xc00
+       std     r10,HSTATE_SCRATCH0(r13)
+
+.balign        IFETCH_ALIGN_BYTES
+kvmppc_p9_exit_interrupt:
+       /*
+        * If set to KVM_GUEST_MODE_HV_P9 but we're still in the
+        * hypervisor, that means we can't return from the entry stack.
+        */
+       rldicl. r10,r12,64-MSR_HV_LG,63
+       bne-    kvmppc_p9_bad_interrupt
+
+       std     r1,HSTATE_SCRATCH1(r13)
+       std     r3,HSTATE_SCRATCH2(r13)
+       ld      r1,HSTATE_HOST_R1(r13)
+       ld      r3,HSTATE_KVM_VCPU(r13)
+
+       std     r9,VCPU_CR(r3)
+
+1:
+       std     r11,VCPU_PC(r3)
+       std     r12,VCPU_MSR(r3)
+
+       reg = 14
+       .rept   18
+       std     reg,__VCPU_GPR(reg)(r3)
+       reg = reg + 1
+       .endr
+
+       /* r1, r3, r9-r13 are saved to vcpu by C code */
+       std     r0,VCPU_GPR(R0)(r3)
+       std     r2,VCPU_GPR(R2)(r3)
+       reg = 4
+       .rept   5
+       std     reg,__VCPU_GPR(reg)(r3)
+       reg = reg + 1
+       .endr
+
+       ld      r2,PACATOC(r13)
+
+       mflr    r4
+       std     r4,VCPU_LR(r3)
+       mfspr   r4,SPRN_XER
+       std     r4,VCPU_XER(r3)
+
+       reg = 14
+       .rept   18
+       ld      reg,STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
+       reg = reg + 1
+       .endr
+
+       lwz     r4,SFS+8(r1)
+       mtcr    r4
+
+       /*
+        * Flush the link stack here, before executing the first blr on the
+        * way out of the guest.
+        *
+        * The link stack won't match coming out of the guest anyway so the
+        * only cost is the flush itself. The call clobbers r0.
+        */
+1:     nop
+       patch_site 1b patch__call_kvm_flush_link_stack_p9
+
+       addi    r1,r1,SFS
+       ld      r0,PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+
+/*
+ * Took an interrupt somewhere right before HRFID to guest, so registers are
+ * in a bad way. Return things hopefully enough to run host virtual code and
+ * run the Linux interrupt handler (SRESET or MCE) to print something useful.
+ *
+ * We could be really clever and save all host registers in known locations
+ * before setting HSTATE_IN_GUEST, then restoring them all here, and setting
+ * return address to a fixup that sets them up again. But that's a lot of
+ * effort for a small bit of code. Lots of other things to do first.
+ */
+kvmppc_p9_bad_interrupt:
+BEGIN_MMU_FTR_SECTION
+       /*
+        * Hash host doesn't try to recover MMU (requires host SLB reload)
+        */
+       b       .
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
+       /*
+        * Clean up guest registers to give host a chance to run.
+        */
+       li      r10,0
+       mtspr   SPRN_AMR,r10
+       mtspr   SPRN_IAMR,r10
+       mtspr   SPRN_CIABR,r10
+       mtspr   SPRN_DAWRX0,r10
+BEGIN_FTR_SECTION
+       mtspr   SPRN_DAWRX1,r10
+END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
+       mtspr   SPRN_PID,r10
+
+       /*
+        * Switch to host MMU mode
+        */
+       ld      r10, HSTATE_KVM_VCPU(r13)
+       ld      r10, VCPU_KVM(r10)
+       lwz     r10, KVM_HOST_LPID(r10)
+       mtspr   SPRN_LPID,r10
+
+       ld      r10, HSTATE_KVM_VCPU(r13)
+       ld      r10, VCPU_KVM(r10)
+       ld      r10, KVM_HOST_LPCR(r10)
+       mtspr   SPRN_LPCR,r10
+
+       /*
+        * Set GUEST_MODE_NONE so the handler won't branch to KVM, and clear
+        * MSR_RI in r12 ([H]SRR1) so the handler won't try to return.
+        */
+       li      r10,KVM_GUEST_MODE_NONE
+       stb     r10,HSTATE_IN_GUEST(r13)
+       li      r10,MSR_RI
+       andc    r12,r12,r10
+
+       /*
+        * Go back to interrupt handler. MCE and SRESET have their specific
+        * PACA save area so they should be used directly. They set up their
+        * own stack. The other handlers all use EXGEN. They will use the
+        * guest r1 if it looks like a kernel stack, so just load the
+        * emergency stack and go to program check for all other interrupts.
+        */
+       ld      r10,HSTATE_SCRATCH0(r13)
+       cmpwi   r10,BOOK3S_INTERRUPT_MACHINE_CHECK
+       beq     machine_check_common
+
+       cmpwi   r10,BOOK3S_INTERRUPT_SYSTEM_RESET
+       beq     system_reset_common
+
+       b       .
+#endif
index d909c06..b5905ae 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/pte-walk.h>
 #include <asm/ultravisor.h>
 #include <asm/kvm_book3s_uvmem.h>
+#include <asm/plpar_wrappers.h>
 
 /*
  * Supported radix tree geometry.
@@ -318,9 +319,19 @@ void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
        }
 
        psi = shift_to_mmu_psize(pshift);
-       rb = addr | (mmu_get_ap(psi) << PPC_BITLSHIFT(58));
-       rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(0, 0, 1),
-                               lpid, rb);
+
+       if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE)) {
+               rb = addr | (mmu_get_ap(psi) << PPC_BITLSHIFT(58));
+               rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(0, 0, 1),
+                                       lpid, rb);
+       } else {
+               rc = pseries_rpt_invalidate(lpid, H_RPTI_TARGET_CMMU,
+                                           H_RPTI_TYPE_NESTED |
+                                           H_RPTI_TYPE_TLB,
+                                           psize_to_rpti_pgsize(psi),
+                                           addr, addr + psize);
+       }
+
        if (rc)
                pr_err("KVM: TLB page invalidation hcall failed, rc=%ld\n", rc);
 }
@@ -334,8 +345,14 @@ static void kvmppc_radix_flush_pwc(struct kvm *kvm, unsigned int lpid)
                return;
        }
 
-       rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(1, 0, 1),
-                               lpid, TLBIEL_INVAL_SET_LPID);
+       if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE))
+               rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(1, 0, 1),
+                                       lpid, TLBIEL_INVAL_SET_LPID);
+       else
+               rc = pseries_rpt_invalidate(lpid, H_RPTI_TARGET_CMMU,
+                                           H_RPTI_TYPE_NESTED |
+                                           H_RPTI_TYPE_PWC, H_RPTI_PAGE_ALL,
+                                           0, -1UL);
        if (rc)
                pr_err("KVM: TLB PWC invalidation hcall failed, rc=%ld\n", rc);
 }
index 083a4e0..dc65915 100644 (file)
@@ -391,10 +391,6 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
        /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
        /*          liobn, ioba, tce); */
 
-       /* For radix, we might be in virtual mode, so punt */
-       if (kvm_is_radix(vcpu->kvm))
-               return H_TOO_HARD;
-
        stt = kvmppc_find_table(vcpu->kvm, liobn);
        if (!stt)
                return H_TOO_HARD;
@@ -489,10 +485,6 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
        bool prereg = false;
        struct kvmppc_spapr_tce_iommu_table *stit;
 
-       /* For radix, we might be in virtual mode, so punt */
-       if (kvm_is_radix(vcpu->kvm))
-               return H_TOO_HARD;
-
        /*
         * used to check for invalidations in progress
         */
@@ -602,10 +594,6 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
        long i, ret;
        struct kvmppc_spapr_tce_iommu_table *stit;
 
-       /* For radix, we might be in virtual mode, so punt */
-       if (kvm_is_radix(vcpu->kvm))
-               return H_TOO_HARD;
-
        stt = kvmppc_find_table(vcpu->kvm, liobn);
        if (!stt)
                return H_TOO_HARD;
index bc08136..cd544a4 100644 (file)
@@ -76,6 +76,7 @@
 #include <asm/kvm_book3s_uvmem.h>
 #include <asm/ultravisor.h>
 #include <asm/dtl.h>
+#include <asm/plpar_wrappers.h>
 
 #include "book3s.h"
 
@@ -103,13 +104,9 @@ static int target_smt_mode;
 module_param(target_smt_mode, int, 0644);
 MODULE_PARM_DESC(target_smt_mode, "Target threads per core (0 = max)");
 
-static bool indep_threads_mode = true;
-module_param(indep_threads_mode, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(indep_threads_mode, "Independent-threads mode (only on POWER9)");
-
 static bool one_vm_per_core;
 module_param(one_vm_per_core, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires indep_threads_mode=N)");
+MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires POWER8 or older)");
 
 #ifdef CONFIG_KVM_XICS
 static const struct kernel_param_ops module_param_ops = {
@@ -134,9 +131,6 @@ static inline bool nesting_enabled(struct kvm *kvm)
        return kvm->arch.nested_enable && kvm_is_radix(kvm);
 }
 
-/* If set, the threads on each CPU core have to be in the same MMU mode */
-static bool no_mixing_hpt_and_radix __read_mostly;
-
 static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
 
 /*
@@ -236,7 +230,7 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
 
        waitp = kvm_arch_vcpu_get_wait(vcpu);
        if (rcuwait_wake_up(waitp))
-               ++vcpu->stat.halt_wakeup;
+               ++vcpu->stat.generic.halt_wakeup;
 
        cpu = READ_ONCE(vcpu->arch.thread_cpu);
        if (cpu >= 0 && kvmppc_ipi_thread(cpu))
@@ -807,7 +801,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags,
                 * KVM does not support mflags=2 (AIL=2) and AIL=1 is reserved.
                 * Keep this in synch with kvmppc_filter_guest_lpcr_hv.
                 */
-               if (mflags != 0 && mflags != 3)
+               if (cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG) &&
+                               kvmhv_vcpu_is_radix(vcpu) && mflags == 3)
                        return H_UNSUPPORTED_FLAG_START;
                return H_TOO_HARD;
        default:
@@ -899,6 +894,10 @@ static int kvm_arch_vcpu_yield_to(struct kvm_vcpu *target)
         * H_SUCCESS if the source vcore wasn't idle (e.g. if it may
         * have useful work to do and should not confer) so we don't
         * recheck that here.
+        *
+        * In the case of the P9 single vcpu per vcore case, the real
+        * mode handler is not called but no other threads are in the
+        * source vcore.
         */
 
        spin_lock(&vcore->lock);
@@ -924,8 +923,71 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu)
        return yield_count;
 }
 
+/*
+ * H_RPT_INVALIDATE hcall handler for nested guests.
+ *
+ * Handles only nested process-scoped invalidation requests in L0.
+ */
+static int kvmppc_nested_h_rpt_invalidate(struct kvm_vcpu *vcpu)
+{
+       unsigned long type = kvmppc_get_gpr(vcpu, 6);
+       unsigned long pid, pg_sizes, start, end;
+
+       /*
+        * The partition-scoped invalidations aren't handled here in L0.
+        */
+       if (type & H_RPTI_TYPE_NESTED)
+               return RESUME_HOST;
+
+       pid = kvmppc_get_gpr(vcpu, 4);
+       pg_sizes = kvmppc_get_gpr(vcpu, 7);
+       start = kvmppc_get_gpr(vcpu, 8);
+       end = kvmppc_get_gpr(vcpu, 9);
+
+       do_h_rpt_invalidate_prt(pid, vcpu->arch.nested->shadow_lpid,
+                               type, pg_sizes, start, end);
+
+       kvmppc_set_gpr(vcpu, 3, H_SUCCESS);
+       return RESUME_GUEST;
+}
+
+static long kvmppc_h_rpt_invalidate(struct kvm_vcpu *vcpu,
+                                   unsigned long id, unsigned long target,
+                                   unsigned long type, unsigned long pg_sizes,
+                                   unsigned long start, unsigned long end)
+{
+       if (!kvm_is_radix(vcpu->kvm))
+               return H_UNSUPPORTED;
+
+       if (end < start)
+               return H_P5;
+
+       /*
+        * Partition-scoped invalidation for nested guests.
+        */
+       if (type & H_RPTI_TYPE_NESTED) {
+               if (!nesting_enabled(vcpu->kvm))
+                       return H_FUNCTION;
+
+               /* Support only cores as target */
+               if (target != H_RPTI_TARGET_CMMU)
+                       return H_P2;
+
+               return do_h_rpt_invalidate_pat(vcpu, id, type, pg_sizes,
+                                              start, end);
+       }
+
+       /*
+        * Process-scoped invalidation for L1 guests.
+        */
+       do_h_rpt_invalidate_prt(id, vcpu->kvm->arch.lpid,
+                               type, pg_sizes, start, end);
+       return H_SUCCESS;
+}
+
 int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
 {
+       struct kvm *kvm = vcpu->kvm;
        unsigned long req = kvmppc_get_gpr(vcpu, 3);
        unsigned long target, ret = H_SUCCESS;
        int yield_count;
@@ -937,11 +999,57 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                return RESUME_HOST;
 
        switch (req) {
+       case H_REMOVE:
+               ret = kvmppc_h_remove(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5),
+                                       kvmppc_get_gpr(vcpu, 6));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_ENTER:
+               ret = kvmppc_h_enter(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5),
+                                       kvmppc_get_gpr(vcpu, 6),
+                                       kvmppc_get_gpr(vcpu, 7));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_READ:
+               ret = kvmppc_h_read(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_CLEAR_MOD:
+               ret = kvmppc_h_clear_mod(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_CLEAR_REF:
+               ret = kvmppc_h_clear_ref(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_PROTECT:
+               ret = kvmppc_h_protect(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                       kvmppc_get_gpr(vcpu, 5),
+                                       kvmppc_get_gpr(vcpu, 6));
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+       case H_BULK_REMOVE:
+               ret = kvmppc_h_bulk_remove(vcpu);
+               if (ret == H_TOO_HARD)
+                       return RESUME_HOST;
+               break;
+
        case H_CEDE:
                break;
        case H_PROD:
                target = kvmppc_get_gpr(vcpu, 4);
-               tvcpu = kvmppc_find_vcpu(vcpu->kvm, target);
+               tvcpu = kvmppc_find_vcpu(kvm, target);
                if (!tvcpu) {
                        ret = H_PARAMETER;
                        break;
@@ -955,7 +1063,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                target = kvmppc_get_gpr(vcpu, 4);
                if (target == -1)
                        break;
-               tvcpu = kvmppc_find_vcpu(vcpu->kvm, target);
+               tvcpu = kvmppc_find_vcpu(kvm, target);
                if (!tvcpu) {
                        ret = H_PARAMETER;
                        break;
@@ -971,12 +1079,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                                        kvmppc_get_gpr(vcpu, 6));
                break;
        case H_RTAS:
-               if (list_empty(&vcpu->kvm->arch.rtas_tokens))
+               if (list_empty(&kvm->arch.rtas_tokens))
                        return RESUME_HOST;
 
-               idx = srcu_read_lock(&vcpu->kvm->srcu);
+               idx = srcu_read_lock(&kvm->srcu);
                rc = kvmppc_rtas_hcall(vcpu);
-               srcu_read_unlock(&vcpu->kvm->srcu, idx);
+               srcu_read_unlock(&kvm->srcu, idx);
 
                if (rc == -ENOENT)
                        return RESUME_HOST;
@@ -1060,15 +1168,23 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                if (!powernv_get_random_long(&vcpu->arch.regs.gpr[4]))
                        ret = H_HARDWARE;
                break;
+       case H_RPT_INVALIDATE:
+               ret = kvmppc_h_rpt_invalidate(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                             kvmppc_get_gpr(vcpu, 5),
+                                             kvmppc_get_gpr(vcpu, 6),
+                                             kvmppc_get_gpr(vcpu, 7),
+                                             kvmppc_get_gpr(vcpu, 8),
+                                             kvmppc_get_gpr(vcpu, 9));
+               break;
 
        case H_SET_PARTITION_TABLE:
                ret = H_FUNCTION;
-               if (nesting_enabled(vcpu->kvm))
+               if (nesting_enabled(kvm))
                        ret = kvmhv_set_partition_table(vcpu);
                break;
        case H_ENTER_NESTED:
                ret = H_FUNCTION;
-               if (!nesting_enabled(vcpu->kvm))
+               if (!nesting_enabled(kvm))
                        break;
                ret = kvmhv_enter_nested_guest(vcpu);
                if (ret == H_INTERRUPT) {
@@ -1083,12 +1199,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                break;
        case H_TLB_INVALIDATE:
                ret = H_FUNCTION;
-               if (nesting_enabled(vcpu->kvm))
+               if (nesting_enabled(kvm))
                        ret = kvmhv_do_nested_tlbie(vcpu);
                break;
        case H_COPY_TOFROM_GUEST:
                ret = H_FUNCTION;
-               if (nesting_enabled(vcpu->kvm))
+               if (nesting_enabled(kvm))
                        ret = kvmhv_copy_tofrom_guest_nested(vcpu);
                break;
        case H_PAGE_INIT:
@@ -1099,7 +1215,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
        case H_SVM_PAGE_IN:
                ret = H_UNSUPPORTED;
                if (kvmppc_get_srr1(vcpu) & MSR_S)
-                       ret = kvmppc_h_svm_page_in(vcpu->kvm,
+                       ret = kvmppc_h_svm_page_in(kvm,
                                                   kvmppc_get_gpr(vcpu, 4),
                                                   kvmppc_get_gpr(vcpu, 5),
                                                   kvmppc_get_gpr(vcpu, 6));
@@ -1107,7 +1223,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
        case H_SVM_PAGE_OUT:
                ret = H_UNSUPPORTED;
                if (kvmppc_get_srr1(vcpu) & MSR_S)
-                       ret = kvmppc_h_svm_page_out(vcpu->kvm,
+                       ret = kvmppc_h_svm_page_out(kvm,
                                                    kvmppc_get_gpr(vcpu, 4),
                                                    kvmppc_get_gpr(vcpu, 5),
                                                    kvmppc_get_gpr(vcpu, 6));
@@ -1115,12 +1231,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
        case H_SVM_INIT_START:
                ret = H_UNSUPPORTED;
                if (kvmppc_get_srr1(vcpu) & MSR_S)
-                       ret = kvmppc_h_svm_init_start(vcpu->kvm);
+                       ret = kvmppc_h_svm_init_start(kvm);
                break;
        case H_SVM_INIT_DONE:
                ret = H_UNSUPPORTED;
                if (kvmppc_get_srr1(vcpu) & MSR_S)
-                       ret = kvmppc_h_svm_init_done(vcpu->kvm);
+                       ret = kvmppc_h_svm_init_done(kvm);
                break;
        case H_SVM_INIT_ABORT:
                /*
@@ -1130,24 +1246,26 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
                 * Instead the kvm->arch.secure_guest flag is checked inside
                 * kvmppc_h_svm_init_abort().
                 */
-               ret = kvmppc_h_svm_init_abort(vcpu->kvm);
+               ret = kvmppc_h_svm_init_abort(kvm);
                break;
 
        default:
                return RESUME_HOST;
        }
+       WARN_ON_ONCE(ret == H_TOO_HARD);
        kvmppc_set_gpr(vcpu, 3, ret);
        vcpu->arch.hcall_needed = 0;
        return RESUME_GUEST;
 }
 
 /*
- * Handle H_CEDE in the nested virtualization case where we haven't
- * called the real-mode hcall handlers in book3s_hv_rmhandlers.S.
+ * Handle H_CEDE in the P9 path where we don't call the real-mode hcall
+ * handlers in book3s_hv_rmhandlers.S.
+ *
  * This has to be done early, not in kvmppc_pseries_do_hcall(), so
  * that the cede logic in kvmppc_run_single_vcpu() works properly.
  */
-static void kvmppc_nested_cede(struct kvm_vcpu *vcpu)
+static void kvmppc_cede(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.shregs.msr |= MSR_EE;
        vcpu->arch.ceded = 1;
@@ -1178,6 +1296,7 @@ static int kvmppc_hcall_impl_hv(unsigned long cmd)
        case H_XIRR_X:
 #endif
        case H_PAGE_INIT:
+       case H_RPT_INVALIDATE:
                return 1;
        }
 
@@ -1400,13 +1519,39 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,
        }
        case BOOK3S_INTERRUPT_SYSCALL:
        {
-               /* hcall - punt to userspace */
                int i;
 
-               /* hypercall with MSR_PR has already been handled in rmode,
-                * and never reaches here.
-                */
+               if (unlikely(vcpu->arch.shregs.msr & MSR_PR)) {
+                       /*
+                        * Guest userspace executed sc 1. This can only be
+                        * reached by the P9 path because the old path
+                        * handles this case in realmode hcall handlers.
+                        */
+                       if (!kvmhv_vcpu_is_radix(vcpu)) {
+                               /*
+                                * A guest could be running PR KVM, so this
+                                * may be a PR KVM hcall. It must be reflected
+                                * to the guest kernel as a sc interrupt.
+                                */
+                               kvmppc_core_queue_syscall(vcpu);
+                       } else {
+                               /*
+                                * Radix guests can not run PR KVM or nested HV
+                                * hash guests which might run PR KVM, so this
+                                * is always a privilege fault. Send a program
+                                * check to guest kernel.
+                                */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV);
+                       }
+                       r = RESUME_GUEST;
+                       break;
+               }
 
+               /*
+                * hcall - gather args and set exit_reason. This will next be
+                * handled by kvmppc_pseries_do_hcall which may be able to deal
+                * with it and resume guest, or may punt to userspace.
+                */
                run->papr_hcall.nr = kvmppc_get_gpr(vcpu, 3);
                for (i = 0; i < 9; ++i)
                        run->papr_hcall.args[i] = kvmppc_get_gpr(vcpu, 4 + i);
@@ -1419,20 +1564,102 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,
         * We get these next two if the guest accesses a page which it thinks
         * it has mapped but which is not actually present, either because
         * it is for an emulated I/O device or because the corresonding
-        * host page has been paged out.  Any other HDSI/HISI interrupts
-        * have been handled already.
+        * host page has been paged out.
+        *
+        * Any other HDSI/HISI interrupts have been handled already for P7/8
+        * guests. For POWER9 hash guests not using rmhandlers, basic hash
+        * fault handling is done here.
         */
-       case BOOK3S_INTERRUPT_H_DATA_STORAGE:
-               r = RESUME_PAGE_FAULT;
+       case BOOK3S_INTERRUPT_H_DATA_STORAGE: {
+               unsigned long vsid;
+               long err;
+
+               if (vcpu->arch.fault_dsisr == HDSISR_CANARY) {
+                       r = RESUME_GUEST; /* Just retry if it's the canary */
+                       break;
+               }
+
+               if (kvm_is_radix(vcpu->kvm) || !cpu_has_feature(CPU_FTR_ARCH_300)) {
+                       /*
+                        * Radix doesn't require anything, and pre-ISAv3.0 hash
+                        * already attempted to handle this in rmhandlers. The
+                        * hash fault handling below is v3 only (it uses ASDR
+                        * via fault_gpa).
+                        */
+                       r = RESUME_PAGE_FAULT;
+                       break;
+               }
+
+               if (!(vcpu->arch.fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT))) {
+                       kvmppc_core_queue_data_storage(vcpu,
+                               vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
+                       r = RESUME_GUEST;
+                       break;
+               }
+
+               if (!(vcpu->arch.shregs.msr & MSR_DR))
+                       vsid = vcpu->kvm->arch.vrma_slb_v;
+               else
+                       vsid = vcpu->arch.fault_gpa;
+
+               err = kvmppc_hpte_hv_fault(vcpu, vcpu->arch.fault_dar,
+                               vsid, vcpu->arch.fault_dsisr, true);
+               if (err == 0) {
+                       r = RESUME_GUEST;
+               } else if (err == -1 || err == -2) {
+                       r = RESUME_PAGE_FAULT;
+               } else {
+                       kvmppc_core_queue_data_storage(vcpu,
+                               vcpu->arch.fault_dar, err);
+                       r = RESUME_GUEST;
+               }
                break;
-       case BOOK3S_INTERRUPT_H_INST_STORAGE:
+       }
+       case BOOK3S_INTERRUPT_H_INST_STORAGE: {
+               unsigned long vsid;
+               long err;
+
                vcpu->arch.fault_dar = kvmppc_get_pc(vcpu);
                vcpu->arch.fault_dsisr = vcpu->arch.shregs.msr &
                        DSISR_SRR1_MATCH_64S;
-               if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE)
-                       vcpu->arch.fault_dsisr |= DSISR_ISSTORE;
-               r = RESUME_PAGE_FAULT;
+               if (kvm_is_radix(vcpu->kvm) || !cpu_has_feature(CPU_FTR_ARCH_300)) {
+                       /*
+                        * Radix doesn't require anything, and pre-ISAv3.0 hash
+                        * already attempted to handle this in rmhandlers. The
+                        * hash fault handling below is v3 only (it uses ASDR
+                        * via fault_gpa).
+                        */
+                       if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE)
+                               vcpu->arch.fault_dsisr |= DSISR_ISSTORE;
+                       r = RESUME_PAGE_FAULT;
+                       break;
+               }
+
+               if (!(vcpu->arch.fault_dsisr & SRR1_ISI_NOPT)) {
+                       kvmppc_core_queue_inst_storage(vcpu,
+                               vcpu->arch.fault_dsisr);
+                       r = RESUME_GUEST;
+                       break;
+               }
+
+               if (!(vcpu->arch.shregs.msr & MSR_IR))
+                       vsid = vcpu->kvm->arch.vrma_slb_v;
+               else
+                       vsid = vcpu->arch.fault_gpa;
+
+               err = kvmppc_hpte_hv_fault(vcpu, vcpu->arch.fault_dar,
+                               vsid, vcpu->arch.fault_dsisr, false);
+               if (err == 0) {
+                       r = RESUME_GUEST;
+               } else if (err == -1) {
+                       r = RESUME_PAGE_FAULT;
+               } else {
+                       kvmppc_core_queue_inst_storage(vcpu, err);
+                       r = RESUME_GUEST;
+               }
                break;
+       }
+
        /*
         * This occurs if the guest executes an illegal instruction.
         * If the guest debug is disabled, generate a program interrupt
@@ -1593,6 +1820,23 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
                if (!xics_on_xive())
                        kvmppc_xics_rm_complete(vcpu, 0);
                break;
+       case BOOK3S_INTERRUPT_SYSCALL:
+       {
+               unsigned long req = kvmppc_get_gpr(vcpu, 3);
+
+               /*
+                * The H_RPT_INVALIDATE hcalls issued by nested
+                * guests for process-scoped invalidations when
+                * GTSE=0, are handled here in L0.
+                */
+               if (req == H_RPT_INVALIDATE) {
+                       r = kvmppc_nested_h_rpt_invalidate(vcpu);
+                       break;
+               }
+
+               r = RESUME_HOST;
+               break;
+       }
        default:
                r = RESUME_HOST;
                break;
@@ -1654,6 +1898,14 @@ unsigned long kvmppc_filter_lpcr_hv(struct kvm *kvm, unsigned long lpcr)
                lpcr &= ~LPCR_AIL;
        if ((lpcr & LPCR_AIL) != LPCR_AIL_3)
                lpcr &= ~LPCR_AIL; /* LPCR[AIL]=1/2 is disallowed */
+       /*
+        * On some POWER9s we force AIL off for radix guests to prevent
+        * executing in MSR[HV]=1 mode with the MMU enabled and PIDR set to
+        * guest, which can result in Q0 translations with LPID=0 PID=PIDR to
+        * be cached, which the host TLB management does not expect.
+        */
+       if (kvm_is_radix(kvm) && cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
+               lpcr &= ~LPCR_AIL;
 
        /*
         * On POWER9, allow userspace to enable large decrementer for the
@@ -2233,7 +2485,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
  */
 static int threads_per_vcore(struct kvm *kvm)
 {
-       if (kvm->arch.threads_indep)
+       if (cpu_has_feature(CPU_FTR_ARCH_300))
                return 1;
        return threads_per_subcore;
 }
@@ -2657,7 +2909,7 @@ static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)
        cpumask_t *cpu_in_guest;
        int i;
 
-       cpu = cpu_first_thread_sibling(cpu);
+       cpu = cpu_first_tlb_thread_sibling(cpu);
        if (nested) {
                cpumask_set_cpu(cpu, &nested->need_tlb_flush);
                cpu_in_guest = &nested->cpu_in_guest;
@@ -2671,9 +2923,10 @@ static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)
         * the other side is the first smp_mb() in kvmppc_run_core().
         */
        smp_mb();
-       for (i = 0; i < threads_per_core; ++i)
-               if (cpumask_test_cpu(cpu + i, cpu_in_guest))
-                       smp_call_function_single(cpu + i, do_nothing, NULL, 1);
+       for (i = cpu; i <= cpu_last_tlb_thread_sibling(cpu);
+                                       i += cpu_tlb_thread_sibling_step())
+               if (cpumask_test_cpu(i, cpu_in_guest))
+                       smp_call_function_single(i, do_nothing, NULL, 1);
 }
 
 static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu)
@@ -2704,8 +2957,8 @@ static void kvmppc_prepare_radix_vcpu(struct kvm_vcpu *vcpu, int pcpu)
         */
        if (prev_cpu != pcpu) {
                if (prev_cpu >= 0 &&
-                   cpu_first_thread_sibling(prev_cpu) !=
-                   cpu_first_thread_sibling(pcpu))
+                   cpu_first_tlb_thread_sibling(prev_cpu) !=
+                   cpu_first_tlb_thread_sibling(pcpu))
                        radix_flush_cpu(kvm, prev_cpu, vcpu);
                if (nested)
                        nested->prev_cpu[vcpu->arch.nested_vcpu_id] = pcpu;
@@ -2967,9 +3220,6 @@ static void prepare_threads(struct kvmppc_vcore *vc)
        for_each_runnable_thread(i, vcpu, vc) {
                if (signal_pending(vcpu->arch.run_task))
                        vcpu->arch.ret = -EINTR;
-               else if (no_mixing_hpt_and_radix &&
-                        kvm_is_radix(vc->kvm) != radix_enabled())
-                       vcpu->arch.ret = -EINVAL;
                else if (vcpu->arch.vpa.update_pending ||
                         vcpu->arch.slb_shadow.update_pending ||
                         vcpu->arch.dtl.update_pending)
@@ -3176,6 +3426,9 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        int trap;
        bool is_power8;
 
+       if (WARN_ON_ONCE(cpu_has_feature(CPU_FTR_ARCH_300)))
+               return;
+
        /*
         * Remove from the list any threads that have a signal pending
         * or need a VPA update done
@@ -3203,9 +3456,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
         * Make sure we are running on primary threads, and that secondary
         * threads are offline.  Also check if the number of threads in this
         * guest are greater than the current system threads per guest.
-        * On POWER9, we need to be not in independent-threads mode if
-        * this is a HPT guest on a radix host machine where the
-        * CPU threads may not be in different MMU modes.
         */
        if ((controlled_threads > 1) &&
            ((vc->num_threads > threads_per_subcore) || !on_primary_thread())) {
@@ -3230,18 +3480,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
                collect_piggybacks(&core_info, target_threads);
 
        /*
-        * On radix, arrange for TLB flushing if necessary.
-        * This has to be done before disabling interrupts since
-        * it uses smp_call_function().
-        */
-       pcpu = smp_processor_id();
-       if (kvm_is_radix(vc->kvm)) {
-               for (sub = 0; sub < core_info.n_subcores; ++sub)
-                       for_each_runnable_thread(i, vcpu, core_info.vc[sub])
-                               kvmppc_prepare_radix_vcpu(vcpu, pcpu);
-       }
-
-       /*
         * Hard-disable interrupts, and check resched flag and signals.
         * If we need to reschedule or deliver a signal, clean up
         * and return without going into the guest(s).
@@ -3273,8 +3511,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        cmd_bit = stat_bit = 0;
        split = core_info.n_subcores;
        sip = NULL;
-       is_power8 = cpu_has_feature(CPU_FTR_ARCH_207S)
-               && !cpu_has_feature(CPU_FTR_ARCH_300);
+       is_power8 = cpu_has_feature(CPU_FTR_ARCH_207S);
 
        if (split > 1) {
                sip = &split_info;
@@ -3478,184 +3715,113 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        trace_kvmppc_run_core(vc, 1);
 }
 
-/*
- * Load up hypervisor-mode registers on P9.
- */
-static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
-                                    unsigned long lpcr)
+static void load_spr_state(struct kvm_vcpu *vcpu)
 {
-       struct kvmppc_vcore *vc = vcpu->arch.vcore;
-       s64 hdec;
-       u64 tb, purr, spurr;
-       int trap;
-       unsigned long host_hfscr = mfspr(SPRN_HFSCR);
-       unsigned long host_ciabr = mfspr(SPRN_CIABR);
-       unsigned long host_dawr0 = mfspr(SPRN_DAWR0);
-       unsigned long host_dawrx0 = mfspr(SPRN_DAWRX0);
-       unsigned long host_psscr = mfspr(SPRN_PSSCR);
-       unsigned long host_pidr = mfspr(SPRN_PID);
-       unsigned long host_dawr1 = 0;
-       unsigned long host_dawrx1 = 0;
-
-       if (cpu_has_feature(CPU_FTR_DAWR1)) {
-               host_dawr1 = mfspr(SPRN_DAWR1);
-               host_dawrx1 = mfspr(SPRN_DAWRX1);
-       }
+       mtspr(SPRN_DSCR, vcpu->arch.dscr);
+       mtspr(SPRN_IAMR, vcpu->arch.iamr);
+       mtspr(SPRN_PSPB, vcpu->arch.pspb);
+       mtspr(SPRN_FSCR, vcpu->arch.fscr);
+       mtspr(SPRN_TAR, vcpu->arch.tar);
+       mtspr(SPRN_EBBHR, vcpu->arch.ebbhr);
+       mtspr(SPRN_EBBRR, vcpu->arch.ebbrr);
+       mtspr(SPRN_BESCR, vcpu->arch.bescr);
+       mtspr(SPRN_WORT, vcpu->arch.wort);
+       mtspr(SPRN_TIDR, vcpu->arch.tid);
+       mtspr(SPRN_AMR, vcpu->arch.amr);
+       mtspr(SPRN_UAMOR, vcpu->arch.uamor);
 
        /*
-        * P8 and P9 suppress the HDEC exception when LPCR[HDICE] = 0,
-        * so set HDICE before writing HDEC.
+        * DAR, DSISR, and for nested HV, SPRGs must be set with MSR[RI]
+        * clear (or hstate set appropriately to catch those registers
+        * being clobbered if we take a MCE or SRESET), so those are done
+        * later.
         */
-       mtspr(SPRN_LPCR, vcpu->kvm->arch.host_lpcr | LPCR_HDICE);
-       isync();
-
-       hdec = time_limit - mftb();
-       if (hdec < 0) {
-               mtspr(SPRN_LPCR, vcpu->kvm->arch.host_lpcr);
-               isync();
-               return BOOK3S_INTERRUPT_HV_DECREMENTER;
-       }
-       mtspr(SPRN_HDEC, hdec);
-
-       if (vc->tb_offset) {
-               u64 new_tb = mftb() + vc->tb_offset;
-               mtspr(SPRN_TBU40, new_tb);
-               tb = mftb();
-               if ((tb & 0xffffff) < (new_tb & 0xffffff))
-                       mtspr(SPRN_TBU40, new_tb + 0x1000000);
-               vc->tb_offset_applied = vc->tb_offset;
-       }
-
-       if (vc->pcr)
-               mtspr(SPRN_PCR, vc->pcr | PCR_MASK);
-       mtspr(SPRN_DPDES, vc->dpdes);
-       mtspr(SPRN_VTB, vc->vtb);
-
-       local_paca->kvm_hstate.host_purr = mfspr(SPRN_PURR);
-       local_paca->kvm_hstate.host_spurr = mfspr(SPRN_SPURR);
-       mtspr(SPRN_PURR, vcpu->arch.purr);
-       mtspr(SPRN_SPURR, vcpu->arch.spurr);
-
-       if (dawr_enabled()) {
-               mtspr(SPRN_DAWR0, vcpu->arch.dawr0);
-               mtspr(SPRN_DAWRX0, vcpu->arch.dawrx0);
-               if (cpu_has_feature(CPU_FTR_DAWR1)) {
-                       mtspr(SPRN_DAWR1, vcpu->arch.dawr1);
-                       mtspr(SPRN_DAWRX1, vcpu->arch.dawrx1);
-               }
-       }
-       mtspr(SPRN_CIABR, vcpu->arch.ciabr);
-       mtspr(SPRN_IC, vcpu->arch.ic);
-       mtspr(SPRN_PID, vcpu->arch.pid);
 
-       mtspr(SPRN_PSSCR, vcpu->arch.psscr | PSSCR_EC |
-             (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
-
-       mtspr(SPRN_HFSCR, vcpu->arch.hfscr);
-
-       mtspr(SPRN_SPRG0, vcpu->arch.shregs.sprg0);
-       mtspr(SPRN_SPRG1, vcpu->arch.shregs.sprg1);
-       mtspr(SPRN_SPRG2, vcpu->arch.shregs.sprg2);
-       mtspr(SPRN_SPRG3, vcpu->arch.shregs.sprg3);
-
-       mtspr(SPRN_AMOR, ~0UL);
-
-       mtspr(SPRN_LPCR, lpcr);
-       isync();
-
-       kvmppc_xive_push_vcpu(vcpu);
-
-       mtspr(SPRN_SRR0, vcpu->arch.shregs.srr0);
-       mtspr(SPRN_SRR1, vcpu->arch.shregs.srr1);
-
-       trap = __kvmhv_vcpu_entry_p9(vcpu);
-
-       /* Advance host PURR/SPURR by the amount used by guest */
-       purr = mfspr(SPRN_PURR);
-       spurr = mfspr(SPRN_SPURR);
-       mtspr(SPRN_PURR, local_paca->kvm_hstate.host_purr +
-             purr - vcpu->arch.purr);
-       mtspr(SPRN_SPURR, local_paca->kvm_hstate.host_spurr +
-             spurr - vcpu->arch.spurr);
-       vcpu->arch.purr = purr;
-       vcpu->arch.spurr = spurr;
+       if (!(vcpu->arch.ctrl & 1))
+               mtspr(SPRN_CTRLT, mfspr(SPRN_CTRLF) & ~1);
+}
 
-       vcpu->arch.ic = mfspr(SPRN_IC);
-       vcpu->arch.pid = mfspr(SPRN_PID);
-       vcpu->arch.psscr = mfspr(SPRN_PSSCR) & PSSCR_GUEST_VIS;
+static void store_spr_state(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.ctrl = mfspr(SPRN_CTRLF);
 
-       vcpu->arch.shregs.sprg0 = mfspr(SPRN_SPRG0);
-       vcpu->arch.shregs.sprg1 = mfspr(SPRN_SPRG1);
-       vcpu->arch.shregs.sprg2 = mfspr(SPRN_SPRG2);
-       vcpu->arch.shregs.sprg3 = mfspr(SPRN_SPRG3);
+       vcpu->arch.iamr = mfspr(SPRN_IAMR);
+       vcpu->arch.pspb = mfspr(SPRN_PSPB);
+       vcpu->arch.fscr = mfspr(SPRN_FSCR);
+       vcpu->arch.tar = mfspr(SPRN_TAR);
+       vcpu->arch.ebbhr = mfspr(SPRN_EBBHR);
+       vcpu->arch.ebbrr = mfspr(SPRN_EBBRR);
+       vcpu->arch.bescr = mfspr(SPRN_BESCR);
+       vcpu->arch.wort = mfspr(SPRN_WORT);
+       vcpu->arch.tid = mfspr(SPRN_TIDR);
+       vcpu->arch.amr = mfspr(SPRN_AMR);
+       vcpu->arch.uamor = mfspr(SPRN_UAMOR);
+       vcpu->arch.dscr = mfspr(SPRN_DSCR);
+}
 
-       /* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */
-       mtspr(SPRN_PSSCR, host_psscr |
-             (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
-       mtspr(SPRN_HFSCR, host_hfscr);
-       mtspr(SPRN_CIABR, host_ciabr);
-       mtspr(SPRN_DAWR0, host_dawr0);
-       mtspr(SPRN_DAWRX0, host_dawrx0);
-       if (cpu_has_feature(CPU_FTR_DAWR1)) {
-               mtspr(SPRN_DAWR1, host_dawr1);
-               mtspr(SPRN_DAWRX1, host_dawrx1);
-       }
-       mtspr(SPRN_PID, host_pidr);
+/*
+ * Privileged (non-hypervisor) host registers to save.
+ */
+struct p9_host_os_sprs {
+       unsigned long dscr;
+       unsigned long tidr;
+       unsigned long iamr;
+       unsigned long amr;
+       unsigned long fscr;
+};
 
-       /*
-        * Since this is radix, do a eieio; tlbsync; ptesync sequence in
-        * case we interrupted the guest between a tlbie and a ptesync.
-        */
-       asm volatile("eieio; tlbsync; ptesync");
+static void save_p9_host_os_sprs(struct p9_host_os_sprs *host_os_sprs)
+{
+       host_os_sprs->dscr = mfspr(SPRN_DSCR);
+       host_os_sprs->tidr = mfspr(SPRN_TIDR);
+       host_os_sprs->iamr = mfspr(SPRN_IAMR);
+       host_os_sprs->amr = mfspr(SPRN_AMR);
+       host_os_sprs->fscr = mfspr(SPRN_FSCR);
+}
 
-       /*
-        * cp_abort is required if the processor supports local copy-paste
-        * to clear the copy buffer that was under control of the guest.
-        */
-       if (cpu_has_feature(CPU_FTR_ARCH_31))
-               asm volatile(PPC_CP_ABORT);
+/* vcpu guest regs must already be saved */
+static void restore_p9_host_os_sprs(struct kvm_vcpu *vcpu,
+                                   struct p9_host_os_sprs *host_os_sprs)
+{
+       mtspr(SPRN_PSPB, 0);
+       mtspr(SPRN_WORT, 0);
+       mtspr(SPRN_UAMOR, 0);
 
-       mtspr(SPRN_LPID, vcpu->kvm->arch.host_lpid);    /* restore host LPID */
-       isync();
+       mtspr(SPRN_DSCR, host_os_sprs->dscr);
+       mtspr(SPRN_TIDR, host_os_sprs->tidr);
+       mtspr(SPRN_IAMR, host_os_sprs->iamr);
 
-       vc->dpdes = mfspr(SPRN_DPDES);
-       vc->vtb = mfspr(SPRN_VTB);
-       mtspr(SPRN_DPDES, 0);
-       if (vc->pcr)
-               mtspr(SPRN_PCR, PCR_MASK);
+       if (host_os_sprs->amr != vcpu->arch.amr)
+               mtspr(SPRN_AMR, host_os_sprs->amr);
 
-       if (vc->tb_offset_applied) {
-               u64 new_tb = mftb() - vc->tb_offset_applied;
-               mtspr(SPRN_TBU40, new_tb);
-               tb = mftb();
-               if ((tb & 0xffffff) < (new_tb & 0xffffff))
-                       mtspr(SPRN_TBU40, new_tb + 0x1000000);
-               vc->tb_offset_applied = 0;
-       }
+       if (host_os_sprs->fscr != vcpu->arch.fscr)
+               mtspr(SPRN_FSCR, host_os_sprs->fscr);
 
-       mtspr(SPRN_HDEC, 0x7fffffff);
-       mtspr(SPRN_LPCR, vcpu->kvm->arch.host_lpcr);
+       /* Save guest CTRL register, set runlatch to 1 */
+       if (!(vcpu->arch.ctrl & 1))
+               mtspr(SPRN_CTRLT, 1);
+}
 
-       return trap;
+static inline bool hcall_is_xics(unsigned long req)
+{
+       return req == H_EOI || req == H_CPPR || req == H_IPI ||
+               req == H_IPOLL || req == H_XIRR || req == H_XIRR_X;
 }
 
 /*
- * Virtual-mode guest entry for POWER9 and later when the host and
- * guest are both using the radix MMU.  The LPIDR has already been set.
+ * Guest entry for POWER9 and later CPUs.
  */
 static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                         unsigned long lpcr)
 {
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
-       unsigned long host_dscr = mfspr(SPRN_DSCR);
-       unsigned long host_tidr = mfspr(SPRN_TIDR);
-       unsigned long host_iamr = mfspr(SPRN_IAMR);
-       unsigned long host_amr = mfspr(SPRN_AMR);
-       unsigned long host_fscr = mfspr(SPRN_FSCR);
+       struct p9_host_os_sprs host_os_sprs;
        s64 dec;
        u64 tb;
        int trap, save_pmu;
 
+       WARN_ON_ONCE(vcpu->arch.ceded);
+
        dec = mfspr(SPRN_DEC);
        tb = mftb();
        if (dec < 0)
@@ -3664,7 +3830,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
        if (local_paca->kvm_hstate.dec_expires < time_limit)
                time_limit = local_paca->kvm_hstate.dec_expires;
 
-       vcpu->arch.ceded = 0;
+       save_p9_host_os_sprs(&host_os_sprs);
 
        kvmhv_save_host_pmu();          /* saves it to PACA kvm_hstate */
 
@@ -3693,24 +3859,20 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
 #endif
        mtspr(SPRN_VRSAVE, vcpu->arch.vrsave);
 
-       mtspr(SPRN_DSCR, vcpu->arch.dscr);
-       mtspr(SPRN_IAMR, vcpu->arch.iamr);
-       mtspr(SPRN_PSPB, vcpu->arch.pspb);
-       mtspr(SPRN_FSCR, vcpu->arch.fscr);
-       mtspr(SPRN_TAR, vcpu->arch.tar);
-       mtspr(SPRN_EBBHR, vcpu->arch.ebbhr);
-       mtspr(SPRN_EBBRR, vcpu->arch.ebbrr);
-       mtspr(SPRN_BESCR, vcpu->arch.bescr);
-       mtspr(SPRN_WORT, vcpu->arch.wort);
-       mtspr(SPRN_TIDR, vcpu->arch.tid);
-       mtspr(SPRN_DAR, vcpu->arch.shregs.dar);
-       mtspr(SPRN_DSISR, vcpu->arch.shregs.dsisr);
-       mtspr(SPRN_AMR, vcpu->arch.amr);
-       mtspr(SPRN_UAMOR, vcpu->arch.uamor);
-
-       if (!(vcpu->arch.ctrl & 1))
-               mtspr(SPRN_CTRLT, mfspr(SPRN_CTRLF) & ~1);
+       load_spr_state(vcpu);
 
+       /*
+        * When setting DEC, we must always deal with irq_work_raise via NMI vs
+        * setting DEC. The problem occurs right as we switch into guest mode
+        * if a NMI hits and sets pending work and sets DEC, then that will
+        * apply to the guest and not bring us back to the host.
+        *
+        * irq_work_raise could check a flag (or possibly LPCR[HDICE] for
+        * example) and set HDEC to 1? That wouldn't solve the nested hv
+        * case which needs to abort the hcall or zero the time limit.
+        *
+        * XXX: Another day's problem.
+        */
        mtspr(SPRN_DEC, vcpu->arch.dec_expires - mftb());
 
        if (kvmhv_on_pseries()) {
@@ -3718,7 +3880,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                 * We need to save and restore the guest visible part of the
                 * psscr (i.e. using SPRN_PSSCR_PR) since the hypervisor
                 * doesn't do this for us. Note only required if pseries since
-                * this is done in kvmhv_load_hv_regs_and_go() below otherwise.
+                * this is done in kvmhv_vcpu_entry_p9() below otherwise.
                 */
                unsigned long host_psscr;
                /* call our hypervisor to load up HV regs and go */
@@ -3738,6 +3900,8 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                        hvregs.vcpu_token = vcpu->vcpu_id;
                }
                hvregs.hdec_expiry = time_limit;
+               mtspr(SPRN_DAR, vcpu->arch.shregs.dar);
+               mtspr(SPRN_DSISR, vcpu->arch.shregs.dsisr);
                trap = plpar_hcall_norets(H_ENTER_NESTED, __pa(&hvregs),
                                          __pa(&vcpu->arch.regs));
                kvmhv_restore_hv_return_state(vcpu, &hvregs);
@@ -3750,15 +3914,41 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
                /* H_CEDE has to be handled now, not later */
                if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested &&
                    kvmppc_get_gpr(vcpu, 3) == H_CEDE) {
-                       kvmppc_nested_cede(vcpu);
+                       kvmppc_cede(vcpu);
                        kvmppc_set_gpr(vcpu, 3, 0);
                        trap = 0;
                }
        } else {
-               trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit, lpcr);
+               kvmppc_xive_push_vcpu(vcpu);
+               trap = kvmhv_vcpu_entry_p9(vcpu, time_limit, lpcr);
+               if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested &&
+                   !(vcpu->arch.shregs.msr & MSR_PR)) {
+                       unsigned long req = kvmppc_get_gpr(vcpu, 3);
+
+                       /* H_CEDE has to be handled now, not later */
+                       if (req == H_CEDE) {
+                               kvmppc_cede(vcpu);
+                               kvmppc_xive_rearm_escalation(vcpu); /* may un-cede */
+                               kvmppc_set_gpr(vcpu, 3, 0);
+                               trap = 0;
+
+                       /* XICS hcalls must be handled before xive is pulled */
+                       } else if (hcall_is_xics(req)) {
+                               int ret;
+
+                               ret = kvmppc_xive_xics_hcall(vcpu, req);
+                               if (ret != H_TOO_HARD) {
+                                       kvmppc_set_gpr(vcpu, 3, ret);
+                                       trap = 0;
+                               }
+                       }
+               }
+               kvmppc_xive_pull_vcpu(vcpu);
+
+               if (kvm_is_radix(vcpu->kvm))
+                       vcpu->arch.slb_max = 0;
        }
 
-       vcpu->arch.slb_max = 0;
        dec = mfspr(SPRN_DEC);
        if (!(lpcr & LPCR_LD)) /* Sign extend if not using large decrementer */
                dec = (s32) dec;
@@ -3766,36 +3956,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
        vcpu->arch.dec_expires = dec + tb;
        vcpu->cpu = -1;
        vcpu->arch.thread_cpu = -1;
-       /* Save guest CTRL register, set runlatch to 1 */
-       vcpu->arch.ctrl = mfspr(SPRN_CTRLF);
-       if (!(vcpu->arch.ctrl & 1))
-               mtspr(SPRN_CTRLT, vcpu->arch.ctrl | 1);
-
-       vcpu->arch.iamr = mfspr(SPRN_IAMR);
-       vcpu->arch.pspb = mfspr(SPRN_PSPB);
-       vcpu->arch.fscr = mfspr(SPRN_FSCR);
-       vcpu->arch.tar = mfspr(SPRN_TAR);
-       vcpu->arch.ebbhr = mfspr(SPRN_EBBHR);
-       vcpu->arch.ebbrr = mfspr(SPRN_EBBRR);
-       vcpu->arch.bescr = mfspr(SPRN_BESCR);
-       vcpu->arch.wort = mfspr(SPRN_WORT);
-       vcpu->arch.tid = mfspr(SPRN_TIDR);
-       vcpu->arch.amr = mfspr(SPRN_AMR);
-       vcpu->arch.uamor = mfspr(SPRN_UAMOR);
-       vcpu->arch.dscr = mfspr(SPRN_DSCR);
 
-       mtspr(SPRN_PSPB, 0);
-       mtspr(SPRN_WORT, 0);
-       mtspr(SPRN_UAMOR, 0);
-       mtspr(SPRN_DSCR, host_dscr);
-       mtspr(SPRN_TIDR, host_tidr);
-       mtspr(SPRN_IAMR, host_iamr);
+       store_spr_state(vcpu);
 
-       if (host_amr != vcpu->arch.amr)
-               mtspr(SPRN_AMR, host_amr);
-
-       if (host_fscr != vcpu->arch.fscr)
-               mtspr(SPRN_FSCR, host_fscr);
+       restore_p9_host_os_sprs(vcpu, &host_os_sprs);
 
        msr_check_and_set(MSR_FP | MSR_VEC | MSR_VSX);
        store_fp_state(&vcpu->arch.fp);
@@ -3825,6 +3989,9 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit,
        vc->in_guest = 0;
 
        mtspr(SPRN_DEC, local_paca->kvm_hstate.dec_expires - mftb());
+       /* We may have raced with new irq work */
+       if (test_irq_work_pending())
+               set_dec(1);
        mtspr(SPRN_SPRG_VDSO_WRITE, local_paca->sprg_vdso);
 
        kvmhv_load_host_pmu();
@@ -3925,7 +4092,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
        cur = start_poll = ktime_get();
        if (vc->halt_poll_ns) {
                ktime_t stop = ktime_add_ns(start_poll, vc->halt_poll_ns);
-               ++vc->runner->stat.halt_attempted_poll;
+               ++vc->runner->stat.generic.halt_attempted_poll;
 
                vc->vcore_state = VCORE_POLLING;
                spin_unlock(&vc->lock);
@@ -3942,7 +4109,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
                vc->vcore_state = VCORE_INACTIVE;
 
                if (!do_sleep) {
-                       ++vc->runner->stat.halt_successful_poll;
+                       ++vc->runner->stat.generic.halt_successful_poll;
                        goto out;
                }
        }
@@ -3954,7 +4121,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc)
                do_sleep = 0;
                /* If we polled, count this as a successful poll */
                if (vc->halt_poll_ns)
-                       ++vc->runner->stat.halt_successful_poll;
+                       ++vc->runner->stat.generic.halt_successful_poll;
                goto out;
        }
 
@@ -3981,13 +4148,13 @@ out:
                        ktime_to_ns(cur) - ktime_to_ns(start_wait);
                /* Attribute failed poll time */
                if (vc->halt_poll_ns)
-                       vc->runner->stat.halt_poll_fail_ns +=
+                       vc->runner->stat.generic.halt_poll_fail_ns +=
                                ktime_to_ns(start_wait) -
                                ktime_to_ns(start_poll);
        } else {
                /* Attribute successful poll time */
                if (vc->halt_poll_ns)
-                       vc->runner->stat.halt_poll_success_ns +=
+                       vc->runner->stat.generic.halt_poll_success_ns +=
                                ktime_to_ns(cur) -
                                ktime_to_ns(start_poll);
        }
@@ -4014,7 +4181,6 @@ out:
 /*
  * This never fails for a radix guest, as none of the operations it does
  * for a radix guest can fail or have a way to report failure.
- * kvmhv_run_single_vcpu() relies on this fact.
  */
 static int kvmhv_setup_mmu(struct kvm_vcpu *vcpu)
 {
@@ -4170,7 +4336,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
 {
        struct kvm_run *run = vcpu->run;
        int trap, r, pcpu;
-       int srcu_idx, lpid;
+       int srcu_idx;
        struct kvmppc_vcore *vc;
        struct kvm *kvm = vcpu->kvm;
        struct kvm_nested_guest *nested = vcpu->arch.nested;
@@ -4193,8 +4359,15 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
        vc->runner = vcpu;
 
        /* See if the MMU is ready to go */
-       if (!kvm->arch.mmu_ready)
-               kvmhv_setup_mmu(vcpu);
+       if (!kvm->arch.mmu_ready) {
+               r = kvmhv_setup_mmu(vcpu);
+               if (r) {
+                       run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+                       run->fail_entry.hardware_entry_failure_reason = 0;
+                       vcpu->arch.ret = r;
+                       return r;
+               }
+       }
 
        if (need_resched())
                cond_resched();
@@ -4207,7 +4380,8 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
        preempt_disable();
        pcpu = smp_processor_id();
        vc->pcpu = pcpu;
-       kvmppc_prepare_radix_vcpu(vcpu, pcpu);
+       if (kvm_is_radix(kvm))
+               kvmppc_prepare_radix_vcpu(vcpu, pcpu);
 
        local_irq_disable();
        hard_irq_disable();
@@ -4244,13 +4418,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
        vc->vcore_state = VCORE_RUNNING;
        trace_kvmppc_run_core(vc, 0);
 
-       if (cpu_has_feature(CPU_FTR_HVMODE)) {
-               lpid = nested ? nested->shadow_lpid : kvm->arch.lpid;
-               mtspr(SPRN_LPID, lpid);
-               isync();
-               kvmppc_check_need_tlb_flush(kvm, pcpu, nested);
-       }
-
        guest_enter_irqoff();
 
        srcu_idx = srcu_read_lock(&kvm->srcu);
@@ -4269,11 +4436,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
 
        srcu_read_unlock(&kvm->srcu, srcu_idx);
 
-       if (cpu_has_feature(CPU_FTR_HVMODE)) {
-               mtspr(SPRN_LPID, kvm->arch.host_lpid);
-               isync();
-       }
-
        set_irq_happened(trap);
 
        kvmppc_set_host_core(pcpu);
@@ -4419,19 +4581,23 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu)
        vcpu->arch.state = KVMPPC_VCPU_BUSY_IN_HOST;
 
        do {
-               /*
-                * The TLB prefetch bug fixup is only in the kvmppc_run_vcpu
-                * path, which also handles hash and dependent threads mode.
-                */
-               if (kvm->arch.threads_indep && kvm_is_radix(kvm) &&
-                   !cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
+               if (cpu_has_feature(CPU_FTR_ARCH_300))
                        r = kvmhv_run_single_vcpu(vcpu, ~(u64)0,
                                                  vcpu->arch.vcore->lpcr);
                else
                        r = kvmppc_run_vcpu(vcpu);
 
-               if (run->exit_reason == KVM_EXIT_PAPR_HCALL &&
-                   !(vcpu->arch.shregs.msr & MSR_PR)) {
+               if (run->exit_reason == KVM_EXIT_PAPR_HCALL) {
+                       if (WARN_ON_ONCE(vcpu->arch.shregs.msr & MSR_PR)) {
+                               /*
+                                * These should have been caught reflected
+                                * into the guest by now. Final sanity check:
+                                * don't allow userspace to execute hcalls in
+                                * the hypervisor.
+                                */
+                               r = RESUME_GUEST;
+                               continue;
+                       }
                        trace_kvm_hcall_enter(vcpu);
                        r = kvmppc_pseries_do_hcall(vcpu);
                        trace_kvm_hcall_exit(vcpu, r);
@@ -5038,18 +5204,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
        /*
         * Track that we now have a HV mode VM active. This blocks secondary
         * CPU threads from coming online.
-        * On POWER9, we only need to do this if the "indep_threads_mode"
-        * module parameter has been set to N.
         */
-       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
-               if (!indep_threads_mode && !cpu_has_feature(CPU_FTR_HVMODE)) {
-                       pr_warn("KVM: Ignoring indep_threads_mode=N in nested hypervisor\n");
-                       kvm->arch.threads_indep = true;
-               } else {
-                       kvm->arch.threads_indep = indep_threads_mode;
-               }
-       }
-       if (!kvm->arch.threads_indep)
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
                kvm_hv_vm_activated();
 
        /*
@@ -5090,7 +5246,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
 {
        debugfs_remove_recursive(kvm->arch.debugfs_dir);
 
-       if (!kvm->arch.threads_indep)
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
                kvm_hv_vm_deactivated();
 
        kvmppc_free_vcores(kvm);
@@ -5511,7 +5667,9 @@ static int kvmhv_enable_nested(struct kvm *kvm)
 {
        if (!nested)
                return -EPERM;
-       if (!cpu_has_feature(CPU_FTR_ARCH_300) || no_mixing_hpt_and_radix)
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+               return -ENODEV;
+       if (!radix_enabled())
                return -ENODEV;
 
        /* kvm == NULL means the caller is testing if the capability exists */
@@ -5674,11 +5832,25 @@ static int kvmhv_enable_dawr1(struct kvm *kvm)
 
 static bool kvmppc_hash_v3_possible(void)
 {
-       if (radix_enabled() && no_mixing_hpt_and_radix)
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+               return false;
+
+       if (!cpu_has_feature(CPU_FTR_HVMODE))
                return false;
 
-       return cpu_has_feature(CPU_FTR_ARCH_300) &&
-               cpu_has_feature(CPU_FTR_HVMODE);
+       /*
+        * POWER9 chips before version 2.02 can't have some threads in
+        * HPT mode and some in radix mode on the same core.
+        */
+       if (radix_enabled()) {
+               unsigned int pvr = mfspr(SPRN_PVR);
+               if ((pvr >> 16) == PVR_POWER9 &&
+                   (((pvr & 0xe000) == 0 && (pvr & 0xfff) < 0x202) ||
+                    ((pvr & 0xe000) == 0x2000 && (pvr & 0xfff) < 0x101)))
+                       return false;
+       }
+
+       return true;
 }
 
 static struct kvmppc_ops kvm_ops_hv = {
@@ -5822,18 +5994,6 @@ static int kvmppc_book3s_init_hv(void)
        if (kvmppc_radix_possible())
                r = kvmppc_radix_init();
 
-       /*
-        * POWER9 chips before version 2.02 can't have some threads in
-        * HPT mode and some in radix mode on the same core.
-        */
-       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
-               unsigned int pvr = mfspr(SPRN_PVR);
-               if ((pvr >> 16) == PVR_POWER9 &&
-                   (((pvr & 0xe000) == 0 && (pvr & 0xfff) < 0x202) ||
-                    ((pvr & 0xe000) == 0x2000 && (pvr & 0xfff) < 0x101)))
-                       no_mixing_hpt_and_radix = true;
-       }
-
        r = kvmppc_uvmem_init();
        if (r < 0)
                pr_err("KVM-HV: kvmppc_uvmem_init failed %d\n", r);
index 7a0e33a..be8ef1c 100644 (file)
 #include "book3s_xive.h"
 
 /*
- * The XIVE module will populate these when it loads
- */
-unsigned long (*__xive_vm_h_xirr)(struct kvm_vcpu *vcpu);
-unsigned long (*__xive_vm_h_ipoll)(struct kvm_vcpu *vcpu, unsigned long server);
-int (*__xive_vm_h_ipi)(struct kvm_vcpu *vcpu, unsigned long server,
-                      unsigned long mfrr);
-int (*__xive_vm_h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr);
-int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr);
-EXPORT_SYMBOL_GPL(__xive_vm_h_xirr);
-EXPORT_SYMBOL_GPL(__xive_vm_h_ipoll);
-EXPORT_SYMBOL_GPL(__xive_vm_h_ipi);
-EXPORT_SYMBOL_GPL(__xive_vm_h_cppr);
-EXPORT_SYMBOL_GPL(__xive_vm_h_eoi);
-
-/*
  * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206)
  * should be power of 2.
  */
@@ -196,16 +181,9 @@ int kvmppc_hwrng_present(void)
 }
 EXPORT_SYMBOL_GPL(kvmppc_hwrng_present);
 
-long kvmppc_h_random(struct kvm_vcpu *vcpu)
+long kvmppc_rm_h_random(struct kvm_vcpu *vcpu)
 {
-       int r;
-
-       /* Only need to do the expensive mfmsr() on radix */
-       if (kvm_is_radix(vcpu->kvm) && (mfmsr() & MSR_IR))
-               r = powernv_get_random_long(&vcpu->arch.regs.gpr[4]);
-       else
-               r = powernv_get_random_real_mode(&vcpu->arch.regs.gpr[4]);
-       if (r)
+       if (powernv_get_random_real_mode(&vcpu->arch.regs.gpr[4]))
                return H_SUCCESS;
 
        return H_HARDWARE;
@@ -221,15 +199,6 @@ void kvmhv_rm_send_ipi(int cpu)
        void __iomem *xics_phys;
        unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
 
-       /* For a nested hypervisor, use the XICS via hcall */
-       if (kvmhv_on_pseries()) {
-               unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-               plpar_hcall_raw(H_IPI, retbuf, get_hard_smp_processor_id(cpu),
-                               IPI_PRIORITY);
-               return;
-       }
-
        /* On POWER9 we can use msgsnd for any destination cpu. */
        if (cpu_has_feature(CPU_FTR_ARCH_300)) {
                msg |= get_hard_smp_processor_id(cpu);
@@ -442,19 +411,12 @@ static long kvmppc_read_one_intr(bool *again)
                return 1;
 
        /* Now read the interrupt from the ICP */
-       if (kvmhv_on_pseries()) {
-               unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-               rc = plpar_hcall_raw(H_XIRR, retbuf, 0xFF);
-               xirr = cpu_to_be32(retbuf[0]);
-       } else {
-               xics_phys = local_paca->kvm_hstate.xics_phys;
-               rc = 0;
-               if (!xics_phys)
-                       rc = opal_int_get_xirr(&xirr, false);
-               else
-                       xirr = __raw_rm_readl(xics_phys + XICS_XIRR);
-       }
+       xics_phys = local_paca->kvm_hstate.xics_phys;
+       rc = 0;
+       if (!xics_phys)
+               rc = opal_int_get_xirr(&xirr, false);
+       else
+               xirr = __raw_rm_readl(xics_phys + XICS_XIRR);
        if (rc < 0)
                return 1;
 
@@ -483,13 +445,7 @@ static long kvmppc_read_one_intr(bool *again)
         */
        if (xisr == XICS_IPI) {
                rc = 0;
-               if (kvmhv_on_pseries()) {
-                       unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-                       plpar_hcall_raw(H_IPI, retbuf,
-                                       hard_smp_processor_id(), 0xff);
-                       plpar_hcall_raw(H_EOI, retbuf, h_xirr);
-               } else if (xics_phys) {
+               if (xics_phys) {
                        __raw_rm_writeb(0xff, xics_phys + XICS_MFRR);
                        __raw_rm_writel(xirr, xics_phys + XICS_XIRR);
                } else {
@@ -515,13 +471,7 @@ static long kvmppc_read_one_intr(bool *again)
                        /* We raced with the host,
                         * we need to resend that IPI, bummer
                         */
-                       if (kvmhv_on_pseries()) {
-                               unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-                               plpar_hcall_raw(H_IPI, retbuf,
-                                               hard_smp_processor_id(),
-                                               IPI_PRIORITY);
-                       } else if (xics_phys)
+                       if (xics_phys)
                                __raw_rm_writeb(IPI_PRIORITY,
                                                xics_phys + XICS_MFRR);
                        else
@@ -541,22 +491,13 @@ static long kvmppc_read_one_intr(bool *again)
 }
 
 #ifdef CONFIG_KVM_XICS
-static inline bool is_rm(void)
-{
-       return !(mfmsr() & MSR_DR);
-}
-
 unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu)
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_xirr(vcpu);
-               if (unlikely(!__xive_vm_h_xirr))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_xirr(vcpu);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_xirr(vcpu);
+       else
                return xics_rm_h_xirr(vcpu);
 }
 
@@ -565,13 +506,9 @@ unsigned long kvmppc_rm_h_xirr_x(struct kvm_vcpu *vcpu)
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
        vcpu->arch.regs.gpr[5] = get_tb();
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_xirr(vcpu);
-               if (unlikely(!__xive_vm_h_xirr))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_xirr(vcpu);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_xirr(vcpu);
+       else
                return xics_rm_h_xirr(vcpu);
 }
 
@@ -579,13 +516,9 @@ unsigned long kvmppc_rm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server)
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_ipoll(vcpu, server);
-               if (unlikely(!__xive_vm_h_ipoll))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_ipoll(vcpu, server);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_ipoll(vcpu, server);
+       else
                return H_TOO_HARD;
 }
 
@@ -594,13 +527,9 @@ int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_ipi(vcpu, server, mfrr);
-               if (unlikely(!__xive_vm_h_ipi))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_ipi(vcpu, server, mfrr);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_ipi(vcpu, server, mfrr);
+       else
                return xics_rm_h_ipi(vcpu, server, mfrr);
 }
 
@@ -608,13 +537,9 @@ int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_cppr(vcpu, cppr);
-               if (unlikely(!__xive_vm_h_cppr))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_cppr(vcpu, cppr);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_cppr(vcpu, cppr);
+       else
                return xics_rm_h_cppr(vcpu, cppr);
 }
 
@@ -622,13 +547,9 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       if (xics_on_xive()) {
-               if (is_rm())
-                       return xive_rm_h_eoi(vcpu, xirr);
-               if (unlikely(!__xive_vm_h_eoi))
-                       return H_NOT_AVAILABLE;
-               return __xive_vm_h_eoi(vcpu, xirr);
-       } else
+       if (xics_on_xive())
+               return xive_rm_h_eoi(vcpu, xirr);
+       else
                return xics_rm_h_eoi(vcpu, xirr);
 }
 #endif /* CONFIG_KVM_XICS */
@@ -800,7 +721,7 @@ void kvmppc_check_need_tlb_flush(struct kvm *kvm, int pcpu,
         * Thus we make all 4 threads use the same bit.
         */
        if (cpu_has_feature(CPU_FTR_ARCH_300))
-               pcpu = cpu_first_thread_sibling(pcpu);
+               pcpu = cpu_first_tlb_thread_sibling(pcpu);
 
        if (nested)
                need_tlb_flush = &nested->need_tlb_flush;
index 327417d..4444f83 100644 (file)
@@ -58,7 +58,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        /*
         * Put whatever is in the decrementer into the
         * hypervisor decrementer.
-        * Because of a hardware deviation in P8 and P9,
+        * Because of a hardware deviation in P8,
         * we need to set LPCR[HDICE] before writing HDEC.
         */
        ld      r5, HSTATE_KVM_VCORE(r13)
@@ -67,15 +67,10 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        ori     r8, r9, LPCR_HDICE
        mtspr   SPRN_LPCR, r8
        isync
-       andis.  r0, r9, LPCR_LD@h
        mfspr   r8,SPRN_DEC
        mftb    r7
-BEGIN_FTR_SECTION
-       /* On POWER9, don't sign-extend if host LPCR[LD] bit is set */
-       bne     32f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        extsw   r8,r8
-32:    mtspr   SPRN_HDEC,r8
+       mtspr   SPRN_HDEC,r8
        add     r8,r8,r7
        std     r8,HSTATE_DECEXP(r13)
 
index 60724f6..8543ad5 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pte-walk.h>
 #include <asm/reg.h>
+#include <asm/plpar_wrappers.h>
 
 static struct patb_entry *pseries_partition_tb;
 
@@ -53,7 +54,8 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr)
        hr->dawrx1 = vcpu->arch.dawrx1;
 }
 
-static void byteswap_pt_regs(struct pt_regs *regs)
+/* Use noinline_for_stack due to https://bugs.llvm.org/show_bug.cgi?id=49610 */
+static noinline_for_stack void byteswap_pt_regs(struct pt_regs *regs)
 {
        unsigned long *addr = (unsigned long *) regs;
 
@@ -467,8 +469,15 @@ static void kvmhv_flush_lpid(unsigned int lpid)
                return;
        }
 
-       rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(2, 0, 1),
-                               lpid, TLBIEL_INVAL_SET_LPID);
+       if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE))
+               rc = plpar_hcall_norets(H_TLB_INVALIDATE, H_TLBIE_P1_ENC(2, 0, 1),
+                                       lpid, TLBIEL_INVAL_SET_LPID);
+       else
+               rc = pseries_rpt_invalidate(lpid, H_RPTI_TARGET_CMMU,
+                                           H_RPTI_TYPE_NESTED |
+                                           H_RPTI_TYPE_TLB | H_RPTI_TYPE_PWC |
+                                           H_RPTI_TYPE_PAT,
+                                           H_RPTI_PAGE_ALL, 0, -1UL);
        if (rc)
                pr_err("KVM: TLB LPID invalidation hcall failed, rc=%ld\n", rc);
 }
@@ -1214,6 +1223,113 @@ long kvmhv_do_nested_tlbie(struct kvm_vcpu *vcpu)
        return H_SUCCESS;
 }
 
+static long do_tlb_invalidate_nested_all(struct kvm_vcpu *vcpu,
+                                        unsigned long lpid, unsigned long ric)
+{
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_nested_guest *gp;
+
+       gp = kvmhv_get_nested(kvm, lpid, false);
+       if (gp) {
+               kvmhv_emulate_tlbie_lpid(vcpu, gp, ric);
+               kvmhv_put_nested(gp);
+       }
+       return H_SUCCESS;
+}
+
+/*
+ * Number of pages above which we invalidate the entire LPID rather than
+ * flush individual pages.
+ */
+static unsigned long tlb_range_flush_page_ceiling __read_mostly = 33;
+
+static long do_tlb_invalidate_nested_tlb(struct kvm_vcpu *vcpu,
+                                        unsigned long lpid,
+                                        unsigned long pg_sizes,
+                                        unsigned long start,
+                                        unsigned long end)
+{
+       int ret = H_P4;
+       unsigned long addr, nr_pages;
+       struct mmu_psize_def *def;
+       unsigned long psize, ap, page_size;
+       bool flush_lpid;
+
+       for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
+               def = &mmu_psize_defs[psize];
+               if (!(pg_sizes & def->h_rpt_pgsize))
+                       continue;
+
+               nr_pages = (end - start) >> def->shift;
+               flush_lpid = nr_pages > tlb_range_flush_page_ceiling;
+               if (flush_lpid)
+                       return do_tlb_invalidate_nested_all(vcpu, lpid,
+                                                       RIC_FLUSH_TLB);
+               addr = start;
+               ap = mmu_get_ap(psize);
+               page_size = 1UL << def->shift;
+               do {
+                       ret = kvmhv_emulate_tlbie_tlb_addr(vcpu, lpid, ap,
+                                                  get_epn(addr));
+                       if (ret)
+                               return H_P4;
+                       addr += page_size;
+               } while (addr < end);
+       }
+       return ret;
+}
+
+/*
+ * Performs partition-scoped invalidations for nested guests
+ * as part of H_RPT_INVALIDATE hcall.
+ */
+long do_h_rpt_invalidate_pat(struct kvm_vcpu *vcpu, unsigned long lpid,
+                            unsigned long type, unsigned long pg_sizes,
+                            unsigned long start, unsigned long end)
+{
+       /*
+        * If L2 lpid isn't valid, we need to return H_PARAMETER.
+        *
+        * However, nested KVM issues a L2 lpid flush call when creating
+        * partition table entries for L2. This happens even before the
+        * corresponding shadow lpid is created in HV which happens in
+        * H_ENTER_NESTED call. Since we can't differentiate this case from
+        * the invalid case, we ignore such flush requests and return success.
+        */
+       if (!kvmhv_find_nested(vcpu->kvm, lpid))
+               return H_SUCCESS;
+
+       /*
+        * A flush all request can be handled by a full lpid flush only.
+        */
+       if ((type & H_RPTI_TYPE_NESTED_ALL) == H_RPTI_TYPE_NESTED_ALL)
+               return do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_ALL);
+
+       /*
+        * We don't need to handle a PWC flush like process table here,
+        * because intermediate partition scoped table in nested guest doesn't
+        * really have PWC. Only level we have PWC is in L0 and for nested
+        * invalidate at L0 we always do kvm_flush_lpid() which does
+        * radix__flush_all_lpid(). For range invalidate at any level, we
+        * are not removing the higher level page tables and hence there is
+        * no PWC invalidate needed.
+        *
+        * if (type & H_RPTI_TYPE_PWC) {
+        *      ret = do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_PWC);
+        *      if (ret)
+        *              return H_P4;
+        * }
+        */
+
+       if (start == 0 && end == -1)
+               return do_tlb_invalidate_nested_all(vcpu, lpid, RIC_FLUSH_TLB);
+
+       if (type & H_RPTI_TYPE_TLB)
+               return do_tlb_invalidate_nested_tlb(vcpu, lpid, pg_sizes,
+                                                   start, end);
+       return H_SUCCESS;
+}
+
 /* Used to convert a nested guest real address to a L1 guest real address */
 static int kvmhv_translate_addr_nested(struct kvm_vcpu *vcpu,
                                       struct kvm_nested_guest *gp,
diff --git a/arch/powerpc/kvm/book3s_hv_p9_entry.c b/arch/powerpc/kvm/book3s_hv_p9_entry.c
new file mode 100644 (file)
index 0000000..83f592e
--- /dev/null
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <asm/asm-prototypes.h>
+#include <asm/dbell.h>
+#include <asm/kvm_ppc.h>
+#include <asm/ppc-opcode.h>
+
+#ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
+static void __start_timing(struct kvm_vcpu *vcpu, struct kvmhv_tb_accumulator *next)
+{
+       struct kvmppc_vcore *vc = vcpu->arch.vcore;
+       u64 tb = mftb() - vc->tb_offset_applied;
+
+       vcpu->arch.cur_activity = next;
+       vcpu->arch.cur_tb_start = tb;
+}
+
+static void __accumulate_time(struct kvm_vcpu *vcpu, struct kvmhv_tb_accumulator *next)
+{
+       struct kvmppc_vcore *vc = vcpu->arch.vcore;
+       struct kvmhv_tb_accumulator *curr;
+       u64 tb = mftb() - vc->tb_offset_applied;
+       u64 prev_tb;
+       u64 delta;
+       u64 seq;
+
+       curr = vcpu->arch.cur_activity;
+       vcpu->arch.cur_activity = next;
+       prev_tb = vcpu->arch.cur_tb_start;
+       vcpu->arch.cur_tb_start = tb;
+
+       if (!curr)
+               return;
+
+       delta = tb - prev_tb;
+
+       seq = curr->seqcount;
+       curr->seqcount = seq + 1;
+       smp_wmb();
+       curr->tb_total += delta;
+       if (seq == 0 || delta < curr->tb_min)
+               curr->tb_min = delta;
+       if (delta > curr->tb_max)
+               curr->tb_max = delta;
+       smp_wmb();
+       curr->seqcount = seq + 2;
+}
+
+#define start_timing(vcpu, next) __start_timing(vcpu, next)
+#define end_timing(vcpu) __start_timing(vcpu, NULL)
+#define accumulate_time(vcpu, next) __accumulate_time(vcpu, next)
+#else
+#define start_timing(vcpu, next) do {} while (0)
+#define end_timing(vcpu) do {} while (0)
+#define accumulate_time(vcpu, next) do {} while (0)
+#endif
+
+static inline void mfslb(unsigned int idx, u64 *slbee, u64 *slbev)
+{
+       asm volatile("slbmfev  %0,%1" : "=r" (*slbev) : "r" (idx));
+       asm volatile("slbmfee  %0,%1" : "=r" (*slbee) : "r" (idx));
+}
+
+static inline void mtslb(u64 slbee, u64 slbev)
+{
+       asm volatile("slbmte %0,%1" :: "r" (slbev), "r" (slbee));
+}
+
+static inline void clear_slb_entry(unsigned int idx)
+{
+       mtslb(idx, 0);
+}
+
+static inline void slb_clear_invalidate_partition(void)
+{
+       clear_slb_entry(0);
+       asm volatile(PPC_SLBIA(6));
+}
+
+/*
+ * Malicious or buggy radix guests may have inserted SLB entries
+ * (only 0..3 because radix always runs with UPRT=1), so these must
+ * be cleared here to avoid side-channels. slbmte is used rather
+ * than slbia, as it won't clear cached translations.
+ */
+static void radix_clear_slb(void)
+{
+       int i;
+
+       for (i = 0; i < 4; i++)
+               clear_slb_entry(i);
+}
+
+static void switch_mmu_to_guest_radix(struct kvm *kvm, struct kvm_vcpu *vcpu, u64 lpcr)
+{
+       struct kvm_nested_guest *nested = vcpu->arch.nested;
+       u32 lpid;
+
+       lpid = nested ? nested->shadow_lpid : kvm->arch.lpid;
+
+       /*
+        * All the isync()s are overkill but trivially follow the ISA
+        * requirements. Some can likely be replaced with justification
+        * comment for why they are not needed.
+        */
+       isync();
+       mtspr(SPRN_LPID, lpid);
+       isync();
+       mtspr(SPRN_LPCR, lpcr);
+       isync();
+       mtspr(SPRN_PID, vcpu->arch.pid);
+       isync();
+}
+
+static void switch_mmu_to_guest_hpt(struct kvm *kvm, struct kvm_vcpu *vcpu, u64 lpcr)
+{
+       u32 lpid;
+       int i;
+
+       lpid = kvm->arch.lpid;
+
+       mtspr(SPRN_LPID, lpid);
+       mtspr(SPRN_LPCR, lpcr);
+       mtspr(SPRN_PID, vcpu->arch.pid);
+
+       for (i = 0; i < vcpu->arch.slb_max; i++)
+               mtslb(vcpu->arch.slb[i].orige, vcpu->arch.slb[i].origv);
+
+       isync();
+}
+
+static void switch_mmu_to_host(struct kvm *kvm, u32 pid)
+{
+       isync();
+       mtspr(SPRN_PID, pid);
+       isync();
+       mtspr(SPRN_LPID, kvm->arch.host_lpid);
+       isync();
+       mtspr(SPRN_LPCR, kvm->arch.host_lpcr);
+       isync();
+
+       if (!radix_enabled())
+               slb_restore_bolted_realmode();
+}
+
+static void save_clear_host_mmu(struct kvm *kvm)
+{
+       if (!radix_enabled()) {
+               /*
+                * Hash host could save and restore host SLB entries to
+                * reduce SLB fault overheads of VM exits, but for now the
+                * existing code clears all entries and restores just the
+                * bolted ones when switching back to host.
+                */
+               slb_clear_invalidate_partition();
+       }
+}
+
+static void save_clear_guest_mmu(struct kvm *kvm, struct kvm_vcpu *vcpu)
+{
+       if (kvm_is_radix(kvm)) {
+               radix_clear_slb();
+       } else {
+               int i;
+               int nr = 0;
+
+               /*
+                * This must run before switching to host (radix host can't
+                * access all SLBs).
+                */
+               for (i = 0; i < vcpu->arch.slb_nr; i++) {
+                       u64 slbee, slbev;
+                       mfslb(i, &slbee, &slbev);
+                       if (slbee & SLB_ESID_V) {
+                               vcpu->arch.slb[nr].orige = slbee | i;
+                               vcpu->arch.slb[nr].origv = slbev;
+                               nr++;
+                       }
+               }
+               vcpu->arch.slb_max = nr;
+               slb_clear_invalidate_partition();
+       }
+}
+
+int kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr)
+{
+       struct kvm *kvm = vcpu->kvm;
+       struct kvm_nested_guest *nested = vcpu->arch.nested;
+       struct kvmppc_vcore *vc = vcpu->arch.vcore;
+       s64 hdec;
+       u64 tb, purr, spurr;
+       u64 *exsave;
+       bool ri_set;
+       int trap;
+       unsigned long msr;
+       unsigned long host_hfscr;
+       unsigned long host_ciabr;
+       unsigned long host_dawr0;
+       unsigned long host_dawrx0;
+       unsigned long host_psscr;
+       unsigned long host_pidr;
+       unsigned long host_dawr1;
+       unsigned long host_dawrx1;
+
+       hdec = time_limit - mftb();
+       if (hdec < 0)
+               return BOOK3S_INTERRUPT_HV_DECREMENTER;
+
+       WARN_ON_ONCE(vcpu->arch.shregs.msr & MSR_HV);
+       WARN_ON_ONCE(!(vcpu->arch.shregs.msr & MSR_ME));
+
+       start_timing(vcpu, &vcpu->arch.rm_entry);
+
+       vcpu->arch.ceded = 0;
+
+       if (vc->tb_offset) {
+               u64 new_tb = mftb() + vc->tb_offset;
+               mtspr(SPRN_TBU40, new_tb);
+               tb = mftb();
+               if ((tb & 0xffffff) < (new_tb & 0xffffff))
+                       mtspr(SPRN_TBU40, new_tb + 0x1000000);
+               vc->tb_offset_applied = vc->tb_offset;
+       }
+
+       msr = mfmsr();
+
+       host_hfscr = mfspr(SPRN_HFSCR);
+       host_ciabr = mfspr(SPRN_CIABR);
+       host_dawr0 = mfspr(SPRN_DAWR0);
+       host_dawrx0 = mfspr(SPRN_DAWRX0);
+       host_psscr = mfspr(SPRN_PSSCR);
+       host_pidr = mfspr(SPRN_PID);
+       if (cpu_has_feature(CPU_FTR_DAWR1)) {
+               host_dawr1 = mfspr(SPRN_DAWR1);
+               host_dawrx1 = mfspr(SPRN_DAWRX1);
+       }
+
+       if (vc->pcr)
+               mtspr(SPRN_PCR, vc->pcr | PCR_MASK);
+       mtspr(SPRN_DPDES, vc->dpdes);
+       mtspr(SPRN_VTB, vc->vtb);
+
+       local_paca->kvm_hstate.host_purr = mfspr(SPRN_PURR);
+       local_paca->kvm_hstate.host_spurr = mfspr(SPRN_SPURR);
+       mtspr(SPRN_PURR, vcpu->arch.purr);
+       mtspr(SPRN_SPURR, vcpu->arch.spurr);
+
+       if (dawr_enabled()) {
+               mtspr(SPRN_DAWR0, vcpu->arch.dawr0);
+               mtspr(SPRN_DAWRX0, vcpu->arch.dawrx0);
+               if (cpu_has_feature(CPU_FTR_DAWR1)) {
+                       mtspr(SPRN_DAWR1, vcpu->arch.dawr1);
+                       mtspr(SPRN_DAWRX1, vcpu->arch.dawrx1);
+               }
+       }
+       mtspr(SPRN_CIABR, vcpu->arch.ciabr);
+       mtspr(SPRN_IC, vcpu->arch.ic);
+
+       mtspr(SPRN_PSSCR, vcpu->arch.psscr | PSSCR_EC |
+             (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
+
+       mtspr(SPRN_HFSCR, vcpu->arch.hfscr);
+
+       mtspr(SPRN_HSRR0, vcpu->arch.regs.nip);
+       mtspr(SPRN_HSRR1, (vcpu->arch.shregs.msr & ~MSR_HV) | MSR_ME);
+
+       /*
+        * On POWER9 DD2.1 and below, sometimes on a Hypervisor Data Storage
+        * Interrupt (HDSI) the HDSISR is not be updated at all.
+        *
+        * To work around this we put a canary value into the HDSISR before
+        * returning to a guest and then check for this canary when we take a
+        * HDSI. If we find the canary on a HDSI, we know the hardware didn't
+        * update the HDSISR. In this case we return to the guest to retake the
+        * HDSI which should correctly update the HDSISR the second time HDSI
+        * entry.
+        *
+        * Just do this on all p9 processors for now.
+        */
+       mtspr(SPRN_HDSISR, HDSISR_CANARY);
+
+       mtspr(SPRN_SPRG0, vcpu->arch.shregs.sprg0);
+       mtspr(SPRN_SPRG1, vcpu->arch.shregs.sprg1);
+       mtspr(SPRN_SPRG2, vcpu->arch.shregs.sprg2);
+       mtspr(SPRN_SPRG3, vcpu->arch.shregs.sprg3);
+
+       mtspr(SPRN_AMOR, ~0UL);
+
+       local_paca->kvm_hstate.in_guest = KVM_GUEST_MODE_HV_P9;
+
+       /*
+        * Hash host, hash guest, or radix guest with prefetch bug, all have
+        * to disable the MMU before switching to guest MMU state.
+        */
+       if (!radix_enabled() || !kvm_is_radix(kvm) ||
+                       cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
+               __mtmsrd(msr & ~(MSR_IR|MSR_DR|MSR_RI), 0);
+
+       save_clear_host_mmu(kvm);
+
+       if (kvm_is_radix(kvm)) {
+               switch_mmu_to_guest_radix(kvm, vcpu, lpcr);
+               if (!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
+                       __mtmsrd(0, 1); /* clear RI */
+
+       } else {
+               switch_mmu_to_guest_hpt(kvm, vcpu, lpcr);
+       }
+
+       /* TLBIEL uses LPID=LPIDR, so run this after setting guest LPID */
+       kvmppc_check_need_tlb_flush(kvm, vc->pcpu, nested);
+
+       /*
+        * P9 suppresses the HDEC exception when LPCR[HDICE] = 0,
+        * so set guest LPCR (with HDICE) before writing HDEC.
+        */
+       mtspr(SPRN_HDEC, hdec);
+
+       mtspr(SPRN_DAR, vcpu->arch.shregs.dar);
+       mtspr(SPRN_DSISR, vcpu->arch.shregs.dsisr);
+       mtspr(SPRN_SRR0, vcpu->arch.shregs.srr0);
+       mtspr(SPRN_SRR1, vcpu->arch.shregs.srr1);
+
+       accumulate_time(vcpu, &vcpu->arch.guest_time);
+
+       kvmppc_p9_enter_guest(vcpu);
+
+       accumulate_time(vcpu, &vcpu->arch.rm_intr);
+
+       /* XXX: Could get these from r11/12 and paca exsave instead */
+       vcpu->arch.shregs.srr0 = mfspr(SPRN_SRR0);
+       vcpu->arch.shregs.srr1 = mfspr(SPRN_SRR1);
+       vcpu->arch.shregs.dar = mfspr(SPRN_DAR);
+       vcpu->arch.shregs.dsisr = mfspr(SPRN_DSISR);
+
+       /* 0x2 bit for HSRR is only used by PR and P7/8 HV paths, clear it */
+       trap = local_paca->kvm_hstate.scratch0 & ~0x2;
+
+       /* HSRR interrupts leave MSR[RI] unchanged, SRR interrupts clear it. */
+       ri_set = false;
+       if (likely(trap > BOOK3S_INTERRUPT_MACHINE_CHECK)) {
+               if (trap != BOOK3S_INTERRUPT_SYSCALL &&
+                               (vcpu->arch.shregs.msr & MSR_RI))
+                       ri_set = true;
+               exsave = local_paca->exgen;
+       } else if (trap == BOOK3S_INTERRUPT_SYSTEM_RESET) {
+               exsave = local_paca->exnmi;
+       } else { /* trap == 0x200 */
+               exsave = local_paca->exmc;
+       }
+
+       vcpu->arch.regs.gpr[1] = local_paca->kvm_hstate.scratch1;
+       vcpu->arch.regs.gpr[3] = local_paca->kvm_hstate.scratch2;
+
+       /*
+        * Only set RI after reading machine check regs (DAR, DSISR, SRR0/1)
+        * and hstate scratch (which we need to move into exsave to make
+        * re-entrant vs SRESET/MCE)
+        */
+       if (ri_set) {
+               if (unlikely(!(mfmsr() & MSR_RI))) {
+                       __mtmsrd(MSR_RI, 1);
+                       WARN_ON_ONCE(1);
+               }
+       } else {
+               WARN_ON_ONCE(mfmsr() & MSR_RI);
+               __mtmsrd(MSR_RI, 1);
+       }
+
+       vcpu->arch.regs.gpr[9] = exsave[EX_R9/sizeof(u64)];
+       vcpu->arch.regs.gpr[10] = exsave[EX_R10/sizeof(u64)];
+       vcpu->arch.regs.gpr[11] = exsave[EX_R11/sizeof(u64)];
+       vcpu->arch.regs.gpr[12] = exsave[EX_R12/sizeof(u64)];
+       vcpu->arch.regs.gpr[13] = exsave[EX_R13/sizeof(u64)];
+       vcpu->arch.ppr = exsave[EX_PPR/sizeof(u64)];
+       vcpu->arch.cfar = exsave[EX_CFAR/sizeof(u64)];
+       vcpu->arch.regs.ctr = exsave[EX_CTR/sizeof(u64)];
+
+       vcpu->arch.last_inst = KVM_INST_FETCH_FAILED;
+
+       if (unlikely(trap == BOOK3S_INTERRUPT_MACHINE_CHECK)) {
+               vcpu->arch.fault_dar = exsave[EX_DAR/sizeof(u64)];
+               vcpu->arch.fault_dsisr = exsave[EX_DSISR/sizeof(u64)];
+               kvmppc_realmode_machine_check(vcpu);
+
+       } else if (unlikely(trap == BOOK3S_INTERRUPT_HMI)) {
+               kvmppc_realmode_hmi_handler();
+
+       } else if (trap == BOOK3S_INTERRUPT_H_EMUL_ASSIST) {
+               vcpu->arch.emul_inst = mfspr(SPRN_HEIR);
+
+       } else if (trap == BOOK3S_INTERRUPT_H_DATA_STORAGE) {
+               vcpu->arch.fault_dar = exsave[EX_DAR/sizeof(u64)];
+               vcpu->arch.fault_dsisr = exsave[EX_DSISR/sizeof(u64)];
+               vcpu->arch.fault_gpa = mfspr(SPRN_ASDR);
+
+       } else if (trap == BOOK3S_INTERRUPT_H_INST_STORAGE) {
+               vcpu->arch.fault_gpa = mfspr(SPRN_ASDR);
+
+       } else if (trap == BOOK3S_INTERRUPT_H_FAC_UNAVAIL) {
+               vcpu->arch.hfscr = mfspr(SPRN_HFSCR);
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /*
+        * Softpatch interrupt for transactional memory emulation cases
+        * on POWER9 DD2.2.  This is early in the guest exit path - we
+        * haven't saved registers or done a treclaim yet.
+        */
+       } else if (trap == BOOK3S_INTERRUPT_HV_SOFTPATCH) {
+               vcpu->arch.emul_inst = mfspr(SPRN_HEIR);
+
+               /*
+                * The cases we want to handle here are those where the guest
+                * is in real suspend mode and is trying to transition to
+                * transactional mode.
+                */
+               if (local_paca->kvm_hstate.fake_suspend &&
+                               (vcpu->arch.shregs.msr & MSR_TS_S)) {
+                       if (kvmhv_p9_tm_emulation_early(vcpu)) {
+                               /* Prevent it being handled again. */
+                               trap = 0;
+                       }
+               }
+#endif
+       }
+
+       accumulate_time(vcpu, &vcpu->arch.rm_exit);
+
+       /* Advance host PURR/SPURR by the amount used by guest */
+       purr = mfspr(SPRN_PURR);
+       spurr = mfspr(SPRN_SPURR);
+       mtspr(SPRN_PURR, local_paca->kvm_hstate.host_purr +
+             purr - vcpu->arch.purr);
+       mtspr(SPRN_SPURR, local_paca->kvm_hstate.host_spurr +
+             spurr - vcpu->arch.spurr);
+       vcpu->arch.purr = purr;
+       vcpu->arch.spurr = spurr;
+
+       vcpu->arch.ic = mfspr(SPRN_IC);
+       vcpu->arch.pid = mfspr(SPRN_PID);
+       vcpu->arch.psscr = mfspr(SPRN_PSSCR) & PSSCR_GUEST_VIS;
+
+       vcpu->arch.shregs.sprg0 = mfspr(SPRN_SPRG0);
+       vcpu->arch.shregs.sprg1 = mfspr(SPRN_SPRG1);
+       vcpu->arch.shregs.sprg2 = mfspr(SPRN_SPRG2);
+       vcpu->arch.shregs.sprg3 = mfspr(SPRN_SPRG3);
+
+       /* Preserve PSSCR[FAKE_SUSPEND] until we've called kvmppc_save_tm_hv */
+       mtspr(SPRN_PSSCR, host_psscr |
+             (local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
+       mtspr(SPRN_HFSCR, host_hfscr);
+       mtspr(SPRN_CIABR, host_ciabr);
+       mtspr(SPRN_DAWR0, host_dawr0);
+       mtspr(SPRN_DAWRX0, host_dawrx0);
+       if (cpu_has_feature(CPU_FTR_DAWR1)) {
+               mtspr(SPRN_DAWR1, host_dawr1);
+               mtspr(SPRN_DAWRX1, host_dawrx1);
+       }
+
+       if (kvm_is_radix(kvm)) {
+               /*
+                * Since this is radix, do a eieio; tlbsync; ptesync sequence
+                * in case we interrupted the guest between a tlbie and a
+                * ptesync.
+                */
+               asm volatile("eieio; tlbsync; ptesync");
+       }
+
+       /*
+        * cp_abort is required if the processor supports local copy-paste
+        * to clear the copy buffer that was under control of the guest.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_31))
+               asm volatile(PPC_CP_ABORT);
+
+       vc->dpdes = mfspr(SPRN_DPDES);
+       vc->vtb = mfspr(SPRN_VTB);
+       mtspr(SPRN_DPDES, 0);
+       if (vc->pcr)
+               mtspr(SPRN_PCR, PCR_MASK);
+
+       if (vc->tb_offset_applied) {
+               u64 new_tb = mftb() - vc->tb_offset_applied;
+               mtspr(SPRN_TBU40, new_tb);
+               tb = mftb();
+               if ((tb & 0xffffff) < (new_tb & 0xffffff))
+                       mtspr(SPRN_TBU40, new_tb + 0x1000000);
+               vc->tb_offset_applied = 0;
+       }
+
+       mtspr(SPRN_HDEC, 0x7fffffff);
+
+       save_clear_guest_mmu(kvm, vcpu);
+       switch_mmu_to_host(kvm, host_pidr);
+       local_paca->kvm_hstate.in_guest = KVM_GUEST_MODE_NONE;
+
+       /*
+        * If we are in real mode, only switch MMU on after the MMU is
+        * switched to host, to avoid the P9_RADIX_PREFETCH_BUG.
+        */
+       __mtmsrd(msr, 0);
+
+       end_timing(vcpu);
+
+       return trap;
+}
+EXPORT_SYMBOL_GPL(kvmhv_vcpu_entry_p9);
index 7a0f124..632b254 100644 (file)
@@ -46,6 +46,10 @@ static int global_invalidates(struct kvm *kvm)
        else
                global = 1;
 
+       /* LPID has been switched to host if in virt mode so can't do local */
+       if (!global && (mfmsr() & (MSR_IR|MSR_DR)))
+               global = 1;
+
        if (!global) {
                /* any other core might now have stale TLB entries... */
                smp_wmb();
@@ -56,7 +60,7 @@ static int global_invalidates(struct kvm *kvm)
                 * so use the bit for the first thread to represent the core.
                 */
                if (cpu_has_feature(CPU_FTR_ARCH_300))
-                       cpu = cpu_first_thread_sibling(cpu);
+                       cpu = cpu_first_tlb_thread_sibling(cpu);
                cpumask_clear_cpu(cpu, &kvm->arch.need_tlb_flush);
        }
 
@@ -398,6 +402,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                                 vcpu->arch.pgdir, true,
                                 &vcpu->arch.regs.gpr[4]);
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_enter);
 
 #ifdef __BIG_ENDIAN__
 #define LOCK_TOKEN     (*(u32 *)(&get_paca()->lock_token))
@@ -542,6 +547,7 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
        return kvmppc_do_h_remove(vcpu->kvm, flags, pte_index, avpn,
                                  &vcpu->arch.regs.gpr[4]);
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_remove);
 
 long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
@@ -660,6 +666,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_bulk_remove);
 
 long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
                      unsigned long pte_index, unsigned long avpn)
@@ -730,6 +737,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
 
        return H_SUCCESS;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_protect);
 
 long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
                   unsigned long pte_index)
@@ -770,6 +778,7 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
        }
        return H_SUCCESS;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_read);
 
 long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags,
                        unsigned long pte_index)
@@ -818,6 +827,7 @@ long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags,
        unlock_hpte(hpte, v & ~HPTE_V_HVLOCK);
        return ret;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_clear_ref);
 
 long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
                        unsigned long pte_index)
@@ -865,6 +875,7 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
        unlock_hpte(hpte, v & ~HPTE_V_HVLOCK);
        return ret;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_clear_mod);
 
 static int kvmppc_get_hpa(struct kvm_vcpu *vcpu, unsigned long mmu_seq,
                          unsigned long gpa, int writing, unsigned long *hpa,
@@ -1283,3 +1294,4 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
 
        return -1;              /* send fault up to host kernel mode */
 }
+EXPORT_SYMBOL_GPL(kvmppc_hpte_hv_fault);
index c2c9c73..0a11ec8 100644 (file)
@@ -141,13 +141,6 @@ static void icp_rm_set_vcpu_irq(struct kvm_vcpu *vcpu,
                return;
        }
 
-       if (xive_enabled() && kvmhv_on_pseries()) {
-               /* No XICS access or hypercalls available, too hard */
-               this_icp->rm_action |= XICS_RM_KICK_VCPU;
-               this_icp->rm_kick_target = vcpu;
-               return;
-       }
-
        /*
         * Check if the core is loaded,
         * if not, find an available host core to post to wake the VCPU,
@@ -771,14 +764,6 @@ static void icp_eoi(struct irq_chip *c, u32 hwirq, __be32 xirr, bool *again)
        void __iomem *xics_phys;
        int64_t rc;
 
-       if (kvmhv_on_pseries()) {
-               unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
-               iosync();
-               plpar_hcall_raw(H_EOI, retbuf, hwirq);
-               return;
-       }
-
        rc = pnv_opal_pci_msi_eoi(c, hwirq);
 
        if (rc)
index 004f0d4..8dd437d 100644 (file)
 #include <asm/export.h>
 #include <asm/tm.h>
 #include <asm/opal.h>
-#include <asm/xive-regs.h>
 #include <asm/thread_info.h>
 #include <asm/asm-compat.h>
 #include <asm/feature-fixups.h>
 #include <asm/cpuidle.h>
-#include <asm/ultravisor-api.h>
-
-/* Sign-extend HDEC if not on POWER9 */
-#define EXTEND_HDEC(reg)                       \
-BEGIN_FTR_SECTION;                             \
-       extsw   reg, reg;                       \
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 
 /* Values in HSTATE_NAPPING(r13) */
 #define NAPPING_CEDE   1
@@ -44,9 +36,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 #define NAPPING_UNSPLIT        3
 
 /* Stack frame offsets for kvmppc_hv_entry */
-#define SFS                    208
+#define SFS                    160
 #define STACK_SLOT_TRAP                (SFS-4)
-#define STACK_SLOT_SHORT_PATH  (SFS-8)
 #define STACK_SLOT_TID         (SFS-16)
 #define STACK_SLOT_PSSCR       (SFS-24)
 #define STACK_SLOT_PID         (SFS-32)
@@ -57,11 +48,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 #define STACK_SLOT_HFSCR       (SFS-72)
 #define STACK_SLOT_AMR         (SFS-80)
 #define STACK_SLOT_UAMOR       (SFS-88)
-#define STACK_SLOT_DAWR1       (SFS-96)
-#define STACK_SLOT_DAWRX1      (SFS-104)
-#define STACK_SLOT_FSCR                (SFS-112)
-/* the following is used by the P9 short path */
-#define STACK_SLOT_NVGPRS      (SFS-152)       /* 18 gprs */
+#define STACK_SLOT_FSCR                (SFS-96)
 
 /*
  * Call kvmppc_hv_entry in real mode.
@@ -137,15 +124,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        /* Return the trap number on this thread as the return value */
        mr      r3, r12
 
-       /*
-        * If we came back from the guest via a relocation-on interrupt,
-        * we will be in virtual mode at this point, which makes it a
-        * little easier to get back to the caller.
-        */
-       mfmsr   r0
-       andi.   r0, r0, MSR_IR          /* in real mode? */
-       bne     .Lvirt_return
-
        /* RFI into the highmem handler */
        mfmsr   r6
        li      r0, MSR_RI
@@ -155,11 +133,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        mtsrr1  r7
        RFI_TO_KERNEL
 
-       /* Virtual-mode return */
-.Lvirt_return:
-       mtlr    r8
-       blr
-
 kvmppc_primary_no_guest:
        /* We handle this much like a ceded vcpu */
        /* put the HDEC into the DEC, since HDEC interrupts don't wake us */
@@ -246,7 +219,7 @@ kvm_novcpu_wakeup:
 
        /* See if our timeslice has expired (HDEC is negative) */
        mfspr   r0, SPRN_HDEC
-       EXTEND_HDEC(r0)
+       extsw   r0, r0
        li      r12, BOOK3S_INTERRUPT_HV_DECREMENTER
        cmpdi   r0, 0
        blt     kvm_novcpu_exit
@@ -348,10 +321,8 @@ kvm_secondary_got_guest:
        lbz     r4, HSTATE_PTID(r13)
        cmpwi   r4, 0
        bne     63f
-       LOAD_REG_ADDR(r6, decrementer_max)
-       ld      r6, 0(r6)
+       lis     r6,0x7fff               /* MAX_INT@h */
        mtspr   SPRN_HDEC, r6
-BEGIN_FTR_SECTION
        /* and set per-LPAR registers, if doing dynamic micro-threading */
        ld      r6, HSTATE_SPLIT_MODE(r13)
        cmpdi   r6, 0
@@ -363,7 +334,6 @@ BEGIN_FTR_SECTION
        ld      r0, KVM_SPLIT_LDBAR(r6)
        mtspr   SPRN_LDBAR, r0
        isync
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 63:
        /* Order load of vcpu after load of vcore */
        lwsync
@@ -434,7 +404,6 @@ kvm_no_guest:
        blr
 
 53:
-BEGIN_FTR_SECTION
        HMT_LOW
        ld      r5, HSTATE_KVM_VCORE(r13)
        cmpdi   r5, 0
@@ -449,14 +418,6 @@ BEGIN_FTR_SECTION
        b       kvm_unsplit_nap
 60:    HMT_MEDIUM
        b       kvm_secondary_got_guest
-FTR_SECTION_ELSE
-       HMT_LOW
-       ld      r5, HSTATE_KVM_VCORE(r13)
-       cmpdi   r5, 0
-       beq     kvm_no_guest
-       HMT_MEDIUM
-       b       kvm_secondary_got_guest
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
 
 54:    li      r0, KVM_HWTHREAD_IN_KVM
        stb     r0, HSTATE_HWTHREAD_STATE(r13)
@@ -582,13 +543,11 @@ kvmppc_hv_entry:
        bne     10f
 
        lwz     r7,KVM_LPID(r9)
-BEGIN_FTR_SECTION
        ld      r6,KVM_SDR1(r9)
        li      r0,LPID_RSVD            /* switch to reserved LPID */
        mtspr   SPRN_LPID,r0
        ptesync
        mtspr   SPRN_SDR1,r6            /* switch to partition page table */
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPID,r7
        isync
 
@@ -669,16 +628,6 @@ kvmppc_got_guest:
 
        /* Save host values of some registers */
 BEGIN_FTR_SECTION
-       mfspr   r5, SPRN_TIDR
-       mfspr   r6, SPRN_PSSCR
-       mfspr   r7, SPRN_PID
-       std     r5, STACK_SLOT_TID(r1)
-       std     r6, STACK_SLOT_PSSCR(r1)
-       std     r7, STACK_SLOT_PID(r1)
-       mfspr   r5, SPRN_HFSCR
-       std     r5, STACK_SLOT_HFSCR(r1)
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
-BEGIN_FTR_SECTION
        mfspr   r5, SPRN_CIABR
        mfspr   r6, SPRN_DAWR0
        mfspr   r7, SPRN_DAWRX0
@@ -690,12 +639,6 @@ BEGIN_FTR_SECTION
        mfspr   r5, SPRN_FSCR
        std     r5, STACK_SLOT_FSCR(r1)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
-BEGIN_FTR_SECTION
-       mfspr   r6, SPRN_DAWR1
-       mfspr   r7, SPRN_DAWRX1
-       std     r6, STACK_SLOT_DAWR1(r1)
-       std     r7, STACK_SLOT_DAWRX1(r1)
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S | CPU_FTR_DAWR1)
 
        mfspr   r5, SPRN_AMR
        std     r5, STACK_SLOT_AMR(r1)
@@ -713,13 +656,9 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/*
- * Branch around the call if both CPU_FTR_TM and
- * CPU_FTR_P9_TM_HV_ASSIST are off.
- */
 BEGIN_FTR_SECTION
        b       91f
-END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR)
         */
@@ -786,12 +725,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        ld      r6, VCPU_DAWRX0(r4)
        mtspr   SPRN_DAWR0, r5
        mtspr   SPRN_DAWRX0, r6
-BEGIN_FTR_SECTION
-       ld      r5, VCPU_DAWR1(r4)
-       ld      r6, VCPU_DAWRX1(r4)
-       mtspr   SPRN_DAWR1, r5
-       mtspr   SPRN_DAWRX1, r6
-END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
 1:
        ld      r7, VCPU_CIABR(r4)
        ld      r8, VCPU_TAR(r4)
@@ -809,7 +742,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
        mtspr   SPRN_BESCR, r6
        mtspr   SPRN_PID, r7
        mtspr   SPRN_WORT, r8
-BEGIN_FTR_SECTION
        /* POWER8-only registers */
        ld      r5, VCPU_TCSCR(r4)
        ld      r6, VCPU_ACOP(r4)
@@ -820,18 +752,6 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_CSIGR, r7
        mtspr   SPRN_TACR, r8
        nop
-FTR_SECTION_ELSE
-       /* POWER9-only registers */
-       ld      r5, VCPU_TID(r4)
-       ld      r6, VCPU_PSSCR(r4)
-       lbz     r8, HSTATE_FAKE_SUSPEND(r13)
-       oris    r6, r6, PSSCR_EC@h      /* This makes stop trap to HV */
-       rldimi  r6, r8, PSSCR_FAKE_SUSPEND_LG, 63 - PSSCR_FAKE_SUSPEND_LG
-       ld      r7, VCPU_HFSCR(r4)
-       mtspr   SPRN_TIDR, r5
-       mtspr   SPRN_PSSCR, r6
-       mtspr   SPRN_HFSCR, r7
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
 8:
 
        ld      r5, VCPU_SPRG0(r4)
@@ -901,23 +821,15 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
 
        /* Check if HDEC expires soon */
        mfspr   r3, SPRN_HDEC
-       EXTEND_HDEC(r3)
+       extsw   r3, r3
        cmpdi   r3, 512         /* 1 microsecond */
        blt     hdec_soon
 
-       ld      r6, VCPU_KVM(r4)
-       lbz     r0, KVM_RADIX(r6)
-       cmpwi   r0, 0
-       bne     9f
-
-       /* For hash guest, clear out and reload the SLB */
-BEGIN_MMU_FTR_SECTION
-       /* Radix host won't have populated the SLB, so no need to clear */
+       /* Clear out and reload the SLB */
        li      r6, 0
        slbmte  r6, r6
        PPC_SLBIA(6)
        ptesync
-END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
 
        /* Load up guest SLB entries (N.B. slb_max will be 0 for radix) */
        lwz     r5,VCPU_SLB_MAX(r4)
@@ -932,96 +844,9 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
        bdnz    1b
 9:
 
-#ifdef CONFIG_KVM_XICS
-       /* We are entering the guest on that thread, push VCPU to XIVE */
-       ld      r11, VCPU_XIVE_SAVED_STATE(r4)
-       li      r9, TM_QW1_OS
-       lwz     r8, VCPU_XIVE_CAM_WORD(r4)
-       cmpwi   r8, 0
-       beq     no_xive
-       li      r7, TM_QW1_OS + TM_WORD2
-       mfmsr   r0
-       andi.   r0, r0, MSR_DR          /* in real mode? */
-       beq     2f
-       ld      r10, HSTATE_XIVE_TIMA_VIRT(r13)
-       cmpldi  cr1, r10, 0
-       beq     cr1, no_xive
-       eieio
-       stdx    r11,r9,r10
-       stwx    r8,r7,r10
-       b       3f
-2:     ld      r10, HSTATE_XIVE_TIMA_PHYS(r13)
-       cmpldi  cr1, r10, 0
-       beq     cr1, no_xive
-       eieio
-       stdcix  r11,r9,r10
-       stwcix  r8,r7,r10
-3:     li      r9, 1
-       stb     r9, VCPU_XIVE_PUSHED(r4)
-       eieio
-
-       /*
-        * We clear the irq_pending flag. There is a small chance of a
-        * race vs. the escalation interrupt happening on another
-        * processor setting it again, but the only consequence is to
-        * cause a spurrious wakeup on the next H_CEDE which is not an
-        * issue.
-        */
-       li      r0,0
-       stb     r0, VCPU_IRQ_PENDING(r4)
-
-       /*
-        * In single escalation mode, if the escalation interrupt is
-        * on, we mask it.
-        */
-       lbz     r0, VCPU_XIVE_ESC_ON(r4)
-       cmpwi   cr1, r0,0
-       beq     cr1, 1f
-       li      r9, XIVE_ESB_SET_PQ_01
-       beq     4f                      /* in real mode? */
-       ld      r10, VCPU_XIVE_ESC_VADDR(r4)
-       ldx     r0, r10, r9
-       b       5f
-4:     ld      r10, VCPU_XIVE_ESC_RADDR(r4)
-       ldcix   r0, r10, r9
-5:     sync
-
-       /* We have a possible subtle race here: The escalation interrupt might
-        * have fired and be on its way to the host queue while we mask it,
-        * and if we unmask it early enough (re-cede right away), there is
-        * a theorical possibility that it fires again, thus landing in the
-        * target queue more than once which is a big no-no.
-        *
-        * Fortunately, solving this is rather easy. If the above load setting
-        * PQ to 01 returns a previous value where P is set, then we know the
-        * escalation interrupt is somewhere on its way to the host. In that
-        * case we simply don't clear the xive_esc_on flag below. It will be
-        * eventually cleared by the handler for the escalation interrupt.
-        *
-        * Then, when doing a cede, we check that flag again before re-enabling
-        * the escalation interrupt, and if set, we abort the cede.
-        */
-       andi.   r0, r0, XIVE_ESB_VAL_P
-       bne-    1f
-
-       /* Now P is 0, we can clear the flag */
-       li      r0, 0
-       stb     r0, VCPU_XIVE_ESC_ON(r4)
-1:
-no_xive:
-#endif /* CONFIG_KVM_XICS */
-
-       li      r0, 0
-       stw     r0, STACK_SLOT_SHORT_PATH(r1)
-
 deliver_guest_interrupt:       /* r4 = vcpu, r13 = paca */
        /* Check if we can deliver an external or decrementer interrupt now */
        ld      r0, VCPU_PENDING_EXC(r4)
-BEGIN_FTR_SECTION
-       /* On POWER9, also check for emulated doorbell interrupt */
-       lbz     r3, VCPU_DBELL_REQ(r4)
-       or      r0, r0, r3
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        cmpdi   r0, 0
        beq     71f
        mr      r3, r4
@@ -1033,7 +858,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        mtspr   SPRN_SRR0, r6
        mtspr   SPRN_SRR1, r7
 
-fast_guest_entry_c:
        ld      r10, VCPU_PC(r4)
        ld      r11, VCPU_MSR(r4)
        /* r11 = vcpu->arch.msr & ~MSR_HV */
@@ -1095,18 +919,8 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_PPR, r0
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
 
-/* Move canary into DSISR to check for later */
-BEGIN_FTR_SECTION
-       li      r0, 0x7fff
-       mtspr   SPRN_HDSISR, r0
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
-
-       ld      r6, VCPU_KVM(r4)
-       lbz     r7, KVM_SECURE_GUEST(r6)
-       cmpdi   r7, 0
        ld      r6, VCPU_GPR(R6)(r4)
        ld      r7, VCPU_GPR(R7)(r4)
-       bne     ret_to_ultra
 
        ld      r0, VCPU_CR(r4)
        mtcr    r0
@@ -1117,117 +931,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        ld      r4, VCPU_GPR(R4)(r4)
        HRFI_TO_GUEST
        b       .
-/*
- * Use UV_RETURN ultracall to return control back to the Ultravisor after
- * processing an hypercall or interrupt that was forwarded (a.k.a. reflected)
- * to the Hypervisor.
- *
- * All registers have already been loaded, except:
- *   R0 = hcall result
- *   R2 = SRR1, so UV can detect a synthesized interrupt (if any)
- *   R3 = UV_RETURN
- */
-ret_to_ultra:
-       ld      r0, VCPU_CR(r4)
-       mtcr    r0
-
-       ld      r0, VCPU_GPR(R3)(r4)
-       mfspr   r2, SPRN_SRR1
-       li      r3, 0
-       ori     r3, r3, UV_RETURN
-       ld      r4, VCPU_GPR(R4)(r4)
-       sc      2
-
-/*
- * Enter the guest on a P9 or later system where we have exactly
- * one vcpu per vcore and we don't need to go to real mode
- * (which implies that host and guest are both using radix MMU mode).
- * r3 = vcpu pointer
- * Most SPRs and all the VSRs have been loaded already.
- */
-_GLOBAL(__kvmhv_vcpu_entry_p9)
-EXPORT_SYMBOL_GPL(__kvmhv_vcpu_entry_p9)
-       mflr    r0
-       std     r0, PPC_LR_STKOFF(r1)
-       stdu    r1, -SFS(r1)
-
-       li      r0, 1
-       stw     r0, STACK_SLOT_SHORT_PATH(r1)
-
-       std     r3, HSTATE_KVM_VCPU(r13)
-       mfcr    r4
-       stw     r4, SFS+8(r1)
-
-       std     r1, HSTATE_HOST_R1(r13)
-
-       reg = 14
-       .rept   18
-       std     reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
-       reg = reg + 1
-       .endr
-
-       reg = 14
-       .rept   18
-       ld      reg, __VCPU_GPR(reg)(r3)
-       reg = reg + 1
-       .endr
-
-       mfmsr   r10
-       std     r10, HSTATE_HOST_MSR(r13)
-
-       mr      r4, r3
-       b       fast_guest_entry_c
-guest_exit_short_path:
-       /*
-        * Malicious or buggy radix guests may have inserted SLB entries
-        * (only 0..3 because radix always runs with UPRT=1), so these must
-        * be cleared here to avoid side-channels. slbmte is used rather
-        * than slbia, as it won't clear cached translations.
-        */
-       li      r0,0
-       slbmte  r0,r0
-       li      r4,1
-       slbmte  r0,r4
-       li      r4,2
-       slbmte  r0,r4
-       li      r4,3
-       slbmte  r0,r4
-
-       li      r0, KVM_GUEST_MODE_NONE
-       stb     r0, HSTATE_IN_GUEST(r13)
-
-       reg = 14
-       .rept   18
-       std     reg, __VCPU_GPR(reg)(r9)
-       reg = reg + 1
-       .endr
-
-       reg = 14
-       .rept   18
-       ld      reg, STACK_SLOT_NVGPRS + ((reg - 14) * 8)(r1)
-       reg = reg + 1
-       .endr
-
-       lwz     r4, SFS+8(r1)
-       mtcr    r4
-
-       mr      r3, r12         /* trap number */
-
-       addi    r1, r1, SFS
-       ld      r0, PPC_LR_STKOFF(r1)
-       mtlr    r0
-
-       /* If we are in real mode, do a rfid to get back to the caller */
-       mfmsr   r4
-       andi.   r5, r4, MSR_IR
-       bnelr
-       rldicl  r5, r4, 64 - MSR_TS_S_LG, 62    /* extract TS field */
-       mtspr   SPRN_SRR0, r0
-       ld      r10, HSTATE_HOST_MSR(r13)
-       rldimi  r10, r5, MSR_TS_S_LG, 63 - MSR_TS_T_LG
-       mtspr   SPRN_SRR1, r10
-       RFI_TO_KERNEL
-       b       .
 
 secondary_too_late:
        li      r12, 0
@@ -1268,21 +971,16 @@ hdec_soon:
 kvmppc_interrupt_hv:
        /*
         * Register contents:
+        * R9           = HSTATE_IN_GUEST
         * R12          = (guest CR << 32) | interrupt vector
         * R13          = PACA
         * guest R12 saved in shadow VCPU SCRATCH0
         * guest R13 saved in SPRN_SCRATCH0
+        * guest R9 saved in HSTATE_SCRATCH2
         */
-       std     r9, HSTATE_SCRATCH2(r13)
-       lbz     r9, HSTATE_IN_GUEST(r13)
-       cmpwi   r9, KVM_GUEST_MODE_HOST_HV
-       beq     kvmppc_bad_host_intr
-#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
-       cmpwi   r9, KVM_GUEST_MODE_GUEST
-       ld      r9, HSTATE_SCRATCH2(r13)
-       beq     kvmppc_interrupt_pr
-#endif
        /* We're now back in the host but in guest MMU context */
+       cmpwi   r9,KVM_GUEST_MODE_HOST_HV
+       beq     kvmppc_bad_host_intr
        li      r9, KVM_GUEST_MODE_HOST_HV
        stb     r9, HSTATE_IN_GUEST(r13)
 
@@ -1400,7 +1098,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        cmpwi   r12,BOOK3S_INTERRUPT_HV_DECREMENTER
        bne     2f
        mfspr   r3,SPRN_HDEC
-       EXTEND_HDEC(r3)
+       extsw   r3, r3
        cmpdi   r3,0
        mr      r4,r9
        bge     fast_guest_return
@@ -1412,14 +1110,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        /* Hypervisor doorbell - exit only if host IPI flag set */
        cmpwi   r12, BOOK3S_INTERRUPT_H_DOORBELL
        bne     3f
-BEGIN_FTR_SECTION
-       PPC_MSGSYNC
-       lwsync
-       /* always exit if we're running a nested guest */
-       ld      r0, VCPU_NESTED(r9)
-       cmpdi   r0, 0
-       bne     guest_exit_cont
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        lbz     r0, HSTATE_HOST_IPI(r13)
        cmpwi   r0, 0
        beq     maybe_reenter_guest
@@ -1449,62 +1139,16 @@ guest_exit_cont:                /* r9 = vcpu, r12 = trap, r13 = paca */
        mr      r4, r9
        bl      kvmhv_accumulate_time
 #endif
-#ifdef CONFIG_KVM_XICS
-       /* We are exiting, pull the VP from the XIVE */
-       lbz     r0, VCPU_XIVE_PUSHED(r9)
-       cmpwi   cr0, r0, 0
-       beq     1f
-       li      r7, TM_SPC_PULL_OS_CTX
-       li      r6, TM_QW1_OS
-       mfmsr   r0
-       andi.   r0, r0, MSR_DR          /* in real mode? */
-       beq     2f
-       ld      r10, HSTATE_XIVE_TIMA_VIRT(r13)
-       cmpldi  cr0, r10, 0
-       beq     1f
-       /* First load to pull the context, we ignore the value */
-       eieio
-       lwzx    r11, r7, r10
-       /* Second load to recover the context state (Words 0 and 1) */
-       ldx     r11, r6, r10
-       b       3f
-2:     ld      r10, HSTATE_XIVE_TIMA_PHYS(r13)
-       cmpldi  cr0, r10, 0
-       beq     1f
-       /* First load to pull the context, we ignore the value */
-       eieio
-       lwzcix  r11, r7, r10
-       /* Second load to recover the context state (Words 0 and 1) */
-       ldcix   r11, r6, r10
-3:     std     r11, VCPU_XIVE_SAVED_STATE(r9)
-       /* Fixup some of the state for the next load */
-       li      r10, 0
-       li      r0, 0xff
-       stb     r10, VCPU_XIVE_PUSHED(r9)
-       stb     r10, (VCPU_XIVE_SAVED_STATE+3)(r9)
-       stb     r0, (VCPU_XIVE_SAVED_STATE+4)(r9)
-       eieio
-1:
-#endif /* CONFIG_KVM_XICS */
 
        /*
         * Possibly flush the link stack here, before we do a blr in
-        * guest_exit_short_path.
+        * kvmhv_switch_to_host.
         */
 1:     nop
        patch_site 1b patch__call_kvm_flush_link_stack
 
-       /* If we came in through the P9 short path, go back out to C now */
-       lwz     r0, STACK_SLOT_SHORT_PATH(r1)
-       cmpwi   r0, 0
-       bne     guest_exit_short_path
-
        /* For hash guest, read the guest SLB and save it away */
-       ld      r5, VCPU_KVM(r9)
-       lbz     r0, KVM_RADIX(r5)
        li      r5, 0
-       cmpwi   r0, 0
-       bne     0f                      /* for radix, save 0 entries */
        lwz     r0,VCPU_SLB_NR(r9)      /* number of entries in SLB */
        mtctr   r0
        li      r6,0
@@ -1528,9 +1172,6 @@ guest_exit_cont:          /* r9 = vcpu, r12 = trap, r13 = paca */
        stw     r5,VCPU_SLB_MAX(r9)
 
        /* load host SLB entries */
-BEGIN_MMU_FTR_SECTION
-       b       guest_bypass
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        ld      r8,PACA_SLBSHADOWPTR(r13)
 
        .rept   SLB_NUM_BOLTED
@@ -1543,21 +1184,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        slbmte  r6,r5
 1:     addi    r8,r8,16
        .endr
-       b       guest_bypass
-
-0:     /*
-        * Sanitise radix guest SLB, see guest_exit_short_path comment.
-        * We clear vcpu->arch.slb_max to match earlier behaviour.
-        */
-       li      r0,0
-       stw     r0,VCPU_SLB_MAX(r9)
-       slbmte  r0,r0
-       li      r4,1
-       slbmte  r0,r4
-       li      r4,2
-       slbmte  r0,r4
-       li      r4,3
-       slbmte  r0,r4
 
 guest_bypass:
        stw     r12, STACK_SLOT_TRAP(r1)
@@ -1567,12 +1193,6 @@ guest_bypass:
        ld      r3, HSTATE_KVM_VCORE(r13)
        mfspr   r5,SPRN_DEC
        mftb    r6
-       /* On P9, if the guest has large decr enabled, don't sign extend */
-BEGIN_FTR_SECTION
-       ld      r4, VCORE_LPCR(r3)
-       andis.  r4, r4, LPCR_LD@h
-       bne     16f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        extsw   r5,r5
 16:    add     r5,r5,r6
        /* r5 is a guest timebase value here, convert to host TB */
@@ -1646,7 +1266,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        std     r6, VCPU_BESCR(r9)
        stw     r7, VCPU_GUEST_PID(r9)
        std     r8, VCPU_WORT(r9)
-BEGIN_FTR_SECTION
        mfspr   r5, SPRN_TCSCR
        mfspr   r6, SPRN_ACOP
        mfspr   r7, SPRN_CSIGR
@@ -1655,17 +1274,6 @@ BEGIN_FTR_SECTION
        std     r6, VCPU_ACOP(r9)
        std     r7, VCPU_CSIGR(r9)
        std     r8, VCPU_TACR(r9)
-FTR_SECTION_ELSE
-       mfspr   r5, SPRN_TIDR
-       mfspr   r6, SPRN_PSSCR
-       std     r5, VCPU_TID(r9)
-       rldicl  r6, r6, 4, 50           /* r6 &= PSSCR_GUEST_VIS */
-       rotldi  r6, r6, 60
-       std     r6, VCPU_PSSCR(r9)
-       /* Restore host HFSCR value */
-       ld      r7, STACK_SLOT_HFSCR(r1)
-       mtspr   SPRN_HFSCR, r7
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300)
 BEGIN_FTR_SECTION
        ld      r5, STACK_SLOT_FSCR(r1)
        mtspr   SPRN_FSCR, r5
@@ -1677,13 +1285,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        li      r0, 0
        mtspr   SPRN_PSPB, r0
        mtspr   SPRN_WORT, r0
-BEGIN_FTR_SECTION
        mtspr   SPRN_TCSCR, r0
        /* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */
        li      r0, 1
        sldi    r0, r0, 31
        mtspr   SPRN_MMCRS, r0
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 
        /* Save and restore AMR, IAMR and UAMOR before turning on the MMU */
        ld      r8, STACK_SLOT_IAMR(r1)
@@ -1740,13 +1346,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        bl      kvmppc_save_fp
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/*
- * Branch around the call if both CPU_FTR_TM and
- * CPU_FTR_P9_TM_HV_ASSIST are off.
- */
 BEGIN_FTR_SECTION
        b       91f
-END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR)
         */
@@ -1792,80 +1394,6 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_DAWR0, r6
        mtspr   SPRN_DAWRX0, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
-BEGIN_FTR_SECTION
-       ld      r6, STACK_SLOT_DAWR1(r1)
-       ld      r7, STACK_SLOT_DAWRX1(r1)
-       mtspr   SPRN_DAWR1, r6
-       mtspr   SPRN_DAWRX1, r7
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S | CPU_FTR_DAWR1)
-BEGIN_FTR_SECTION
-       ld      r5, STACK_SLOT_TID(r1)
-       ld      r6, STACK_SLOT_PSSCR(r1)
-       ld      r7, STACK_SLOT_PID(r1)
-       mtspr   SPRN_TIDR, r5
-       mtspr   SPRN_PSSCR, r6
-       mtspr   SPRN_PID, r7
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
-
-#ifdef CONFIG_PPC_RADIX_MMU
-       /*
-        * Are we running hash or radix ?
-        */
-       ld      r5, VCPU_KVM(r9)
-       lbz     r0, KVM_RADIX(r5)
-       cmpwi   cr2, r0, 0
-       beq     cr2, 2f
-
-       /*
-        * Radix: do eieio; tlbsync; ptesync sequence in case we
-        * interrupted the guest between a tlbie and a ptesync.
-        */
-       eieio
-       tlbsync
-       ptesync
-
-BEGIN_FTR_SECTION
-       /* Radix: Handle the case where the guest used an illegal PID */
-       LOAD_REG_ADDR(r4, mmu_base_pid)
-       lwz     r3, VCPU_GUEST_PID(r9)
-       lwz     r5, 0(r4)
-       cmpw    cr0,r3,r5
-       blt     2f
-
-       /*
-        * Illegal PID, the HW might have prefetched and cached in the TLB
-        * some translations for the  LPID 0 / guest PID combination which
-        * Linux doesn't know about, so we need to flush that PID out of
-        * the TLB. First we need to set LPIDR to 0 so tlbiel applies to
-        * the right context.
-       */
-       li      r0,0
-       mtspr   SPRN_LPID,r0
-       isync
-
-       /* Then do a congruence class local flush */
-       ld      r6,VCPU_KVM(r9)
-       lwz     r0,KVM_TLB_SETS(r6)
-       mtctr   r0
-       li      r7,0x400                /* IS field = 0b01 */
-       ptesync
-       sldi    r0,r3,32                /* RS has PID */
-1:     PPC_TLBIEL(7,0,2,1,1)           /* RIC=2, PRS=1, R=1 */
-       addi    r7,r7,0x1000
-       bdnz    1b
-       ptesync
-END_FTR_SECTION_IFSET(CPU_FTR_P9_RADIX_PREFETCH_BUG)
-
-2:
-#endif /* CONFIG_PPC_RADIX_MMU */
-
-       /*
-        * cp_abort is required if the processor supports local copy-paste
-        * to clear the copy buffer that was under control of the guest.
-        */
-BEGIN_FTR_SECTION
-       PPC_CP_ABORT
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_31)
 
        /*
         * POWER7/POWER8 guest -> host partition switch code.
@@ -1902,13 +1430,11 @@ kvmhv_switch_to_host:
 
        /* Primary thread switches back to host partition */
        lwz     r7,KVM_HOST_LPID(r4)
-BEGIN_FTR_SECTION
        ld      r6,KVM_HOST_SDR1(r4)
        li      r8,LPID_RSVD            /* switch to reserved LPID */
        mtspr   SPRN_LPID,r8
        ptesync
        mtspr   SPRN_SDR1,r6            /* switch to host page table */
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPID,r7
        isync
 
@@ -2117,26 +1643,13 @@ kvmppc_tm_emul:
  * reflect the HDSI to the guest as a DSI.
  */
 kvmppc_hdsi:
-       ld      r3, VCPU_KVM(r9)
-       lbz     r0, KVM_RADIX(r3)
        mfspr   r4, SPRN_HDAR
        mfspr   r6, SPRN_HDSISR
-BEGIN_FTR_SECTION
-       /* Look for DSISR canary. If we find it, retry instruction */
-       cmpdi   r6, 0x7fff
-       beq     6f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
-       cmpwi   r0, 0
-       bne     .Lradix_hdsi            /* on radix, just save DAR/DSISR/ASDR */
        /* HPTE not found fault or protection fault? */
        andis.  r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
        beq     1f                      /* if not, send it to the guest */
        andi.   r0, r11, MSR_DR         /* data relocation enabled? */
        beq     3f
-BEGIN_FTR_SECTION
-       mfspr   r5, SPRN_ASDR           /* on POWER9, use ASDR to get VSID */
-       b       4f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        clrrdi  r0, r4, 28
        PPC_SLBFEE_DOT(R5, R0)          /* if so, look up SLB */
        li      r0, BOOK3S_INTERRUPT_DATA_SEGMENT
@@ -2204,31 +1717,15 @@ fast_interrupt_c_return:
        stb     r0, HSTATE_IN_GUEST(r13)
        b       guest_exit_cont
 
-.Lradix_hdsi:
-       std     r4, VCPU_FAULT_DAR(r9)
-       stw     r6, VCPU_FAULT_DSISR(r9)
-.Lradix_hisi:
-       mfspr   r5, SPRN_ASDR
-       std     r5, VCPU_FAULT_GPA(r9)
-       b       guest_exit_cont
-
 /*
  * Similarly for an HISI, reflect it to the guest as an ISI unless
  * it is an HPTE not found fault for a page that we have paged out.
  */
 kvmppc_hisi:
-       ld      r3, VCPU_KVM(r9)
-       lbz     r0, KVM_RADIX(r3)
-       cmpwi   r0, 0
-       bne     .Lradix_hisi            /* for radix, just save ASDR */
        andis.  r0, r11, SRR1_ISI_NOPT@h
        beq     1f
        andi.   r0, r11, MSR_IR         /* instruction relocation enabled? */
        beq     3f
-BEGIN_FTR_SECTION
-       mfspr   r5, SPRN_ASDR           /* on POWER9, use ASDR to get VSID */
-       b       4f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        clrrdi  r0, r10, 28
        PPC_SLBFEE_DOT(R5, R0)          /* if so, look up SLB */
        li      r0, BOOK3S_INTERRUPT_INST_SEGMENT
@@ -2276,10 +1773,6 @@ hcall_try_real_mode:
        andi.   r0,r11,MSR_PR
        /* sc 1 from userspace - reflect to guest syscall */
        bne     sc_1_fast_return
-       /* sc 1 from nested guest - give it to L1 to handle */
-       ld      r0, VCPU_NESTED(r9)
-       cmpdi   r0, 0
-       bne     guest_exit_cont
        clrrdi  r3,r3,2
        cmpldi  r3,hcall_real_table_end - hcall_real_table
        bge     guest_exit_cont
@@ -2544,7 +2037,7 @@ hcall_real_table:
 #else
        .long   0               /* 0x2fc - H_XIRR_X*/
 #endif
-       .long   DOTSYM(kvmppc_h_random) - hcall_real_table
+       .long   DOTSYM(kvmppc_rm_h_random) - hcall_real_table
        .globl  hcall_real_table_end
 hcall_real_table_end:
 
@@ -2675,13 +2168,9 @@ _GLOBAL(kvmppc_h_cede)           /* r3 = vcpu pointer, r11 = msr, r13 = paca */
        bl      kvmppc_save_fp
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/*
- * Branch around the call if both CPU_FTR_TM and
- * CPU_FTR_P9_TM_HV_ASSIST are off.
- */
 BEGIN_FTR_SECTION
        b       91f
-END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR)
         */
@@ -2701,15 +2190,8 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
        mfspr   r3, SPRN_DEC
        mfspr   r4, SPRN_HDEC
        mftb    r5
-BEGIN_FTR_SECTION
-       /* On P9 check whether the guest has large decrementer mode enabled */
-       ld      r6, HSTATE_KVM_VCORE(r13)
-       ld      r6, VCORE_LPCR(r6)
-       andis.  r6, r6, LPCR_LD@h
-       bne     68f
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        extsw   r3, r3
-68:    EXTEND_HDEC(r4)
+       extsw   r4, r4
        cmpd    r3, r4
        ble     67f
        mtspr   SPRN_DEC, r4
@@ -2754,28 +2236,11 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
 kvm_nap_sequence:              /* desired LPCR value in r5 */
-BEGIN_FTR_SECTION
-       /*
-        * PSSCR bits:  exit criterion = 1 (wakeup based on LPCR at sreset)
-        *              enable state loss = 1 (allow SMT mode switch)
-        *              requested level = 0 (just stop dispatching)
-        */
-       lis     r3, (PSSCR_EC | PSSCR_ESL)@h
-       /* Set LPCR_PECE_HVEE bit to enable wakeup by HV interrupts */
-       li      r4, LPCR_PECE_HVEE@higher
-       sldi    r4, r4, 32
-       or      r5, r5, r4
-FTR_SECTION_ELSE
        li      r3, PNV_THREAD_NAP
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPCR,r5
        isync
 
-BEGIN_FTR_SECTION
-       bl      isa300_idle_stop_mayloss
-FTR_SECTION_ELSE
        bl      isa206_idle_insn_mayloss
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
 
        mfspr   r0, SPRN_CTRLF
        ori     r0, r0, 1
@@ -2794,10 +2259,8 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
        beq     kvm_end_cede
        cmpwi   r0, NAPPING_NOVCPU
        beq     kvm_novcpu_wakeup
-BEGIN_FTR_SECTION
        cmpwi   r0, NAPPING_UNSPLIT
        beq     kvm_unsplit_wakeup
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        twi     31,0,0 /* Nap state must not be zero */
 
 33:    mr      r4, r3
@@ -2817,13 +2280,9 @@ kvm_end_cede:
 #endif
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-/*
- * Branch around the call if both CPU_FTR_TM and
- * CPU_FTR_P9_TM_HV_ASSIST are off.
- */
 BEGIN_FTR_SECTION
        b       91f
-END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS (but not CR)
         */
@@ -2913,47 +2372,7 @@ kvm_cede_prodded:
        /* we've ceded but we want to give control to the host */
 kvm_cede_exit:
        ld      r9, HSTATE_KVM_VCPU(r13)
-#ifdef CONFIG_KVM_XICS
-       /* are we using XIVE with single escalation? */
-       ld      r10, VCPU_XIVE_ESC_VADDR(r9)
-       cmpdi   r10, 0
-       beq     3f
-       li      r6, XIVE_ESB_SET_PQ_00
-       /*
-        * If we still have a pending escalation, abort the cede,
-        * and we must set PQ to 10 rather than 00 so that we don't
-        * potentially end up with two entries for the escalation
-        * interrupt in the XIVE interrupt queue.  In that case
-        * we also don't want to set xive_esc_on to 1 here in
-        * case we race with xive_esc_irq().
-        */
-       lbz     r5, VCPU_XIVE_ESC_ON(r9)
-       cmpwi   r5, 0
-       beq     4f
-       li      r0, 0
-       stb     r0, VCPU_CEDED(r9)
-       /*
-        * The escalation interrupts are special as we don't EOI them.
-        * There is no need to use the load-after-store ordering offset
-        * to set PQ to 10 as we won't use StoreEOI.
-        */
-       li      r6, XIVE_ESB_SET_PQ_10
-       b       5f
-4:     li      r0, 1
-       stb     r0, VCPU_XIVE_ESC_ON(r9)
-       /* make sure store to xive_esc_on is seen before xive_esc_irq runs */
-       sync
-5:     /* Enable XIVE escalation */
-       mfmsr   r0
-       andi.   r0, r0, MSR_DR          /* in real mode? */
-       beq     1f
-       ldx     r0, r10, r6
-       b       2f
-1:     ld      r10, VCPU_XIVE_ESC_RADDR(r9)
-       ldcix   r0, r10, r6
-2:     sync
-#endif /* CONFIG_KVM_XICS */
-3:     b       guest_exit_cont
+       b       guest_exit_cont
 
        /* Try to do machine check recovery in real mode */
 machine_check_realmode:
@@ -3030,10 +2449,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        PPC_MSGCLR(6)
        /* see if it's a host IPI */
        li      r3, 1
-BEGIN_FTR_SECTION
-       PPC_MSGSYNC
-       lwsync
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        lbz     r0, HSTATE_HOST_IPI(r13)
        cmpwi   r0, 0
        bnelr
@@ -3342,73 +2757,12 @@ kvmppc_bad_host_intr:
        std     r3, STACK_FRAME_OVERHEAD-16(r1)
 
        /*
-        * On POWER9 do a minimal restore of the MMU and call C code,
-        * which will print a message and panic.
         * XXX On POWER7 and POWER8, we just spin here since we don't
         * know what the other threads are doing (and we don't want to
         * coordinate with them) - but at least we now have register state
         * in memory that we might be able to look at from another CPU.
         */
-BEGIN_FTR_SECTION
        b       .
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
-       ld      r9, HSTATE_KVM_VCPU(r13)
-       ld      r10, VCPU_KVM(r9)
-
-       li      r0, 0
-       mtspr   SPRN_AMR, r0
-       mtspr   SPRN_IAMR, r0
-       mtspr   SPRN_CIABR, r0
-       mtspr   SPRN_DAWRX0, r0
-BEGIN_FTR_SECTION
-       mtspr   SPRN_DAWRX1, r0
-END_FTR_SECTION_IFSET(CPU_FTR_DAWR1)
-
-       /* Clear hash and radix guest SLB, see guest_exit_short_path comment. */
-       slbmte  r0, r0
-       PPC_SLBIA(6)
-
-BEGIN_MMU_FTR_SECTION
-       b       4f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
-
-       ptesync
-       ld      r8, PACA_SLBSHADOWPTR(r13)
-       .rept   SLB_NUM_BOLTED
-       li      r3, SLBSHADOW_SAVEAREA
-       LDX_BE  r5, r8, r3
-       addi    r3, r3, 8
-       LDX_BE  r6, r8, r3
-       andis.  r7, r5, SLB_ESID_V@h
-       beq     3f
-       slbmte  r6, r5
-3:     addi    r8, r8, 16
-       .endr
-
-4:     lwz     r7, KVM_HOST_LPID(r10)
-       mtspr   SPRN_LPID, r7
-       mtspr   SPRN_PID, r0
-       ld      r8, KVM_HOST_LPCR(r10)
-       mtspr   SPRN_LPCR, r8
-       isync
-       li      r0, KVM_GUEST_MODE_NONE
-       stb     r0, HSTATE_IN_GUEST(r13)
-
-       /*
-        * Turn on the MMU and jump to C code
-        */
-       bcl     20, 31, .+4
-5:     mflr    r3
-       addi    r3, r3, 9f - 5b
-       li      r4, -1
-       rldimi  r3, r4, 62, 0   /* ensure 0xc000000000000000 bits are set */
-       ld      r4, PACAKMSR(r13)
-       mtspr   SPRN_SRR0, r3
-       mtspr   SPRN_SRR1, r4
-       RFI_TO_KERNEL
-9:     addi    r3, r1, STACK_FRAME_OVERHEAD
-       bl      kvmppc_bad_interrupt
-       b       9b
 
 /*
  * This mimics the MSR transition on IRQ delivery.  The new guest MSR is taken
index 84e5a2d..b898a59 100644 (file)
@@ -90,6 +90,7 @@
 #include <linux/migrate.h>
 #include <linux/kvm_host.h>
 #include <linux/ksm.h>
+#include <linux/of.h>
 #include <asm/ultravisor.h>
 #include <asm/mman.h>
 #include <asm/kvm_ppc.h>
index d7733b0..71bcb01 100644 (file)
@@ -493,7 +493,7 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
                if (!vcpu->arch.pending_exceptions) {
                        kvm_vcpu_block(vcpu);
                        kvm_clear_request(KVM_REQ_UNHALT, vcpu);
-                       vcpu->stat.halt_wakeup++;
+                       vcpu->stat.generic.halt_wakeup++;
 
                        /* Unset POW bit after we woke up */
                        msr &= ~MSR_POW;
index 031c801..ac14239 100644 (file)
@@ -378,7 +378,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
                kvmppc_set_msr_fast(vcpu, kvmppc_get_msr(vcpu) | MSR_EE);
                kvm_vcpu_block(vcpu);
                kvm_clear_request(KVM_REQ_UNHALT, vcpu);
-               vcpu->stat.halt_wakeup++;
+               vcpu->stat.generic.halt_wakeup++;
                return EMULATE_DONE;
        case H_LOGICAL_CI_LOAD:
                return kvmppc_h_pr_logical_ci_load(vcpu);
index 1f492aa..202046a 100644 (file)
@@ -164,12 +164,15 @@ kvmppc_interrupt_pr:
        /* 64-bit entry. Register usage at this point:
         *
         * SPRG_SCRATCH0   = guest R13
+        * R9              = HSTATE_IN_GUEST
         * R12             = (guest CR << 32) | exit handler id
         * R13             = PACA
         * HSTATE.SCRATCH0 = guest R12
+        * HSTATE.SCRATCH2 = guest R9
         */
 #ifdef CONFIG_PPC64
        /* Match 32-bit entry */
+       ld      r9,HSTATE_SCRATCH2(r13)
        rotldi  r12, r12, 32              /* Flip R12 halves for stw */
        stw     r12, HSTATE_SCRATCH1(r13) /* CR is now in the low half */
        srdi    r12, r12, 32              /* shift trap into low half */
index e7219b6..8cfab35 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
 #include <linux/uaccess.h>
+#include <linux/irqdomain.h>
 #include <asm/kvm_book3s.h>
 #include <asm/kvm_ppc.h>
 #include <asm/hvcall.h>
@@ -128,6 +129,71 @@ void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu)
 EXPORT_SYMBOL_GPL(kvmppc_xive_push_vcpu);
 
 /*
+ * Pull a vcpu's context from the XIVE on guest exit.
+ * This assumes we are in virtual mode (MMU on)
+ */
+void kvmppc_xive_pull_vcpu(struct kvm_vcpu *vcpu)
+{
+       void __iomem *tima = local_paca->kvm_hstate.xive_tima_virt;
+
+       if (!vcpu->arch.xive_pushed)
+               return;
+
+       /*
+        * Should not have been pushed if there is no tima
+        */
+       if (WARN_ON(!tima))
+               return;
+
+       eieio();
+       /* First load to pull the context, we ignore the value */
+       __raw_readl(tima + TM_SPC_PULL_OS_CTX);
+       /* Second load to recover the context state (Words 0 and 1) */
+       vcpu->arch.xive_saved_state.w01 = __raw_readq(tima + TM_QW1_OS);
+
+       /* Fixup some of the state for the next load */
+       vcpu->arch.xive_saved_state.lsmfb = 0;
+       vcpu->arch.xive_saved_state.ack = 0xff;
+       vcpu->arch.xive_pushed = 0;
+       eieio();
+}
+EXPORT_SYMBOL_GPL(kvmppc_xive_pull_vcpu);
+
+void kvmppc_xive_rearm_escalation(struct kvm_vcpu *vcpu)
+{
+       void __iomem *esc_vaddr = (void __iomem *)vcpu->arch.xive_esc_vaddr;
+
+       if (!esc_vaddr)
+               return;
+
+       /* we are using XIVE with single escalation */
+
+       if (vcpu->arch.xive_esc_on) {
+               /*
+                * If we still have a pending escalation, abort the cede,
+                * and we must set PQ to 10 rather than 00 so that we don't
+                * potentially end up with two entries for the escalation
+                * interrupt in the XIVE interrupt queue.  In that case
+                * we also don't want to set xive_esc_on to 1 here in
+                * case we race with xive_esc_irq().
+                */
+               vcpu->arch.ceded = 0;
+               /*
+                * The escalation interrupts are special as we don't EOI them.
+                * There is no need to use the load-after-store ordering offset
+                * to set PQ to 10 as we won't use StoreEOI.
+                */
+               __raw_readq(esc_vaddr + XIVE_ESB_SET_PQ_10);
+       } else {
+               vcpu->arch.xive_esc_on = true;
+               mb();
+               __raw_readq(esc_vaddr + XIVE_ESB_SET_PQ_00);
+       }
+       mb();
+}
+EXPORT_SYMBOL_GPL(kvmppc_xive_rearm_escalation);
+
+/*
  * This is a simple trigger for a generic XIVE IRQ. This must
  * only be called for interrupts that support a trigger page
  */
@@ -2075,6 +2141,36 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
        return 0;
 }
 
+int kvmppc_xive_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
+{
+       struct kvmppc_vcore *vc = vcpu->arch.vcore;
+
+       /* The VM should have configured XICS mode before doing XICS hcalls. */
+       if (!kvmppc_xics_enabled(vcpu))
+               return H_TOO_HARD;
+
+       switch (req) {
+       case H_XIRR:
+               return xive_vm_h_xirr(vcpu);
+       case H_CPPR:
+               return xive_vm_h_cppr(vcpu, kvmppc_get_gpr(vcpu, 4));
+       case H_EOI:
+               return xive_vm_h_eoi(vcpu, kvmppc_get_gpr(vcpu, 4));
+       case H_IPI:
+               return xive_vm_h_ipi(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                         kvmppc_get_gpr(vcpu, 5));
+       case H_IPOLL:
+               return xive_vm_h_ipoll(vcpu, kvmppc_get_gpr(vcpu, 4));
+       case H_XIRR_X:
+               xive_vm_h_xirr(vcpu);
+               kvmppc_set_gpr(vcpu, 5, get_tb() + vc->tb_offset);
+               return H_SUCCESS;
+       }
+
+       return H_UNSUPPORTED;
+}
+EXPORT_SYMBOL_GPL(kvmppc_xive_xics_hcall);
+
 int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu)
 {
        struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
@@ -2257,21 +2353,3 @@ struct kvm_device_ops kvm_xive_ops = {
        .get_attr = xive_get_attr,
        .has_attr = xive_has_attr,
 };
-
-void kvmppc_xive_init_module(void)
-{
-       __xive_vm_h_xirr = xive_vm_h_xirr;
-       __xive_vm_h_ipoll = xive_vm_h_ipoll;
-       __xive_vm_h_ipi = xive_vm_h_ipi;
-       __xive_vm_h_cppr = xive_vm_h_cppr;
-       __xive_vm_h_eoi = xive_vm_h_eoi;
-}
-
-void kvmppc_xive_exit_module(void)
-{
-       __xive_vm_h_xirr = NULL;
-       __xive_vm_h_ipoll = NULL;
-       __xive_vm_h_ipi = NULL;
-       __xive_vm_h_cppr = NULL;
-       __xive_vm_h_eoi = NULL;
-}
index 86c24a4..afe9eea 100644 (file)
@@ -289,13 +289,6 @@ extern int xive_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
 extern int xive_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr);
 extern int xive_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr);
 
-extern unsigned long (*__xive_vm_h_xirr)(struct kvm_vcpu *vcpu);
-extern unsigned long (*__xive_vm_h_ipoll)(struct kvm_vcpu *vcpu, unsigned long server);
-extern int (*__xive_vm_h_ipi)(struct kvm_vcpu *vcpu, unsigned long server,
-                             unsigned long mfrr);
-extern int (*__xive_vm_h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr);
-extern int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr);
-
 /*
  * Common Xive routines for XICS-over-XIVE and XIVE native
  */
index 76800c8..573ecaa 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/file.h>
+#include <linux/irqdomain.h>
 #include <asm/uaccess.h>
 #include <asm/kvm_book3s.h>
 #include <asm/kvm_ppc.h>
@@ -1281,13 +1282,3 @@ struct kvm_device_ops kvm_xive_native_ops = {
        .has_attr = kvmppc_xive_native_has_attr,
        .mmap = kvmppc_xive_native_mmap,
 };
-
-void kvmppc_xive_native_init_module(void)
-{
-       ;
-}
-
-void kvmppc_xive_native_exit_module(void)
-{
-       ;
-}
index 7d5fe43..551b30d 100644 (file)
 
 unsigned long kvmppc_booke_handlers;
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("mmio", mmio_exits),
-       VCPU_STAT("sig", signal_exits),
-       VCPU_STAT("itlb_r", itlb_real_miss_exits),
-       VCPU_STAT("itlb_v", itlb_virt_miss_exits),
-       VCPU_STAT("dtlb_r", dtlb_real_miss_exits),
-       VCPU_STAT("dtlb_v", dtlb_virt_miss_exits),
-       VCPU_STAT("sysc", syscall_exits),
-       VCPU_STAT("isi", isi_exits),
-       VCPU_STAT("dsi", dsi_exits),
-       VCPU_STAT("inst_emu", emulated_inst_exits),
-       VCPU_STAT("dec", dec_exits),
-       VCPU_STAT("ext_intr", ext_intr_exits),
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("doorbell", dbell_exits),
-       VCPU_STAT("guest doorbell", gdbell_exits),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       VM_STAT("remote_tlb_flush", remote_tlb_flush),
-       { NULL }
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS(),
+       STATS_DESC_ICOUNTER(VM, num_2M_pages),
+       STATS_DESC_ICOUNTER(VM, num_1G_pages)
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, sum_exits),
+       STATS_DESC_COUNTER(VCPU, mmio_exits),
+       STATS_DESC_COUNTER(VCPU, signal_exits),
+       STATS_DESC_COUNTER(VCPU, light_exits),
+       STATS_DESC_COUNTER(VCPU, itlb_real_miss_exits),
+       STATS_DESC_COUNTER(VCPU, itlb_virt_miss_exits),
+       STATS_DESC_COUNTER(VCPU, dtlb_real_miss_exits),
+       STATS_DESC_COUNTER(VCPU, dtlb_virt_miss_exits),
+       STATS_DESC_COUNTER(VCPU, syscall_exits),
+       STATS_DESC_COUNTER(VCPU, isi_exits),
+       STATS_DESC_COUNTER(VCPU, dsi_exits),
+       STATS_DESC_COUNTER(VCPU, emulated_inst_exits),
+       STATS_DESC_COUNTER(VCPU, dec_exits),
+       STATS_DESC_COUNTER(VCPU, ext_intr_exits),
+       STATS_DESC_TIME_NSEC(VCPU, halt_wait_ns),
+       STATS_DESC_COUNTER(VCPU, halt_successful_wait),
+       STATS_DESC_COUNTER(VCPU, dbell_exits),
+       STATS_DESC_COUNTER(VCPU, gdbell_exits),
+       STATS_DESC_COUNTER(VCPU, ld),
+       STATS_DESC_COUNTER(VCPU, st),
+       STATS_DESC_COUNTER(VCPU, pthru_all),
+       STATS_DESC_COUNTER(VCPU, pthru_host),
+       STATS_DESC_COUNTER(VCPU, pthru_bad_aff)
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 /* TODO: use vcpu_printf() */
index a2a68a9..be33b53 100644 (file)
@@ -682,6 +682,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = !!(hv_enabled && kvmppc_hv_ops->enable_dawr1 &&
                       !kvmppc_hv_ops->enable_dawr1(NULL));
                break;
+       case KVM_CAP_PPC_RPT_INVALIDATE:
+               r = 1;
+               break;
 #endif
        default:
                r = 0;
index 5fef8db..2176a5f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/sched/mm.h>
 #include <linux/memblock.h>
+#include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
@@ -357,30 +358,19 @@ static void __init radix_init_pgtable(void)
        }
 
        /* Find out how many PID bits are supported */
-       if (!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
-               if (!mmu_pid_bits)
-                       mmu_pid_bits = 20;
-               mmu_base_pid = 1;
-       } else if (cpu_has_feature(CPU_FTR_HVMODE)) {
-               if (!mmu_pid_bits)
-                       mmu_pid_bits = 20;
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       if (!cpu_has_feature(CPU_FTR_HVMODE) &&
+                       cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) {
                /*
-                * When KVM is possible, we only use the top half of the
-                * PID space to avoid collisions between host and guest PIDs
-                * which can cause problems due to prefetch when exiting the
-                * guest with AIL=3
+                * Older versions of KVM on these machines perfer if the
+                * guest only uses the low 19 PID bits.
                 */
-               mmu_base_pid = 1 << (mmu_pid_bits - 1);
-#else
-               mmu_base_pid = 1;
-#endif
-       } else {
-               /* The guest uses the bottom half of the PID space */
                if (!mmu_pid_bits)
                        mmu_pid_bits = 19;
-               mmu_base_pid = 1;
+       } else {
+               if (!mmu_pid_bits)
+                       mmu_pid_bits = 20;
        }
+       mmu_base_pid = 1;
 
        /*
         * Allocate Partition table and process table for the
@@ -486,6 +476,7 @@ static int __init radix_dt_scan_page_sizes(unsigned long node,
                def = &mmu_psize_defs[idx];
                def->shift = shift;
                def->ap  = ap;
+               def->h_rpt_pgsize = psize_to_rpti_pgsize(idx);
        }
 
        /* needed ? */
@@ -560,9 +551,13 @@ void __init radix__early_init_devtree(void)
                 */
                mmu_psize_defs[MMU_PAGE_4K].shift = 12;
                mmu_psize_defs[MMU_PAGE_4K].ap = 0x0;
+               mmu_psize_defs[MMU_PAGE_4K].h_rpt_pgsize =
+                       psize_to_rpti_pgsize(MMU_PAGE_4K);
 
                mmu_psize_defs[MMU_PAGE_64K].shift = 16;
                mmu_psize_defs[MMU_PAGE_64K].ap = 0x5;
+               mmu_psize_defs[MMU_PAGE_64K].h_rpt_pgsize =
+                       psize_to_rpti_pgsize(MMU_PAGE_64K);
        }
 
        /*
index 409e612..318ec4f 100644 (file)
 
 #include "internal.h"
 
-#define RIC_FLUSH_TLB 0
-#define RIC_FLUSH_PWC 1
-#define RIC_FLUSH_ALL 2
-
 /*
  * tlbiel instruction for radix, set invalidation
  * i.e., r=1 and is=01 or is=10 or is=11
@@ -130,6 +126,21 @@ static __always_inline void __tlbie_pid(unsigned long pid, unsigned long ric)
        trace_tlbie(0, 0, rb, rs, ric, prs, r);
 }
 
+static __always_inline void __tlbie_pid_lpid(unsigned long pid,
+                                            unsigned long lpid,
+                                            unsigned long ric)
+{
+       unsigned long rb, rs, prs, r;
+
+       rb = PPC_BIT(53); /* IS = 1 */
+       rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31)));
+       prs = 1; /* process scoped */
+       r = 1;   /* radix format */
+
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
+       trace_tlbie(0, 0, rb, rs, ric, prs, r);
+}
 static __always_inline void __tlbie_lpid(unsigned long lpid, unsigned long ric)
 {
        unsigned long rb,rs,prs,r;
@@ -190,6 +201,23 @@ static __always_inline void __tlbie_va(unsigned long va, unsigned long pid,
        trace_tlbie(0, 0, rb, rs, ric, prs, r);
 }
 
+static __always_inline void __tlbie_va_lpid(unsigned long va, unsigned long pid,
+                                           unsigned long lpid,
+                                           unsigned long ap, unsigned long ric)
+{
+       unsigned long rb, rs, prs, r;
+
+       rb = va & ~(PPC_BITMASK(52, 63));
+       rb |= ap << PPC_BITLSHIFT(58);
+       rs = (pid << PPC_BITLSHIFT(31)) | (lpid & ~(PPC_BITMASK(0, 31)));
+       prs = 1; /* process scoped */
+       r = 1;   /* radix format */
+
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
+       trace_tlbie(0, 0, rb, rs, ric, prs, r);
+}
+
 static __always_inline void __tlbie_lpid_va(unsigned long va, unsigned long lpid,
                                            unsigned long ap, unsigned long ric)
 {
@@ -235,6 +263,22 @@ static inline void fixup_tlbie_va_range(unsigned long va, unsigned long pid,
        }
 }
 
+static inline void fixup_tlbie_va_range_lpid(unsigned long va,
+                                            unsigned long pid,
+                                            unsigned long lpid,
+                                            unsigned long ap)
+{
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
+               asm volatile("ptesync" : : : "memory");
+               __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB);
+       }
+
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
+               asm volatile("ptesync" : : : "memory");
+               __tlbie_va_lpid(va, pid, lpid, ap, RIC_FLUSH_TLB);
+       }
+}
+
 static inline void fixup_tlbie_pid(unsigned long pid)
 {
        /*
@@ -254,6 +298,25 @@ static inline void fixup_tlbie_pid(unsigned long pid)
        }
 }
 
+static inline void fixup_tlbie_pid_lpid(unsigned long pid, unsigned long lpid)
+{
+       /*
+        * We can use any address for the invalidation, pick one which is
+        * probably unused as an optimisation.
+        */
+       unsigned long va = ((1UL << 52) - 1);
+
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) {
+               asm volatile("ptesync" : : : "memory");
+               __tlbie_pid_lpid(0, lpid, RIC_FLUSH_TLB);
+       }
+
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) {
+               asm volatile("ptesync" : : : "memory");
+               __tlbie_va_lpid(va, pid, lpid, mmu_get_ap(MMU_PAGE_64K),
+                               RIC_FLUSH_TLB);
+       }
+}
 
 static inline void fixup_tlbie_lpid_va(unsigned long va, unsigned long lpid,
                                       unsigned long ap)
@@ -344,6 +407,31 @@ static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
        asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 
+static inline void _tlbie_pid_lpid(unsigned long pid, unsigned long lpid,
+                                  unsigned long ric)
+{
+       asm volatile("ptesync" : : : "memory");
+
+       /*
+        * Workaround the fact that the "ric" argument to __tlbie_pid
+        * must be a compile-time contraint to match the "i" constraint
+        * in the asm statement.
+        */
+       switch (ric) {
+       case RIC_FLUSH_TLB:
+               __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_TLB);
+               fixup_tlbie_pid_lpid(pid, lpid);
+               break;
+       case RIC_FLUSH_PWC:
+               __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC);
+               break;
+       case RIC_FLUSH_ALL:
+       default:
+               __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_ALL);
+               fixup_tlbie_pid_lpid(pid, lpid);
+       }
+       asm volatile("eieio; tlbsync; ptesync" : : : "memory");
+}
 struct tlbiel_pid {
        unsigned long pid;
        unsigned long ric;
@@ -469,6 +557,20 @@ static inline void __tlbie_va_range(unsigned long start, unsigned long end,
        fixup_tlbie_va_range(addr - page_size, pid, ap);
 }
 
+static inline void __tlbie_va_range_lpid(unsigned long start, unsigned long end,
+                                        unsigned long pid, unsigned long lpid,
+                                        unsigned long page_size,
+                                        unsigned long psize)
+{
+       unsigned long addr;
+       unsigned long ap = mmu_get_ap(psize);
+
+       for (addr = start; addr < end; addr += page_size)
+               __tlbie_va_lpid(addr, pid, lpid, ap, RIC_FLUSH_TLB);
+
+       fixup_tlbie_va_range_lpid(addr - page_size, pid, lpid, ap);
+}
+
 static __always_inline void _tlbie_va(unsigned long va, unsigned long pid,
                                      unsigned long psize, unsigned long ric)
 {
@@ -549,6 +651,18 @@ static inline void _tlbie_va_range(unsigned long start, unsigned long end,
        asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 
+static inline void _tlbie_va_range_lpid(unsigned long start, unsigned long end,
+                                       unsigned long pid, unsigned long lpid,
+                                       unsigned long page_size,
+                                       unsigned long psize, bool also_pwc)
+{
+       asm volatile("ptesync" : : : "memory");
+       if (also_pwc)
+               __tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC);
+       __tlbie_va_range_lpid(start, end, pid, lpid, page_size, psize);
+       asm volatile("eieio; tlbsync; ptesync" : : : "memory");
+}
+
 static inline void _tlbiel_va_range_multicast(struct mm_struct *mm,
                                unsigned long start, unsigned long end,
                                unsigned long pid, unsigned long page_size,
@@ -1338,47 +1452,57 @@ void radix__flush_tlb_all(void)
 }
 
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-extern void radix_kvm_prefetch_workaround(struct mm_struct *mm)
+/*
+ * Performs process-scoped invalidations for a given LPID
+ * as part of H_RPT_INVALIDATE hcall.
+ */
+void do_h_rpt_invalidate_prt(unsigned long pid, unsigned long lpid,
+                            unsigned long type, unsigned long pg_sizes,
+                            unsigned long start, unsigned long end)
 {
-       unsigned long pid = mm->context.id;
+       unsigned long psize, nr_pages;
+       struct mmu_psize_def *def;
+       bool flush_pid;
 
-       if (unlikely(pid == MMU_NO_CONTEXT))
+       /*
+        * A H_RPTI_TYPE_ALL request implies RIC=3, hence
+        * do a single IS=1 based flush.
+        */
+       if ((type & H_RPTI_TYPE_ALL) == H_RPTI_TYPE_ALL) {
+               _tlbie_pid_lpid(pid, lpid, RIC_FLUSH_ALL);
                return;
+       }
 
-       if (!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG))
-               return;
+       if (type & H_RPTI_TYPE_PWC)
+               _tlbie_pid_lpid(pid, lpid, RIC_FLUSH_PWC);
 
-       /*
-        * If this context hasn't run on that CPU before and KVM is
-        * around, there's a slim chance that the guest on another
-        * CPU just brought in obsolete translation into the TLB of
-        * this CPU due to a bad prefetch using the guest PID on
-        * the way into the hypervisor.
-        *
-        * We work around this here. If KVM is possible, we check if
-        * any sibling thread is in KVM. If it is, the window may exist
-        * and thus we flush that PID from the core.
-        *
-        * A potential future improvement would be to mark which PIDs
-        * have never been used on the system and avoid it if the PID
-        * is new and the process has no other cpumask bit set.
-        */
-       if (cpu_has_feature(CPU_FTR_HVMODE) && radix_enabled()) {
-               int cpu = smp_processor_id();
-               int sib = cpu_first_thread_sibling(cpu);
-               bool flush = false;
-
-               for (; sib <= cpu_last_thread_sibling(cpu) && !flush; sib++) {
-                       if (sib == cpu)
-                               continue;
-                       if (!cpu_possible(sib))
-                               continue;
-                       if (paca_ptrs[sib]->kvm_hstate.kvm_vcpu)
-                               flush = true;
+       /* Full PID flush */
+       if (start == 0 && end == -1)
+               return _tlbie_pid_lpid(pid, lpid, RIC_FLUSH_TLB);
+
+       /* Do range invalidation for all the valid page sizes */
+       for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
+               def = &mmu_psize_defs[psize];
+               if (!(pg_sizes & def->h_rpt_pgsize))
+                       continue;
+
+               nr_pages = (end - start) >> def->shift;
+               flush_pid = nr_pages > tlb_single_page_flush_ceiling;
+
+               /*
+                * If the number of pages spanning the range is above
+                * the ceiling, convert the request into a full PID flush.
+                * And since PID flush takes out all the page sizes, there
+                * is no need to consider remaining page sizes.
+                */
+               if (flush_pid) {
+                       _tlbie_pid_lpid(pid, lpid, RIC_FLUSH_TLB);
+                       return;
                }
-               if (flush)
-                       _tlbiel_pid(pid, RIC_FLUSH_ALL);
+               _tlbie_va_range_lpid(start, end, pid, lpid,
+                                    (1UL << def->shift), psize, false);
        }
 }
-EXPORT_SYMBOL_GPL(radix_kvm_prefetch_workaround);
+EXPORT_SYMBOL_GPL(do_h_rpt_invalidate_prt);
+
 #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
index 043bbea..a6b36a4 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include <asm/kasan.h>
+#include <asm/sparsemem.h>
 #include <asm/svm.h>
 
 #include <mm/mmu_decl.h>
index a857af4..7424653 100644 (file)
@@ -83,9 +83,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
        if (cpu_has_feature(CPU_FTR_ALTIVEC))
                asm volatile ("dssall");
 
-       if (new_on_cpu)
-               radix_kvm_prefetch_workaround(next);
-       else
+       if (!new_on_cpu)
                membarrier_arch_switch_mm(prev, next, tsk);
 
        /*
index 16d4d1b..5162241 100644 (file)
@@ -2254,7 +2254,7 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
        bool use_siar = regs_use_siar(regs);
        unsigned long siar = mfspr(SPRN_SIAR);
 
-       if (ppmu->flags & PPMU_P10_DD1) {
+       if (ppmu && (ppmu->flags & PPMU_P10_DD1)) {
                if (siar)
                        return siar;
                else
index e7c976b..cb70c5f 100644 (file)
@@ -35,6 +35,7 @@ config PPC_IBM_CELL_BLADE
 config AXON_MSI
        bool
        depends on PPC_IBM_CELL_BLADE && PCI_MSI
+       select IRQ_DOMAIN_NOMAP
        default y
 
 menu "Cell Broadband Engine options"
index 35bbd15..b207a7f 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/types.h>
 #include <linux/export.h>
 #include <asm/io.h>
index d39a921..609bda2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <asm/io.h>
index c02d8c5..b97bf12 100644 (file)
@@ -24,6 +24,7 @@ config PPC_PMAC32_PSURGE
        bool "Support for powersurge upgrade cards" if EXPERT
        depends on SMP && PPC32 && PPC_PMAC
        select PPC_SMP_MUXED_IPI
+       select IRQ_DOMAIN_NOMAP
        default y
        help
          The powersurge cpu boards can be used in the generation
index 999997d..528a7e0 100644 (file)
@@ -604,7 +604,7 @@ struct p9_sprs {
        u64 uamor;
 };
 
-static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
+static unsigned long power9_idle_stop(unsigned long psscr)
 {
        int cpu = raw_smp_processor_id();
        int first = cpu_first_thread_sibling(cpu);
@@ -620,8 +620,6 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
        if (!(psscr & (PSSCR_EC|PSSCR_ESL))) {
                /* EC=ESL=0 case */
 
-               BUG_ON(!mmu_on);
-
                /*
                 * Wake synchronously. SRESET via xscom may still cause
                 * a 0x100 powersave wakeup with SRR1 reason!
@@ -803,8 +801,7 @@ core_woken:
                __slb_restore_bolted_realmode();
 
 out:
-       if (mmu_on)
-               mtmsr(MSR_KERNEL);
+       mtmsr(MSR_KERNEL);
 
        return srr1;
 }
@@ -895,7 +892,7 @@ struct p10_sprs {
         */
 };
 
-static unsigned long power10_idle_stop(unsigned long psscr, bool mmu_on)
+static unsigned long power10_idle_stop(unsigned long psscr)
 {
        int cpu = raw_smp_processor_id();
        int first = cpu_first_thread_sibling(cpu);
@@ -909,8 +906,6 @@ static unsigned long power10_idle_stop(unsigned long psscr, bool mmu_on)
        if (!(psscr & (PSSCR_EC|PSSCR_ESL))) {
                /* EC=ESL=0 case */
 
-               BUG_ON(!mmu_on);
-
                /*
                 * Wake synchronously. SRESET via xscom may still cause
                 * a 0x100 powersave wakeup with SRR1 reason!
@@ -991,8 +986,7 @@ core_woken:
                __slb_restore_bolted_realmode();
 
 out:
-       if (mmu_on)
-               mtmsr(MSR_KERNEL);
+       mtmsr(MSR_KERNEL);
 
        return srr1;
 }
@@ -1002,40 +996,10 @@ static unsigned long arch300_offline_stop(unsigned long psscr)
 {
        unsigned long srr1;
 
-#ifndef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-       __ppc64_runlatch_off();
        if (cpu_has_feature(CPU_FTR_ARCH_31))
-               srr1 = power10_idle_stop(psscr, true);
+               srr1 = power10_idle_stop(psscr);
        else
-               srr1 = power9_idle_stop(psscr, true);
-       __ppc64_runlatch_on();
-#else
-       /*
-        * Tell KVM we're entering idle.
-        * This does not have to be done in real mode because the P9 MMU
-        * is independent per-thread. Some steppings share radix/hash mode
-        * between threads, but in that case KVM has a barrier sync in real
-        * mode before and after switching between radix and hash.
-        *
-        * kvm_start_guest must still be called in real mode though, hence
-        * the false argument.
-        */
-       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_IDLE;
-
-       __ppc64_runlatch_off();
-       if (cpu_has_feature(CPU_FTR_ARCH_31))
-               srr1 = power10_idle_stop(psscr, false);
-       else
-               srr1 = power9_idle_stop(psscr, false);
-       __ppc64_runlatch_on();
-
-       local_paca->kvm_hstate.hwthread_state = KVM_HWTHREAD_IN_KERNEL;
-       /* Order setting hwthread_state vs. testing hwthread_req */
-       smp_mb();
-       if (local_paca->kvm_hstate.hwthread_req)
-               srr1 = idle_kvm_start_guest(srr1);
-       mtmsr(MSR_KERNEL);
-#endif
+               srr1 = power9_idle_stop(psscr);
 
        return srr1;
 }
@@ -1055,9 +1019,9 @@ void arch300_idle_type(unsigned long stop_psscr_val,
 
        __ppc64_runlatch_off();
        if (cpu_has_feature(CPU_FTR_ARCH_31))
-               srr1 = power10_idle_stop(psscr, true);
+               srr1 = power10_idle_stop(psscr);
        else
-               srr1 = power9_idle_stop(psscr, true);
+               srr1 = power9_idle_stop(psscr);
        __ppc64_runlatch_on();
 
        fini_irq_for_idle_irqsoff();
index e32406e..4d0535c 100644 (file)
@@ -7,6 +7,7 @@ config PPC_PS3
        select USB_OHCI_BIG_ENDIAN_MMIO
        select USB_EHCI_BIG_ENDIAN_MMIO
        select HAVE_PCI
+       select IRQ_DOMAIN_NOMAP
        help
          This option enables support for the Sony PS3 game console
          and other platforms using the PS3 hypervisor.  Enabling this
index 78f2339..4987142 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 
 #include <asm/machdep.h>
 #include <asm/udbg.h>
@@ -45,7 +46,7 @@
  * implementation equates HV plug value to Linux virq value, constrains each
  * interrupt to have a system wide unique plug number, and limits the range
  * of the plug values to map into the first dword of the bitmaps.  This
- * gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note
+ * gives a usable range of plug values of  {NR_IRQS_LEGACY..63}.  Note
  * that there is no constraint on how many in this set an individual thread
  * can acquire.
  *
@@ -721,7 +722,7 @@ static unsigned int ps3_get_irq(void)
        }
 
 #if defined(DEBUG)
-       if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
+       if (unlikely(plug < NR_IRQS_LEGACY || plug > PS3_PLUG_MAX)) {
                dump_bmp(&per_cpu(ps3_private, 0));
                dump_bmp(&per_cpu(ps3_private, 1));
                BUG();
index a15ab33..c6c79ef 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/kobject.h>
 #include <linux/dma-map-ops.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
index 48866e6..0070525 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
index 13583bb..5fa5fa2 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
index c1d76c3..dc1a151 100644 (file)
@@ -260,7 +260,8 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
        raw_spin_unlock_irqrestore(&i8259_lock, flags);
 
        /* create a legacy host */
-       i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);
+       i8259_host = irq_domain_add_legacy(node, NR_IRQS_LEGACY, 0, 0,
+                                          &i8259_host_ops, NULL);
        if (i8259_host == NULL) {
                printk(KERN_ERR "i8259: failed to allocate irq host !\n");
                return;
index b0426f2..995fb2a 100644 (file)
@@ -602,7 +602,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
 /* Find an mpic associated with a given linux interrupt */
 static struct mpic *mpic_find(unsigned int irq)
 {
-       if (irq < NUM_ISA_INTERRUPTS)
+       if (irq < NR_IRQS_LEGACY)
                return NULL;
 
        return irq_get_chip_data(irq);
index 49f9541..042bb38 100644 (file)
@@ -404,7 +404,8 @@ void __init tsi108_pci_int_init(struct device_node *node)
 {
        DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
 
-       pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);
+       pci_irq_host = irq_domain_add_legacy(node, NR_IRQS_LEGACY, 0, 0,
+                                            &pci_irq_domain_ops, NULL);
        if (pci_irq_host == NULL) {
                printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
                return;
index 21b9d1b..6765d9e 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/cpu.h>
 #include <linux/of.h>
 
index 68fd254..675d708 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/cpu.h>
 #include <linux/of.h>
 
index 7e4305c..fdf8db4 100644 (file)
@@ -201,7 +201,7 @@ void xics_migrate_irqs_away(void)
                struct ics *ics;
 
                /* We can't set affinity on ISA interrupts */
-               if (virq < NUM_ISA_INTERRUPTS)
+               if (virq < NR_IRQS_LEGACY)
                        continue;
                /* We only need to migrate enabled IRQS */
                if (!desc->action)
index 785c292..97796c6 100644 (file)
@@ -3,6 +3,7 @@ config PPC_XIVE
        bool
        select PPC_SMP_MUXED_IPI
        select HARDIRQS_SW_RESEND
+       select IRQ_DOMAIN_NOMAP
 
 config PPC_XIVE_NATIVE
        bool
index c8173e9..84de2d7 100644 (file)
@@ -3162,6 +3162,7 @@ memzcan(void)
 
 static void show_task(struct task_struct *tsk)
 {
+       unsigned int p_state = READ_ONCE(tsk->__state);
        char state;
 
        /*
@@ -3169,14 +3170,14 @@ static void show_task(struct task_struct *tsk)
         * appropriate for calling from xmon. This could be moved
         * to a common, generic, routine used by both.
         */
-       state = (tsk->state == 0) ? 'R' :
-               (tsk->state < 0) ? 'U' :
-               (tsk->state & TASK_UNINTERRUPTIBLE) ? 'D' :
-               (tsk->state & TASK_STOPPED) ? 'T' :
-               (tsk->state & TASK_TRACED) ? 'C' :
+       state = (p_state == 0) ? 'R' :
+               (p_state < 0) ? 'U' :
+               (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
+               (p_state & TASK_STOPPED) ? 'T' :
+               (p_state & TASK_TRACED) ? 'C' :
                (tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
                (tsk->exit_state & EXIT_DEAD) ? 'E' :
-               (tsk->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
+               (p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
 
        printf("%16px %16lx %16px %6d %6d %c %2d %s\n", tsk,
                tsk->thread.ksp, tsk->thread.regs,
index ed96376..30676eb 100644 (file)
@@ -14,6 +14,7 @@ config SOC_SIFIVE
        select CLK_SIFIVE
        select CLK_SIFIVE_PRCI
        select SIFIVE_PLIC
+       select RISCV_ERRATA_ALTERNATIVE
        select ERRATA_SIFIVE
        help
          This enables support for SiFive SoC platform hardware.
index 4be0206..99ecd8b 100644 (file)
@@ -16,7 +16,7 @@ ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
        CC_FLAGS_FTRACE := -fpatchable-function-entry=8
 endif
 
-ifeq ($(CONFIG_64BIT)$(CONFIG_CMODEL_MEDLOW),yy)
+ifeq ($(CONFIG_CMODEL_MEDLOW),y)
 KBUILD_CFLAGS_MODULE += -mcmodel=medany
 endif
 
index 8eef82e..abbb960 100644 (file)
                        cache-size = <2097152>;
                        cache-unified;
                        interrupt-parent = <&plic0>;
-                       interrupts = <19 20 21 22>;
+                       interrupts = <19 21 22 20>;
                        reg = <0x0 0x2010000 0x0 0x1000>;
                };
                gpio: gpio@10060000 {
index 400a8c8..ac9bdf4 100644 (file)
 #define __atomic_release_fence()                                       \
        __asm__ __volatile__(RISCV_RELEASE_BARRIER "" ::: "memory");
 
-static __always_inline int atomic_read(const atomic_t *v)
+static __always_inline int arch_atomic_read(const atomic_t *v)
 {
        return READ_ONCE(v->counter);
 }
-static __always_inline void atomic_set(atomic_t *v, int i)
+static __always_inline void arch_atomic_set(atomic_t *v, int i)
 {
        WRITE_ONCE(v->counter, i);
 }
 
 #ifndef CONFIG_GENERIC_ATOMIC64
 #define ATOMIC64_INIT(i) { (i) }
-static __always_inline s64 atomic64_read(const atomic64_t *v)
+static __always_inline s64 arch_atomic64_read(const atomic64_t *v)
 {
        return READ_ONCE(v->counter);
 }
-static __always_inline void atomic64_set(atomic64_t *v, s64 i)
+static __always_inline void arch_atomic64_set(atomic64_t *v, s64 i)
 {
        WRITE_ONCE(v->counter, i);
 }
@@ -53,7 +53,7 @@ static __always_inline void atomic64_set(atomic64_t *v, s64 i)
  */
 #define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix)             \
 static __always_inline                                                 \
-void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)            \
+void arch_atomic##prefix##_##op(c_type i, atomic##prefix##_t *v)       \
 {                                                                      \
        __asm__ __volatile__ (                                          \
                "       amo" #asm_op "." #asm_type " zero, %1, %0"      \
@@ -87,7 +87,7 @@ ATOMIC_OPS(xor, xor,  i)
  */
 #define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix)       \
 static __always_inline                                                 \
-c_type atomic##prefix##_fetch_##op##_relaxed(c_type i,                 \
+c_type arch_atomic##prefix##_fetch_##op##_relaxed(c_type i,            \
                                             atomic##prefix##_t *v)     \
 {                                                                      \
        register c_type ret;                                            \
@@ -99,7 +99,7 @@ c_type atomic##prefix##_fetch_##op##_relaxed(c_type i,                        \
        return ret;                                                     \
 }                                                                      \
 static __always_inline                                                 \
-c_type atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v)    \
+c_type arch_atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v)       \
 {                                                                      \
        register c_type ret;                                            \
        __asm__ __volatile__ (                                          \
@@ -112,15 +112,15 @@ c_type atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v)       \
 
 #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_type, c_type, prefix)        \
 static __always_inline                                                 \
-c_type atomic##prefix##_##op##_return_relaxed(c_type i,                        \
+c_type arch_atomic##prefix##_##op##_return_relaxed(c_type i,           \
                                              atomic##prefix##_t *v)    \
 {                                                                      \
-        return atomic##prefix##_fetch_##op##_relaxed(i, v) c_op I;     \
+        return arch_atomic##prefix##_fetch_##op##_relaxed(i, v) c_op I;        \
 }                                                                      \
 static __always_inline                                                 \
-c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \
+c_type arch_atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v)    \
 {                                                                      \
-        return atomic##prefix##_fetch_##op(i, v) c_op I;               \
+        return arch_atomic##prefix##_fetch_##op(i, v) c_op I;          \
 }
 
 #ifdef CONFIG_GENERIC_ATOMIC64
@@ -138,26 +138,26 @@ c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v)    \
 ATOMIC_OPS(add, add, +,  i)
 ATOMIC_OPS(sub, add, +, -i)
 
-#define atomic_add_return_relaxed      atomic_add_return_relaxed
-#define atomic_sub_return_relaxed      atomic_sub_return_relaxed
-#define atomic_add_return              atomic_add_return
-#define atomic_sub_return              atomic_sub_return
+#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
+#define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
+#define arch_atomic_add_return         arch_atomic_add_return
+#define arch_atomic_sub_return         arch_atomic_sub_return
 
-#define atomic_fetch_add_relaxed       atomic_fetch_add_relaxed
-#define atomic_fetch_sub_relaxed       atomic_fetch_sub_relaxed
-#define atomic_fetch_add               atomic_fetch_add
-#define atomic_fetch_sub               atomic_fetch_sub
+#define arch_atomic_fetch_add_relaxed  arch_atomic_fetch_add_relaxed
+#define arch_atomic_fetch_sub_relaxed  arch_atomic_fetch_sub_relaxed
+#define arch_atomic_fetch_add          arch_atomic_fetch_add
+#define arch_atomic_fetch_sub          arch_atomic_fetch_sub
 
 #ifndef CONFIG_GENERIC_ATOMIC64
-#define atomic64_add_return_relaxed    atomic64_add_return_relaxed
-#define atomic64_sub_return_relaxed    atomic64_sub_return_relaxed
-#define atomic64_add_return            atomic64_add_return
-#define atomic64_sub_return            atomic64_sub_return
-
-#define atomic64_fetch_add_relaxed     atomic64_fetch_add_relaxed
-#define atomic64_fetch_sub_relaxed     atomic64_fetch_sub_relaxed
-#define atomic64_fetch_add             atomic64_fetch_add
-#define atomic64_fetch_sub             atomic64_fetch_sub
+#define arch_atomic64_add_return_relaxed       arch_atomic64_add_return_relaxed
+#define arch_atomic64_sub_return_relaxed       arch_atomic64_sub_return_relaxed
+#define arch_atomic64_add_return               arch_atomic64_add_return
+#define arch_atomic64_sub_return               arch_atomic64_sub_return
+
+#define arch_atomic64_fetch_add_relaxed        arch_atomic64_fetch_add_relaxed
+#define arch_atomic64_fetch_sub_relaxed        arch_atomic64_fetch_sub_relaxed
+#define arch_atomic64_fetch_add                arch_atomic64_fetch_add
+#define arch_atomic64_fetch_sub                arch_atomic64_fetch_sub
 #endif
 
 #undef ATOMIC_OPS
@@ -175,20 +175,20 @@ ATOMIC_OPS(and, and, i)
 ATOMIC_OPS( or,  or, i)
 ATOMIC_OPS(xor, xor, i)
 
-#define atomic_fetch_and_relaxed       atomic_fetch_and_relaxed
-#define atomic_fetch_or_relaxed                atomic_fetch_or_relaxed
-#define atomic_fetch_xor_relaxed       atomic_fetch_xor_relaxed
-#define atomic_fetch_and               atomic_fetch_and
-#define atomic_fetch_or                        atomic_fetch_or
-#define atomic_fetch_xor               atomic_fetch_xor
+#define arch_atomic_fetch_and_relaxed  arch_atomic_fetch_and_relaxed
+#define arch_atomic_fetch_or_relaxed   arch_atomic_fetch_or_relaxed
+#define arch_atomic_fetch_xor_relaxed  arch_atomic_fetch_xor_relaxed
+#define arch_atomic_fetch_and          arch_atomic_fetch_and
+#define arch_atomic_fetch_or           arch_atomic_fetch_or
+#define arch_atomic_fetch_xor          arch_atomic_fetch_xor
 
 #ifndef CONFIG_GENERIC_ATOMIC64
-#define atomic64_fetch_and_relaxed     atomic64_fetch_and_relaxed
-#define atomic64_fetch_or_relaxed      atomic64_fetch_or_relaxed
-#define atomic64_fetch_xor_relaxed     atomic64_fetch_xor_relaxed
-#define atomic64_fetch_and             atomic64_fetch_and
-#define atomic64_fetch_or              atomic64_fetch_or
-#define atomic64_fetch_xor             atomic64_fetch_xor
+#define arch_atomic64_fetch_and_relaxed        arch_atomic64_fetch_and_relaxed
+#define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed
+#define arch_atomic64_fetch_xor_relaxed        arch_atomic64_fetch_xor_relaxed
+#define arch_atomic64_fetch_and                arch_atomic64_fetch_and
+#define arch_atomic64_fetch_or         arch_atomic64_fetch_or
+#define arch_atomic64_fetch_xor                arch_atomic64_fetch_xor
 #endif
 
 #undef ATOMIC_OPS
@@ -197,7 +197,7 @@ ATOMIC_OPS(xor, xor, i)
 #undef ATOMIC_OP_RETURN
 
 /* This is required to provide a full barrier on success. */
-static __always_inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+static __always_inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int prev, rc;
 
@@ -214,10 +214,10 @@ static __always_inline int atomic_fetch_add_unless(atomic_t *v, int a, int u)
                : "memory");
        return prev;
 }
-#define atomic_fetch_add_unless atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
 
 #ifndef CONFIG_GENERIC_ATOMIC64
-static __always_inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+static __always_inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        s64 prev;
        long rc;
@@ -235,7 +235,7 @@ static __always_inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u
                : "memory");
        return prev;
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+#define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
 #endif
 
 /*
@@ -244,45 +244,45 @@ static __always_inline s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u
  */
 #define ATOMIC_OP(c_t, prefix, size)                                   \
 static __always_inline                                                 \
-c_t atomic##prefix##_xchg_relaxed(atomic##prefix##_t *v, c_t n)                \
+c_t arch_atomic##prefix##_xchg_relaxed(atomic##prefix##_t *v, c_t n)   \
 {                                                                      \
        return __xchg_relaxed(&(v->counter), n, size);                  \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_xchg_acquire(atomic##prefix##_t *v, c_t n)                \
+c_t arch_atomic##prefix##_xchg_acquire(atomic##prefix##_t *v, c_t n)   \
 {                                                                      \
        return __xchg_acquire(&(v->counter), n, size);                  \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n)                \
+c_t arch_atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n)   \
 {                                                                      \
        return __xchg_release(&(v->counter), n, size);                  \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n)                        \
+c_t arch_atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n)           \
 {                                                                      \
        return __xchg(&(v->counter), n, size);                          \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v,            \
+c_t arch_atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v,       \
                                     c_t o, c_t n)                      \
 {                                                                      \
        return __cmpxchg_relaxed(&(v->counter), o, n, size);            \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_cmpxchg_acquire(atomic##prefix##_t *v,            \
+c_t arch_atomic##prefix##_cmpxchg_acquire(atomic##prefix##_t *v,       \
                                     c_t o, c_t n)                      \
 {                                                                      \
        return __cmpxchg_acquire(&(v->counter), o, n, size);            \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_cmpxchg_release(atomic##prefix##_t *v,            \
+c_t arch_atomic##prefix##_cmpxchg_release(atomic##prefix##_t *v,       \
                                     c_t o, c_t n)                      \
 {                                                                      \
        return __cmpxchg_release(&(v->counter), o, n, size);            \
 }                                                                      \
 static __always_inline                                                 \
-c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n)      \
+c_t arch_atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \
 {                                                                      \
        return __cmpxchg(&(v->counter), o, n, size);                    \
 }
@@ -298,19 +298,19 @@ c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \
 
 ATOMIC_OPS()
 
-#define atomic_xchg_relaxed atomic_xchg_relaxed
-#define atomic_xchg_acquire atomic_xchg_acquire
-#define atomic_xchg_release atomic_xchg_release
-#define atomic_xchg atomic_xchg
-#define atomic_cmpxchg_relaxed atomic_cmpxchg_relaxed
-#define atomic_cmpxchg_acquire atomic_cmpxchg_acquire
-#define atomic_cmpxchg_release atomic_cmpxchg_release
-#define atomic_cmpxchg atomic_cmpxchg
+#define arch_atomic_xchg_relaxed       arch_atomic_xchg_relaxed
+#define arch_atomic_xchg_acquire       arch_atomic_xchg_acquire
+#define arch_atomic_xchg_release       arch_atomic_xchg_release
+#define arch_atomic_xchg               arch_atomic_xchg
+#define arch_atomic_cmpxchg_relaxed    arch_atomic_cmpxchg_relaxed
+#define arch_atomic_cmpxchg_acquire    arch_atomic_cmpxchg_acquire
+#define arch_atomic_cmpxchg_release    arch_atomic_cmpxchg_release
+#define arch_atomic_cmpxchg            arch_atomic_cmpxchg
 
 #undef ATOMIC_OPS
 #undef ATOMIC_OP
 
-static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset)
+static __always_inline int arch_atomic_sub_if_positive(atomic_t *v, int offset)
 {
        int prev, rc;
 
@@ -328,10 +328,10 @@ static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset)
        return prev - offset;
 }
 
-#define atomic_dec_if_positive(v)      atomic_sub_if_positive(v, 1)
+#define arch_atomic_dec_if_positive(v) arch_atomic_sub_if_positive(v, 1)
 
 #ifndef CONFIG_GENERIC_ATOMIC64
-static __always_inline s64 atomic64_sub_if_positive(atomic64_t *v, s64 offset)
+static __always_inline s64 arch_atomic64_sub_if_positive(atomic64_t *v, s64 offset)
 {
        s64 prev;
        long rc;
@@ -350,7 +350,7 @@ static __always_inline s64 atomic64_sub_if_positive(atomic64_t *v, s64 offset)
        return prev - offset;
 }
 
-#define atomic64_dec_if_positive(v)    atomic64_sub_if_positive(v, 1)
+#define arch_atomic64_dec_if_positive(v)       arch_atomic64_sub_if_positive(v, 1)
 #endif
 
 #endif /* _ASM_RISCV_ATOMIC_H */
index 262e5bb..36dc962 100644 (file)
@@ -37,7 +37,7 @@
        __ret;                                                          \
 })
 
-#define xchg_relaxed(ptr, x)                                           \
+#define arch_xchg_relaxed(ptr, x)                                      \
 ({                                                                     \
        __typeof__(*(ptr)) _x_ = (x);                                   \
        (__typeof__(*(ptr))) __xchg_relaxed((ptr),                      \
@@ -72,7 +72,7 @@
        __ret;                                                          \
 })
 
-#define xchg_acquire(ptr, x)                                           \
+#define arch_xchg_acquire(ptr, x)                                      \
 ({                                                                     \
        __typeof__(*(ptr)) _x_ = (x);                                   \
        (__typeof__(*(ptr))) __xchg_acquire((ptr),                      \
        __ret;                                                          \
 })
 
-#define xchg_release(ptr, x)                                           \
+#define arch_xchg_release(ptr, x)                                      \
 ({                                                                     \
        __typeof__(*(ptr)) _x_ = (x);                                   \
        (__typeof__(*(ptr))) __xchg_release((ptr),                      \
        __ret;                                                          \
 })
 
-#define xchg(ptr, x)                                                   \
+#define arch_xchg(ptr, x)                                              \
 ({                                                                     \
        __typeof__(*(ptr)) _x_ = (x);                                   \
        (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr)));        \
 #define xchg32(ptr, x)                                                 \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 4);                              \
-       xchg((ptr), (x));                                               \
+       arch_xchg((ptr), (x));                                          \
 })
 
 #define xchg64(ptr, x)                                                 \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       xchg((ptr), (x));                                               \
+       arch_xchg((ptr), (x));                                          \
 })
 
 /*
        __ret;                                                          \
 })
 
-#define cmpxchg_relaxed(ptr, o, n)                                     \
+#define arch_cmpxchg_relaxed(ptr, o, n)                                        \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
        __ret;                                                          \
 })
 
-#define cmpxchg_acquire(ptr, o, n)                                     \
+#define arch_cmpxchg_acquire(ptr, o, n)                                        \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
        __ret;                                                          \
 })
 
-#define cmpxchg_release(ptr, o, n)                                     \
+#define arch_cmpxchg_release(ptr, o, n)                                        \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
        __ret;                                                          \
 })
 
-#define cmpxchg(ptr, o, n)                                             \
+#define arch_cmpxchg(ptr, o, n)                                                \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
                                       _o_, _n_, sizeof(*(ptr)));       \
 })
 
-#define cmpxchg_local(ptr, o, n)                                       \
+#define arch_cmpxchg_local(ptr, o, n)                                  \
        (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
 
 #define cmpxchg32(ptr, o, n)                                           \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 4);                              \
-       cmpxchg((ptr), (o), (n));                                       \
+       arch_cmpxchg((ptr), (o), (n));                                  \
 })
 
 #define cmpxchg32_local(ptr, o, n)                                     \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 4);                              \
-       cmpxchg_relaxed((ptr), (o), (n))                                \
+       arch_cmpxchg_relaxed((ptr), (o), (n))                           \
 })
 
-#define cmpxchg64(ptr, o, n)                                           \
+#define arch_cmpxchg64(ptr, o, n)                                      \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg((ptr), (o), (n));                                       \
+       arch_cmpxchg((ptr), (o), (n));                                  \
 })
 
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_relaxed((ptr), (o), (n));                               \
+       arch_cmpxchg_relaxed((ptr), (o), (n));                          \
 })
 
 #endif /* _ASM_RISCV_CMPXCHG_H */
index 9469f46..380cd3a 100644 (file)
@@ -30,9 +30,8 @@
 
 #define BPF_JIT_REGION_SIZE    (SZ_128M)
 #ifdef CONFIG_64BIT
-/* KASLR should leave at least 128MB for BPF after the kernel */
-#define BPF_JIT_REGION_START   PFN_ALIGN((unsigned long)&_end)
-#define BPF_JIT_REGION_END     (BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE)
+#define BPF_JIT_REGION_START   (BPF_JIT_REGION_END - BPF_JIT_REGION_SIZE)
+#define BPF_JIT_REGION_END     (MODULES_END)
 #else
 #define BPF_JIT_REGION_START   (PAGE_OFFSET - BPF_JIT_REGION_SIZE)
 #define BPF_JIT_REGION_END     (VMALLOC_END)
index 15cc65a..247e33f 100644 (file)
@@ -279,23 +279,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 9a408e2..bd82375 100644 (file)
@@ -180,7 +180,6 @@ asmlinkage __visible void smp_callin(void)
         * Disable preemption before enabling interrupts, so we don't try to
         * schedule a CPU that hasn't actually started yet.
         */
-       preempt_disable();
        local_irq_enable();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
index bde85fc..ff467b9 100644 (file)
@@ -132,7 +132,7 @@ unsigned long get_wchan(struct task_struct *task)
 {
        unsigned long pc = 0;
 
-       if (likely(task && task != current && task->state != TASK_RUNNING))
+       if (likely(task && task != current && !task_is_running(task)))
                walk_stackframe(task, NULL, save_wchan, &pc);
        return pc;
 }
index 9daacae..d7189c8 100644 (file)
@@ -169,7 +169,7 @@ static void __init kasan_shallow_populate(void *start, void *end)
 
 void __init kasan_init(void)
 {
-       phys_addr_t _start, _end;
+       phys_addr_t p_start, p_end;
        u64 i;
 
        /*
@@ -189,9 +189,9 @@ void __init kasan_init(void)
                        (void *)kasan_mem_to_shadow((void *)VMALLOC_END));
 
        /* Populate the linear mapping */
-       for_each_mem_range(i, &_start, &_end) {
-               void *start = (void *)__va(_start);
-               void *end = (void *)__va(_end);
+       for_each_mem_range(i, &p_start, &p_end) {
+               void *start = (void *)__va(p_start);
+               void *end = (void *)__va(p_end);
 
                if (start >= end)
                        break;
@@ -201,7 +201,7 @@ void __init kasan_init(void)
 
        /* Populate kernel, BPF, modules mapping */
        kasan_populate(kasan_mem_to_shadow((const void *)MODULES_VADDR),
-                      kasan_mem_to_shadow((const void *)BPF_JIT_REGION_END));
+                      kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G));
 
        for (i = 0; i < PTRS_PER_PTE; i++)
                set_pte(&kasan_early_shadow_pte[i],
index 7c93c65..7138d18 100644 (file)
@@ -147,6 +147,4 @@ ATOMIC64_OPS(xor)
 #define arch_atomic64_fetch_sub(_i, _v)  arch_atomic64_fetch_add(-(s64)(_i), _v)
 #define arch_atomic64_sub(_i, _v)       arch_atomic64_add(-(s64)(_i), _v)
 
-#define ARCH_ATOMIC
-
 #endif /* __ARCH_S390_ATOMIC__  */
index 8925f39..9b4473f 100644 (file)
@@ -361,6 +361,7 @@ struct sie_page {
 };
 
 struct kvm_vcpu_stat {
+       struct kvm_vcpu_stat_generic generic;
        u64 exit_userspace;
        u64 exit_null;
        u64 exit_external_request;
@@ -370,13 +371,7 @@ struct kvm_vcpu_stat {
        u64 exit_validity;
        u64 exit_instruction;
        u64 exit_pei;
-       u64 halt_successful_poll;
-       u64 halt_attempted_poll;
-       u64 halt_poll_invalid;
        u64 halt_no_poll_steal;
-       u64 halt_wakeup;
-       u64 halt_poll_success_ns;
-       u64 halt_poll_fail_ns;
        u64 instruction_lctl;
        u64 instruction_lctlg;
        u64 instruction_stctl;
@@ -755,12 +750,12 @@ struct kvm_vcpu_arch {
 };
 
 struct kvm_vm_stat {
+       struct kvm_vm_stat_generic generic;
        u64 inject_io;
        u64 inject_float_mchk;
        u64 inject_pfault_done;
        u64 inject_service_signal;
        u64 inject_virtio;
-       u64 remote_tlb_flush;
 };
 
 struct kvm_arch_memory_slot {
index cc98f9b..479dc76 100644 (file)
@@ -68,9 +68,9 @@ static inline void copy_page(void *to, void *from)
 #define clear_user_page(page, vaddr, pg)       clear_page(page)
 #define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 
 /*
  * These are used to make use of C type-checking..
index b49e049..23ff51b 100644 (file)
@@ -32,7 +32,7 @@ static inline void preempt_count_set(int pc)
 #define init_task_preempt_count(p)     do { } while (0)
 
 #define init_idle_preempt_count(p, cpu)        do { \
-       S390_lowcore.preempt_count = PREEMPT_ENABLED; \
+       S390_lowcore.preempt_count = PREEMPT_DISABLED; \
 } while (0)
 
 static inline void set_preempt_need_resched(void)
@@ -91,7 +91,7 @@ static inline void preempt_count_set(int pc)
 #define init_task_preempt_count(p)     do { } while (0)
 
 #define init_idle_preempt_count(p, cpu)        do { \
-       S390_lowcore.preempt_count = PREEMPT_ENABLED; \
+       S390_lowcore.preempt_count = PREEMPT_DISABLED; \
 } while (0)
 
 static inline void set_preempt_need_resched(void)
index 2b54316..76c6034 100644 (file)
@@ -91,12 +91,16 @@ struct stack_frame {
        CALL_ARGS_4(arg1, arg2, arg3, arg4);                            \
        register unsigned long r4 asm("6") = (unsigned long)(arg5)
 
-#define CALL_FMT_0 "=&d" (r2) :
-#define CALL_FMT_1 "+&d" (r2) :
-#define CALL_FMT_2 CALL_FMT_1 "d" (r3),
-#define CALL_FMT_3 CALL_FMT_2 "d" (r4),
-#define CALL_FMT_4 CALL_FMT_3 "d" (r5),
-#define CALL_FMT_5 CALL_FMT_4 "d" (r6),
+/*
+ * To keep this simple mark register 2-6 as being changed (volatile)
+ * by the called function, even though register 6 is saved/nonvolatile.
+ */
+#define CALL_FMT_0 "=&d" (r2)
+#define CALL_FMT_1 "+&d" (r2)
+#define CALL_FMT_2 CALL_FMT_1, "+&d" (r3)
+#define CALL_FMT_3 CALL_FMT_2, "+&d" (r4)
+#define CALL_FMT_4 CALL_FMT_3, "+&d" (r5)
+#define CALL_FMT_5 CALL_FMT_4, "+&d" (r6)
 
 #define CALL_CLOBBER_5 "0", "1", "14", "cc", "memory"
 #define CALL_CLOBBER_4 CALL_CLOBBER_5
@@ -118,7 +122,7 @@ struct stack_frame {
                "       brasl   14,%[_fn]\n"                            \
                "       la      15,0(%[_prev])\n"                       \
                : [_prev] "=&a" (prev), CALL_FMT_##nr                   \
-                 [_stack] "R" (stack),                                 \
+               : [_stack] "R" (stack),                                 \
                  [_bc] "i" (offsetof(struct stack_frame, back_chain)), \
                  [_frame] "d" (frame),                                 \
                  [_fn] "X" (fn) : CALL_CLOBBER_##nr);                  \
index 12de7a9..e84f495 100644 (file)
@@ -418,6 +418,7 @@ ENTRY(\name)
        xgr     %r6,%r6
        xgr     %r7,%r7
        xgr     %r10,%r10
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
        tm      %r8,0x0001              # coming from user space?
@@ -651,9 +652,9 @@ ENDPROC(stack_overflow)
 .Lcleanup_sie_mcck:
        larl    %r13,.Lsie_entry
        slgr    %r9,%r13
-       larl    %r13,.Lsie_skip
+       lghi    %r13,.Lsie_skip - .Lsie_entry
        clgr    %r9,%r13
-       jh      .Lcleanup_sie_int
+       jhe     .Lcleanup_sie_int
        oi      __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
 .Lcleanup_sie_int:
        BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
index aae24dc..74b0bd2 100644 (file)
@@ -446,23 +446,6 @@ static int kprobe_trap_handler(struct pt_regs *regs, int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(p);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (p->fault_handler && p->fault_handler(p, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index e20bed1..7ae5dde 100644 (file)
@@ -180,7 +180,7 @@ unsigned long get_wchan(struct task_struct *p)
        struct unwind_state state;
        unsigned long ip = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
+       if (!p || p == current || task_is_running(p) || !task_stack_page(p))
                return 0;
 
        if (!try_get_task_stack(p))
index 90163e6..080e7ae 100644 (file)
@@ -512,7 +512,6 @@ void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
 
        /* No handlers present - check for system call restart */
        clear_pt_regs_flag(regs, PIF_SYSCALL);
-       clear_pt_regs_flag(regs, PIF_SYSCALL_RESTART);
        if (current->thread.system_call) {
                regs->int_code = current->thread.system_call;
                switch (regs->gprs[2]) {
index 2fec2b8..111909a 100644 (file)
@@ -878,7 +878,6 @@ static void smp_init_secondary(void)
        restore_access_regs(S390_lowcore.access_regs_save_area);
        cpu_init();
        rcu_cpu_starting(cpu);
-       preempt_disable();
        init_cpu_timer();
        vtime_init();
        vdso_getcpu_init();
index bfcc327..26aa261 100644 (file)
@@ -66,7 +66,10 @@ static void cpu_group_map(cpumask_t *dst, struct mask_info *info, unsigned int c
 {
        static cpumask_t mask;
 
-       cpumask_copy(&mask, cpumask_of(cpu));
+       cpumask_clear(&mask);
+       if (!cpu_online(cpu))
+               goto out;
+       cpumask_set_cpu(cpu, &mask);
        switch (topology_mode) {
        case TOPOLOGY_MODE_HW:
                while (info) {
@@ -83,10 +86,10 @@ static void cpu_group_map(cpumask_t *dst, struct mask_info *info, unsigned int c
        default:
                fallthrough;
        case TOPOLOGY_MODE_SINGLE:
-               cpumask_copy(&mask, cpumask_of(cpu));
                break;
        }
        cpumask_and(&mask, &mask, cpu_online_mask);
+out:
        cpumask_copy(dst, &mask);
 }
 
@@ -95,7 +98,10 @@ static void cpu_thread_map(cpumask_t *dst, unsigned int cpu)
        static cpumask_t mask;
        int i;
 
-       cpumask_copy(&mask, cpumask_of(cpu));
+       cpumask_clear(&mask);
+       if (!cpu_online(cpu))
+               goto out;
+       cpumask_set_cpu(cpu, &mask);
        if (topology_mode != TOPOLOGY_MODE_HW)
                goto out;
        cpu -= cpu % (smp_cpu_mtid + 1);
index 12decca..b3aaadc 100644 (file)
@@ -4,7 +4,8 @@
 # Copyright IBM Corp. 2008
 
 KVM := ../../../virt/kvm
-common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o  $(KVM)/async_pf.o $(KVM)/irqchip.o $(KVM)/vfio.o
+common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o  $(KVM)/async_pf.o \
+             $(KVM)/irqchip.o $(KVM)/vfio.o $(KVM)/binary_stats.o
 
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
index 1296fc1..f9fb1e1 100644 (file)
 #define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
                           (KVM_MAX_VCPUS + LOCAL_IRQS))
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("userspace_handled", exit_userspace),
-       VCPU_STAT("exit_null", exit_null),
-       VCPU_STAT("pfault_sync", pfault_sync),
-       VCPU_STAT("exit_validity", exit_validity),
-       VCPU_STAT("exit_stop_request", exit_stop_request),
-       VCPU_STAT("exit_external_request", exit_external_request),
-       VCPU_STAT("exit_io_request", exit_io_request),
-       VCPU_STAT("exit_external_interrupt", exit_external_interrupt),
-       VCPU_STAT("exit_instruction", exit_instruction),
-       VCPU_STAT("exit_pei", exit_pei),
-       VCPU_STAT("exit_program_interruption", exit_program_interruption),
-       VCPU_STAT("exit_instr_and_program_int", exit_instr_and_program),
-       VCPU_STAT("exit_operation_exception", exit_operation_exception),
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_no_poll_steal", halt_no_poll_steal),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       VCPU_STAT("instruction_lctlg", instruction_lctlg),
-       VCPU_STAT("instruction_lctl", instruction_lctl),
-       VCPU_STAT("instruction_stctl", instruction_stctl),
-       VCPU_STAT("instruction_stctg", instruction_stctg),
-       VCPU_STAT("deliver_ckc", deliver_ckc),
-       VCPU_STAT("deliver_cputm", deliver_cputm),
-       VCPU_STAT("deliver_emergency_signal", deliver_emergency_signal),
-       VCPU_STAT("deliver_external_call", deliver_external_call),
-       VCPU_STAT("deliver_service_signal", deliver_service_signal),
-       VCPU_STAT("deliver_virtio", deliver_virtio),
-       VCPU_STAT("deliver_stop_signal", deliver_stop_signal),
-       VCPU_STAT("deliver_prefix_signal", deliver_prefix_signal),
-       VCPU_STAT("deliver_restart_signal", deliver_restart_signal),
-       VCPU_STAT("deliver_program", deliver_program),
-       VCPU_STAT("deliver_io", deliver_io),
-       VCPU_STAT("deliver_machine_check", deliver_machine_check),
-       VCPU_STAT("exit_wait_state", exit_wait_state),
-       VCPU_STAT("inject_ckc", inject_ckc),
-       VCPU_STAT("inject_cputm", inject_cputm),
-       VCPU_STAT("inject_external_call", inject_external_call),
-       VM_STAT("inject_float_mchk", inject_float_mchk),
-       VCPU_STAT("inject_emergency_signal", inject_emergency_signal),
-       VM_STAT("inject_io", inject_io),
-       VCPU_STAT("inject_mchk", inject_mchk),
-       VM_STAT("inject_pfault_done", inject_pfault_done),
-       VCPU_STAT("inject_program", inject_program),
-       VCPU_STAT("inject_restart", inject_restart),
-       VM_STAT("inject_service_signal", inject_service_signal),
-       VCPU_STAT("inject_set_prefix", inject_set_prefix),
-       VCPU_STAT("inject_stop_signal", inject_stop_signal),
-       VCPU_STAT("inject_pfault_init", inject_pfault_init),
-       VM_STAT("inject_virtio", inject_virtio),
-       VCPU_STAT("instruction_epsw", instruction_epsw),
-       VCPU_STAT("instruction_gs", instruction_gs),
-       VCPU_STAT("instruction_io_other", instruction_io_other),
-       VCPU_STAT("instruction_lpsw", instruction_lpsw),
-       VCPU_STAT("instruction_lpswe", instruction_lpswe),
-       VCPU_STAT("instruction_pfmf", instruction_pfmf),
-       VCPU_STAT("instruction_ptff", instruction_ptff),
-       VCPU_STAT("instruction_stidp", instruction_stidp),
-       VCPU_STAT("instruction_sck", instruction_sck),
-       VCPU_STAT("instruction_sckpf", instruction_sckpf),
-       VCPU_STAT("instruction_spx", instruction_spx),
-       VCPU_STAT("instruction_stpx", instruction_stpx),
-       VCPU_STAT("instruction_stap", instruction_stap),
-       VCPU_STAT("instruction_iske", instruction_iske),
-       VCPU_STAT("instruction_ri", instruction_ri),
-       VCPU_STAT("instruction_rrbe", instruction_rrbe),
-       VCPU_STAT("instruction_sske", instruction_sske),
-       VCPU_STAT("instruction_ipte_interlock", instruction_ipte_interlock),
-       VCPU_STAT("instruction_essa", instruction_essa),
-       VCPU_STAT("instruction_stsi", instruction_stsi),
-       VCPU_STAT("instruction_stfl", instruction_stfl),
-       VCPU_STAT("instruction_tb", instruction_tb),
-       VCPU_STAT("instruction_tpi", instruction_tpi),
-       VCPU_STAT("instruction_tprot", instruction_tprot),
-       VCPU_STAT("instruction_tsch", instruction_tsch),
-       VCPU_STAT("instruction_sthyi", instruction_sthyi),
-       VCPU_STAT("instruction_sie", instruction_sie),
-       VCPU_STAT("instruction_sigp_sense", instruction_sigp_sense),
-       VCPU_STAT("instruction_sigp_sense_running", instruction_sigp_sense_running),
-       VCPU_STAT("instruction_sigp_external_call", instruction_sigp_external_call),
-       VCPU_STAT("instruction_sigp_emergency", instruction_sigp_emergency),
-       VCPU_STAT("instruction_sigp_cond_emergency", instruction_sigp_cond_emergency),
-       VCPU_STAT("instruction_sigp_start", instruction_sigp_start),
-       VCPU_STAT("instruction_sigp_stop", instruction_sigp_stop),
-       VCPU_STAT("instruction_sigp_stop_store_status", instruction_sigp_stop_store_status),
-       VCPU_STAT("instruction_sigp_store_status", instruction_sigp_store_status),
-       VCPU_STAT("instruction_sigp_store_adtl_status", instruction_sigp_store_adtl_status),
-       VCPU_STAT("instruction_sigp_set_arch", instruction_sigp_arch),
-       VCPU_STAT("instruction_sigp_set_prefix", instruction_sigp_prefix),
-       VCPU_STAT("instruction_sigp_restart", instruction_sigp_restart),
-       VCPU_STAT("instruction_sigp_cpu_reset", instruction_sigp_cpu_reset),
-       VCPU_STAT("instruction_sigp_init_cpu_reset", instruction_sigp_init_cpu_reset),
-       VCPU_STAT("instruction_sigp_unknown", instruction_sigp_unknown),
-       VCPU_STAT("instruction_diag_10", diagnose_10),
-       VCPU_STAT("instruction_diag_44", diagnose_44),
-       VCPU_STAT("instruction_diag_9c", diagnose_9c),
-       VCPU_STAT("diag_9c_ignored", diagnose_9c_ignored),
-       VCPU_STAT("diag_9c_forward", diagnose_9c_forward),
-       VCPU_STAT("instruction_diag_258", diagnose_258),
-       VCPU_STAT("instruction_diag_308", diagnose_308),
-       VCPU_STAT("instruction_diag_500", diagnose_500),
-       VCPU_STAT("instruction_diag_other", diagnose_other),
-       { NULL }
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS(),
+       STATS_DESC_COUNTER(VM, inject_io),
+       STATS_DESC_COUNTER(VM, inject_float_mchk),
+       STATS_DESC_COUNTER(VM, inject_pfault_done),
+       STATS_DESC_COUNTER(VM, inject_service_signal),
+       STATS_DESC_COUNTER(VM, inject_virtio)
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, exit_userspace),
+       STATS_DESC_COUNTER(VCPU, exit_null),
+       STATS_DESC_COUNTER(VCPU, exit_external_request),
+       STATS_DESC_COUNTER(VCPU, exit_io_request),
+       STATS_DESC_COUNTER(VCPU, exit_external_interrupt),
+       STATS_DESC_COUNTER(VCPU, exit_stop_request),
+       STATS_DESC_COUNTER(VCPU, exit_validity),
+       STATS_DESC_COUNTER(VCPU, exit_instruction),
+       STATS_DESC_COUNTER(VCPU, exit_pei),
+       STATS_DESC_COUNTER(VCPU, halt_no_poll_steal),
+       STATS_DESC_COUNTER(VCPU, instruction_lctl),
+       STATS_DESC_COUNTER(VCPU, instruction_lctlg),
+       STATS_DESC_COUNTER(VCPU, instruction_stctl),
+       STATS_DESC_COUNTER(VCPU, instruction_stctg),
+       STATS_DESC_COUNTER(VCPU, exit_program_interruption),
+       STATS_DESC_COUNTER(VCPU, exit_instr_and_program),
+       STATS_DESC_COUNTER(VCPU, exit_operation_exception),
+       STATS_DESC_COUNTER(VCPU, deliver_ckc),
+       STATS_DESC_COUNTER(VCPU, deliver_cputm),
+       STATS_DESC_COUNTER(VCPU, deliver_external_call),
+       STATS_DESC_COUNTER(VCPU, deliver_emergency_signal),
+       STATS_DESC_COUNTER(VCPU, deliver_service_signal),
+       STATS_DESC_COUNTER(VCPU, deliver_virtio),
+       STATS_DESC_COUNTER(VCPU, deliver_stop_signal),
+       STATS_DESC_COUNTER(VCPU, deliver_prefix_signal),
+       STATS_DESC_COUNTER(VCPU, deliver_restart_signal),
+       STATS_DESC_COUNTER(VCPU, deliver_program),
+       STATS_DESC_COUNTER(VCPU, deliver_io),
+       STATS_DESC_COUNTER(VCPU, deliver_machine_check),
+       STATS_DESC_COUNTER(VCPU, exit_wait_state),
+       STATS_DESC_COUNTER(VCPU, inject_ckc),
+       STATS_DESC_COUNTER(VCPU, inject_cputm),
+       STATS_DESC_COUNTER(VCPU, inject_external_call),
+       STATS_DESC_COUNTER(VCPU, inject_emergency_signal),
+       STATS_DESC_COUNTER(VCPU, inject_mchk),
+       STATS_DESC_COUNTER(VCPU, inject_pfault_init),
+       STATS_DESC_COUNTER(VCPU, inject_program),
+       STATS_DESC_COUNTER(VCPU, inject_restart),
+       STATS_DESC_COUNTER(VCPU, inject_set_prefix),
+       STATS_DESC_COUNTER(VCPU, inject_stop_signal),
+       STATS_DESC_COUNTER(VCPU, instruction_epsw),
+       STATS_DESC_COUNTER(VCPU, instruction_gs),
+       STATS_DESC_COUNTER(VCPU, instruction_io_other),
+       STATS_DESC_COUNTER(VCPU, instruction_lpsw),
+       STATS_DESC_COUNTER(VCPU, instruction_lpswe),
+       STATS_DESC_COUNTER(VCPU, instruction_pfmf),
+       STATS_DESC_COUNTER(VCPU, instruction_ptff),
+       STATS_DESC_COUNTER(VCPU, instruction_sck),
+       STATS_DESC_COUNTER(VCPU, instruction_sckpf),
+       STATS_DESC_COUNTER(VCPU, instruction_stidp),
+       STATS_DESC_COUNTER(VCPU, instruction_spx),
+       STATS_DESC_COUNTER(VCPU, instruction_stpx),
+       STATS_DESC_COUNTER(VCPU, instruction_stap),
+       STATS_DESC_COUNTER(VCPU, instruction_iske),
+       STATS_DESC_COUNTER(VCPU, instruction_ri),
+       STATS_DESC_COUNTER(VCPU, instruction_rrbe),
+       STATS_DESC_COUNTER(VCPU, instruction_sske),
+       STATS_DESC_COUNTER(VCPU, instruction_ipte_interlock),
+       STATS_DESC_COUNTER(VCPU, instruction_stsi),
+       STATS_DESC_COUNTER(VCPU, instruction_stfl),
+       STATS_DESC_COUNTER(VCPU, instruction_tb),
+       STATS_DESC_COUNTER(VCPU, instruction_tpi),
+       STATS_DESC_COUNTER(VCPU, instruction_tprot),
+       STATS_DESC_COUNTER(VCPU, instruction_tsch),
+       STATS_DESC_COUNTER(VCPU, instruction_sie),
+       STATS_DESC_COUNTER(VCPU, instruction_essa),
+       STATS_DESC_COUNTER(VCPU, instruction_sthyi),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_sense),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_sense_running),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_external_call),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_emergency),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_cond_emergency),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_start),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_stop),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_stop_store_status),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_store_status),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_store_adtl_status),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_arch),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_prefix),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_restart),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_init_cpu_reset),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_cpu_reset),
+       STATS_DESC_COUNTER(VCPU, instruction_sigp_unknown),
+       STATS_DESC_COUNTER(VCPU, diagnose_10),
+       STATS_DESC_COUNTER(VCPU, diagnose_44),
+       STATS_DESC_COUNTER(VCPU, diagnose_9c),
+       STATS_DESC_COUNTER(VCPU, diagnose_9c_ignored),
+       STATS_DESC_COUNTER(VCPU, diagnose_9c_forward),
+       STATS_DESC_COUNTER(VCPU, diagnose_258),
+       STATS_DESC_COUNTER(VCPU, diagnose_308),
+       STATS_DESC_COUNTER(VCPU, diagnose_500),
+       STATS_DESC_COUNTER(VCPU, diagnose_other),
+       STATS_DESC_COUNTER(VCPU, pfault_sync)
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 /* allow nested virtualization in KVM (if enabled by user space) */
@@ -329,31 +349,31 @@ static void allow_cpu_feat(unsigned long nr)
 
 static inline int plo_test_bit(unsigned char nr)
 {
-       register unsigned long r0 asm("0") = (unsigned long) nr | 0x100;
+       unsigned long function = (unsigned long)nr | 0x100;
        int cc;
 
        asm volatile(
+               "       lgr     0,%[function]\n"
                /* Parameter registers are ignored for "test bit" */
                "       plo     0,0,0,0(0)\n"
                "       ipm     %0\n"
                "       srl     %0,28\n"
                : "=d" (cc)
-               : "d" (r0)
-               : "cc");
+               : [function] "d" (function)
+               : "cc", "0");
        return cc == 0;
 }
 
 static __always_inline void __insn32_query(unsigned int opcode, u8 *query)
 {
-       register unsigned long r0 asm("0") = 0; /* query function */
-       register unsigned long r1 asm("1") = (unsigned long) query;
-
        asm volatile(
-               /* Parameter regs are ignored */
+               "       lghi    0,0\n"
+               "       lgr     1,%[query]\n"
+               /* Parameter registers are ignored */
                "       .insn   rrf,%[opc] << 16,2,4,6,0\n"
                :
-               : "d" (r0), "a" (r1), [opc] "i" (opcode)
-               : "cc", "memory");
+               : [query] "d" ((unsigned long)query), [opc] "i" (opcode)
+               : "cc", "memory", "0", "1");
 }
 
 #define INSN_SORTL 0xb938
@@ -713,6 +733,10 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                                set_kvm_facility(kvm->arch.model.fac_mask, 152);
                                set_kvm_facility(kvm->arch.model.fac_list, 152);
                        }
+                       if (test_facility(192)) {
+                               set_kvm_facility(kvm->arch.model.fac_mask, 192);
+                               set_kvm_facility(kvm->arch.model.fac_list, 192);
+                       }
                        r = 0;
                } else
                        r = -EINVAL;
index 813b6e9..c8841f4 100644 (file)
@@ -140,7 +140,12 @@ static int kvm_s390_pv_alloc_vm(struct kvm *kvm)
        /* Allocate variable storage */
        vlen = ALIGN(virt * ((npages * PAGE_SIZE) / HPAGE_SIZE), PAGE_SIZE);
        vlen += uv_info.guest_virt_base_stor_len;
-       kvm->arch.pv.stor_var = vzalloc(vlen);
+       /*
+        * The Create Secure Configuration Ultravisor Call does not support
+        * using large pages for the virtual memory area.
+        * This is a hardware limitation.
+        */
+       kvm->arch.pv.stor_var = vmalloc_no_huge(vlen);
        if (!kvm->arch.pv.stor_var)
                goto out_err;
        return 0;
index 826d017..8ae3dc5 100644 (file)
@@ -702,7 +702,7 @@ static void pfault_interrupt(struct ext_code ext_code,
                         * interrupt since it must be a leftover of a PFAULT
                         * CANCEL operation which didn't remove all pending
                         * completion interrupts. */
-                       if (tsk->state == TASK_RUNNING)
+                       if (task_is_running(tsk))
                                tsk->thread.pfault_wait = -1;
                }
        } else {
index 61ce5b5..606324e 100644 (file)
@@ -115,6 +115,10 @@ static struct facility_def facility_defs[] = {
                        12, /* AP Query Configuration Information */
                        15, /* AP Facilities Test */
                        156, /* etoken facility */
+                       165, /* nnpa facility */
+                       193, /* bear enhancement facility */
+                       194, /* rdp enhancement facility */
+                       196, /* processor activity instrumentation facility */
                        -1  /* END */
                }
        },
index aace62d..059791f 100644 (file)
@@ -3,7 +3,7 @@
 #define __ASM_SH_ATOMIC_GRB_H
 
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        int tmp;                                                        \
                                                                        \
@@ -23,7 +23,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        int tmp;                                                        \
                                                                        \
@@ -45,7 +45,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        int res, tmp;                                                   \
                                                                        \
index ee523bd..7665de9 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 #define ATOMIC_OP(op, c_op)                                            \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -21,7 +21,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }
 
 #define ATOMIC_OP_RETURN(op, c_op)                                     \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long temp, flags;                                      \
                                                                        \
@@ -35,7 +35,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op)                                      \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned long temp, flags;                                      \
                                                                        \
index 1d06e4d..b63dcfb 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long tmp;                                              \
                                                                        \
@@ -32,7 +32,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long temp;                                             \
                                                                        \
@@ -50,7 +50,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned long res, temp;                                        \
                                                                        \
index 7c2a8a7..528bfed 100644 (file)
@@ -19,8 +19,8 @@
 #include <asm/cmpxchg.h>
 #include <asm/barrier.h>
 
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic_set(v,i)                WRITE_ONCE((v)->counter, (i))
+#define arch_atomic_read(v)            READ_ONCE((v)->counter)
+#define arch_atomic_set(v,i)           WRITE_ONCE((v)->counter, (i))
 
 #if defined(CONFIG_GUSA_RB)
 #include <asm/atomic-grb.h>
@@ -30,8 +30,8 @@
 #include <asm/atomic-irq.h>
 #endif
 
-#define atomic_xchg(v, new)            (xchg(&((v)->counter), new))
-#define atomic_cmpxchg(v, o, n)                (cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_xchg(v, new)       (arch_xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, o, n)   (arch_cmpxchg(&((v)->counter), (o), (n)))
 
 #endif /* CONFIG_CPU_J2 */
 
index e9501d8..0ed9b3f 100644 (file)
@@ -45,7 +45,7 @@ extern void __xchg_called_with_bad_pointer(void);
        __xchg__res;                                    \
 })
 
-#define xchg(ptr,x)    \
+#define arch_xchg(ptr,x)       \
        ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
 
 /* This function doesn't exist, so you'll get a linker error
@@ -63,7 +63,7 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
+#define arch_cmpxchg(ptr,o,n)                                           \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
index 756100b..1c7f358 100644 (file)
@@ -383,23 +383,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 1aa508e..717de05 100644 (file)
@@ -186,7 +186,7 @@ unsigned long get_wchan(struct task_struct *p)
 {
        unsigned long pc;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        /*
index 372acdc..65924d9 100644 (file)
@@ -186,8 +186,6 @@ asmlinkage void start_secondary(void)
 
        per_cpu_trap_init();
 
-       preempt_disable();
-
        notify_cpu_starting(cpu);
 
        local_irq_enable();
index efad553..d775daa 100644 (file)
 #include <asm/barrier.h>
 #include <asm-generic/atomic64.h>
 
-int atomic_add_return(int, atomic_t *);
-int atomic_fetch_add(int, atomic_t *);
-int atomic_fetch_and(int, atomic_t *);
-int atomic_fetch_or(int, atomic_t *);
-int atomic_fetch_xor(int, atomic_t *);
-int atomic_cmpxchg(atomic_t *, int, int);
-int atomic_xchg(atomic_t *, int);
-int atomic_fetch_add_unless(atomic_t *, int, int);
-void atomic_set(atomic_t *, int);
+int arch_atomic_add_return(int, atomic_t *);
+int arch_atomic_fetch_add(int, atomic_t *);
+int arch_atomic_fetch_and(int, atomic_t *);
+int arch_atomic_fetch_or(int, atomic_t *);
+int arch_atomic_fetch_xor(int, atomic_t *);
+int arch_atomic_cmpxchg(atomic_t *, int, int);
+int arch_atomic_xchg(atomic_t *, int);
+int arch_atomic_fetch_add_unless(atomic_t *, int, int);
+void arch_atomic_set(atomic_t *, int);
 
-#define atomic_fetch_add_unless        atomic_fetch_add_unless
+#define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
 
-#define atomic_set_release(v, i)       atomic_set((v), (i))
+#define arch_atomic_set_release(v, i)  arch_atomic_set((v), (i))
 
-#define atomic_read(v)          READ_ONCE((v)->counter)
+#define arch_atomic_read(v)            READ_ONCE((v)->counter)
 
-#define atomic_add(i, v)       ((void)atomic_add_return( (int)(i), (v)))
-#define atomic_sub(i, v)       ((void)atomic_add_return(-(int)(i), (v)))
+#define arch_atomic_add(i, v)  ((void)arch_atomic_add_return( (int)(i), (v)))
+#define arch_atomic_sub(i, v)  ((void)arch_atomic_add_return(-(int)(i), (v)))
 
-#define atomic_and(i, v)       ((void)atomic_fetch_and((i), (v)))
-#define atomic_or(i, v)                ((void)atomic_fetch_or((i), (v)))
-#define atomic_xor(i, v)       ((void)atomic_fetch_xor((i), (v)))
+#define arch_atomic_and(i, v)  ((void)arch_atomic_fetch_and((i), (v)))
+#define arch_atomic_or(i, v)   ((void)arch_atomic_fetch_or((i), (v)))
+#define arch_atomic_xor(i, v)  ((void)arch_atomic_fetch_xor((i), (v)))
 
-#define atomic_sub_return(i, v)        (atomic_add_return(-(int)(i), (v)))
-#define atomic_fetch_sub(i, v)  (atomic_fetch_add (-(int)(i), (v)))
+#define arch_atomic_sub_return(i, v)   (arch_atomic_add_return(-(int)(i), (v)))
+#define arch_atomic_fetch_sub(i, v)    (arch_atomic_fetch_add (-(int)(i), (v)))
 
 #endif /* !(__ARCH_SPARC_ATOMIC__) */
index 6b235d3..0778916 100644 (file)
 
 #define ATOMIC64_INIT(i)       { (i) }
 
-#define atomic_read(v)         READ_ONCE((v)->counter)
-#define atomic64_read(v)       READ_ONCE((v)->counter)
+#define arch_atomic_read(v)    READ_ONCE((v)->counter)
+#define arch_atomic64_read(v)  READ_ONCE((v)->counter)
 
-#define atomic_set(v, i)       WRITE_ONCE(((v)->counter), (i))
-#define atomic64_set(v, i)     WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_set(v, i)  WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic64_set(v, i)        WRITE_ONCE(((v)->counter), (i))
 
 #define ATOMIC_OP(op)                                                  \
-void atomic_##op(int, atomic_t *);                                     \
-void atomic64_##op(s64, atomic64_t *);
+void arch_atomic_##op(int, atomic_t *);                                        \
+void arch_atomic64_##op(s64, atomic64_t *);
 
 #define ATOMIC_OP_RETURN(op)                                           \
-int atomic_##op##_return(int, atomic_t *);                             \
-s64 atomic64_##op##_return(s64, atomic64_t *);
+int arch_atomic_##op##_return(int, atomic_t *);                                \
+s64 arch_atomic64_##op##_return(s64, atomic64_t *);
 
 #define ATOMIC_FETCH_OP(op)                                            \
-int atomic_fetch_##op(int, atomic_t *);                                        \
-s64 atomic64_fetch_##op(s64, atomic64_t *);
+int arch_atomic_fetch_##op(int, atomic_t *);                           \
+s64 arch_atomic64_fetch_##op(s64, atomic64_t *);
 
 #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
 
@@ -49,18 +49,18 @@ ATOMIC_OPS(xor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_cmpxchg(v, o, n) (arch_cmpxchg(&((v)->counter), (o), (n)))
 
-static inline int atomic_xchg(atomic_t *v, int new)
+static inline int arch_atomic_xchg(atomic_t *v, int new)
 {
-       return xchg(&v->counter, new);
+       return arch_xchg(&v->counter, new);
 }
 
-#define atomic64_cmpxchg(v, o, n) \
-       ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
-#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic64_cmpxchg(v, o, n) \
+       ((__typeof__((v)->counter))arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
-s64 atomic64_dec_if_positive(atomic64_t *v);
-#define atomic64_dec_if_positive atomic64_dec_if_positive
+s64 arch_atomic64_dec_if_positive(atomic64_t *v);
+#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
 
 #endif /* !(__ARCH_SPARC64_ATOMIC__) */
index a53d744..27a57a3 100644 (file)
@@ -25,7 +25,7 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int
        return x;
 }
 
-#define xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
+#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));})
 
 /* Emulate cmpxchg() the same way we emulate atomics,
  * by hashing the object address and indexing into an array
@@ -55,7 +55,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
        return old;
 }
 
-#define cmpxchg(ptr, o, n)                                             \
+#define arch_cmpxchg(ptr, o, n)                                                \
 ({                                                                     \
        __typeof__(*(ptr)) _o_ = (o);                                   \
        __typeof__(*(ptr)) _n_ = (n);                                   \
@@ -64,7 +64,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
 })
 
 u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new);
-#define cmpxchg64(ptr, old, new)       __cmpxchg_u64(ptr, old, new)
+#define arch_cmpxchg64(ptr, old, new)  __cmpxchg_u64(ptr, old, new)
 
 #include <asm-generic/cmpxchg-local.h>
 
@@ -72,9 +72,9 @@ u64 __cmpxchg_u64(u64 *ptr, u64 old, u64 new);
  * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
  * them available.
  */
-#define cmpxchg_local(ptr, o, n)                                              \
-       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+#define arch_cmpxchg_local(ptr, o, n)                                         \
+       ((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o),\
                        (unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
 
 #endif /* __ARCH_SPARC_CMPXCHG__ */
index 316faa0..8c39a99 100644 (file)
@@ -52,7 +52,7 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long
        return val;
 }
 
-#define xchg(ptr,x)                                                    \
+#define arch_xchg(ptr,x)                                                       \
 ({     __typeof__(*(ptr)) __ret;                                       \
        __ret = (__typeof__(*(ptr)))                                    \
                __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)));      \
@@ -168,7 +168,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        return old;
 }
 
-#define cmpxchg(ptr,o,n)                                                \
+#define arch_cmpxchg(ptr,o,n)                                           \
   ({                                                                    \
      __typeof__(*(ptr)) _o_ = (o);                                      \
      __typeof__(*(ptr)) _n_ = (n);                                      \
@@ -189,20 +189,20 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        case 4:
        case 8: return __cmpxchg(ptr, old, new, size);
        default:
-               return __cmpxchg_local_generic(ptr, old, new, size);
+               return __generic_cmpxchg_local(ptr, old, new, size);
        }
 
        return old;
 }
 
-#define cmpxchg_local(ptr, o, n)                                       \
+#define arch_cmpxchg_local(ptr, o, n)                                  \
        ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
                        (unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n)                                     \
+#define arch_cmpxchg64_local(ptr, o, n)                                        \
   ({                                                                   \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg_local((ptr), (o), (n));                                 \
   })
-#define cmpxchg64(ptr, o, n)   cmpxchg64_local((ptr), (o), (n))
+#define arch_cmpxchg64(ptr, o, n)      arch_cmpxchg64_local((ptr), (o), (n))
 
 #endif /* __ARCH_SPARC64_CMPXCHG__ */
index 217c21a..4c05a4e 100644 (file)
@@ -346,23 +346,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        case KPROBE_HIT_ACTIVE:
        case KPROBE_HIT_SSDONE:
                /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-
-               /*
                 * In case the user-specified fault handler returned
                 * zero, try to fix up.
                 */
index 3b97949..93983d6 100644 (file)
@@ -376,8 +376,7 @@ unsigned long get_wchan(struct task_struct *task)
        struct reg_window32 *rw;
        int count = 0;
 
-       if (!task || task == current ||
-            task->state == TASK_RUNNING)
+       if (!task || task == current || task_is_running(task))
                goto out;
 
        fp = task_thread_info(task)->ksp + bias;
index 7afd0a8..d33c58a 100644 (file)
@@ -674,8 +674,7 @@ unsigned long get_wchan(struct task_struct *task)
         unsigned long ret = 0;
        int count = 0; 
 
-       if (!task || task == current ||
-            task->state == TASK_RUNNING)
+       if (!task || task == current || task_is_running(task))
                goto out;
 
        tp = task_thread_info(task);
index 50c127a..22b148e 100644 (file)
@@ -348,7 +348,6 @@ static void sparc_start_secondary(void *arg)
         */
        arch_cpu_pre_starting(arg);
 
-       preempt_disable();
        cpu = smp_processor_id();
 
        notify_cpu_starting(cpu);
index e38d8bf..ae5faa1 100644 (file)
@@ -138,9 +138,6 @@ void smp_callin(void)
 
        set_cpu_online(cpuid, true);
 
-       /* idle thread is expected to have preempt disabled */
-       preempt_disable();
-
        local_irq_enable();
 
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
index 281fa63..8b81d0f 100644 (file)
@@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(dummy);
 #endif /* SMP */
 
 #define ATOMIC_FETCH_OP(op, c_op)                                      \
-int atomic_fetch_##op(int i, atomic_t *v)                              \
+int arch_atomic_fetch_##op(int i, atomic_t *v)                         \
 {                                                                      \
        int ret;                                                        \
        unsigned long flags;                                            \
@@ -41,10 +41,10 @@ int atomic_fetch_##op(int i, atomic_t *v)                           \
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);                  \
        return ret;                                                     \
 }                                                                      \
-EXPORT_SYMBOL(atomic_fetch_##op);
+EXPORT_SYMBOL(arch_atomic_fetch_##op);
 
 #define ATOMIC_OP_RETURN(op, c_op)                                     \
-int atomic_##op##_return(int i, atomic_t *v)                           \
+int arch_atomic_##op##_return(int i, atomic_t *v)                      \
 {                                                                      \
        int ret;                                                        \
        unsigned long flags;                                            \
@@ -55,7 +55,7 @@ int atomic_##op##_return(int i, atomic_t *v)                          \
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);                  \
        return ret;                                                     \
 }                                                                      \
-EXPORT_SYMBOL(atomic_##op##_return);
+EXPORT_SYMBOL(arch_atomic_##op##_return);
 
 ATOMIC_OP_RETURN(add, +=)
 
@@ -67,7 +67,7 @@ ATOMIC_FETCH_OP(xor, ^=)
 #undef ATOMIC_FETCH_OP
 #undef ATOMIC_OP_RETURN
 
-int atomic_xchg(atomic_t *v, int new)
+int arch_atomic_xchg(atomic_t *v, int new)
 {
        int ret;
        unsigned long flags;
@@ -78,9 +78,9 @@ int atomic_xchg(atomic_t *v, int new)
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
        return ret;
 }
-EXPORT_SYMBOL(atomic_xchg);
+EXPORT_SYMBOL(arch_atomic_xchg);
 
-int atomic_cmpxchg(atomic_t *v, int old, int new)
+int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        int ret;
        unsigned long flags;
@@ -93,9 +93,9 @@ int atomic_cmpxchg(atomic_t *v, int old, int new)
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
        return ret;
 }
-EXPORT_SYMBOL(atomic_cmpxchg);
+EXPORT_SYMBOL(arch_atomic_cmpxchg);
 
-int atomic_fetch_add_unless(atomic_t *v, int a, int u)
+int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        int ret;
        unsigned long flags;
@@ -107,10 +107,10 @@ int atomic_fetch_add_unless(atomic_t *v, int a, int u)
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
        return ret;
 }
-EXPORT_SYMBOL(atomic_fetch_add_unless);
+EXPORT_SYMBOL(arch_atomic_fetch_add_unless);
 
 /* Atomic operations are already serializing */
-void atomic_set(atomic_t *v, int i)
+void arch_atomic_set(atomic_t *v, int i)
 {
        unsigned long flags;
 
@@ -118,7 +118,7 @@ void atomic_set(atomic_t *v, int i)
        v->counter = i;
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
 }
-EXPORT_SYMBOL(atomic_set);
+EXPORT_SYMBOL(arch_atomic_set);
 
 unsigned long ___set_bit(unsigned long *addr, unsigned long mask)
 {
index 456b65a..8245d4a 100644 (file)
@@ -19,7 +19,7 @@
         */
 
 #define ATOMIC_OP(op)                                                  \
-ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */             \
+ENTRY(arch_atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */                \
        BACKOFF_SETUP(%o2);                                             \
 1:     lduw    [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -30,11 +30,11 @@ ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */          \
        retl;                                                           \
         nop;                                                           \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic_##op);                                                  \
-EXPORT_SYMBOL(atomic_##op);
+ENDPROC(arch_atomic_##op);                                             \
+EXPORT_SYMBOL(arch_atomic_##op);
 
 #define ATOMIC_OP_RETURN(op)                                           \
-ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */    \
+ENTRY(arch_atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */\
        BACKOFF_SETUP(%o2);                                             \
 1:     lduw    [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -45,11 +45,11 @@ ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \
        retl;                                                           \
         sra    %g1, 0, %o0;                                            \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic_##op##_return);                                         \
-EXPORT_SYMBOL(atomic_##op##_return);
+ENDPROC(arch_atomic_##op##_return);                                    \
+EXPORT_SYMBOL(arch_atomic_##op##_return);
 
 #define ATOMIC_FETCH_OP(op)                                            \
-ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */       \
+ENTRY(arch_atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */  \
        BACKOFF_SETUP(%o2);                                             \
 1:     lduw    [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -60,8 +60,8 @@ ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */      \
        retl;                                                           \
         sra    %g1, 0, %o0;                                            \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic_fetch_##op);                                            \
-EXPORT_SYMBOL(atomic_fetch_##op);
+ENDPROC(arch_atomic_fetch_##op);                                       \
+EXPORT_SYMBOL(arch_atomic_fetch_##op);
 
 ATOMIC_OP(add)
 ATOMIC_OP_RETURN(add)
@@ -85,7 +85,7 @@ ATOMIC_FETCH_OP(xor)
 #undef ATOMIC_OP
 
 #define ATOMIC64_OP(op)                                                        \
-ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */           \
+ENTRY(arch_atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */      \
        BACKOFF_SETUP(%o2);                                             \
 1:     ldx     [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -96,11 +96,11 @@ ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */                \
        retl;                                                           \
         nop;                                                           \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic64_##op);                                                        \
-EXPORT_SYMBOL(atomic64_##op);
+ENDPROC(arch_atomic64_##op);                                           \
+EXPORT_SYMBOL(arch_atomic64_##op);
 
 #define ATOMIC64_OP_RETURN(op)                                         \
-ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */  \
+ENTRY(arch_atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */     \
        BACKOFF_SETUP(%o2);                                             \
 1:     ldx     [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -111,11 +111,11 @@ ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */     \
        retl;                                                           \
         op     %g1, %o0, %o0;                                          \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic64_##op##_return);                                       \
-EXPORT_SYMBOL(atomic64_##op##_return);
+ENDPROC(arch_atomic64_##op##_return);                                  \
+EXPORT_SYMBOL(arch_atomic64_##op##_return);
 
 #define ATOMIC64_FETCH_OP(op)                                          \
-ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */     \
+ENTRY(arch_atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */        \
        BACKOFF_SETUP(%o2);                                             \
 1:     ldx     [%o1], %g1;                                             \
        op      %g1, %o0, %g7;                                          \
@@ -126,8 +126,8 @@ ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */  \
        retl;                                                           \
         mov    %g1, %o0;                                               \
 2:     BACKOFF_SPIN(%o2, %o3, 1b);                                     \
-ENDPROC(atomic64_fetch_##op);                                          \
-EXPORT_SYMBOL(atomic64_fetch_##op);
+ENDPROC(arch_atomic64_fetch_##op);                                     \
+EXPORT_SYMBOL(arch_atomic64_fetch_##op);
 
 ATOMIC64_OP(add)
 ATOMIC64_OP_RETURN(add)
@@ -150,7 +150,7 @@ ATOMIC64_FETCH_OP(xor)
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
-ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
+ENTRY(arch_atomic64_dec_if_positive) /* %o0 = atomic_ptr */
        BACKOFF_SETUP(%o2)
 1:     ldx     [%o0], %g1
        brlez,pn %g1, 3f
@@ -162,5 +162,5 @@ ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
 3:     retl
         sub    %g1, 1, %o0
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
-ENDPROC(atomic64_dec_if_positive)
-EXPORT_SYMBOL(atomic64_dec_if_positive)
+ENDPROC(arch_atomic64_dec_if_positive)
+EXPORT_SYMBOL(arch_atomic64_dec_if_positive)
index c501106..457a38d 100644 (file)
@@ -369,7 +369,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long stack_page, sp, ip;
        bool seen_sched = 0;
 
-       if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING))
+       if ((p == NULL) || (p == current) || task_is_running(p))
                return 0;
 
        stack_page = (unsigned long) task_stack_page(p);
index 3d91f89..9ee19e5 100644 (file)
@@ -41,7 +41,7 @@ void handle_syscall(struct uml_pt_regs *r)
                goto out;
 
        syscall = UPT_SYSCALL_NR(r);
-       if (syscall >= 0 && syscall <= __NR_syscall_max)
+       if (syscall >= 0 && syscall < __NR_syscalls)
                PT_REGS_SET_SYSCALL_RETURN(regs,
                                EXECUTE_SYSCALL(syscall, regs));
 
index 0045e1b..86dae42 100644 (file)
@@ -1693,35 +1693,6 @@ config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
          Set whether the default state of memory_corruption_check is
          on or off.
 
-config X86_RESERVE_LOW
-       int "Amount of low memory, in kilobytes, to reserve for the BIOS"
-       default 64
-       range 4 640
-       help
-         Specify the amount of low memory to reserve for the BIOS.
-
-         The first page contains BIOS data structures that the kernel
-         must not use, so that page must always be reserved.
-
-         By default we reserve the first 64K of physical RAM, as a
-         number of BIOSes are known to corrupt that memory range
-         during events such as suspend/resume or monitor cable
-         insertion, so it must not be used by the kernel.
-
-         You can set this to 4 if you are absolutely sure that you
-         trust the BIOS to get all its memory reservations and usages
-         right.  If you know your BIOS have problems beyond the
-         default 64K area, you can set this to 640 to avoid using the
-         entire low memory range.
-
-         If you have doubts about the BIOS (e.g. suspend/resume does
-         not work or there's kernel crashes after certain hardware
-         hotplug events) then you might want to enable
-         X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check
-         typical corruption patterns.
-
-         Leave this to the default value of 64 if you are unsure.
-
 config MATH_EMULATION
        bool
        depends on MODIFY_LDT_SYSCALL
index cb5e8d3..53eceaf 100644 (file)
@@ -257,7 +257,7 @@ drivers-$(CONFIG_FB) += arch/x86/video/
 
 boot := arch/x86/boot
 
-BOOT_TARGETS = bzdisk fdimage fdimage144 fdimage288 isoimage
+BOOT_TARGETS = bzdisk fdimage fdimage144 fdimage288 hdimage isoimage
 
 PHONY += bzImage $(BOOT_TARGETS)
 
@@ -315,8 +315,9 @@ define archhelp
   echo  '  fdimage             - Create 1.4MB boot floppy image (arch/x86/boot/fdimage)'
   echo  '  fdimage144          - Create 1.4MB boot floppy image (arch/x86/boot/fdimage)'
   echo  '  fdimage288          - Create 2.8MB boot floppy image (arch/x86/boot/fdimage)'
+  echo  '  hdimage             - Create a BIOS/EFI hard disk image (arch/x86/boot/hdimage)'
   echo  '  isoimage            - Create a boot CD-ROM image (arch/x86/boot/image.iso)'
-  echo  '                        bzdisk/fdimage*/isoimage also accept:'
+  echo  '                        bzdisk/fdimage*/hdimage/isoimage also accept:'
   echo  '                        FDARGS="..."  arguments for the booted kernel'
   echo  '                        FDINITRD=file initrd for the booted kernel'
   echo  ''
index 9cc7f13..1189be0 100644 (file)
@@ -11,3 +11,4 @@ setup.elf
 fdimage
 mtools.conf
 image.iso
+hdimage
index fe60520..dfbc26a 100644 (file)
@@ -29,7 +29,7 @@ KCOV_INSTRUMENT               := n
 SVGA_MODE      := -DSVGA_MODE=NORMAL_VGA
 
 targets                := vmlinux.bin setup.bin setup.elf bzImage
-targets                += fdimage fdimage144 fdimage288 image.iso mtools.conf
+targets                += fdimage fdimage144 fdimage288 image.iso hdimage
 subdir-                := compressed
 
 setup-y                += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o
@@ -115,47 +115,49 @@ $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
 # Set this if you want to pass append arguments to the
-# bzdisk/fdimage/isoimage kernel
+# bzdisk/fdimage/hdimage/isoimage kernel
 FDARGS =
-# Set this if you want an initrd included with the
-# bzdisk/fdimage/isoimage kernel
+# Set this if you want one or more initrds included in the image
 FDINITRD =
 
-image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
+imgdeps = $(obj)/bzImage $(obj)/mtools.conf $(src)/genimage.sh
 
 $(obj)/mtools.conf: $(src)/mtools.conf.in
        sed -e 's|@OBJ@|$(obj)|g' < $< > $@
 
+targets += mtools.conf
+
+# genimage.sh requires bash, but it also has a bunch of other
+# external dependencies.
 quiet_cmd_genimage = GENIMAGE $3
-cmd_genimage = sh $(srctree)/$(src)/genimage.sh $2 $3 $(obj)/bzImage \
-                       $(obj)/mtools.conf '$(image_cmdline)' $(FDINITRD)
+cmd_genimage = $(BASH) $(srctree)/$(src)/genimage.sh $2 $3 $(obj)/bzImage \
+               $(obj)/mtools.conf '$(FDARGS)' $(FDINITRD)
 
-PHONY += bzdisk fdimage fdimage144 fdimage288 isoimage bzlilo install
+PHONY += bzdisk fdimage fdimage144 fdimage288 hdimage isoimage install
 
 # This requires write access to /dev/fd0
-bzdisk: $(obj)/bzImage $(obj)/mtools.conf
+# All images require syslinux to be installed; hdimage also requires
+# EDK2/OVMF if the kernel is compiled with the EFI stub.
+bzdisk: $(imgdeps)
        $(call cmd,genimage,bzdisk,/dev/fd0)
 
-# These require being root or having syslinux 2.02 or higher installed
-fdimage fdimage144: $(obj)/bzImage $(obj)/mtools.conf
+fdimage fdimage144: $(imgdeps)
        $(call cmd,genimage,fdimage144,$(obj)/fdimage)
        @$(kecho) 'Kernel: $(obj)/fdimage is ready'
 
-fdimage288: $(obj)/bzImage $(obj)/mtools.conf
+fdimage288: $(imgdeps)
        $(call cmd,genimage,fdimage288,$(obj)/fdimage)
        @$(kecho) 'Kernel: $(obj)/fdimage is ready'
 
-isoimage: $(obj)/bzImage
+hdimage: $(imgdeps)
+       $(call cmd,genimage,hdimage,$(obj)/hdimage)
+       @$(kecho) 'Kernel: $(obj)/hdimage is ready'
+
+isoimage: $(imgdeps)
        $(call cmd,genimage,isoimage,$(obj)/image.iso)
        @$(kecho) 'Kernel: $(obj)/image.iso is ready'
 
-bzlilo:
-       if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
-       if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
-       cat $(obj)/bzImage > $(INSTALL_PATH)/vmlinuz
-       cp System.map $(INSTALL_PATH)/
-       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
-
 install:
-       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(obj)/bzImage \
+       $(CONFIG_SHELL) $(srctree)/$(src)/install.sh \
+               $(KERNELRELEASE) $(obj)/bzImage \
                System.map "$(INSTALL_PATH)"
index 6a10d52..0673fdf 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 #
 # 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
@@ -8,15 +8,24 @@
 #
 # Adapted from code in arch/x86/boot/Makefile by H. Peter Anvin and others
 #
-# "make fdimage/fdimage144/fdimage288/isoimage" script for x86 architecture
+# "make fdimage/fdimage144/fdimage288/hdimage/isoimage"
+# script for x86 architecture
 #
 # Arguments:
-#   $1 - fdimage format
-#   $2 - target image file
-#   $3 - kernel bzImage file
-#   $4 - mtool configuration file
-#   $5 - kernel cmdline
-#   $6 - inird image file
+#   $1  - fdimage format
+#   $2  - target image file
+#   $3  - kernel bzImage file
+#   $4  - mtools configuration file
+#   $5  - kernel cmdline
+#   $6+ - initrd image file(s)
+#
+# This script requires:
+#   bash
+#   syslinux
+#   mtools (for fdimage* and hdimage)
+#   edk2/OVMF (for hdimage)
+#
+# Otherwise try to stick to POSIX shell commands...
 #
 
 # Use "make V=1" to debug this script
@@ -26,105 +35,237 @@ case "${KBUILD_VERBOSE}" in
         ;;
 esac
 
-verify () {
-       if [ ! -f "$1" ]; then
-               echo ""                                                   1>&2
-               echo " *** Missing file: $1"                              1>&2
-               echo ""                                                   1>&2
-               exit 1
+# Exit the top-level shell with an error
+topshell=$$
+trap 'exit 1' USR1
+die() {
+       echo ""        1>&2
+       echo " *** $*" 1>&2
+       echo ""        1>&2
+       kill -USR1 $topshell
+}
+
+# Verify the existence and readability of a file
+verify() {
+       if [ ! -f "$1" -o ! -r "$1" ]; then
+               die "Missing file: $1"
        fi
 }
 
+diskfmt="$1"
+FIMAGE="$2"
+FBZIMAGE="$3"
+MTOOLSRC="$4"
+KCMDLINE="$5"
+shift 5                                # Remaining arguments = initrd files
+
+export MTOOLSRC
 
-export MTOOLSRC=$4
-FIMAGE=$2
-FBZIMAGE=$3
-KCMDLINE=$5
-FDINITRD=$6
+# common options for dd
+dd='dd iflag=fullblock'
 
 # Make sure the files actually exist
 verify "$FBZIMAGE"
 
-genbzdisk() {
-       verify "$MTOOLSRC"
-       mformat a:
-       syslinux $FIMAGE
-       echo "$KCMDLINE" | mcopy - a:syslinux.cfg
-       if [ -f "$FDINITRD" ] ; then
-               mcopy "$FDINITRD" a:initrd.img
+declare -a FDINITRDS
+irdpfx=' initrd='
+initrdopts_syslinux=''
+initrdopts_efi=''
+for f in "$@"; do
+       if [ -f "$f" -a -r "$f" ]; then
+           FDINITRDS=("${FDINITRDS[@]}" "$f")
+           fname="$(basename "$f")"
+           initrdopts_syslinux="${initrdopts_syslinux}${irdpfx}${fname}"
+           irdpfx=,
+           initrdopts_efi="${initrdopts_efi} initrd=${fname}"
        fi
-       mcopy $FBZIMAGE a:linux
+done
+
+# Read a $3-byte littleendian unsigned value at offset $2 from file $1
+le() {
+       local n=0
+       local m=1
+       for b in $(od -A n -v -j $2 -N $3 -t u1 "$1"); do
+               n=$((n + b*m))
+               m=$((m * 256))
+       done
+       echo $n
 }
 
-genfdimage144() {
-       verify "$MTOOLSRC"
-       dd if=/dev/zero of=$FIMAGE bs=1024 count=1440 2> /dev/null
-       mformat v:
-       syslinux $FIMAGE
-       echo "$KCMDLINE" | mcopy - v:syslinux.cfg
-       if [ -f "$FDINITRD" ] ; then
-               mcopy "$FDINITRD" v:initrd.img
-       fi
-       mcopy $FBZIMAGE v:linux
+# Get the EFI architecture name such that boot{name}.efi is the default
+# boot file name. Returns false with no output if the file is not an
+# EFI image or otherwise unknown.
+efiarch() {
+       [ -f "$1" ] || return
+       [ $(le "$1" 0 2) -eq 23117 ] || return          # MZ magic
+       peoffs=$(le "$1" 60 4)                          # PE header offset
+       [ $peoffs -ge 64 ] || return
+       [ $(le "$1" $peoffs 4) -eq 17744 ] || return    # PE magic
+       case $(le "$1" $((peoffs+4+20)) 2) in           # PE type
+               267)    ;;                              # PE32
+               523)    ;;                              # PE32+
+               *) return 1 ;;                          # Invalid
+       esac
+       [ $(le "$1" $((peoffs+4+20+68)) 2) -eq 10 ] || return # EFI app
+       case $(le "$1" $((peoffs+4)) 2) in              # Machine type
+                332)   echo i386       ;;
+                450)   echo arm        ;;
+                512)   echo ia64       ;;
+               20530)  echo riscv32    ;;
+               20580)  echo riscv64    ;;
+               20776)  echo riscv128   ;;
+               34404)  echo x64        ;;
+               43620)  echo aa64       ;;
+       esac
 }
 
-genfdimage288() {
-       verify "$MTOOLSRC"
-       dd if=/dev/zero of=$FIMAGE bs=1024 count=2880 2> /dev/null
-       mformat w:
-       syslinux $FIMAGE
-       echo "$KCMDLINE" | mcopy - W:syslinux.cfg
-       if [ -f "$FDINITRD" ] ; then
-               mcopy "$FDINITRD" w:initrd.img
-       fi
-       mcopy $FBZIMAGE w:linux
+# Get the combined sizes in bytes of the files given, counting sparse
+# files as full length, and padding each file to a 4K block size
+filesizes() {
+       local t=0
+       local s
+       for s in $(ls -lnL "$@" 2>/dev/null | awk '/^-/{ print $5; }'); do
+               t=$((t + ((s+4095)/4096)*4096))
+       done
+       echo $t
 }
 
-geniso() {
-       tmp_dir=`dirname $FIMAGE`/isoimage
-       rm -rf $tmp_dir
-       mkdir $tmp_dir
-       for i in lib lib64 share ; do
-               for j in syslinux ISOLINUX ; do
-                       if [ -f /usr/$i/$j/isolinux.bin ] ; then
-                               isolinux=/usr/$i/$j/isolinux.bin
-                       fi
+# Expand directory names which should be in /usr/share into a list
+# of possible alternatives
+sharedirs() {
+       local dir file
+       for dir in /usr/share /usr/lib64 /usr/lib; do
+               for file; do
+                       echo "$dir/$file"
+                       echo "$dir/${file^^}"
                done
-               for j in syslinux syslinux/modules/bios ; do
-                       if [ -f /usr/$i/$j/ldlinux.c32 ]; then
-                               ldlinux=/usr/$i/$j/ldlinux.c32
-                       fi
+       done
+}
+efidirs() {
+       local dir file
+       for dir in /usr/share /boot /usr/lib64 /usr/lib; do
+               for file; do
+                       echo "$dir/$file"
+                       echo "$dir/${file^^}"
                done
-               if [ -n "$isolinux" -a -n "$ldlinux" ] ; then
-                       break
+       done
+}
+
+findsyslinux() {
+       local f="$(find -L $(sharedirs syslinux isolinux) \
+                   -name "$1" -readable -type f -print -quit 2>/dev/null)"
+       if [ ! -f "$f" ]; then
+               die "Need a $1 file, please install syslinux/isolinux."
+       fi
+       echo "$f"
+       return 0
+}
+
+findovmf() {
+       local arch="$1"
+       shift
+       local -a names=(-false)
+       local name f
+       for name; do
+               names=("${names[@]}" -or -iname "$name")
+       done
+       for f in $(find -L $(efidirs edk2 ovmf) \
+                       \( "${names[@]}" \) -readable -type f \
+                       -print 2>/dev/null); do
+               if [ "$(efiarch "$f")" = "$arch" ]; then
+                       echo "$f"
+                       return 0
                fi
        done
-       if [ -z "$isolinux" ] ; then
-               echo 'Need an isolinux.bin file, please install syslinux/isolinux.'
-               exit 1
+       die "Need a $1 file for $arch, please install EDK2/OVMF."
+}
+
+do_mcopy() {
+       if [ ${#FDINITRDS[@]} -gt 0 ]; then
+               mcopy "${FDINITRDS[@]}" "$1"
+       fi
+       if [ -n "$efishell" ]; then
+               mmd "$1"EFI "$1"EFI/Boot
+               mcopy "$efishell" "$1"EFI/Boot/boot${kefiarch}.efi
        fi
-       if [ -z "$ldlinux" ] ; then
-               echo 'Need an ldlinux.c32 file, please install syslinux/isolinux.'
-               exit 1
+       if [ -n "$kefiarch" ]; then
+               echo linux "$KCMDLINE$initrdopts_efi" | \
+                       mcopy - "$1"startup.nsh
        fi
-       cp $isolinux $tmp_dir
-       cp $ldlinux $tmp_dir
-       cp $FBZIMAGE $tmp_dir/linux
-       echo "$KCMDLINE" > $tmp_dir/isolinux.cfg
-       if [ -f "$FDINITRD" ] ; then
-               cp "$FDINITRD" $tmp_dir/initrd.img
+       echo default linux "$KCMDLINE$initrdopts_syslinux" | \
+               mcopy - "$1"syslinux.cfg
+       mcopy "$FBZIMAGE" "$1"linux
+}
+
+genbzdisk() {
+       verify "$MTOOLSRC"
+       mformat -v 'LINUX_BOOT' a:
+       syslinux "$FIMAGE"
+       do_mcopy a:
+}
+
+genfdimage144() {
+       verify "$MTOOLSRC"
+       $dd if=/dev/zero of="$FIMAGE" bs=1024 count=1440 2>/dev/null
+       mformat -v 'LINUX_BOOT' v:
+       syslinux "$FIMAGE"
+       do_mcopy v:
+}
+
+genfdimage288() {
+       verify "$MTOOLSRC"
+       $dd if=/dev/zero of="$FIMAGE" bs=1024 count=2880 2>/dev/null
+       mformat -v 'LINUX_BOOT' w:
+       syslinux "$FIMAGE"
+       do_mcopy w:
+}
+
+genhdimage() {
+       verify "$MTOOLSRC"
+       mbr="$(findsyslinux mbr.bin)"
+       kefiarch="$(efiarch "$FBZIMAGE")"
+       if [ -n "$kefiarch" ]; then
+               # The efishell provides command line handling
+               efishell="$(findovmf $kefiarch shell.efi shell${kefiarch}.efi)"
+               ptype='-T 0xef' # EFI system partition, no GPT
        fi
-       genisoimage -J -r -input-charset=utf-8 -quiet -o $FIMAGE \
-               -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 \
-               -boot-info-table $tmp_dir
-       isohybrid $FIMAGE 2>/dev/null || true
-       rm -rf $tmp_dir
+       sizes=$(filesizes "$FBZIMAGE" "${FDINITRDS[@]}" "$efishell")
+       # Allow 1% + 1 MiB for filesystem and partition table overhead,
+       # syslinux, and config files
+       megs=$(((sizes + sizes/100 + 2*1024*1024 - 1)/(1024*1024)))
+       $dd if=/dev/zero of="$FIMAGE" bs=$((1024*1024)) count=$megs 2>/dev/null
+       mpartition -I -c -s 32 -h 64 -t $megs $ptype -b 512 -a h:
+       $dd if="$mbr" of="$FIMAGE" bs=440 count=1 conv=notrunc 2>/dev/null
+       mformat -v 'LINUX_BOOT' -s 32 -h 64 -t $megs h:
+       syslinux --offset $((512*512)) "$FIMAGE"
+       do_mcopy h:
+}
+
+geniso() {
+       tmp_dir="$(dirname "$FIMAGE")/isoimage"
+       rm -rf "$tmp_dir"
+       mkdir "$tmp_dir"
+       isolinux=$(findsyslinux isolinux.bin)
+       ldlinux=$(findsyslinux  ldlinux.c32)
+       cp "$isolinux" "$ldlinux" "$tmp_dir"
+       cp "$FBZIMAGE" "$tmp_dir"/linux
+       echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg
+       cp "${FDINITRDS[@]}" "$tmp_dir"/
+       genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \
+                   -quiet -o "$FIMAGE" -b isolinux.bin \
+                   -c boot.cat -no-emul-boot -boot-load-size 4 \
+                   -boot-info-table "$tmp_dir"
+       isohybrid "$FIMAGE" 2>/dev/null || true
+       rm -rf "$tmp_dir"
 }
 
-case $1 in
+rm -f "$FIMAGE"
+
+case "$diskfmt" in
        bzdisk)     genbzdisk;;
        fdimage144) genfdimage144;;
        fdimage288) genfdimage288;;
+       hdimage)    genhdimage;;
        isoimage)   geniso;;
-       *)          echo 'Unknown image format'; exit 1;
+       *)          die "Unknown image format: $diskfmt";;
 esac
index efd6d24..9e2662d 100644 (file)
@@ -14,4 +14,7 @@ drive v:
 drive w:
   file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=36 filter
 
+# Hard disk
+drive h:
+  file="@OBJ@/hdimage" partition=1 mformat_only
 
index 6706b6c..38caf61 100644 (file)
@@ -1500,7 +1500,7 @@ static int __init curve25519_mod_init(void)
 static void __exit curve25519_mod_exit(void)
 {
        if (IS_REACHABLE(CONFIG_CRYPTO_KPP) &&
-           (boot_cpu_has(X86_FEATURE_BMI2) || boot_cpu_has(X86_FEATURE_ADX)))
+           static_branch_likely(&curve25519_use_bmi2_adx))
                crypto_unregister_kpp(&curve25519_alg);
 }
 
index 08bf95d..7fec5dc 100644 (file)
@@ -8,18 +8,8 @@ UBSAN_SANITIZE := n
 KCOV_INSTRUMENT := n
 
 CFLAGS_REMOVE_common.o         = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_syscall_64.o     = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_syscall_32.o     = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_syscall_x32.o    = $(CC_FLAGS_FTRACE)
 
 CFLAGS_common.o                        += -fno-stack-protector
-CFLAGS_syscall_64.o            += -fno-stack-protector
-CFLAGS_syscall_32.o            += -fno-stack-protector
-CFLAGS_syscall_x32.o           += -fno-stack-protector
-
-CFLAGS_syscall_64.o            += $(call cc-option,-Wno-override-init,)
-CFLAGS_syscall_32.o            += $(call cc-option,-Wno-override-init,)
-CFLAGS_syscall_x32.o           += $(call cc-option,-Wno-override-init,)
 
 obj-y                          := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
 obj-y                          += common.o
index 07a9331..a4c061f 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/percpu.h>
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
+#include <asm/ptrace-abi.h>
 
 /*
 
@@ -62,42 +63,7 @@ For 32-bit we have the following conventions - kernel is built with
  * for assembly code:
  */
 
-/* The layout forms the "struct pt_regs" on the stack: */
-/*
- * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
- * unless syscall needs a complete, fully filled "struct pt_regs".
- */
-#define R15            0*8
-#define R14            1*8
-#define R13            2*8
-#define R12            3*8
-#define RBP            4*8
-#define RBX            5*8
-/* These regs are callee-clobbered. Always saved on kernel entry. */
-#define R11            6*8
-#define R10            7*8
-#define R9             8*8
-#define R8             9*8
-#define RAX            10*8
-#define RCX            11*8
-#define RDX            12*8
-#define RSI            13*8
-#define RDI            14*8
-/*
- * On syscall entry, this is syscall#. On CPU exception, this is error code.
- * On hw interrupt, it's IRQ number:
- */
-#define ORIG_RAX       15*8
-/* Return frame for iretq */
-#define RIP            16*8
-#define CS             17*8
-#define EFLAGS         18*8
-#define RSP            19*8
-#define SS             20*8
-
-#define SIZEOF_PTREGS  21*8
-
-.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0
+.macro PUSH_REGS rdx=%rdx rax=%rax save_ret=0
        .if \save_ret
        pushq   %rsi            /* pt_regs->si */
        movq    8(%rsp), %rsi   /* temporarily store the return address in %rsi */
@@ -124,7 +90,9 @@ For 32-bit we have the following conventions - kernel is built with
        .if \save_ret
        pushq   %rsi            /* return address on top of stack */
        .endif
+.endm
 
+.macro CLEAR_REGS
        /*
         * Sanitize registers of values that a speculation attack might
         * otherwise want to exploit. The lower registers are likely clobbered
@@ -146,6 +114,11 @@ For 32-bit we have the following conventions - kernel is built with
 
 .endm
 
+.macro PUSH_AND_CLEAR_REGS rdx=%rdx rax=%rax save_ret=0
+       PUSH_REGS rdx=\rdx, rax=\rax, save_ret=\save_ret
+       CLEAR_REGS
+.endm
+
 .macro POP_REGS pop_rdi=1 skip_r11rcx=0
        popq %r15
        popq %r14
index 7b2542b..6c28264 100644 (file)
 #include <asm/irq_stack.h>
 
 #ifdef CONFIG_X86_64
-__visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
+
+static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
+{
+       /*
+        * Convert negative numbers to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int unr = nr;
+
+       if (likely(unr < NR_syscalls)) {
+               unr = array_index_nospec(unr, NR_syscalls);
+               regs->ax = sys_call_table[unr](regs);
+               return true;
+       }
+       return false;
+}
+
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
+{
+       /*
+        * Adjust the starting offset of the table, and convert numbers
+        * < __X32_SYSCALL_BIT to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int xnr = nr - __X32_SYSCALL_BIT;
+
+       if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
+               xnr = array_index_nospec(xnr, X32_NR_syscalls);
+               regs->ax = x32_sys_call_table[xnr](regs);
+               return true;
+       }
+       return false;
+}
+
+__visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
 {
        add_random_kstack_offset();
        nr = syscall_enter_from_user_mode(regs, nr);
 
        instrumentation_begin();
-       if (likely(nr < NR_syscalls)) {
-               nr = array_index_nospec(nr, NR_syscalls);
-               regs->ax = sys_call_table[nr](regs);
-#ifdef CONFIG_X86_X32_ABI
-       } else if (likely((nr & __X32_SYSCALL_BIT) &&
-                         (nr & ~__X32_SYSCALL_BIT) < X32_NR_syscalls)) {
-               nr = array_index_nospec(nr & ~__X32_SYSCALL_BIT,
-                                       X32_NR_syscalls);
-               regs->ax = x32_sys_call_table[nr](regs);
-#endif
+
+       if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
+               /* Invalid system call, but still a system call. */
+               regs->ax = __x64_sys_ni_syscall(regs);
        }
+
        instrumentation_end();
        syscall_exit_to_user_mode(regs);
 }
 #endif
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
-static __always_inline unsigned int syscall_32_enter(struct pt_regs *regs)
+static __always_inline int syscall_32_enter(struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_IA32_EMULATION))
                current_thread_info()->status |= TS_COMPAT;
 
-       return (unsigned int)regs->orig_ax;
+       return (int)regs->orig_ax;
 }
 
 /*
  * Invoke a 32-bit syscall.  Called with IRQs on in CONTEXT_KERNEL.
  */
-static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs,
-                                                 unsigned int nr)
+static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
 {
-       if (likely(nr < IA32_NR_syscalls)) {
-               nr = array_index_nospec(nr, IA32_NR_syscalls);
-               regs->ax = ia32_sys_call_table[nr](regs);
+       /*
+        * Convert negative numbers to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int unr = nr;
+
+       if (likely(unr < IA32_NR_syscalls)) {
+               unr = array_index_nospec(unr, IA32_NR_syscalls);
+               regs->ax = ia32_sys_call_table[unr](regs);
+       } else if (nr != -1) {
+               regs->ax = __ia32_sys_ni_syscall(regs);
        }
 }
 
 /* Handles int $0x80 */
 __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
-       unsigned int nr = syscall_32_enter(regs);
+       int nr = syscall_32_enter(regs);
 
        add_random_kstack_offset();
        /*
-        * Subtlety here: if ptrace pokes something larger than 2^32-1 into
-        * orig_ax, the unsigned int return value truncates it.  This may
-        * or may not be necessary, but it matches the old asm behavior.
+        * Subtlety here: if ptrace pokes something larger than 2^31-1 into
+        * orig_ax, the int return value truncates it. This matches
+        * the semantics of syscall_get_nr().
         */
-       nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
+       nr = syscall_enter_from_user_mode(regs, nr);
        instrumentation_begin();
 
        do_syscall_32_irqs_on(regs, nr);
@@ -101,7 +137,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-       unsigned int nr = syscall_32_enter(regs);
+       int nr = syscall_32_enter(regs);
        int res;
 
        add_random_kstack_offset();
@@ -130,14 +166,13 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
                /* User code screwed up. */
                regs->ax = -EFAULT;
 
-               instrumentation_end();
                local_irq_disable();
+               instrumentation_end();
                irqentry_exit_to_user_mode(regs);
                return false;
        }
 
-       /* The case truncates any ptrace induced syscall nr > 2^32 -1 */
-       nr = (unsigned int)syscall_enter_from_user_mode_work(regs, nr);
+       nr = syscall_enter_from_user_mode_work(regs, nr);
 
        /* Now this is just like a normal syscall. */
        do_syscall_32_irqs_on(regs, nr);
@@ -269,15 +304,16 @@ __visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
        irqentry_state_t state = irqentry_enter(regs);
        bool inhcall;
 
+       instrumentation_begin();
        run_sysvec_on_irqstack_cond(__xen_pv_evtchn_do_upcall, regs);
 
        inhcall = get_and_clear_inhcall();
        if (inhcall && !WARN_ON_ONCE(state.exit_rcu)) {
-               instrumentation_begin();
                irqentry_exit_cond_resched();
                instrumentation_end();
                restore_inhcall(inhcall);
        } else {
+               instrumentation_end();
                irqentry_exit(regs, state);
        }
 }
index a16a529..e38a4cf 100644 (file)
@@ -107,8 +107,9 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
        PUSH_AND_CLEAR_REGS rax=$-ENOSYS
 
        /* IRQs are off. */
-       movq    %rax, %rdi
-       movq    %rsp, %rsi
+       movq    %rsp, %rdi
+       /* Sign extend the lower 32bit as syscall numbers are treated as int */
+       movslq  %eax, %rsi
        call    do_syscall_64           /* returns with IRQs disabled */
 
        /*
@@ -506,7 +507,7 @@ SYM_CODE_START(\asmsym)
 
        movq    %rsp, %rdi              /* pt_regs pointer */
 
-       call    \cfunc
+       call    kernel_\cfunc
 
        /*
         * No need to switch back to the IST stack. The current stack is either
@@ -517,7 +518,7 @@ SYM_CODE_START(\asmsym)
 
        /* Switch to the regular task stack */
 .Lfrom_usermode_switch_stack_\@:
-       idtentry_body safe_stack_\cfunc, has_error_code=1
+       idtentry_body user_\cfunc, has_error_code=1
 
 _ASM_NOKPROBE(\asmsym)
 SYM_CODE_END(\asmsym)
index 86eb0d8..8cfc9bc 100644 (file)
@@ -5,21 +5,21 @@
 #include <linux/sys.h>
 #include <linux/cache.h>
 #include <linux/syscalls.h>
-#include <asm/unistd.h>
 #include <asm/syscall.h>
 
-#define __SYSCALL_I386(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
+#ifdef CONFIG_IA32_EMULATION
+#define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, compat)
+#else
+#define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, native)
+#endif
+
+#define __SYSCALL(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
 
 #include <asm/syscalls_32.h>
-#undef __SYSCALL_I386
+#undef __SYSCALL
 
-#define __SYSCALL_I386(nr, sym) [nr] = __ia32_##sym,
+#define __SYSCALL(nr, sym) __ia32_##sym,
 
-__visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_ia32_syscall_max] = &__ia32_sys_ni_syscall,
+__visible const sys_call_ptr_t ia32_sys_call_table[] = {
 #include <asm/syscalls_32.h>
 };
index 1594ec7..be120ee 100644 (file)
@@ -5,23 +5,14 @@
 #include <linux/sys.h>
 #include <linux/cache.h>
 #include <linux/syscalls.h>
-#include <asm/unistd.h>
 #include <asm/syscall.h>
 
-#define __SYSCALL_X32(nr, sym)
-#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym)
-
-#define __SYSCALL_64(nr, sym) extern long __x64_##sym(const struct pt_regs *);
+#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
 #include <asm/syscalls_64.h>
-#undef __SYSCALL_64
+#undef __SYSCALL
 
-#define __SYSCALL_64(nr, sym) [nr] = __x64_##sym,
+#define __SYSCALL(nr, sym) __x64_##sym,
 
-asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_syscall_max] = &__x64_sys_ni_syscall,
+asmlinkage const sys_call_ptr_t sys_call_table[] = {
 #include <asm/syscalls_64.h>
 };
index f2fe0a3..bdd0e03 100644 (file)
@@ -5,37 +5,14 @@
 #include <linux/sys.h>
 #include <linux/cache.h>
 #include <linux/syscalls.h>
-#include <asm/unistd.h>
 #include <asm/syscall.h>
 
-/*
- * Reuse the 64-bit entry points for the x32 versions that occupy different
- * slots in the syscall table.
- */
-#define __x32_sys_readv                __x64_sys_readv
-#define __x32_sys_writev       __x64_sys_writev
-#define __x32_sys_getsockopt   __x64_sys_getsockopt
-#define __x32_sys_setsockopt   __x64_sys_setsockopt
-#define __x32_sys_vmsplice     __x64_sys_vmsplice
-#define __x32_sys_process_vm_readv     __x64_sys_process_vm_readv
-#define __x32_sys_process_vm_writev    __x64_sys_process_vm_writev
+#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
+#include <asm/syscalls_x32.h>
+#undef __SYSCALL
 
-#define __SYSCALL_64(nr, sym)
+#define __SYSCALL(nr, sym) __x64_##sym,
 
-#define __SYSCALL_X32(nr, sym) extern long __x32_##sym(const struct pt_regs *);
-#define __SYSCALL_COMMON(nr, sym) extern long __x64_##sym(const struct pt_regs *);
-#include <asm/syscalls_64.h>
-#undef __SYSCALL_X32
-#undef __SYSCALL_COMMON
-
-#define __SYSCALL_X32(nr, sym) [nr] = __x32_##sym,
-#define __SYSCALL_COMMON(nr, sym) [nr] = __x64_##sym,
-
-asmlinkage const sys_call_ptr_t x32_sys_call_table[__NR_x32_syscall_max+1] = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_x32_syscall_max] = &__x64_sys_ni_syscall,
-#include <asm/syscalls_64.h>
+asmlinkage const sys_call_ptr_t x32_sys_call_table[] = {
+#include <asm/syscalls_x32.h>
 };
index d8c4f6c..5b3efed 100644 (file)
@@ -9,47 +9,54 @@ _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') \
 syscall32 := $(src)/syscall_32.tbl
 syscall64 := $(src)/syscall_64.tbl
 
-syshdr := $(srctree)/$(src)/syscallhdr.sh
-systbl := $(srctree)/$(src)/syscalltbl.sh
+syshdr := $(srctree)/scripts/syscallhdr.sh
+systbl := $(srctree)/scripts/syscalltbl.sh
+offset :=
+prefix :=
 
 quiet_cmd_syshdr = SYSHDR  $@
-      cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' '$<' '$@' \
-                  '$(syshdr_abi_$(basetarget))' \
-                  '$(syshdr_pfx_$(basetarget))' \
-                  '$(syshdr_offset_$(basetarget))'
+      cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --abis $(abis) --emit-nr \
+               $(if $(offset),--offset $(offset)) \
+               $(if $(prefix),--prefix $(prefix)) \
+               $< $@
 quiet_cmd_systbl = SYSTBL  $@
-      cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@
+      cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis $(abis) $< $@
 
 quiet_cmd_hypercalls = HYPERCALLS $@
       cmd_hypercalls = $(CONFIG_SHELL) '$<' $@ $(filter-out $<, $(real-prereqs))
 
-syshdr_abi_unistd_32 := i386
+$(uapi)/unistd_32.h: abis := i386
 $(uapi)/unistd_32.h: $(syscall32) $(syshdr) FORCE
        $(call if_changed,syshdr)
 
-syshdr_abi_unistd_32_ia32 := i386
-syshdr_pfx_unistd_32_ia32 := ia32_
+$(out)/unistd_32_ia32.h: abis := i386
+$(out)/unistd_32_ia32.h: prefix := ia32_
 $(out)/unistd_32_ia32.h: $(syscall32) $(syshdr) FORCE
        $(call if_changed,syshdr)
 
-syshdr_abi_unistd_x32 := common,x32
-syshdr_offset_unistd_x32 := __X32_SYSCALL_BIT
+$(uapi)/unistd_x32.h: abis := common,x32
+$(uapi)/unistd_x32.h: offset := __X32_SYSCALL_BIT
 $(uapi)/unistd_x32.h: $(syscall64) $(syshdr) FORCE
        $(call if_changed,syshdr)
 
-syshdr_abi_unistd_64 := common,64
+$(uapi)/unistd_64.h: abis := common,64
 $(uapi)/unistd_64.h: $(syscall64) $(syshdr) FORCE
        $(call if_changed,syshdr)
 
-syshdr_abi_unistd_64_x32 := x32
-syshdr_pfx_unistd_64_x32 := x32_
+$(out)/unistd_64_x32.h: abis := x32
+$(out)/unistd_64_x32.h: prefix := x32_
 $(out)/unistd_64_x32.h: $(syscall64) $(syshdr) FORCE
        $(call if_changed,syshdr)
 
+$(out)/syscalls_32.h: abis := i386
 $(out)/syscalls_32.h: $(syscall32) $(systbl) FORCE
        $(call if_changed,systbl)
+$(out)/syscalls_64.h: abis := common,64
 $(out)/syscalls_64.h: $(syscall64) $(systbl) FORCE
        $(call if_changed,systbl)
+$(out)/syscalls_x32.h: abis := common,x32
+$(out)/syscalls_x32.h: $(syscall64) $(systbl) FORCE
+       $(call if_changed,systbl)
 
 $(out)/xen-hypercalls.h: $(srctree)/scripts/xen-hypercalls.sh FORCE
        $(call if_changed,hypercalls)
@@ -60,6 +67,7 @@ uapisyshdr-y                  += unistd_32.h unistd_64.h unistd_x32.h
 syshdr-y                       += syscalls_32.h
 syshdr-$(CONFIG_X86_64)                += unistd_32_ia32.h unistd_64_x32.h
 syshdr-$(CONFIG_X86_64)                += syscalls_64.h
+syshdr-$(CONFIG_X86_X32)       += syscalls_x32.h
 syshdr-$(CONFIG_XEN)           += xen-hypercalls.h
 
 uapisyshdr-y   := $(addprefix $(uapi)/, $(uapisyshdr-y))
diff --git a/arch/x86/entry/syscalls/syscallhdr.sh b/arch/x86/entry/syscalls/syscallhdr.sh
deleted file mode 100644 (file)
index cc1e638..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-in="$1"
-out="$2"
-my_abis=`echo "($3)" | tr ',' '|'`
-prefix="$4"
-offset="$5"
-
-fileguard=_ASM_X86_`basename "$out" | sed \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
-    -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'`
-grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | (
-    echo "#ifndef ${fileguard}"
-    echo "#define ${fileguard} 1"
-    echo ""
-
-    max=0
-    while read nr abi name entry ; do
-       if [ -z "$offset" ]; then
-           echo "#define __NR_${prefix}${name} $nr"
-       else
-           echo "#define __NR_${prefix}${name} ($offset + $nr)"
-        fi
-
-       max=$nr
-    done
-
-    echo ""
-    echo "#ifdef __KERNEL__"
-    echo "#define __NR_${prefix}syscall_max $max"
-    echo "#endif"
-    echo ""
-    echo "#endif /* ${fileguard} */"
-) > "$out"
diff --git a/arch/x86/entry/syscalls/syscalltbl.sh b/arch/x86/entry/syscalls/syscalltbl.sh
deleted file mode 100644 (file)
index 929bde1..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0
-
-in="$1"
-out="$2"
-
-syscall_macro() {
-    local abi="$1"
-    local nr="$2"
-    local entry="$3"
-
-    echo "__SYSCALL_${abi}($nr, $entry)"
-}
-
-emit() {
-    local abi="$1"
-    local nr="$2"
-    local entry="$3"
-    local compat="$4"
-
-    if [ "$abi" != "I386" -a -n "$compat" ]; then
-       echo "a compat entry ($abi: $compat) for a 64-bit syscall makes no sense" >&2
-       exit 1
-    fi
-
-    if [ -z "$compat" ]; then
-       if [ -n "$entry" ]; then
-           syscall_macro "$abi" "$nr" "$entry"
-       fi
-    else
-       echo "#ifdef CONFIG_X86_32"
-       if [ -n "$entry" ]; then
-           syscall_macro "$abi" "$nr" "$entry"
-       fi
-       echo "#else"
-       syscall_macro "$abi" "$nr" "$compat"
-       echo "#endif"
-    fi
-}
-
-grep '^[0-9]' "$in" | sort -n | (
-    while read nr abi name entry compat; do
-       abi=`echo "$abi" | tr '[a-z]' '[A-Z]'`
-       emit "$abi" "$nr" "$entry" "$compat"
-    done
-) > "$out"
index 8f71dd7..1eb4513 100644 (file)
@@ -1626,6 +1626,8 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
                goto do_del;
 
+       __set_bit(event->hw.idx, cpuc->dirty);
+
        /*
         * Not a TXN, therefore cleanup properly.
         */
@@ -2474,6 +2476,31 @@ static int x86_pmu_event_init(struct perf_event *event)
        return err;
 }
 
+void perf_clear_dirty_counters(void)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       int i;
+
+        /* Don't need to clear the assigned counter. */
+       for (i = 0; i < cpuc->n_events; i++)
+               __clear_bit(cpuc->assign[i], cpuc->dirty);
+
+       if (bitmap_empty(cpuc->dirty, X86_PMC_IDX_MAX))
+               return;
+
+       for_each_set_bit(i, cpuc->dirty, X86_PMC_IDX_MAX) {
+               /* Metrics and fake events don't have corresponding HW counters. */
+               if (is_metric_idx(i) || (i == INTEL_PMC_IDX_FIXED_VLBR))
+                       continue;
+               else if (i >= INTEL_PMC_IDX_FIXED)
+                       wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + (i - INTEL_PMC_IDX_FIXED), 0);
+               else
+                       wrmsrl(x86_pmu_event_addr(i), 0);
+       }
+
+       bitmap_zero(cpuc->dirty, X86_PMC_IDX_MAX);
+}
+
 static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
 {
        if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
@@ -2497,7 +2524,6 @@ static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
 
 static void x86_pmu_event_unmapped(struct perf_event *event, struct mm_struct *mm)
 {
-
        if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
                return;
 
index e288922..fca7a6e 100644 (file)
@@ -280,6 +280,8 @@ static struct extra_reg intel_spr_extra_regs[] __read_mostly = {
        INTEL_UEVENT_EXTRA_REG(0x012b, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
        INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
        INTEL_UEVENT_EXTRA_REG(0x01c6, MSR_PEBS_FRONTEND, 0x7fff17, FE),
+       INTEL_UEVENT_EXTRA_REG(0x40ad, MSR_PEBS_FRONTEND, 0x7, FE),
+       INTEL_UEVENT_EXTRA_REG(0x04c2, MSR_PEBS_FRONTEND, 0x8, FE),
        EVENT_EXTRA_END
 };
 
@@ -4030,8 +4032,10 @@ spr_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
         * The :ppp indicates the Precise Distribution (PDist) facility, which
         * is only supported on the GP counter 0. If a :ppp event which is not
         * available on the GP counter 0, error out.
+        * Exception: Instruction PDIR is only available on the fixed counter 0.
         */
-       if (event->attr.precise_ip == 3) {
+       if ((event->attr.precise_ip == 3) &&
+           !constraint_match(&fixed0_constraint, event->hw.config)) {
                if (c->idxmsk64 & BIT_ULL(0))
                        return &counter0_constraint;
 
@@ -6015,7 +6019,13 @@ __init int intel_pmu_init(void)
                tsx_attr = hsw_tsx_events_attrs;
                intel_pmu_pebs_data_source_skl(pmem);
 
-               if (boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
+               /*
+                * Processors with CPUID.RTM_ALWAYS_ABORT have TSX deprecated by default.
+                * TSX force abort hooks are not required on these systems. Only deploy
+                * workaround when microcode has not enabled X86_FEATURE_RTM_ALWAYS_ABORT.
+                */
+               if (boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT) &&
+                  !boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT)) {
                        x86_pmu.flags |= PMU_FL_TFA;
                        x86_pmu.get_event_constraints = tfa_get_event_constraints;
                        x86_pmu.enable_all = intel_tfa_pmu_enable_all;
@@ -6157,8 +6167,13 @@ __init int intel_pmu_init(void)
                pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
                pmu->name = "cpu_core";
                pmu->cpu_type = hybrid_big;
-               pmu->num_counters = x86_pmu.num_counters + 2;
-               pmu->num_counters_fixed = x86_pmu.num_counters_fixed + 1;
+               if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) {
+                       pmu->num_counters = x86_pmu.num_counters + 2;
+                       pmu->num_counters_fixed = x86_pmu.num_counters_fixed + 1;
+               } else {
+                       pmu->num_counters = x86_pmu.num_counters;
+                       pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
+               }
                pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
                pmu->unconstrained = (struct event_constraint)
                                        __EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
index 1ec8fd3..8647713 100644 (file)
@@ -1187,6 +1187,9 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        struct debug_store *ds = cpuc->ds;
+       u64 value = ds->pebs_event_reset[hwc->idx];
+       u32 base = MSR_RELOAD_PMC0;
+       unsigned int idx = hwc->idx;
 
        if (!is_pebs_pt(event))
                return;
@@ -1196,7 +1199,12 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
 
        cpuc->pebs_enabled |= PEBS_OUTPUT_PT;
 
-       wrmsrl(MSR_RELOAD_PMC0 + hwc->idx, ds->pebs_event_reset[hwc->idx]);
+       if (hwc->idx >= INTEL_PMC_IDX_FIXED) {
+               base = MSR_RELOAD_FIXED_CTR0;
+               idx = hwc->idx - INTEL_PMC_IDX_FIXED;
+               value = ds->pebs_event_reset[MAX_PEBS_EVENTS + idx];
+       }
+       wrmsrl(base + idx, value);
 }
 
 void intel_pmu_pebs_enable(struct perf_event *event)
@@ -1204,6 +1212,7 @@ void intel_pmu_pebs_enable(struct perf_event *event)
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        struct debug_store *ds = cpuc->ds;
+       unsigned int idx = hwc->idx;
 
        hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
 
@@ -1222,19 +1231,18 @@ void intel_pmu_pebs_enable(struct perf_event *event)
                }
        }
 
+       if (idx >= INTEL_PMC_IDX_FIXED)
+               idx = MAX_PEBS_EVENTS + (idx - INTEL_PMC_IDX_FIXED);
+
        /*
         * Use auto-reload if possible to save a MSR write in the PMI.
         * This must be done in pmu::start(), because PERF_EVENT_IOC_PERIOD.
         */
        if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
-               unsigned int idx = hwc->idx;
-
-               if (idx >= INTEL_PMC_IDX_FIXED)
-                       idx = MAX_PEBS_EVENTS + (idx - INTEL_PMC_IDX_FIXED);
                ds->pebs_event_reset[idx] =
                        (u64)(-hwc->sample_period) & x86_pmu.cntval_mask;
        } else {
-               ds->pebs_event_reset[hwc->idx] = 0;
+               ds->pebs_event_reset[idx] = 0;
        }
 
        intel_pmu_pebs_via_pt_enable(event);
index 4409d2c..e8453de 100644 (file)
@@ -731,7 +731,8 @@ void reserve_lbr_buffers(void)
                if (!kmem_cache || cpuc->lbr_xsave)
                        continue;
 
-               cpuc->lbr_xsave = kmem_cache_alloc_node(kmem_cache, GFP_KERNEL,
+               cpuc->lbr_xsave = kmem_cache_alloc_node(kmem_cache,
+                                                       GFP_KERNEL | __GFP_ZERO,
                                                        cpu_to_node(cpu));
        }
 }
index df7b07d..9bf4dbb 100644 (file)
@@ -801,8 +801,6 @@ static void uncore_pmu_enable(struct pmu *pmu)
        struct intel_uncore_box *box;
 
        uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
-       if (!uncore_pmu)
-               return;
 
        box = uncore_pmu_to_box(uncore_pmu, smp_processor_id());
        if (!box)
@@ -818,8 +816,6 @@ static void uncore_pmu_disable(struct pmu *pmu)
        struct intel_uncore_box *box;
 
        uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
-       if (!uncore_pmu)
-               return;
 
        box = uncore_pmu_to_box(uncore_pmu, smp_processor_id());
        if (!box)
index 2917910..187d728 100644 (file)
@@ -92,6 +92,7 @@ struct intel_uncore_type {
        /*
         * Optional callbacks for managing mapping of Uncore units to PMONs
         */
+       int (*get_topology)(struct intel_uncore_type *type);
        int (*set_mapping)(struct intel_uncore_type *type);
        void (*cleanup_mapping)(struct intel_uncore_type *type);
 };
index 3a75a2c..bb6eb1e 100644 (file)
 #define SKX_M2M_PCI_PMON_CTR0          0x200
 #define SKX_M2M_PCI_PMON_BOX_CTL       0x258
 
+/* Memory Map registers device ID */
+#define SNR_ICX_MESH2IIO_MMAP_DID              0x9a2
+#define SNR_ICX_SAD_CONTROL_CFG                0x3f4
+
+/* Getting I/O stack id in SAD_COTROL_CFG notation */
+#define SAD_CONTROL_STACK_ID(data)             (((data) >> 4) & 0x7)
+
 /* SNR Ubox */
 #define SNR_U_MSR_PMON_CTR0                    0x1f98
 #define SNR_U_MSR_PMON_CTL0                    0x1f91
@@ -3682,12 +3689,19 @@ static inline u8 skx_iio_stack(struct intel_uncore_pmu *pmu, int die)
 }
 
 static umode_t
-skx_iio_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
+pmu_iio_mapping_visible(struct kobject *kobj, struct attribute *attr,
+                        int die, int zero_bus_pmu)
 {
        struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(kobj_to_dev(kobj));
 
-       /* Root bus 0x00 is valid only for die 0 AND pmu_idx = 0. */
-       return (!skx_iio_stack(pmu, die) && pmu->pmu_idx) ? 0 : attr->mode;
+       return (!skx_iio_stack(pmu, die) && pmu->pmu_idx != zero_bus_pmu) ? 0 : attr->mode;
+}
+
+static umode_t
+skx_iio_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
+{
+       /* Root bus 0x00 is valid only for pmu_idx = 0. */
+       return pmu_iio_mapping_visible(kobj, attr, die, 0);
 }
 
 static ssize_t skx_iio_mapping_show(struct device *dev,
@@ -3772,7 +3786,8 @@ static const struct attribute_group *skx_iio_attr_update[] = {
        NULL,
 };
 
-static int skx_iio_set_mapping(struct intel_uncore_type *type)
+static int
+pmu_iio_set_mapping(struct intel_uncore_type *type, struct attribute_group *ag)
 {
        char buf[64];
        int ret;
@@ -3780,7 +3795,7 @@ static int skx_iio_set_mapping(struct intel_uncore_type *type)
        struct attribute **attrs = NULL;
        struct dev_ext_attribute *eas = NULL;
 
-       ret = skx_iio_get_topology(type);
+       ret = type->get_topology(type);
        if (ret < 0)
                goto clear_attr_update;
 
@@ -3807,7 +3822,7 @@ static int skx_iio_set_mapping(struct intel_uncore_type *type)
                eas[die].var = (void *)die;
                attrs[die] = &eas[die].attr.attr;
        }
-       skx_iio_mapping_group.attrs = attrs;
+       ag->attrs = attrs;
 
        return 0;
 err:
@@ -3821,6 +3836,11 @@ clear_attr_update:
        return ret;
 }
 
+static int skx_iio_set_mapping(struct intel_uncore_type *type)
+{
+       return pmu_iio_set_mapping(type, &skx_iio_mapping_group);
+}
+
 static void skx_iio_cleanup_mapping(struct intel_uncore_type *type)
 {
        struct attribute **attr = skx_iio_mapping_group.attrs;
@@ -3851,6 +3871,7 @@ static struct intel_uncore_type skx_uncore_iio = {
        .ops                    = &skx_uncore_iio_ops,
        .format_group           = &skx_uncore_iio_format_group,
        .attr_update            = skx_iio_attr_update,
+       .get_topology           = skx_iio_get_topology,
        .set_mapping            = skx_iio_set_mapping,
        .cleanup_mapping        = skx_iio_cleanup_mapping,
 };
@@ -4393,6 +4414,91 @@ static const struct attribute_group snr_uncore_iio_format_group = {
        .attrs = snr_uncore_iio_formats_attr,
 };
 
+static umode_t
+snr_iio_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
+{
+       /* Root bus 0x00 is valid only for pmu_idx = 1. */
+       return pmu_iio_mapping_visible(kobj, attr, die, 1);
+}
+
+static struct attribute_group snr_iio_mapping_group = {
+       .is_visible     = snr_iio_mapping_visible,
+};
+
+static const struct attribute_group *snr_iio_attr_update[] = {
+       &snr_iio_mapping_group,
+       NULL,
+};
+
+static int sad_cfg_iio_topology(struct intel_uncore_type *type, u8 *sad_pmon_mapping)
+{
+       u32 sad_cfg;
+       int die, stack_id, ret = -EPERM;
+       struct pci_dev *dev = NULL;
+
+       type->topology = kcalloc(uncore_max_dies(), sizeof(*type->topology),
+                                GFP_KERNEL);
+       if (!type->topology)
+               return -ENOMEM;
+
+       while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, SNR_ICX_MESH2IIO_MMAP_DID, dev))) {
+               ret = pci_read_config_dword(dev, SNR_ICX_SAD_CONTROL_CFG, &sad_cfg);
+               if (ret) {
+                       ret = pcibios_err_to_errno(ret);
+                       break;
+               }
+
+               die = uncore_pcibus_to_dieid(dev->bus);
+               stack_id = SAD_CONTROL_STACK_ID(sad_cfg);
+               if (die < 0 || stack_id >= type->num_boxes) {
+                       ret = -EPERM;
+                       break;
+               }
+
+               /* Convert stack id from SAD_CONTROL to PMON notation. */
+               stack_id = sad_pmon_mapping[stack_id];
+
+               ((u8 *)&(type->topology[die].configuration))[stack_id] = dev->bus->number;
+               type->topology[die].segment = pci_domain_nr(dev->bus);
+       }
+
+       if (ret) {
+               kfree(type->topology);
+               type->topology = NULL;
+       }
+
+       return ret;
+}
+
+/*
+ * SNR has a static mapping of stack IDs from SAD_CONTROL_CFG notation to PMON
+ */
+enum {
+       SNR_QAT_PMON_ID,
+       SNR_CBDMA_DMI_PMON_ID,
+       SNR_NIS_PMON_ID,
+       SNR_DLB_PMON_ID,
+       SNR_PCIE_GEN3_PMON_ID
+};
+
+static u8 snr_sad_pmon_mapping[] = {
+       SNR_CBDMA_DMI_PMON_ID,
+       SNR_PCIE_GEN3_PMON_ID,
+       SNR_DLB_PMON_ID,
+       SNR_NIS_PMON_ID,
+       SNR_QAT_PMON_ID
+};
+
+static int snr_iio_get_topology(struct intel_uncore_type *type)
+{
+       return sad_cfg_iio_topology(type, snr_sad_pmon_mapping);
+}
+
+static int snr_iio_set_mapping(struct intel_uncore_type *type)
+{
+       return pmu_iio_set_mapping(type, &snr_iio_mapping_group);
+}
+
 static struct intel_uncore_type snr_uncore_iio = {
        .name                   = "iio",
        .num_counters           = 4,
@@ -4406,6 +4512,10 @@ static struct intel_uncore_type snr_uncore_iio = {
        .msr_offset             = SNR_IIO_MSR_OFFSET,
        .ops                    = &ivbep_uncore_msr_ops,
        .format_group           = &snr_uncore_iio_format_group,
+       .attr_update            = snr_iio_attr_update,
+       .get_topology           = snr_iio_get_topology,
+       .set_mapping            = snr_iio_set_mapping,
+       .cleanup_mapping        = skx_iio_cleanup_mapping,
 };
 
 static struct intel_uncore_type snr_uncore_irp = {
@@ -4933,6 +5043,53 @@ static struct event_constraint icx_uncore_iio_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+static umode_t
+icx_iio_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
+{
+       /* Root bus 0x00 is valid only for pmu_idx = 5. */
+       return pmu_iio_mapping_visible(kobj, attr, die, 5);
+}
+
+static struct attribute_group icx_iio_mapping_group = {
+       .is_visible     = icx_iio_mapping_visible,
+};
+
+static const struct attribute_group *icx_iio_attr_update[] = {
+       &icx_iio_mapping_group,
+       NULL,
+};
+
+/*
+ * ICX has a static mapping of stack IDs from SAD_CONTROL_CFG notation to PMON
+ */
+enum {
+       ICX_PCIE1_PMON_ID,
+       ICX_PCIE2_PMON_ID,
+       ICX_PCIE3_PMON_ID,
+       ICX_PCIE4_PMON_ID,
+       ICX_PCIE5_PMON_ID,
+       ICX_CBDMA_DMI_PMON_ID
+};
+
+static u8 icx_sad_pmon_mapping[] = {
+       ICX_CBDMA_DMI_PMON_ID,
+       ICX_PCIE1_PMON_ID,
+       ICX_PCIE2_PMON_ID,
+       ICX_PCIE3_PMON_ID,
+       ICX_PCIE4_PMON_ID,
+       ICX_PCIE5_PMON_ID,
+};
+
+static int icx_iio_get_topology(struct intel_uncore_type *type)
+{
+       return sad_cfg_iio_topology(type, icx_sad_pmon_mapping);
+}
+
+static int icx_iio_set_mapping(struct intel_uncore_type *type)
+{
+       return pmu_iio_set_mapping(type, &icx_iio_mapping_group);
+}
+
 static struct intel_uncore_type icx_uncore_iio = {
        .name                   = "iio",
        .num_counters           = 4,
@@ -4947,6 +5104,10 @@ static struct intel_uncore_type icx_uncore_iio = {
        .constraints            = icx_uncore_iio_constraints,
        .ops                    = &skx_uncore_iio_ops,
        .format_group           = &snr_uncore_iio_format_group,
+       .attr_update            = icx_iio_attr_update,
+       .get_topology           = icx_iio_get_topology,
+       .set_mapping            = icx_iio_set_mapping,
+       .cleanup_mapping        = skx_iio_cleanup_mapping,
 };
 
 static struct intel_uncore_type icx_uncore_irp = {
index ad87cb3..2bf1c7e 100644 (file)
@@ -229,6 +229,7 @@ struct cpu_hw_events {
         */
        struct perf_event       *events[X86_PMC_IDX_MAX]; /* in counter order */
        unsigned long           active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+       unsigned long           dirty[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
        int                     enabled;
 
        int                     n_events; /* the # of events in the below arrays */
index 84a1042..85feafa 100644 (file)
@@ -764,13 +764,14 @@ static struct rapl_model model_spr = {
        .rapl_msrs      = intel_rapl_spr_msrs,
 };
 
-static struct rapl_model model_amd_fam17h = {
+static struct rapl_model model_amd_hygon = {
        .events         = BIT(PERF_RAPL_PKG),
        .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT,
        .rapl_msrs      = amd_rapl_msrs,
 };
 
 static const struct x86_cpu_id rapl_model_match[] __initconst = {
+       X86_MATCH_FEATURE(X86_FEATURE_RAPL,             &model_amd_hygon),
        X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &model_snb),
        X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &model_snbep),
        X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &model_snb),
@@ -803,9 +804,6 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE,           &model_skl),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,         &model_skl),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &model_spr),
-       X86_MATCH_VENDOR_FAM(AMD,       0x17,           &model_amd_fam17h),
-       X86_MATCH_VENDOR_FAM(HYGON,     0x18,           &model_amd_fam17h),
-       X86_MATCH_VENDOR_FAM(AMD,       0x19,           &model_amd_fam17h),
        {},
 };
 MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
index bb0ae4b..6952e21 100644 (file)
@@ -614,50 +614,3 @@ bool hv_is_isolation_supported(void)
        return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
 }
 EXPORT_SYMBOL_GPL(hv_is_isolation_supported);
-
-/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */
-bool hv_query_ext_cap(u64 cap_query)
-{
-       /*
-        * The address of the 'hv_extended_cap' variable will be used as an
-        * output parameter to the hypercall below and so it should be
-        * compatible with 'virt_to_phys'. Which means, it's address should be
-        * directly mapped. Use 'static' to keep it compatible; stack variables
-        * can be virtually mapped, making them imcompatible with
-        * 'virt_to_phys'.
-        * Hypercall input/output addresses should also be 8-byte aligned.
-        */
-       static u64 hv_extended_cap __aligned(8);
-       static bool hv_extended_cap_queried;
-       u64 status;
-
-       /*
-        * Querying extended capabilities is an extended hypercall. Check if the
-        * partition supports extended hypercall, first.
-        */
-       if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS))
-               return false;
-
-       /* Extended capabilities do not change at runtime. */
-       if (hv_extended_cap_queried)
-               return hv_extended_cap & cap_query;
-
-       status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL,
-                                &hv_extended_cap);
-
-       /*
-        * The query extended capabilities hypercall should not fail under
-        * any normal circumstances. Avoid repeatedly making the hypercall, on
-        * error.
-        */
-       hv_extended_cap_queried = true;
-       status &= HV_HYPERCALL_RESULT_MASK;
-       if (status != HV_STATUS_SUCCESS) {
-               pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n",
-                      status);
-               return false;
-       }
-
-       return hv_extended_cap & cap_query;
-}
-EXPORT_SYMBOL_GPL(hv_query_ext_cap);
index b19ec82..1e51650 100644 (file)
@@ -3,6 +3,7 @@
 
 generated-y += syscalls_32.h
 generated-y += syscalls_64.h
+generated-y += syscalls_x32.h
 generated-y += unistd_32_ia32.h
 generated-y += unistd_64_x32.h
 generated-y += xen-hypercalls.h
index 0603c74..3ad3da9 100644 (file)
@@ -3,25 +3,26 @@
 #define _ASM_X86_ASM_H
 
 #ifdef __ASSEMBLY__
-# define __ASM_FORM(x) x
-# define __ASM_FORM_RAW(x)     x
-# define __ASM_FORM_COMMA(x) x,
+# define __ASM_FORM(x, ...)            x,## __VA_ARGS__
+# define __ASM_FORM_RAW(x, ...)                x,## __VA_ARGS__
+# define __ASM_FORM_COMMA(x, ...)      x,## __VA_ARGS__,
 #else
 #include <linux/stringify.h>
-
-# define __ASM_FORM(x) " " __stringify(x) " "
-# define __ASM_FORM_RAW(x)     __stringify(x)
-# define __ASM_FORM_COMMA(x) " " __stringify(x) ","
+# define __ASM_FORM(x, ...)            " " __stringify(x,##__VA_ARGS__) " "
+# define __ASM_FORM_RAW(x, ...)                    __stringify(x,##__VA_ARGS__)
+# define __ASM_FORM_COMMA(x, ...)      " " __stringify(x,##__VA_ARGS__) ","
 #endif
 
+#define _ASM_BYTES(x, ...)     __ASM_FORM(.byte x,##__VA_ARGS__ ;)
+
 #ifndef __x86_64__
 /* 32 bit */
-# define __ASM_SEL(a,b) __ASM_FORM(a)
-# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
+# define __ASM_SEL(a,b)                __ASM_FORM(a)
+# define __ASM_SEL_RAW(a,b)    __ASM_FORM_RAW(a)
 #else
 /* 64 bit */
-# define __ASM_SEL(a,b) __ASM_FORM(b)
-# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
+# define __ASM_SEL(a,b)                __ASM_FORM(b)
+# define __ASM_SEL_RAW(a,b)    __ASM_FORM_RAW(b)
 #endif
 
 #define __ASM_SIZE(inst, ...)  __ASM_SEL(inst##l##__VA_ARGS__, \
 # define CC_OUT(c) [_cc_ ## c] "=qm"
 #endif
 
+#ifdef __KERNEL__
+
 /* Exception table entry */
 #ifdef __ASSEMBLY__
 # define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
@@ -185,4 +188,6 @@ register unsigned long current_stack_pointer asm(_ASM_SP);
 #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
 #endif /* __ASSEMBLY__ */
 
+#endif /* __KERNEL__ */
+
 #endif /* _ASM_X86_ASM_H */
index f732741..5e754e8 100644 (file)
@@ -269,6 +269,4 @@ static __always_inline int arch_atomic_fetch_xor(int i, atomic_t *v)
 # include <asm/atomic64_64.h>
 #endif
 
-#define ARCH_ATOMIC
-
 #endif /* _ASM_X86_ATOMIC_H */
index 4819d5e..3ba772a 100644 (file)
@@ -54,11 +54,8 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
 #define dma_rmb()      barrier()
 #define dma_wmb()      barrier()
 
-#ifdef CONFIG_X86_32
-#define __smp_mb()     asm volatile("lock; addl $0,-4(%%esp)" ::: "memory", "cc")
-#else
-#define __smp_mb()     asm volatile("lock; addl $0,-4(%%rsp)" ::: "memory", "cc")
-#endif
+#define __smp_mb()     asm volatile("lock; addl $0,-4(%%" _ASM_SP ")" ::: "memory", "cc")
+
 #define __smp_rmb()    dma_rmb()
 #define __smp_wmb()    barrier()
 #define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
index ac37830..d0ce5cf 100644 (file)
 #define X86_FEATURE_EXTD_APICID                ( 3*32+26) /* Extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM            ( 3*32+27) /* AMD multi-node processor */
 #define X86_FEATURE_APERFMPERF         ( 3*32+28) /* P-State hardware coordination feedback capability (APERF/MPERF MSRs) */
-/* free                                        ( 3*32+29) */
+#define X86_FEATURE_RAPL               ( 3*32+29) /* AMD/Hygon RAPL interface */
 #define X86_FEATURE_NONSTOP_TSC_S3     ( 3*32+30) /* TSC doesn't stop in S3 state */
 #define X86_FEATURE_TSC_KNOWN_FREQ     ( 3*32+31) /* TSC has known frequency */
 
 #define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */
 #define X86_FEATURE_SRBDS_CTRL         (18*32+ 9) /* "" SRBDS mitigation MSR available */
 #define X86_FEATURE_MD_CLEAR           (18*32+10) /* VERW clears CPU buffers */
+#define X86_FEATURE_RTM_ALWAYS_ABORT   (18*32+11) /* "" RTM transaction always aborts */
 #define X86_FEATURE_TSX_FORCE_ABORT    (18*32+13) /* "" TSX_FORCE_ABORT */
 #define X86_FEATURE_SERIALIZE          (18*32+14) /* SERIALIZE instruction */
 #define X86_FEATURE_HYBRID_CPU         (18*32+15) /* "" This part has CPUs of more than one type */
index f58de66..8b6bd63 100644 (file)
@@ -9,10 +9,4 @@ int crash_setup_memmap_entries(struct kimage *image,
                struct boot_params *params);
 void crash_smp_send_stop(void);
 
-#ifdef CONFIG_KEXEC_CORE
-void __init crash_reserve_low_1M(void);
-#else
-static inline void __init crash_reserve_low_1M(void) { }
-#endif
-
 #endif /* _ASM_X86_CRASH_H */
index 476082a..e63cf58 100644 (file)
@@ -224,6 +224,26 @@ static inline void store_idt(struct desc_ptr *dtr)
        asm volatile("sidt %0":"=m" (*dtr));
 }
 
+static inline void native_gdt_invalidate(void)
+{
+       const struct desc_ptr invalid_gdt = {
+               .address = 0,
+               .size = 0
+       };
+
+       native_load_gdt(&invalid_gdt);
+}
+
+static inline void native_idt_invalidate(void)
+{
+       const struct desc_ptr invalid_idt = {
+               .address = 0,
+               .size = 0
+       };
+
+       native_load_idt(&invalid_idt);
+}
+
 /*
  * The LTR instruction marks the TSS GDT entry as busy. On 64-bit, the GDT is
  * a read-only remapping. To prevent a page fault, the GDT is switched to the
@@ -421,12 +441,10 @@ extern bool idt_is_f00f_address(unsigned long address);
 
 #ifdef CONFIG_X86_64
 extern void idt_setup_early_pf(void);
-extern void idt_setup_ist_traps(void);
 #else
 static inline void idt_setup_early_pf(void) { }
-static inline void idt_setup_ist_traps(void) { }
 #endif
 
-extern void idt_invalidate(void *addr);
+extern void idt_invalidate(void);
 
 #endif /* _ASM_X86_DESC_H */
index ceeba9f..16bf4d4 100644 (file)
@@ -204,6 +204,14 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
                asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
 }
 
+static inline void fxsave(struct fxregs_state *fx)
+{
+       if (IS_ENABLED(CONFIG_X86_32))
+               asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
+       else
+               asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
+}
+
 /* These macros all use (%edi)/(%rdi) as the single memory argument. */
 #define XSAVE          ".byte " REX_PREFIX "0x0f,0xae,0x27"
 #define XSAVEOPT       ".byte " REX_PREFIX "0x0f,0xae,0x37"
@@ -272,28 +280,6 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
  * This function is called only during boot time when x86 caps are not set
  * up and alternative can not be used yet.
  */
-static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
-{
-       u64 mask = xfeatures_mask_all;
-       u32 lmask = mask;
-       u32 hmask = mask >> 32;
-       int err;
-
-       WARN_ON(system_state != SYSTEM_BOOTING);
-
-       if (boot_cpu_has(X86_FEATURE_XSAVES))
-               XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
-       else
-               XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
-
-       /* We should never fault when copying to a kernel buffer: */
-       WARN_ON_FPU(err);
-}
-
-/*
- * This function is called only during boot time when x86 caps are not set
- * up and alternative can not be used yet.
- */
 static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
 {
        u64 mask = -1;
@@ -578,10 +564,17 @@ static inline void switch_fpu_finish(struct fpu *new_fpu)
         * PKRU state is switched eagerly because it needs to be valid before we
         * return to userland e.g. for a copy_to_user() operation.
         */
-       if (current->mm) {
+       if (!(current->flags & PF_KTHREAD)) {
+               /*
+                * If the PKRU bit in xsave.header.xfeatures is not set,
+                * then the PKRU component was in init state, which means
+                * XRSTOR will set PKRU to 0. If the bit is not set then
+                * get_xsave_addr() will return NULL because the PKRU value
+                * in memory is not valid. This means pkru_val has to be
+                * set to 0 and not to init_pkru_value.
+                */
                pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU);
-               if (pk)
-                       pkru_val = pk->pkru;
+               pkru_val = pk ? pk->pkru : 0;
        }
        __write_pkru(pkru_val);
 }
index 606f5cc..f1366ce 100644 (file)
@@ -52,7 +52,7 @@
  * Support for passing hypercall input parameter block via XMM
  * registers is available
  */
-#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          BIT(4)
+#define HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE           BIT(4)
 /* Support for a virtual guest idle state is available */
 #define HV_X64_GUEST_IDLE_STATE_AVAILABLE              BIT(5)
 /* Frequency MSRs available */
 #define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE           BIT(10)
 /* Support for debug MSRs available */
 #define HV_FEATURE_DEBUG_MSRS_AVAILABLE                        BIT(11)
+/*
+ * Support for returning hypercall output block via XMM
+ * registers is available
+ */
+#define HV_X64_HYPERCALL_XMM_OUTPUT_AVAILABLE          BIT(15)
 /* stimer Direct Mode is available */
 #define HV_STIMER_DIRECT_MODE_AVAILABLE                        BIT(19)
 
 #define HV_X64_NESTED_GUEST_MAPPING_FLUSH              BIT(18)
 #define HV_X64_NESTED_MSR_BITMAP                       BIT(19)
 
+/*
+ * This is specific to AMD and specifies that enlightened TLB flush is
+ * supported. If guest opts in to this feature, ASID invalidations only
+ * flushes gva -> hpa mapping entries. To flush the TLB entries derived
+ * from NPT, hypercalls should be used (HvFlushGuestPhysicalAddressSpace
+ * or HvFlushGuestPhysicalAddressList).
+ */
+#define HV_X64_NESTED_ENLIGHTENED_TLB                  BIT(22)
+
 /* HYPERV_CPUID_ISOLATION_CONFIG.EAX bits. */
 #define HV_PARAVISOR_PRESENT                           BIT(0)
 
@@ -314,6 +328,9 @@ struct hv_tsc_emulation_status {
 #define HV_X64_MSR_TSC_REFERENCE_ENABLE                0x00000001
 #define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12
 
+/* Number of XMM registers used in hypercall input/output */
+#define HV_HYPERCALL_MAX_XMM_REGISTERS         6
+
 struct hv_nested_enlightenments_control {
        struct {
                __u32 directhypercall:1;
index 73d45b0..1345088 100644 (file)
@@ -312,8 +312,8 @@ static __always_inline void __##func(struct pt_regs *regs)
  */
 #define DECLARE_IDTENTRY_VC(vector, func)                              \
        DECLARE_IDTENTRY_RAW_ERRORCODE(vector, func);                   \
-       __visible noinstr void ist_##func(struct pt_regs *regs, unsigned long error_code);      \
-       __visible noinstr void safe_stack_##func(struct pt_regs *regs, unsigned long error_code)
+       __visible noinstr void kernel_##func(struct pt_regs *regs, unsigned long error_code);   \
+       __visible noinstr void   user_##func(struct pt_regs *regs, unsigned long error_code)
 
 /**
  * DEFINE_IDTENTRY_IST - Emit code for IST entry points
@@ -355,33 +355,24 @@ static __always_inline void __##func(struct pt_regs *regs)
        DEFINE_IDTENTRY_RAW_ERRORCODE(func)
 
 /**
- * DEFINE_IDTENTRY_VC_SAFE_STACK - Emit code for VMM communication handler
-                                  which runs on a safe stack.
+ * DEFINE_IDTENTRY_VC_KERNEL - Emit code for VMM communication handler
+                              when raised from kernel mode
  * @func:      Function name of the entry point
  *
  * Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
  */
-#define DEFINE_IDTENTRY_VC_SAFE_STACK(func)                            \
-       DEFINE_IDTENTRY_RAW_ERRORCODE(safe_stack_##func)
+#define DEFINE_IDTENTRY_VC_KERNEL(func)                                \
+       DEFINE_IDTENTRY_RAW_ERRORCODE(kernel_##func)
 
 /**
- * DEFINE_IDTENTRY_VC_IST - Emit code for VMM communication handler
-                           which runs on the VC fall-back stack
+ * DEFINE_IDTENTRY_VC_USER - Emit code for VMM communication handler
+                            when raised from user mode
  * @func:      Function name of the entry point
  *
  * Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
  */
-#define DEFINE_IDTENTRY_VC_IST(func)                           \
-       DEFINE_IDTENTRY_RAW_ERRORCODE(ist_##func)
-
-/**
- * DEFINE_IDTENTRY_VC - Emit code for VMM communication handler
- * @func:      Function name of the entry point
- *
- * Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
- */
-#define DEFINE_IDTENTRY_VC(func)                                       \
-       DEFINE_IDTENTRY_RAW_ERRORCODE(func)
+#define DEFINE_IDTENTRY_VC_USER(func)                          \
+       DEFINE_IDTENTRY_RAW_ERRORCODE(user_##func)
 
 #else  /* CONFIG_X86_64 */
 
@@ -504,7 +495,7 @@ __visible noinstr void func(struct pt_regs *regs,                   \
        .align 8
 SYM_CODE_START(irq_entries_start)
     vector=FIRST_EXTERNAL_VECTOR
-    .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
+    .rept NR_EXTERNAL_VECTORS
        UNWIND_HINT_IRET_REGS
 0 :
        .byte   0x6a, vector
@@ -520,7 +511,7 @@ SYM_CODE_END(irq_entries_start)
        .align 8
 SYM_CODE_START(spurious_entries_start)
     vector=FIRST_SYSTEM_VECTOR
-    .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+    .rept NR_SYSTEM_VECTORS
        UNWIND_HINT_IRET_REGS
 0 :
        .byte   0x6a, vector
index 955b06d..2715843 100644 (file)
 
 #define INTEL_FAM6_TIGERLAKE_L         0x8C    /* Willow Cove */
 #define INTEL_FAM6_TIGERLAKE           0x8D    /* Willow Cove */
-#define INTEL_FAM6_SAPPHIRERAPIDS_X    0x8F    /* Willow Cove */
+
+#define INTEL_FAM6_SAPPHIRERAPIDS_X    0x8F    /* Golden Cove */
 
 #define INTEL_FAM6_ALDERLAKE           0x97    /* Golden Cove / Gracemont */
 #define INTEL_FAM6_ALDERLAKE_L         0x9A    /* Golden Cove / Gracemont */
index 889f8b1..43dcb92 100644 (file)
@@ -26,8 +26,8 @@
  * This file enumerates the exact layout of them:
  */
 
+/* This is used as an interrupt vector when programming the APIC. */
 #define NMI_VECTOR                     0x02
-#define MCE_VECTOR                     0x12
 
 /*
  * IDT vectors usable for external interrupt sources start at 0x20.
@@ -84,7 +84,7 @@
  */
 #define IRQ_WORK_VECTOR                        0xf6
 
-#define UV_BAU_MESSAGE                 0xf5
+/* 0xf5 - unused, was UV_BAU_MESSAGE */
 #define DEFERRED_ERROR_VECTOR          0xf4
 
 /* Vector on which hypervisor callbacks will be delivered */
 #define FIRST_SYSTEM_VECTOR            NR_VECTORS
 #endif
 
+#define NR_EXTERNAL_VECTORS            (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
+#define NR_SYSTEM_VECTORS              (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+
 /*
  * Size the maximum number of interrupts.
  *
index 610a053..0449b12 100644 (file)
@@ -4,8 +4,6 @@
 
 #define HAVE_JUMP_LABEL_BATCH
 
-#define JUMP_LABEL_NOP_SIZE 5
-
 #include <asm/asm.h>
 #include <asm/nops.h>
 
 #include <linux/stringify.h>
 #include <linux/types.h>
 
+#define JUMP_TABLE_ENTRY                               \
+       ".pushsection __jump_table,  \"aw\" \n\t"       \
+       _ASM_ALIGN "\n\t"                               \
+       ".long 1b - . \n\t"                             \
+       ".long %l[l_yes] - . \n\t"                      \
+       _ASM_PTR "%c0 + %c1 - .\n\t"                    \
+       ".popsection \n\t"
+
+#ifdef CONFIG_STACK_VALIDATION
+
+static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
+{
+       asm_volatile_goto("1:"
+               "jmp %l[l_yes] # objtool NOPs this \n\t"
+               JUMP_TABLE_ENTRY
+               : :  "i" (key), "i" (2 | branch) : : l_yes);
+
+       return false;
+l_yes:
+       return true;
+}
+
+#else
+
 static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
 {
        asm_volatile_goto("1:"
                ".byte " __stringify(BYTES_NOP5) "\n\t"
-               ".pushsection __jump_table,  \"aw\" \n\t"
-               _ASM_ALIGN "\n\t"
-               ".long 1b - ., %l[l_yes] - . \n\t"
-               _ASM_PTR "%c0 + %c1 - .\n\t"
-               ".popsection \n\t"
+               JUMP_TABLE_ENTRY
                : :  "i" (key), "i" (branch) : : l_yes);
 
        return false;
@@ -30,16 +48,13 @@ l_yes:
        return true;
 }
 
+#endif /* STACK_VALIDATION */
+
 static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
 {
        asm_volatile_goto("1:"
-               ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t"
-               "2:\n\t"
-               ".pushsection __jump_table,  \"aw\" \n\t"
-               _ASM_ALIGN "\n\t"
-               ".long 1b - ., %l[l_yes] - . \n\t"
-               _ASM_PTR "%c0 + %c1 - .\n\t"
-               ".popsection \n\t"
+               "jmp %l[l_yes]\n\t"
+               JUMP_TABLE_ENTRY
                : :  "i" (key), "i" (branch) : : l_yes);
 
        return false;
@@ -47,41 +62,7 @@ l_yes:
        return true;
 }
 
-#else  /* __ASSEMBLY__ */
-
-.macro STATIC_JUMP_IF_TRUE target, key, def
-.Lstatic_jump_\@:
-       .if \def
-       /* Equivalent to "jmp.d32 \target" */
-       .byte           0xe9
-       .long           \target - .Lstatic_jump_after_\@
-.Lstatic_jump_after_\@:
-       .else
-       .byte           BYTES_NOP5
-       .endif
-       .pushsection __jump_table, "aw"
-       _ASM_ALIGN
-       .long           .Lstatic_jump_\@ - ., \target - .
-       _ASM_PTR        \key - .
-       .popsection
-.endm
-
-.macro STATIC_JUMP_IF_FALSE target, key, def
-.Lstatic_jump_\@:
-       .if \def
-       .byte           BYTES_NOP5
-       .else
-       /* Equivalent to "jmp.d32 \target" */
-       .byte           0xe9
-       .long           \target - .Lstatic_jump_after_\@
-.Lstatic_jump_after_\@:
-       .endif
-       .pushsection __jump_table, "aw"
-       _ASM_ALIGN
-       .long           .Lstatic_jump_\@ - ., \target - .
-       _ASM_PTR        \key + 1 - .
-       .popsection
-.endm
+extern int arch_jump_entry_size(struct jump_entry *entry);
 
 #endif /* __ASSEMBLY__ */
 
index e7bef91..a12a498 100644 (file)
@@ -87,7 +87,10 @@ KVM_X86_OP(set_identity_map_addr)
 KVM_X86_OP(get_mt_mask)
 KVM_X86_OP(load_mmu_pgd)
 KVM_X86_OP_NULL(has_wbinvd_exit)
-KVM_X86_OP(write_l1_tsc_offset)
+KVM_X86_OP(get_l2_tsc_offset)
+KVM_X86_OP(get_l2_tsc_multiplier)
+KVM_X86_OP(write_tsc_offset)
+KVM_X86_OP(write_tsc_multiplier)
 KVM_X86_OP(get_exit_info)
 KVM_X86_OP(check_intercept)
 KVM_X86_OP(handle_exit_irqoff)
@@ -106,8 +109,8 @@ KVM_X86_OP_NULL(set_hv_timer)
 KVM_X86_OP_NULL(cancel_hv_timer)
 KVM_X86_OP(setup_mce)
 KVM_X86_OP(smi_allowed)
-KVM_X86_OP(pre_enter_smm)
-KVM_X86_OP(pre_leave_smm)
+KVM_X86_OP(enter_smm)
+KVM_X86_OP(leave_smm)
 KVM_X86_OP(enable_smi_window)
 KVM_X86_OP_NULL(mem_enc_op)
 KVM_X86_OP_NULL(mem_enc_reg_region)
index 9c7ced0..974cbfb 100644 (file)
@@ -85,7 +85,7 @@
 #define KVM_REQ_APICV_UPDATE \
        KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_TLB_FLUSH_CURRENT      KVM_ARCH_REQ(26)
-#define KVM_REQ_HV_TLB_FLUSH \
+#define KVM_REQ_TLB_FLUSH_GUEST \
        KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_APF_READY              KVM_ARCH_REQ(28)
 #define KVM_REQ_MSR_FILTER_CHANGED     KVM_ARCH_REQ(29)
@@ -269,12 +269,36 @@ enum x86_intercept_stage;
 struct kvm_kernel_irq_routing_entry;
 
 /*
- * the pages used as guest page table on soft mmu are tracked by
- * kvm_memory_slot.arch.gfn_track which is 16 bits, so the role bits used
- * by indirect shadow page can not be more than 15 bits.
+ * kvm_mmu_page_role tracks the properties of a shadow page (where shadow page
+ * also includes TDP pages) to determine whether or not a page can be used in
+ * the given MMU context.  This is a subset of the overall kvm_mmu_role to
+ * minimize the size of kvm_memory_slot.arch.gfn_track, i.e. allows allocating
+ * 2 bytes per gfn instead of 4 bytes per gfn.
  *
- * Currently, we used 14 bits that are @level, @gpte_is_8_bytes, @quadrant, @access,
- * @nxe, @cr0_wp, @smep_andnot_wp and @smap_andnot_wp.
+ * Indirect upper-level shadow pages are tracked for write-protection via
+ * gfn_track.  As above, gfn_track is a 16 bit counter, so KVM must not create
+ * more than 2^16-1 upper-level shadow pages at a single gfn, otherwise
+ * gfn_track will overflow and explosions will ensure.
+ *
+ * A unique shadow page (SP) for a gfn is created if and only if an existing SP
+ * cannot be reused.  The ability to reuse a SP is tracked by its role, which
+ * incorporates various mode bits and properties of the SP.  Roughly speaking,
+ * the number of unique SPs that can theoretically be created is 2^n, where n
+ * is the number of bits that are used to compute the role.
+ *
+ * But, even though there are 18 bits in the mask below, not all combinations
+ * of modes and flags are possible.  The maximum number of possible upper-level
+ * shadow pages for a single gfn is in the neighborhood of 2^13.
+ *
+ *   - invalid shadow pages are not accounted.
+ *   - level is effectively limited to four combinations, not 16 as the number
+ *     bits would imply, as 4k SPs are not tracked (allowed to go unsync).
+ *   - level is effectively unused for non-PAE paging because there is exactly
+ *     one upper level (see 4k SP exception above).
+ *   - quadrant is used only for non-PAE paging and is exclusive with
+ *     gpte_is_8_bytes.
+ *   - execonly and ad_disabled are used only for nested EPT, which makes it
+ *     exclusive with quadrant.
  */
 union kvm_mmu_page_role {
        u32 word;
@@ -285,7 +309,7 @@ union kvm_mmu_page_role {
                unsigned direct:1;
                unsigned access:3;
                unsigned invalid:1;
-               unsigned nxe:1;
+               unsigned efer_nx:1;
                unsigned cr0_wp:1;
                unsigned smep_andnot_wp:1;
                unsigned smap_andnot_wp:1;
@@ -303,13 +327,26 @@ union kvm_mmu_page_role {
        };
 };
 
-union kvm_mmu_extended_role {
 /*
- * This structure complements kvm_mmu_page_role caching everything needed for
- * MMU configuration. If nothing in both these structures changed, MMU
- * re-configuration can be skipped. @valid bit is set on first usage so we don't
- * treat all-zero structure as valid data.
+ * kvm_mmu_extended_role complements kvm_mmu_page_role, tracking properties
+ * relevant to the current MMU configuration.   When loading CR0, CR4, or EFER,
+ * including on nested transitions, if nothing in the full role changes then
+ * MMU re-configuration can be skipped. @valid bit is set on first usage so we
+ * don't treat all-zero structure as valid data.
+ *
+ * The properties that are tracked in the extended role but not the page role
+ * are for things that either (a) do not affect the validity of the shadow page
+ * or (b) are indirectly reflected in the shadow page's role.  For example,
+ * CR4.PKE only affects permission checks for software walks of the guest page
+ * tables (because KVM doesn't support Protection Keys with shadow paging), and
+ * CR0.PG, CR4.PAE, and CR4.PSE are indirectly reflected in role.level.
+ *
+ * Note, SMEP and SMAP are not redundant with sm*p_andnot_wp in the page role.
+ * If CR0.WP=1, KVM can reuse shadow pages for the guest regardless of SMEP and
+ * SMAP, but the MMU's permission checks for software walks need to be SMEP and
+ * SMAP aware regardless of CR0.WP.
  */
+union kvm_mmu_extended_role {
        u32 word;
        struct {
                unsigned int valid:1;
@@ -320,7 +357,7 @@ union kvm_mmu_extended_role {
                unsigned int cr4_pke:1;
                unsigned int cr4_smap:1;
                unsigned int cr4_smep:1;
-               unsigned int maxphyaddr:6;
+               unsigned int cr4_la57:1;
        };
 };
 
@@ -420,11 +457,6 @@ struct kvm_mmu {
 
        struct rsvd_bits_validate guest_rsvd_check;
 
-       /* Can have large pages at levels 2..last_nonleaf_level-1. */
-       u8 last_nonleaf_level;
-
-       bool nx;
-
        u64 pdptrs[4]; /* pae */
 };
 
@@ -543,6 +575,15 @@ struct kvm_vcpu_hv {
        struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
        DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
        cpumask_t tlb_flush;
+       bool enforce_cpuid;
+       struct {
+               u32 features_eax; /* HYPERV_CPUID_FEATURES.EAX */
+               u32 features_ebx; /* HYPERV_CPUID_FEATURES.EBX */
+               u32 features_edx; /* HYPERV_CPUID_FEATURES.EDX */
+               u32 enlightenments_eax; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EAX */
+               u32 enlightenments_ebx; /* HYPERV_CPUID_ENLIGHTMENT_INFO.EBX */
+               u32 syndbg_cap_eax; /* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */
+       } cpuid_cache;
 };
 
 /* Xen HVM per vcpu emulation context */
@@ -707,7 +748,7 @@ struct kvm_vcpu_arch {
        } st;
 
        u64 l1_tsc_offset;
-       u64 tsc_offset;
+       u64 tsc_offset; /* current tsc offset */
        u64 last_guest_tsc;
        u64 last_host_tsc;
        u64 tsc_offset_adjustment;
@@ -721,7 +762,8 @@ struct kvm_vcpu_arch {
        u32 virtual_tsc_khz;
        s64 ia32_tsc_adjust_msr;
        u64 msr_ia32_power_ctl;
-       u64 tsc_scaling_ratio;
+       u64 l1_tsc_scaling_ratio;
+       u64 tsc_scaling_ratio; /* current scaling ratio */
 
        atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
        unsigned nmi_pending; /* NMI queued after currently running handler */
@@ -829,7 +871,7 @@ struct kvm_vcpu_arch {
        bool l1tf_flush_l1d;
 
        /* Host CPU on which VM-entry was most recently attempted */
-       unsigned int last_vmentry_cpu;
+       int last_vmentry_cpu;
 
        /* AMD MSRC001_0015 Hardware Configuration */
        u64 msr_hwcr;
@@ -851,6 +893,16 @@ struct kvm_vcpu_arch {
 
        /* Protected Guests */
        bool guest_state_protected;
+
+       /*
+        * Set when PDPTS were loaded directly by the userspace without
+        * reading the guest memory
+        */
+       bool pdptrs_from_userspace;
+
+#if IS_ENABLED(CONFIG_HYPERV)
+       hpa_t hv_root_tdp;
+#endif
 };
 
 struct kvm_lpage_info {
@@ -1002,7 +1054,7 @@ struct kvm_arch {
        struct kvm_apic_map __rcu *apic_map;
        atomic_t apic_map_dirty;
 
-       bool apic_access_page_done;
+       bool apic_access_memslot_enabled;
        unsigned long apicv_inhibit_reasons;
 
        gpa_t wall_clock;
@@ -1062,11 +1114,19 @@ struct kvm_arch {
        bool exception_payload_enabled;
 
        bool bus_lock_detection_enabled;
+       /*
+        * If exit_on_emulation_error is set, and the in-kernel instruction
+        * emulator fails to emulate an instruction, allow userspace
+        * the opportunity to look at it.
+        */
+       bool exit_on_emulation_error;
 
        /* Deflect RDMSR and WRMSR to user space when they trigger a #GP */
        u32 user_space_msr_mask;
        struct kvm_x86_msr_filter __rcu *msr_filter;
 
+       u32 hypercall_exit_enabled;
+
        /* Guest can access the SGX PROVISIONKEY. */
        bool sgx_provisioning_allowed;
 
@@ -1124,23 +1184,35 @@ struct kvm_arch {
         */
        spinlock_t tdp_mmu_pages_lock;
 #endif /* CONFIG_X86_64 */
+
+       /*
+        * If set, rmaps have been allocated for all memslots and should be
+        * allocated for any newly created or modified memslots.
+        */
+       bool memslots_have_rmaps;
+
+#if IS_ENABLED(CONFIG_HYPERV)
+       hpa_t   hv_root_tdp;
+       spinlock_t hv_root_tdp_lock;
+#endif
 };
 
 struct kvm_vm_stat {
-       ulong mmu_shadow_zapped;
-       ulong mmu_pte_write;
-       ulong mmu_pde_zapped;
-       ulong mmu_flooded;
-       ulong mmu_recycled;
-       ulong mmu_cache_miss;
-       ulong mmu_unsync;
-       ulong remote_tlb_flush;
-       ulong lpages;
-       ulong nx_lpage_splits;
-       ulong max_mmu_page_hash_collisions;
+       struct kvm_vm_stat_generic generic;
+       u64 mmu_shadow_zapped;
+       u64 mmu_pte_write;
+       u64 mmu_pde_zapped;
+       u64 mmu_flooded;
+       u64 mmu_recycled;
+       u64 mmu_cache_miss;
+       u64 mmu_unsync;
+       u64 lpages;
+       u64 nx_lpage_splits;
+       u64 max_mmu_page_hash_collisions;
 };
 
 struct kvm_vcpu_stat {
+       struct kvm_vcpu_stat_generic generic;
        u64 pf_fixed;
        u64 pf_guest;
        u64 tlb_flush;
@@ -1154,10 +1226,6 @@ struct kvm_vcpu_stat {
        u64 nmi_window_exits;
        u64 l1d_flush;
        u64 halt_exits;
-       u64 halt_successful_poll;
-       u64 halt_attempted_poll;
-       u64 halt_poll_invalid;
-       u64 halt_wakeup;
        u64 request_irq_exits;
        u64 irq_exits;
        u64 host_state_reload;
@@ -1168,11 +1236,10 @@ struct kvm_vcpu_stat {
        u64 irq_injections;
        u64 nmi_injections;
        u64 req_event;
-       u64 halt_poll_success_ns;
-       u64 halt_poll_fail_ns;
        u64 nested_run;
        u64 directed_yield_attempted;
        u64 directed_yield_successful;
+       u64 guest_mode;
 };
 
 struct x86_instruction_info;
@@ -1304,8 +1371,10 @@ struct kvm_x86_ops {
 
        bool (*has_wbinvd_exit)(void);
 
-       /* Returns actual tsc_offset set in active VMCS */
-       u64 (*write_l1_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+       u64 (*get_l2_tsc_offset)(struct kvm_vcpu *vcpu);
+       u64 (*get_l2_tsc_multiplier)(struct kvm_vcpu *vcpu);
+       void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+       void (*write_tsc_multiplier)(struct kvm_vcpu *vcpu, u64 multiplier);
 
        /*
         * Retrieve somewhat arbitrary exit information.  Intended to be used
@@ -1363,8 +1432,8 @@ struct kvm_x86_ops {
        void (*setup_mce)(struct kvm_vcpu *vcpu);
 
        int (*smi_allowed)(struct kvm_vcpu *vcpu, bool for_injection);
-       int (*pre_enter_smm)(struct kvm_vcpu *vcpu, char *smstate);
-       int (*pre_leave_smm)(struct kvm_vcpu *vcpu, const char *smstate);
+       int (*enter_smm)(struct kvm_vcpu *vcpu, char *smstate);
+       int (*leave_smm)(struct kvm_vcpu *vcpu, const char *smstate);
        void (*enable_smi_window)(struct kvm_vcpu *vcpu);
 
        int (*mem_enc_op)(struct kvm *kvm, void __user *argp);
@@ -1423,6 +1492,7 @@ struct kvm_arch_async_pf {
 extern u32 __read_mostly kvm_nr_uret_msrs;
 extern u64 __read_mostly host_efer;
 extern bool __read_mostly allow_smaller_maxphyaddr;
+extern bool __read_mostly enable_apicv;
 extern struct kvm_x86_ops kvm_x86_ops;
 
 #define KVM_X86_OP(func) \
@@ -1463,6 +1533,7 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
 void kvm_mmu_init_vm(struct kvm *kvm);
 void kvm_mmu_uninit_vm(struct kvm *kvm);
 
+void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu);
 void kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
                                      struct kvm_memory_slot *memslot,
@@ -1477,7 +1548,6 @@ unsigned long kvm_mmu_calculate_default_mmu_pages(struct kvm *kvm);
 void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned long kvm_nr_mmu_pages);
 
 int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3);
-bool pdptrs_changed(struct kvm_vcpu *vcpu);
 
 int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
                          const void *val, int bytes);
@@ -1650,6 +1720,7 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn);
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
 void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
                        ulong roots_to_free);
+void kvm_mmu_free_guest_mode_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu);
 gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
                           struct x86_exception *exception);
 gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva,
@@ -1662,7 +1733,6 @@ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
                                struct x86_exception *exception);
 
 bool kvm_apicv_activated(struct kvm *kvm);
-void kvm_apicv_init(struct kvm *kvm, bool enable);
 void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu);
 void kvm_request_apicv_update(struct kvm *kvm, bool activate,
                              unsigned long bit);
@@ -1675,8 +1745,7 @@ void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
 void kvm_mmu_invalidate_gva(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
                            gva_t gva, hpa_t root_hpa);
 void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid);
-void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd, bool skip_tlb_flush,
-                    bool skip_mmu_sync);
+void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd);
 
 void kvm_configure_mmu(bool enable_tdp, int tdp_max_root_level,
                       int tdp_huge_page_level);
@@ -1788,8 +1857,10 @@ static inline bool kvm_is_supported_user_return_msr(u32 msr)
        return kvm_find_user_return_msr(msr) >= 0;
 }
 
-u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc, u64 ratio);
 u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
+u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier);
+u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier);
 
 unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu);
 bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
@@ -1863,4 +1934,6 @@ static inline int kvm_cpu_get_apicid(int mps_cpu)
 
 int kvm_cpu_dirty_log_size(void);
 
+int alloc_all_memslots_rmaps(struct kvm *kvm);
+
 #endif /* _ASM_X86_KVM_HOST_H */
index ddfb3ca..0607ec4 100644 (file)
@@ -305,7 +305,7 @@ extern void apei_mce_report_mem_error(int corrected,
 /* These may be used by multiple smca_hwid_mcatypes */
 enum smca_bank_types {
        SMCA_LS = 0,    /* Load Store */
-       SMCA_LS_V2,     /* Load Store */
+       SMCA_LS_V2,
        SMCA_IF,        /* Instruction Fetch */
        SMCA_L2_CACHE,  /* L2 Cache */
        SMCA_DE,        /* Decoder Unit */
@@ -314,17 +314,22 @@ enum smca_bank_types {
        SMCA_FP,        /* Floating Point */
        SMCA_L3_CACHE,  /* L3 Cache */
        SMCA_CS,        /* Coherent Slave */
-       SMCA_CS_V2,     /* Coherent Slave */
+       SMCA_CS_V2,
        SMCA_PIE,       /* Power, Interrupts, etc. */
        SMCA_UMC,       /* Unified Memory Controller */
+       SMCA_UMC_V2,
        SMCA_PB,        /* Parameter Block */
        SMCA_PSP,       /* Platform Security Processor */
-       SMCA_PSP_V2,    /* Platform Security Processor */
+       SMCA_PSP_V2,
        SMCA_SMU,       /* System Management Unit */
-       SMCA_SMU_V2,    /* System Management Unit */
+       SMCA_SMU_V2,
        SMCA_MP5,       /* Microprocessor 5 Unit */
        SMCA_NBIO,      /* Northbridge IO Unit */
        SMCA_PCIE,      /* PCI Express Unit */
+       SMCA_PCIE_V2,
+       SMCA_XGMI_PCS,  /* xGMI PCS Unit */
+       SMCA_XGMI_PHY,  /* xGMI PHY Unit */
+       SMCA_WAFL_PHY,  /* WAFL PHY Unit */
        N_SMCA_BANK_TYPES
 };
 
index 211ba33..a7c4134 100644 (file)
 
 #define MSR_TFA_RTM_FORCE_ABORT_BIT    0
 #define MSR_TFA_RTM_FORCE_ABORT                BIT_ULL(MSR_TFA_RTM_FORCE_ABORT_BIT)
+#define MSR_TFA_TSX_CPUID_CLEAR_BIT    1
+#define MSR_TFA_TSX_CPUID_CLEAR                BIT_ULL(MSR_TFA_TSX_CPUID_CLEAR_BIT)
+#define MSR_TFA_SDV_ENABLE_RTM_BIT     2
+#define MSR_TFA_SDV_ENABLE_RTM         BIT_ULL(MSR_TFA_SDV_ENABLE_RTM_BIT)
 
 /* P4/Xeon+ specific */
 #define MSR_IA32_MCG_EAX               0x00000180
index c1e5e81..c5573ea 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_NOPS_H
 #define _ASM_X86_NOPS_H
 
+#include <asm/asm.h>
+
 /*
  * Define nops for use with alternative() and for tracing.
  */
 
 #endif /* CONFIG_64BIT */
 
-#ifdef __ASSEMBLY__
-#define _ASM_MK_NOP(x) .byte x
-#else
-#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
-#endif
-
-#define ASM_NOP1 _ASM_MK_NOP(BYTES_NOP1)
-#define ASM_NOP2 _ASM_MK_NOP(BYTES_NOP2)
-#define ASM_NOP3 _ASM_MK_NOP(BYTES_NOP3)
-#define ASM_NOP4 _ASM_MK_NOP(BYTES_NOP4)
-#define ASM_NOP5 _ASM_MK_NOP(BYTES_NOP5)
-#define ASM_NOP6 _ASM_MK_NOP(BYTES_NOP6)
-#define ASM_NOP7 _ASM_MK_NOP(BYTES_NOP7)
-#define ASM_NOP8 _ASM_MK_NOP(BYTES_NOP8)
+#define ASM_NOP1 _ASM_BYTES(BYTES_NOP1)
+#define ASM_NOP2 _ASM_BYTES(BYTES_NOP2)
+#define ASM_NOP3 _ASM_BYTES(BYTES_NOP3)
+#define ASM_NOP4 _ASM_BYTES(BYTES_NOP4)
+#define ASM_NOP5 _ASM_BYTES(BYTES_NOP5)
+#define ASM_NOP6 _ASM_BYTES(BYTES_NOP6)
+#define ASM_NOP7 _ASM_BYTES(BYTES_NOP7)
+#define ASM_NOP8 _ASM_BYTES(BYTES_NOP8)
 
 #define ASM_NOP_MAX 8
 
index 7555b48..4d5810c 100644 (file)
@@ -34,9 +34,9 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
        copy_page(to, from);
 }
 
-#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
-#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#define alloc_zeroed_user_highpage_movable(vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, vma, vaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 
 #ifndef __pa
 #define __pa(x)                __phys_addr((unsigned long)(x))
index ca840fe..4bde0dc 100644 (file)
@@ -75,7 +75,7 @@ void copy_page(void *to, void *from);
  *
  * With page table isolation enabled, we map the LDT in ... [stay tuned]
  */
-static inline unsigned long task_size_max(void)
+static __always_inline unsigned long task_size_max(void)
 {
        unsigned long ret;
 
index 544f41a..8fc1b50 100644 (file)
@@ -478,6 +478,7 @@ struct x86_pmu_lbr {
 
 extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap);
 extern void perf_check_microcode(void);
+extern void perf_clear_dirty_counters(void);
 extern int x86_perf_rdpmc_index(struct perf_event *event);
 #else
 static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
index f8cb8af..fe5efbc 100644 (file)
@@ -44,7 +44,7 @@ static __always_inline void preempt_count_set(int pc)
 #define init_task_preempt_count(p) do { } while (0)
 
 #define init_idle_preempt_count(p, cpu) do { \
-       per_cpu(__preempt_count, (cpu)) = PREEMPT_ENABLED; \
+       per_cpu(__preempt_count, (cpu)) = PREEMPT_DISABLED; \
 } while (0)
 
 /*
index 556b2b1..364d0e4 100644 (file)
@@ -663,6 +663,7 @@ extern void load_direct_gdt(int);
 extern void load_fixmap_gdt(int);
 extern void load_percpu_segment(int);
 extern void cpu_init(void);
+extern void cpu_init_secondary(void);
 extern void cpu_init_exception_handling(void);
 extern void cr4_init(void);
 
index 629c3df..2cef6c5 100644 (file)
@@ -9,8 +9,13 @@
 #define __ASM_X86_SEV_COMMON_H
 
 #define GHCB_MSR_INFO_POS              0
-#define GHCB_MSR_INFO_MASK             (BIT_ULL(12) - 1)
+#define GHCB_DATA_LOW                  12
+#define GHCB_MSR_INFO_MASK             (BIT_ULL(GHCB_DATA_LOW) - 1)
 
+#define GHCB_DATA(v)                   \
+       (((unsigned long)(v) & ~GHCB_MSR_INFO_MASK) >> GHCB_DATA_LOW)
+
+/* SEV Information Request/Response */
 #define GHCB_MSR_SEV_INFO_RESP         0x001
 #define GHCB_MSR_SEV_INFO_REQ          0x002
 #define GHCB_MSR_VER_MAX_POS           48
@@ -28,6 +33,7 @@
 #define GHCB_MSR_PROTO_MAX(v)          (((v) >> GHCB_MSR_VER_MAX_POS) & GHCB_MSR_VER_MAX_MASK)
 #define GHCB_MSR_PROTO_MIN(v)          (((v) >> GHCB_MSR_VER_MIN_POS) & GHCB_MSR_VER_MIN_MASK)
 
+/* CPUID Request/Response */
 #define GHCB_MSR_CPUID_REQ             0x004
 #define GHCB_MSR_CPUID_RESP            0x005
 #define GHCB_MSR_CPUID_FUNC_POS                32
                (((unsigned long)reg & GHCB_MSR_CPUID_REG_MASK) << GHCB_MSR_CPUID_REG_POS) | \
                (((unsigned long)fn) << GHCB_MSR_CPUID_FUNC_POS))
 
+/* AP Reset Hold */
+#define GHCB_MSR_AP_RESET_HOLD_REQ             0x006
+#define GHCB_MSR_AP_RESET_HOLD_RESP            0x007
+
+/* GHCB Hypervisor Feature Request/Response */
+#define GHCB_MSR_HV_FT_REQ                     0x080
+#define GHCB_MSR_HV_FT_RESP                    0x081
+
 #define GHCB_MSR_TERM_REQ              0x100
 #define GHCB_MSR_TERM_REASON_SET_POS   12
 #define GHCB_MSR_TERM_REASON_SET_MASK  0xf
index 9c31e0e..05f3e21 100644 (file)
@@ -13,7 +13,7 @@
 /*
  * This file contains both data structures defined by SGX architecture and Linux
  * defined software data structures and functions.  The two should not be mixed
- * together for better readibility.  The architectural definitions come first.
+ * together for better readability.  The architectural definitions come first.
  */
 
 /* The SGX specific CPUID function. */
index b6ffe58..24a8d6c 100644 (file)
@@ -11,7 +11,7 @@
  * The same segment is shared by percpu area and stack canary.  On
  * x86_64, percpu symbols are zero based and %gs (64-bit) points to the
  * base of percpu area.  The first occupant of the percpu area is always
- * fixed_percpu_data which contains stack_canary at the approproate
+ * fixed_percpu_data which contains stack_canary at the appropriate
  * offset.  On x86_32, the stack canary is just a regular percpu
  * variable.
  *
index 772e60e..e322676 100644 (file)
@@ -156,6 +156,12 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
        u64 avic_physical_id;   /* Offset 0xf8 */
        u8 reserved_7[8];
        u64 vmsa_pa;            /* Used for an SEV-ES guest */
+       u8 reserved_8[720];
+       /*
+        * Offset 0x3e0, 32 bytes reserved
+        * for use by hypervisor/software.
+        */
+       u8 reserved_sw[32];
 };
 
 
@@ -314,7 +320,7 @@ struct ghcb {
 
 
 #define EXPECTED_VMCB_SAVE_AREA_SIZE           1032
-#define EXPECTED_VMCB_CONTROL_AREA_SIZE                272
+#define EXPECTED_VMCB_CONTROL_AREA_SIZE                1024
 #define EXPECTED_GHCB_SIZE                     PAGE_SIZE
 
 static inline void __unused_size_checks(void)
@@ -326,7 +332,6 @@ static inline void __unused_size_checks(void)
 
 struct vmcb {
        struct vmcb_control_area control;
-       u8 reserved_control[1024 - sizeof(struct vmcb_control_area)];
        struct vmcb_save_area save;
 } __packed;
 
index 7cbf733..f7e2d82 100644 (file)
@@ -21,13 +21,12 @@ extern const sys_call_ptr_t sys_call_table[];
 
 #if defined(CONFIG_X86_32)
 #define ia32_sys_call_table sys_call_table
-#endif
-
-#if defined(CONFIG_IA32_EMULATION)
+#else
+/*
+ * These may not exist, but still put the prototypes in so we
+ * can use IS_ENABLED().
+ */
 extern const sys_call_ptr_t ia32_sys_call_table[];
-#endif
-
-#ifdef CONFIG_X86_X32_ABI
 extern const sys_call_ptr_t x32_sys_call_table[];
 #endif
 
@@ -160,7 +159,7 @@ static inline int syscall_get_arch(struct task_struct *task)
                ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
 }
 
-void do_syscall_64(unsigned long nr, struct pt_regs *regs);
+void do_syscall_64(struct pt_regs *regs, int nr);
 void do_int80_syscall_32(struct pt_regs *regs);
 long do_fast_syscall_32(struct pt_regs *regs);
 
index 80c08c7..6a2827d 100644 (file)
@@ -17,7 +17,7 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
  * __x64_sys_*()         - 64-bit native syscall
  * __ia32_sys_*()        - 32-bit native syscall or common compat syscall
  * __ia32_compat_sys_*() - 32-bit compat syscall
- * __x32_compat_sys_*()  - 64-bit X32 compat syscall
+ * __x64_compat_sys_*()  - 64-bit X32 compat syscall
  *
  * The registers are decoded according to the ABI:
  * 64-bit: RDI, RSI, RDX, R10, R8, R9
@@ -166,17 +166,17 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
  * with x86_64 obviously do not need such care.
  */
 #define __X32_COMPAT_SYS_STUB0(name)                                   \
-       __SYS_STUB0(x32, compat_sys_##name)
+       __SYS_STUB0(x64, compat_sys_##name)
 
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)                           \
-       __SYS_STUBx(x32, compat_sys##name,                              \
+       __SYS_STUBx(x64, compat_sys##name,                              \
                    SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
 
 #define __X32_COMPAT_COND_SYSCALL(name)                                        \
-       __COND_SYSCALL(x32, compat_sys_##name)
+       __COND_SYSCALL(x64, compat_sys_##name)
 
 #define __X32_COMPAT_SYS_NI(name)                                      \
-       __SYS_NI(x32, compat_sys_##name)
+       __SYS_NI(x64, compat_sys_##name)
 #else /* CONFIG_X86_X32 */
 #define __X32_COMPAT_SYS_STUB0(name)
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)
index c1c3d31..80e9d52 100644 (file)
@@ -13,7 +13,7 @@
 #  define __ARCH_WANT_SYS_OLD_MMAP
 #  define __ARCH_WANT_SYS_OLD_SELECT
 
-#  define __NR_ia32_syscall_max __NR_syscall_max
+#  define IA32_NR_syscalls (__NR_syscalls)
 
 # else
 
 #  define __ARCH_WANT_COMPAT_SYS_PWRITEV64
 #  define __ARCH_WANT_COMPAT_SYS_PREADV64V2
 #  define __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
+#  define X32_NR_syscalls (__NR_x32_syscalls)
+#  define IA32_NR_syscalls (__NR_ia32_syscalls)
 
 # endif
 
-# define NR_syscalls (__NR_syscall_max + 1)
-# define X32_NR_syscalls (__NR_x32_syscall_max + 1)
-# define IA32_NR_syscalls (__NR_ia32_syscall_max + 1)
+# define NR_syscalls (__NR_syscalls)
 
 # define __ARCH_WANT_NEW_STAT
 # define __ARCH_WANT_OLD_READDIR
index 5fdfcb4..054604a 100644 (file)
@@ -2,10 +2,12 @@
 #ifndef _ASM_X86_HWCAP2_H
 #define _ASM_X86_HWCAP2_H
 
+#include <linux/const.h>
+
 /* MONITOR/MWAIT enabled in Ring 3 */
-#define HWCAP2_RING3MWAIT              (1 << 0)
+#define HWCAP2_RING3MWAIT              _BITUL(0)
 
 /* Kernel allows FSGSBASE instructions available in Ring 3 */
-#define HWCAP2_FSGSBASE                        BIT(1)
+#define HWCAP2_FSGSBASE                        _BITUL(1)
 
 #endif
index 0662f64..a6c327f 100644 (file)
@@ -159,6 +159,19 @@ struct kvm_sregs {
        __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
 };
 
+struct kvm_sregs2 {
+       /* out (KVM_GET_SREGS2) / in (KVM_SET_SREGS2) */
+       struct kvm_segment cs, ds, es, fs, gs, ss;
+       struct kvm_segment tr, ldt;
+       struct kvm_dtable gdt, idt;
+       __u64 cr0, cr2, cr3, cr4, cr8;
+       __u64 efer;
+       __u64 apic_base;
+       __u64 flags;
+       __u64 pdptrs[4];
+};
+#define KVM_SREGS2_FLAGS_PDPTRS_VALID 1
+
 /* for KVM_GET_FPU and KVM_SET_FPU */
 struct kvm_fpu {
        __u8  fpr[8][16];
index 950afeb..5146bba 100644 (file)
@@ -33,6 +33,8 @@
 #define KVM_FEATURE_PV_SCHED_YIELD     13
 #define KVM_FEATURE_ASYNC_PF_INT       14
 #define KVM_FEATURE_MSI_EXT_DEST_ID    15
+#define KVM_FEATURE_HC_MAP_GPA_RANGE   16
+#define KVM_FEATURE_MIGRATION_CONTROL  17
 
 #define KVM_HINTS_REALTIME      0
 
@@ -54,6 +56,7 @@
 #define MSR_KVM_POLL_CONTROL   0x4b564d05
 #define MSR_KVM_ASYNC_PF_INT   0x4b564d06
 #define MSR_KVM_ASYNC_PF_ACK   0x4b564d07
+#define MSR_KVM_MIGRATION_CONTROL      0x4b564d08
 
 struct kvm_steal_time {
        __u64 steal;
@@ -90,6 +93,16 @@ struct kvm_clock_pairing {
 /* MSR_KVM_ASYNC_PF_INT */
 #define KVM_ASYNC_PF_VEC_MASK                  GENMASK(7, 0)
 
+/* MSR_KVM_MIGRATION_CONTROL */
+#define KVM_MIGRATION_READY            (1 << 0)
+
+/* KVM_HC_MAP_GPA_RANGE */
+#define KVM_MAP_GPA_RANGE_PAGE_SZ_4K   0
+#define KVM_MAP_GPA_RANGE_PAGE_SZ_2M   (1 << 0)
+#define KVM_MAP_GPA_RANGE_PAGE_SZ_1G   (1 << 1)
+#define KVM_MAP_GPA_RANGE_ENC_STAT(n)  (n << 4)
+#define KVM_MAP_GPA_RANGE_ENCRYPTED    KVM_MAP_GPA_RANGE_ENC_STAT(1)
+#define KVM_MAP_GPA_RANGE_DECRYPTED    KVM_MAP_GPA_RANGE_ENC_STAT(0)
 
 /* Operations for KVM_HC_MMU_OP */
 #define KVM_MMU_OP_WRITE_PTE            1
index 554f75f..efa9693 100644 (file)
 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE          1
 #define SVM_VMGEXIT_UNSUPPORTED_EVENT          0x8000ffff
 
+/* Exit code reserved for hypervisor/software use */
+#define SVM_EXIT_SW                            0xf0000000
+
 #define SVM_EXIT_ERR           -1
 
 #define SVM_EXIT_REASONS \
index 49ae4e1..7de599e 100644 (file)
@@ -197,7 +197,8 @@ static int __init ffh_cstate_init(void)
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
        if (c->x86_vendor != X86_VENDOR_INTEL &&
-           c->x86_vendor != X86_VENDOR_AMD)
+           c->x86_vendor != X86_VENDOR_AMD &&
+           c->x86_vendor != X86_VENDOR_HYGON)
                return -1;
 
        cpu_cstate_entry = alloc_percpu(struct cstate_entry);
index 6fe5b44..e9da3dc 100644 (file)
@@ -75,7 +75,7 @@ do {                                                                  \
        }                                                               \
 } while (0)
 
-const unsigned char x86nops[] =
+static const unsigned char x86nops[] =
 {
        BYTES_NOP1,
        BYTES_NOP2,
@@ -301,8 +301,8 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
                        instr, instr, a->instrlen,
                        replacement, a->replacementlen);
 
-               DUMP_BYTES(instr, a->instrlen, "%px: old_insn: ", instr);
-               DUMP_BYTES(replacement, a->replacementlen, "%px: rpl_insn: ", replacement);
+               DUMP_BYTES(instr, a->instrlen, "%px:   old_insn: ", instr);
+               DUMP_BYTES(replacement, a->replacementlen, "%px:   rpl_insn: ", replacement);
 
                memcpy(insn_buff, replacement, a->replacementlen);
                insn_buff_sz = a->replacementlen;
index 0908309..23dda36 100644 (file)
@@ -25,6 +25,7 @@
 #define PCI_DEVICE_ID_AMD_17H_M60H_DF_F4 0x144c
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
 #define PCI_DEVICE_ID_AMD_19H_DF_F4    0x1654
+#define PCI_DEVICE_ID_AMD_19H_M50H_DF_F4 0x166e
 
 /* Protect the PCI config register pairs used for SMN and DF indirect access. */
 static DEFINE_MUTEX(smn_mutex);
@@ -57,6 +58,7 @@ static const struct pci_device_id amd_nb_misc_ids[] = {
        { 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) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) },
        {}
 };
 
@@ -72,6 +74,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M60H_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_19H_DF_F4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F4) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
        {}
 };
index c06ac56..b7c0030 100644 (file)
@@ -646,6 +646,10 @@ static void early_init_amd(struct cpuinfo_x86 *c)
        if (c->x86_power & BIT(12))
                set_cpu_cap(c, X86_FEATURE_ACC_POWER);
 
+       /* Bit 14 indicates the Runtime Average Power Limit interface. */
+       if (c->x86_power & BIT(14))
+               set_cpu_cap(c, X86_FEATURE_RAPL);
+
 #ifdef CONFIG_X86_64
        set_cpu_cap(c, X86_FEATURE_SYSCALL32);
 #else
index a1b756c..a99d003 100644 (file)
@@ -1773,10 +1773,16 @@ void syscall_init(void)
        wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
 #endif
 
-       /* Flags to clear on syscall */
+       /*
+        * Flags to clear on syscall; clear as much as possible
+        * to minimize user space-kernel interference.
+        */
        wrmsrl(MSR_SYSCALL_MASK,
-              X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|
-              X86_EFLAGS_IOPL|X86_EFLAGS_AC|X86_EFLAGS_NT);
+              X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
+              X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_TF|
+              X86_EFLAGS_IF|X86_EFLAGS_DF|X86_EFLAGS_OF|
+              X86_EFLAGS_IOPL|X86_EFLAGS_NT|X86_EFLAGS_RF|
+              X86_EFLAGS_AC|X86_EFLAGS_ID);
 }
 
 #else  /* CONFIG_X86_64 */
@@ -1938,13 +1944,12 @@ void cpu_init_exception_handling(void)
 
 /*
  * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
+ * initialized (naturally) in the bootstrap process, such as the GDT.  We
+ * reload it nevertheless, this function acts as a 'CPU state barrier',
+ * nothing should get across.
  */
 void cpu_init(void)
 {
-       struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
        struct task_struct *cur = current;
        int cpu = raw_smp_processor_id();
 
@@ -1957,8 +1962,6 @@ void cpu_init(void)
            early_cpu_to_node(cpu) != NUMA_NO_NODE)
                set_numa_node(early_cpu_to_node(cpu));
 #endif
-       setup_getcpu(cpu);
-
        pr_debug("Initializing CPU#%d\n", cpu);
 
        if (IS_ENABLED(CONFIG_X86_64) || cpu_feature_enabled(X86_FEATURE_VME) ||
@@ -1970,7 +1973,6 @@ void cpu_init(void)
         * and set up the GDT descriptor:
         */
        switch_to_new_gdt(cpu);
-       load_current_idt();
 
        if (IS_ENABLED(CONFIG_X86_64)) {
                loadsegment(fs, 0);
@@ -1990,12 +1992,6 @@ void cpu_init(void)
        initialize_tlbstate_and_flush();
        enter_lazy_tlb(&init_mm, cur);
 
-       /* Initialize the TSS. */
-       tss_setup_ist(tss);
-       tss_setup_io_bitmap(tss);
-       set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
-
-       load_TR_desc();
        /*
         * sp0 points to the entry trampoline stack regardless of what task
         * is running.
@@ -2017,6 +2013,18 @@ void cpu_init(void)
        load_fixmap_gdt(cpu);
 }
 
+#ifdef CONFIG_SMP
+void cpu_init_secondary(void)
+{
+       /*
+        * Relies on the BP having set-up the IDT tables, which are loaded
+        * on this CPU in cpu_init_exception_handling().
+        */
+       cpu_init_exception_handling();
+       cpu_init();
+}
+#endif
+
 /*
  * The microcode loader calls this upon late microcode load to recheck features,
  * only when microcode has been updated. Caller holds microcode_mutex and CPU
index 6794412..9552130 100644 (file)
@@ -48,6 +48,7 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[],
 enum tsx_ctrl_states {
        TSX_CTRL_ENABLE,
        TSX_CTRL_DISABLE,
+       TSX_CTRL_RTM_ALWAYS_ABORT,
        TSX_CTRL_NOT_SUPPORTED,
 };
 
@@ -56,6 +57,7 @@ extern __ro_after_init enum tsx_ctrl_states tsx_ctrl_state;
 extern void __init tsx_init(void);
 extern void tsx_enable(void);
 extern void tsx_disable(void);
+extern void tsx_clear_cpuid(void);
 #else
 static inline void tsx_init(void) { }
 #endif /* CONFIG_CPU_SUP_INTEL */
index 0bd6c74..6d50136 100644 (file)
@@ -260,6 +260,10 @@ static void early_init_hygon(struct cpuinfo_x86 *c)
        if (c->x86_power & BIT(12))
                set_cpu_cap(c, X86_FEATURE_ACC_POWER);
 
+       /* Bit 14 indicates the Runtime Average Power Limit interface. */
+       if (c->x86_power & BIT(14))
+               set_cpu_cap(c, X86_FEATURE_RAPL);
+
 #ifdef CONFIG_X86_64
        set_cpu_cap(c, X86_FEATURE_SYSCALL32);
 #endif
index 8adffc1..8321c43 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/thread_info.h>
 #include <linux/init.h>
 #include <linux/uaccess.h>
+#include <linux/delay.h>
 
 #include <asm/cpufeature.h>
 #include <asm/msr.h>
@@ -41,6 +42,7 @@ enum split_lock_detect_state {
        sld_off = 0,
        sld_warn,
        sld_fatal,
+       sld_ratelimit,
 };
 
 /*
@@ -717,8 +719,10 @@ static void init_intel(struct cpuinfo_x86 *c)
 
        if (tsx_ctrl_state == TSX_CTRL_ENABLE)
                tsx_enable();
-       if (tsx_ctrl_state == TSX_CTRL_DISABLE)
+       else if (tsx_ctrl_state == TSX_CTRL_DISABLE)
                tsx_disable();
+       else if (tsx_ctrl_state == TSX_CTRL_RTM_ALWAYS_ABORT)
+               tsx_clear_cpuid();
 
        split_lock_init();
        bus_lock_init();
@@ -997,13 +1001,30 @@ static const struct {
        { "off",        sld_off   },
        { "warn",       sld_warn  },
        { "fatal",      sld_fatal },
+       { "ratelimit:", sld_ratelimit },
 };
 
+static struct ratelimit_state bld_ratelimit;
+
 static inline bool match_option(const char *arg, int arglen, const char *opt)
 {
-       int len = strlen(opt);
+       int len = strlen(opt), ratelimit;
+
+       if (strncmp(arg, opt, len))
+               return false;
+
+       /*
+        * Min ratelimit is 1 bus lock/sec.
+        * Max ratelimit is 1000 bus locks/sec.
+        */
+       if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 &&
+           ratelimit > 0 && ratelimit <= 1000) {
+               ratelimit_state_init(&bld_ratelimit, HZ, ratelimit);
+               ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE);
+               return true;
+       }
 
-       return len == arglen && !strncmp(arg, opt, len);
+       return len == arglen;
 }
 
 static bool split_lock_verify_msr(bool on)
@@ -1082,6 +1103,15 @@ static void sld_update_msr(bool on)
 
 static void split_lock_init(void)
 {
+       /*
+        * #DB for bus lock handles ratelimit and #AC for split lock is
+        * disabled.
+        */
+       if (sld_state == sld_ratelimit) {
+               split_lock_verify_msr(false);
+               return;
+       }
+
        if (cpu_model_supports_sld)
                split_lock_verify_msr(sld_state != sld_off);
 }
@@ -1154,6 +1184,12 @@ void handle_bus_lock(struct pt_regs *regs)
        switch (sld_state) {
        case sld_off:
                break;
+       case sld_ratelimit:
+               /* Enforce no more than bld_ratelimit bus locks/sec. */
+               while (!__ratelimit(&bld_ratelimit))
+                       msleep(20);
+               /* Warn on the bus lock. */
+               fallthrough;
        case sld_warn:
                pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n",
                                    current->comm, current->pid, regs->ip);
@@ -1259,6 +1295,10 @@ static void sld_state_show(void)
                                " from non-WB" : "");
                }
                break;
+       case sld_ratelimit:
+               if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
+                       pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst);
+               break;
        }
 }
 
index e486f96..08831ac 100644 (file)
@@ -77,27 +77,29 @@ struct smca_bank_name {
 };
 
 static struct smca_bank_name smca_names[] = {
-       [SMCA_LS]       = { "load_store",       "Load Store Unit" },
-       [SMCA_LS_V2]    = { "load_store",       "Load Store Unit" },
-       [SMCA_IF]       = { "insn_fetch",       "Instruction Fetch Unit" },
-       [SMCA_L2_CACHE] = { "l2_cache",         "L2 Cache" },
-       [SMCA_DE]       = { "decode_unit",      "Decode Unit" },
-       [SMCA_RESERVED] = { "reserved",         "Reserved" },
-       [SMCA_EX]       = { "execution_unit",   "Execution Unit" },
-       [SMCA_FP]       = { "floating_point",   "Floating Point Unit" },
-       [SMCA_L3_CACHE] = { "l3_cache",         "L3 Cache" },
-       [SMCA_CS]       = { "coherent_slave",   "Coherent Slave" },
-       [SMCA_CS_V2]    = { "coherent_slave",   "Coherent Slave" },
-       [SMCA_PIE]      = { "pie",              "Power, Interrupts, etc." },
-       [SMCA_UMC]      = { "umc",              "Unified Memory Controller" },
-       [SMCA_PB]       = { "param_block",      "Parameter Block" },
-       [SMCA_PSP]      = { "psp",              "Platform Security Processor" },
-       [SMCA_PSP_V2]   = { "psp",              "Platform Security Processor" },
-       [SMCA_SMU]      = { "smu",              "System Management Unit" },
-       [SMCA_SMU_V2]   = { "smu",              "System Management Unit" },
-       [SMCA_MP5]      = { "mp5",              "Microprocessor 5 Unit" },
-       [SMCA_NBIO]     = { "nbio",             "Northbridge IO Unit" },
-       [SMCA_PCIE]     = { "pcie",             "PCI Express Unit" },
+       [SMCA_LS ... SMCA_LS_V2]        = { "load_store",       "Load Store Unit" },
+       [SMCA_IF]                       = { "insn_fetch",       "Instruction Fetch Unit" },
+       [SMCA_L2_CACHE]                 = { "l2_cache",         "L2 Cache" },
+       [SMCA_DE]                       = { "decode_unit",      "Decode Unit" },
+       [SMCA_RESERVED]                 = { "reserved",         "Reserved" },
+       [SMCA_EX]                       = { "execution_unit",   "Execution Unit" },
+       [SMCA_FP]                       = { "floating_point",   "Floating Point Unit" },
+       [SMCA_L3_CACHE]                 = { "l3_cache",         "L3 Cache" },
+       [SMCA_CS ... SMCA_CS_V2]        = { "coherent_slave",   "Coherent Slave" },
+       [SMCA_PIE]                      = { "pie",              "Power, Interrupts, etc." },
+
+       /* UMC v2 is separate because both of them can exist in a single system. */
+       [SMCA_UMC]                      = { "umc",              "Unified Memory Controller" },
+       [SMCA_UMC_V2]                   = { "umc_v2",           "Unified Memory Controller v2" },
+       [SMCA_PB]                       = { "param_block",      "Parameter Block" },
+       [SMCA_PSP ... SMCA_PSP_V2]      = { "psp",              "Platform Security Processor" },
+       [SMCA_SMU ... SMCA_SMU_V2]      = { "smu",              "System Management Unit" },
+       [SMCA_MP5]                      = { "mp5",              "Microprocessor 5 Unit" },
+       [SMCA_NBIO]                     = { "nbio",             "Northbridge IO Unit" },
+       [SMCA_PCIE ... SMCA_PCIE_V2]    = { "pcie",             "PCI Express Unit" },
+       [SMCA_XGMI_PCS]                 = { "xgmi_pcs",         "Ext Global Memory Interconnect PCS Unit" },
+       [SMCA_XGMI_PHY]                 = { "xgmi_phy",         "Ext Global Memory Interconnect PHY Unit" },
+       [SMCA_WAFL_PHY]                 = { "wafl_phy",         "WAFL PHY Unit" },
 };
 
 static const char *smca_get_name(enum smca_bank_types t)
@@ -155,6 +157,7 @@ static struct smca_hwid smca_hwid_mcatypes[] = {
 
        /* Unified Memory Controller MCA type */
        { SMCA_UMC,      HWID_MCATYPE(0x96, 0x0)        },
+       { SMCA_UMC_V2,   HWID_MCATYPE(0x96, 0x1)        },
 
        /* Parameter Block MCA type */
        { SMCA_PB,       HWID_MCATYPE(0x05, 0x0)        },
@@ -175,6 +178,16 @@ static struct smca_hwid smca_hwid_mcatypes[] = {
 
        /* PCI Express Unit MCA type */
        { SMCA_PCIE,     HWID_MCATYPE(0x46, 0x0)        },
+       { SMCA_PCIE_V2,  HWID_MCATYPE(0x46, 0x1)        },
+
+       /* xGMI PCS MCA type */
+       { SMCA_XGMI_PCS, HWID_MCATYPE(0x50, 0x0)        },
+
+       /* xGMI PHY MCA type */
+       { SMCA_XGMI_PHY, HWID_MCATYPE(0x259, 0x0)       },
+
+       /* WAFL PHY MCA type */
+       { SMCA_WAFL_PHY, HWID_MCATYPE(0x267, 0x0)       },
 };
 
 struct smca_bank smca_banks[MAX_NR_BANKS];
index b58b853..0e3ae64 100644 (file)
@@ -36,7 +36,8 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err)
        mce_setup(&m);
        m.bank = -1;
        /* Fake a memory read error with unknown channel */
-       m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f;
+       m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f;
+       m.misc = (MCI_MISC_ADDR_PHYS << 6) | PAGE_SHIFT;
 
        if (severity >= GHES_SEV_RECOVERABLE)
                m.status |= MCI_STATUS_UC;
index 22f1334..01ca94f 100644 (file)
@@ -236,7 +236,7 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
        for_each_present_cpu(i) {
                if (i == 0)
                        continue;
-               ret = hv_call_add_logical_proc(numa_cpu_node(i), i, cpu_physical_id(i));
+               ret = hv_call_add_logical_proc(numa_cpu_node(i), i, i);
                BUG_ON(ret);
        }
 
@@ -252,6 +252,7 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
 
 static void __init ms_hyperv_init_platform(void)
 {
+       int hv_max_functions_eax;
        int hv_host_info_eax;
        int hv_host_info_ebx;
        int hv_host_info_ecx;
@@ -269,6 +270,8 @@ static void __init ms_hyperv_init_platform(void)
        ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
        ms_hyperv.hints    = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
 
+       hv_max_functions_eax = cpuid_eax(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS);
+
        pr_info("Hyper-V: privilege flags low 0x%x, high 0x%x, hints 0x%x, misc 0x%x\n",
                ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints,
                ms_hyperv.misc_features);
@@ -298,8 +301,7 @@ static void __init ms_hyperv_init_platform(void)
        /*
         * Extract host information.
         */
-       if (cpuid_eax(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS) >=
-           HYPERV_CPUID_VERSION) {
+       if (hv_max_functions_eax >= HYPERV_CPUID_VERSION) {
                hv_host_info_eax = cpuid_eax(HYPERV_CPUID_VERSION);
                hv_host_info_ebx = cpuid_ebx(HYPERV_CPUID_VERSION);
                hv_host_info_ecx = cpuid_ecx(HYPERV_CPUID_VERSION);
@@ -325,9 +327,11 @@ static void __init ms_hyperv_init_platform(void)
                        ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b);
        }
 
-       if (ms_hyperv.hints & HV_X64_ENLIGHTENED_VMCS_RECOMMENDED) {
+       if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) {
                ms_hyperv.nested_features =
                        cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
+               pr_info("Hyper-V: Nested features: 0x%x\n",
+                       ms_hyperv.nested_features);
        }
 
        /*
index c4d320d..6a5f60a 100644 (file)
@@ -70,6 +70,7 @@ DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
  * struct mon_evt - Entry in the event list of a resource
  * @evtid:             event id
  * @name:              name of the event
+ * @list:              entry in &rdt_resource->evt_list
  */
 struct mon_evt {
        u32                     evtid;
@@ -78,10 +79,13 @@ struct mon_evt {
 };
 
 /**
- * struct mon_data_bits - Monitoring details for each event file
- * @rid:               Resource id associated with the event file.
+ * union mon_data_bits - Monitoring details for each event file
+ * @priv:              Used to store monitoring event data in @u
+ *                     as kernfs private data
+ * @rid:               Resource id associated with the event file
  * @evtid:             Event id associated with the event file
  * @domid:             The domain to which the event file belongs
+ * @u:                 Name of the bit fields struct
  */
 union mon_data_bits {
        void *priv;
@@ -119,6 +123,7 @@ enum rdt_group_type {
  * @RDT_MODE_PSEUDO_LOCKSETUP: Resource group will be used for Pseudo-Locking
  * @RDT_MODE_PSEUDO_LOCKED: No sharing of this resource group's allocations
  *                          allowed AND the allocations are Cache Pseudo-Locked
+ * @RDT_NUM_MODES: Total number of modes
  *
  * The mode of a resource group enables control over the allowed overlap
  * between allocations associated with different resource groups (classes
@@ -142,7 +147,7 @@ enum rdtgrp_mode {
 
 /**
  * struct mongroup - store mon group's data in resctrl fs.
- * @mon_data_kn                kernlfs node for the mon_data directory
+ * @mon_data_kn:               kernfs node for the mon_data directory
  * @parent:                    parent rdtgrp
  * @crdtgrp_list:              child rdtgroup node list
  * @rmid:                      rmid for this rdtgroup
@@ -282,11 +287,11 @@ struct rftype {
 /**
  * struct mbm_state - status for each MBM counter in each domain
  * @chunks:    Total data moved (multiply by rdt_group.mon_scale to get bytes)
- * @prev_msr   Value of IA32_QM_CTR for this RMID last time we read it
+ * @prev_msr:  Value of IA32_QM_CTR for this RMID last time we read it
  * @prev_bw_msr:Value of previous IA32_QM_CTR for bandwidth counting
- * @prev_bw    The most recent bandwidth in MBps
- * @delta_bw   Difference between the current and previous bandwidth
- * @delta_comp Indicates whether to compute the delta_bw
+ * @prev_bw:   The most recent bandwidth in MBps
+ * @delta_bw:  Difference between the current and previous bandwidth
+ * @delta_comp:        Indicates whether to compute the delta_bw
  */
 struct mbm_state {
        u64     chunks;
@@ -456,11 +461,13 @@ struct rdt_parse_data {
  * @data_width:                Character width of data when displaying
  * @domains:           All domains for this resource
  * @cache:             Cache allocation related data
+ * @membw:             If the component has bandwidth controls, their properties.
  * @format_str:                Per resource format string to show domain value
  * @parse_ctrlval:     Per resource function pointer to parse control values
  * @evt_list:          List of monitoring events
  * @num_rmid:          Number of RMIDs available
  * @mon_scale:         cqm counter * mon_scale = occupancy in bytes
+ * @mbm_width:         Monitor width, to detect and correct for overflow.
  * @fflags:            flags to choose base and info files
  */
 struct rdt_resource {
index 05a89e3..2207916 100644 (file)
@@ -49,6 +49,7 @@ static struct class *pseudo_lock_class;
 
 /**
  * get_prefetch_disable_bits - prefetch disable bits of supported platforms
+ * @void: It takes no parameters.
  *
  * Capture the list of platforms that have been validated to support
  * pseudo-locking. This includes testing to ensure pseudo-locked regions
@@ -162,7 +163,7 @@ static struct rdtgroup *region_find_by_minor(unsigned int minor)
 }
 
 /**
- * pseudo_lock_pm_req - A power management QoS request list entry
+ * struct pseudo_lock_pm_req - A power management QoS request list entry
  * @list:      Entry within the @pm_reqs list for a pseudo-locked region
  * @req:       PM QoS request
  */
@@ -184,6 +185,7 @@ static void pseudo_lock_cstates_relax(struct pseudo_lock_region *plr)
 
 /**
  * pseudo_lock_cstates_constrain - Restrict cores from entering C6
+ * @plr: Pseudo-locked region
  *
  * To prevent the cache from being affected by power management entering
  * C6 has to be avoided. This is accomplished by requesting a latency
@@ -196,6 +198,8 @@ static void pseudo_lock_cstates_relax(struct pseudo_lock_region *plr)
  * the ACPI latencies need to be considered while keeping in mind that C2
  * may be set to map to deeper sleep states. In this case the latency
  * requirement needs to prevent entering C2 also.
+ *
+ * Return: 0 on success, <0 on failure
  */
 static int pseudo_lock_cstates_constrain(struct pseudo_lock_region *plr)
 {
@@ -520,7 +524,7 @@ static int pseudo_lock_fn(void *_rdtgrp)
 
 /**
  * rdtgroup_monitor_in_progress - Test if monitoring in progress
- * @r: resource group being queried
+ * @rdtgrp: resource group being queried
  *
  * Return: 1 if monitor groups have been created for this resource
  * group, 0 otherwise.
@@ -1140,6 +1144,8 @@ out:
 
 /**
  * pseudo_lock_measure_cycles - Trigger latency measure to pseudo-locked region
+ * @rdtgrp: Resource group to which the pseudo-locked region belongs.
+ * @sel: Selector of which measurement to perform on a pseudo-locked region.
  *
  * The measurement of latency to access a pseudo-locked region should be
  * done from a cpu that is associated with that pseudo-locked region.
index 3be2032..001808e 100644 (file)
@@ -383,7 +383,7 @@ const struct vm_operations_struct sgx_vm_ops = {
 
 /**
  * sgx_encl_release - Destroy an enclave instance
- * @kref:      address of a kref inside &sgx_encl
+ * @ref:       address of a kref inside &sgx_encl
  *
  * Used together with kref_put(). Frees all the resources associated with the
  * enclave and the instance itself.
index 6ad165a..64511c4 100644 (file)
@@ -212,6 +212,7 @@ static int sgx_vepc_release(struct inode *inode, struct file *file)
                list_splice_tail(&secs_pages, &zombie_secs_pages);
        mutex_unlock(&zombie_secs_pages_lock);
 
+       xa_destroy(&vepc->page_array);
        kfree(vepc);
 
        return 0;
index e2ad30e..9c7a5f0 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Intel Transactional Synchronization Extensions (TSX) control.
  *
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019-2021 Intel Corporation
  *
  * Author:
  *     Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
@@ -84,13 +84,46 @@ static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
        return TSX_CTRL_ENABLE;
 }
 
+void tsx_clear_cpuid(void)
+{
+       u64 msr;
+
+       /*
+        * MSR_TFA_TSX_CPUID_CLEAR bit is only present when both CPUID
+        * bits RTM_ALWAYS_ABORT and TSX_FORCE_ABORT are present.
+        */
+       if (boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) &&
+           boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
+               rdmsrl(MSR_TSX_FORCE_ABORT, msr);
+               msr |= MSR_TFA_TSX_CPUID_CLEAR;
+               wrmsrl(MSR_TSX_FORCE_ABORT, msr);
+       }
+}
+
 void __init tsx_init(void)
 {
        char arg[5] = {};
        int ret;
 
-       if (!tsx_ctrl_is_supported())
+       /*
+        * Hardware will always abort a TSX transaction if both CPUID bits
+        * RTM_ALWAYS_ABORT and TSX_FORCE_ABORT are set. In this case, it is
+        * better not to enumerate CPUID.RTM and CPUID.HLE bits. Clear them
+        * here.
+        */
+       if (boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) &&
+           boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
+               tsx_ctrl_state = TSX_CTRL_RTM_ALWAYS_ABORT;
+               tsx_clear_cpuid();
+               setup_clear_cpu_cap(X86_FEATURE_RTM);
+               setup_clear_cpu_cap(X86_FEATURE_HLE);
                return;
+       }
+
+       if (!tsx_ctrl_is_supported()) {
+               tsx_ctrl_state = TSX_CTRL_NOT_SUPPORTED;
+               return;
+       }
 
        ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
        if (ret >= 0) {
index 54ce999..e8326a8 100644 (file)
@@ -70,19 +70,6 @@ static inline void cpu_crash_vmclear_loaded_vmcss(void)
        rcu_read_unlock();
 }
 
-/*
- * When the crashkernel option is specified, only use the low
- * 1M for the real mode trampoline.
- */
-void __init crash_reserve_low_1M(void)
-{
-       if (cmdline_find_option(boot_command_line, "crashkernel", NULL, 0) < 0)
-               return;
-
-       memblock_reserve(0, 1<<20);
-       pr_info("Reserving the low 1M of memory for crashkernel\n");
-}
-
 #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
 
 static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
index a4ec653..b7b92cd 100644 (file)
@@ -221,28 +221,18 @@ sanitize_restored_user_xstate(union fpregs_state *state,
 
        if (use_xsave()) {
                /*
-                * Note: we don't need to zero the reserved bits in the
-                * xstate_header here because we either didn't copy them at all,
-                * or we checked earlier that they aren't set.
+                * Clear all feature bits which are not set in
+                * user_xfeatures and clear all extended features
+                * for fx_only mode.
                 */
+               u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures;
 
                /*
-                * 'user_xfeatures' might have bits clear which are
-                * set in header->xfeatures. This represents features that
-                * were in init state prior to a signal delivery, and need
-                * to be reset back to the init state.  Clear any user
-                * feature bits which are set in the kernel buffer to get
-                * them back to the init state.
-                *
-                * Supervisor state is unchanged by input from userspace.
-                * Ensure supervisor state bits stay set and supervisor
-                * state is not modified.
+                * Supervisor state has to be preserved. The sigframe
+                * restore can only modify user features, i.e. @mask
+                * cannot contain them.
                 */
-               if (fx_only)
-                       header->xfeatures = XFEATURE_MASK_FPSSE;
-               else
-                       header->xfeatures &= user_xfeatures |
-                                            xfeatures_mask_supervisor();
+               header->xfeatures &= mask | xfeatures_mask_supervisor();
        }
 
        if (use_fxsr()) {
@@ -307,13 +297,17 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                return 0;
        }
 
-       if (!access_ok(buf, size))
-               return -EACCES;
+       if (!access_ok(buf, size)) {
+               ret = -EACCES;
+               goto out;
+       }
 
-       if (!static_cpu_has(X86_FEATURE_FPU))
-               return fpregs_soft_set(current, NULL,
-                                      0, sizeof(struct user_i387_ia32_struct),
-                                      NULL, buf) != 0;
+       if (!static_cpu_has(X86_FEATURE_FPU)) {
+               ret = fpregs_soft_set(current, NULL, 0,
+                                     sizeof(struct user_i387_ia32_struct),
+                                     NULL, buf);
+               goto out;
+       }
 
        if (use_xsave()) {
                struct _fpx_sw_bytes fx_sw_user;
@@ -369,6 +363,25 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                        fpregs_unlock();
                        return 0;
                }
+
+               /*
+                * The above did an FPU restore operation, restricted to
+                * the user portion of the registers, and failed, but the
+                * microcode might have modified the FPU registers
+                * nevertheless.
+                *
+                * If the FPU registers do not belong to current, then
+                * invalidate the FPU register state otherwise the task might
+                * preempt current and return to user space with corrupted
+                * FPU registers.
+                *
+                * In case current owns the FPU registers then no further
+                * action is required. The fixup below will handle it
+                * correctly.
+                */
+               if (test_thread_flag(TIF_NEED_FPU_LOAD))
+                       __cpu_invalidate_fpregs_state();
+
                fpregs_unlock();
        } else {
                /*
@@ -377,7 +390,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                 */
                ret = __copy_from_user(&env, buf, sizeof(env));
                if (ret)
-                       goto err_out;
+                       goto out;
                envp = &env;
        }
 
@@ -405,16 +418,9 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
        if (use_xsave() && !fx_only) {
                u64 init_bv = xfeatures_mask_user() & ~user_xfeatures;
 
-               if (using_compacted_format()) {
-                       ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
-               } else {
-                       ret = __copy_from_user(&fpu->state.xsave, buf_fx, state_size);
-
-                       if (!ret && state_size > offsetof(struct xregs_state, header))
-                               ret = validate_user_xstate_header(&fpu->state.xsave.header);
-               }
+               ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
                if (ret)
-                       goto err_out;
+                       goto out;
 
                sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
                                              fx_only);
@@ -434,7 +440,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size);
                if (ret) {
                        ret = -EFAULT;
-                       goto err_out;
+                       goto out;
                }
 
                sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
@@ -452,7 +458,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
        } else {
                ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size);
                if (ret)
-                       goto err_out;
+                       goto out;
 
                fpregs_lock();
                ret = copy_kernel_to_fregs_err(&fpu->state.fsave);
@@ -463,7 +469,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
                fpregs_deactivate(fpu);
        fpregs_unlock();
 
-err_out:
+out:
        if (ret)
                fpu__clear_user_states(fpu);
        return ret;
index d0eef96..1cadb2f 100644 (file)
@@ -441,12 +441,35 @@ static void __init print_xstate_offset_size(void)
 }
 
 /*
+ * All supported features have either init state all zeros or are
+ * handled in setup_init_fpu() individually. This is an explicit
+ * feature list and does not use XFEATURE_MASK*SUPPORTED to catch
+ * newly added supported features at build time and make people
+ * actually look at the init state for the new feature.
+ */
+#define XFEATURES_INIT_FPSTATE_HANDLED         \
+       (XFEATURE_MASK_FP |                     \
+        XFEATURE_MASK_SSE |                    \
+        XFEATURE_MASK_YMM |                    \
+        XFEATURE_MASK_OPMASK |                 \
+        XFEATURE_MASK_ZMM_Hi256 |              \
+        XFEATURE_MASK_Hi16_ZMM  |              \
+        XFEATURE_MASK_PKRU |                   \
+        XFEATURE_MASK_BNDREGS |                \
+        XFEATURE_MASK_BNDCSR |                 \
+        XFEATURE_MASK_PASID)
+
+/*
  * setup the xstate image representing the init state
  */
 static void __init setup_init_fpu_buf(void)
 {
        static int on_boot_cpu __initdata = 1;
 
+       BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
+                     XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
+                    XFEATURES_INIT_FPSTATE_HANDLED);
+
        WARN_ON_FPU(!on_boot_cpu);
        on_boot_cpu = 0;
 
@@ -466,10 +489,22 @@ static void __init setup_init_fpu_buf(void)
        copy_kernel_to_xregs_booting(&init_fpstate.xsave);
 
        /*
-        * Dump the init state again. This is to identify the init state
-        * of any feature which is not represented by all zero's.
+        * All components are now in init state. Read the state back so
+        * that init_fpstate contains all non-zero init state. This only
+        * works with XSAVE, but not with XSAVEOPT and XSAVES because
+        * those use the init optimization which skips writing data for
+        * components in init state.
+        *
+        * XSAVE could be used, but that would require to reshuffle the
+        * data when XSAVES is available because XSAVES uses xstate
+        * compaction. But doing so is a pointless exercise because most
+        * components have an all zeros init state except for the legacy
+        * ones (FP and SSE). Those can be saved with FXSAVE into the
+        * legacy area. Adding new features requires to ensure that init
+        * state is all zeroes or if not to add the necessary handling
+        * here.
         */
-       copy_xregs_to_kernel_booting(&init_fpstate.xsave);
+       fxsave(&init_fpstate.fxsave);
 }
 
 static int xfeature_uncompacted_offset(int xfeature_nr)
index 04bddaa..d8b3ebd 100644 (file)
@@ -62,7 +62,7 @@ SYM_CODE_START_NOALIGN(startup_64)
         */
 
        /* Set up the stack for verify_cpu(), similar to initial_stack below */
-       leaq    (__end_init_task - SIZEOF_PTREGS)(%rip), %rsp
+       leaq    (__end_init_task - FRAME_SIZE)(%rip), %rsp
 
        leaq    _text(%rip), %rdi
        pushq   %rsi
@@ -343,10 +343,10 @@ SYM_DATA(initial_vc_handler,      .quad handle_vc_boot_ghcb)
 #endif
 
 /*
- * The SIZEOF_PTREGS gap is a convention which helps the in-kernel unwinder
+ * The FRAME_SIZE gap is a convention which helps the in-kernel unwinder
  * reliably detect the end of the stack.
  */
-SYM_DATA(initial_stack, .quad init_thread_union + THREAD_SIZE - SIZEOF_PTREGS)
+SYM_DATA(initial_stack, .quad init_thread_union + THREAD_SIZE - FRAME_SIZE)
        __FINITDATA
 
        __INIT
index d552f17..df0fa69 100644 (file)
 #define SYSG(_vector, _addr)                           \
        G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL3, __KERNEL_CS)
 
+#ifdef CONFIG_X86_64
 /*
  * Interrupt gate with interrupt stack. The _ist index is the index in
  * the tss.ist[] array, but for the descriptor it needs to start at 1.
  */
 #define ISTG(_vector, _addr, _ist)                     \
        G(_vector, _addr, _ist + 1, GATE_INTERRUPT, DPL0, __KERNEL_CS)
+#else
+#define ISTG(_vector, _addr, _ist)     INTG(_vector, _addr)
+#endif
 
 /* Task gate */
 #define TSKG(_vector, _gdt)                            \
@@ -74,7 +78,7 @@ static const __initconst struct idt_data early_idts[] = {
  */
 static const __initconst struct idt_data def_idts[] = {
        INTG(X86_TRAP_DE,               asm_exc_divide_error),
-       INTG(X86_TRAP_NMI,              asm_exc_nmi),
+       ISTG(X86_TRAP_NMI,              asm_exc_nmi, IST_INDEX_NMI),
        INTG(X86_TRAP_BR,               asm_exc_bounds),
        INTG(X86_TRAP_UD,               asm_exc_invalid_op),
        INTG(X86_TRAP_NM,               asm_exc_device_not_available),
@@ -91,12 +95,16 @@ static const __initconst struct idt_data def_idts[] = {
 #ifdef CONFIG_X86_32
        TSKG(X86_TRAP_DF,               GDT_ENTRY_DOUBLEFAULT_TSS),
 #else
-       INTG(X86_TRAP_DF,               asm_exc_double_fault),
+       ISTG(X86_TRAP_DF,               asm_exc_double_fault, IST_INDEX_DF),
 #endif
-       INTG(X86_TRAP_DB,               asm_exc_debug),
+       ISTG(X86_TRAP_DB,               asm_exc_debug, IST_INDEX_DB),
 
 #ifdef CONFIG_X86_MCE
-       INTG(X86_TRAP_MC,               asm_exc_machine_check),
+       ISTG(X86_TRAP_MC,               asm_exc_machine_check, IST_INDEX_MCE),
+#endif
+
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+       ISTG(X86_TRAP_VC,               asm_exc_vmm_communication, IST_INDEX_VC),
 #endif
 
        SYSG(X86_TRAP_OF,               asm_exc_overflow),
@@ -221,22 +229,6 @@ static const __initconst struct idt_data early_pf_idts[] = {
        INTG(X86_TRAP_PF,               asm_exc_page_fault),
 };
 
-/*
- * The exceptions which use Interrupt stacks. They are setup after
- * cpu_init() when the TSS has been initialized.
- */
-static const __initconst struct idt_data ist_idts[] = {
-       ISTG(X86_TRAP_DB,       asm_exc_debug,                  IST_INDEX_DB),
-       ISTG(X86_TRAP_NMI,      asm_exc_nmi,                    IST_INDEX_NMI),
-       ISTG(X86_TRAP_DF,       asm_exc_double_fault,           IST_INDEX_DF),
-#ifdef CONFIG_X86_MCE
-       ISTG(X86_TRAP_MC,       asm_exc_machine_check,          IST_INDEX_MCE),
-#endif
-#ifdef CONFIG_AMD_MEM_ENCRYPT
-       ISTG(X86_TRAP_VC,       asm_exc_vmm_communication,      IST_INDEX_VC),
-#endif
-};
-
 /**
  * idt_setup_early_pf - Initialize the idt table with early pagefault handler
  *
@@ -254,14 +246,6 @@ void __init idt_setup_early_pf(void)
        idt_setup_from_table(idt_table, early_pf_idts,
                             ARRAY_SIZE(early_pf_idts), true);
 }
-
-/**
- * idt_setup_ist_traps - Initialize the idt table with traps using IST
- */
-void __init idt_setup_ist_traps(void)
-{
-       idt_setup_from_table(idt_table, ist_idts, ARRAY_SIZE(ist_idts), true);
-}
 #endif
 
 static void __init idt_map_in_cea(void)
@@ -331,11 +315,10 @@ void __init idt_setup_early_handler(void)
 
 /**
  * idt_invalidate - Invalidate interrupt descriptor table
- * @addr:      The virtual address of the 'invalid' IDT
  */
-void idt_invalidate(void *addr)
+void idt_invalidate(void)
 {
-       struct desc_ptr idt = { .address = (unsigned long) addr, .size = 0 };
+       static const struct desc_ptr idt = { .address = 0, .size = 0 };
 
        load_idt(&idt);
 }
index 6a2eb62..674906f 100644 (file)
 #include <asm/kprobes.h>
 #include <asm/alternative.h>
 #include <asm/text-patching.h>
+#include <asm/insn.h>
 
-static void bug_at(const void *ip, int line)
+int arch_jump_entry_size(struct jump_entry *entry)
 {
-       /*
-        * The location is not an op that we were expecting.
-        * Something went wrong. Crash the box, as something could be
-        * corrupting the kernel.
-        */
-       pr_crit("jump_label: Fatal kernel bug, unexpected op at %pS [%p] (%5ph) %d\n", ip, ip, ip, line);
-       BUG();
+       struct insn insn = {};
+
+       insn_decode_kernel(&insn, (void *)jump_entry_code(entry));
+       BUG_ON(insn.length != 2 && insn.length != 5);
+
+       return insn.length;
 }
 
-static const void *
-__jump_label_set_jump_code(struct jump_entry *entry, enum jump_label_type type)
+struct jump_label_patch {
+       const void *code;
+       int size;
+};
+
+static struct jump_label_patch
+__jump_label_patch(struct jump_entry *entry, enum jump_label_type type)
 {
-       const void *expect, *code;
+       const void *expect, *code, *nop;
        const void *addr, *dest;
-       int line;
+       int size;
 
        addr = (void *)jump_entry_code(entry);
        dest = (void *)jump_entry_target(entry);
 
-       code = text_gen_insn(JMP32_INSN_OPCODE, addr, dest);
+       size = arch_jump_entry_size(entry);
+       switch (size) {
+       case JMP8_INSN_SIZE:
+               code = text_gen_insn(JMP8_INSN_OPCODE, addr, dest);
+               nop = x86_nops[size];
+               break;
 
-       if (type == JUMP_LABEL_JMP) {
-               expect = x86_nops[5]; line = __LINE__;
-       } else {
-               expect = code; line = __LINE__;
+       case JMP32_INSN_SIZE:
+               code = text_gen_insn(JMP32_INSN_OPCODE, addr, dest);
+               nop = x86_nops[size];
+               break;
+
+       default: BUG();
        }
 
-       if (memcmp(addr, expect, JUMP_LABEL_NOP_SIZE))
-               bug_at(addr, line);
+       if (type == JUMP_LABEL_JMP)
+               expect = nop;
+       else
+               expect = code;
+
+       if (memcmp(addr, expect, size)) {
+               /*
+                * The location is not an op that we were expecting.
+                * Something went wrong. Crash the box, as something could be
+                * corrupting the kernel.
+                */
+               pr_crit("jump_label: Fatal kernel bug, unexpected op at %pS [%p] (%5ph != %5ph)) size:%d type:%d\n",
+                               addr, addr, addr, expect, size, type);
+               BUG();
+       }
 
        if (type == JUMP_LABEL_NOP)
-               code = x86_nops[5];
+               code = nop;
 
-       return code;
+       return (struct jump_label_patch){.code = code, .size = size};
 }
 
 static inline void __jump_label_transform(struct jump_entry *entry,
                                          enum jump_label_type type,
                                          int init)
 {
-       const void *opcode = __jump_label_set_jump_code(entry, type);
+       const struct jump_label_patch jlp = __jump_label_patch(entry, type);
 
        /*
         * As long as only a single processor is running and the code is still
@@ -72,12 +97,11 @@ static inline void __jump_label_transform(struct jump_entry *entry,
         * always nop being the 'currently valid' instruction
         */
        if (init || system_state == SYSTEM_BOOTING) {
-               text_poke_early((void *)jump_entry_code(entry), opcode,
-                               JUMP_LABEL_NOP_SIZE);
+               text_poke_early((void *)jump_entry_code(entry), jlp.code, jlp.size);
                return;
        }
 
-       text_poke_bp((void *)jump_entry_code(entry), opcode, JUMP_LABEL_NOP_SIZE, NULL);
+       text_poke_bp((void *)jump_entry_code(entry), jlp.code, jlp.size, NULL);
 }
 
 static void __ref jump_label_transform(struct jump_entry *entry,
@@ -98,7 +122,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
 bool arch_jump_label_transform_queue(struct jump_entry *entry,
                                     enum jump_label_type type)
 {
-       const void *opcode;
+       struct jump_label_patch jlp;
 
        if (system_state == SYSTEM_BOOTING) {
                /*
@@ -109,9 +133,8 @@ bool arch_jump_label_transform_queue(struct jump_entry *entry,
        }
 
        mutex_lock(&text_mutex);
-       opcode = __jump_label_set_jump_code(entry, type);
-       text_poke_queue((void *)jump_entry_code(entry),
-                       opcode, JUMP_LABEL_NOP_SIZE, NULL);
+       jlp = __jump_label_patch(entry, type);
+       text_poke_queue((void *)jump_entry_code(entry), jlp.code, jlp.size, NULL);
        mutex_unlock(&text_mutex);
        return true;
 }
index d3d6554..c492ad3 100644 (file)
@@ -674,7 +674,7 @@ static int prepare_emulation(struct kprobe *p, struct insn *insn)
                        break;
 
                if (insn->addr_bytes != sizeof(unsigned long))
-                       return -EOPNOTSUPP;     /* Don't support differnt size */
+                       return -EOPNOTSUPP;     /* Don't support different size */
                if (X86_MODRM_MOD(opcode) != 3)
                        return -EOPNOTSUPP;     /* TODO: support memory addressing */
 
@@ -1102,24 +1102,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                        restore_previous_kprobe(kcb);
                else
                        reset_current_kprobe();
-       } else if (kcb->kprobe_status == KPROBE_HIT_ACTIVE ||
-                  kcb->kprobe_status == KPROBE_HIT_SSDONE) {
-               /*
-                * We increment the nmissed count for accounting,
-                * we can also use npre/npostfault count for accounting
-                * these specific fault cases.
-                */
-               kprobes_inc_nmissed_count(cur);
-
-               /*
-                * We come here because instructions in the pre/post
-                * handler caused the page_fault, this could happen
-                * if handler tries to access user space by
-                * copy_from_user(), get_user() etc. Let the
-                * user-specified handler try to fix it first.
-                */
-               if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
-                       return 1;
        }
 
        return 0;
index 64b00b0..1b373d7 100644 (file)
 #include <asm/set_memory.h>
 #include <asm/debugreg.h>
 
-static void set_gdt(void *newgdt, __u16 limit)
-{
-       struct desc_ptr curgdt;
-
-       /* ia32 supports unaligned loads & stores */
-       curgdt.size    = limit;
-       curgdt.address = (unsigned long)newgdt;
-
-       load_gdt(&curgdt);
-}
-
 static void load_segments(void)
 {
 #define __STR(X) #X
@@ -232,8 +221,8 @@ void machine_kexec(struct kimage *image)
         * The gdt & idt are now invalid.
         * If you want to load them you must set up your own idt & gdt.
         */
-       idt_invalidate(phys_to_virt(0));
-       set_gdt(phys_to_virt(0), 0);
+       native_idt_invalidate();
+       native_gdt_invalidate();
 
        /* now call it */
        image->start = relocate_kernel_ptr((unsigned long)image->head,
index c078b0d..131f30f 100644 (file)
@@ -256,35 +256,6 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
        return init_transition_pgtable(image, level4p);
 }
 
-static void set_idt(void *newidt, u16 limit)
-{
-       struct desc_ptr curidt;
-
-       /* x86-64 supports unaligned loads & stores */
-       curidt.size    = limit;
-       curidt.address = (unsigned long)newidt;
-
-       __asm__ __volatile__ (
-               "lidtq %0\n"
-               : : "m" (curidt)
-               );
-};
-
-
-static void set_gdt(void *newgdt, u16 limit)
-{
-       struct desc_ptr curgdt;
-
-       /* x86-64 supports unaligned loads & stores */
-       curgdt.size    = limit;
-       curgdt.address = (unsigned long)newgdt;
-
-       __asm__ __volatile__ (
-               "lgdtq %0\n"
-               : : "m" (curgdt)
-               );
-};
-
 static void load_segments(void)
 {
        __asm__ __volatile__ (
@@ -379,8 +350,8 @@ void machine_kexec(struct kimage *image)
         * The gdt & idt are now invalid.
         * If you want to load them you must set up your own idt & gdt.
         */
-       set_gdt(phys_to_virt(0), 0);
-       set_idt(phys_to_virt(0), 0);
+       native_idt_invalidate();
+       native_gdt_invalidate();
 
        /* now call it */
        image->start = relocate_kernel((unsigned long)image->head,
index 5e1f381..e52b208 100644 (file)
@@ -931,7 +931,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long start, bottom, top, sp, fp, ip, ret = 0;
        int count = 0;
 
-       if (p == current || p->state == TASK_RUNNING)
+       if (p == current || task_is_running(p))
                return 0;
 
        if (!try_get_task_stack(p))
@@ -975,7 +975,7 @@ unsigned long get_wchan(struct task_struct *p)
                        goto out;
                }
                fp = READ_ONCE_NOCHECK(*(unsigned long *)fp);
-       } while (count++ < 16 && p->state != TASK_RUNNING);
+       } while (count++ < 16 && !task_is_running(p));
 
 out:
        put_task_stack(p);
index 87a4143..4c208ea 100644 (file)
@@ -911,7 +911,7 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 value)
                 * syscall with TS_COMPAT still set.
                 */
                regs->orig_ax = value;
-               if (syscall_get_nr(child, regs) >= 0)
+               if (syscall_get_nr(child, regs) != -1)
                        child->thread_info.status |= TS_I386_REGS_POKED;
                break;
 
index b29657b..ebfb911 100644 (file)
@@ -669,7 +669,7 @@ static void native_machine_emergency_restart(void)
                        break;
 
                case BOOT_TRIPLE:
-                       idt_invalidate(NULL);
+                       idt_invalidate();
                        __asm__ __volatile__("int3");
 
                        /* We're probably dead after this, but... */
index 1e72062..85acd22 100644 (file)
@@ -695,30 +695,6 @@ static void __init e820_add_kernel_range(void)
        e820__range_add(start, size, E820_TYPE_RAM);
 }
 
-static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
-
-static int __init parse_reservelow(char *p)
-{
-       unsigned long long size;
-
-       if (!p)
-               return -EINVAL;
-
-       size = memparse(p, &p);
-
-       if (size < 4096)
-               size = 4096;
-
-       if (size > 640*1024)
-               size = 640*1024;
-
-       reserve_low = size;
-
-       return 0;
-}
-
-early_param("reservelow", parse_reservelow);
-
 static void __init early_reserve_memory(void)
 {
        /*
@@ -1084,17 +1060,18 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        /*
-        * Find free memory for the real mode trampoline and place it
-        * there.
-        * If there is not enough free memory under 1M, on EFI-enabled
-        * systems there will be additional attempt to reclaim the memory
-        * for the real mode trampoline at efi_free_boot_services().
+        * Find free memory for the real mode trampoline and place it there. If
+        * there is not enough free memory under 1M, on EFI-enabled systems
+        * there will be additional attempt to reclaim the memory for the real
+        * mode trampoline at efi_free_boot_services().
+        *
+        * Unconditionally reserve the entire first 1M of RAM because BIOSes
+        * are known to corrupt low memory and several hundred kilobytes are not
+        * worth complex detection what memory gets clobbered. Windows does the
+        * same thing for very similar reasons.
         *
-        * Unconditionally reserve the entire first 1M of RAM because
-        * BIOSes are know to corrupt low memory and several
-        * hundred kilobytes are not worth complex detection what memory gets
-        * clobbered. Moreover, on machines with SandyBridge graphics or in
-        * setups that use crashkernel the entire 1M is reserved anyway.
+        * Moreover, on machines with SandyBridge graphics or in setups that use
+        * crashkernel the entire 1M is reserved anyway.
         */
        reserve_real_mode();
 
index 651b81c..a6895e4 100644 (file)
@@ -7,12 +7,11 @@
  * Author: Joerg Roedel <jroedel@suse.de>
  */
 
-#define pr_fmt(fmt)    "SEV-ES: " fmt
+#define pr_fmt(fmt)    "SEV: " fmt
 
 #include <linux/sched/debug.h> /* For show_regs() */
 #include <linux/percpu-defs.h>
 #include <linux/mem_encrypt.h>
-#include <linux/lockdep.h>
 #include <linux/printk.h>
 #include <linux/mm_types.h>
 #include <linux/set_memory.h>
@@ -192,11 +191,19 @@ void noinstr __sev_es_ist_exit(void)
        this_cpu_write(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC], *(unsigned long *)ist);
 }
 
-static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
+/*
+ * Nothing shall interrupt this code path while holding the per-CPU
+ * GHCB. The backup GHCB is only for NMIs interrupting this path.
+ *
+ * Callers must disable local interrupts around it.
+ */
+static noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
 {
        struct sev_es_runtime_data *data;
        struct ghcb *ghcb;
 
+       WARN_ON(!irqs_disabled());
+
        data = this_cpu_read(runtime_data);
        ghcb = &data->ghcb_page;
 
@@ -213,7 +220,9 @@ static __always_inline struct ghcb *sev_es_get_ghcb(struct ghcb_state *state)
                        data->ghcb_active        = false;
                        data->backup_ghcb_active = false;
 
+                       instrumentation_begin();
                        panic("Unable to handle #VC exception! GHCB and Backup GHCB are already in use");
+                       instrumentation_end();
                }
 
                /* Mark backup_ghcb active before writing to it */
@@ -258,17 +267,24 @@ static int vc_fetch_insn_kernel(struct es_em_ctxt *ctxt,
 static enum es_result __vc_decode_user_insn(struct es_em_ctxt *ctxt)
 {
        char buffer[MAX_INSN_SIZE];
-       int res;
+       int insn_bytes;
 
-       res = insn_fetch_from_user_inatomic(ctxt->regs, buffer);
-       if (!res) {
+       insn_bytes = insn_fetch_from_user_inatomic(ctxt->regs, buffer);
+       if (insn_bytes == 0) {
+               /* Nothing could be copied */
                ctxt->fi.vector     = X86_TRAP_PF;
                ctxt->fi.error_code = X86_PF_INSTR | X86_PF_USER;
                ctxt->fi.cr2        = ctxt->regs->ip;
                return ES_EXCEPTION;
+       } else if (insn_bytes == -EINVAL) {
+               /* Effective RIP could not be calculated */
+               ctxt->fi.vector     = X86_TRAP_GP;
+               ctxt->fi.error_code = 0;
+               ctxt->fi.cr2        = 0;
+               return ES_EXCEPTION;
        }
 
-       if (!insn_decode_from_regs(&ctxt->insn, ctxt->regs, buffer, res))
+       if (!insn_decode_from_regs(&ctxt->insn, ctxt->regs, buffer, insn_bytes))
                return ES_DECODE_FAILED;
 
        if (ctxt->insn.immediate.got)
@@ -479,11 +495,13 @@ static enum es_result vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt
 /* Include code shared with pre-decompression boot stage */
 #include "sev-shared.c"
 
-static __always_inline void sev_es_put_ghcb(struct ghcb_state *state)
+static noinstr void __sev_put_ghcb(struct ghcb_state *state)
 {
        struct sev_es_runtime_data *data;
        struct ghcb *ghcb;
 
+       WARN_ON(!irqs_disabled());
+
        data = this_cpu_read(runtime_data);
        ghcb = &data->ghcb_page;
 
@@ -507,7 +525,7 @@ void noinstr __sev_es_nmi_complete(void)
        struct ghcb_state state;
        struct ghcb *ghcb;
 
-       ghcb = sev_es_get_ghcb(&state);
+       ghcb = __sev_get_ghcb(&state);
 
        vc_ghcb_invalidate(ghcb);
        ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_NMI_COMPLETE);
@@ -517,7 +535,7 @@ void noinstr __sev_es_nmi_complete(void)
        sev_es_wr_ghcb_msr(__pa_nodebug(ghcb));
        VMGEXIT();
 
-       sev_es_put_ghcb(&state);
+       __sev_put_ghcb(&state);
 }
 
 static u64 get_jump_table_addr(void)
@@ -529,7 +547,7 @@ static u64 get_jump_table_addr(void)
 
        local_irq_save(flags);
 
-       ghcb = sev_es_get_ghcb(&state);
+       ghcb = __sev_get_ghcb(&state);
 
        vc_ghcb_invalidate(ghcb);
        ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_JUMP_TABLE);
@@ -543,7 +561,7 @@ static u64 get_jump_table_addr(void)
            ghcb_sw_exit_info_2_is_valid(ghcb))
                ret = ghcb->save.sw_exit_info_2;
 
-       sev_es_put_ghcb(&state);
+       __sev_put_ghcb(&state);
 
        local_irq_restore(flags);
 
@@ -668,7 +686,7 @@ static void sev_es_ap_hlt_loop(void)
        struct ghcb_state state;
        struct ghcb *ghcb;
 
-       ghcb = sev_es_get_ghcb(&state);
+       ghcb = __sev_get_ghcb(&state);
 
        while (true) {
                vc_ghcb_invalidate(ghcb);
@@ -685,7 +703,7 @@ static void sev_es_ap_hlt_loop(void)
                        break;
        }
 
-       sev_es_put_ghcb(&state);
+       __sev_put_ghcb(&state);
 }
 
 /*
@@ -775,7 +793,7 @@ void __init sev_es_init_vc_handling(void)
        sev_es_setup_play_dead();
 
        /* Secondary CPUs use the runtime #VC handler */
-       initial_vc_handler = (unsigned long)safe_stack_exc_vmm_communication;
+       initial_vc_handler = (unsigned long)kernel_exc_vmm_communication;
 }
 
 static void __init vc_early_forward_exception(struct es_em_ctxt *ctxt)
@@ -1213,14 +1231,6 @@ static enum es_result vc_handle_trap_ac(struct ghcb *ghcb,
        return ES_EXCEPTION;
 }
 
-static __always_inline void vc_handle_trap_db(struct pt_regs *regs)
-{
-       if (user_mode(regs))
-               noist_exc_debug(regs);
-       else
-               exc_debug(regs);
-}
-
 static enum es_result vc_handle_exitcode(struct es_em_ctxt *ctxt,
                                         struct ghcb *ghcb,
                                         unsigned long exit_code)
@@ -1316,44 +1326,15 @@ static __always_inline bool on_vc_fallback_stack(struct pt_regs *regs)
        return (sp >= __this_cpu_ist_bottom_va(VC2) && sp < __this_cpu_ist_top_va(VC2));
 }
 
-/*
- * Main #VC exception handler. It is called when the entry code was able to
- * switch off the IST to a safe kernel stack.
- *
- * With the current implementation it is always possible to switch to a safe
- * stack because #VC exceptions only happen at known places, like intercepted
- * instructions or accesses to MMIO areas/IO ports. They can also happen with
- * code instrumentation when the hypervisor intercepts #DB, but the critical
- * paths are forbidden to be instrumented, so #DB exceptions currently also
- * only happen in safe places.
- */
-DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
+static bool vc_raw_handle_exception(struct pt_regs *regs, unsigned long error_code)
 {
-       irqentry_state_t irq_state;
        struct ghcb_state state;
        struct es_em_ctxt ctxt;
        enum es_result result;
        struct ghcb *ghcb;
+       bool ret = true;
 
-       /*
-        * Handle #DB before calling into !noinstr code to avoid recursive #DB.
-        */
-       if (error_code == SVM_EXIT_EXCP_BASE + X86_TRAP_DB) {
-               vc_handle_trap_db(regs);
-               return;
-       }
-
-       irq_state = irqentry_nmi_enter(regs);
-       lockdep_assert_irqs_disabled();
-       instrumentation_begin();
-
-       /*
-        * This is invoked through an interrupt gate, so IRQs are disabled. The
-        * code below might walk page-tables for user or kernel addresses, so
-        * keep the IRQs disabled to protect us against concurrent TLB flushes.
-        */
-
-       ghcb = sev_es_get_ghcb(&state);
+       ghcb = __sev_get_ghcb(&state);
 
        vc_ghcb_invalidate(ghcb);
        result = vc_init_em_ctxt(&ctxt, regs, error_code);
@@ -1361,7 +1342,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
        if (result == ES_OK)
                result = vc_handle_exitcode(&ctxt, ghcb, error_code);
 
-       sev_es_put_ghcb(&state);
+       __sev_put_ghcb(&state);
 
        /* Done - now check the result */
        switch (result) {
@@ -1369,17 +1350,20 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
                vc_finish_insn(&ctxt);
                break;
        case ES_UNSUPPORTED:
-               pr_err_ratelimited("Unsupported exit-code 0x%02lx in early #VC exception (IP: 0x%lx)\n",
+               pr_err_ratelimited("Unsupported exit-code 0x%02lx in #VC exception (IP: 0x%lx)\n",
                                   error_code, regs->ip);
-               goto fail;
+               ret = false;
+               break;
        case ES_VMM_ERROR:
                pr_err_ratelimited("Failure in communication with VMM (exit-code 0x%02lx IP: 0x%lx)\n",
                                   error_code, regs->ip);
-               goto fail;
+               ret = false;
+               break;
        case ES_DECODE_FAILED:
                pr_err_ratelimited("Failed to decode instruction (exit-code 0x%02lx IP: 0x%lx)\n",
                                   error_code, regs->ip);
-               goto fail;
+               ret = false;
+               break;
        case ES_EXCEPTION:
                vc_forward_exception(&ctxt);
                break;
@@ -1395,24 +1379,52 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
                BUG();
        }
 
-out:
-       instrumentation_end();
-       irqentry_nmi_exit(regs, irq_state);
+       return ret;
+}
 
-       return;
+static __always_inline bool vc_is_db(unsigned long error_code)
+{
+       return error_code == SVM_EXIT_EXCP_BASE + X86_TRAP_DB;
+}
 
-fail:
-       if (user_mode(regs)) {
-               /*
-                * Do not kill the machine if user-space triggered the
-                * exception. Send SIGBUS instead and let user-space deal with
-                * it.
-                */
-               force_sig_fault(SIGBUS, BUS_OBJERR, (void __user *)0);
-       } else {
-               pr_emerg("PANIC: Unhandled #VC exception in kernel space (result=%d)\n",
-                        result);
+/*
+ * Runtime #VC exception handler when raised from kernel mode. Runs in NMI mode
+ * and will panic when an error happens.
+ */
+DEFINE_IDTENTRY_VC_KERNEL(exc_vmm_communication)
+{
+       irqentry_state_t irq_state;
+
+       /*
+        * With the current implementation it is always possible to switch to a
+        * safe stack because #VC exceptions only happen at known places, like
+        * intercepted instructions or accesses to MMIO areas/IO ports. They can
+        * also happen with code instrumentation when the hypervisor intercepts
+        * #DB, but the critical paths are forbidden to be instrumented, so #DB
+        * exceptions currently also only happen in safe places.
+        *
+        * But keep this here in case the noinstr annotations are violated due
+        * to bug elsewhere.
+        */
+       if (unlikely(on_vc_fallback_stack(regs))) {
+               instrumentation_begin();
+               panic("Can't handle #VC exception from unsupported context\n");
+               instrumentation_end();
+       }
 
+       /*
+        * Handle #DB before calling into !noinstr code to avoid recursive #DB.
+        */
+       if (vc_is_db(error_code)) {
+               exc_debug(regs);
+               return;
+       }
+
+       irq_state = irqentry_nmi_enter(regs);
+
+       instrumentation_begin();
+
+       if (!vc_raw_handle_exception(regs, error_code)) {
                /* Show some debug info */
                show_regs(regs);
 
@@ -1423,23 +1435,38 @@ fail:
                panic("Returned from Terminate-Request to Hypervisor\n");
        }
 
-       goto out;
+       instrumentation_end();
+       irqentry_nmi_exit(regs, irq_state);
 }
 
-/* This handler runs on the #VC fall-back stack. It can cause further #VC exceptions */
-DEFINE_IDTENTRY_VC_IST(exc_vmm_communication)
+/*
+ * Runtime #VC exception handler when raised from user mode. Runs in IRQ mode
+ * and will kill the current task with SIGBUS when an error happens.
+ */
+DEFINE_IDTENTRY_VC_USER(exc_vmm_communication)
 {
+       /*
+        * Handle #DB before calling into !noinstr code to avoid recursive #DB.
+        */
+       if (vc_is_db(error_code)) {
+               noist_exc_debug(regs);
+               return;
+       }
+
+       irqentry_enter_from_user_mode(regs);
        instrumentation_begin();
-       panic("Can't handle #VC exception from unsupported context\n");
-       instrumentation_end();
-}
 
-DEFINE_IDTENTRY_VC(exc_vmm_communication)
-{
-       if (likely(!on_vc_fallback_stack(regs)))
-               safe_stack_exc_vmm_communication(regs, error_code);
-       else
-               ist_exc_vmm_communication(regs, error_code);
+       if (!vc_raw_handle_exception(regs, error_code)) {
+               /*
+                * Do not kill the machine if user-space triggered the
+                * exception. Send SIGBUS instead and let user-space deal with
+                * it.
+                */
+               force_sig_fault(SIGBUS, BUS_OBJERR, (void __user *)0);
+       }
+
+       instrumentation_end();
+       irqentry_exit_to_user_mode(regs);
 }
 
 bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
index a06cb10..e12779a 100644 (file)
@@ -713,7 +713,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
                save_v86_state((struct kernel_vm86_regs *) regs, VM86_SIGNAL);
 
        /* Are we from a system call? */
-       if (syscall_get_nr(current, regs) >= 0) {
+       if (syscall_get_nr(current, regs) != -1) {
                /* If so, check system call restarting.. */
                switch (syscall_get_error(current, regs)) {
                case -ERESTART_RESTARTBLOCK:
@@ -793,7 +793,7 @@ void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
        }
 
        /* Did we come from a system call? */
-       if (syscall_get_nr(current, regs) >= 0) {
+       if (syscall_get_nr(current, regs) != -1) {
                /* Restart the system call - no handlers present */
                switch (syscall_get_error(current, regs)) {
                case -ERESTARTNOHAND:
index 7770245..9320285 100644 (file)
@@ -232,11 +232,9 @@ static void notrace start_secondary(void *unused)
        load_cr3(swapper_pg_dir);
        __flush_tlb_all();
 #endif
-       cpu_init_exception_handling();
-       cpu_init();
+       cpu_init_secondary();
        rcu_cpu_starting(raw_smp_processor_id());
        x86_cpuinit.early_percpu_clock_init();
-       preempt_disable();
        smp_callin();
 
        enable_start_cpu0 = 0;
index 853ea7a..ed540e0 100644 (file)
@@ -1160,12 +1160,9 @@ void __init trap_init(void)
        /* Init GHCB memory pages when running as an SEV-ES guest */
        sev_es_init_vc_handling();
 
+       /* Initialize TSS before setting up traps so ISTs work */
+       cpu_init_exception_handling();
+       /* Setup traps as cpu_init() might #GP */
        idt_setup_traps();
-
-       /*
-        * Should be a barrier for any external CPU state:
-        */
        cpu_init();
-
-       idt_setup_ist_traps();
 }
index 57ec011..2e076a4 100644 (file)
@@ -1128,6 +1128,7 @@ static int tsc_cs_enable(struct clocksource *cs)
 static struct clocksource clocksource_tsc_early = {
        .name                   = "tsc-early",
        .rating                 = 299,
+       .uncertainty_margin     = 32 * NSEC_PER_MSEC,
        .read                   = read_tsc,
        .mask                   = CLOCKSOURCE_MASK(64),
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
@@ -1152,7 +1153,8 @@ static struct clocksource clocksource_tsc = {
        .mask                   = CLOCKSOURCE_MASK(64),
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_VALID_FOR_HRES |
-                                 CLOCK_SOURCE_MUST_VERIFY,
+                                 CLOCK_SOURCE_MUST_VERIFY |
+                                 CLOCK_SOURCE_VERIFY_PERCPU,
        .vdso_clock_mode        = VDSO_CLOCKMODE_TSC,
        .enable                 = tsc_cs_enable,
        .resume                 = tsc_resume,
index 8daa70b..576b47e 100644 (file)
@@ -346,14 +346,12 @@ bool fixup_umip_exception(struct pt_regs *regs)
        if (!regs)
                return false;
 
-       nr_copied = insn_fetch_from_user(regs, buf);
-
        /*
-        * The insn_fetch_from_user above could have failed if user code
-        * is protected by a memory protection key. Give up on emulation
-        * in such a case.  Should we issue a page fault?
+        * Give up on emulation if fetching the instruction failed. Should a
+        * page fault or a #GP be issued?
         */
-       if (!nr_copied)
+       nr_copied = insn_fetch_from_user(regs, buf);
+       if (nr_copied <= 0)
                return false;
 
        if (!insn_decode_from_regs(&insn, regs, buf, nr_copied))
index f6b93a3..ac69894 100644 (file)
@@ -22,8 +22,6 @@ config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
        depends on HAVE_KVM
        depends on HIGH_RES_TIMERS
-       # for TASKSTATS/TASK_DELAY_ACCT:
-       depends on NET && MULTIUSER
        depends on X86_LOCAL_APIC
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
@@ -36,8 +34,7 @@ config KVM
        select KVM_ASYNC_PF
        select USER_RETURN_NOTIFIER
        select KVM_MMIO
-       select TASKSTATS
-       select TASK_DELAY_ACCT
+       select SCHED_INFO
        select PERF_EVENTS
        select HAVE_KVM_MSI
        select HAVE_KVM_CPU_RELAX_INTERCEPT
@@ -46,6 +43,7 @@ config KVM
        select KVM_GENERIC_DIRTYLOG_READ_PROTECT
        select KVM_VFIO
        select SRCU
+       select HAVE_KVM_PM_NOTIFIER if PM
        help
          Support hosting fully virtualized guest machines using hardware
          virtualization extensions.  You will need a fairly recent
index c589db5..75dfd27 100644 (file)
@@ -11,13 +11,18 @@ KVM := ../../../virt/kvm
 
 kvm-y                  += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
                                $(KVM)/eventfd.o $(KVM)/irqchip.o $(KVM)/vfio.o \
-                               $(KVM)/dirty_ring.o
+                               $(KVM)/dirty_ring.o $(KVM)/binary_stats.o
 kvm-$(CONFIG_KVM_ASYNC_PF)     += $(KVM)/async_pf.o
 
 kvm-y                  += x86.o emulate.o i8259.o irq.o lapic.o \
                           i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
                           hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
                           mmu/spte.o
+
+ifdef CONFIG_HYPERV
+kvm-y                  += kvm_onhyperv.o
+endif
+
 kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o
 kvm-$(CONFIG_KVM_XEN)  += xen.o
 
@@ -27,6 +32,10 @@ kvm-intel-$(CONFIG_X86_SGX_KVM)      += vmx/sgx.o
 
 kvm-amd-y              += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o svm/sev.o
 
+ifdef CONFIG_HYPERV
+kvm-amd-y              += svm/svm_onhyperv.o
+endif
+
 obj-$(CONFIG_KVM)      += kvm.o
 obj-$(CONFIG_KVM_INTEL)        += kvm-intel.o
 obj-$(CONFIG_KVM_AMD)  += kvm-amd.o
index 9a48f13..c42613c 100644 (file)
@@ -202,10 +202,10 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
        static_call(kvm_x86_vcpu_after_set_cpuid)(vcpu);
 
        /*
-        * Except for the MMU, which needs to be reset after any vendor
-        * specific adjustments to the reserved GPA bits.
+        * Except for the MMU, which needs to do its thing any vendor specific
+        * adjustments to the reserved GPA bits.
         */
-       kvm_mmu_reset_context(vcpu);
+       kvm_mmu_after_set_cpuid(vcpu);
 }
 
 static int is_efer_nx(void)
@@ -655,6 +655,7 @@ static int __do_cpuid_func_emulated(struct kvm_cpuid_array *array, u32 func)
                if (kvm_cpu_cap_has(X86_FEATURE_RDTSCP))
                        entry->ecx = F(RDPID);
                ++array->nent;
+               break;
        default:
                break;
        }
index 7e818d6..95a9841 100644 (file)
@@ -17,6 +17,15 @@ static int vcpu_get_timer_advance_ns(void *data, u64 *val)
 
 DEFINE_SIMPLE_ATTRIBUTE(vcpu_timer_advance_ns_fops, vcpu_get_timer_advance_ns, NULL, "%llu\n");
 
+static int vcpu_get_guest_mode(void *data, u64 *val)
+{
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
+       *val = vcpu->stat.guest_mode;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vcpu_guest_mode_fops, vcpu_get_guest_mode, NULL, "%lld\n");
+
 static int vcpu_get_tsc_offset(void *data, u64 *val)
 {
        struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data;
@@ -45,6 +54,8 @@ DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_frac_fops, vcpu_get_tsc_scaling_frac_bi
 
 void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry)
 {
+       debugfs_create_file("guest_mode", 0444, debugfs_dentry, vcpu,
+                           &vcpu_guest_mode_fops);
        debugfs_create_file("tsc-offset", 0444, debugfs_dentry, vcpu,
                            &vcpu_tsc_offset_fops);
 
index 5e5de05..2837110 100644 (file)
@@ -22,7 +22,6 @@
 #include "kvm_cache_regs.h"
 #include "kvm_emulate.h"
 #include <linux/stringify.h>
-#include <asm/fpu/api.h>
 #include <asm/debugreg.h>
 #include <asm/nospec-branch.h>
 
@@ -1081,116 +1080,14 @@ static void fetch_register_operand(struct operand *op)
        }
 }
 
-static void emulator_get_fpu(void)
-{
-       fpregs_lock();
-
-       fpregs_assert_state_consistent();
-       if (test_thread_flag(TIF_NEED_FPU_LOAD))
-               switch_fpu_return();
-}
-
-static void emulator_put_fpu(void)
-{
-       fpregs_unlock();
-}
-
-static void read_sse_reg(sse128_t *data, int reg)
-{
-       emulator_get_fpu();
-       switch (reg) {
-       case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
-       case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
-       case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break;
-       case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break;
-       case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break;
-       case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break;
-       case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break;
-       case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break;
-#ifdef CONFIG_X86_64
-       case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break;
-       case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break;
-       case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break;
-       case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break;
-       case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break;
-       case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break;
-       case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break;
-       case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break;
-#endif
-       default: BUG();
-       }
-       emulator_put_fpu();
-}
-
-static void write_sse_reg(sse128_t *data, int reg)
-{
-       emulator_get_fpu();
-       switch (reg) {
-       case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
-       case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
-       case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break;
-       case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break;
-       case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break;
-       case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break;
-       case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break;
-       case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break;
-#ifdef CONFIG_X86_64
-       case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break;
-       case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break;
-       case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break;
-       case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break;
-       case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break;
-       case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break;
-       case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break;
-       case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break;
-#endif
-       default: BUG();
-       }
-       emulator_put_fpu();
-}
-
-static void read_mmx_reg(u64 *data, int reg)
-{
-       emulator_get_fpu();
-       switch (reg) {
-       case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
-       case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
-       case 2: asm("movq %%mm2, %0" : "=m"(*data)); break;
-       case 3: asm("movq %%mm3, %0" : "=m"(*data)); break;
-       case 4: asm("movq %%mm4, %0" : "=m"(*data)); break;
-       case 5: asm("movq %%mm5, %0" : "=m"(*data)); break;
-       case 6: asm("movq %%mm6, %0" : "=m"(*data)); break;
-       case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
-       default: BUG();
-       }
-       emulator_put_fpu();
-}
-
-static void write_mmx_reg(u64 *data, int reg)
-{
-       emulator_get_fpu();
-       switch (reg) {
-       case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
-       case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
-       case 2: asm("movq %0, %%mm2" : : "m"(*data)); break;
-       case 3: asm("movq %0, %%mm3" : : "m"(*data)); break;
-       case 4: asm("movq %0, %%mm4" : : "m"(*data)); break;
-       case 5: asm("movq %0, %%mm5" : : "m"(*data)); break;
-       case 6: asm("movq %0, %%mm6" : : "m"(*data)); break;
-       case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
-       default: BUG();
-       }
-       emulator_put_fpu();
-}
-
 static int em_fninit(struct x86_emulate_ctxt *ctxt)
 {
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       emulator_get_fpu();
+       kvm_fpu_get();
        asm volatile("fninit");
-       emulator_put_fpu();
+       kvm_fpu_put();
        return X86EMUL_CONTINUE;
 }
 
@@ -1201,9 +1098,9 @@ static int em_fnstcw(struct x86_emulate_ctxt *ctxt)
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       emulator_get_fpu();
+       kvm_fpu_get();
        asm volatile("fnstcw %0": "+m"(fcw));
-       emulator_put_fpu();
+       kvm_fpu_put();
 
        ctxt->dst.val = fcw;
 
@@ -1217,9 +1114,9 @@ static int em_fnstsw(struct x86_emulate_ctxt *ctxt)
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       emulator_get_fpu();
+       kvm_fpu_get();
        asm volatile("fnstsw %0": "+m"(fsw));
-       emulator_put_fpu();
+       kvm_fpu_put();
 
        ctxt->dst.val = fsw;
 
@@ -1238,7 +1135,7 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
                op->type = OP_XMM;
                op->bytes = 16;
                op->addr.xmm = reg;
-               read_sse_reg(&op->vec_val, reg);
+               kvm_read_sse_reg(reg, &op->vec_val);
                return;
        }
        if (ctxt->d & Mmx) {
@@ -1289,7 +1186,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                        op->type = OP_XMM;
                        op->bytes = 16;
                        op->addr.xmm = ctxt->modrm_rm;
-                       read_sse_reg(&op->vec_val, ctxt->modrm_rm);
+                       kvm_read_sse_reg(ctxt->modrm_rm, &op->vec_val);
                        return rc;
                }
                if (ctxt->d & Mmx) {
@@ -1866,10 +1763,10 @@ static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
                                       op->bytes * op->count);
                break;
        case OP_XMM:
-               write_sse_reg(&op->vec_val, op->addr.xmm);
+               kvm_write_sse_reg(op->addr.xmm, &op->vec_val);
                break;
        case OP_MM:
-               write_mmx_reg(&op->mm_val, op->addr.mm);
+               kvm_write_mmx_reg(op->addr.mm, &op->mm_val);
                break;
        case OP_NONE:
                /* no writeback */
@@ -2638,8 +2535,7 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt)
        if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_INSIDE_NMI_MASK) == 0)
                ctxt->ops->set_nmi_mask(ctxt, false);
 
-       ctxt->ops->set_hflags(ctxt, ctxt->ops->get_hflags(ctxt) &
-               ~(X86EMUL_SMM_INSIDE_NMI_MASK | X86EMUL_SMM_MASK));
+       ctxt->ops->exiting_smm(ctxt);
 
        /*
         * Get back to real mode, to prepare a safe state in which to load
@@ -2678,12 +2574,12 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt)
        }
 
        /*
-        * Give pre_leave_smm() a chance to make ISA-specific changes to the
-        * vCPU state (e.g. enter guest mode) before loading state from the SMM
+        * Give leave_smm() a chance to make ISA-specific changes to the vCPU
+        * state (e.g. enter guest mode) before loading state from the SMM
         * state-save area.
         */
-       if (ctxt->ops->pre_leave_smm(ctxt, buf))
-               return X86EMUL_UNHANDLEABLE;
+       if (ctxt->ops->leave_smm(ctxt, buf))
+               goto emulate_shutdown;
 
 #ifdef CONFIG_X86_64
        if (emulator_has_longmode(ctxt))
@@ -2692,13 +2588,21 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt)
 #endif
                ret = rsm_load_state_32(ctxt, buf);
 
-       if (ret != X86EMUL_CONTINUE) {
-               /* FIXME: should triple fault */
-               return X86EMUL_UNHANDLEABLE;
-       }
+       if (ret != X86EMUL_CONTINUE)
+               goto emulate_shutdown;
 
-       ctxt->ops->post_leave_smm(ctxt);
+       /*
+        * Note, the ctxt->ops callbacks are responsible for handling side
+        * effects when writing MSRs and CRs, e.g. MMU context resets, CPUID
+        * runtime updates, etc...  If that changes, e.g. this flow is moved
+        * out of the emulator to make it look more like enter_smm(), then
+        * those side effects need to be explicitly handled for both success
+        * and shutdown.
+        */
+       return X86EMUL_CONTINUE;
 
+emulate_shutdown:
+       ctxt->ops->triple_fault(ctxt);
        return X86EMUL_CONTINUE;
 }
 
@@ -4124,11 +4028,11 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       emulator_get_fpu();
+       kvm_fpu_get();
 
        rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
 
-       emulator_put_fpu();
+       kvm_fpu_put();
 
        if (rc != X86EMUL_CONTINUE)
                return rc;
@@ -4172,7 +4076,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       emulator_get_fpu();
+       kvm_fpu_get();
 
        if (size < __fxstate_size(16)) {
                rc = fxregs_fixup(&fx_state, size);
@@ -4189,7 +4093,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
                rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state));
 
 out:
-       emulator_put_fpu();
+       kvm_fpu_put();
 
        return rc;
 }
@@ -5437,9 +5341,9 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
 {
        int rc;
 
-       emulator_get_fpu();
+       kvm_fpu_get();
        rc = asm_safe("fwait");
-       emulator_put_fpu();
+       kvm_fpu_put();
 
        if (unlikely(rc != X86EMUL_CONTINUE))
                return emulate_exception(ctxt, MF_VECTOR, 0, false);
@@ -5450,7 +5354,7 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
 static void fetch_possible_mmx_operand(struct operand *op)
 {
        if (op->type == OP_MM)
-               read_mmx_reg(&op->mm_val, op->addr.mm);
+               kvm_read_mmx_reg(op->addr.mm, &op->mm_val);
 }
 
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop)
diff --git a/arch/x86/kvm/fpu.h b/arch/x86/kvm/fpu.h
new file mode 100644 (file)
index 0000000..3ba1288
--- /dev/null
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __KVM_FPU_H_
+#define __KVM_FPU_H_
+
+#include <asm/fpu/api.h>
+
+typedef u32            __attribute__((vector_size(16))) sse128_t;
+#define __sse128_u     union { sse128_t vec; u64 as_u64[2]; u32 as_u32[4]; }
+#define sse128_lo(x)   ({ __sse128_u t; t.vec = x; t.as_u64[0]; })
+#define sse128_hi(x)   ({ __sse128_u t; t.vec = x; t.as_u64[1]; })
+#define sse128_l0(x)   ({ __sse128_u t; t.vec = x; t.as_u32[0]; })
+#define sse128_l1(x)   ({ __sse128_u t; t.vec = x; t.as_u32[1]; })
+#define sse128_l2(x)   ({ __sse128_u t; t.vec = x; t.as_u32[2]; })
+#define sse128_l3(x)   ({ __sse128_u t; t.vec = x; t.as_u32[3]; })
+#define sse128(lo, hi) ({ __sse128_u t; t.as_u64[0] = lo; t.as_u64[1] = hi; t.vec; })
+
+static inline void _kvm_read_sse_reg(int reg, sse128_t *data)
+{
+       switch (reg) {
+       case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
+       case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
+       case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break;
+       case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break;
+       case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break;
+       case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break;
+       case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break;
+       case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break;
+#ifdef CONFIG_X86_64
+       case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break;
+       case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break;
+       case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break;
+       case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break;
+       case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break;
+       case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break;
+       case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break;
+       case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break;
+#endif
+       default: BUG();
+       }
+}
+
+static inline void _kvm_write_sse_reg(int reg, const sse128_t *data)
+{
+       switch (reg) {
+       case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
+       case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
+       case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break;
+       case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break;
+       case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break;
+       case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break;
+       case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break;
+       case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break;
+#ifdef CONFIG_X86_64
+       case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break;
+       case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break;
+       case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break;
+       case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break;
+       case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break;
+       case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break;
+       case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break;
+       case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break;
+#endif
+       default: BUG();
+       }
+}
+
+static inline void _kvm_read_mmx_reg(int reg, u64 *data)
+{
+       switch (reg) {
+       case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
+       case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
+       case 2: asm("movq %%mm2, %0" : "=m"(*data)); break;
+       case 3: asm("movq %%mm3, %0" : "=m"(*data)); break;
+       case 4: asm("movq %%mm4, %0" : "=m"(*data)); break;
+       case 5: asm("movq %%mm5, %0" : "=m"(*data)); break;
+       case 6: asm("movq %%mm6, %0" : "=m"(*data)); break;
+       case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
+       default: BUG();
+       }
+}
+
+static inline void _kvm_write_mmx_reg(int reg, const u64 *data)
+{
+       switch (reg) {
+       case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
+       case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
+       case 2: asm("movq %0, %%mm2" : : "m"(*data)); break;
+       case 3: asm("movq %0, %%mm3" : : "m"(*data)); break;
+       case 4: asm("movq %0, %%mm4" : : "m"(*data)); break;
+       case 5: asm("movq %0, %%mm5" : : "m"(*data)); break;
+       case 6: asm("movq %0, %%mm6" : : "m"(*data)); break;
+       case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
+       default: BUG();
+       }
+}
+
+static inline void kvm_fpu_get(void)
+{
+       fpregs_lock();
+
+       fpregs_assert_state_consistent();
+       if (test_thread_flag(TIF_NEED_FPU_LOAD))
+               switch_fpu_return();
+}
+
+static inline void kvm_fpu_put(void)
+{
+       fpregs_unlock();
+}
+
+static inline void kvm_read_sse_reg(int reg, sse128_t *data)
+{
+       kvm_fpu_get();
+       _kvm_read_sse_reg(reg, data);
+       kvm_fpu_put();
+}
+
+static inline void kvm_write_sse_reg(int reg, const sse128_t *data)
+{
+       kvm_fpu_get();
+       _kvm_write_sse_reg(reg, data);
+       kvm_fpu_put();
+}
+
+static inline void kvm_read_mmx_reg(int reg, u64 *data)
+{
+       kvm_fpu_get();
+       _kvm_read_mmx_reg(reg, data);
+       kvm_fpu_put();
+}
+
+static inline void kvm_write_mmx_reg(int reg, const u64 *data)
+{
+       kvm_fpu_get();
+       _kvm_write_mmx_reg(reg, data);
+       kvm_fpu_put();
+}
+
+#endif
index f00830e..b07592c 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "trace.h"
 #include "irq.h"
+#include "fpu.h"
 
 /* "Hv#1" signature */
 #define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
@@ -273,15 +274,10 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
 
 static bool kvm_hv_is_syndbg_enabled(struct kvm_vcpu *vcpu)
 {
-       struct kvm_cpuid_entry2 *entry;
-
-       entry = kvm_find_cpuid_entry(vcpu,
-                                    HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES,
-                                    0);
-       if (!entry)
-               return false;
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
 
-       return entry->eax & HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+       return hv_vcpu->cpuid_cache.syndbg_cap_eax &
+               HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
 }
 
 static int kvm_hv_syndbg_complete_userspace(struct kvm_vcpu *vcpu)
@@ -635,11 +631,17 @@ static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config,
        union hv_stimer_config new_config = {.as_uint64 = config},
                old_config = {.as_uint64 = stimer->config.as_uint64};
        struct kvm_vcpu *vcpu = hv_stimer_to_vcpu(stimer);
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
        struct kvm_vcpu_hv_synic *synic = to_hv_synic(vcpu);
 
        if (!synic->active && !host)
                return 1;
 
+       if (unlikely(!host && hv_vcpu->enforce_cpuid && new_config.direct_mode &&
+                    !(hv_vcpu->cpuid_cache.features_edx &
+                      HV_STIMER_DIRECT_MODE_AVAILABLE)))
+               return 1;
+
        trace_kvm_hv_stimer_set_config(hv_stimer_to_vcpu(stimer)->vcpu_id,
                                       stimer->index, config, host);
 
@@ -1206,12 +1208,90 @@ out_unlock:
        mutex_unlock(&hv->hv_lock);
 }
 
+
+static bool hv_check_msr_access(struct kvm_vcpu_hv *hv_vcpu, u32 msr)
+{
+       if (!hv_vcpu->enforce_cpuid)
+               return true;
+
+       switch (msr) {
+       case HV_X64_MSR_GUEST_OS_ID:
+       case HV_X64_MSR_HYPERCALL:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_HYPERCALL_AVAILABLE;
+       case HV_X64_MSR_VP_RUNTIME:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_VP_RUNTIME_AVAILABLE;
+       case HV_X64_MSR_TIME_REF_COUNT:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_TIME_REF_COUNT_AVAILABLE;
+       case HV_X64_MSR_VP_INDEX:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_VP_INDEX_AVAILABLE;
+       case HV_X64_MSR_RESET:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_RESET_AVAILABLE;
+       case HV_X64_MSR_REFERENCE_TSC:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_REFERENCE_TSC_AVAILABLE;
+       case HV_X64_MSR_SCONTROL:
+       case HV_X64_MSR_SVERSION:
+       case HV_X64_MSR_SIEFP:
+       case HV_X64_MSR_SIMP:
+       case HV_X64_MSR_EOM:
+       case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_SYNIC_AVAILABLE;
+       case HV_X64_MSR_STIMER0_CONFIG:
+       case HV_X64_MSR_STIMER1_CONFIG:
+       case HV_X64_MSR_STIMER2_CONFIG:
+       case HV_X64_MSR_STIMER3_CONFIG:
+       case HV_X64_MSR_STIMER0_COUNT:
+       case HV_X64_MSR_STIMER1_COUNT:
+       case HV_X64_MSR_STIMER2_COUNT:
+       case HV_X64_MSR_STIMER3_COUNT:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_SYNTIMER_AVAILABLE;
+       case HV_X64_MSR_EOI:
+       case HV_X64_MSR_ICR:
+       case HV_X64_MSR_TPR:
+       case HV_X64_MSR_VP_ASSIST_PAGE:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_MSR_APIC_ACCESS_AVAILABLE;
+               break;
+       case HV_X64_MSR_TSC_FREQUENCY:
+       case HV_X64_MSR_APIC_FREQUENCY:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_ACCESS_FREQUENCY_MSRS;
+       case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_CONTROL:
+       case HV_X64_MSR_TSC_EMULATION_STATUS:
+               return hv_vcpu->cpuid_cache.features_eax &
+                       HV_ACCESS_REENLIGHTENMENT;
+       case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
+       case HV_X64_MSR_CRASH_CTL:
+               return hv_vcpu->cpuid_cache.features_edx &
+                       HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
+       case HV_X64_MSR_SYNDBG_OPTIONS:
+       case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
+               return hv_vcpu->cpuid_cache.features_edx &
+                       HV_FEATURE_DEBUG_MSRS_AVAILABLE;
+       default:
+               break;
+       }
+
+       return false;
+}
+
 static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
                             bool host)
 {
        struct kvm *kvm = vcpu->kvm;
        struct kvm_hv *hv = to_kvm_hv(kvm);
 
+       if (unlikely(!host && !hv_check_msr_access(to_hv_vcpu(vcpu), msr)))
+               return 1;
+
        switch (msr) {
        case HV_X64_MSR_GUEST_OS_ID:
                hv->hv_guest_os_id = data;
@@ -1340,6 +1420,9 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
 {
        struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
 
+       if (unlikely(!host && !hv_check_msr_access(hv_vcpu, msr)))
+               return 1;
+
        switch (msr) {
        case HV_X64_MSR_VP_INDEX: {
                struct kvm_hv *hv = to_kvm_hv(vcpu->kvm);
@@ -1454,6 +1537,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata,
        struct kvm *kvm = vcpu->kvm;
        struct kvm_hv *hv = to_kvm_hv(kvm);
 
+       if (unlikely(!host && !hv_check_msr_access(to_hv_vcpu(vcpu), msr)))
+               return 1;
+
        switch (msr) {
        case HV_X64_MSR_GUEST_OS_ID:
                data = hv->hv_guest_os_id;
@@ -1503,6 +1589,9 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata,
        u64 data = 0;
        struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
 
+       if (unlikely(!host && !hv_check_msr_access(hv_vcpu, msr)))
+               return 1;
+
        switch (msr) {
        case HV_X64_MSR_VP_INDEX:
                data = hv_vcpu->vp_index;
@@ -1631,8 +1720,22 @@ static __always_inline unsigned long *sparse_set_to_vcpu_mask(
        return vcpu_bitmap;
 }
 
-static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, u64 ingpa, u16 rep_cnt, bool ex)
+struct kvm_hv_hcall {
+       u64 param;
+       u64 ingpa;
+       u64 outgpa;
+       u16 code;
+       u16 rep_cnt;
+       u16 rep_idx;
+       bool fast;
+       bool rep;
+       sse128_t xmm[HV_HYPERCALL_MAX_XMM_REGISTERS];
+};
+
+static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool ex)
 {
+       int i;
+       gpa_t gpa;
        struct kvm *kvm = vcpu->kvm;
        struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
        struct hv_tlb_flush_ex flush_ex;
@@ -1646,8 +1749,15 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, u64 ingpa, u16 rep_cnt, bool
        bool all_cpus;
 
        if (!ex) {
-               if (unlikely(kvm_read_guest(kvm, ingpa, &flush, sizeof(flush))))
-                       return HV_STATUS_INVALID_HYPERCALL_INPUT;
+               if (hc->fast) {
+                       flush.address_space = hc->ingpa;
+                       flush.flags = hc->outgpa;
+                       flush.processor_mask = sse128_lo(hc->xmm[0]);
+               } else {
+                       if (unlikely(kvm_read_guest(kvm, hc->ingpa,
+                                                   &flush, sizeof(flush))))
+                               return HV_STATUS_INVALID_HYPERCALL_INPUT;
+               }
 
                trace_kvm_hv_flush_tlb(flush.processor_mask,
                                       flush.address_space, flush.flags);
@@ -1665,9 +1775,16 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, u64 ingpa, u16 rep_cnt, bool
                all_cpus = (flush.flags & HV_FLUSH_ALL_PROCESSORS) ||
                        flush.processor_mask == 0;
        } else {
-               if (unlikely(kvm_read_guest(kvm, ingpa, &flush_ex,
-                                           sizeof(flush_ex))))
-                       return HV_STATUS_INVALID_HYPERCALL_INPUT;
+               if (hc->fast) {
+                       flush_ex.address_space = hc->ingpa;
+                       flush_ex.flags = hc->outgpa;
+                       memcpy(&flush_ex.hv_vp_set,
+                              &hc->xmm[0], sizeof(hc->xmm[0]));
+               } else {
+                       if (unlikely(kvm_read_guest(kvm, hc->ingpa, &flush_ex,
+                                                   sizeof(flush_ex))))
+                               return HV_STATUS_INVALID_HYPERCALL_INPUT;
+               }
 
                trace_kvm_hv_flush_tlb_ex(flush_ex.hv_vp_set.valid_bank_mask,
                                          flush_ex.hv_vp_set.format,
@@ -1678,20 +1795,28 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, u64 ingpa, u16 rep_cnt, bool
                all_cpus = flush_ex.hv_vp_set.format !=
                        HV_GENERIC_SET_SPARSE_4K;
 
-               sparse_banks_len =
-                       bitmap_weight((unsigned long *)&valid_bank_mask, 64) *
-                       sizeof(sparse_banks[0]);
+               sparse_banks_len = bitmap_weight((unsigned long *)&valid_bank_mask, 64);
 
                if (!sparse_banks_len && !all_cpus)
                        goto ret_success;
 
-               if (!all_cpus &&
-                   kvm_read_guest(kvm,
-                                  ingpa + offsetof(struct hv_tlb_flush_ex,
-                                                   hv_vp_set.bank_contents),
-                                  sparse_banks,
-                                  sparse_banks_len))
-                       return HV_STATUS_INVALID_HYPERCALL_INPUT;
+               if (!all_cpus) {
+                       if (hc->fast) {
+                               if (sparse_banks_len > HV_HYPERCALL_MAX_XMM_REGISTERS - 1)
+                                       return HV_STATUS_INVALID_HYPERCALL_INPUT;
+                               for (i = 0; i < sparse_banks_len; i += 2) {
+                                       sparse_banks[i] = sse128_lo(hc->xmm[i / 2 + 1]);
+                                       sparse_banks[i + 1] = sse128_hi(hc->xmm[i / 2 + 1]);
+                               }
+                       } else {
+                               gpa = hc->ingpa + offsetof(struct hv_tlb_flush_ex,
+                                                          hv_vp_set.bank_contents);
+                               if (unlikely(kvm_read_guest(kvm, gpa, sparse_banks,
+                                                           sparse_banks_len *
+                                                           sizeof(sparse_banks[0]))))
+                                       return HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       }
+               }
        }
 
        cpumask_clear(&hv_vcpu->tlb_flush);
@@ -1704,13 +1829,13 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, u64 ingpa, u16 rep_cnt, bool
         * vcpu->arch.cr3 may not be up-to-date for running vCPUs so we can't
         * analyze it here, flush TLB regardless of the specified address space.
         */
-       kvm_make_vcpus_request_mask(kvm, KVM_REQ_HV_TLB_FLUSH,
+       kvm_make_vcpus_request_mask(kvm, KVM_REQ_TLB_FLUSH_GUEST,
                                    NULL, vcpu_mask, &hv_vcpu->tlb_flush);
 
 ret_success:
-       /* We always do full TLB flush, set rep_done = rep_cnt. */
+       /* We always do full TLB flush, set 'Reps completed' = 'Rep Count' */
        return (u64)HV_STATUS_SUCCESS |
-               ((u64)rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET);
+               ((u64)hc->rep_cnt << HV_HYPERCALL_REP_COMP_OFFSET);
 }
 
 static void kvm_send_ipi_to_many(struct kvm *kvm, u32 vector,
@@ -1732,8 +1857,7 @@ static void kvm_send_ipi_to_many(struct kvm *kvm, u32 vector,
        }
 }
 
-static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, u64 ingpa, u64 outgpa,
-                          bool ex, bool fast)
+static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool ex)
 {
        struct kvm *kvm = vcpu->kvm;
        struct hv_send_ipi_ex send_ipi_ex;
@@ -1748,25 +1872,25 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, u64 ingpa, u64 outgpa,
        bool all_cpus;
 
        if (!ex) {
-               if (!fast) {
-                       if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi,
+               if (!hc->fast) {
+                       if (unlikely(kvm_read_guest(kvm, hc->ingpa, &send_ipi,
                                                    sizeof(send_ipi))))
                                return HV_STATUS_INVALID_HYPERCALL_INPUT;
                        sparse_banks[0] = send_ipi.cpu_mask;
                        vector = send_ipi.vector;
                } else {
                        /* 'reserved' part of hv_send_ipi should be 0 */
-                       if (unlikely(ingpa >> 32 != 0))
+                       if (unlikely(hc->ingpa >> 32 != 0))
                                return HV_STATUS_INVALID_HYPERCALL_INPUT;
-                       sparse_banks[0] = outgpa;
-                       vector = (u32)ingpa;
+                       sparse_banks[0] = hc->outgpa;
+                       vector = (u32)hc->ingpa;
                }
                all_cpus = false;
                valid_bank_mask = BIT_ULL(0);
 
                trace_kvm_hv_send_ipi(vector, sparse_banks[0]);
        } else {
-               if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi_ex,
+               if (unlikely(kvm_read_guest(kvm, hc->ingpa, &send_ipi_ex,
                                            sizeof(send_ipi_ex))))
                        return HV_STATUS_INVALID_HYPERCALL_INPUT;
 
@@ -1786,8 +1910,8 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, u64 ingpa, u64 outgpa,
 
                if (!all_cpus &&
                    kvm_read_guest(kvm,
-                                  ingpa + offsetof(struct hv_send_ipi_ex,
-                                                   vp_set.bank_contents),
+                                  hc->ingpa + offsetof(struct hv_send_ipi_ex,
+                                                       vp_set.bank_contents),
                                   sparse_banks,
                                   sparse_banks_len))
                        return HV_STATUS_INVALID_HYPERCALL_INPUT;
@@ -1809,12 +1933,67 @@ ret_success:
 void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *entry;
+       struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
 
        entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_INTERFACE, 0);
-       if (entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX)
+       if (entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX) {
                vcpu->arch.hyperv_enabled = true;
-       else
+       } else {
                vcpu->arch.hyperv_enabled = false;
+               return;
+       }
+
+       if (!to_hv_vcpu(vcpu) && kvm_hv_vcpu_init(vcpu))
+               return;
+
+       hv_vcpu = to_hv_vcpu(vcpu);
+
+       entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES, 0);
+       if (entry) {
+               hv_vcpu->cpuid_cache.features_eax = entry->eax;
+               hv_vcpu->cpuid_cache.features_ebx = entry->ebx;
+               hv_vcpu->cpuid_cache.features_edx = entry->edx;
+       } else {
+               hv_vcpu->cpuid_cache.features_eax = 0;
+               hv_vcpu->cpuid_cache.features_ebx = 0;
+               hv_vcpu->cpuid_cache.features_edx = 0;
+       }
+
+       entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_ENLIGHTMENT_INFO, 0);
+       if (entry) {
+               hv_vcpu->cpuid_cache.enlightenments_eax = entry->eax;
+               hv_vcpu->cpuid_cache.enlightenments_ebx = entry->ebx;
+       } else {
+               hv_vcpu->cpuid_cache.enlightenments_eax = 0;
+               hv_vcpu->cpuid_cache.enlightenments_ebx = 0;
+       }
+
+       entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES, 0);
+       if (entry)
+               hv_vcpu->cpuid_cache.syndbg_cap_eax = entry->eax;
+       else
+               hv_vcpu->cpuid_cache.syndbg_cap_eax = 0;
+}
+
+int kvm_hv_set_enforce_cpuid(struct kvm_vcpu *vcpu, bool enforce)
+{
+       struct kvm_vcpu_hv *hv_vcpu;
+       int ret = 0;
+
+       if (!to_hv_vcpu(vcpu)) {
+               if (enforce) {
+                       ret = kvm_hv_vcpu_init(vcpu);
+                       if (ret)
+                               return ret;
+               } else {
+                       return 0;
+               }
+       }
+
+       hv_vcpu = to_hv_vcpu(vcpu);
+       hv_vcpu->enforce_cpuid = enforce;
+
+       return ret;
 }
 
 bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu)
@@ -1847,20 +2026,21 @@ static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
        return kvm_hv_hypercall_complete(vcpu, vcpu->run->hyperv.u.hcall.result);
 }
 
-static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param)
+static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc)
 {
        struct kvm_hv *hv = to_kvm_hv(vcpu->kvm);
        struct eventfd_ctx *eventfd;
 
-       if (unlikely(!fast)) {
+       if (unlikely(!hc->fast)) {
                int ret;
-               gpa_t gpa = param;
+               gpa_t gpa = hc->ingpa;
 
-               if ((gpa & (__alignof__(param) - 1)) ||
-                   offset_in_page(gpa) + sizeof(param) > PAGE_SIZE)
+               if ((gpa & (__alignof__(hc->ingpa) - 1)) ||
+                   offset_in_page(gpa) + sizeof(hc->ingpa) > PAGE_SIZE)
                        return HV_STATUS_INVALID_ALIGNMENT;
 
-               ret = kvm_vcpu_read_guest(vcpu, gpa, &param, sizeof(param));
+               ret = kvm_vcpu_read_guest(vcpu, gpa,
+                                         &hc->ingpa, sizeof(hc->ingpa));
                if (ret < 0)
                        return HV_STATUS_INVALID_ALIGNMENT;
        }
@@ -1870,15 +2050,15 @@ static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param)
         * have no use for it, and in all known usecases it is zero, so just
         * report lookup failure if it isn't.
         */
-       if (param & 0xffff00000000ULL)
+       if (hc->ingpa & 0xffff00000000ULL)
                return HV_STATUS_INVALID_PORT_ID;
        /* remaining bits are reserved-zero */
-       if (param & ~KVM_HYPERV_CONN_ID_MASK)
+       if (hc->ingpa & ~KVM_HYPERV_CONN_ID_MASK)
                return HV_STATUS_INVALID_HYPERCALL_INPUT;
 
        /* the eventfd is protected by vcpu->kvm->srcu, but conn_to_evt isn't */
        rcu_read_lock();
-       eventfd = idr_find(&hv->conn_to_evt, param);
+       eventfd = idr_find(&hv->conn_to_evt, hc->ingpa);
        rcu_read_unlock();
        if (!eventfd)
                return HV_STATUS_INVALID_PORT_ID;
@@ -1887,11 +2067,80 @@ static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param)
        return HV_STATUS_SUCCESS;
 }
 
+static bool is_xmm_fast_hypercall(struct kvm_hv_hcall *hc)
+{
+       switch (hc->code) {
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST:
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE:
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX:
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX:
+               return true;
+       }
+
+       return false;
+}
+
+static void kvm_hv_hypercall_read_xmm(struct kvm_hv_hcall *hc)
+{
+       int reg;
+
+       kvm_fpu_get();
+       for (reg = 0; reg < HV_HYPERCALL_MAX_XMM_REGISTERS; reg++)
+               _kvm_read_sse_reg(reg, &hc->xmm[reg]);
+       kvm_fpu_put();
+}
+
+static bool hv_check_hypercall_access(struct kvm_vcpu_hv *hv_vcpu, u16 code)
+{
+       if (!hv_vcpu->enforce_cpuid)
+               return true;
+
+       switch (code) {
+       case HVCALL_NOTIFY_LONG_SPIN_WAIT:
+               return hv_vcpu->cpuid_cache.enlightenments_ebx &&
+                       hv_vcpu->cpuid_cache.enlightenments_ebx != U32_MAX;
+       case HVCALL_POST_MESSAGE:
+               return hv_vcpu->cpuid_cache.features_ebx & HV_POST_MESSAGES;
+       case HVCALL_SIGNAL_EVENT:
+               return hv_vcpu->cpuid_cache.features_ebx & HV_SIGNAL_EVENTS;
+       case HVCALL_POST_DEBUG_DATA:
+       case HVCALL_RETRIEVE_DEBUG_DATA:
+       case HVCALL_RESET_DEBUG_SESSION:
+               /*
+                * Return 'true' when SynDBG is disabled so the resulting code
+                * will be HV_STATUS_INVALID_HYPERCALL_CODE.
+                */
+               return !kvm_hv_is_syndbg_enabled(hv_vcpu->vcpu) ||
+                       hv_vcpu->cpuid_cache.features_ebx & HV_DEBUGGING;
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX:
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX:
+               if (!(hv_vcpu->cpuid_cache.enlightenments_eax &
+                     HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
+                       return false;
+               fallthrough;
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST:
+       case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE:
+               return hv_vcpu->cpuid_cache.enlightenments_eax &
+                       HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED;
+       case HVCALL_SEND_IPI_EX:
+               if (!(hv_vcpu->cpuid_cache.enlightenments_eax &
+                     HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
+                       return false;
+               fallthrough;
+       case HVCALL_SEND_IPI:
+               return hv_vcpu->cpuid_cache.enlightenments_eax &
+                       HV_X64_CLUSTER_IPI_RECOMMENDED;
+       default:
+               break;
+       }
+
+       return true;
+}
+
 int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
 {
-       u64 param, ingpa, outgpa, ret = HV_STATUS_SUCCESS;
-       uint16_t code, rep_idx, rep_cnt;
-       bool fast, rep;
+       struct kvm_hv_hcall hc;
+       u64 ret = HV_STATUS_SUCCESS;
 
        /*
         * hypercall generates UD from non zero cpl and real mode
@@ -1904,104 +2153,113 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
 
 #ifdef CONFIG_X86_64
        if (is_64_bit_mode(vcpu)) {
-               param = kvm_rcx_read(vcpu);
-               ingpa = kvm_rdx_read(vcpu);
-               outgpa = kvm_r8_read(vcpu);
+               hc.param = kvm_rcx_read(vcpu);
+               hc.ingpa = kvm_rdx_read(vcpu);
+               hc.outgpa = kvm_r8_read(vcpu);
        } else
 #endif
        {
-               param = ((u64)kvm_rdx_read(vcpu) << 32) |
-                       (kvm_rax_read(vcpu) & 0xffffffff);
-               ingpa = ((u64)kvm_rbx_read(vcpu) << 32) |
-                       (kvm_rcx_read(vcpu) & 0xffffffff);
-               outgpa = ((u64)kvm_rdi_read(vcpu) << 32) |
-                       (kvm_rsi_read(vcpu) & 0xffffffff);
+               hc.param = ((u64)kvm_rdx_read(vcpu) << 32) |
+                           (kvm_rax_read(vcpu) & 0xffffffff);
+               hc.ingpa = ((u64)kvm_rbx_read(vcpu) << 32) |
+                           (kvm_rcx_read(vcpu) & 0xffffffff);
+               hc.outgpa = ((u64)kvm_rdi_read(vcpu) << 32) |
+                            (kvm_rsi_read(vcpu) & 0xffffffff);
        }
 
-       code = param & 0xffff;
-       fast = !!(param & HV_HYPERCALL_FAST_BIT);
-       rep_cnt = (param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff;
-       rep_idx = (param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff;
-       rep = !!(rep_cnt || rep_idx);
+       hc.code = hc.param & 0xffff;
+       hc.fast = !!(hc.param & HV_HYPERCALL_FAST_BIT);
+       hc.rep_cnt = (hc.param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff;
+       hc.rep_idx = (hc.param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff;
+       hc.rep = !!(hc.rep_cnt || hc.rep_idx);
 
-       trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa);
+       if (hc.fast && is_xmm_fast_hypercall(&hc))
+               kvm_hv_hypercall_read_xmm(&hc);
 
-       switch (code) {
+       trace_kvm_hv_hypercall(hc.code, hc.fast, hc.rep_cnt, hc.rep_idx,
+                              hc.ingpa, hc.outgpa);
+
+       if (unlikely(!hv_check_hypercall_access(to_hv_vcpu(vcpu), hc.code))) {
+               ret = HV_STATUS_ACCESS_DENIED;
+               goto hypercall_complete;
+       }
+
+       switch (hc.code) {
        case HVCALL_NOTIFY_LONG_SPIN_WAIT:
-               if (unlikely(rep)) {
+               if (unlikely(hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
                kvm_vcpu_on_spin(vcpu, true);
                break;
        case HVCALL_SIGNAL_EVENT:
-               if (unlikely(rep)) {
+               if (unlikely(hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hvcall_signal_event(vcpu, fast, ingpa);
+               ret = kvm_hvcall_signal_event(vcpu, &hc);
                if (ret != HV_STATUS_INVALID_PORT_ID)
                        break;
                fallthrough;    /* maybe userspace knows this conn_id */
        case HVCALL_POST_MESSAGE:
                /* don't bother userspace if it has no way to handle it */
-               if (unlikely(rep || !to_hv_synic(vcpu)->active)) {
+               if (unlikely(hc.rep || !to_hv_synic(vcpu)->active)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
                vcpu->run->exit_reason = KVM_EXIT_HYPERV;
                vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL;
-               vcpu->run->hyperv.u.hcall.input = param;
-               vcpu->run->hyperv.u.hcall.params[0] = ingpa;
-               vcpu->run->hyperv.u.hcall.params[1] = outgpa;
+               vcpu->run->hyperv.u.hcall.input = hc.param;
+               vcpu->run->hyperv.u.hcall.params[0] = hc.ingpa;
+               vcpu->run->hyperv.u.hcall.params[1] = hc.outgpa;
                vcpu->arch.complete_userspace_io =
                                kvm_hv_hypercall_complete_userspace;
                return 0;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST:
-               if (unlikely(fast || !rep_cnt || rep_idx)) {
+               if (unlikely(!hc.rep_cnt || hc.rep_idx)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, false);
+               ret = kvm_hv_flush_tlb(vcpu, &hc, false);
                break;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE:
-               if (unlikely(fast || rep)) {
+               if (unlikely(hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, false);
+               ret = kvm_hv_flush_tlb(vcpu, &hc, false);
                break;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX:
-               if (unlikely(fast || !rep_cnt || rep_idx)) {
+               if (unlikely(!hc.rep_cnt || hc.rep_idx)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, true);
+               ret = kvm_hv_flush_tlb(vcpu, &hc, true);
                break;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX:
-               if (unlikely(fast || rep)) {
+               if (unlikely(hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_flush_tlb(vcpu, ingpa, rep_cnt, true);
+               ret = kvm_hv_flush_tlb(vcpu, &hc, true);
                break;
        case HVCALL_SEND_IPI:
-               if (unlikely(rep)) {
+               if (unlikely(hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, false, fast);
+               ret = kvm_hv_send_ipi(vcpu, &hc, false);
                break;
        case HVCALL_SEND_IPI_EX:
-               if (unlikely(fast || rep)) {
+               if (unlikely(hc.fast || hc.rep)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
-               ret = kvm_hv_send_ipi(vcpu, ingpa, outgpa, true, false);
+               ret = kvm_hv_send_ipi(vcpu, &hc, true);
                break;
        case HVCALL_POST_DEBUG_DATA:
        case HVCALL_RETRIEVE_DEBUG_DATA:
-               if (unlikely(fast)) {
+               if (unlikely(hc.fast)) {
                        ret = HV_STATUS_INVALID_PARAMETER;
                        break;
                }
@@ -2020,9 +2278,9 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                }
                vcpu->run->exit_reason = KVM_EXIT_HYPERV;
                vcpu->run->hyperv.type = KVM_EXIT_HYPERV_HCALL;
-               vcpu->run->hyperv.u.hcall.input = param;
-               vcpu->run->hyperv.u.hcall.params[0] = ingpa;
-               vcpu->run->hyperv.u.hcall.params[1] = outgpa;
+               vcpu->run->hyperv.u.hcall.input = hc.param;
+               vcpu->run->hyperv.u.hcall.params[0] = hc.ingpa;
+               vcpu->run->hyperv.u.hcall.params[1] = hc.outgpa;
                vcpu->arch.complete_userspace_io =
                                kvm_hv_hypercall_complete_userspace;
                return 0;
@@ -2032,6 +2290,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                break;
        }
 
+hypercall_complete:
        return kvm_hv_hypercall_complete(vcpu, ret);
 }
 
@@ -2180,6 +2439,7 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
                        ent->ebx |= HV_POST_MESSAGES;
                        ent->ebx |= HV_SIGNAL_EVENTS;
 
+                       ent->edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE;
                        ent->edx |= HV_FEATURE_FREQUENCY_MSRS_AVAILABLE;
                        ent->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
 
index 60547d5..730da85 100644 (file)
@@ -138,6 +138,7 @@ void kvm_hv_invalidate_tsc_page(struct kvm *kvm);
 void kvm_hv_init_vm(struct kvm *kvm);
 void kvm_hv_destroy_vm(struct kvm *kvm);
 void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu);
+int kvm_hv_set_enforce_cpuid(struct kvm_vcpu *vcpu, bool enforce);
 int kvm_vm_ioctl_hv_eventfd(struct kvm *kvm, struct kvm_hyperv_eventfd *args);
 int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
                     struct kvm_cpuid_entry2 __user *entries);
index 3db5c42..90e1ffd 100644 (file)
@@ -55,6 +55,13 @@ static inline void kvm_register_mark_available(struct kvm_vcpu *vcpu,
        __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
 }
 
+static inline void kvm_register_clear_available(struct kvm_vcpu *vcpu,
+                                              enum kvm_reg reg)
+{
+       __clear_bit(reg, (unsigned long *)&vcpu->arch.regs_avail);
+       __clear_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty);
+}
+
 static inline void kvm_register_mark_dirty(struct kvm_vcpu *vcpu,
                                           enum kvm_reg reg)
 {
@@ -118,6 +125,11 @@ static inline u64 kvm_pdptr_read(struct kvm_vcpu *vcpu, int index)
        return vcpu->arch.walk_mmu->pdptrs[index];
 }
 
+static inline void kvm_pdptr_write(struct kvm_vcpu *vcpu, int index, u64 value)
+{
+       vcpu->arch.walk_mmu->pdptrs[index] = value;
+}
+
 static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
 {
        ulong tmask = mask & KVM_POSSIBLE_CR0_GUEST_BITS;
@@ -162,6 +174,7 @@ static inline u64 kvm_read_edx_eax(struct kvm_vcpu *vcpu)
 static inline void enter_guest_mode(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.hflags |= HF_GUEST_MASK;
+       vcpu->stat.guest_mode = 1;
 }
 
 static inline void leave_guest_mode(struct kvm_vcpu *vcpu)
@@ -172,6 +185,8 @@ static inline void leave_guest_mode(struct kvm_vcpu *vcpu)
                vcpu->arch.load_eoi_exitmap_pending = false;
                kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
        }
+
+       vcpu->stat.guest_mode = 0;
 }
 
 static inline bool is_guest_mode(struct kvm_vcpu *vcpu)
index 3e870bf..68b4202 100644 (file)
@@ -13,6 +13,7 @@
 #define _ASM_X86_KVM_X86_EMULATE_H
 
 #include <asm/desc_defs.h>
+#include "fpu.h"
 
 struct x86_emulate_ctxt;
 enum x86_intercept;
@@ -229,15 +230,12 @@ struct x86_emulate_ops {
        void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked);
 
        unsigned (*get_hflags)(struct x86_emulate_ctxt *ctxt);
-       void (*set_hflags)(struct x86_emulate_ctxt *ctxt, unsigned hflags);
-       int (*pre_leave_smm)(struct x86_emulate_ctxt *ctxt,
-                            const char *smstate);
-       void (*post_leave_smm)(struct x86_emulate_ctxt *ctxt);
+       void (*exiting_smm)(struct x86_emulate_ctxt *ctxt);
+       int (*leave_smm)(struct x86_emulate_ctxt *ctxt, const char *smstate);
+       void (*triple_fault)(struct x86_emulate_ctxt *ctxt);
        int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr);
 };
 
-typedef u32 __attribute__((vector_size(16))) sse128_t;
-
 /* Type, address-of, and value of an instruction's operand. */
 struct operand {
        enum { OP_REG, OP_MEM, OP_MEM_STR, OP_IMM, OP_XMM, OP_MM, OP_NONE } type;
diff --git a/arch/x86/kvm/kvm_onhyperv.c b/arch/x86/kvm/kvm_onhyperv.c
new file mode 100644 (file)
index 0000000..c7db2df
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM L1 hypervisor optimizations on Hyper-V.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/mshyperv.h>
+
+#include "hyperv.h"
+#include "kvm_onhyperv.h"
+
+static int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush,
+               void *data)
+{
+       struct kvm_tlb_range *range = data;
+
+       return hyperv_fill_flush_guest_mapping_list(flush, range->start_gfn,
+                       range->pages);
+}
+
+static inline int hv_remote_flush_root_tdp(hpa_t root_tdp,
+                                          struct kvm_tlb_range *range)
+{
+       if (range)
+               return hyperv_flush_guest_mapping_range(root_tdp,
+                               kvm_fill_hv_flush_list_func, (void *)range);
+       else
+               return hyperv_flush_guest_mapping(root_tdp);
+}
+
+int hv_remote_flush_tlb_with_range(struct kvm *kvm,
+               struct kvm_tlb_range *range)
+{
+       struct kvm_arch *kvm_arch = &kvm->arch;
+       struct kvm_vcpu *vcpu;
+       int ret = 0, i, nr_unique_valid_roots;
+       hpa_t root;
+
+       spin_lock(&kvm_arch->hv_root_tdp_lock);
+
+       if (!VALID_PAGE(kvm_arch->hv_root_tdp)) {
+               nr_unique_valid_roots = 0;
+
+               /*
+                * Flush all valid roots, and see if all vCPUs have converged
+                * on a common root, in which case future flushes can skip the
+                * loop and flush the common root.
+                */
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       root = vcpu->arch.hv_root_tdp;
+                       if (!VALID_PAGE(root) || root == kvm_arch->hv_root_tdp)
+                               continue;
+
+                       /*
+                        * Set the tracked root to the first valid root.  Keep
+                        * this root for the entirety of the loop even if more
+                        * roots are encountered as a low effort optimization
+                        * to avoid flushing the same (first) root again.
+                        */
+                       if (++nr_unique_valid_roots == 1)
+                               kvm_arch->hv_root_tdp = root;
+
+                       if (!ret)
+                               ret = hv_remote_flush_root_tdp(root, range);
+
+                       /*
+                        * Stop processing roots if a failure occurred and
+                        * multiple valid roots have already been detected.
+                        */
+                       if (ret && nr_unique_valid_roots > 1)
+                               break;
+               }
+
+               /*
+                * The optimized flush of a single root can't be used if there
+                * are multiple valid roots (obviously).
+                */
+               if (nr_unique_valid_roots > 1)
+                       kvm_arch->hv_root_tdp = INVALID_PAGE;
+       } else {
+               ret = hv_remote_flush_root_tdp(kvm_arch->hv_root_tdp, range);
+       }
+
+       spin_unlock(&kvm_arch->hv_root_tdp_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hv_remote_flush_tlb_with_range);
+
+int hv_remote_flush_tlb(struct kvm *kvm)
+{
+       return hv_remote_flush_tlb_with_range(kvm, NULL);
+}
+EXPORT_SYMBOL_GPL(hv_remote_flush_tlb);
diff --git a/arch/x86/kvm/kvm_onhyperv.h b/arch/x86/kvm/kvm_onhyperv.h
new file mode 100644 (file)
index 0000000..1c67abf
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * KVM L1 hypervisor optimizations on Hyper-V.
+ */
+
+#ifndef __ARCH_X86_KVM_KVM_ONHYPERV_H__
+#define __ARCH_X86_KVM_KVM_ONHYPERV_H__
+
+#if IS_ENABLED(CONFIG_HYPERV)
+int hv_remote_flush_tlb_with_range(struct kvm *kvm,
+               struct kvm_tlb_range *range);
+int hv_remote_flush_tlb(struct kvm *kvm);
+
+static inline void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp)
+{
+       struct kvm_arch *kvm_arch = &vcpu->kvm->arch;
+
+       if (kvm_x86_ops.tlb_remote_flush == hv_remote_flush_tlb) {
+               spin_lock(&kvm_arch->hv_root_tdp_lock);
+               vcpu->arch.hv_root_tdp = root_tdp;
+               if (root_tdp != kvm_arch->hv_root_tdp)
+                       kvm_arch->hv_root_tdp = INVALID_PAGE;
+               spin_unlock(&kvm_arch->hv_root_tdp_lock);
+       }
+}
+#else /* !CONFIG_HYPERV */
+static inline void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp)
+{
+}
+#endif /* !CONFIG_HYPERV */
+
+#endif
index 6d72d8f..ba5a278 100644 (file)
@@ -1410,6 +1410,9 @@ int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
        if (!apic_x2apic_mode(apic))
                valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI);
 
+       if (alignment + len > 4)
+               return 1;
+
        if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset)))
                return 1;
 
@@ -2628,6 +2631,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
        apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
        update_divide_count(apic);
        __start_apic_timer(apic, APIC_TMCCT);
+       kvm_lapic_set_reg(apic, APIC_TMCCT, 0);
        kvm_apic_update_apicv(vcpu);
        apic->highest_isr_cache = -1;
        if (vcpu->arch.apicv_active) {
@@ -2869,7 +2873,7 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len)
        return kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, addr, new_len);
 }
 
-void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
+int kvm_apic_accept_events(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
        u8 sipi_vector;
@@ -2877,7 +2881,7 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
        unsigned long pe;
 
        if (!lapic_in_kernel(vcpu))
-               return;
+               return 0;
 
        /*
         * Read pending events before calling the check_events
@@ -2885,12 +2889,12 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
         */
        pe = smp_load_acquire(&apic->pending_events);
        if (!pe)
-               return;
+               return 0;
 
        if (is_guest_mode(vcpu)) {
                r = kvm_check_nested_events(vcpu);
                if (r < 0)
-                       return;
+                       return r == -EBUSY ? 0 : r;
                /*
                 * If an event has happened and caused a vmexit,
                 * we know INITs are latched and therefore
@@ -2911,7 +2915,7 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
                WARN_ON_ONCE(vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED);
                if (test_bit(KVM_APIC_SIPI, &pe))
                        clear_bit(KVM_APIC_SIPI, &apic->pending_events);
-               return;
+               return 0;
        }
 
        if (test_bit(KVM_APIC_INIT, &pe)) {
@@ -2932,6 +2936,7 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
                        vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
                }
        }
+       return 0;
 }
 
 void kvm_lapic_exit(void)
index 997c45a..d7c25d0 100644 (file)
@@ -76,7 +76,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu);
 int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
 int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
-void kvm_apic_accept_events(struct kvm_vcpu *vcpu);
+int kvm_apic_accept_events(struct kvm_vcpu *vcpu);
 void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event);
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
index 88d0ed5..83e6c69 100644 (file)
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
+#define KVM_MMU_CR4_ROLE_BITS (X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE | \
+                              X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE | \
+                              X86_CR4_LA57)
+
+#define KVM_MMU_CR0_ROLE_BITS (X86_CR0_PG | X86_CR0_WP)
+
 static __always_inline u64 rsvd_bits(int s, int e)
 {
        BUILD_BUG_ON(__builtin_constant_p(e) && __builtin_constant_p(s) && e < s);
@@ -62,12 +68,9 @@ static __always_inline u64 rsvd_bits(int s, int e)
 void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask);
 void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only);
 
-void
-reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
-
-void kvm_init_mmu(struct kvm_vcpu *vcpu, bool reset_roots);
-void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, u32 cr0, u32 cr4, u32 efer,
-                            gpa_t nested_cr3);
+void kvm_init_mmu(struct kvm_vcpu *vcpu);
+void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, unsigned long cr0,
+                            unsigned long cr4, u64 efer, gpa_t nested_cr3);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
                             bool accessed_dirty, gpa_t new_eptp);
 bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu);
@@ -162,11 +165,6 @@ static inline bool is_writable_pte(unsigned long pte)
        return pte & PT_WRITABLE_MASK;
 }
 
-static inline bool is_write_protection(struct kvm_vcpu *vcpu)
-{
-       return kvm_read_cr0_bits(vcpu, X86_CR0_WP);
-}
-
 /*
  * Check if a given access (described through the I/D, W/R and U/S bits of a
  * page fault error code pfec) causes a permission fault with the given PTE
@@ -232,4 +230,14 @@ int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu);
 int kvm_mmu_post_init_vm(struct kvm *kvm);
 void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
 
+static inline bool kvm_memslots_have_rmaps(struct kvm *kvm)
+{
+       /*
+        * Read memslot_have_rmaps before rmap pointers.  Hence, threads reading
+        * memslots_have_rmaps in any lock context are guaranteed to see the
+        * pointers.  Pairs with smp_store_release in alloc_all_memslots_rmaps.
+        */
+       return smp_load_acquire(&kvm->arch.memslots_have_rmaps);
+}
+
 #endif
index 0144c40..845d114 100644 (file)
@@ -55,7 +55,7 @@
 
 extern bool itlb_multihit_kvm_mitigation;
 
-static int __read_mostly nx_huge_pages = -1;
+int __read_mostly nx_huge_pages = -1;
 #ifdef CONFIG_PREEMPT_RT
 /* Recovery can cause latency spikes, disable it for PREEMPT_RT.  */
 static uint __read_mostly nx_huge_pages_recovery_ratio = 0;
@@ -176,9 +176,80 @@ static void mmu_spte_set(u64 *sptep, u64 spte);
 static union kvm_mmu_page_role
 kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu);
 
+struct kvm_mmu_role_regs {
+       const unsigned long cr0;
+       const unsigned long cr4;
+       const u64 efer;
+};
+
 #define CREATE_TRACE_POINTS
 #include "mmutrace.h"
 
+/*
+ * Yes, lot's of underscores.  They're a hint that you probably shouldn't be
+ * reading from the role_regs.  Once the mmu_role is constructed, it becomes
+ * the single source of truth for the MMU's state.
+ */
+#define BUILD_MMU_ROLE_REGS_ACCESSOR(reg, name, flag)                  \
+static inline bool ____is_##reg##_##name(struct kvm_mmu_role_regs *regs)\
+{                                                                      \
+       return !!(regs->reg & flag);                                    \
+}
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr0, pg, X86_CR0_PG);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr0, wp, X86_CR0_WP);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, pse, X86_CR4_PSE);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, pae, X86_CR4_PAE);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, smep, X86_CR4_SMEP);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, smap, X86_CR4_SMAP);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, pke, X86_CR4_PKE);
+BUILD_MMU_ROLE_REGS_ACCESSOR(cr4, la57, X86_CR4_LA57);
+BUILD_MMU_ROLE_REGS_ACCESSOR(efer, nx, EFER_NX);
+BUILD_MMU_ROLE_REGS_ACCESSOR(efer, lma, EFER_LMA);
+
+/*
+ * The MMU itself (with a valid role) is the single source of truth for the
+ * MMU.  Do not use the regs used to build the MMU/role, nor the vCPU.  The
+ * regs don't account for dependencies, e.g. clearing CR4 bits if CR0.PG=1,
+ * and the vCPU may be incorrect/irrelevant.
+ */
+#define BUILD_MMU_ROLE_ACCESSOR(base_or_ext, reg, name)                \
+static inline bool is_##reg##_##name(struct kvm_mmu *mmu)      \
+{                                                              \
+       return !!(mmu->mmu_role. base_or_ext . reg##_##name);   \
+}
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr0, pg);
+BUILD_MMU_ROLE_ACCESSOR(base, cr0, wp);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, pse);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, pae);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, smep);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, smap);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, pke);
+BUILD_MMU_ROLE_ACCESSOR(ext,  cr4, la57);
+BUILD_MMU_ROLE_ACCESSOR(base, efer, nx);
+
+static struct kvm_mmu_role_regs vcpu_to_role_regs(struct kvm_vcpu *vcpu)
+{
+       struct kvm_mmu_role_regs regs = {
+               .cr0 = kvm_read_cr0_bits(vcpu, KVM_MMU_CR0_ROLE_BITS),
+               .cr4 = kvm_read_cr4_bits(vcpu, KVM_MMU_CR4_ROLE_BITS),
+               .efer = vcpu->arch.efer,
+       };
+
+       return regs;
+}
+
+static int role_regs_to_root_level(struct kvm_mmu_role_regs *regs)
+{
+       if (!____is_cr0_pg(regs))
+               return 0;
+       else if (____is_efer_lma(regs))
+               return ____is_cr4_la57(regs) ? PT64_ROOT_5LEVEL :
+                                              PT64_ROOT_4LEVEL;
+       else if (____is_cr4_pae(regs))
+               return PT32E_ROOT_LEVEL;
+       else
+               return PT32_ROOT_LEVEL;
+}
 
 static inline bool kvm_available_flush_tlb_with_range(void)
 {
@@ -208,11 +279,6 @@ void kvm_flush_remote_tlbs_with_address(struct kvm *kvm,
        kvm_flush_remote_tlbs_with_range(kvm, &range);
 }
 
-bool is_nx_huge_page_enabled(void)
-{
-       return READ_ONCE(nx_huge_pages);
-}
-
 static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
                           unsigned int access)
 {
@@ -269,11 +335,6 @@ static int is_cpuid_PSE36(void)
        return 1;
 }
 
-static int is_nx(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.efer & EFER_NX;
-}
-
 static gfn_t pse36_gfn_delta(u32 gpte)
 {
        int shift = 32 - PT32_DIR_PSE36_SHIFT - PAGE_SHIFT;
@@ -1177,8 +1238,7 @@ static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
  * @gfn_offset: start of the BITS_PER_LONG pages we care about
  * @mask: indicates which pages we should protect
  *
- * Used when we do not need to care about huge page mappings: e.g. during dirty
- * logging we do not have any such mappings.
+ * Used when we do not need to care about huge page mappings.
  */
 static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
                                     struct kvm_memory_slot *slot,
@@ -1189,6 +1249,10 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
        if (is_tdp_mmu_enabled(kvm))
                kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot,
                                slot->base_gfn + gfn_offset, mask, true);
+
+       if (!kvm_memslots_have_rmaps(kvm))
+               return;
+
        while (mask) {
                rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
                                          PG_LEVEL_4K, slot);
@@ -1218,6 +1282,10 @@ static void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
        if (is_tdp_mmu_enabled(kvm))
                kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot,
                                slot->base_gfn + gfn_offset, mask, false);
+
+       if (!kvm_memslots_have_rmaps(kvm))
+               return;
+
        while (mask) {
                rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
                                          PG_LEVEL_4K, slot);
@@ -1235,13 +1303,36 @@ static void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
  * It calls kvm_mmu_write_protect_pt_masked to write protect selected pages to
  * enable dirty logging for them.
  *
- * Used when we do not need to care about huge page mappings: e.g. during dirty
- * logging we do not have any such mappings.
+ * We need to care about huge page mappings: e.g. during dirty logging we may
+ * have such mappings.
  */
 void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
                                struct kvm_memory_slot *slot,
                                gfn_t gfn_offset, unsigned long mask)
 {
+       /*
+        * Huge pages are NOT write protected when we start dirty logging in
+        * initially-all-set mode; must write protect them here so that they
+        * are split to 4K on the first write.
+        *
+        * The gfn_offset is guaranteed to be aligned to 64, but the base_gfn
+        * of memslot has no such restriction, so the range can cross two large
+        * pages.
+        */
+       if (kvm_dirty_log_manual_protect_and_init_set(kvm)) {
+               gfn_t start = slot->base_gfn + gfn_offset + __ffs(mask);
+               gfn_t end = slot->base_gfn + gfn_offset + __fls(mask);
+
+               kvm_mmu_slot_gfn_write_protect(kvm, slot, start, PG_LEVEL_2M);
+
+               /* Cross two large pages? */
+               if (ALIGN(start << PAGE_SHIFT, PMD_SIZE) !=
+                   ALIGN(end << PAGE_SHIFT, PMD_SIZE))
+                       kvm_mmu_slot_gfn_write_protect(kvm, slot, end,
+                                                      PG_LEVEL_2M);
+       }
+
+       /* Now handle 4K PTEs.  */
        if (kvm_x86_ops.cpu_dirty_log_size)
                kvm_mmu_clear_dirty_pt_masked(kvm, slot, gfn_offset, mask);
        else
@@ -1254,20 +1345,23 @@ int kvm_cpu_dirty_log_size(void)
 }
 
 bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
-                                   struct kvm_memory_slot *slot, u64 gfn)
+                                   struct kvm_memory_slot *slot, u64 gfn,
+                                   int min_level)
 {
        struct kvm_rmap_head *rmap_head;
        int i;
        bool write_protected = false;
 
-       for (i = PG_LEVEL_4K; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) {
-               rmap_head = __gfn_to_rmap(gfn, i, slot);
-               write_protected |= __rmap_write_protect(kvm, rmap_head, true);
+       if (kvm_memslots_have_rmaps(kvm)) {
+               for (i = min_level; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) {
+                       rmap_head = __gfn_to_rmap(gfn, i, slot);
+                       write_protected |= __rmap_write_protect(kvm, rmap_head, true);
+               }
        }
 
        if (is_tdp_mmu_enabled(kvm))
                write_protected |=
-                       kvm_tdp_mmu_write_protect_gfn(kvm, slot, gfn);
+                       kvm_tdp_mmu_write_protect_gfn(kvm, slot, gfn, min_level);
 
        return write_protected;
 }
@@ -1277,7 +1371,7 @@ static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
        struct kvm_memory_slot *slot;
 
        slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
-       return kvm_mmu_slot_gfn_write_protect(vcpu->kvm, slot, gfn);
+       return kvm_mmu_slot_gfn_write_protect(vcpu->kvm, slot, gfn, PG_LEVEL_4K);
 }
 
 static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
@@ -1433,9 +1527,10 @@ static __always_inline bool kvm_handle_gfn_range(struct kvm *kvm,
 
 bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
 {
-       bool flush;
+       bool flush = false;
 
-       flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmapp);
+       if (kvm_memslots_have_rmaps(kvm))
+               flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmapp);
 
        if (is_tdp_mmu_enabled(kvm))
                flush |= kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush);
@@ -1445,9 +1540,10 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
 
 bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 {
-       bool flush;
+       bool flush = false;
 
-       flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmapp);
+       if (kvm_memslots_have_rmaps(kvm))
+               flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmapp);
 
        if (is_tdp_mmu_enabled(kvm))
                flush |= kvm_tdp_mmu_set_spte_gfn(kvm, range);
@@ -1500,9 +1596,10 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 
 bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 {
-       bool young;
+       bool young = false;
 
-       young = kvm_handle_gfn_range(kvm, range, kvm_age_rmapp);
+       if (kvm_memslots_have_rmaps(kvm))
+               young = kvm_handle_gfn_range(kvm, range, kvm_age_rmapp);
 
        if (is_tdp_mmu_enabled(kvm))
                young |= kvm_tdp_mmu_age_gfn_range(kvm, range);
@@ -1512,9 +1609,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 
 bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 {
-       bool young;
+       bool young = false;
 
-       young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmapp);
+       if (kvm_memslots_have_rmaps(kvm))
+               young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmapp);
 
        if (is_tdp_mmu_enabled(kvm))
                young |= kvm_tdp_mmu_test_age_gfn(kvm, range);
@@ -1748,17 +1846,10 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
          &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)])     \
                if ((_sp)->gfn != (_gfn) || (_sp)->role.direct) {} else
 
-static inline bool is_ept_sp(struct kvm_mmu_page *sp)
-{
-       return sp->role.cr0_wp && sp->role.smap_andnot_wp;
-}
-
-/* @sp->gfn should be write-protected at the call site */
-static bool __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
-                           struct list_head *invalid_list)
+static bool kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+                        struct list_head *invalid_list)
 {
-       if ((!is_ept_sp(sp) && sp->role.gpte_is_8_bytes != !!is_pae(vcpu)) ||
-           vcpu->arch.mmu->sync_page(vcpu, sp) == 0) {
+       if (vcpu->arch.mmu->sync_page(vcpu, sp) == 0) {
                kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list);
                return false;
        }
@@ -1804,31 +1895,6 @@ static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
               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)
-{
-       kvm_unlink_unsync_page(vcpu->kvm, sp);
-       return __kvm_sync_page(vcpu, sp, invalid_list);
-}
-
-/* @gfn should be write-protected at the call site */
-static bool kvm_sync_pages(struct kvm_vcpu *vcpu, gfn_t gfn,
-                          struct list_head *invalid_list)
-{
-       struct kvm_mmu_page *s;
-       bool ret = false;
-
-       for_each_gfn_indirect_valid_sp(vcpu->kvm, s, gfn) {
-               if (!s->unsync)
-                       continue;
-
-               WARN_ON(s->role.level != PG_LEVEL_4K);
-               ret |= kvm_sync_page(vcpu, s, invalid_list);
-       }
-
-       return ret;
-}
-
 struct mmu_page_path {
        struct kvm_mmu_page *parent[PT64_ROOT_MAX_LEVEL];
        unsigned int idx[PT64_ROOT_MAX_LEVEL];
@@ -1923,6 +1989,7 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
                }
 
                for_each_sp(pages, sp, parents, i) {
+                       kvm_unlink_unsync_page(vcpu->kvm, sp);
                        flush |= kvm_sync_page(vcpu, sp, &invalid_list);
                        mmu_pages_clear_parents(&parents);
                }
@@ -1958,8 +2025,6 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        struct hlist_head *sp_list;
        unsigned quadrant;
        struct kvm_mmu_page *sp;
-       bool need_sync = false;
-       bool flush = false;
        int collisions = 0;
        LIST_HEAD(invalid_list);
 
@@ -1982,20 +2047,39 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                        continue;
                }
 
-               if (!need_sync && sp->unsync)
-                       need_sync = true;
-
-               if (sp->role.word != role.word)
+               if (sp->role.word != role.word) {
+                       /*
+                        * If the guest is creating an upper-level page, zap
+                        * unsync pages for the same gfn.  While it's possible
+                        * the guest is using recursive page tables, in all
+                        * likelihood the guest has stopped using the unsync
+                        * page and is installing a completely unrelated page.
+                        * Unsync pages must not be left as is, because the new
+                        * upper-level page will be write-protected.
+                        */
+                       if (level > PG_LEVEL_4K && sp->unsync)
+                               kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
+                                                        &invalid_list);
                        continue;
+               }
 
                if (direct_mmu)
                        goto trace_get_page;
 
                if (sp->unsync) {
-                       /* The page is good, but __kvm_sync_page might still end
-                        * up zapping it.  If so, break in order to rebuild it.
+                       /*
+                        * The page is good, but is stale.  kvm_sync_page does
+                        * get the latest guest state, but (unlike mmu_unsync_children)
+                        * it doesn't write-protect the page or mark it synchronized!
+                        * This way the validity of the mapping is ensured, but the
+                        * overhead of write protection is not incurred until the
+                        * guest invalidates the TLB mapping.  This allows multiple
+                        * SPs for a single gfn to be unsync.
+                        *
+                        * If the sync fails, the page is zapped.  If so, break
+                        * in order to rebuild it.
                         */
-                       if (!__kvm_sync_page(vcpu, sp, &invalid_list))
+                       if (!kvm_sync_page(vcpu, sp, &invalid_list))
                                break;
 
                        WARN_ON(!list_empty(&invalid_list));
@@ -2020,22 +2104,14 @@ trace_get_page:
        sp->role = role;
        hlist_add_head(&sp->hash_link, sp_list);
        if (!direct) {
-               /*
-                * we should do write protection before syncing pages
-                * otherwise the content of the synced shadow page may
-                * be inconsistent with guest page table.
-                */
                account_shadowed(vcpu->kvm, sp);
                if (level == PG_LEVEL_4K && rmap_write_protect(vcpu, gfn))
                        kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1);
-
-               if (level > PG_LEVEL_4K && need_sync)
-                       flush |= kvm_sync_pages(vcpu, gfn, &invalid_list);
        }
        trace_kvm_mmu_get_page(sp, true);
-
-       kvm_mmu_flush_or_zap(vcpu, &invalid_list, false, flush);
 out:
+       kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
+
        if (collisions > vcpu->kvm->stat.max_mmu_page_hash_collisions)
                vcpu->kvm->stat.max_mmu_page_hash_collisions = collisions;
        return sp;
@@ -2374,7 +2450,7 @@ static int make_mmu_pages_available(struct kvm_vcpu *vcpu)
         * page is available, while the caller may end up allocating as many as
         * four pages, e.g. for PAE roots or for 5-level paging.  Temporarily
         * exceeding the (arbitrary by default) limit will not harm the host,
-        * being too agressive may unnecessarily kill the guest, and getting an
+        * being too aggressive may unnecessarily kill the guest, and getting an
         * exact count is far more trouble than it's worth, especially in the
         * page fault paths.
         */
@@ -2448,17 +2524,33 @@ static void kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
        kvm_mmu_mark_parents_unsync(sp);
 }
 
-bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
-                           bool can_unsync)
+/*
+ * Attempt to unsync any shadow pages that can be reached by the specified gfn,
+ * KVM is creating a writable mapping for said gfn.  Returns 0 if all pages
+ * were marked unsync (or if there is no shadow page), -EPERM if the SPTE must
+ * be write-protected.
+ */
+int mmu_try_to_unsync_pages(struct kvm_vcpu *vcpu, gfn_t gfn, bool can_unsync)
 {
        struct kvm_mmu_page *sp;
 
+       /*
+        * Force write-protection if the page is being tracked.  Note, the page
+        * track machinery is used to write-protect upper-level shadow pages,
+        * i.e. this guards the role.level == 4K assertion below!
+        */
        if (kvm_page_track_is_active(vcpu, gfn, KVM_PAGE_TRACK_WRITE))
-               return true;
+               return -EPERM;
 
+       /*
+        * The page is not write-tracked, mark existing shadow pages unsync
+        * unless KVM is synchronizing an unsync SP (can_unsync = false).  In
+        * that case, KVM must complete emulation of the guest TLB flush before
+        * allowing shadow pages to become unsync (writable by the guest).
+        */
        for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn) {
                if (!can_unsync)
-                       return true;
+                       return -EPERM;
 
                if (sp->unsync)
                        continue;
@@ -2489,8 +2581,8 @@ bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
         *                      2.2 Guest issues TLB flush.
         *                          That causes a VM Exit.
         *
-        *                      2.3 kvm_mmu_sync_pages() reads sp->unsync.
-        *                          Since it is false, so it just returns.
+        *                      2.3 Walking of unsync pages sees sp->unsync is
+        *                          false and skips the page.
         *
         *                      2.4 Guest accesses GVA X.
         *                          Since the mapping in the SP was not updated,
@@ -2506,7 +2598,7 @@ bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
         */
        smp_wmb();
 
-       return false;
+       return 0;
 }
 
 static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
@@ -2827,9 +2919,6 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
        gfn_t gfn = gpa >> PAGE_SHIFT;
        gfn_t base_gfn = gfn;
 
-       if (WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa)))
-               return RET_PF_RETRY;
-
        level = kvm_mmu_hugepage_adjust(vcpu, gfn, max_level, &pfn,
                                        huge_page_disallowed, &req_level);
 
@@ -3180,6 +3269,33 @@ void kvm_mmu_free_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_free_roots);
 
+void kvm_mmu_free_guest_mode_roots(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu)
+{
+       unsigned long roots_to_free = 0;
+       hpa_t root_hpa;
+       int i;
+
+       /*
+        * This should not be called while L2 is active, L2 can't invalidate
+        * _only_ its own roots, e.g. INVVPID unconditionally exits.
+        */
+       WARN_ON_ONCE(mmu->mmu_role.base.guest_mode);
+
+       for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) {
+               root_hpa = mmu->prev_roots[i].hpa;
+               if (!VALID_PAGE(root_hpa))
+                       continue;
+
+               if (!to_shadow_page(root_hpa) ||
+                       to_shadow_page(root_hpa)->role.guest_mode)
+                       roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i);
+       }
+
+       kvm_mmu_free_roots(vcpu, mmu, roots_to_free);
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_free_guest_mode_roots);
+
+
 static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn)
 {
        int ret = 0;
@@ -3280,6 +3396,10 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
                }
        }
 
+       r = alloc_all_memslots_rmaps(vcpu->kvm);
+       if (r)
+               return r;
+
        write_lock(&vcpu->kvm->mmu_lock);
        r = make_mmu_pages_available(vcpu);
        if (r < 0)
@@ -3423,8 +3543,8 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
                 * flush strictly after those changes are made. We only need to
                 * ensure that the other CPU sets these flags before any actual
                 * changes to the page tables are made. The comments in
-                * mmu_need_write_protect() describe what could go wrong if this
-                * requirement isn't satisfied.
+                * mmu_try_to_unsync_pages() describe what could go wrong if
+                * this requirement isn't satisfied.
                 */
                if (!smp_load_acquire(&sp->unsync) &&
                    !smp_load_acquire(&sp->unsync_children))
@@ -3474,19 +3594,6 @@ static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gpa_t vaddr,
        return vcpu->arch.nested_mmu.translate_gpa(vcpu, vaddr, access, exception);
 }
 
-static bool
-__is_rsvd_bits_set(struct rsvd_bits_validate *rsvd_check, u64 pte, int level)
-{
-       int bit7 = (pte >> 7) & 1;
-
-       return pte & rsvd_check->rsvd_bits_mask[bit7][level-1];
-}
-
-static bool __is_bad_mt_xwr(struct rsvd_bits_validate *rsvd_check, u64 pte)
-{
-       return rsvd_check->bad_mt_xwr & BIT_ULL(pte & 0x3f);
-}
-
 static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct)
 {
        /*
@@ -3540,12 +3647,7 @@ static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
        int root, leaf, level;
        bool reserved = false;
 
-       if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) {
-               *sptep = 0ull;
-               return reserved;
-       }
-
-       if (is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa))
+       if (is_tdp_mmu(vcpu->arch.mmu))
                leaf = kvm_tdp_mmu_get_walk(vcpu, addr, sptes, &root);
        else
                leaf = get_walk(vcpu, addr, sptes, &root);
@@ -3569,13 +3671,7 @@ static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
        rsvd_check = &vcpu->arch.mmu->shadow_zero_check;
 
        for (level = root; level >= leaf; level--)
-               /*
-                * Use a bitwise-OR instead of a logical-OR to aggregate the
-                * reserved bit and EPT's invalid memtype/XWR checks to avoid
-                * adding a Jcc in the loop.
-                */
-               reserved |= __is_bad_mt_xwr(rsvd_check, sptes[level]) |
-                           __is_rsvd_bits_set(rsvd_check, sptes[level], level);
+               reserved |= is_rsvd_spte(rsvd_check, sptes[level], level);
 
        if (reserved) {
                pr_err("%s: reserved bits set on MMU-present spte, addr 0x%llx, hierarchy:\n",
@@ -3583,7 +3679,7 @@ static bool get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep)
                for (level = root; level >= leaf; level--)
                        pr_err("------ spte = 0x%llx level = %d, rsvd bits = 0x%llx",
                               sptes[level], level,
-                              rsvd_check->rsvd_bits_mask[(sptes[level] >> 7) & 1][level-1]);
+                              get_rsvd_bits(rsvd_check, sptes[level], level));
        }
 
        return reserved;
@@ -3717,6 +3813,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
 static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
                             bool prefault, int max_level, bool is_tdp)
 {
+       bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
        bool write = error_code & PFERR_WRITE_MASK;
        bool map_writable;
 
@@ -3729,7 +3826,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
        if (page_fault_handle_page_track(vcpu, error_code, gfn))
                return RET_PF_EMULATE;
 
-       if (!is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa)) {
+       if (!is_tdp_mmu_fault) {
                r = fast_page_fault(vcpu, gpa, error_code);
                if (r != RET_PF_INVALID)
                        return r;
@@ -3751,7 +3848,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
 
        r = RET_PF_RETRY;
 
-       if (is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa))
+       if (is_tdp_mmu_fault)
                read_lock(&vcpu->kvm->mmu_lock);
        else
                write_lock(&vcpu->kvm->mmu_lock);
@@ -3762,7 +3859,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
        if (r)
                goto out_unlock;
 
-       if (is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa))
+       if (is_tdp_mmu_fault)
                r = kvm_tdp_mmu_map(vcpu, gpa, error_code, map_writable, max_level,
                                    pfn, prefault);
        else
@@ -3770,7 +3867,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
                                 prefault, is_tdp);
 
 out_unlock:
-       if (is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa))
+       if (is_tdp_mmu_fault)
                read_unlock(&vcpu->kvm->mmu_lock);
        else
                write_unlock(&vcpu->kvm->mmu_lock);
@@ -3840,17 +3937,13 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
                                 max_level, true);
 }
 
-static void nonpaging_init_context(struct kvm_vcpu *vcpu,
-                                  struct kvm_mmu *context)
+static void nonpaging_init_context(struct kvm_mmu *context)
 {
        context->page_fault = nonpaging_page_fault;
        context->gva_to_gpa = nonpaging_gva_to_gpa;
        context->sync_page = nonpaging_sync_page;
        context->invlpg = NULL;
-       context->root_level = 0;
-       context->shadow_root_level = PT32E_ROOT_LEVEL;
        context->direct_map = true;
-       context->nx = false;
 }
 
 static inline bool is_root_usable(struct kvm_mmu_root_info *root, gpa_t pgd,
@@ -3913,8 +4006,7 @@ static bool fast_pgd_switch(struct kvm_vcpu *vcpu, gpa_t new_pgd,
 }
 
 static void __kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd,
-                             union kvm_mmu_page_role new_role,
-                             bool skip_tlb_flush, bool skip_mmu_sync)
+                             union kvm_mmu_page_role new_role)
 {
        if (!fast_pgd_switch(vcpu, new_pgd, new_role)) {
                kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, KVM_MMU_ROOT_CURRENT);
@@ -3929,10 +4021,10 @@ static void __kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd,
         */
        kvm_make_request(KVM_REQ_LOAD_MMU_PGD, vcpu);
 
-       if (!skip_mmu_sync || force_flush_and_sync_on_reuse)
+       if (force_flush_and_sync_on_reuse) {
                kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
-       if (!skip_tlb_flush || force_flush_and_sync_on_reuse)
                kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+       }
 
        /*
         * The last MMIO access's GVA and GPA are cached in the VCPU. When
@@ -3951,11 +4043,9 @@ static void __kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd,
                                to_shadow_page(vcpu->arch.mmu->root_hpa));
 }
 
-void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd, bool skip_tlb_flush,
-                    bool skip_mmu_sync)
+void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd)
 {
-       __kvm_mmu_new_pgd(vcpu, new_pgd, kvm_mmu_calc_root_page_role(vcpu),
-                         skip_tlb_flush, skip_mmu_sync);
+       __kvm_mmu_new_pgd(vcpu, new_pgd, kvm_mmu_calc_root_page_role(vcpu));
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_new_pgd);
 
@@ -3981,26 +4071,6 @@ static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
        return false;
 }
 
-static inline bool is_last_gpte(struct kvm_mmu *mmu,
-                               unsigned level, unsigned gpte)
-{
-       /*
-        * The RHS has bit 7 set iff level < mmu->last_nonleaf_level.
-        * If it is clear, there are no large pages at this level, so clear
-        * PT_PAGE_SIZE_MASK in gpte if that is the case.
-        */
-       gpte &= level - mmu->last_nonleaf_level;
-
-       /*
-        * PG_LEVEL_4K always terminates.  The RHS has bit 7 set
-        * iff level <= PG_LEVEL_4K, which for our purpose means
-        * level == PG_LEVEL_4K; set PT_PAGE_SIZE_MASK in gpte then.
-        */
-       gpte |= level - PG_LEVEL_4K - 1;
-
-       return gpte & PT_PAGE_SIZE_MASK;
-}
-
 #define PTTYPE_EPT 18 /* arbitrary */
 #define PTTYPE PTTYPE_EPT
 #include "paging_tmpl.h"
@@ -4015,8 +4085,7 @@ static inline bool is_last_gpte(struct kvm_mmu *mmu,
 #undef PTTYPE
 
 static void
-__reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
-                       struct rsvd_bits_validate *rsvd_check,
+__reset_rsvds_bits_mask(struct rsvd_bits_validate *rsvd_check,
                        u64 pa_bits_rsvd, int level, bool nx, bool gbpages,
                        bool pse, bool amd)
 {
@@ -4105,14 +4174,29 @@ __reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
        }
 }
 
+static bool guest_can_use_gbpages(struct kvm_vcpu *vcpu)
+{
+       /*
+        * If TDP is enabled, let the guest use GBPAGES if they're supported in
+        * hardware.  The hardware page walker doesn't let KVM disable GBPAGES,
+        * i.e. won't treat them as reserved, and KVM doesn't redo the GVA->GPA
+        * walk for performance and complexity reasons.  Not to mention KVM
+        * _can't_ solve the problem because GVA->GPA walks aren't visible to
+        * KVM once a TDP translation is installed.  Mimic hardware behavior so
+        * that KVM's is at least consistent, i.e. doesn't randomly inject #PF.
+        */
+       return tdp_enabled ? boot_cpu_has(X86_FEATURE_GBPAGES) :
+                            guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES);
+}
+
 static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
                                  struct kvm_mmu *context)
 {
-       __reset_rsvds_bits_mask(vcpu, &context->guest_rsvd_check,
+       __reset_rsvds_bits_mask(&context->guest_rsvd_check,
                                vcpu->arch.reserved_gpa_bits,
-                               context->root_level, context->nx,
-                               guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES),
-                               is_pse(vcpu),
+                               context->root_level, is_efer_nx(context),
+                               guest_can_use_gbpages(vcpu),
+                               is_cr4_pse(context),
                                guest_cpuid_is_amd_or_hygon(vcpu));
 }
 
@@ -4165,24 +4249,32 @@ static inline u64 reserved_hpa_bits(void)
  * table in guest or amd nested guest, its mmu features completely
  * follow the features in guest.
  */
-void
-reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
+static void reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
+                                       struct kvm_mmu *context)
 {
-       bool uses_nx = context->nx ||
-               context->mmu_role.base.smep_andnot_wp;
+       /*
+        * KVM uses NX when TDP is disabled to handle a variety of scenarios,
+        * notably for huge SPTEs if iTLB multi-hit mitigation is enabled and
+        * to generate correct permissions for CR0.WP=0/CR4.SMEP=1/EFER.NX=0.
+        * The iTLB multi-hit workaround can be toggled at any time, so assume
+        * NX can be used by any non-nested shadow MMU to avoid having to reset
+        * MMU contexts.  Note, KVM forces EFER.NX=1 when TDP is disabled.
+        */
+       bool uses_nx = is_efer_nx(context) || !tdp_enabled;
+
+       /* @amd adds a check on bit of SPTEs, which KVM shouldn't use anyways. */
+       bool is_amd = true;
+       /* KVM doesn't use 2-level page tables for the shadow MMU. */
+       bool is_pse = false;
        struct rsvd_bits_validate *shadow_zero_check;
        int i;
 
-       /*
-        * Passing "true" to the last argument is okay; it adds a check
-        * on bit 8 of the SPTEs which KVM doesn't use anyway.
-        */
+       WARN_ON_ONCE(context->shadow_root_level < PT32E_ROOT_LEVEL);
+
        shadow_zero_check = &context->shadow_zero_check;
-       __reset_rsvds_bits_mask(vcpu, shadow_zero_check,
-                               reserved_hpa_bits(),
+       __reset_rsvds_bits_mask(shadow_zero_check, reserved_hpa_bits(),
                                context->shadow_root_level, uses_nx,
-                               guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES),
-                               is_pse(vcpu), true);
+                               guest_can_use_gbpages(vcpu), is_pse, is_amd);
 
        if (!shadow_me_mask)
                return;
@@ -4193,7 +4285,6 @@ reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
        }
 
 }
-EXPORT_SYMBOL_GPL(reset_shadow_zero_bits_mask);
 
 static inline bool boot_cpu_is_amd(void)
 {
@@ -4215,11 +4306,10 @@ reset_tdp_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
        shadow_zero_check = &context->shadow_zero_check;
 
        if (boot_cpu_is_amd())
-               __reset_rsvds_bits_mask(vcpu, shadow_zero_check,
-                                       reserved_hpa_bits(),
+               __reset_rsvds_bits_mask(shadow_zero_check, reserved_hpa_bits(),
                                        context->shadow_root_level, false,
                                        boot_cpu_has(X86_FEATURE_GBPAGES),
-                                       true, true);
+                                       false, true);
        else
                __reset_rsvds_bits_mask_ept(shadow_zero_check,
                                            reserved_hpa_bits(), false);
@@ -4255,8 +4345,7 @@ reset_ept_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
         (7 & (access) ? 128 : 0))
 
 
-static void update_permission_bitmask(struct kvm_vcpu *vcpu,
-                                     struct kvm_mmu *mmu, bool ept)
+static void update_permission_bitmask(struct kvm_mmu *mmu, bool ept)
 {
        unsigned byte;
 
@@ -4264,9 +4353,10 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
        const u8 w = BYTE_MASK(ACC_WRITE_MASK);
        const u8 u = BYTE_MASK(ACC_USER_MASK);
 
-       bool cr4_smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP) != 0;
-       bool cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP) != 0;
-       bool cr0_wp = is_write_protection(vcpu);
+       bool cr4_smep = is_cr4_smep(mmu);
+       bool cr4_smap = is_cr4_smap(mmu);
+       bool cr0_wp = is_cr0_wp(mmu);
+       bool efer_nx = is_efer_nx(mmu);
 
        for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
                unsigned pfec = byte << 1;
@@ -4292,7 +4382,7 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
                        u8 kf = (pfec & PFERR_USER_MASK) ? 0 : u;
 
                        /* Not really needed: !nx will cause pte.nx to fault */
-                       if (!mmu->nx)
+                       if (!efer_nx)
                                ff = 0;
 
                        /* Allow supervisor writes if !cr0.wp */
@@ -4351,24 +4441,17 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
 * away both AD and WD.  For all reads or if the last condition holds, WD
 * only will be masked away.
 */
-static void update_pkru_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
-                               bool ept)
+static void update_pkru_bitmask(struct kvm_mmu *mmu)
 {
        unsigned bit;
        bool wp;
 
-       if (ept) {
-               mmu->pkru_mask = 0;
-               return;
-       }
-
-       /* PKEY is enabled only if CR4.PKE and EFER.LMA are both set. */
-       if (!kvm_read_cr4_bits(vcpu, X86_CR4_PKE) || !is_long_mode(vcpu)) {
+       if (!is_cr4_pke(mmu)) {
                mmu->pkru_mask = 0;
                return;
        }
 
-       wp = is_write_protection(vcpu);
+       wp = is_cr0_wp(mmu);
 
        for (bit = 0; bit < ARRAY_SIZE(mmu->permissions); ++bit) {
                unsigned pfec, pkey_bits;
@@ -4402,81 +4485,51 @@ static void update_pkru_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
        }
 }
 
-static void update_last_nonleaf_level(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu)
+static void reset_guest_paging_metadata(struct kvm_vcpu *vcpu,
+                                       struct kvm_mmu *mmu)
 {
-       unsigned root_level = mmu->root_level;
+       if (!is_cr0_pg(mmu))
+               return;
 
-       mmu->last_nonleaf_level = root_level;
-       if (root_level == PT32_ROOT_LEVEL && is_pse(vcpu))
-               mmu->last_nonleaf_level++;
+       reset_rsvds_bits_mask(vcpu, mmu);
+       update_permission_bitmask(mmu, false);
+       update_pkru_bitmask(mmu);
 }
 
-static void paging64_init_context_common(struct kvm_vcpu *vcpu,
-                                        struct kvm_mmu *context,
-                                        int level)
+static void paging64_init_context(struct kvm_mmu *context)
 {
-       context->nx = is_nx(vcpu);
-       context->root_level = level;
-
-       reset_rsvds_bits_mask(vcpu, context);
-       update_permission_bitmask(vcpu, context, false);
-       update_pkru_bitmask(vcpu, context, false);
-       update_last_nonleaf_level(vcpu, context);
-
-       MMU_WARN_ON(!is_pae(vcpu));
        context->page_fault = paging64_page_fault;
        context->gva_to_gpa = paging64_gva_to_gpa;
        context->sync_page = paging64_sync_page;
        context->invlpg = paging64_invlpg;
-       context->shadow_root_level = level;
        context->direct_map = false;
 }
 
-static void paging64_init_context(struct kvm_vcpu *vcpu,
-                                 struct kvm_mmu *context)
+static void paging32_init_context(struct kvm_mmu *context)
 {
-       int root_level = is_la57_mode(vcpu) ?
-                        PT64_ROOT_5LEVEL : PT64_ROOT_4LEVEL;
-
-       paging64_init_context_common(vcpu, context, root_level);
-}
-
-static void paging32_init_context(struct kvm_vcpu *vcpu,
-                                 struct kvm_mmu *context)
-{
-       context->nx = false;
-       context->root_level = PT32_ROOT_LEVEL;
-
-       reset_rsvds_bits_mask(vcpu, context);
-       update_permission_bitmask(vcpu, context, false);
-       update_pkru_bitmask(vcpu, context, false);
-       update_last_nonleaf_level(vcpu, context);
-
        context->page_fault = paging32_page_fault;
        context->gva_to_gpa = paging32_gva_to_gpa;
        context->sync_page = paging32_sync_page;
        context->invlpg = paging32_invlpg;
-       context->shadow_root_level = PT32E_ROOT_LEVEL;
        context->direct_map = false;
 }
 
-static void paging32E_init_context(struct kvm_vcpu *vcpu,
-                                  struct kvm_mmu *context)
-{
-       paging64_init_context_common(vcpu, context, PT32E_ROOT_LEVEL);
-}
-
-static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu)
+static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu,
+                                                        struct kvm_mmu_role_regs *regs)
 {
        union kvm_mmu_extended_role ext = {0};
 
-       ext.cr0_pg = !!is_paging(vcpu);
-       ext.cr4_pae = !!is_pae(vcpu);
-       ext.cr4_smep = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
-       ext.cr4_smap = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
-       ext.cr4_pse = !!is_pse(vcpu);
-       ext.cr4_pke = !!kvm_read_cr4_bits(vcpu, X86_CR4_PKE);
-       ext.maxphyaddr = cpuid_maxphyaddr(vcpu);
+       if (____is_cr0_pg(regs)) {
+               ext.cr0_pg = 1;
+               ext.cr4_pae = ____is_cr4_pae(regs);
+               ext.cr4_smep = ____is_cr4_smep(regs);
+               ext.cr4_smap = ____is_cr4_smap(regs);
+               ext.cr4_pse = ____is_cr4_pse(regs);
+
+               /* PKEY and LA57 are active iff long mode is active. */
+               ext.cr4_pke = ____is_efer_lma(regs) && ____is_cr4_pke(regs);
+               ext.cr4_la57 = ____is_efer_lma(regs) && ____is_cr4_la57(regs);
+       }
 
        ext.valid = 1;
 
@@ -4484,20 +4537,23 @@ static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu)
 }
 
 static union kvm_mmu_role kvm_calc_mmu_role_common(struct kvm_vcpu *vcpu,
+                                                  struct kvm_mmu_role_regs *regs,
                                                   bool base_only)
 {
        union kvm_mmu_role role = {0};
 
        role.base.access = ACC_ALL;
-       role.base.nxe = !!is_nx(vcpu);
-       role.base.cr0_wp = is_write_protection(vcpu);
+       if (____is_cr0_pg(regs)) {
+               role.base.efer_nx = ____is_efer_nx(regs);
+               role.base.cr0_wp = ____is_cr0_wp(regs);
+       }
        role.base.smm = is_smm(vcpu);
        role.base.guest_mode = is_guest_mode(vcpu);
 
        if (base_only)
                return role;
 
-       role.ext = kvm_calc_mmu_role_ext(vcpu);
+       role.ext = kvm_calc_mmu_role_ext(vcpu, regs);
 
        return role;
 }
@@ -4512,9 +4568,10 @@ static inline int kvm_mmu_get_tdp_level(struct kvm_vcpu *vcpu)
 }
 
 static union kvm_mmu_role
-kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only)
+kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu,
+                               struct kvm_mmu_role_regs *regs, bool base_only)
 {
-       union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, base_only);
+       union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, regs, base_only);
 
        role.base.ad_disabled = (shadow_accessed_mask == 0);
        role.base.level = kvm_mmu_get_tdp_level(vcpu);
@@ -4527,8 +4584,9 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only)
 static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
 {
        struct kvm_mmu *context = &vcpu->arch.root_mmu;
+       struct kvm_mmu_role_regs regs = vcpu_to_role_regs(vcpu);
        union kvm_mmu_role new_role =
-               kvm_calc_tdp_mmu_root_page_role(vcpu, false);
+               kvm_calc_tdp_mmu_root_page_role(vcpu, &regs, false);
 
        if (new_role.as_u64 == context->mmu_role.as_u64)
                return;
@@ -4542,60 +4600,44 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
        context->get_guest_pgd = get_cr3;
        context->get_pdptr = kvm_pdptr_read;
        context->inject_page_fault = kvm_inject_page_fault;
+       context->root_level = role_regs_to_root_level(&regs);
 
-       if (!is_paging(vcpu)) {
-               context->nx = false;
+       if (!is_cr0_pg(context))
                context->gva_to_gpa = nonpaging_gva_to_gpa;
-               context->root_level = 0;
-       } else if (is_long_mode(vcpu)) {
-               context->nx = is_nx(vcpu);
-               context->root_level = is_la57_mode(vcpu) ?
-                               PT64_ROOT_5LEVEL : PT64_ROOT_4LEVEL;
-               reset_rsvds_bits_mask(vcpu, context);
-               context->gva_to_gpa = paging64_gva_to_gpa;
-       } else if (is_pae(vcpu)) {
-               context->nx = is_nx(vcpu);
-               context->root_level = PT32E_ROOT_LEVEL;
-               reset_rsvds_bits_mask(vcpu, context);
+       else if (is_cr4_pae(context))
                context->gva_to_gpa = paging64_gva_to_gpa;
-       } else {
-               context->nx = false;
-               context->root_level = PT32_ROOT_LEVEL;
-               reset_rsvds_bits_mask(vcpu, context);
+       else
                context->gva_to_gpa = paging32_gva_to_gpa;
-       }
 
-       update_permission_bitmask(vcpu, context, false);
-       update_pkru_bitmask(vcpu, context, false);
-       update_last_nonleaf_level(vcpu, context);
+       reset_guest_paging_metadata(vcpu, context);
        reset_tdp_shadow_zero_bits_mask(vcpu, context);
 }
 
 static union kvm_mmu_role
-kvm_calc_shadow_root_page_role_common(struct kvm_vcpu *vcpu, bool base_only)
+kvm_calc_shadow_root_page_role_common(struct kvm_vcpu *vcpu,
+                                     struct kvm_mmu_role_regs *regs, bool base_only)
 {
-       union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, base_only);
+       union kvm_mmu_role role = kvm_calc_mmu_role_common(vcpu, regs, base_only);
 
-       role.base.smep_andnot_wp = role.ext.cr4_smep &&
-               !is_write_protection(vcpu);
-       role.base.smap_andnot_wp = role.ext.cr4_smap &&
-               !is_write_protection(vcpu);
-       role.base.gpte_is_8_bytes = !!is_pae(vcpu);
+       role.base.smep_andnot_wp = role.ext.cr4_smep && !____is_cr0_wp(regs);
+       role.base.smap_andnot_wp = role.ext.cr4_smap && !____is_cr0_wp(regs);
+       role.base.gpte_is_8_bytes = ____is_cr0_pg(regs) && ____is_cr4_pae(regs);
 
        return role;
 }
 
 static union kvm_mmu_role
-kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only)
+kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu,
+                                  struct kvm_mmu_role_regs *regs, bool base_only)
 {
        union kvm_mmu_role role =
-               kvm_calc_shadow_root_page_role_common(vcpu, base_only);
+               kvm_calc_shadow_root_page_role_common(vcpu, regs, base_only);
 
-       role.base.direct = !is_paging(vcpu);
+       role.base.direct = !____is_cr0_pg(regs);
 
-       if (!is_long_mode(vcpu))
+       if (!____is_efer_lma(regs))
                role.base.level = PT32E_ROOT_LEVEL;
-       else if (is_la57_mode(vcpu))
+       else if (____is_cr4_la57(regs))
                role.base.level = PT64_ROOT_5LEVEL;
        else
                role.base.level = PT64_ROOT_4LEVEL;
@@ -4604,37 +4646,44 @@ kvm_calc_shadow_mmu_root_page_role(struct kvm_vcpu *vcpu, bool base_only)
 }
 
 static void shadow_mmu_init_context(struct kvm_vcpu *vcpu, struct kvm_mmu *context,
-                                   u32 cr0, u32 cr4, u32 efer,
+                                   struct kvm_mmu_role_regs *regs,
                                    union kvm_mmu_role new_role)
 {
-       if (!(cr0 & X86_CR0_PG))
-               nonpaging_init_context(vcpu, context);
-       else if (efer & EFER_LMA)
-               paging64_init_context(vcpu, context);
-       else if (cr4 & X86_CR4_PAE)
-               paging32E_init_context(vcpu, context);
-       else
-               paging32_init_context(vcpu, context);
+       if (new_role.as_u64 == context->mmu_role.as_u64)
+               return;
 
        context->mmu_role.as_u64 = new_role.as_u64;
+
+       if (!is_cr0_pg(context))
+               nonpaging_init_context(context);
+       else if (is_cr4_pae(context))
+               paging64_init_context(context);
+       else
+               paging32_init_context(context);
+       context->root_level = role_regs_to_root_level(regs);
+
+       reset_guest_paging_metadata(vcpu, context);
+       context->shadow_root_level = new_role.base.level;
+
        reset_shadow_zero_bits_mask(vcpu, context);
 }
 
-static void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, u32 cr0, u32 cr4, u32 efer)
+static void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu,
+                               struct kvm_mmu_role_regs *regs)
 {
        struct kvm_mmu *context = &vcpu->arch.root_mmu;
        union kvm_mmu_role new_role =
-               kvm_calc_shadow_mmu_root_page_role(vcpu, false);
+               kvm_calc_shadow_mmu_root_page_role(vcpu, regs, false);
 
-       if (new_role.as_u64 != context->mmu_role.as_u64)
-               shadow_mmu_init_context(vcpu, context, cr0, cr4, efer, new_role);
+       shadow_mmu_init_context(vcpu, context, regs, new_role);
 }
 
 static union kvm_mmu_role
-kvm_calc_shadow_npt_root_page_role(struct kvm_vcpu *vcpu)
+kvm_calc_shadow_npt_root_page_role(struct kvm_vcpu *vcpu,
+                                  struct kvm_mmu_role_regs *regs)
 {
        union kvm_mmu_role role =
-               kvm_calc_shadow_root_page_role_common(vcpu, false);
+               kvm_calc_shadow_root_page_role_common(vcpu, regs, false);
 
        role.base.direct = false;
        role.base.level = kvm_mmu_get_tdp_level(vcpu);
@@ -4642,23 +4691,22 @@ kvm_calc_shadow_npt_root_page_role(struct kvm_vcpu *vcpu)
        return role;
 }
 
-void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, u32 cr0, u32 cr4, u32 efer,
-                            gpa_t nested_cr3)
+void kvm_init_shadow_npt_mmu(struct kvm_vcpu *vcpu, unsigned long cr0,
+                            unsigned long cr4, u64 efer, gpa_t nested_cr3)
 {
        struct kvm_mmu *context = &vcpu->arch.guest_mmu;
-       union kvm_mmu_role new_role = kvm_calc_shadow_npt_root_page_role(vcpu);
+       struct kvm_mmu_role_regs regs = {
+               .cr0 = cr0,
+               .cr4 = cr4,
+               .efer = efer,
+       };
+       union kvm_mmu_role new_role;
 
-       __kvm_mmu_new_pgd(vcpu, nested_cr3, new_role.base, false, false);
+       new_role = kvm_calc_shadow_npt_root_page_role(vcpu, &regs);
 
-       if (new_role.as_u64 != context->mmu_role.as_u64) {
-               shadow_mmu_init_context(vcpu, context, cr0, cr4, efer, new_role);
+       __kvm_mmu_new_pgd(vcpu, nested_cr3, new_role.base);
 
-               /*
-                * Override the level set by the common init helper, nested TDP
-                * always uses the host's TDP configuration.
-                */
-               context->shadow_root_level = new_role.base.level;
-       }
+       shadow_mmu_init_context(vcpu, context, &regs, new_role);
 }
 EXPORT_SYMBOL_GPL(kvm_init_shadow_npt_mmu);
 
@@ -4678,15 +4726,10 @@ kvm_calc_shadow_ept_root_page_role(struct kvm_vcpu *vcpu, bool accessed_dirty,
        role.base.guest_mode = true;
        role.base.access = ACC_ALL;
 
-       /*
-        * WP=1 and NOT_WP=1 is an impossible combination, use WP and the
-        * SMAP variation to denote shadow EPT entries.
-        */
-       role.base.cr0_wp = true;
-       role.base.smap_andnot_wp = true;
-
-       role.ext = kvm_calc_mmu_role_ext(vcpu);
+       /* EPT, and thus nested EPT, does not consume CR0, CR4, nor EFER. */
+       role.ext.word = 0;
        role.ext.execonly = execonly;
+       role.ext.valid = 1;
 
        return role;
 }
@@ -4700,14 +4743,15 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
                kvm_calc_shadow_ept_root_page_role(vcpu, accessed_dirty,
                                                   execonly, level);
 
-       __kvm_mmu_new_pgd(vcpu, new_eptp, new_role.base, true, true);
+       __kvm_mmu_new_pgd(vcpu, new_eptp, new_role.base);
 
        if (new_role.as_u64 == context->mmu_role.as_u64)
                return;
 
+       context->mmu_role.as_u64 = new_role.as_u64;
+
        context->shadow_root_level = level;
 
-       context->nx = true;
        context->ept_ad = accessed_dirty;
        context->page_fault = ept_page_fault;
        context->gva_to_gpa = ept_gva_to_gpa;
@@ -4715,11 +4759,9 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly,
        context->invlpg = ept_invlpg;
        context->root_level = level;
        context->direct_map = false;
-       context->mmu_role.as_u64 = new_role.as_u64;
 
-       update_permission_bitmask(vcpu, context, true);
-       update_pkru_bitmask(vcpu, context, true);
-       update_last_nonleaf_level(vcpu, context);
+       update_permission_bitmask(context, true);
+       update_pkru_bitmask(context);
        reset_rsvds_bits_mask_ept(vcpu, context, execonly);
        reset_ept_shadow_zero_bits_mask(vcpu, context, execonly);
 }
@@ -4728,20 +4770,36 @@ EXPORT_SYMBOL_GPL(kvm_init_shadow_ept_mmu);
 static void init_kvm_softmmu(struct kvm_vcpu *vcpu)
 {
        struct kvm_mmu *context = &vcpu->arch.root_mmu;
+       struct kvm_mmu_role_regs regs = vcpu_to_role_regs(vcpu);
 
-       kvm_init_shadow_mmu(vcpu,
-                           kvm_read_cr0_bits(vcpu, X86_CR0_PG),
-                           kvm_read_cr4_bits(vcpu, X86_CR4_PAE),
-                           vcpu->arch.efer);
+       kvm_init_shadow_mmu(vcpu, &regs);
 
        context->get_guest_pgd     = get_cr3;
        context->get_pdptr         = kvm_pdptr_read;
        context->inject_page_fault = kvm_inject_page_fault;
 }
 
+static union kvm_mmu_role
+kvm_calc_nested_mmu_role(struct kvm_vcpu *vcpu, struct kvm_mmu_role_regs *regs)
+{
+       union kvm_mmu_role role;
+
+       role = kvm_calc_shadow_root_page_role_common(vcpu, regs, false);
+
+       /*
+        * Nested MMUs are used only for walking L2's gva->gpa, they never have
+        * shadow pages of their own and so "direct" has no meaning.   Set it
+        * to "true" to try to detect bogus usage of the nested MMU.
+        */
+       role.base.direct = true;
+       role.base.level = role_regs_to_root_level(regs);
+       return role;
+}
+
 static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
 {
-       union kvm_mmu_role new_role = kvm_calc_mmu_role_common(vcpu, false);
+       struct kvm_mmu_role_regs regs = vcpu_to_role_regs(vcpu);
+       union kvm_mmu_role new_role = kvm_calc_nested_mmu_role(vcpu, &regs);
        struct kvm_mmu *g_context = &vcpu->arch.nested_mmu;
 
        if (new_role.as_u64 == g_context->mmu_role.as_u64)
@@ -4751,6 +4809,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
        g_context->get_guest_pgd     = get_cr3;
        g_context->get_pdptr         = kvm_pdptr_read;
        g_context->inject_page_fault = kvm_inject_page_fault;
+       g_context->root_level        = new_role.base.level;
 
        /*
         * L2 page tables are never shadowed, so there is no need to sync
@@ -4766,44 +4825,20 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
         * nested page tables as the second level of translation. Basically
         * the gva_to_gpa functions between mmu and nested_mmu are swapped.
         */
-       if (!is_paging(vcpu)) {
-               g_context->nx = false;
-               g_context->root_level = 0;
+       if (!is_paging(vcpu))
                g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested;
-       } else if (is_long_mode(vcpu)) {
-               g_context->nx = is_nx(vcpu);
-               g_context->root_level = is_la57_mode(vcpu) ?
-                                       PT64_ROOT_5LEVEL : PT64_ROOT_4LEVEL;
-               reset_rsvds_bits_mask(vcpu, g_context);
+       else if (is_long_mode(vcpu))
                g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
-       } else if (is_pae(vcpu)) {
-               g_context->nx = is_nx(vcpu);
-               g_context->root_level = PT32E_ROOT_LEVEL;
-               reset_rsvds_bits_mask(vcpu, g_context);
+       else if (is_pae(vcpu))
                g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
-       } else {
-               g_context->nx = false;
-               g_context->root_level = PT32_ROOT_LEVEL;
-               reset_rsvds_bits_mask(vcpu, g_context);
+       else
                g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
-       }
 
-       update_permission_bitmask(vcpu, g_context, false);
-       update_pkru_bitmask(vcpu, g_context, false);
-       update_last_nonleaf_level(vcpu, g_context);
+       reset_guest_paging_metadata(vcpu, g_context);
 }
 
-void kvm_init_mmu(struct kvm_vcpu *vcpu, bool reset_roots)
+void kvm_init_mmu(struct kvm_vcpu *vcpu)
 {
-       if (reset_roots) {
-               uint i;
-
-               vcpu->arch.mmu->root_hpa = INVALID_PAGE;
-
-               for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
-                       vcpu->arch.mmu->prev_roots[i] = KVM_MMU_ROOT_INFO_INVALID;
-       }
-
        if (mmu_is_nested(vcpu))
                init_kvm_nested_mmu(vcpu);
        else if (tdp_enabled)
@@ -4816,20 +4851,53 @@ EXPORT_SYMBOL_GPL(kvm_init_mmu);
 static union kvm_mmu_page_role
 kvm_mmu_calc_root_page_role(struct kvm_vcpu *vcpu)
 {
+       struct kvm_mmu_role_regs regs = vcpu_to_role_regs(vcpu);
        union kvm_mmu_role role;
 
        if (tdp_enabled)
-               role = kvm_calc_tdp_mmu_root_page_role(vcpu, true);
+               role = kvm_calc_tdp_mmu_root_page_role(vcpu, &regs, true);
        else
-               role = kvm_calc_shadow_mmu_root_page_role(vcpu, true);
+               role = kvm_calc_shadow_mmu_root_page_role(vcpu, &regs, true);
 
        return role.base;
 }
 
+void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu)
+{
+       /*
+        * Invalidate all MMU roles to force them to reinitialize as CPUID
+        * information is factored into reserved bit calculations.
+        */
+       vcpu->arch.root_mmu.mmu_role.ext.valid = 0;
+       vcpu->arch.guest_mmu.mmu_role.ext.valid = 0;
+       vcpu->arch.nested_mmu.mmu_role.ext.valid = 0;
+       kvm_mmu_reset_context(vcpu);
+
+       /*
+        * KVM does not correctly handle changing guest CPUID after KVM_RUN, as
+        * MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
+        * tracked in kvm_mmu_page_role.  As a result, KVM may miss guest page
+        * faults due to reusing SPs/SPTEs.  Alert userspace, but otherwise
+        * sweep the problem under the rug.
+        *
+        * KVM's horrific CPUID ABI makes the problem all but impossible to
+        * solve, as correctly handling multiple vCPU models (with respect to
+        * paging and physical address properties) in a single VM would require
+        * tracking all relevant CPUID information in kvm_mmu_page_role.  That
+        * is very undesirable as it would double the memory requirements for
+        * gfn_track (see struct kvm_mmu_page_role comments), and in practice
+        * no sane VMM mucks with the core vCPU model on the fly.
+        */
+       if (vcpu->arch.last_vmentry_cpu != -1) {
+               pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} after KVM_RUN may cause guest instability\n");
+               pr_warn_ratelimited("KVM: KVM_SET_CPUID{,2} will fail after KVM_RUN starting with Linux 5.16\n");
+       }
+}
+
 void kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
 {
        kvm_mmu_unload(vcpu);
-       kvm_init_mmu(vcpu, true);
+       kvm_init_mmu(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_reset_context);
 
@@ -5467,7 +5535,13 @@ void kvm_mmu_init_vm(struct kvm *kvm)
 {
        struct kvm_page_track_notifier_node *node = &kvm->arch.mmu_sp_tracker;
 
-       kvm_mmu_init_tdp_mmu(kvm);
+       if (!kvm_mmu_init_tdp_mmu(kvm))
+               /*
+                * No smp_load/store wrappers needed here as we are in
+                * VM init and there cannot be any memslots / other threads
+                * accessing this struct kvm yet.
+                */
+               kvm->arch.memslots_have_rmaps = true;
 
        node->track_write = kvm_mmu_pte_write;
        node->track_flush_slot = kvm_mmu_invalidate_zap_pages_in_memslot;
@@ -5490,29 +5564,29 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
        int i;
        bool flush = false;
 
-       write_lock(&kvm->mmu_lock);
-       for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
-               slots = __kvm_memslots(kvm, i);
-               kvm_for_each_memslot(memslot, slots) {
-                       gfn_t start, end;
-
-                       start = max(gfn_start, memslot->base_gfn);
-                       end = min(gfn_end, memslot->base_gfn + memslot->npages);
-                       if (start >= end)
-                               continue;
+       if (kvm_memslots_have_rmaps(kvm)) {
+               write_lock(&kvm->mmu_lock);
+               for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+                       slots = __kvm_memslots(kvm, i);
+                       kvm_for_each_memslot(memslot, slots) {
+                               gfn_t start, end;
+
+                               start = max(gfn_start, memslot->base_gfn);
+                               end = min(gfn_end, memslot->base_gfn + memslot->npages);
+                               if (start >= end)
+                                       continue;
 
-                       flush = slot_handle_level_range(kvm, memslot, kvm_zap_rmapp,
-                                                       PG_LEVEL_4K,
-                                                       KVM_MAX_HUGEPAGE_LEVEL,
-                                                       start, end - 1, true, flush);
+                               flush = slot_handle_level_range(kvm, memslot,
+                                               kvm_zap_rmapp, PG_LEVEL_4K,
+                                               KVM_MAX_HUGEPAGE_LEVEL, start,
+                                               end - 1, true, flush);
+                       }
                }
+               if (flush)
+                       kvm_flush_remote_tlbs_with_address(kvm, gfn_start, gfn_end);
+               write_unlock(&kvm->mmu_lock);
        }
 
-       if (flush)
-               kvm_flush_remote_tlbs_with_address(kvm, gfn_start, gfn_end);
-
-       write_unlock(&kvm->mmu_lock);
-
        if (is_tdp_mmu_enabled(kvm)) {
                flush = false;
 
@@ -5539,12 +5613,15 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
                                      struct kvm_memory_slot *memslot,
                                      int start_level)
 {
-       bool flush;
+       bool flush = false;
 
-       write_lock(&kvm->mmu_lock);
-       flush = slot_handle_level(kvm, memslot, slot_rmap_write_protect,
-                               start_level, KVM_MAX_HUGEPAGE_LEVEL, false);
-       write_unlock(&kvm->mmu_lock);
+       if (kvm_memslots_have_rmaps(kvm)) {
+               write_lock(&kvm->mmu_lock);
+               flush = slot_handle_level(kvm, memslot, slot_rmap_write_protect,
+                                         start_level, KVM_MAX_HUGEPAGE_LEVEL,
+                                         false);
+               write_unlock(&kvm->mmu_lock);
+       }
 
        if (is_tdp_mmu_enabled(kvm)) {
                read_lock(&kvm->mmu_lock);
@@ -5612,18 +5689,17 @@ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm,
 {
        /* FIXME: const-ify all uses of struct kvm_memory_slot.  */
        struct kvm_memory_slot *slot = (struct kvm_memory_slot *)memslot;
-       bool flush;
-
-       write_lock(&kvm->mmu_lock);
-       flush = slot_handle_leaf(kvm, slot, kvm_mmu_zap_collapsible_spte, true);
+       bool flush = false;
 
-       if (flush)
-               kvm_arch_flush_remote_tlbs_memslot(kvm, slot);
-       write_unlock(&kvm->mmu_lock);
+       if (kvm_memslots_have_rmaps(kvm)) {
+               write_lock(&kvm->mmu_lock);
+               flush = slot_handle_leaf(kvm, slot, kvm_mmu_zap_collapsible_spte, true);
+               if (flush)
+                       kvm_arch_flush_remote_tlbs_memslot(kvm, slot);
+               write_unlock(&kvm->mmu_lock);
+       }
 
        if (is_tdp_mmu_enabled(kvm)) {
-               flush = false;
-
                read_lock(&kvm->mmu_lock);
                flush = kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot, flush);
                if (flush)
@@ -5650,11 +5726,14 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
 void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
                                   struct kvm_memory_slot *memslot)
 {
-       bool flush;
+       bool flush = false;
 
-       write_lock(&kvm->mmu_lock);
-       flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty, false);
-       write_unlock(&kvm->mmu_lock);
+       if (kvm_memslots_have_rmaps(kvm)) {
+               write_lock(&kvm->mmu_lock);
+               flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty,
+                                        false);
+               write_unlock(&kvm->mmu_lock);
+       }
 
        if (is_tdp_mmu_enabled(kvm)) {
                read_lock(&kvm->mmu_lock);
@@ -5957,6 +6036,7 @@ static int set_nx_huge_pages_recovery_ratio(const char *val, const struct kernel
 
 static void kvm_recover_nx_lpages(struct kvm *kvm)
 {
+       unsigned long nx_lpage_splits = kvm->stat.nx_lpage_splits;
        int rcu_idx;
        struct kvm_mmu_page *sp;
        unsigned int ratio;
@@ -5968,7 +6048,7 @@ static void kvm_recover_nx_lpages(struct kvm *kvm)
        write_lock(&kvm->mmu_lock);
 
        ratio = READ_ONCE(nx_huge_pages_recovery_ratio);
-       to_zap = ratio ? DIV_ROUND_UP(kvm->stat.nx_lpage_splits, ratio) : 0;
+       to_zap = ratio ? DIV_ROUND_UP(nx_lpage_splits, ratio) : 0;
        for ( ; to_zap; --to_zap) {
                if (list_empty(&kvm->arch.lpage_disallowed_mmu_pages))
                        break;
index d64ccb4..3556729 100644 (file)
@@ -116,14 +116,19 @@ static inline bool kvm_vcpu_ad_need_write_protect(struct kvm_vcpu *vcpu)
               kvm_x86_ops.cpu_dirty_log_size;
 }
 
-bool is_nx_huge_page_enabled(void);
-bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
-                           bool can_unsync);
+extern int nx_huge_pages;
+static inline bool is_nx_huge_page_enabled(void)
+{
+       return READ_ONCE(nx_huge_pages);
+}
+
+int mmu_try_to_unsync_pages(struct kvm_vcpu *vcpu, gfn_t gfn, bool can_unsync);
 
 void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
 void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
 bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
-                                   struct kvm_memory_slot *slot, u64 gfn);
+                                   struct kvm_memory_slot *slot, u64 gfn,
+                                   int min_level);
 void kvm_flush_remote_tlbs_with_address(struct kvm *kvm,
                                        u64 start_gfn, u64 pages);
 
@@ -158,8 +163,6 @@ int kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, gfn_t gfn,
 void disallowed_hugepage_adjust(u64 spte, gfn_t gfn, int cur_level,
                                kvm_pfn_t *pfnp, int *goal_levelp);
 
-bool is_nx_huge_page_enabled(void);
-
 void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc);
 
 void account_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp);
index e798489..efbad33 100644 (file)
@@ -40,7 +40,7 @@
                         role.direct ? " direct" : "",                  \
                         access_str[role.access],                       \
                         role.invalid ? " invalid" : "",                \
-                        role.nxe ? "" : "!",                           \
+                        role.efer_nx ? "" : "!",                       \
                         role.ad_disabled ? "!" : "",                   \
                         __entry->root_count,                           \
                         __entry->unsync ? "unsync" : "sync", 0);       \
index 34bb0ec..91a9f7e 100644 (file)
@@ -100,7 +100,7 @@ void kvm_slot_page_track_add_page(struct kvm *kvm,
        kvm_mmu_gfn_disallow_lpage(slot, gfn);
 
        if (mode == KVM_PAGE_TRACK_WRITE)
-               if (kvm_mmu_slot_gfn_write_protect(kvm, slot, gfn))
+               if (kvm_mmu_slot_gfn_write_protect(kvm, slot, gfn, PG_LEVEL_4K))
                        kvm_flush_remote_tlbs(kvm);
 }
 EXPORT_SYMBOL_GPL(kvm_slot_page_track_add_page);
index 823a591..490a028 100644 (file)
@@ -305,6 +305,35 @@ static inline unsigned FNAME(gpte_pkeys)(struct kvm_vcpu *vcpu, u64 gpte)
        return pkeys;
 }
 
+static inline bool FNAME(is_last_gpte)(struct kvm_mmu *mmu,
+                                      unsigned int level, unsigned int gpte)
+{
+       /*
+        * For EPT and PAE paging (both variants), bit 7 is either reserved at
+        * all level or indicates a huge page (ignoring CR3/EPTP).  In either
+        * case, bit 7 being set terminates the walk.
+        */
+#if PTTYPE == 32
+       /*
+        * 32-bit paging requires special handling because bit 7 is ignored if
+        * CR4.PSE=0, not reserved.  Clear bit 7 in the gpte if the level is
+        * greater than the last level for which bit 7 is the PAGE_SIZE bit.
+        *
+        * The RHS has bit 7 set iff level < (2 + PSE).  If it is clear, bit 7
+        * is not reserved and does not indicate a large page at this level,
+        * so clear PT_PAGE_SIZE_MASK in gpte if that is the case.
+        */
+       gpte &= level - (PT32_ROOT_LEVEL + mmu->mmu_role.ext.cr4_pse);
+#endif
+       /*
+        * PG_LEVEL_4K always terminates.  The RHS has bit 7 set
+        * iff level <= PG_LEVEL_4K, which for our purpose means
+        * level == PG_LEVEL_4K; set PT_PAGE_SIZE_MASK in gpte then.
+        */
+       gpte |= level - PG_LEVEL_4K - 1;
+
+       return gpte & PT_PAGE_SIZE_MASK;
+}
 /*
  * Fetch a guest pte for a guest virtual address, or for an L2's GPA.
  */
@@ -421,7 +450,7 @@ retry_walk:
 
                /* Convert to ACC_*_MASK flags for struct guest_walker.  */
                walker->pt_access[walker->level - 1] = FNAME(gpte_access)(pt_access ^ walk_nx_mask);
-       } while (!is_last_gpte(mmu, walker->level, pte));
+       } while (!FNAME(is_last_gpte)(mmu, walker->level, pte));
 
        pte_pkey = FNAME(gpte_pkeys)(vcpu, pte);
        accessed_dirty = have_ad ? pte_access & PT_GUEST_ACCESSED_MASK : 0;
@@ -471,8 +500,7 @@ retry_walk:
 
 error:
        errcode |= write_fault | user_fault;
-       if (fetch_fault && (mmu->nx ||
-                           kvm_read_cr4_bits(vcpu, X86_CR4_SMEP)))
+       if (fetch_fault && (is_efer_nx(mmu) || is_cr4_smep(mmu)))
                errcode |= PFERR_FETCH_MASK;
 
        walker->fault.vector = PF_VECTOR;
@@ -767,7 +795,7 @@ FNAME(is_self_change_mapping)(struct kvm_vcpu *vcpu,
        bool self_changed = false;
 
        if (!(walker->pte_access & ACC_WRITE_MASK ||
-             (!is_write_protection(vcpu) && !user_fault)))
+           (!is_cr0_wp(vcpu->arch.mmu) && !user_fault)))
                return false;
 
        for (level = walker->level; level <= walker->max_level; level++) {
@@ -865,8 +893,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gpa_t addr, u32 error_code,
         * we will cache the incorrect access into mmio spte.
         */
        if (write_fault && !(walker.pte_access & ACC_WRITE_MASK) &&
-            !is_write_protection(vcpu) && !user_fault &&
-             !is_noslot_pfn(pfn)) {
+           !is_cr0_wp(vcpu->arch.mmu) && !user_fault && !is_noslot_pfn(pfn)) {
                walker.pte_access |= ACC_WRITE_MASK;
                walker.pte_access &= ~ACC_USER_MASK;
 
@@ -876,7 +903,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gpa_t addr, u32 error_code,
                 * then we should prevent the kernel from executing it
                 * if SMEP is enabled.
                 */
-               if (kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))
+               if (is_cr4_smep(vcpu->arch.mmu))
                        walker.pte_access &= ~ACC_EXEC_MASK;
        }
 
@@ -1031,13 +1058,36 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gpa_t vaddr,
  */
 static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
+       union kvm_mmu_page_role mmu_role = vcpu->arch.mmu->mmu_role.base;
        int i, nr_present = 0;
        bool host_writable;
        gpa_t first_pte_gpa;
        int set_spte_ret = 0;
 
-       /* direct kvm_mmu_page can not be unsync. */
-       BUG_ON(sp->role.direct);
+       /*
+        * Ignore various flags when verifying that it's safe to sync a shadow
+        * page using the current MMU context.
+        *
+        *  - level: not part of the overall MMU role and will never match as the MMU's
+        *           level tracks the root level
+        *  - access: updated based on the new guest PTE
+        *  - quadrant: not part of the overall MMU role (similar to level)
+        */
+       const union kvm_mmu_page_role sync_role_ign = {
+               .level = 0xf,
+               .access = 0x7,
+               .quadrant = 0x3,
+       };
+
+       /*
+        * Direct pages can never be unsync, and KVM should never attempt to
+        * sync a shadow page for a different MMU context, e.g. if the role
+        * differs then the memslot lookup (SMM vs. non-SMM) will be bogus, the
+        * reserved bits checks will be wrong, etc...
+        */
+       if (WARN_ON_ONCE(sp->role.direct ||
+                        (sp->role.word ^ mmu_role.word) & ~sync_role_ign.word))
+               return 0;
 
        first_pte_gpa = FNAME(get_level1_sp_gpa)(sp);
 
index 66d43ce..3e97cdb 100644 (file)
@@ -103,13 +103,6 @@ int make_spte(struct kvm_vcpu *vcpu, unsigned int pte_access, int level,
                spte |= SPTE_TDP_AD_WRPROT_ONLY_MASK;
 
        /*
-        * Bits 62:52 of PAE SPTEs are reserved.  WARN if said bits are set
-        * if PAE paging may be employed (shadow paging or any 32-bit KVM).
-        */
-       WARN_ON_ONCE((!tdp_enabled || !IS_ENABLED(CONFIG_X86_64)) &&
-                    (spte & SPTE_TDP_AD_MASK));
-
-       /*
         * For the EPT case, shadow_present_mask is 0 if hardware
         * supports exec-only page table entries.  In that case,
         * ACC_USER_MASK and shadow_user_mask are used to represent
@@ -154,13 +147,19 @@ int make_spte(struct kvm_vcpu *vcpu, unsigned int pte_access, int level,
                /*
                 * Optimization: for pte sync, if spte was writable the hash
                 * lookup is unnecessary (and expensive). Write protection
-                * is responsibility of mmu_get_page / kvm_sync_page.
+                * is responsibility of kvm_mmu_get_page / kvm_mmu_sync_roots.
                 * Same reasoning can be applied to dirty page accounting.
                 */
                if (!can_unsync && is_writable_pte(old_spte))
                        goto out;
 
-               if (mmu_need_write_protect(vcpu, gfn, can_unsync)) {
+               /*
+                * Unsync shadow pages that are reachable by the new, writable
+                * SPTE.  Write-protect the SPTE if the page can't be unsync'd,
+                * e.g. it's write-tracked (upper-level SPs) or has one or more
+                * shadow pages and unsync'ing pages is not allowed.
+                */
+               if (mmu_try_to_unsync_pages(vcpu, gfn, can_unsync)) {
                        pgprintk("%s: found shadow page for %llx, marking ro\n",
                                 __func__, gfn);
                        ret |= SET_SPTE_WRITE_PROTECTED_PT;
@@ -176,7 +175,10 @@ int make_spte(struct kvm_vcpu *vcpu, unsigned int pte_access, int level,
                spte = mark_spte_for_access_track(spte);
 
 out:
-       WARN_ON(is_mmio_spte(spte));
+       WARN_ONCE(is_rsvd_spte(&vcpu->arch.mmu->shadow_zero_check, spte, level),
+                 "spte = 0x%llx, level = %d, rsvd bits = 0x%llx", spte, level,
+                 get_rsvd_bits(&vcpu->arch.mmu->shadow_zero_check, spte, level));
+
        *new_spte = spte;
        return ret;
 }
index bca0ba1..7a5ce93 100644 (file)
@@ -293,6 +293,38 @@ static inline bool is_dirty_spte(u64 spte)
        return dirty_mask ? spte & dirty_mask : spte & PT_WRITABLE_MASK;
 }
 
+static inline u64 get_rsvd_bits(struct rsvd_bits_validate *rsvd_check, u64 pte,
+                               int level)
+{
+       int bit7 = (pte >> 7) & 1;
+
+       return rsvd_check->rsvd_bits_mask[bit7][level-1];
+}
+
+static inline bool __is_rsvd_bits_set(struct rsvd_bits_validate *rsvd_check,
+                                     u64 pte, int level)
+{
+       return pte & get_rsvd_bits(rsvd_check, pte, level);
+}
+
+static inline bool __is_bad_mt_xwr(struct rsvd_bits_validate *rsvd_check,
+                                  u64 pte)
+{
+       return rsvd_check->bad_mt_xwr & BIT_ULL(pte & 0x3f);
+}
+
+static __always_inline bool is_rsvd_spte(struct rsvd_bits_validate *rsvd_check,
+                                        u64 spte, int level)
+{
+       /*
+        * Use a bitwise-OR instead of a logical-OR to aggregate the reserved
+        * bits and EPT's invalid memtype/XWR checks to avoid an extra Jcc
+        * (this is extremely unlikely to be short-circuited as true).
+        */
+       return __is_bad_mt_xwr(rsvd_check, spte) |
+              __is_rsvd_bits_set(rsvd_check, spte, level);
+}
+
 static inline bool spte_can_locklessly_be_made_writable(u64 spte)
 {
        return (spte & shadow_host_writable_mask) &&
index 237317b..0853370 100644 (file)
@@ -14,10 +14,10 @@ static bool __read_mostly tdp_mmu_enabled = false;
 module_param_named(tdp_mmu, tdp_mmu_enabled, bool, 0644);
 
 /* Initializes the TDP MMU for the VM, if enabled. */
-void kvm_mmu_init_tdp_mmu(struct kvm *kvm)
+bool kvm_mmu_init_tdp_mmu(struct kvm *kvm)
 {
        if (!tdp_enabled || !READ_ONCE(tdp_mmu_enabled))
-               return;
+               return false;
 
        /* This should not be changed for the lifetime of the VM. */
        kvm->arch.tdp_mmu_enabled = true;
@@ -25,6 +25,8 @@ void kvm_mmu_init_tdp_mmu(struct kvm *kvm)
        INIT_LIST_HEAD(&kvm->arch.tdp_mmu_roots);
        spin_lock_init(&kvm->arch.tdp_mmu_pages_lock);
        INIT_LIST_HEAD(&kvm->arch.tdp_mmu_pages);
+
+       return true;
 }
 
 static __always_inline void kvm_lockdep_assert_mmu_lock_held(struct kvm *kvm,
@@ -335,7 +337,7 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
 
        for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
                sptep = rcu_dereference(pt) + i;
-               gfn = base_gfn + (i * KVM_PAGES_PER_HPAGE(level - 1));
+               gfn = base_gfn + i * KVM_PAGES_PER_HPAGE(level);
 
                if (shared) {
                        /*
@@ -377,12 +379,12 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
                        WRITE_ONCE(*sptep, REMOVED_SPTE);
                }
                handle_changed_spte(kvm, kvm_mmu_page_as_id(sp), gfn,
-                                   old_child_spte, REMOVED_SPTE, level - 1,
+                                   old_child_spte, REMOVED_SPTE, level,
                                    shared);
        }
 
        kvm_flush_remote_tlbs_with_address(kvm, gfn,
-                                          KVM_PAGES_PER_HPAGE(level));
+                                          KVM_PAGES_PER_HPAGE(level + 1));
 
        call_rcu(&sp->rcu_head, tdp_mmu_free_sp_rcu_callback);
 }
@@ -912,7 +914,7 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu, int write,
                                          kvm_pfn_t pfn, bool prefault)
 {
        u64 new_spte;
-       int ret = 0;
+       int ret = RET_PF_FIXED;
        int make_spte_ret = 0;
 
        if (unlikely(is_noslot_pfn(pfn)))
@@ -949,7 +951,11 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu, int write,
                                       rcu_dereference(iter->sptep));
        }
 
-       if (!prefault)
+       /*
+        * Increase pf_fixed in both RET_PF_EMULATE and RET_PF_FIXED to be
+        * consistent with legacy MMU behavior.
+        */
+       if (ret != RET_PF_SPURIOUS)
                vcpu->stat.pf_fixed++;
 
        return ret;
@@ -977,11 +983,6 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
        int level;
        int req_level;
 
-       if (WARN_ON(!VALID_PAGE(vcpu->arch.mmu->root_hpa)))
-               return RET_PF_RETRY;
-       if (WARN_ON(!is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa)))
-               return RET_PF_RETRY;
-
        level = kvm_mmu_hugepage_adjust(vcpu, gfn, max_level, &pfn,
                                        huge_page_disallowed, &req_level);
 
@@ -1017,14 +1018,14 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
 
                if (!is_shadow_present_pte(iter.old_spte)) {
                        /*
-                        * If SPTE has been forzen by another thread, just
+                        * If SPTE has been frozen by another thread, just
                         * give up and retry, avoiding unnecessary page table
                         * allocation and free.
                         */
                        if (is_removed_spte(iter.old_spte))
                                break;
 
-                       sp = alloc_tdp_mmu_page(vcpu, iter.gfn, iter.level);
+                       sp = alloc_tdp_mmu_page(vcpu, iter.gfn, iter.level - 1);
                        child_pt = sp->spt;
 
                        new_spte = make_nonleaf_spte(child_pt,
@@ -1462,15 +1463,22 @@ bool kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
  * Returns true if an SPTE was set and a TLB flush is needed.
  */
 static bool write_protect_gfn(struct kvm *kvm, struct kvm_mmu_page *root,
-                             gfn_t gfn)
+                             gfn_t gfn, int min_level)
 {
        struct tdp_iter iter;
        u64 new_spte;
        bool spte_set = false;
 
+       BUG_ON(min_level > KVM_MAX_HUGEPAGE_LEVEL);
+
        rcu_read_lock();
 
-       tdp_root_for_each_leaf_pte(iter, root, gfn, gfn + 1) {
+       for_each_tdp_pte_min_level(iter, root->spt, root->role.level,
+                                  min_level, gfn, gfn + 1) {
+               if (!is_shadow_present_pte(iter.old_spte) ||
+                   !is_last_spte(iter.old_spte, iter.level))
+                       continue;
+
                if (!is_writable_pte(iter.old_spte))
                        break;
 
@@ -1492,14 +1500,15 @@ static bool write_protect_gfn(struct kvm *kvm, struct kvm_mmu_page *root,
  * Returns true if an SPTE was set and a TLB flush is needed.
  */
 bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm,
-                                  struct kvm_memory_slot *slot, gfn_t gfn)
+                                  struct kvm_memory_slot *slot, gfn_t gfn,
+                                  int min_level)
 {
        struct kvm_mmu_page *root;
        bool spte_set = false;
 
        lockdep_assert_held_write(&kvm->mmu_lock);
        for_each_tdp_mmu_root(kvm, root, slot->as_id)
-               spte_set |= write_protect_gfn(kvm, root, gfn);
+               spte_set |= write_protect_gfn(kvm, root, gfn, min_level);
 
        return spte_set;
 }
index 5fdf630..1cae448 100644 (file)
@@ -31,7 +31,7 @@ static inline bool kvm_tdp_mmu_zap_gfn_range(struct kvm *kvm, int as_id,
 }
 static inline bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
-       gfn_t end = sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level);
+       gfn_t end = sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level + 1);
 
        /*
         * Don't allow yielding, as the caller may have a flush pending.  Note,
@@ -74,37 +74,40 @@ bool kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
                                       bool flush);
 
 bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm,
-                                  struct kvm_memory_slot *slot, gfn_t gfn);
+                                  struct kvm_memory_slot *slot, gfn_t gfn,
+                                  int min_level);
 
 int kvm_tdp_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes,
                         int *root_level);
 
 #ifdef CONFIG_X86_64
-void kvm_mmu_init_tdp_mmu(struct kvm *kvm);
+bool kvm_mmu_init_tdp_mmu(struct kvm *kvm);
 void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm);
 static inline bool is_tdp_mmu_enabled(struct kvm *kvm) { return kvm->arch.tdp_mmu_enabled; }
 static inline bool is_tdp_mmu_page(struct kvm_mmu_page *sp) { return sp->tdp_mmu_page; }
-#else
-static inline void kvm_mmu_init_tdp_mmu(struct kvm *kvm) {}
-static inline void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm) {}
-static inline bool is_tdp_mmu_enabled(struct kvm *kvm) { return false; }
-static inline bool is_tdp_mmu_page(struct kvm_mmu_page *sp) { return false; }
-#endif
 
-static inline bool is_tdp_mmu_root(struct kvm *kvm, hpa_t hpa)
+static inline bool is_tdp_mmu(struct kvm_mmu *mmu)
 {
        struct kvm_mmu_page *sp;
+       hpa_t hpa = mmu->root_hpa;
 
-       if (!is_tdp_mmu_enabled(kvm))
-               return false;
        if (WARN_ON(!VALID_PAGE(hpa)))
                return false;
 
+       /*
+        * A NULL shadow page is legal when shadowing a non-paging guest with
+        * PAE paging, as the MMU will be direct with root_hpa pointing at the
+        * pae_root page, not a shadow page.
+        */
        sp = to_shadow_page(hpa);
-       if (WARN_ON(!sp))
-               return false;
-
-       return is_tdp_mmu_page(sp) && sp->root_count;
+       return sp && is_tdp_mmu_page(sp) && sp->root_count;
 }
+#else
+static inline bool kvm_mmu_init_tdp_mmu(struct kvm *kvm) { return false; }
+static inline void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm) {}
+static inline bool is_tdp_mmu_enabled(struct kvm *kvm) { return false; }
+static inline bool is_tdp_mmu_page(struct kvm_mmu_page *sp) { return false; }
+static inline bool is_tdp_mmu(struct kvm_mmu *mmu) { return false; }
+#endif
 
 #endif /* __KVM_X86_MMU_TDP_MMU_H */
index 0e62e6a..1d01da6 100644 (file)
 #include "irq.h"
 #include "svm.h"
 
-/* enable / disable AVIC */
-bool avic;
-module_param(avic, bool, S_IRUGO);
-
 #define SVM_AVIC_DOORBELL      0xc001011b
 
 #define AVIC_HPA_MASK  ~((0xFFFULL << 52) | 0xFFF)
@@ -124,7 +120,7 @@ void avic_vm_destroy(struct kvm *kvm)
        unsigned long flags;
        struct kvm_svm *kvm_svm = to_kvm_svm(kvm);
 
-       if (!avic)
+       if (!enable_apicv)
                return;
 
        if (kvm_svm->avic_logical_id_table_page)
@@ -147,7 +143,7 @@ int avic_vm_init(struct kvm *kvm)
        struct page *l_page;
        u32 vm_id;
 
-       if (!avic)
+       if (!enable_apicv)
                return 0;
 
        /* Allocating physical APIC ID table (4KB) */
@@ -221,7 +217,7 @@ static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
        return &avic_physical_id_table[index];
 }
 
-/**
+/*
  * Note:
  * AVIC hardware walks the nested page table to check permissions,
  * but does not use the SPA address specified in the leaf page
@@ -240,7 +236,7 @@ static int avic_update_access_page(struct kvm *kvm, bool activate)
         * APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT
         * memory region. So, we need to ensure that kvm->mm == current->mm.
         */
-       if ((kvm->arch.apic_access_page_done == activate) ||
+       if ((kvm->arch.apic_access_memslot_enabled == activate) ||
            (kvm->mm != current->mm))
                goto out;
 
@@ -253,7 +249,7 @@ static int avic_update_access_page(struct kvm *kvm, bool activate)
                goto out;
        }
 
-       kvm->arch.apic_access_page_done = activate;
+       kvm->arch.apic_access_memslot_enabled = activate;
 out:
        mutex_unlock(&kvm->slots_lock);
        return r;
@@ -569,7 +565,7 @@ int avic_init_vcpu(struct vcpu_svm *svm)
        int ret;
        struct kvm_vcpu *vcpu = &svm->vcpu;
 
-       if (!avic || !irqchip_in_kernel(vcpu->kvm))
+       if (!enable_apicv || !irqchip_in_kernel(vcpu->kvm))
                return 0;
 
        ret = avic_init_backing_page(vcpu);
@@ -593,7 +589,7 @@ void avic_post_state_restore(struct kvm_vcpu *vcpu)
 
 void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate)
 {
-       if (!avic || !lapic_in_kernel(vcpu))
+       if (!enable_apicv || !lapic_in_kernel(vcpu))
                return;
 
        srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
@@ -653,7 +649,7 @@ void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
        struct vmcb *vmcb = svm->vmcb;
        bool activated = kvm_vcpu_apicv_active(vcpu);
 
-       if (!avic)
+       if (!enable_apicv)
                return;
 
        if (activated) {
@@ -764,7 +760,7 @@ out:
        return ret;
 }
 
-/**
+/*
  * Note:
  * The HW cannot support posting multicast/broadcast
  * interrupts to a vCPU. So, we still use legacy interrupt
@@ -1005,7 +1001,7 @@ void avic_vcpu_put(struct kvm_vcpu *vcpu)
        WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
 }
 
-/**
+/*
  * This function is called during VCPU halt/unhalt.
  */
 static void avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
index 5e8d844..21d03e3 100644 (file)
@@ -98,13 +98,18 @@ static void nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
        WARN_ON(mmu_is_nested(vcpu));
 
        vcpu->arch.mmu = &vcpu->arch.guest_mmu;
+
+       /*
+        * The NPT format depends on L1's CR4 and EFER, which is in vmcb01.  Note,
+        * when called via KVM_SET_NESTED_STATE, that state may _not_ match current
+        * vCPU state.  CR0.WP is explicitly ignored, while CR0.PG is required.
+        */
        kvm_init_shadow_npt_mmu(vcpu, X86_CR0_PG, svm->vmcb01.ptr->save.cr4,
                                svm->vmcb01.ptr->save.efer,
                                svm->nested.ctl.nested_cr3);
        vcpu->arch.mmu->get_guest_pgd     = nested_svm_get_tdp_cr3;
        vcpu->arch.mmu->get_pdptr         = nested_svm_get_tdp_pdptr;
        vcpu->arch.mmu->inject_page_fault = nested_svm_inject_npf_exit;
-       reset_shadow_zero_bits_mask(vcpu, vcpu->arch.mmu);
        vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
 }
 
@@ -380,33 +385,47 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm)
        return svm->nested.ctl.nested_ctl & SVM_NESTED_CTL_NP_ENABLE;
 }
 
+static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
+{
+       /*
+        * TODO: optimize unconditional TLB flush/MMU sync.  A partial list of
+        * things to fix before this can be conditional:
+        *
+        *  - Flush TLBs for both L1 and L2 remote TLB flush
+        *  - Honor L1's request to flush an ASID on nested VMRUN
+        *  - Sync nested NPT MMU on VMRUN that flushes L2's ASID[*]
+        *  - Don't crush a pending TLB flush in vmcb02 on nested VMRUN
+        *  - Flush L1's ASID on KVM_REQ_TLB_FLUSH_GUEST
+        *
+        * [*] Unlike nested EPT, SVM's ASID management can invalidate nested
+        *     NPT guest-physical mappings on VMRUN.
+        */
+       kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
+       kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+}
+
 /*
  * Load guest's/host's cr3 on nested vmentry or vmexit. @nested_npt is true
  * if we are emulating VM-Entry into a guest with NPT enabled.
  */
 static int nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
-                              bool nested_npt)
+                              bool nested_npt, bool reload_pdptrs)
 {
        if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3)))
                return -EINVAL;
 
-       if (!nested_npt && is_pae_paging(vcpu) &&
-           (cr3 != kvm_read_cr3(vcpu) || pdptrs_changed(vcpu))) {
-               if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)))
-                       return -EINVAL;
-       }
+       if (reload_pdptrs && !nested_npt && is_pae_paging(vcpu) &&
+           CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)))
+               return -EINVAL;
 
-       /*
-        * TODO: optimize unconditional TLB flush/MMU sync here and in
-        * kvm_init_shadow_npt_mmu().
-        */
        if (!nested_npt)
-               kvm_mmu_new_pgd(vcpu, cr3, false, false);
+               kvm_mmu_new_pgd(vcpu, cr3);
 
        vcpu->arch.cr3 = cr3;
        kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);
 
-       kvm_init_mmu(vcpu, false);
+       /* Re-initialize the MMU, e.g. to pick up CR4 MMU role changes. */
+       kvm_init_mmu(vcpu);
 
        return 0;
 }
@@ -481,6 +500,7 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12
 static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
 {
        const u32 mask = V_INTR_MASKING_MASK | V_GIF_ENABLE_MASK | V_GIF_MASK;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
 
        /*
         * Filled at exit: exit_code, exit_code_hi, exit_info_1, exit_info_2,
@@ -505,10 +525,10 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
 
        /* nested_cr3.  */
        if (nested_npt_enabled(svm))
-               nested_svm_init_mmu_context(&svm->vcpu);
+               nested_svm_init_mmu_context(vcpu);
 
-       svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset =
-               svm->vcpu.arch.l1_tsc_offset + svm->nested.ctl.tsc_offset;
+       svm->vmcb->control.tsc_offset = vcpu->arch.tsc_offset =
+               vcpu->arch.l1_tsc_offset + svm->nested.ctl.tsc_offset;
 
        svm->vmcb->control.int_ctl             =
                (svm->nested.ctl.int_ctl & ~mask) |
@@ -523,8 +543,10 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm)
        svm->vmcb->control.pause_filter_count  = svm->nested.ctl.pause_filter_count;
        svm->vmcb->control.pause_filter_thresh = svm->nested.ctl.pause_filter_thresh;
 
+       nested_svm_transition_tlb_flush(vcpu);
+
        /* Enter Guest-Mode */
-       enter_guest_mode(&svm->vcpu);
+       enter_guest_mode(vcpu);
 
        /*
         * Merge guest and host intercepts - must be called with vcpu in
@@ -576,7 +598,7 @@ int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa,
        nested_vmcb02_prepare_save(svm, vmcb12);
 
        ret = nested_svm_load_cr3(&svm->vcpu, vmcb12->save.cr3,
-                                 nested_npt_enabled(svm));
+                                 nested_npt_enabled(svm), true);
        if (ret)
                return ret;
 
@@ -596,8 +618,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
        struct kvm_host_map map;
        u64 vmcb12_gpa;
 
-       ++vcpu->stat.nested_run;
-
        if (is_smm(vcpu)) {
                kvm_queue_exception(vcpu, UD_VECTOR);
                return 1;
@@ -803,9 +823,11 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
 
        kvm_vcpu_unmap(vcpu, &map, true);
 
+       nested_svm_transition_tlb_flush(vcpu);
+
        nested_svm_uninit_mmu_context(vcpu);
 
-       rc = nested_svm_load_cr3(vcpu, svm->vmcb->save.cr3, false);
+       rc = nested_svm_load_cr3(vcpu, svm->vmcb->save.cr3, false, true);
        if (rc)
                return 1;
 
@@ -1228,8 +1250,8 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
                &user_kvm_nested_state->data.svm[0];
        struct vmcb_control_area *ctl;
        struct vmcb_save_area *save;
+       unsigned long cr0;
        int ret;
-       u32 cr0;
 
        BUILD_BUG_ON(sizeof(struct vmcb_control_area) + sizeof(struct vmcb_save_area) >
                     KVM_STATE_NESTED_SVM_VMCB_SIZE);
@@ -1302,6 +1324,19 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
                goto out_free;
 
        /*
+        * While the nested guest CR3 is already checked and set by
+        * KVM_SET_SREGS, it was set when nested state was yet loaded,
+        * thus MMU might not be initialized correctly.
+        * Set it again to fix this.
+        */
+
+       ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
+                                 nested_npt_enabled(svm), false);
+       if (WARN_ON_ONCE(ret))
+               goto out_free;
+
+
+       /*
         * All checks done, we can enter guest mode. Userspace provides
         * vmcb12.control, which will be combined with L1 and stored into
         * vmcb02, and the L1 save state which we store in vmcb01.
@@ -1358,9 +1393,15 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
        if (WARN_ON(!is_guest_mode(vcpu)))
                return true;
 
-       if (nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
-                               nested_npt_enabled(svm)))
-               return false;
+       if (!vcpu->arch.pdptrs_from_userspace &&
+           !nested_npt_enabled(svm) && is_pae_paging(vcpu))
+               /*
+                * Reload the guest's PDPTRs since after a migration
+                * the guest CR3 might be restored prior to setting the nested
+                * state which can lead to a load of wrong PDPTRs.
+                */
+               if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3)))
+                       return false;
 
        if (!nested_svm_vmrun_msrpm(svm)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
index e0ce5da..8d36f0c 100644 (file)
@@ -199,9 +199,19 @@ static void sev_asid_free(struct kvm_sev_info *sev)
        sev->misc_cg = NULL;
 }
 
-static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
+static void sev_decommission(unsigned int handle)
 {
        struct sev_data_decommission decommission;
+
+       if (!handle)
+               return;
+
+       decommission.handle = handle;
+       sev_guest_decommission(&decommission, NULL);
+}
+
+static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
+{
        struct sev_data_deactivate deactivate;
 
        if (!handle)
@@ -214,9 +224,7 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
        sev_guest_deactivate(&deactivate, NULL);
        up_read(&sev_deactivate_lock);
 
-       /* decommission handle */
-       decommission.handle = handle;
-       sev_guest_decommission(&decommission, NULL);
+       sev_decommission(handle);
 }
 
 static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
@@ -341,8 +349,10 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
 
        /* Bind ASID to this guest */
        ret = sev_bind_asid(kvm, start.handle, error);
-       if (ret)
+       if (ret) {
+               sev_decommission(start.handle);
                goto e_free_session;
+       }
 
        /* return handle to userspace */
        params.handle = start.handle;
index e088086..8834822 100644 (file)
@@ -43,6 +43,9 @@
 #include "svm.h"
 #include "svm_ops.h"
 
+#include "kvm_onhyperv.h"
+#include "svm_onhyperv.h"
+
 #define __ex(x) __kvm_handle_fault_on_reboot(x)
 
 MODULE_AUTHOR("Qumranet");
@@ -185,6 +188,13 @@ module_param(vls, int, 0444);
 static int vgif = true;
 module_param(vgif, int, 0444);
 
+/*
+ * enable / disable AVIC.  Because the defaults differ for APICv
+ * support between VMX and SVM we cannot use module_param_named.
+ */
+static bool avic;
+module_param(avic, bool, 0444);
+
 bool __read_mostly dump_invalid_vmcb;
 module_param(dump_invalid_vmcb, bool, 0644);
 
@@ -673,6 +683,9 @@ static void set_msr_interception_bitmap(struct kvm_vcpu *vcpu, u32 *msrpm,
        write ? clear_bit(bit_write, &tmp) : set_bit(bit_write, &tmp);
 
        msrpm[offset] = tmp;
+
+       svm_hv_vmcb_dirty_nested_enlightenments(vcpu);
+
 }
 
 void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
@@ -939,6 +952,16 @@ static __init int svm_hardware_setup(void)
        int r;
        unsigned int order = get_order(IOPM_SIZE);
 
+       /*
+        * NX is required for shadow paging and for NPT if the NX huge pages
+        * mitigation is enabled.
+        */
+       if (!boot_cpu_has(X86_FEATURE_NX)) {
+               pr_err_ratelimited("NX (Execute Disable) not supported\n");
+               return -EOPNOTSUPP;
+       }
+       kvm_enable_efer_bits(EFER_NX);
+
        iopm_pages = alloc_pages(GFP_KERNEL, order);
 
        if (!iopm_pages)
@@ -952,9 +975,6 @@ static __init int svm_hardware_setup(void)
 
        supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
 
-       if (boot_cpu_has(X86_FEATURE_NX))
-               kvm_enable_efer_bits(EFER_NX);
-
        if (boot_cpu_has(X86_FEATURE_FXSR_OPT))
                kvm_enable_efer_bits(EFER_FFXSR);
 
@@ -996,6 +1016,8 @@ static __init int svm_hardware_setup(void)
        /* Note, SEV setup consumes npt_enabled. */
        sev_hardware_setup();
 
+       svm_hv_hardware_setup();
+
        svm_adjust_mmio_mask();
 
        for_each_possible_cpu(cpu) {
@@ -1009,14 +1031,12 @@ static __init int svm_hardware_setup(void)
                        nrips = false;
        }
 
-       if (avic) {
-               if (!npt_enabled || !boot_cpu_has(X86_FEATURE_AVIC)) {
-                       avic = false;
-               } else {
-                       pr_info("AVIC enabled\n");
+       enable_apicv = avic = avic && npt_enabled && boot_cpu_has(X86_FEATURE_AVIC);
 
-                       amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier);
-               }
+       if (enable_apicv) {
+               pr_info("AVIC enabled\n");
+
+               amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier);
        }
 
        if (vls) {
@@ -1080,26 +1100,30 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
        seg->base = 0;
 }
 
-static u64 svm_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+static u64 svm_get_l2_tsc_offset(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       u64 g_tsc_offset = 0;
 
-       if (is_guest_mode(vcpu)) {
-               /* Write L1's TSC offset.  */
-               g_tsc_offset = svm->vmcb->control.tsc_offset -
-                              svm->vmcb01.ptr->control.tsc_offset;
-               svm->vmcb01.ptr->control.tsc_offset = offset;
-       }
+       return svm->nested.ctl.tsc_offset;
+}
 
-       trace_kvm_write_tsc_offset(vcpu->vcpu_id,
-                                  svm->vmcb->control.tsc_offset - g_tsc_offset,
-                                  offset);
+static u64 svm_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu)
+{
+       return kvm_default_tsc_scaling_ratio;
+}
 
-       svm->vmcb->control.tsc_offset = offset + g_tsc_offset;
+static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
 
+       svm->vmcb01.ptr->control.tsc_offset = vcpu->arch.l1_tsc_offset;
+       svm->vmcb->control.tsc_offset = offset;
        vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
-       return svm->vmcb->control.tsc_offset;
+}
+
+static void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier)
+{
+       wrmsrl(MSR_AMD64_TSC_RATIO, multiplier);
 }
 
 /* Evaluate instruction intercepts that depend on guest CPUID features. */
@@ -1287,6 +1311,8 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
                }
        }
 
+       svm_hv_init_vmcb(svm->vmcb);
+
        vmcb_mark_all_dirty(svm->vmcb);
 
        enable_gif(svm);
@@ -3106,6 +3132,8 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
                return;
        }
 
+       pr_err("VMCB %p, last attempted VMRUN on CPU %d\n",
+              svm->current_vmcb->ptr, vcpu->arch.last_vmentry_cpu);
        pr_err("VMCB Control Area:\n");
        pr_err("%-20s%04x\n", "cr_read:", control->intercepts[INTERCEPT_CR] & 0xffff);
        pr_err("%-20s%04x\n", "cr_write:", control->intercepts[INTERCEPT_CR] >> 16);
@@ -3762,6 +3790,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
        }
        svm->vmcb->save.cr2 = vcpu->arch.cr2;
 
+       svm_hv_update_vp_id(svm->vmcb, vcpu);
+
        /*
         * Run with all-zero DR6 unless needed, so that we can get the exact cause
         * of a #DB.
@@ -3835,6 +3865,12 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
        svm->next_rip = 0;
        if (is_guest_mode(vcpu)) {
                nested_sync_control_from_vmcb02(svm);
+
+               /* Track VMRUNs that have made past consistency checking */
+               if (svm->nested.nested_run_pending &&
+                   svm->vmcb->control.exit_code != SVM_EXIT_ERR)
+                        ++vcpu->stat.nested_run;
+
                svm->nested.nested_run_pending = 0;
        }
 
@@ -3846,10 +3882,8 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
                vcpu->arch.apf.host_apf_flags =
                        kvm_read_and_reset_apf_flags();
 
-       if (npt_enabled) {
-               vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
-               vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR);
-       }
+       if (npt_enabled)
+               kvm_register_clear_available(vcpu, VCPU_EXREG_PDPTR);
 
        /*
         * We need to handle MC intercepts here before the vcpu has a chance to
@@ -3877,6 +3911,8 @@ static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa,
                svm->vmcb->control.nested_cr3 = __sme_set(root_hpa);
                vmcb_mark_dirty(svm->vmcb, VMCB_NPT);
 
+               hv_track_root_tdp(vcpu, root_hpa);
+
                /* Loading L2's CR3 is handled by enter_svm_guest_mode.  */
                if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail))
                        return;
@@ -4249,7 +4285,7 @@ static int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
        return !svm_smi_blocked(vcpu);
 }
 
-static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
+static int svm_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        int ret;
@@ -4271,7 +4307,7 @@ static int svm_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
        return 0;
 }
 
-static int svm_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
+static int svm_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        struct kvm_host_map map;
@@ -4427,13 +4463,12 @@ static int svm_vm_init(struct kvm *kvm)
        if (!pause_filter_count || !pause_filter_thresh)
                kvm->arch.pause_in_guest = true;
 
-       if (avic) {
+       if (enable_apicv) {
                int ret = avic_vm_init(kvm);
                if (ret)
                        return ret;
        }
 
-       kvm_apicv_init(kvm, avic);
        return 0;
 }
 
@@ -4524,7 +4559,10 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
 
        .has_wbinvd_exit = svm_has_wbinvd_exit,
 
-       .write_l1_tsc_offset = svm_write_l1_tsc_offset,
+       .get_l2_tsc_offset = svm_get_l2_tsc_offset,
+       .get_l2_tsc_multiplier = svm_get_l2_tsc_multiplier,
+       .write_tsc_offset = svm_write_tsc_offset,
+       .write_tsc_multiplier = svm_write_tsc_multiplier,
 
        .load_mmu_pgd = svm_load_mmu_pgd,
 
@@ -4544,8 +4582,8 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .setup_mce = svm_setup_mce,
 
        .smi_allowed = svm_smi_allowed,
-       .pre_enter_smm = svm_pre_enter_smm,
-       .pre_leave_smm = svm_pre_leave_smm,
+       .enter_smm = svm_enter_smm,
+       .leave_smm = svm_leave_smm,
        .enable_smi_window = svm_enable_smi_window,
 
        .mem_enc_op = svm_mem_enc_op,
index 2908c6a..f89b623 100644 (file)
 extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
 extern bool npt_enabled;
 
+/*
+ * Clean bits in VMCB.
+ * VMCB_ALL_CLEAN_MASK might also need to
+ * be updated if this enum is modified.
+ */
 enum {
        VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
                            pause filter count */
@@ -49,9 +54,17 @@ enum {
                          * AVIC PHYSICAL_TABLE pointer,
                          * AVIC LOGICAL_TABLE pointer
                          */
-       VMCB_DIRTY_MAX,
+       VMCB_SW = 31,    /* Reserved for hypervisor/software use */
 };
 
+#define VMCB_ALL_CLEAN_MASK (                                  \
+       (1U << VMCB_INTERCEPTS) | (1U << VMCB_PERM_MAP) |       \
+       (1U << VMCB_ASID) | (1U << VMCB_INTR) |                 \
+       (1U << VMCB_NPT) | (1U << VMCB_CR) | (1U << VMCB_DR) |  \
+       (1U << VMCB_DT) | (1U << VMCB_SEG) | (1U << VMCB_CR2) | \
+       (1U << VMCB_LBR) | (1U << VMCB_AVIC) |                  \
+       (1U << VMCB_SW))
+
 /* TPR and CR2 are always written before VMRUN */
 #define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
 
@@ -238,10 +251,15 @@ static inline void vmcb_mark_all_dirty(struct vmcb *vmcb)
 
 static inline void vmcb_mark_all_clean(struct vmcb *vmcb)
 {
-       vmcb->control.clean = ((1 << VMCB_DIRTY_MAX) - 1)
+       vmcb->control.clean = VMCB_ALL_CLEAN_MASK
                               & ~VMCB_ALWAYS_DIRTY_MASK;
 }
 
+static inline bool vmcb_is_clean(struct vmcb *vmcb, int bit)
+{
+       return (vmcb->control.clean & (1 << bit));
+}
+
 static inline void vmcb_mark_dirty(struct vmcb *vmcb, int bit)
 {
        vmcb->control.clean &= ~(1 << bit);
@@ -480,8 +498,6 @@ extern struct kvm_x86_nested_ops svm_nested_ops;
 
 #define VMCB_AVIC_APIC_BAR_MASK                0xFFFFFFFFFF000ULL
 
-extern bool avic;
-
 static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
 {
        svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK;
diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c
new file mode 100644 (file)
index 0000000..98aa981
--- /dev/null
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM L1 hypervisor optimizations on Hyper-V for SVM.
+ */
+
+#include <linux/kvm_host.h>
+#include "kvm_cache_regs.h"
+
+#include <asm/mshyperv.h>
+
+#include "svm.h"
+#include "svm_ops.h"
+
+#include "hyperv.h"
+#include "kvm_onhyperv.h"
+#include "svm_onhyperv.h"
+
+int svm_hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu)
+{
+       struct hv_enlightenments *hve;
+       struct hv_partition_assist_pg **p_hv_pa_pg =
+                       &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
+
+       if (!*p_hv_pa_pg)
+               *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
+
+       if (!*p_hv_pa_pg)
+               return -ENOMEM;
+
+       hve = (struct hv_enlightenments *)to_svm(vcpu)->vmcb->control.reserved_sw;
+
+       hve->partition_assist_page = __pa(*p_hv_pa_pg);
+       hve->hv_vm_id = (unsigned long)vcpu->kvm;
+       if (!hve->hv_enlightenments_control.nested_flush_hypercall) {
+               hve->hv_enlightenments_control.nested_flush_hypercall = 1;
+               vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
+       }
+
+       return 0;
+}
+
diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h
new file mode 100644 (file)
index 0000000..9b9a55a
--- /dev/null
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * KVM L1 hypervisor optimizations on Hyper-V for SVM.
+ */
+
+#ifndef __ARCH_X86_KVM_SVM_ONHYPERV_H__
+#define __ARCH_X86_KVM_SVM_ONHYPERV_H__
+
+#if IS_ENABLED(CONFIG_HYPERV)
+#include <asm/mshyperv.h>
+
+#include "hyperv.h"
+#include "kvm_onhyperv.h"
+
+static struct kvm_x86_ops svm_x86_ops;
+
+/*
+ * Hyper-V uses the software reserved 32 bytes in VMCB
+ * control area to expose SVM enlightenments to guests.
+ */
+struct hv_enlightenments {
+       struct __packed hv_enlightenments_control {
+               u32 nested_flush_hypercall:1;
+               u32 msr_bitmap:1;
+               u32 enlightened_npt_tlb: 1;
+               u32 reserved:29;
+       } __packed hv_enlightenments_control;
+       u32 hv_vp_id;
+       u64 hv_vm_id;
+       u64 partition_assist_page;
+       u64 reserved;
+} __packed;
+
+/*
+ * Hyper-V uses the software reserved clean bit in VMCB
+ */
+#define VMCB_HV_NESTED_ENLIGHTENMENTS VMCB_SW
+
+int svm_hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu);
+
+static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
+{
+       struct hv_enlightenments *hve =
+               (struct hv_enlightenments *)vmcb->control.reserved_sw;
+
+       if (npt_enabled &&
+           ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB)
+               hve->hv_enlightenments_control.enlightened_npt_tlb = 1;
+}
+
+static inline void svm_hv_hardware_setup(void)
+{
+       if (npt_enabled &&
+           ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) {
+               pr_info("kvm: Hyper-V enlightened NPT TLB flush enabled\n");
+               svm_x86_ops.tlb_remote_flush = hv_remote_flush_tlb;
+               svm_x86_ops.tlb_remote_flush_with_range =
+                               hv_remote_flush_tlb_with_range;
+       }
+
+       if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) {
+               int cpu;
+
+               pr_info("kvm: Hyper-V Direct TLB Flush enabled\n");
+               for_each_online_cpu(cpu) {
+                       struct hv_vp_assist_page *vp_ap =
+                               hv_get_vp_assist_page(cpu);
+
+                       if (!vp_ap)
+                               continue;
+
+                       vp_ap->nested_control.features.directhypercall = 1;
+               }
+               svm_x86_ops.enable_direct_tlbflush =
+                               svm_hv_enable_direct_tlbflush;
+       }
+}
+
+static inline void svm_hv_vmcb_dirty_nested_enlightenments(
+               struct kvm_vcpu *vcpu)
+{
+       struct vmcb *vmcb = to_svm(vcpu)->vmcb;
+       struct hv_enlightenments *hve =
+               (struct hv_enlightenments *)vmcb->control.reserved_sw;
+
+       /*
+        * vmcb can be NULL if called during early vcpu init.
+        * And its okay not to mark vmcb dirty during vcpu init
+        * as we mark it dirty unconditionally towards end of vcpu
+        * init phase.
+        */
+       if (vmcb && vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
+           hve->hv_enlightenments_control.msr_bitmap)
+               vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
+}
+
+static inline void svm_hv_update_vp_id(struct vmcb *vmcb,
+               struct kvm_vcpu *vcpu)
+{
+       struct hv_enlightenments *hve =
+               (struct hv_enlightenments *)vmcb->control.reserved_sw;
+       u32 vp_index = kvm_hv_get_vpindex(vcpu);
+
+       if (hve->hv_vp_id != vp_index) {
+               hve->hv_vp_id = vp_index;
+               vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
+       }
+}
+#else
+
+static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
+{
+}
+
+static inline void svm_hv_hardware_setup(void)
+{
+}
+
+static inline void svm_hv_vmcb_dirty_nested_enlightenments(
+               struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void svm_hv_update_vp_id(struct vmcb *vmcb,
+               struct kvm_vcpu *vcpu)
+{
+}
+#endif /* CONFIG_HYPERV */
+
+#endif /* __ARCH_X86_KVM_SVM_ONHYPERV_H__ */
index 4f83914..b484141 100644 (file)
@@ -997,7 +997,7 @@ TRACE_EVENT(kvm_wait_lapic_expire,
                  __entry->delta < 0 ? "early" : "late")
 );
 
-TRACE_EVENT(kvm_enter_smm,
+TRACE_EVENT(kvm_smm_transition,
        TP_PROTO(unsigned int vcpu_id, u64 smbase, bool entering),
        TP_ARGS(vcpu_id, smbase, entering),
 
index aa0e787..4705ad5 100644 (file)
@@ -12,7 +12,6 @@ extern bool __read_mostly enable_ept;
 extern bool __read_mostly enable_unrestricted_guest;
 extern bool __read_mostly enable_ept_ad_bits;
 extern bool __read_mostly enable_pml;
-extern bool __read_mostly enable_apicv;
 extern int __read_mostly pt_mode;
 
 #define PT_MODE_SYSTEM         0
index 41f2466..896b2a5 100644 (file)
@@ -319,6 +319,9 @@ bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa)
        if (unlikely(!assist_page.enlighten_vmentry))
                return false;
 
+       if (unlikely(!evmptr_is_valid(assist_page.current_nested_vmcs)))
+               return false;
+
        *evmcs_gpa = assist_page.current_nested_vmcs;
 
        return true;
index bd41d94..2ec9b46 100644 (file)
@@ -197,6 +197,14 @@ static inline void evmcs_load(u64 phys_addr) {}
 static inline void evmcs_touch_msr_bitmap(void) {}
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
+#define EVMPTR_INVALID (-1ULL)
+#define EVMPTR_MAP_PENDING (-2ULL)
+
+static inline bool evmptr_is_valid(u64 evmptr)
+{
+       return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
+}
+
 enum nested_evmptrld_status {
        EVMPTRLD_DISABLED,
        EVMPTRLD_SUCCEEDED,
index 6058a65..1a52134 100644 (file)
@@ -173,9 +173,13 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu,
                        | X86_EFLAGS_ZF);
        get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
        /*
-        * We don't need to force a shadow sync because
-        * VM_INSTRUCTION_ERROR is not shadowed
+        * We don't need to force sync to shadow VMCS because
+        * VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all
+        * fields and thus must be synced.
         */
+       if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
+               to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true;
+
        return kvm_skip_emulated_instruction(vcpu);
 }
 
@@ -187,7 +191,8 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error)
         * failValid writes the error number to the current VMCS, which
         * can't be done if there isn't a current VMCS.
         */
-       if (vmx->nested.current_vmptr == -1ull && !vmx->nested.hv_evmcs)
+       if (vmx->nested.current_vmptr == -1ull &&
+           !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                return nested_vmx_failInvalid(vcpu);
 
        return nested_vmx_failValid(vcpu, vm_instruction_error);
@@ -221,12 +226,12 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (!vmx->nested.hv_evmcs)
-               return;
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+               kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
+               vmx->nested.hv_evmcs = NULL;
+       }
 
-       kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
-       vmx->nested.hv_evmcs_vmptr = 0;
-       vmx->nested.hv_evmcs = NULL;
+       vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID;
 }
 
 static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
@@ -346,16 +351,21 @@ static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu,
        vmcs12->guest_physical_address = fault->address;
 }
 
+static void nested_ept_new_eptp(struct kvm_vcpu *vcpu)
+{
+       kvm_init_shadow_ept_mmu(vcpu,
+                               to_vmx(vcpu)->nested.msrs.ept_caps &
+                               VMX_EPT_EXECUTE_ONLY_BIT,
+                               nested_ept_ad_enabled(vcpu),
+                               nested_ept_get_eptp(vcpu));
+}
+
 static void nested_ept_init_mmu_context(struct kvm_vcpu *vcpu)
 {
        WARN_ON(mmu_is_nested(vcpu));
 
        vcpu->arch.mmu = &vcpu->arch.guest_mmu;
-       kvm_init_shadow_ept_mmu(vcpu,
-                       to_vmx(vcpu)->nested.msrs.ept_caps &
-                       VMX_EPT_EXECUTE_ONLY_BIT,
-                       nested_ept_ad_enabled(vcpu),
-                       nested_ept_get_eptp(vcpu));
+       nested_ept_new_eptp(vcpu);
        vcpu->arch.mmu->get_guest_pgd     = nested_ept_get_eptp;
        vcpu->arch.mmu->inject_page_fault = nested_ept_inject_page_fault;
        vcpu->arch.mmu->get_pdptr         = kvm_pdptr_read;
@@ -1058,54 +1068,13 @@ static void prepare_vmx_msr_autostore_list(struct kvm_vcpu *vcpu,
 }
 
 /*
- * Returns true if the MMU needs to be sync'd on nested VM-Enter/VM-Exit.
- * tl;dr: the MMU needs a sync if L0 is using shadow paging and L1 didn't
- * enable VPID for L2 (implying it expects a TLB flush on VMX transitions).
- * Here's why.
- *
- * If EPT is enabled by L0 a sync is never needed:
- * - if it is disabled by L1, then L0 is not shadowing L1 or L2 PTEs, there
- *   cannot be unsync'd SPTEs for either L1 or L2.
- *
- * - if it is also enabled by L1, then L0 doesn't need to sync on VM-Enter
- *   VM-Enter as VM-Enter isn't required to invalidate guest-physical mappings
- *   (irrespective of VPID), i.e. L1 can't rely on the (virtual) CPU to flush
- *   stale guest-physical mappings for L2 from the TLB.  And as above, L0 isn't
- *   shadowing L1 PTEs so there are no unsync'd SPTEs to sync on VM-Exit.
- *
- * If EPT is disabled by L0:
- * - if VPID is enabled by L1 (for L2), the situation is similar to when L1
- *   enables EPT: L0 doesn't need to sync as VM-Enter and VM-Exit aren't
- *   required to invalidate linear mappings (EPT is disabled so there are
- *   no combined or guest-physical mappings), i.e. L1 can't rely on the
- *   (virtual) CPU to flush stale linear mappings for either L2 or itself (L1).
- *
- * - however if VPID is disabled by L1, then a sync is needed as L1 expects all
- *   linear mappings (EPT is disabled so there are no combined or guest-physical
- *   mappings) to be invalidated on both VM-Enter and VM-Exit.
- *
- * Note, this logic is subtly different than nested_has_guest_tlb_tag(), which
- * additionally checks that L2 has been assigned a VPID (when EPT is disabled).
- * Whether or not L2 has been assigned a VPID by L0 is irrelevant with respect
- * to L1's expectations, e.g. L0 needs to invalidate hardware TLB entries if L2
- * doesn't have a unique VPID to prevent reusing L1's entries (assuming L1 has
- * been assigned a VPID), but L0 doesn't need to do a MMU sync because L1
- * doesn't expect stale (virtual) TLB entries to be flushed, i.e. L1 doesn't
- * know that L0 will flush the TLB and so L1 will do INVVPID as needed to flush
- * stale TLB entries, at which point L0 will sync L2's MMU.
- */
-static bool nested_vmx_transition_mmu_sync(struct kvm_vcpu *vcpu)
-{
-       return !enable_ept && !nested_cpu_has_vpid(get_vmcs12(vcpu));
-}
-
-/*
  * Load guest's/host's cr3 at nested entry/exit.  @nested_ept is true if we are
  * emulating VM-Entry into a guest with EPT enabled.  On failure, the expected
  * Exit Qualification (for a VM-Entry consistency check VM-Exit) is assigned to
  * @entry_failure_code.
  */
-static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept,
+static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
+                              bool nested_ept, bool reload_pdptrs,
                               enum vm_entry_failure_code *entry_failure_code)
 {
        if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3))) {
@@ -1117,27 +1086,20 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne
         * If PAE paging and EPT are both on, CR3 is not used by the CPU and
         * must not be dereferenced.
         */
-       if (!nested_ept && is_pae_paging(vcpu) &&
-           (cr3 != kvm_read_cr3(vcpu) || pdptrs_changed(vcpu))) {
-               if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))) {
-                       *entry_failure_code = ENTRY_FAIL_PDPTE;
-                       return -EINVAL;
-               }
+       if (reload_pdptrs && !nested_ept && is_pae_paging(vcpu) &&
+           CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))) {
+               *entry_failure_code = ENTRY_FAIL_PDPTE;
+               return -EINVAL;
        }
 
-       /*
-        * Unconditionally skip the TLB flush on fast CR3 switch, all TLB
-        * flushes are handled by nested_vmx_transition_tlb_flush().  See
-        * nested_vmx_transition_mmu_sync for details on skipping the MMU sync.
-        */
        if (!nested_ept)
-               kvm_mmu_new_pgd(vcpu, cr3, true,
-                               !nested_vmx_transition_mmu_sync(vcpu));
+               kvm_mmu_new_pgd(vcpu, cr3);
 
        vcpu->arch.cr3 = cr3;
        kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);
 
-       kvm_init_mmu(vcpu, false);
+       /* Re-initialize the MMU, e.g. to pick up CR4 MMU role changes. */
+       kvm_init_mmu(vcpu);
 
        return 0;
 }
@@ -1170,17 +1132,28 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
        /*
-        * If VPID is disabled, linear and combined mappings are flushed on
-        * VM-Enter/VM-Exit, and guest-physical mappings are valid only for
-        * their associated EPTP.
+        * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
+        * for *all* contexts to be flushed on VM-Enter/VM-Exit, i.e. it's a
+        * full TLB flush from the guest's perspective.  This is required even
+        * if VPID is disabled in the host as KVM may need to synchronize the
+        * MMU in response to the guest TLB flush.
+        *
+        * Note, using TLB_FLUSH_GUEST is correct even if nested EPT is in use.
+        * EPT is a special snowflake, as guest-physical mappings aren't
+        * flushed on VPID invalidations, including VM-Enter or VM-Exit with
+        * VPID disabled.  As a result, KVM _never_ needs to sync nEPT
+        * entries on VM-Enter because L1 can't rely on VM-Enter to flush
+        * those mappings.
         */
-       if (!enable_vpid)
+       if (!nested_cpu_has_vpid(vmcs12)) {
+               kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
                return;
+       }
+
+       /* L2 should never have a VPID if VPID is disabled. */
+       WARN_ON(!enable_vpid);
 
        /*
-        * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
-        * for *all* contexts to be flushed on VM-Enter/VM-Exit.
-        *
         * If VPID is enabled and used by vmc12, but L2 does not have a unique
         * TLB tag (ASID), i.e. EPT is disabled and KVM was unable to allocate
         * a VPID for L2, flush the current context as the effective ASID is
@@ -1192,13 +1165,12 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
         *
         * If a TLB flush isn't required due to any of the above, and vpid12 is
         * changing then the new "virtual" VPID (vpid12) will reuse the same
-        * "real" VPID (vpid02), and so needs to be sync'd.  There is no direct
+        * "real" VPID (vpid02), and so needs to be flushed.  There's no direct
         * mapping between vpid02 and vpid12, vpid02 is per-vCPU and reused for
-        * all nested vCPUs.
+        * all nested vCPUs.  Remember, a flush on VM-Enter does not invalidate
+        * guest-physical mappings, so there is no need to sync the nEPT MMU.
         */
-       if (!nested_cpu_has_vpid(vmcs12)) {
-               kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
-       } else if (!nested_has_guest_tlb_tag(vcpu)) {
+       if (!nested_has_guest_tlb_tag(vcpu)) {
                kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
        } else if (is_vmenter &&
                   vmcs12->virtual_processor_id != vmx->nested.last_vpid) {
@@ -1586,7 +1558,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
        vmcs_load(vmx->loaded_vmcs->vmcs);
 }
 
-static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
+static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
 {
        struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
        struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
@@ -1595,7 +1567,7 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
        vmcs12->tpr_threshold = evmcs->tpr_threshold;
        vmcs12->guest_rip = evmcs->guest_rip;
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC))) {
                vmcs12->guest_rsp = evmcs->guest_rsp;
                vmcs12->guest_rflags = evmcs->guest_rflags;
@@ -1603,23 +1575,23 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                        evmcs->guest_interruptibility_info;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC))) {
                vmcs12->cpu_based_vm_exec_control =
                        evmcs->cpu_based_vm_exec_control;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN))) {
                vmcs12->exception_bitmap = evmcs->exception_bitmap;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY))) {
                vmcs12->vm_entry_controls = evmcs->vm_entry_controls;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT))) {
                vmcs12->vm_entry_intr_info_field =
                        evmcs->vm_entry_intr_info_field;
@@ -1629,7 +1601,7 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                        evmcs->vm_entry_instruction_len;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1))) {
                vmcs12->host_ia32_pat = evmcs->host_ia32_pat;
                vmcs12->host_ia32_efer = evmcs->host_ia32_efer;
@@ -1649,7 +1621,7 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                vmcs12->host_tr_selector = evmcs->host_tr_selector;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1))) {
                vmcs12->pin_based_vm_exec_control =
                        evmcs->pin_based_vm_exec_control;
@@ -1658,18 +1630,18 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                        evmcs->secondary_vm_exec_control;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP))) {
                vmcs12->io_bitmap_a = evmcs->io_bitmap_a;
                vmcs12->io_bitmap_b = evmcs->io_bitmap_b;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP))) {
                vmcs12->msr_bitmap = evmcs->msr_bitmap;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2))) {
                vmcs12->guest_es_base = evmcs->guest_es_base;
                vmcs12->guest_cs_base = evmcs->guest_cs_base;
@@ -1709,14 +1681,14 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                vmcs12->guest_tr_selector = evmcs->guest_tr_selector;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2))) {
                vmcs12->tsc_offset = evmcs->tsc_offset;
                vmcs12->virtual_apic_page_addr = evmcs->virtual_apic_page_addr;
                vmcs12->xss_exit_bitmap = evmcs->xss_exit_bitmap;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR))) {
                vmcs12->cr0_guest_host_mask = evmcs->cr0_guest_host_mask;
                vmcs12->cr4_guest_host_mask = evmcs->cr4_guest_host_mask;
@@ -1728,7 +1700,7 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                vmcs12->guest_dr7 = evmcs->guest_dr7;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER))) {
                vmcs12->host_fs_base = evmcs->host_fs_base;
                vmcs12->host_gs_base = evmcs->host_gs_base;
@@ -1738,13 +1710,13 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
                vmcs12->host_rsp = evmcs->host_rsp;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT))) {
                vmcs12->ept_pointer = evmcs->ept_pointer;
                vmcs12->virtual_processor_id = evmcs->virtual_processor_id;
        }
 
-       if (unlikely(!(evmcs->hv_clean_fields &
+       if (unlikely(!(hv_clean_fields &
                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1))) {
                vmcs12->vmcs_link_pointer = evmcs->vmcs_link_pointer;
                vmcs12->guest_ia32_debugctl = evmcs->guest_ia32_debugctl;
@@ -1799,10 +1771,10 @@ static int copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx)
         * vmcs12->exit_io_instruction_eip = evmcs->exit_io_instruction_eip;
         */
 
-       return 0;
+       return;
 }
 
-static int copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
+static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
 {
        struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
        struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
@@ -1962,7 +1934,7 @@ static int copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
 
        evmcs->guest_bndcfgs = vmcs12->guest_bndcfgs;
 
-       return 0;
+       return;
 }
 
 /*
@@ -1979,13 +1951,13 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
        if (likely(!vmx->nested.enlightened_vmcs_enabled))
                return EVMPTRLD_DISABLED;
 
-       if (!nested_enlightened_vmentry(vcpu, &evmcs_gpa))
+       if (!nested_enlightened_vmentry(vcpu, &evmcs_gpa)) {
+               nested_release_evmcs(vcpu);
                return EVMPTRLD_DISABLED;
+       }
 
-       if (unlikely(!vmx->nested.hv_evmcs ||
-                    evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
-               if (!vmx->nested.hv_evmcs)
-                       vmx->nested.current_vmptr = -1ull;
+       if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
+               vmx->nested.current_vmptr = -1ull;
 
                nested_release_evmcs(vcpu);
 
@@ -2023,7 +1995,6 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
                        return EVMPTRLD_VMFAIL;
                }
 
-               vmx->nested.dirty_vmcs12 = true;
                vmx->nested.hv_evmcs_vmptr = evmcs_gpa;
 
                evmcs_gpa_changed = true;
@@ -2056,14 +2027,10 @@ void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (vmx->nested.hv_evmcs) {
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                copy_vmcs12_to_enlightened(vmx);
-               /* All fields are clean */
-               vmx->nested.hv_evmcs->hv_clean_fields |=
-                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
-       } else {
+       else
                copy_vmcs12_to_shadow(vmx);
-       }
 
        vmx->nested.need_vmcs12_to_shadow_sync = false;
 }
@@ -2208,7 +2175,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
        u32 exec_control;
        u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
 
-       if (vmx->nested.dirty_vmcs12 || vmx->nested.hv_evmcs)
+       if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                prepare_vmcs02_early_rare(vmx, vmcs12);
 
        /*
@@ -2277,7 +2244,8 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
                                  SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                                  SECONDARY_EXEC_APIC_REGISTER_VIRT |
-                                 SECONDARY_EXEC_ENABLE_VMFUNC);
+                                 SECONDARY_EXEC_ENABLE_VMFUNC |
+                                 SECONDARY_EXEC_TSC_SCALING);
                if (nested_cpu_has(vmcs12,
                                   CPU_BASED_ACTIVATE_SECONDARY_CONTROLS))
                        exec_control |= vmcs12->secondary_vm_exec_control;
@@ -2488,18 +2456,18 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
  * is assigned to entry_failure_code on failure.
  */
 static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
+                         bool from_vmentry,
                          enum vm_entry_failure_code *entry_failure_code)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
        bool load_guest_pdptrs_vmcs12 = false;
 
-       if (vmx->nested.dirty_vmcs12 || hv_evmcs) {
+       if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
                prepare_vmcs02_rare(vmx, vmcs12);
                vmx->nested.dirty_vmcs12 = false;
 
-               load_guest_pdptrs_vmcs12 = !hv_evmcs ||
-                       !(hv_evmcs->hv_clean_fields &
+               load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
+                       !(vmx->nested.hv_evmcs->hv_clean_fields &
                          HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
        }
 
@@ -2532,10 +2500,18 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat);
        }
 
-       vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
+       vcpu->arch.tsc_offset = kvm_calc_nested_tsc_offset(
+                       vcpu->arch.l1_tsc_offset,
+                       vmx_get_l2_tsc_offset(vcpu),
+                       vmx_get_l2_tsc_multiplier(vcpu));
 
+       vcpu->arch.tsc_scaling_ratio = kvm_calc_nested_tsc_multiplier(
+                       vcpu->arch.l1_tsc_scaling_ratio,
+                       vmx_get_l2_tsc_multiplier(vcpu));
+
+       vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
        if (kvm_has_tsc_control)
-               decache_tsc_multiplier(vmx);
+               vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio);
 
        nested_vmx_transition_tlb_flush(vcpu, vmcs12, true);
 
@@ -2572,7 +2548,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 
        /* Shadow page tables on either EPT or shadow page tables. */
        if (nested_vmx_load_cr3(vcpu, vmcs12->guest_cr3, nested_cpu_has_ept(vmcs12),
-                               entry_failure_code))
+                               from_vmentry, entry_failure_code))
                return -EINVAL;
 
        /*
@@ -2604,6 +2580,17 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 
        kvm_rsp_write(vcpu, vmcs12->guest_rsp);
        kvm_rip_write(vcpu, vmcs12->guest_rip);
+
+       /*
+        * It was observed that genuine Hyper-V running in L1 doesn't reset
+        * 'hv_clean_fields' by itself, it only sets the corresponding dirty
+        * bits when it changes a field in eVMCS. Mark all fields as clean
+        * here.
+        */
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+               vmx->nested.hv_evmcs->hv_clean_fields |=
+                       HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
+
        return 0;
 }
 
@@ -3093,13 +3080,20 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
         * L2 was running), map it here to make sure vmcs12 changes are
         * properly reflected.
         */
-       if (vmx->nested.enlightened_vmcs_enabled && !vmx->nested.hv_evmcs) {
+       if (vmx->nested.enlightened_vmcs_enabled &&
+           vmx->nested.hv_evmcs_vmptr == EVMPTR_MAP_PENDING) {
                enum nested_evmptrld_status evmptrld_status =
                        nested_vmx_handle_enlightened_vmptrld(vcpu, false);
 
                if (evmptrld_status == EVMPTRLD_VMFAIL ||
                    evmptrld_status == EVMPTRLD_ERROR)
                        return false;
+
+               /*
+                * Post migration VMCS12 always provides the most actual
+                * information, copy it to eVMCS upon entry.
+                */
+               vmx->nested.need_vmcs12_to_shadow_sync = true;
        }
 
        return true;
@@ -3113,6 +3107,18 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
        struct page *page;
        u64 hpa;
 
+       if (!vcpu->arch.pdptrs_from_userspace &&
+           !nested_cpu_has_ept(vmcs12) && is_pae_paging(vcpu)) {
+               /*
+                * Reload the guest's PDPTRs since after a migration
+                * the guest CR3 might be restored prior to setting the nested
+                * state which can lead to a load of wrong PDPTRs.
+                */
+               if (CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3)))
+                       return false;
+       }
+
+
        if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) {
                /*
                 * Translate L1 physical address to host physical
@@ -3175,6 +3181,15 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
                                offset_in_page(vmcs12->posted_intr_desc_addr));
                        vmcs_write64(POSTED_INTR_DESC_ADDR,
                                     pfn_to_hpa(map->pfn) + offset_in_page(vmcs12->posted_intr_desc_addr));
+               } else {
+                       /*
+                        * Defer the KVM_INTERNAL_EXIT until KVM tries to
+                        * access the contents of the VMCS12 posted interrupt
+                        * descriptor. (Note that KVM may do this when it
+                        * should not, per the architectural specification.)
+                        */
+                       vmx->nested.pi_desc = NULL;
+                       pin_controls_clearbit(vmx, PIN_BASED_POSTED_INTR);
                }
        }
        if (nested_vmx_prepare_msr_bitmap(vcpu, vmcs12))
@@ -3354,10 +3369,8 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
        }
 
        enter_guest_mode(vcpu);
-       if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
-               vcpu->arch.tsc_offset += vmcs12->tsc_offset;
 
-       if (prepare_vmcs02(vcpu, vmcs12, &entry_failure_code)) {
+       if (prepare_vmcs02(vcpu, vmcs12, from_vmentry, &entry_failure_code)) {
                exit_reason.basic = EXIT_REASON_INVALID_STATE;
                vmcs12->exit_qualification = entry_failure_code;
                goto vmentry_fail_vmexit_guest_mode;
@@ -3437,7 +3450,7 @@ vmentry_fail_vmexit:
 
        load_vmcs12_host_state(vcpu, vmcs12);
        vmcs12->vm_exit_reason = exit_reason.full;
-       if (enable_shadow_vmcs || vmx->nested.hv_evmcs)
+       if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                vmx->nested.need_vmcs12_to_shadow_sync = true;
        return NVMX_VMENTRY_VMEXIT;
 }
@@ -3454,8 +3467,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        u32 interrupt_shadow = vmx_get_interrupt_shadow(vcpu);
        enum nested_evmptrld_status evmptrld_status;
 
-       ++vcpu->stat.nested_run;
-
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
@@ -3467,7 +3478,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                return nested_vmx_failInvalid(vcpu);
        }
 
-       if (CC(!vmx->nested.hv_evmcs && vmx->nested.current_vmptr == -1ull))
+       if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) &&
+              vmx->nested.current_vmptr == -1ull))
                return nested_vmx_failInvalid(vcpu);
 
        vmcs12 = get_vmcs12(vcpu);
@@ -3481,8 +3493,8 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (CC(vmcs12->hdr.shadow_vmcs))
                return nested_vmx_failInvalid(vcpu);
 
-       if (vmx->nested.hv_evmcs) {
-               copy_enlightened_to_vmcs12(vmx);
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+               copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
                /* Enlightened VMCS doesn't have launch state */
                vmcs12->launch_state = !launch;
        } else if (enable_shadow_vmcs) {
@@ -3682,25 +3694,29 @@ void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu)
        }
 }
 
-static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        int max_irr;
        void *vapic_page;
        u16 status;
 
-       if (!vmx->nested.pi_desc || !vmx->nested.pi_pending)
-               return;
+       if (!vmx->nested.pi_pending)
+               return 0;
+
+       if (!vmx->nested.pi_desc)
+               goto mmio_needed;
 
        vmx->nested.pi_pending = false;
+
        if (!pi_test_and_clear_on(vmx->nested.pi_desc))
-               return;
+               return 0;
 
        max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256);
        if (max_irr != 256) {
                vapic_page = vmx->nested.virtual_apic_map.hva;
                if (!vapic_page)
-                       return;
+                       goto mmio_needed;
 
                __kvm_apic_update_irr(vmx->nested.pi_desc->pir,
                        vapic_page, &max_irr);
@@ -3713,6 +3729,11 @@ static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
        }
 
        nested_mark_vmcs12_pages_dirty(vcpu);
+       return 0;
+
+mmio_needed:
+       kvm_handle_memory_failure(vcpu, X86EMUL_IO_NEEDED, NULL);
+       return -ENXIO;
 }
 
 static void nested_vmx_inject_exception_vmexit(struct kvm_vcpu *vcpu,
@@ -3887,8 +3908,7 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
        }
 
 no_vmexit:
-       vmx_complete_nested_posted_interrupt(vcpu);
-       return 0;
+       return vmx_complete_nested_posted_interrupt(vcpu);
 }
 
 static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
@@ -4032,10 +4052,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (vmx->nested.hv_evmcs)
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
 
-       vmx->nested.need_sync_vmcs02_to_vmcs12_rare = !vmx->nested.hv_evmcs;
+       vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
+               !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
 
        vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
        vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
@@ -4206,7 +4227,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
         * Only PDPTE load can fail as the value of cr3 was checked on entry and
         * couldn't have changed.
         */
-       if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, &ignored))
+       if (nested_vmx_load_cr3(vcpu, vmcs12->host_cr3, false, true, &ignored))
                nested_vmx_abort(vcpu, VMX_ABORT_LOAD_HOST_PDPTE_FAIL);
 
        nested_vmx_transition_tlb_flush(vcpu, vmcs12, false);
@@ -4463,8 +4484,11 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
        if (nested_cpu_has_preemption_timer(vmcs12))
                hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
 
-       if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
-               vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
+       if (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETTING)) {
+               vcpu->arch.tsc_offset = vcpu->arch.l1_tsc_offset;
+               if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_TSC_SCALING))
+                       vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
+       }
 
        if (likely(!vmx->fail)) {
                sync_vmcs02_to_vmcs12(vcpu, vmcs12);
@@ -4501,12 +4525,12 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
        vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
        vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
        vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
+       if (kvm_has_tsc_control)
+               vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio);
+
        if (vmx->nested.l1_tpr_threshold != -1)
                vmcs_write32(TPR_THRESHOLD, vmx->nested.l1_tpr_threshold);
 
-       if (kvm_has_tsc_control)
-               decache_tsc_multiplier(vmx);
-
        if (vmx->nested.change_vmcs01_virtual_apic_mode) {
                vmx->nested.change_vmcs01_virtual_apic_mode = false;
                vmx_set_virtual_apic_mode(vcpu);
@@ -4532,7 +4556,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
        }
 
        if ((vm_exit_reason != -1) &&
-           (enable_shadow_vmcs || vmx->nested.hv_evmcs))
+           (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
                vmx->nested.need_vmcs12_to_shadow_sync = true;
 
        /* in case we halted in L2 */
@@ -4987,6 +5011,8 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
                                     vmptr + offsetof(struct vmcs12,
                                                      launch_state),
                                     &zero, sizeof(zero));
+       } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) {
+               nested_release_evmcs(vcpu);
        }
 
        return nested_vmx_succeed(vcpu);
@@ -5228,7 +5254,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
 
        /* Forbid normal VMPTRLD if Enlightened version was used */
-       if (vmx->nested.hv_evmcs)
+       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
                return 1;
 
        if (vmx->nested.current_vmptr != vmptr) {
@@ -5284,7 +5310,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       if (unlikely(to_vmx(vcpu)->nested.hv_evmcs))
+       if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr)))
                return 1;
 
        if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
@@ -5461,8 +5487,8 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
 
        /*
         * Sync the shadow page tables if EPT is disabled, L1 is invalidating
-        * linear mappings for L2 (tagged with L2's VPID).  Free all roots as
-        * VPIDs are not tracked in the MMU role.
+        * linear mappings for L2 (tagged with L2's VPID).  Free all guest
+        * roots as VPIDs are not tracked in the MMU role.
         *
         * Note, this operates on root_mmu, not guest_mmu, as L1 and L2 share
         * an MMU when EPT is disabled.
@@ -5470,8 +5496,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
         * TODO: sync only the affected SPTEs for INVDIVIDUAL_ADDR.
         */
        if (!enable_ept)
-               kvm_mmu_free_roots(vcpu, &vcpu->arch.root_mmu,
-                                  KVM_MMU_ROOTS_ALL);
+               kvm_mmu_free_guest_mode_roots(vcpu, &vcpu->arch.root_mmu);
 
        return nested_vmx_succeed(vcpu);
 }
@@ -5481,23 +5506,16 @@ static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu,
 {
        u32 index = kvm_rcx_read(vcpu);
        u64 new_eptp;
-       bool accessed_dirty;
-       struct kvm_mmu *mmu = vcpu->arch.walk_mmu;
 
-       if (!nested_cpu_has_eptp_switching(vmcs12) ||
-           !nested_cpu_has_ept(vmcs12))
+       if (WARN_ON_ONCE(!nested_cpu_has_ept(vmcs12)))
                return 1;
-
        if (index >= VMFUNC_EPTP_ENTRIES)
                return 1;
 
-
        if (kvm_vcpu_read_guest_page(vcpu, vmcs12->eptp_list_address >> PAGE_SHIFT,
                                     &new_eptp, index * 8, 8))
                return 1;
 
-       accessed_dirty = !!(new_eptp & VMX_EPTP_AD_ENABLE_BIT);
-
        /*
         * If the (L2) guest does a vmfunc to the currently
         * active ept pointer, we don't have to do anything else
@@ -5506,11 +5524,11 @@ static int nested_vmx_eptp_switching(struct kvm_vcpu *vcpu,
                if (!nested_vmx_check_eptp(vcpu, new_eptp))
                        return 1;
 
-               mmu->ept_ad = accessed_dirty;
-               mmu->mmu_role.base.ad_disabled = !accessed_dirty;
                vmcs12->ept_pointer = new_eptp;
+               nested_ept_new_eptp(vcpu);
 
-               kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
+               if (!nested_cpu_has_vpid(vmcs12))
+                       kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
        }
 
        return 0;
@@ -5533,7 +5551,17 @@ static int handle_vmfunc(struct kvm_vcpu *vcpu)
        }
 
        vmcs12 = get_vmcs12(vcpu);
-       if ((vmcs12->vm_function_control & (1 << function)) == 0)
+
+       /*
+        * #UD on out-of-bounds function has priority over VM-Exit, and VMFUNC
+        * is enabled in vmcs02 if and only if it's enabled in vmcs12.
+        */
+       if (WARN_ON_ONCE((function > 63) || !nested_cpu_has_vmfunc(vmcs12))) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return 1;
+       }
+
+       if (!(vmcs12->vm_function_control & BIT_ULL(function)))
                goto fail;
 
        switch (function) {
@@ -5806,6 +5834,9 @@ static bool nested_vmx_l0_wants_exit(struct kvm_vcpu *vcpu,
                else if (is_breakpoint(intr_info) &&
                         vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
                        return true;
+               else if (is_alignment_check(intr_info) &&
+                        !vmx_guest_inject_ac(vcpu))
+                       return true;
                return false;
        case EXIT_REASON_EXTERNAL_INTERRUPT:
                return true;
@@ -6056,7 +6087,8 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
                if (vmx_has_valid_vmcs12(vcpu)) {
                        kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
 
-                       if (vmx->nested.hv_evmcs)
+                       /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
+                       if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
                                kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
 
                        if (is_guest_mode(vcpu) &&
@@ -6112,8 +6144,15 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
        } else  {
                copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
                if (!vmx->nested.need_vmcs12_to_shadow_sync) {
-                       if (vmx->nested.hv_evmcs)
-                               copy_enlightened_to_vmcs12(vmx);
+                       if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+                               /*
+                                * L1 hypervisor is not obliged to keep eVMCS
+                                * clean fields data always up-to-date while
+                                * not in guest mode, 'hv_clean_fields' is only
+                                * supposed to be actual upon vmentry so we need
+                                * to ignore it here and do full copy.
+                                */
+                               copy_enlightened_to_vmcs12(vmx, 0);
                        else if (enable_shadow_vmcs)
                                copy_shadow_to_vmcs12(vmx);
                }
@@ -6255,6 +6294,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
                 * restored yet. EVMCS will be mapped from
                 * nested_get_vmcs12_pages().
                 */
+               vmx->nested.hv_evmcs_vmptr = EVMPTR_MAP_PENDING;
                kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
        } else {
                return -EINVAL;
@@ -6339,6 +6379,40 @@ void nested_vmx_set_vmcs_shadowing_bitmap(void)
 }
 
 /*
+ * Indexing into the vmcs12 uses the VMCS encoding rotated left by 6.  Undo
+ * that madness to get the encoding for comparison.
+ */
+#define VMCS12_IDX_TO_ENC(idx) ((u16)(((u16)(idx) >> 6) | ((u16)(idx) << 10)))
+
+static u64 nested_vmx_calc_vmcs_enum_msr(void)
+{
+       /*
+        * Note these are the so called "index" of the VMCS field encoding, not
+        * the index into vmcs12.
+        */
+       unsigned int max_idx, idx;
+       int i;
+
+       /*
+        * For better or worse, KVM allows VMREAD/VMWRITE to all fields in
+        * vmcs12, regardless of whether or not the associated feature is
+        * exposed to L1.  Simply find the field with the highest index.
+        */
+       max_idx = 0;
+       for (i = 0; i < nr_vmcs12_fields; i++) {
+               /* The vmcs12 table is very, very sparsely populated. */
+               if (!vmcs_field_to_offset_table[i])
+                       continue;
+
+               idx = vmcs_field_index(VMCS12_IDX_TO_ENC(i));
+               if (idx > max_idx)
+                       max_idx = idx;
+       }
+
+       return (u64)max_idx << VMCS_FIELD_INDEX_SHIFT;
+}
+
+/*
  * nested_vmx_setup_ctls_msrs() sets up variables containing the values to be
  * returned for the various VMX controls MSRs when nested VMX is enabled.
  * The same values should also be used to verify that vmcs12 control fields are
@@ -6474,7 +6548,8 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)
                SECONDARY_EXEC_RDRAND_EXITING |
                SECONDARY_EXEC_ENABLE_INVPCID |
                SECONDARY_EXEC_RDSEED_EXITING |
-               SECONDARY_EXEC_XSAVES;
+               SECONDARY_EXEC_XSAVES |
+               SECONDARY_EXEC_TSC_SCALING;
 
        /*
         * We can emulate "VMCS shadowing," even if the hardware
@@ -6582,8 +6657,7 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)
        rdmsrl(MSR_IA32_VMX_CR0_FIXED1, msrs->cr0_fixed1);
        rdmsrl(MSR_IA32_VMX_CR4_FIXED1, msrs->cr4_fixed1);
 
-       /* highest index: VMX_PREEMPTION_TIMER_VALUE */
-       msrs->vmcs_enum = VMCS12_MAX_FIELD_INDEX << 1;
+       msrs->vmcs_enum = nested_vmx_calc_vmcs_enum_msr();
 }
 
 void nested_vmx_hardware_unsetup(void)
index 184418b..b69a80f 100644 (file)
@@ -56,14 +56,9 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       /*
-        * In case we do two consecutive get/set_nested_state()s while L2 was
-        * running hv_evmcs may end up not being mapped (we map it from
-        * nested_vmx_run()/vmx_vcpu_run()). Check is_guest_mode() as we always
-        * have vmcs12 if it is true.
-        */
-       return is_guest_mode(vcpu) || vmx->nested.current_vmptr != -1ull ||
-               vmx->nested.hv_evmcs;
+       /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
+       return vmx->nested.current_vmptr != -1ull ||
+               vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID;
 }
 
 static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
index 1472c6c..4b9957e 100644 (file)
@@ -117,6 +117,11 @@ static inline bool is_gp_fault(u32 intr_info)
        return is_exception_n(intr_info, GP_VECTOR);
 }
 
+static inline bool is_alignment_check(u32 intr_info)
+{
+       return is_exception_n(intr_info, AC_VECTOR);
+}
+
 static inline bool is_machine_check(u32 intr_info)
 {
        return is_exception_n(intr_info, MC_VECTOR);
@@ -164,4 +169,12 @@ static inline int vmcs_field_readonly(unsigned long field)
        return (((field >> 10) & 0x3) == 1);
 }
 
+#define VMCS_FIELD_INDEX_SHIFT         (1)
+#define VMCS_FIELD_INDEX_MASK          GENMASK(9, 1)
+
+static inline unsigned int vmcs_field_index(unsigned long field)
+{
+       return (field & VMCS_FIELD_INDEX_MASK) >> VMCS_FIELD_INDEX_SHIFT;
+}
+
 #endif /* __KVM_X86_VMX_VMCS_H */
index 034adb6..d9f5d7c 100644 (file)
@@ -37,6 +37,7 @@ const unsigned short vmcs_field_to_offset_table[] = {
        FIELD64(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr),
        FIELD64(PML_ADDRESS, pml_address),
        FIELD64(TSC_OFFSET, tsc_offset),
+       FIELD64(TSC_MULTIPLIER, tsc_multiplier),
        FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr),
        FIELD64(APIC_ACCESS_ADDR, apic_access_addr),
        FIELD64(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr),
index 1349495..5e0e1b3 100644 (file)
@@ -70,7 +70,8 @@ struct __packed vmcs12 {
        u64 eptp_list_address;
        u64 pml_address;
        u64 encls_exiting_bitmap;
-       u64 padding64[2]; /* room for future expansion */
+       u64 tsc_multiplier;
+       u64 padding64[1]; /* room for future expansion */
        /*
         * To allow migration of L1 (complete with its L2 guests) between
         * machines of different natural widths (32 or 64 bit), we cannot have
@@ -205,12 +206,6 @@ struct __packed vmcs12 {
 #define VMCS12_SIZE            KVM_STATE_NESTED_VMX_VMCS_SIZE
 
 /*
- * VMCS12_MAX_FIELD_INDEX is the highest index value used in any
- * supported VMCS12 field encoding.
- */
-#define VMCS12_MAX_FIELD_INDEX 0x17
-
-/*
  * For save/restore compatibility, the vmcs12 field offsets must not change.
  */
 #define CHECK_OFFSET(field, loc)                               \
@@ -258,6 +253,7 @@ static inline void vmx_check_vmcs12_offsets(void)
        CHECK_OFFSET(eptp_list_address, 304);
        CHECK_OFFSET(pml_address, 312);
        CHECK_OFFSET(encls_exiting_bitmap, 320);
+       CHECK_OFFSET(tsc_multiplier, 328);
        CHECK_OFFSET(cr0_guest_host_mask, 344);
        CHECK_OFFSET(cr4_guest_host_mask, 352);
        CHECK_OFFSET(cr0_read_shadow, 360);
index 50b42d7..927a552 100644 (file)
@@ -52,6 +52,7 @@
 #include "cpuid.h"
 #include "evmcs.h"
 #include "hyperv.h"
+#include "kvm_onhyperv.h"
 #include "irq.h"
 #include "kvm_cache_regs.h"
 #include "lapic.h"
@@ -101,7 +102,6 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
-bool __read_mostly enable_apicv = 1;
 module_param(enable_apicv, bool, S_IRUGO);
 
 /*
@@ -459,86 +459,6 @@ static unsigned long host_idt_base;
 static bool __read_mostly enlightened_vmcs = true;
 module_param(enlightened_vmcs, bool, 0444);
 
-static int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush,
-               void *data)
-{
-       struct kvm_tlb_range *range = data;
-
-       return hyperv_fill_flush_guest_mapping_list(flush, range->start_gfn,
-                       range->pages);
-}
-
-static inline int hv_remote_flush_root_ept(hpa_t root_ept,
-                                          struct kvm_tlb_range *range)
-{
-       if (range)
-               return hyperv_flush_guest_mapping_range(root_ept,
-                               kvm_fill_hv_flush_list_func, (void *)range);
-       else
-               return hyperv_flush_guest_mapping(root_ept);
-}
-
-static int hv_remote_flush_tlb_with_range(struct kvm *kvm,
-               struct kvm_tlb_range *range)
-{
-       struct kvm_vmx *kvm_vmx = to_kvm_vmx(kvm);
-       struct kvm_vcpu *vcpu;
-       int ret = 0, i, nr_unique_valid_roots;
-       hpa_t root;
-
-       spin_lock(&kvm_vmx->hv_root_ept_lock);
-
-       if (!VALID_PAGE(kvm_vmx->hv_root_ept)) {
-               nr_unique_valid_roots = 0;
-
-               /*
-                * Flush all valid roots, and see if all vCPUs have converged
-                * on a common root, in which case future flushes can skip the
-                * loop and flush the common root.
-                */
-               kvm_for_each_vcpu(i, vcpu, kvm) {
-                       root = to_vmx(vcpu)->hv_root_ept;
-                       if (!VALID_PAGE(root) || root == kvm_vmx->hv_root_ept)
-                               continue;
-
-                       /*
-                        * Set the tracked root to the first valid root.  Keep
-                        * this root for the entirety of the loop even if more
-                        * roots are encountered as a low effort optimization
-                        * to avoid flushing the same (first) root again.
-                        */
-                       if (++nr_unique_valid_roots == 1)
-                               kvm_vmx->hv_root_ept = root;
-
-                       if (!ret)
-                               ret = hv_remote_flush_root_ept(root, range);
-
-                       /*
-                        * Stop processing roots if a failure occurred and
-                        * multiple valid roots have already been detected.
-                        */
-                       if (ret && nr_unique_valid_roots > 1)
-                               break;
-               }
-
-               /*
-                * The optimized flush of a single root can't be used if there
-                * are multiple valid roots (obviously).
-                */
-               if (nr_unique_valid_roots > 1)
-                       kvm_vmx->hv_root_ept = INVALID_PAGE;
-       } else {
-               ret = hv_remote_flush_root_ept(kvm_vmx->hv_root_ept, range);
-       }
-
-       spin_unlock(&kvm_vmx->hv_root_ept_lock);
-       return ret;
-}
-static int hv_remote_flush_tlb(struct kvm *kvm)
-{
-       return hv_remote_flush_tlb_with_range(kvm, NULL);
-}
-
 static int hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu)
 {
        struct hv_enlightened_vmcs *evmcs;
@@ -566,21 +486,6 @@ static int hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu)
 
 #endif /* IS_ENABLED(CONFIG_HYPERV) */
 
-static void hv_track_root_ept(struct kvm_vcpu *vcpu, hpa_t root_ept)
-{
-#if IS_ENABLED(CONFIG_HYPERV)
-       struct kvm_vmx *kvm_vmx = to_kvm_vmx(vcpu->kvm);
-
-       if (kvm_x86_ops.tlb_remote_flush == hv_remote_flush_tlb) {
-               spin_lock(&kvm_vmx->hv_root_ept_lock);
-               to_vmx(vcpu)->hv_root_ept = root_ept;
-               if (root_ept != kvm_vmx->hv_root_ept)
-                       kvm_vmx->hv_root_ept = INVALID_PAGE;
-               spin_unlock(&kvm_vmx->hv_root_ept_lock);
-       }
-#endif
-}
-
 /*
  * Comment's format: document - errata name - stepping - processor name.
  * Refer from
@@ -842,16 +747,21 @@ void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu)
        if (is_guest_mode(vcpu))
                eb |= get_vmcs12(vcpu)->exception_bitmap;
         else {
-               /*
-                * If EPT is enabled, #PF is only trapped if MAXPHYADDR is mismatched
-                * between guest and host.  In that case we only care about present
-                * faults.  For vmcs02, however, PFEC_MASK and PFEC_MATCH are set in
-                * prepare_vmcs02_rare.
-                */
-               bool selective_pf_trap = enable_ept && (eb & (1u << PF_VECTOR));
-               int mask = selective_pf_trap ? PFERR_PRESENT_MASK : 0;
+               int mask = 0, match = 0;
+
+               if (enable_ept && (eb & (1u << PF_VECTOR))) {
+                       /*
+                        * If EPT is enabled, #PF is currently only intercepted
+                        * if MAXPHYADDR is smaller on the guest than on the
+                        * host.  In that case we only care about present,
+                        * non-reserved faults.  For vmcs02, however, PFEC_MASK
+                        * and PFEC_MATCH are set in prepare_vmcs02_rare.
+                        */
+                       mask = PFERR_PRESENT_MASK | PFERR_RSVD_MASK;
+                       match = PFERR_PRESENT_MASK;
+               }
                vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, mask);
-               vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, mask);
+               vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, match);
        }
 
        vmcs_write32(EXCEPTION_BITMAP, eb);
@@ -1390,11 +1300,6 @@ void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu,
 
                vmx->loaded_vmcs->cpu = cpu;
        }
-
-       /* Setup TSC multiplier */
-       if (kvm_has_tsc_control &&
-           vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio)
-               decache_tsc_multiplier(vmx);
 }
 
 /*
@@ -1787,26 +1692,35 @@ static void setup_msrs(struct vcpu_vmx *vmx)
        vmx->guest_uret_msrs_loaded = false;
 }
 
-static u64 vmx_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu)
 {
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
-       u64 g_tsc_offset = 0;
 
-       /*
-        * We're here if L1 chose not to trap WRMSR to TSC. According
-        * to the spec, this should set L1's TSC; The offset that L1
-        * set for L2 remains unchanged, and still needs to be added
-        * to the newly set TSC to get L2's TSC.
-        */
-       if (is_guest_mode(vcpu) &&
-           (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING))
-               g_tsc_offset = vmcs12->tsc_offset;
+       if (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETTING))
+               return vmcs12->tsc_offset;
+
+       return 0;
+}
 
-       trace_kvm_write_tsc_offset(vcpu->vcpu_id,
-                                  vcpu->arch.tsc_offset - g_tsc_offset,
-                                  offset);
-       vmcs_write64(TSC_OFFSET, offset + g_tsc_offset);
-       return offset + g_tsc_offset;
+u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+
+       if (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETTING) &&
+           nested_cpu_has2(vmcs12, SECONDARY_EXEC_TSC_SCALING))
+               return vmcs12->tsc_multiplier;
+
+       return kvm_default_tsc_scaling_ratio;
+}
+
+static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+       vmcs_write64(TSC_OFFSET, offset);
+}
+
+static void vmx_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier)
+{
+       vmcs_write64(TSC_MULTIPLIER, multiplier);
 }
 
 /*
@@ -3181,7 +3095,7 @@ static void vmx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa,
                eptp = construct_eptp(vcpu, root_hpa, root_level);
                vmcs_write64(EPT_POINTER, eptp);
 
-               hv_track_root_ept(vcpu, root_hpa);
+               hv_track_root_tdp(vcpu, root_hpa);
 
                if (!enable_unrestricted_guest && !is_paging(vcpu))
                        guest_cr3 = to_kvm_vmx(kvm)->ept_identity_map_addr;
@@ -3707,7 +3621,7 @@ static int alloc_apic_access_page(struct kvm *kvm)
        int ret = 0;
 
        mutex_lock(&kvm->slots_lock);
-       if (kvm->arch.apic_access_page_done)
+       if (kvm->arch.apic_access_memslot_enabled)
                goto out;
        hva = __x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
                                      APIC_DEFAULT_PHYS_BASE, PAGE_SIZE);
@@ -3727,7 +3641,7 @@ static int alloc_apic_access_page(struct kvm *kvm)
         * is able to migrate it.
         */
        put_page(page);
-       kvm->arch.apic_access_page_done = true;
+       kvm->arch.apic_access_memslot_enabled = true;
 out:
        mutex_unlock(&kvm->slots_lock);
        return ret;
@@ -4829,7 +4743,7 @@ static int handle_machine_check(struct kvm_vcpu *vcpu)
  *  - Guest has #AC detection enabled in CR0
  *  - Guest EFLAGS has AC bit set
  */
-static inline bool guest_inject_ac(struct kvm_vcpu *vcpu)
+bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu)
 {
        if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
                return true;
@@ -4937,7 +4851,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                kvm_run->debug.arch.exception = ex_no;
                break;
        case AC_VECTOR:
-               if (guest_inject_ac(vcpu)) {
+               if (vmx_guest_inject_ac(vcpu)) {
                        kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
                        return 1;
                }
@@ -5810,6 +5724,8 @@ void dump_vmcs(struct kvm_vcpu *vcpu)
        if (cpu_has_secondary_exec_ctrls())
                secondary_exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
 
+       pr_err("VMCS %p, last attempted VM-entry on CPU %d\n",
+              vmx->loaded_vmcs->vmcs, vcpu->arch.last_vmentry_cpu);
        pr_err("*** Guest State ***\n");
        pr_err("CR0: actual=0x%016lx, shadow=0x%016lx, gh_mask=%016lx\n",
               vmcs_readl(GUEST_CR0), vmcs_readl(CR0_READ_SHADOW),
@@ -6247,6 +6163,7 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
        switch (kvm_get_apic_mode(vcpu)) {
        case LAPIC_MODE_INVALID:
                WARN_ONCE(true, "Invalid local APIC state");
+               break;
        case LAPIC_MODE_DISABLED:
                break;
        case LAPIC_MODE_XAPIC:
@@ -6805,7 +6722,18 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_load_host_xsave_state(vcpu);
 
-       vmx->nested.nested_run_pending = 0;
+       if (is_guest_mode(vcpu)) {
+               /*
+                * Track VMLAUNCH/VMRESUME that have made past guest state
+                * checking.
+                */
+               if (vmx->nested.nested_run_pending &&
+                   !vmx->exit_reason.failed_vmentry)
+                       ++vcpu->stat.nested_run;
+
+               vmx->nested.nested_run_pending = 0;
+       }
+
        vmx->idt_vectoring_info = 0;
 
        if (unlikely(vmx->fail)) {
@@ -6940,6 +6868,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
 
        vmx->nested.posted_intr_nv = -1;
        vmx->nested.current_vmptr = -1ull;
+       vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID;
 
        vcpu->arch.microcode_version = 0x100000000ULL;
        vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED;
@@ -6951,9 +6880,6 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
        vmx->pi_desc.nv = POSTED_INTR_VECTOR;
        vmx->pi_desc.sn = 1;
 
-#if IS_ENABLED(CONFIG_HYPERV)
-       vmx->hv_root_ept = INVALID_PAGE;
-#endif
        return 0;
 
 free_vmcs:
@@ -6970,10 +6896,6 @@ free_vpid:
 
 static int vmx_vm_init(struct kvm *kvm)
 {
-#if IS_ENABLED(CONFIG_HYPERV)
-       spin_lock_init(&to_kvm_vmx(kvm)->hv_root_ept_lock);
-#endif
-
        if (!ple_gap)
                kvm->arch.pause_in_guest = true;
 
@@ -7000,7 +6922,6 @@ static int vmx_vm_init(struct kvm *kvm)
                        break;
                }
        }
-       kvm_apicv_init(kvm, enable_apicv);
        return 0;
 }
 
@@ -7452,10 +7373,10 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
                delta_tsc = 0;
 
        /* Convert to host delta tsc if tsc scaling is enabled */
-       if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio &&
+       if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio &&
            delta_tsc && u64_shl_div_u64(delta_tsc,
                                kvm_tsc_scaling_ratio_frac_bits,
-                               vcpu->arch.tsc_scaling_ratio, &delta_tsc))
+                               vcpu->arch.l1_tsc_scaling_ratio, &delta_tsc))
                return -ERANGE;
 
        /*
@@ -7541,7 +7462,7 @@ static int vmx_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
        return !is_smm(vcpu);
 }
 
-static int vmx_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
+static int vmx_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
@@ -7555,7 +7476,7 @@ static int vmx_pre_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
        return 0;
 }
 
-static int vmx_pre_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
+static int vmx_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        int ret;
@@ -7699,7 +7620,10 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
 
        .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 
-       .write_l1_tsc_offset = vmx_write_l1_tsc_offset,
+       .get_l2_tsc_offset = vmx_get_l2_tsc_offset,
+       .get_l2_tsc_multiplier = vmx_get_l2_tsc_multiplier,
+       .write_tsc_offset = vmx_write_tsc_offset,
+       .write_tsc_multiplier = vmx_write_tsc_multiplier,
 
        .load_mmu_pgd = vmx_load_mmu_pgd,
 
@@ -7730,8 +7654,8 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .setup_mce = vmx_setup_mce,
 
        .smi_allowed = vmx_smi_allowed,
-       .pre_enter_smm = vmx_pre_enter_smm,
-       .pre_leave_smm = vmx_pre_leave_smm,
+       .enter_smm = vmx_enter_smm,
+       .leave_smm = vmx_leave_smm,
        .enable_smi_window = vmx_enable_smi_window,
 
        .can_emulate_instruction = vmx_can_emulate_instruction,
@@ -7806,6 +7730,12 @@ static __init int hardware_setup(void)
            !cpu_has_vmx_invept_global())
                enable_ept = 0;
 
+       /* NX support is required for shadow paging. */
+       if (!enable_ept && !boot_cpu_has(X86_FEATURE_NX)) {
+               pr_err_ratelimited("kvm: NX (Execute Disable) not supported\n");
+               return -EOPNOTSUPP;
+       }
+
        if (!cpu_has_vmx_ept_ad_bits() || !enable_ept)
                enable_ept_ad_bits = 0;
 
@@ -7995,6 +7925,8 @@ static void vmx_exit(void)
        }
 #endif
        vmx_cleanup_l1d_flush();
+
+       allow_smaller_maxphyaddr = false;
 }
 module_exit(vmx_exit);
 
index 16e4e45..3979a94 100644 (file)
@@ -322,8 +322,6 @@ struct vcpu_vmx {
        /* apic deadline value in host tsc */
        u64 hv_deadline_tsc;
 
-       u64 current_tsc_ratio;
-
        unsigned long host_debugctlmsr;
 
        /*
@@ -336,10 +334,6 @@ struct vcpu_vmx {
        /* SGX Launch Control public key hash */
        u64 msr_ia32_sgxlepubkeyhash[4];
 
-#if IS_ENABLED(CONFIG_HYPERV)
-       u64 hv_root_ept;
-#endif
-
        struct pt_desc pt_desc;
        struct lbr_desc lbr_desc;
 
@@ -357,11 +351,6 @@ struct kvm_vmx {
        unsigned int tss_addr;
        bool ept_identity_pagetable_done;
        gpa_t ept_identity_map_addr;
-
-#if IS_ENABLED(CONFIG_HYPERV)
-       hpa_t hv_root_ept;
-       spinlock_t hv_root_ept_lock;
-#endif
 };
 
 bool nested_vmx_allowed(struct kvm_vcpu *vcpu);
@@ -387,6 +376,7 @@ void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 void vmx_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 u64 construct_eptp(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level);
 
+bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu);
 void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu);
 void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu);
 bool vmx_nmi_blocked(struct kvm_vcpu *vcpu);
@@ -404,6 +394,9 @@ void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type);
 void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type);
 
+u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu);
+u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu);
+
 static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,
                                             int type, bool value)
 {
@@ -529,12 +522,6 @@ static inline struct vmcs *alloc_vmcs(bool shadow)
                              GFP_KERNEL_ACCOUNT);
 }
 
-static inline void decache_tsc_multiplier(struct vcpu_vmx *vmx)
-{
-       vmx->current_tsc_ratio = vmx->vcpu.arch.tsc_scaling_ratio;
-       vmcs_write64(TSC_MULTIPLIER, vmx->current_tsc_ratio);
-}
-
 static inline bool vmx_has_waitpkg(struct vcpu_vmx *vmx)
 {
        return vmx->secondary_exec_control &
index 6d3955a..17468d9 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/sched/isolation.h>
 #include <linux/mem_encrypt.h>
 #include <linux/entry-kvm.h>
+#include <linux/suspend.h>
 
 #include <trace/events/kvm.h>
 
@@ -102,6 +103,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 
 static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
 
+#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
+
 #define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
                                     KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
 
@@ -113,6 +116,9 @@ static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
 static void store_regs(struct kvm_vcpu *vcpu);
 static int sync_regs(struct kvm_vcpu *vcpu);
 
+static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2);
+static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2);
+
 struct kvm_x86_ops kvm_x86_ops __read_mostly;
 EXPORT_SYMBOL_GPL(kvm_x86_ops);
 
@@ -209,55 +215,78 @@ EXPORT_SYMBOL_GPL(host_efer);
 bool __read_mostly allow_smaller_maxphyaddr = 0;
 EXPORT_SYMBOL_GPL(allow_smaller_maxphyaddr);
 
+bool __read_mostly enable_apicv = true;
+EXPORT_SYMBOL_GPL(enable_apicv);
+
 u64 __read_mostly host_xss;
 EXPORT_SYMBOL_GPL(host_xss);
 u64 __read_mostly supported_xss;
 EXPORT_SYMBOL_GPL(supported_xss);
 
-struct kvm_stats_debugfs_item debugfs_entries[] = {
-       VCPU_STAT("pf_fixed", pf_fixed),
-       VCPU_STAT("pf_guest", pf_guest),
-       VCPU_STAT("tlb_flush", tlb_flush),
-       VCPU_STAT("invlpg", invlpg),
-       VCPU_STAT("exits", exits),
-       VCPU_STAT("io_exits", io_exits),
-       VCPU_STAT("mmio_exits", mmio_exits),
-       VCPU_STAT("signal_exits", signal_exits),
-       VCPU_STAT("irq_window", irq_window_exits),
-       VCPU_STAT("nmi_window", nmi_window_exits),
-       VCPU_STAT("halt_exits", halt_exits),
-       VCPU_STAT("halt_successful_poll", halt_successful_poll),
-       VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
-       VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
-       VCPU_STAT("halt_wakeup", halt_wakeup),
-       VCPU_STAT("hypercalls", hypercalls),
-       VCPU_STAT("request_irq", request_irq_exits),
-       VCPU_STAT("irq_exits", irq_exits),
-       VCPU_STAT("host_state_reload", host_state_reload),
-       VCPU_STAT("fpu_reload", fpu_reload),
-       VCPU_STAT("insn_emulation", insn_emulation),
-       VCPU_STAT("insn_emulation_fail", insn_emulation_fail),
-       VCPU_STAT("irq_injections", irq_injections),
-       VCPU_STAT("nmi_injections", nmi_injections),
-       VCPU_STAT("req_event", req_event),
-       VCPU_STAT("l1d_flush", l1d_flush),
-       VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
-       VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
-       VCPU_STAT("nested_run", nested_run),
-       VCPU_STAT("directed_yield_attempted", directed_yield_attempted),
-       VCPU_STAT("directed_yield_successful", directed_yield_successful),
-       VM_STAT("mmu_shadow_zapped", mmu_shadow_zapped),
-       VM_STAT("mmu_pte_write", mmu_pte_write),
-       VM_STAT("mmu_pde_zapped", mmu_pde_zapped),
-       VM_STAT("mmu_flooded", mmu_flooded),
-       VM_STAT("mmu_recycled", mmu_recycled),
-       VM_STAT("mmu_cache_miss", mmu_cache_miss),
-       VM_STAT("mmu_unsync", mmu_unsync),
-       VM_STAT("remote_tlb_flush", remote_tlb_flush),
-       VM_STAT("largepages", lpages, .mode = 0444),
-       VM_STAT("nx_largepages_splitted", nx_lpage_splits, .mode = 0444),
-       VM_STAT("max_mmu_page_hash_collisions", max_mmu_page_hash_collisions),
-       { NULL }
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+       KVM_GENERIC_VM_STATS(),
+       STATS_DESC_COUNTER(VM, mmu_shadow_zapped),
+       STATS_DESC_COUNTER(VM, mmu_pte_write),
+       STATS_DESC_COUNTER(VM, mmu_pde_zapped),
+       STATS_DESC_COUNTER(VM, mmu_flooded),
+       STATS_DESC_COUNTER(VM, mmu_recycled),
+       STATS_DESC_COUNTER(VM, mmu_cache_miss),
+       STATS_DESC_ICOUNTER(VM, mmu_unsync),
+       STATS_DESC_ICOUNTER(VM, lpages),
+       STATS_DESC_ICOUNTER(VM, nx_lpage_splits),
+       STATS_DESC_PCOUNTER(VM, max_mmu_page_hash_collisions)
+};
+static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
+               sizeof(struct kvm_vm_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vm_stats_desc),
+};
+
+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+       KVM_GENERIC_VCPU_STATS(),
+       STATS_DESC_COUNTER(VCPU, pf_fixed),
+       STATS_DESC_COUNTER(VCPU, pf_guest),
+       STATS_DESC_COUNTER(VCPU, tlb_flush),
+       STATS_DESC_COUNTER(VCPU, invlpg),
+       STATS_DESC_COUNTER(VCPU, exits),
+       STATS_DESC_COUNTER(VCPU, io_exits),
+       STATS_DESC_COUNTER(VCPU, mmio_exits),
+       STATS_DESC_COUNTER(VCPU, signal_exits),
+       STATS_DESC_COUNTER(VCPU, irq_window_exits),
+       STATS_DESC_COUNTER(VCPU, nmi_window_exits),
+       STATS_DESC_COUNTER(VCPU, l1d_flush),
+       STATS_DESC_COUNTER(VCPU, halt_exits),
+       STATS_DESC_COUNTER(VCPU, request_irq_exits),
+       STATS_DESC_COUNTER(VCPU, irq_exits),
+       STATS_DESC_COUNTER(VCPU, host_state_reload),
+       STATS_DESC_COUNTER(VCPU, fpu_reload),
+       STATS_DESC_COUNTER(VCPU, insn_emulation),
+       STATS_DESC_COUNTER(VCPU, insn_emulation_fail),
+       STATS_DESC_COUNTER(VCPU, hypercalls),
+       STATS_DESC_COUNTER(VCPU, irq_injections),
+       STATS_DESC_COUNTER(VCPU, nmi_injections),
+       STATS_DESC_COUNTER(VCPU, req_event),
+       STATS_DESC_COUNTER(VCPU, nested_run),
+       STATS_DESC_COUNTER(VCPU, directed_yield_attempted),
+       STATS_DESC_COUNTER(VCPU, directed_yield_successful),
+       STATS_DESC_ICOUNTER(VCPU, guest_mode)
+};
+static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+               sizeof(struct kvm_vcpu_stat) / sizeof(u64));
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+       .name_size = KVM_STATS_NAME_SIZE,
+       .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+       .id_offset = sizeof(struct kvm_stats_header),
+       .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+       .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+                      sizeof(kvm_vcpu_stats_desc),
 };
 
 u64 __read_mostly host_xcr0;
@@ -778,13 +807,6 @@ int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
 }
 EXPORT_SYMBOL_GPL(kvm_read_guest_page_mmu);
 
-static int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn,
-                              void *data, int offset, int len, u32 access)
-{
-       return kvm_read_guest_page_mmu(vcpu, vcpu->arch.walk_mmu, gfn,
-                                      data, offset, len, access);
-}
-
 static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.reserved_gpa_bits | rsvd_bits(5, 8) | rsvd_bits(1, 2);
@@ -819,6 +841,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
 
        memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs));
        kvm_register_mark_dirty(vcpu, VCPU_EXREG_PDPTR);
+       vcpu->arch.pdptrs_from_userspace = false;
 
 out:
 
@@ -826,40 +849,14 @@ out:
 }
 EXPORT_SYMBOL_GPL(load_pdptrs);
 
-bool pdptrs_changed(struct kvm_vcpu *vcpu)
-{
-       u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)];
-       int offset;
-       gfn_t gfn;
-       int r;
-
-       if (!is_pae_paging(vcpu))
-               return false;
-
-       if (!kvm_register_is_available(vcpu, VCPU_EXREG_PDPTR))
-               return true;
-
-       gfn = (kvm_read_cr3(vcpu) & 0xffffffe0ul) >> PAGE_SHIFT;
-       offset = (kvm_read_cr3(vcpu) & 0xffffffe0ul) & (PAGE_SIZE - 1);
-       r = kvm_read_nested_guest_page(vcpu, gfn, pdpte, offset, sizeof(pdpte),
-                                      PFERR_USER_MASK | PFERR_WRITE_MASK);
-       if (r < 0)
-               return true;
-
-       return memcmp(pdpte, vcpu->arch.walk_mmu->pdptrs, sizeof(pdpte)) != 0;
-}
-EXPORT_SYMBOL_GPL(pdptrs_changed);
-
 void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0)
 {
-       unsigned long update_bits = X86_CR0_PG | X86_CR0_WP;
-
        if ((cr0 ^ old_cr0) & X86_CR0_PG) {
                kvm_clear_async_pf_completion_queue(vcpu);
                kvm_async_pf_hash_reset(vcpu);
        }
 
-       if ((cr0 ^ old_cr0) & update_bits)
+       if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS)
                kvm_mmu_reset_context(vcpu);
 
        if (((cr0 ^ old_cr0) & X86_CR0_CD) &&
@@ -1038,10 +1035,7 @@ EXPORT_SYMBOL_GPL(kvm_is_valid_cr4);
 
 void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4)
 {
-       unsigned long mmu_role_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
-                                     X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE;
-
-       if (((cr4 ^ old_cr4) & mmu_role_bits) ||
+       if (((cr4 ^ old_cr4) & KVM_MMU_CR4_ROLE_BITS) ||
            (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
                kvm_mmu_reset_context(vcpu);
 }
@@ -1084,25 +1078,46 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr4);
 
+static void kvm_invalidate_pcid(struct kvm_vcpu *vcpu, unsigned long pcid)
+{
+       struct kvm_mmu *mmu = vcpu->arch.mmu;
+       unsigned long roots_to_free = 0;
+       int i;
+
+       /*
+        * If neither the current CR3 nor any of the prev_roots use the given
+        * PCID, then nothing needs to be done here because a resync will
+        * happen anyway before switching to any other CR3.
+        */
+       if (kvm_get_active_pcid(vcpu) == pcid) {
+               kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
+               kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
+       }
+
+       for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
+               if (kvm_get_pcid(vcpu, mmu->prev_roots[i].pgd) == pcid)
+                       roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i);
+
+       kvm_mmu_free_roots(vcpu, mmu, roots_to_free);
+}
+
 int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        bool skip_tlb_flush = false;
+       unsigned long pcid = 0;
 #ifdef CONFIG_X86_64
        bool pcid_enabled = kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE);
 
        if (pcid_enabled) {
                skip_tlb_flush = cr3 & X86_CR3_PCID_NOFLUSH;
                cr3 &= ~X86_CR3_PCID_NOFLUSH;
+               pcid = cr3 & X86_CR3_PCID_MASK;
        }
 #endif
 
-       if (cr3 == kvm_read_cr3(vcpu) && !pdptrs_changed(vcpu)) {
-               if (!skip_tlb_flush) {
-                       kvm_mmu_sync_roots(vcpu);
-                       kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
-               }
-               return 0;
-       }
+       /* PDPTRs are always reloaded for PAE paging. */
+       if (cr3 == kvm_read_cr3(vcpu) && !is_pae_paging(vcpu))
+               goto handle_tlb_flush;
 
        /*
         * Do not condition the GPA check on long mode, this helper is used to
@@ -1115,10 +1130,23 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
        if (is_pae_paging(vcpu) && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
                return 1;
 
-       kvm_mmu_new_pgd(vcpu, cr3, skip_tlb_flush, skip_tlb_flush);
+       if (cr3 != kvm_read_cr3(vcpu))
+               kvm_mmu_new_pgd(vcpu, cr3);
+
        vcpu->arch.cr3 = cr3;
        kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);
 
+handle_tlb_flush:
+       /*
+        * A load of CR3 that flushes the TLB flushes only the current PCID,
+        * even if PCID is disabled, in which case PCID=0 is flushed.  It's a
+        * moot point in the end because _disabling_ PCID will flush all PCIDs,
+        * and it's impossible to use a non-zero PCID when PCID is disabled,
+        * i.e. only PCID=0 can be relevant.
+        */
+       if (!skip_tlb_flush)
+               kvm_invalidate_pcid(vcpu, pcid);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_set_cr3);
@@ -2179,13 +2207,15 @@ static u32 adjust_tsc_khz(u32 khz, s32 ppm)
        return v;
 }
 
+static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multiplier);
+
 static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
        u64 ratio;
 
        /* Guest TSC same frequency as host TSC? */
        if (!scale) {
-               vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+               kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio);
                return 0;
        }
 
@@ -2211,7 +2241,7 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
                return -1;
        }
 
-       vcpu->arch.tsc_scaling_ratio = ratio;
+       kvm_vcpu_write_tsc_multiplier(vcpu, ratio);
        return 0;
 }
 
@@ -2223,7 +2253,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
        /* tsc_khz can be zero if TSC calibration fails */
        if (user_tsc_khz == 0) {
                /* set tsc_scaling_ratio to a safe value */
-               vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+               kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio);
                return -1;
        }
 
@@ -2305,10 +2335,9 @@ static inline u64 __scale_tsc(u64 ratio, u64 tsc)
        return mul_u64_u64_shr(tsc, ratio, kvm_tsc_scaling_ratio_frac_bits);
 }
 
-u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc, u64 ratio)
 {
        u64 _tsc = tsc;
-       u64 ratio = vcpu->arch.tsc_scaling_ratio;
 
        if (ratio != kvm_default_tsc_scaling_ratio)
                _tsc = __scale_tsc(ratio, tsc);
@@ -2317,25 +2346,86 @@ u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
 }
 EXPORT_SYMBOL_GPL(kvm_scale_tsc);
 
-static u64 kvm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+static u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
 {
        u64 tsc;
 
-       tsc = kvm_scale_tsc(vcpu, rdtsc());
+       tsc = kvm_scale_tsc(vcpu, rdtsc(), vcpu->arch.l1_tsc_scaling_ratio);
 
        return target_tsc - tsc;
 }
 
 u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 {
-       return vcpu->arch.l1_tsc_offset + kvm_scale_tsc(vcpu, host_tsc);
+       return vcpu->arch.l1_tsc_offset +
+               kvm_scale_tsc(vcpu, host_tsc, vcpu->arch.l1_tsc_scaling_ratio);
 }
 EXPORT_SYMBOL_GPL(kvm_read_l1_tsc);
 
-static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier)
 {
-       vcpu->arch.l1_tsc_offset = offset;
-       vcpu->arch.tsc_offset = static_call(kvm_x86_write_l1_tsc_offset)(vcpu, offset);
+       u64 nested_offset;
+
+       if (l2_multiplier == kvm_default_tsc_scaling_ratio)
+               nested_offset = l1_offset;
+       else
+               nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier,
+                                               kvm_tsc_scaling_ratio_frac_bits);
+
+       nested_offset += l2_offset;
+       return nested_offset;
+}
+EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset);
+
+u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier)
+{
+       if (l2_multiplier != kvm_default_tsc_scaling_ratio)
+               return mul_u64_u64_shr(l1_multiplier, l2_multiplier,
+                                      kvm_tsc_scaling_ratio_frac_bits);
+
+       return l1_multiplier;
+}
+EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_multiplier);
+
+static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset)
+{
+       trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+                                  vcpu->arch.l1_tsc_offset,
+                                  l1_offset);
+
+       vcpu->arch.l1_tsc_offset = l1_offset;
+
+       /*
+        * If we are here because L1 chose not to trap WRMSR to TSC then
+        * according to the spec this should set L1's TSC (as opposed to
+        * setting L1's offset for L2).
+        */
+       if (is_guest_mode(vcpu))
+               vcpu->arch.tsc_offset = kvm_calc_nested_tsc_offset(
+                       l1_offset,
+                       static_call(kvm_x86_get_l2_tsc_offset)(vcpu),
+                       static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu));
+       else
+               vcpu->arch.tsc_offset = l1_offset;
+
+       static_call(kvm_x86_write_tsc_offset)(vcpu, vcpu->arch.tsc_offset);
+}
+
+static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multiplier)
+{
+       vcpu->arch.l1_tsc_scaling_ratio = l1_multiplier;
+
+       /* Userspace is changing the multiplier while L2 is active */
+       if (is_guest_mode(vcpu))
+               vcpu->arch.tsc_scaling_ratio = kvm_calc_nested_tsc_multiplier(
+                       l1_multiplier,
+                       static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu));
+       else
+               vcpu->arch.tsc_scaling_ratio = l1_multiplier;
+
+       if (kvm_has_tsc_control)
+               static_call(kvm_x86_write_tsc_multiplier)(
+                       vcpu, vcpu->arch.tsc_scaling_ratio);
 }
 
 static inline bool kvm_check_tsc_unstable(void)
@@ -2361,7 +2451,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data)
        bool synchronizing = false;
 
        raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-       offset = kvm_compute_tsc_offset(vcpu, data);
+       offset = kvm_compute_l1_tsc_offset(vcpu, data);
        ns = get_kvmclock_base_ns();
        elapsed = ns - kvm->arch.last_tsc_nsec;
 
@@ -2400,7 +2490,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data)
                } else {
                        u64 delta = nsec_to_cycles(vcpu, elapsed);
                        data += delta;
-                       offset = kvm_compute_tsc_offset(vcpu, data);
+                       offset = kvm_compute_l1_tsc_offset(vcpu, data);
                }
                matched = true;
                already_matched = (vcpu->arch.this_tsc_generation == kvm->arch.cur_tsc_generation);
@@ -2459,9 +2549,10 @@ static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
 
 static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
 {
-       if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
+       if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
                WARN_ON(adjustment < 0);
-       adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
+       adjustment = kvm_scale_tsc(vcpu, (u64) adjustment,
+                                  vcpu->arch.l1_tsc_scaling_ratio);
        adjust_tsc_offset_guest(vcpu, adjustment);
 }
 
@@ -2844,7 +2935,8 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        /* With all the info we got, fill in the values */
 
        if (kvm_has_tsc_control)
-               tgt_tsc_khz = kvm_scale_tsc(v, tgt_tsc_khz);
+               tgt_tsc_khz = kvm_scale_tsc(v, tgt_tsc_khz,
+                                           v->arch.l1_tsc_scaling_ratio);
 
        if (unlikely(vcpu->hw_tsc_khz != tgt_tsc_khz)) {
                kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_khz * 1000LL,
@@ -3250,7 +3342,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (msr_info->host_initiated) {
                        kvm_synchronize_tsc(vcpu, data);
                } else {
-                       u64 adj = kvm_compute_tsc_offset(vcpu, data) - vcpu->arch.l1_tsc_offset;
+                       u64 adj = kvm_compute_l1_tsc_offset(vcpu, data) - vcpu->arch.l1_tsc_offset;
                        adjust_tsc_offset_guest(vcpu, adj);
                        vcpu->arch.ia32_tsc_adjust_msr += adj;
                }
@@ -3552,10 +3644,17 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                 * return L1's TSC value to ensure backwards-compatible
                 * behavior for migration.
                 */
-               u64 tsc_offset = msr_info->host_initiated ? vcpu->arch.l1_tsc_offset :
-                                                           vcpu->arch.tsc_offset;
+               u64 offset, ratio;
+
+               if (msr_info->host_initiated) {
+                       offset = vcpu->arch.l1_tsc_offset;
+                       ratio = vcpu->arch.l1_tsc_scaling_ratio;
+               } else {
+                       offset = vcpu->arch.tsc_offset;
+                       ratio = vcpu->arch.tsc_scaling_ratio;
+               }
 
-               msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + tsc_offset;
+               msr_info->data = kvm_scale_tsc(vcpu, rdtsc(), ratio) + offset;
                break;
        }
        case MSR_MTRRcap:
@@ -3879,6 +3978,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_HYPERV_TLBFLUSH:
        case KVM_CAP_HYPERV_SEND_IPI:
        case KVM_CAP_HYPERV_CPUID:
+       case KVM_CAP_HYPERV_ENFORCE_CPUID:
        case KVM_CAP_SYS_HYPERV_CPUID:
        case KVM_CAP_PCI_SEGMENT:
        case KVM_CAP_DEBUGREGS:
@@ -3909,8 +4009,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SGX_ATTRIBUTE:
 #endif
        case KVM_CAP_VM_COPY_ENC_CONTEXT_FROM:
+       case KVM_CAP_SREGS2:
+       case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
                r = 1;
                break;
+       case KVM_CAP_EXIT_HYPERCALL:
+               r = KVM_EXIT_HYPERCALL_VALID_MASK;
+               break;
        case KVM_CAP_SET_GUEST_DEBUG2:
                return KVM_GUESTDBG_VALID_MASK;
 #ifdef CONFIG_KVM_XEN
@@ -4138,7 +4243,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                        mark_tsc_unstable("KVM discovered backwards TSC");
 
                if (kvm_check_tsc_unstable()) {
-                       u64 offset = kvm_compute_tsc_offset(vcpu,
+                       u64 offset = kvm_compute_l1_tsc_offset(vcpu,
                                                vcpu->arch.last_guest_tsc);
                        kvm_vcpu_write_tsc_offset(vcpu, offset);
                        vcpu->arch.tsc_catchup = 1;
@@ -4457,7 +4562,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
-static void kvm_smm_changed(struct kvm_vcpu *vcpu);
+static void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm);
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                                              struct kvm_vcpu_events *events)
@@ -4517,13 +4622,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                vcpu->arch.apic->sipi_vector = events->sipi_vector;
 
        if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
-               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
-                       if (events->smi.smm)
-                               vcpu->arch.hflags |= HF_SMM_MASK;
-                       else
-                               vcpu->arch.hflags &= ~HF_SMM_MASK;
-                       kvm_smm_changed(vcpu);
-               }
+               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm)
+                       kvm_smm_changed(vcpu, events->smi.smm);
 
                vcpu->arch.smi_pending = events->smi.pending;
 
@@ -4807,6 +4907,9 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 
                return static_call(kvm_x86_enable_direct_tlbflush)(vcpu);
 
+       case KVM_CAP_HYPERV_ENFORCE_CPUID:
+               return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]);
+
        case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
                vcpu->arch.pv_cpuid.enforce = cap->args[0];
                if (vcpu->arch.pv_cpuid.enforce)
@@ -4825,6 +4928,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        void __user *argp = (void __user *)arg;
        int r;
        union {
+               struct kvm_sregs2 *sregs2;
                struct kvm_lapic_state *lapic;
                struct kvm_xsave *xsave;
                struct kvm_xcrs *xcrs;
@@ -5197,6 +5301,28 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                break;
        }
 #endif
+       case KVM_GET_SREGS2: {
+               u.sregs2 = kzalloc(sizeof(struct kvm_sregs2), GFP_KERNEL);
+               r = -ENOMEM;
+               if (!u.sregs2)
+                       goto out;
+               __get_sregs2(vcpu, u.sregs2);
+               r = -EFAULT;
+               if (copy_to_user(argp, u.sregs2, sizeof(struct kvm_sregs2)))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_SREGS2: {
+               u.sregs2 = memdup_user(argp, sizeof(struct kvm_sregs2));
+               if (IS_ERR(u.sregs2)) {
+                       r = PTR_ERR(u.sregs2);
+                       u.sregs2 = NULL;
+                       goto out;
+               }
+               r = __set_sregs2(vcpu, u.sregs2);
+               break;
+       }
        default:
                r = -EINVAL;
        }
@@ -5516,6 +5642,21 @@ split_irqchip_unlock:
                if (kvm_x86_ops.vm_copy_enc_context_from)
                        r = kvm_x86_ops.vm_copy_enc_context_from(kvm, cap->args[0]);
                return r;
+       case KVM_CAP_EXIT_HYPERCALL:
+               if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) {
+                       r = -EINVAL;
+                       break;
+               }
+               kvm->arch.hypercall_exit_enabled = cap->args[0];
+               r = 0;
+               break;
+       case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
+               r = -EINVAL;
+               if (cap->args[0] & ~1)
+                       break;
+               kvm->arch.exit_on_emulation_error = cap->args[0];
+               r = 0;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -5630,6 +5771,41 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
        return 0;
 }
 
+#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
+static int kvm_arch_suspend_notifier(struct kvm *kvm)
+{
+       struct kvm_vcpu *vcpu;
+       int i, ret = 0;
+
+       mutex_lock(&kvm->lock);
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               if (!vcpu->arch.pv_time_enabled)
+                       continue;
+
+               ret = kvm_set_guest_paused(vcpu);
+               if (ret) {
+                       kvm_err("Failed to pause guest VCPU%d: %d\n",
+                               vcpu->vcpu_id, ret);
+                       break;
+               }
+       }
+       mutex_unlock(&kvm->lock);
+
+       return ret ? NOTIFY_BAD : NOTIFY_DONE;
+}
+
+int kvm_arch_pm_notifier(struct kvm *kvm, unsigned long state)
+{
+       switch (state) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               return kvm_arch_suspend_notifier(kvm);
+       }
+
+       return NOTIFY_DONE;
+}
+#endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */
+
 long kvm_arch_vm_ioctl(struct file *filp,
                       unsigned int ioctl, unsigned long arg)
 {
@@ -7104,20 +7280,22 @@ static unsigned emulator_get_hflags(struct x86_emulate_ctxt *ctxt)
        return emul_to_vcpu(ctxt)->arch.hflags;
 }
 
-static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_flags)
+static void emulator_exiting_smm(struct x86_emulate_ctxt *ctxt)
 {
-       emul_to_vcpu(ctxt)->arch.hflags = emul_flags;
+       struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
+       kvm_smm_changed(vcpu, false);
 }
 
-static int emulator_pre_leave_smm(struct x86_emulate_ctxt *ctxt,
+static int emulator_leave_smm(struct x86_emulate_ctxt *ctxt,
                                  const char *smstate)
 {
-       return static_call(kvm_x86_pre_leave_smm)(emul_to_vcpu(ctxt), smstate);
+       return static_call(kvm_x86_leave_smm)(emul_to_vcpu(ctxt), smstate);
 }
 
-static void emulator_post_leave_smm(struct x86_emulate_ctxt *ctxt)
+static void emulator_triple_fault(struct x86_emulate_ctxt *ctxt)
 {
-       kvm_smm_changed(emul_to_vcpu(ctxt));
+       kvm_make_request(KVM_REQ_TRIPLE_FAULT, emul_to_vcpu(ctxt));
 }
 
 static int emulator_set_xcr(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr)
@@ -7166,9 +7344,9 @@ static const struct x86_emulate_ops emulate_ops = {
        .guest_has_fxsr      = emulator_guest_has_fxsr,
        .set_nmi_mask        = emulator_set_nmi_mask,
        .get_hflags          = emulator_get_hflags,
-       .set_hflags          = emulator_set_hflags,
-       .pre_leave_smm       = emulator_pre_leave_smm,
-       .post_leave_smm      = emulator_post_leave_smm,
+       .exiting_smm         = emulator_exiting_smm,
+       .leave_smm           = emulator_leave_smm,
+       .triple_fault        = emulator_triple_fault,
        .set_xcr             = emulator_set_xcr,
 };
 
@@ -7274,8 +7452,33 @@ void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip)
 }
 EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt);
 
+static void prepare_emulation_failure_exit(struct kvm_vcpu *vcpu)
+{
+       struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
+       u32 insn_size = ctxt->fetch.end - ctxt->fetch.data;
+       struct kvm_run *run = vcpu->run;
+
+       run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+       run->emulation_failure.suberror = KVM_INTERNAL_ERROR_EMULATION;
+       run->emulation_failure.ndata = 0;
+       run->emulation_failure.flags = 0;
+
+       if (insn_size) {
+               run->emulation_failure.ndata = 3;
+               run->emulation_failure.flags |=
+                       KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES;
+               run->emulation_failure.insn_size = insn_size;
+               memset(run->emulation_failure.insn_bytes, 0x90,
+                      sizeof(run->emulation_failure.insn_bytes));
+               memcpy(run->emulation_failure.insn_bytes,
+                      ctxt->fetch.data, insn_size);
+       }
+}
+
 static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type)
 {
+       struct kvm *kvm = vcpu->kvm;
+
        ++vcpu->stat.insn_emulation_fail;
        trace_kvm_emulate_insn_failed(vcpu);
 
@@ -7284,10 +7487,9 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type)
                return 1;
        }
 
-       if (emulation_type & EMULTYPE_SKIP) {
-               vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-               vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
-               vcpu->run->internal.ndata = 0;
+       if (kvm->arch.exit_on_emulation_error ||
+           (emulation_type & EMULTYPE_SKIP)) {
+               prepare_emulation_failure_exit(vcpu);
                return 0;
        }
 
@@ -7429,11 +7631,14 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
 static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
 static int complete_emulated_pio(struct kvm_vcpu *vcpu);
 
-static void kvm_smm_changed(struct kvm_vcpu *vcpu)
+static void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm)
 {
-       if (!(vcpu->arch.hflags & HF_SMM_MASK)) {
-               /* This is a good place to trace that we are exiting SMM.  */
-               trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, false);
+       trace_kvm_smm_transition(vcpu->vcpu_id, vcpu->arch.smbase, entering_smm);
+
+       if (entering_smm) {
+               vcpu->arch.hflags |= HF_SMM_MASK;
+       } else {
+               vcpu->arch.hflags &= ~(HF_SMM_MASK | HF_SMM_INSIDE_NMI_MASK);
 
                /* Process a latched INIT or SMI, if any.  */
                kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -8258,6 +8463,7 @@ void kvm_arch_exit(void)
        kvm_x86_ops.hardware_enable = NULL;
        kvm_mmu_module_exit();
        free_percpu(user_return_msrs);
+       kmem_cache_destroy(x86_emulator_cache);
        kmem_cache_destroy(x86_fpu_cache);
 #ifdef CONFIG_KVM_XEN
        static_key_deferred_flush(&kvm_xen_enabled);
@@ -8357,16 +8563,15 @@ bool kvm_apicv_activated(struct kvm *kvm)
 }
 EXPORT_SYMBOL_GPL(kvm_apicv_activated);
 
-void kvm_apicv_init(struct kvm *kvm, bool enable)
+static void kvm_apicv_init(struct kvm *kvm)
 {
-       if (enable)
+       if (enable_apicv)
                clear_bit(APICV_INHIBIT_REASON_DISABLE,
                          &kvm->arch.apicv_inhibit_reasons);
        else
                set_bit(APICV_INHIBIT_REASON_DISABLE,
                        &kvm->arch.apicv_inhibit_reasons);
 }
-EXPORT_SYMBOL_GPL(kvm_apicv_init);
 
 static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id)
 {
@@ -8402,6 +8607,17 @@ no_yield:
        return;
 }
 
+static int complete_hypercall_exit(struct kvm_vcpu *vcpu)
+{
+       u64 ret = vcpu->run->hypercall.ret;
+
+       if (!is_64_bit_mode(vcpu))
+               ret = (u32)ret;
+       kvm_rax_write(vcpu, ret);
+       ++vcpu->stat.hypercalls;
+       return kvm_skip_emulated_instruction(vcpu);
+}
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 {
        unsigned long nr, a0, a1, a2, a3, ret;
@@ -8467,6 +8683,28 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
                kvm_sched_yield(vcpu, a0);
                ret = 0;
                break;
+       case KVM_HC_MAP_GPA_RANGE: {
+               u64 gpa = a0, npages = a1, attrs = a2;
+
+               ret = -KVM_ENOSYS;
+               if (!(vcpu->kvm->arch.hypercall_exit_enabled & (1 << KVM_HC_MAP_GPA_RANGE)))
+                       break;
+
+               if (!PAGE_ALIGNED(gpa) || !npages ||
+                   gpa_to_gfn(gpa) + npages <= gpa_to_gfn(gpa)) {
+                       ret = -KVM_EINVAL;
+                       break;
+               }
+
+               vcpu->run->exit_reason        = KVM_EXIT_HYPERCALL;
+               vcpu->run->hypercall.nr       = KVM_HC_MAP_GPA_RANGE;
+               vcpu->run->hypercall.args[0]  = gpa;
+               vcpu->run->hypercall.args[1]  = npages;
+               vcpu->run->hypercall.args[2]  = attrs;
+               vcpu->run->hypercall.longmode = op_64_bit;
+               vcpu->arch.complete_userspace_io = complete_hypercall_exit;
+               return 0;
+       }
        default:
                ret = -KVM_ENOSYS;
                break;
@@ -8550,9 +8788,6 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
 
 int kvm_check_nested_events(struct kvm_vcpu *vcpu)
 {
-       if (WARN_ON_ONCE(!is_guest_mode(vcpu)))
-               return -EIO;
-
        if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
                kvm_x86_ops.nested_ops->triple_fault(vcpu);
                return 1;
@@ -8568,7 +8803,7 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)
        static_call(kvm_x86_queue_exception)(vcpu);
 }
 
-static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit)
+static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit)
 {
        int r;
        bool can_inject = true;
@@ -8615,7 +8850,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit
        if (is_guest_mode(vcpu)) {
                r = kvm_check_nested_events(vcpu);
                if (r < 0)
-                       goto busy;
+                       goto out;
        }
 
        /* try to inject new event if pending */
@@ -8657,7 +8892,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit
        if (vcpu->arch.smi_pending) {
                r = can_inject ? static_call(kvm_x86_smi_allowed)(vcpu, true) : -EBUSY;
                if (r < 0)
-                       goto busy;
+                       goto out;
                if (r) {
                        vcpu->arch.smi_pending = false;
                        ++vcpu->arch.smi_count;
@@ -8670,7 +8905,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit
        if (vcpu->arch.nmi_pending) {
                r = can_inject ? static_call(kvm_x86_nmi_allowed)(vcpu, true) : -EBUSY;
                if (r < 0)
-                       goto busy;
+                       goto out;
                if (r) {
                        --vcpu->arch.nmi_pending;
                        vcpu->arch.nmi_injected = true;
@@ -8685,7 +8920,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit
        if (kvm_cpu_has_injectable_intr(vcpu)) {
                r = can_inject ? static_call(kvm_x86_interrupt_allowed)(vcpu, true) : -EBUSY;
                if (r < 0)
-                       goto busy;
+                       goto out;
                if (r) {
                        kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu), false);
                        static_call(kvm_x86_set_irq)(vcpu);
@@ -8701,11 +8936,14 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit
                *req_immediate_exit = true;
 
        WARN_ON(vcpu->arch.exception.pending);
-       return;
+       return 0;
 
-busy:
-       *req_immediate_exit = true;
-       return;
+out:
+       if (r == -EBUSY) {
+               *req_immediate_exit = true;
+               r = 0;
+       }
+       return r;
 }
 
 static void process_nmi(struct kvm_vcpu *vcpu)
@@ -8884,10 +9122,9 @@ static void enter_smm(struct kvm_vcpu *vcpu)
 {
        struct kvm_segment cs, ds;
        struct desc_ptr dt;
+       unsigned long cr0;
        char buf[512];
-       u32 cr0;
 
-       trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, true);
        memset(buf, 0, 512);
 #ifdef CONFIG_X86_64
        if (guest_cpuid_has(vcpu, X86_FEATURE_LM))
@@ -8897,13 +9134,13 @@ static void enter_smm(struct kvm_vcpu *vcpu)
                enter_smm_save_state_32(vcpu, buf);
 
        /*
-        * Give pre_enter_smm() a chance to make ISA-specific changes to the
-        * vCPU state (e.g. leave guest mode) after we've saved the state into
-        * the SMM state-save area.
+        * Give enter_smm() a chance to make ISA-specific changes to the vCPU
+        * state (e.g. leave guest mode) after we've saved the state into the
+        * SMM state-save area.
         */
-       static_call(kvm_x86_pre_enter_smm)(vcpu, buf);
+       static_call(kvm_x86_enter_smm)(vcpu, buf);
 
-       vcpu->arch.hflags |= HF_SMM_MASK;
+       kvm_smm_changed(vcpu, true);
        kvm_vcpu_write_guest(vcpu, vcpu->arch.smbase + 0xfe00, buf, sizeof(buf));
 
        if (static_call(kvm_x86_get_nmi_mask)(vcpu))
@@ -8992,6 +9229,15 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
        vcpu->arch.apicv_active = kvm_apicv_activated(vcpu->kvm);
        kvm_apic_update_apicv(vcpu);
        static_call(kvm_x86_refresh_apicv_exec_ctrl)(vcpu);
+
+       /*
+        * When APICv gets disabled, we may still have injected interrupts
+        * pending. At the same time, KVM_REQ_EVENT may not be set as APICv was
+        * still active when the interrupt got accepted. Make sure
+        * inject_pending_event() is called to check for that.
+        */
+       if (!vcpu->arch.apicv_active)
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv);
 
@@ -9167,7 +9413,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                }
                if (kvm_check_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu))
                        kvm_vcpu_flush_tlb_current(vcpu);
-               if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu))
+               if (kvm_check_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu))
                        kvm_vcpu_flush_tlb_guest(vcpu);
 
                if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
@@ -9260,13 +9506,21 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||
            kvm_xen_has_interrupt(vcpu)) {
                ++vcpu->stat.req_event;
-               kvm_apic_accept_events(vcpu);
+               r = kvm_apic_accept_events(vcpu);
+               if (r < 0) {
+                       r = 0;
+                       goto out;
+               }
                if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
                        r = 1;
                        goto out;
                }
 
-               inject_pending_event(vcpu, &req_immediate_exit);
+               r = inject_pending_event(vcpu, &req_immediate_exit);
+               if (r < 0) {
+                       r = 0;
+                       goto out;
+               }
                if (req_int_win)
                        static_call(kvm_x86_enable_irq_window)(vcpu);
 
@@ -9468,7 +9722,8 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu)
                        return 1;
        }
 
-       kvm_apic_accept_events(vcpu);
+       if (kvm_apic_accept_events(vcpu) < 0)
+               return 0;
        switch(vcpu->arch.mp_state) {
        case KVM_MP_STATE_HALTED:
        case KVM_MP_STATE_AP_RESET_HOLD:
@@ -9692,7 +9947,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                        goto out;
                }
                kvm_vcpu_block(vcpu);
-               kvm_apic_accept_events(vcpu);
+               if (kvm_apic_accept_events(vcpu) < 0) {
+                       r = 0;
+                       goto out;
+               }
                kvm_clear_request(KVM_REQ_UNHALT, vcpu);
                r = -EAGAIN;
                if (signal_pending(current)) {
@@ -9841,7 +10099,7 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
 }
 EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
 
-static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
 {
        struct desc_ptr dt;
 
@@ -9874,14 +10132,36 @@ skip_protected_regs:
        sregs->cr8 = kvm_get_cr8(vcpu);
        sregs->efer = vcpu->arch.efer;
        sregs->apic_base = kvm_get_apic_base(vcpu);
+}
+
+static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+       __get_sregs_common(vcpu, sregs);
 
-       memset(sregs->interrupt_bitmap, 0, sizeof(sregs->interrupt_bitmap));
+       if (vcpu->arch.guest_state_protected)
+               return;
 
        if (vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft)
                set_bit(vcpu->arch.interrupt.nr,
                        (unsigned long *)sregs->interrupt_bitmap);
 }
 
+static void __get_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2)
+{
+       int i;
+
+       __get_sregs_common(vcpu, (struct kvm_sregs *)sregs2);
+
+       if (vcpu->arch.guest_state_protected)
+               return;
+
+       if (is_pae_paging(vcpu)) {
+               for (i = 0 ; i < 4 ; i++)
+                       sregs2->pdptrs[i] = kvm_pdptr_read(vcpu, i);
+               sregs2->flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID;
+       }
+}
+
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
@@ -9894,11 +10174,17 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
                                    struct kvm_mp_state *mp_state)
 {
+       int r;
+
        vcpu_load(vcpu);
        if (kvm_mpx_supported())
                kvm_load_guest_fpu(vcpu);
 
-       kvm_apic_accept_events(vcpu);
+       r = kvm_apic_accept_events(vcpu);
+       if (r < 0)
+               goto out;
+       r = 0;
+
        if ((vcpu->arch.mp_state == KVM_MP_STATE_HALTED ||
             vcpu->arch.mp_state == KVM_MP_STATE_AP_RESET_HOLD) &&
            vcpu->arch.pv.pv_unhalted)
@@ -9906,10 +10192,11 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
        else
                mp_state->mp_state = vcpu->arch.mp_state;
 
+out:
        if (kvm_mpx_supported())
                kvm_put_guest_fpu(vcpu);
        vcpu_put(vcpu);
-       return 0;
+       return r;
 }
 
 int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
@@ -9993,24 +10280,23 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        return kvm_is_valid_cr4(vcpu, sregs->cr4);
 }
 
-static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
+               int *mmu_reset_needed, bool update_pdptrs)
 {
        struct msr_data apic_base_msr;
-       int mmu_reset_needed = 0;
-       int pending_vec, max_bits, idx;
+       int idx;
        struct desc_ptr dt;
-       int ret = -EINVAL;
 
        if (!kvm_is_valid_sregs(vcpu, sregs))
-               goto out;
+               return -EINVAL;
 
        apic_base_msr.data = sregs->apic_base;
        apic_base_msr.host_initiated = true;
        if (kvm_set_apic_base(vcpu, &apic_base_msr))
-               goto out;
+               return -EINVAL;
 
        if (vcpu->arch.guest_state_protected)
-               goto skip_protected_regs;
+               return 0;
 
        dt.size = sregs->idt.limit;
        dt.address = sregs->idt.base;
@@ -10020,31 +10306,30 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        static_call(kvm_x86_set_gdt)(vcpu, &dt);
 
        vcpu->arch.cr2 = sregs->cr2;
-       mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3;
+       *mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3;
        vcpu->arch.cr3 = sregs->cr3;
        kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);
 
        kvm_set_cr8(vcpu, sregs->cr8);
 
-       mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
+       *mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
        static_call(kvm_x86_set_efer)(vcpu, sregs->efer);
 
-       mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
+       *mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
        static_call(kvm_x86_set_cr0)(vcpu, sregs->cr0);
        vcpu->arch.cr0 = sregs->cr0;
 
-       mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
+       *mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
        static_call(kvm_x86_set_cr4)(vcpu, sregs->cr4);
 
-       idx = srcu_read_lock(&vcpu->kvm->srcu);
-       if (is_pae_paging(vcpu)) {
-               load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu));
-               mmu_reset_needed = 1;
+       if (update_pdptrs) {
+               idx = srcu_read_lock(&vcpu->kvm->srcu);
+               if (is_pae_paging(vcpu)) {
+                       load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu));
+                       *mmu_reset_needed = 1;
+               }
+               srcu_read_unlock(&vcpu->kvm->srcu, idx);
        }
-       srcu_read_unlock(&vcpu->kvm->srcu, idx);
-
-       if (mmu_reset_needed)
-               kvm_mmu_reset_context(vcpu);
 
        kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
        kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -10064,20 +10349,63 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
            !is_protmode(vcpu))
                vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
-skip_protected_regs:
+       return 0;
+}
+
+static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+       int pending_vec, max_bits;
+       int mmu_reset_needed = 0;
+       int ret = __set_sregs_common(vcpu, sregs, &mmu_reset_needed, true);
+
+       if (ret)
+               return ret;
+
+       if (mmu_reset_needed)
+               kvm_mmu_reset_context(vcpu);
+
        max_bits = KVM_NR_INTERRUPTS;
        pending_vec = find_first_bit(
                (const unsigned long *)sregs->interrupt_bitmap, max_bits);
+
        if (pending_vec < max_bits) {
                kvm_queue_interrupt(vcpu, pending_vec, false);
                pr_debug("Set back pending irq %d\n", pending_vec);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
        }
+       return 0;
+}
 
-       kvm_make_request(KVM_REQ_EVENT, vcpu);
+static int __set_sregs2(struct kvm_vcpu *vcpu, struct kvm_sregs2 *sregs2)
+{
+       int mmu_reset_needed = 0;
+       bool valid_pdptrs = sregs2->flags & KVM_SREGS2_FLAGS_PDPTRS_VALID;
+       bool pae = (sregs2->cr0 & X86_CR0_PG) && (sregs2->cr4 & X86_CR4_PAE) &&
+               !(sregs2->efer & EFER_LMA);
+       int i, ret;
 
-       ret = 0;
-out:
-       return ret;
+       if (sregs2->flags & ~KVM_SREGS2_FLAGS_PDPTRS_VALID)
+               return -EINVAL;
+
+       if (valid_pdptrs && (!pae || vcpu->arch.guest_state_protected))
+               return -EINVAL;
+
+       ret = __set_sregs_common(vcpu, (struct kvm_sregs *)sregs2,
+                                &mmu_reset_needed, !valid_pdptrs);
+       if (ret)
+               return ret;
+
+       if (valid_pdptrs) {
+               for (i = 0; i < 4 ; i++)
+                       kvm_pdptr_write(vcpu, i, sregs2->pdptrs[i]);
+
+               kvm_register_mark_dirty(vcpu, VCPU_EXREG_PDPTR);
+               mmu_reset_needed = 1;
+               vcpu->arch.pdptrs_from_userspace = true;
+       }
+       if (mmu_reset_needed)
+               kvm_mmu_reset_context(vcpu);
+       return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
@@ -10301,13 +10629,13 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        struct page *page;
        int r;
 
+       vcpu->arch.last_vmentry_cpu = -1;
+
        if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu))
                vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
        else
                vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
 
-       kvm_set_tsc_khz(vcpu, max_tsc_khz);
-
        r = kvm_mmu_create(vcpu);
        if (r < 0)
                return r;
@@ -10367,6 +10695,10 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        vcpu->arch.pending_external_vector = -1;
        vcpu->arch.preempted_in_kernel = false;
 
+#if IS_ENABLED(CONFIG_HYPERV)
+       vcpu->arch.hv_root_tdp = INVALID_PAGE;
+#endif
+
        r = static_call(kvm_x86_vcpu_create)(vcpu);
        if (r)
                goto free_guest_fpu;
@@ -10375,8 +10707,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT;
        kvm_vcpu_mtrr_init(vcpu);
        vcpu_load(vcpu);
+       kvm_set_tsc_khz(vcpu, max_tsc_khz);
        kvm_vcpu_reset(vcpu, false);
-       kvm_init_mmu(vcpu, false);
+       kvm_init_mmu(vcpu);
        vcpu_put(vcpu);
        return 0;
 
@@ -10450,6 +10783,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
+       unsigned long old_cr0 = kvm_read_cr0(vcpu);
+
        kvm_lapic_reset(vcpu, init_event);
 
        vcpu->arch.hflags = 0;
@@ -10518,6 +10853,17 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        vcpu->arch.ia32_xss = 0;
 
        static_call(kvm_x86_vcpu_reset)(vcpu, init_event);
+
+       /*
+        * Reset the MMU context if paging was enabled prior to INIT (which is
+        * implied if CR0.PG=1 as CR0 will be '0' prior to RESET).  Unlike the
+        * standard CR0/CR4/EFER modification paths, only CR0.PG needs to be
+        * checked because it is unconditionally cleared on INIT and all other
+        * paging related bits are ignored if paging is disabled, i.e. CR0.WP,
+        * CR4, and EFER changes are all irrelevant if CR0.PG was '0'.
+        */
+       if (old_cr0 & X86_CR0_PG)
+               kvm_mmu_reset_context(vcpu);
 }
 
 void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
@@ -10635,6 +10981,9 @@ int kvm_arch_hardware_setup(void *opaque)
        int r;
 
        rdmsrl_safe(MSR_EFER, &host_efer);
+       if (WARN_ON_ONCE(boot_cpu_has(X86_FEATURE_NX) &&
+                        !(host_efer & EFER_NX)))
+               return -EIO;
 
        if (boot_cpu_has(X86_FEATURE_XSAVES))
                rdmsrl(MSR_IA32_XSS, host_xss);
@@ -10750,9 +11099,15 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        kvm->arch.guest_can_read_msr_platform_info = true;
 
+#if IS_ENABLED(CONFIG_HYPERV)
+       spin_lock_init(&kvm->arch.hv_root_tdp_lock);
+       kvm->arch.hv_root_tdp = INVALID_PAGE;
+#endif
+
        INIT_DELAYED_WORK(&kvm->arch.kvmclock_update_work, kvmclock_update_fn);
        INIT_DELAYED_WORK(&kvm->arch.kvmclock_sync_work, kvmclock_sync_fn);
 
+       kvm_apicv_init(kvm);
        kvm_hv_init_vm(kvm);
        kvm_page_track_init(kvm);
        kvm_mmu_init_vm(kvm);
@@ -10913,17 +11268,23 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        kvm_hv_destroy_vm(kvm);
 }
 
-void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
+static void memslot_rmap_free(struct kvm_memory_slot *slot)
 {
        int i;
 
        for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
                kvfree(slot->arch.rmap[i]);
                slot->arch.rmap[i] = NULL;
+       }
+}
 
-               if (i == 0)
-                       continue;
+void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+       int i;
 
+       memslot_rmap_free(slot);
+
+       for (i = 1; i < KVM_NR_PAGE_SIZES; ++i) {
                kvfree(slot->arch.lpage_info[i - 1]);
                slot->arch.lpage_info[i - 1] = NULL;
        }
@@ -10931,11 +11292,79 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
        kvm_page_track_free_memslot(slot);
 }
 
-static int kvm_alloc_memslot_metadata(struct kvm_memory_slot *slot,
-                                     unsigned long npages)
+static int memslot_rmap_alloc(struct kvm_memory_slot *slot,
+                             unsigned long npages)
 {
+       const int sz = sizeof(*slot->arch.rmap[0]);
        int i;
 
+       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+               int level = i + 1;
+               int lpages = gfn_to_index(slot->base_gfn + npages - 1,
+                                         slot->base_gfn, level) + 1;
+
+               WARN_ON(slot->arch.rmap[i]);
+
+               slot->arch.rmap[i] = kvcalloc(lpages, sz, GFP_KERNEL_ACCOUNT);
+               if (!slot->arch.rmap[i]) {
+                       memslot_rmap_free(slot);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+int alloc_all_memslots_rmaps(struct kvm *kvm)
+{
+       struct kvm_memslots *slots;
+       struct kvm_memory_slot *slot;
+       int r, i;
+
+       /*
+        * Check if memslots alreday have rmaps early before acquiring
+        * the slots_arch_lock below.
+        */
+       if (kvm_memslots_have_rmaps(kvm))
+               return 0;
+
+       mutex_lock(&kvm->slots_arch_lock);
+
+       /*
+        * Read memslots_have_rmaps again, under the slots arch lock,
+        * before allocating the rmaps
+        */
+       if (kvm_memslots_have_rmaps(kvm)) {
+               mutex_unlock(&kvm->slots_arch_lock);
+               return 0;
+       }
+
+       for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+               slots = __kvm_memslots(kvm, i);
+               kvm_for_each_memslot(slot, slots) {
+                       r = memslot_rmap_alloc(slot, slot->npages);
+                       if (r) {
+                               mutex_unlock(&kvm->slots_arch_lock);
+                               return r;
+                       }
+               }
+       }
+
+       /*
+        * Ensure that memslots_have_rmaps becomes true strictly after
+        * all the rmap pointers are set.
+        */
+       smp_store_release(&kvm->arch.memslots_have_rmaps, true);
+       mutex_unlock(&kvm->slots_arch_lock);
+       return 0;
+}
+
+static int kvm_alloc_memslot_metadata(struct kvm *kvm,
+                                     struct kvm_memory_slot *slot,
+                                     unsigned long npages)
+{
+       int i, r;
+
        /*
         * Clear out the previous array pointers for the KVM_MR_MOVE case.  The
         * old arrays will be freed by __kvm_set_memory_region() if installing
@@ -10943,7 +11372,13 @@ static int kvm_alloc_memslot_metadata(struct kvm_memory_slot *slot,
         */
        memset(&slot->arch, 0, sizeof(slot->arch));
 
-       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+       if (kvm_memslots_have_rmaps(kvm)) {
+               r = memslot_rmap_alloc(slot, npages);
+               if (r)
+                       return r;
+       }
+
+       for (i = 1; i < KVM_NR_PAGE_SIZES; ++i) {
                struct kvm_lpage_info *linfo;
                unsigned long ugfn;
                int lpages;
@@ -10952,14 +11387,6 @@ static int kvm_alloc_memslot_metadata(struct kvm_memory_slot *slot,
                lpages = gfn_to_index(slot->base_gfn + npages - 1,
                                      slot->base_gfn, level) + 1;
 
-               slot->arch.rmap[i] =
-                       kvcalloc(lpages, sizeof(*slot->arch.rmap[i]),
-                                GFP_KERNEL_ACCOUNT);
-               if (!slot->arch.rmap[i])
-                       goto out_free;
-               if (i == 0)
-                       continue;
-
                linfo = kvcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT);
                if (!linfo)
                        goto out_free;
@@ -10989,12 +11416,9 @@ static int kvm_alloc_memslot_metadata(struct kvm_memory_slot *slot,
        return 0;
 
 out_free:
-       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
-               kvfree(slot->arch.rmap[i]);
-               slot->arch.rmap[i] = NULL;
-               if (i == 0)
-                       continue;
+       memslot_rmap_free(slot);
 
+       for (i = 1; i < KVM_NR_PAGE_SIZES; ++i) {
                kvfree(slot->arch.lpage_info[i - 1]);
                slot->arch.lpage_info[i - 1] = NULL;
        }
@@ -11023,7 +11447,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                enum kvm_mr_change change)
 {
        if (change == KVM_MR_CREATE || change == KVM_MR_MOVE)
-               return kvm_alloc_memslot_metadata(memslot,
+               return kvm_alloc_memslot_metadata(kvm, memslot,
                                                  mem->memory_size >> PAGE_SHIFT);
        return 0;
 }
@@ -11099,36 +11523,19 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm,
                 */
                kvm_mmu_zap_collapsible_sptes(kvm, new);
        } else {
-               /* By default, write-protect everything to log writes. */
-               int level = PG_LEVEL_4K;
+               /*
+                * Initially-all-set does not require write protecting any page,
+                * because they're all assumed to be dirty.
+                */
+               if (kvm_dirty_log_manual_protect_and_init_set(kvm))
+                       return;
 
                if (kvm_x86_ops.cpu_dirty_log_size) {
-                       /*
-                        * Clear all dirty bits, unless pages are treated as
-                        * dirty from the get-go.
-                        */
-                       if (!kvm_dirty_log_manual_protect_and_init_set(kvm))
-                               kvm_mmu_slot_leaf_clear_dirty(kvm, new);
-
-                       /*
-                        * Write-protect large pages on write so that dirty
-                        * logging happens at 4k granularity.  No need to
-                        * write-protect small SPTEs since write accesses are
-                        * logged by the CPU via dirty bits.
-                        */
-                       level = PG_LEVEL_2M;
-               } else if (kvm_dirty_log_manual_protect_and_init_set(kvm)) {
-                       /*
-                        * If we're with initial-all-set, we don't need
-                        * to write protect any small page because
-                        * they're reported as dirty already.  However
-                        * we still need to write-protect huge pages
-                        * so that the page split can happen lazily on
-                        * the first write to the huge page.
-                        */
-                       level = PG_LEVEL_2M;
+                       kvm_mmu_slot_leaf_clear_dirty(kvm, new);
+                       kvm_mmu_slot_remove_write_access(kvm, new, PG_LEVEL_2M);
+               } else {
+                       kvm_mmu_slot_remove_write_access(kvm, new, PG_LEVEL_4K);
                }
-               kvm_mmu_slot_remove_write_access(kvm, new, level);
        }
 }
 
@@ -11697,8 +12104,6 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
 {
        bool pcid_enabled;
        struct x86_exception e;
-       unsigned i;
-       unsigned long roots_to_free = 0;
        struct {
                u64 pcid;
                u64 gla;
@@ -11732,23 +12137,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
                        return 1;
                }
 
-               if (kvm_get_active_pcid(vcpu) == operand.pcid) {
-                       kvm_mmu_sync_roots(vcpu);
-                       kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
-               }
-
-               for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++)
-                       if (kvm_get_pcid(vcpu, vcpu->arch.mmu->prev_roots[i].pgd)
-                           == operand.pcid)
-                               roots_to_free |= KVM_MMU_ROOT_PREVIOUS(i);
-
-               kvm_mmu_free_roots(vcpu, vcpu->arch.mmu, roots_to_free);
-               /*
-                * If neither the current cr3 nor any of the prev_roots use the
-                * given PCID, then nothing needs to be done here because a
-                * resync will happen anyway before switching to any other CR3.
-                */
-
+               kvm_invalidate_pcid(vcpu, operand.pcid);
                return kvm_skip_emulated_instruction(vcpu);
 
        case INVPCID_TYPE_ALL_NON_GLOBAL:
@@ -11761,7 +12150,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
 
                fallthrough;
        case INVPCID_TYPE_ALL_INCL_GLOBAL:
-               kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
+               kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
                return kvm_skip_emulated_instruction(vcpu);
 
        default:
index 521f74e..44ae103 100644 (file)
@@ -157,16 +157,6 @@ static inline bool is_64_bit_mode(struct kvm_vcpu *vcpu)
        return cs_l;
 }
 
-static inline bool is_la57_mode(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_X86_64
-       return (vcpu->arch.efer & EFER_LMA) &&
-                kvm_read_cr4_bits(vcpu, X86_CR4_LA57);
-#else
-       return 0;
-#endif
-}
-
 static inline bool x86_exception_has_error_code(unsigned int vector)
 {
        static u32 exception_has_error_code = BIT(DF_VECTOR) | BIT(TS_VECTOR) |
index a67afd7..a1d24fd 100644 (file)
@@ -1417,7 +1417,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
        }
 }
 
-static unsigned long insn_get_effective_ip(struct pt_regs *regs)
+static int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip)
 {
        unsigned long seg_base = 0;
 
@@ -1430,10 +1430,12 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs)
        if (!user_64bit_mode(regs)) {
                seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
                if (seg_base == -1L)
-                       return 0;
+                       return -EINVAL;
        }
 
-       return seg_base + regs->ip;
+       *ip = seg_base + regs->ip;
+
+       return 0;
 }
 
 /**
@@ -1446,18 +1448,17 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs)
  *
  * Returns:
  *
- * Number of instruction bytes copied.
- *
- * 0 if nothing was copied.
+ * - number of instruction bytes copied.
+ * - 0 if nothing was copied.
+ * - -EINVAL if the linear address of the instruction could not be calculated
  */
 int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
 {
        unsigned long ip;
        int not_copied;
 
-       ip = insn_get_effective_ip(regs);
-       if (!ip)
-               return 0;
+       if (insn_get_effective_ip(regs, &ip))
+               return -EINVAL;
 
        not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE);
 
@@ -1475,18 +1476,17 @@ int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
  *
  * Returns:
  *
- * Number of instruction bytes copied.
- *
- * 0 if nothing was copied.
+ *  - number of instruction bytes copied.
+ *  - 0 if nothing was copied.
+ *  - -EINVAL if the linear address of the instruction could not be calculated.
  */
 int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
 {
        unsigned long ip;
        int not_copied;
 
-       ip = insn_get_effective_ip(regs);
-       if (!ip)
-               return 0;
+       if (insn_get_effective_ip(regs, &ip))
+               return -EINVAL;
 
        not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE);
 
index 4d32cb0..ec9922c 100644 (file)
@@ -58,12 +58,16 @@ SYM_FUNC_START_NOALIGN(__x86_indirect_alt_call_\reg)
 2:     .skip   5-(2b-1b), 0x90
 SYM_FUNC_END(__x86_indirect_alt_call_\reg)
 
+STACK_FRAME_NON_STANDARD(__x86_indirect_alt_call_\reg)
+
 SYM_FUNC_START_NOALIGN(__x86_indirect_alt_jmp_\reg)
        ANNOTATE_RETPOLINE_SAFE
 1:     jmp     *%\reg
 2:     .skip   5-(2b-1b), 0x90
 SYM_FUNC_END(__x86_indirect_alt_jmp_\reg)
 
+STACK_FRAME_NON_STANDARD(__x86_indirect_alt_jmp_\reg)
+
 .endm
 
 /*
index 6bda7f6..2d27932 100644 (file)
@@ -1186,7 +1186,7 @@ do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
                return;
 
        /* kprobes don't want to hook the spurious faults: */
-       if (kprobe_page_fault(regs, X86_TRAP_PF))
+       if (WARN_ON_ONCE(kprobe_page_fault(regs, X86_TRAP_PF)))
                return;
 
        /*
@@ -1239,7 +1239,7 @@ void do_user_addr_fault(struct pt_regs *regs,
        }
 
        /* kprobes don't want to hook the spurious faults: */
-       if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF)))
+       if (WARN_ON_ONCE(kprobe_page_fault(regs, X86_TRAP_PF)))
                return;
 
        /*
index 12c686c..60ade7d 100644 (file)
@@ -118,7 +118,9 @@ static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *des
        if (!IS_ENABLED(CONFIG_EFI))
                return;
 
-       if (efi_mem_type(addr) == EFI_RUNTIME_SERVICES_DATA)
+       if (efi_mem_type(addr) == EFI_RUNTIME_SERVICES_DATA ||
+           (efi_mem_type(addr) == EFI_BOOT_SERVICES_DATA &&
+            efi_mem_attributes(addr) & EFI_MEMORY_RUNTIME))
                desc->flags |= IORES_MAP_ENCRYPTED;
 }
 
index 5eb4dc2..e94da74 100644 (file)
@@ -254,7 +254,13 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
 
                /* make sure all non-reserved blocks are inside the limits */
                bi->start = max(bi->start, low);
-               bi->end = min(bi->end, high);
+
+               /* preserve info for non-RAM areas above 'max_pfn': */
+               if (bi->end > high) {
+                       numa_add_memblk_to(bi->nid, high, bi->end,
+                                          &numa_reserved_meminfo);
+                       bi->end = high;
+               }
 
                /* and there's no empty block */
                if (bi->start >= bi->end)
index a2332ee..4a67b92 100644 (file)
@@ -192,6 +192,10 @@ static const struct file_operations fops_init_pkru = {
 
 static int __init create_init_pkru_value(void)
 {
+       /* Do not expose the file if pkeys are not supported. */
+       if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
+               return 0;
+
        debugfs_create_file("init_pkru", S_IRUSR | S_IWUSR,
                        arch_debugfs_dir, NULL, &fops_init_pkru);
        return 0;
index 7880468..cfe6b1e 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/nospec-branch.h>
 #include <asm/cache.h>
 #include <asm/apic.h>
+#include <asm/perf_event.h>
 
 #include "mm_internal.h"
 
@@ -404,9 +405,14 @@ static inline void cr4_update_pce_mm(struct mm_struct *mm)
 {
        if (static_branch_unlikely(&rdpmc_always_available_key) ||
            (!static_branch_unlikely(&rdpmc_never_available_key) &&
-            atomic_read(&mm->context.perf_rdpmc_allowed)))
+            atomic_read(&mm->context.perf_rdpmc_allowed))) {
+               /*
+                * Clear the existing dirty counters to
+                * prevent the leak for an RDPMC task.
+                */
+               perf_clear_dirty_counters();
                cr4_set_bits_irqsoff(X86_CR4_PCE);
-       else
+       else
                cr4_clear_bits_irqsoff(X86_CR4_PCE);
 }
 
index 02dc646..2edd866 100644 (file)
@@ -779,4 +779,48 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
 
+#define RS690_LOWER_TOP_OF_DRAM2       0x30
+#define RS690_LOWER_TOP_OF_DRAM2_VALID 0x1
+#define RS690_UPPER_TOP_OF_DRAM2       0x31
+#define RS690_HTIU_NB_INDEX            0xA8
+#define RS690_HTIU_NB_INDEX_WR_ENABLE  0x100
+#define RS690_HTIU_NB_DATA             0xAC
+
+/*
+ * Some BIOS implementations support RAM above 4GB, but do not configure the
+ * PCI host to respond to bus master accesses for these addresses. These
+ * implementations set the TOP_OF_DRAM_SLOT1 register correctly, so PCI DMA
+ * works as expected for addresses below 4GB.
+ *
+ * Reference: "AMD RS690 ASIC Family Register Reference Guide" (pg. 2-57)
+ * https://www.amd.com/system/files/TechDocs/43372_rs690_rrg_3.00o.pdf
+ */
+static void rs690_fix_64bit_dma(struct pci_dev *pdev)
+{
+       u32 val = 0;
+       phys_addr_t top_of_dram = __pa(high_memory - 1) + 1;
+
+       if (top_of_dram <= (1ULL << 32))
+               return;
+
+       pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+                               RS690_LOWER_TOP_OF_DRAM2);
+       pci_read_config_dword(pdev, RS690_HTIU_NB_DATA, &val);
+
+       if (val)
+               return;
+
+       pci_info(pdev, "Adjusting top of DRAM to %pa for 64-bit DMA support\n", &top_of_dram);
+
+       pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+               RS690_UPPER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
+       pci_write_config_dword(pdev, RS690_HTIU_NB_DATA, top_of_dram >> 32);
+
+       pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
+               RS690_LOWER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
+       pci_write_config_dword(pdev, RS690_HTIU_NB_DATA,
+               top_of_dram | RS690_LOWER_TOP_OF_DRAM2_VALID);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma);
+
 #endif
index 8a26e70..147c30a 100644 (file)
@@ -468,7 +468,7 @@ void __init efi_init(void)
         */
 
        if (!efi_runtime_supported())
-               pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
+               pr_err("No EFI runtime due to 32/64-bit mismatch with kernel\n");
 
        if (!efi_runtime_supported() || efi_runtime_disabled()) {
                efi_memmap_unmap();
index 6b1f3a4..a0b491a 100644 (file)
@@ -10,7 +10,6 @@
 # Sanitizer runtimes are unavailable and cannot be linked here.
 KASAN_SANITIZE                 := n
 KCSAN_SANITIZE                 := n
-OBJECT_FILES_NON_STANDARD      := y
 
 subdir- := rm
 
index 2ed81e5..0575dec 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
-#include <asm/unistd.h>
 #include <asm/syscall.h>
 
 #define __NO_STUBS
 
 #define old_mmap sys_old_mmap
 
-#define __SYSCALL_I386(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
+#define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, native)
+
+#define __SYSCALL(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 #include <asm/syscalls_32.h>
 
-#undef __SYSCALL_I386
-#define __SYSCALL_I386(nr, sym) [ nr ] = sym,
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) sym,
 
 extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 
 const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_syscall_max] = &sys_ni_syscall,
 #include <asm/syscalls_32.h>
 };
 
index 2e8544d..95725b5 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
-#include <asm/unistd.h>
 #include <asm/syscall.h>
 
 #define __NO_STUBS
 #define stub_execveat sys_execveat
 #define stub_rt_sigreturn sys_rt_sigreturn
 
-#define __SYSCALL_X32(nr, sym)
-#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym)
-
-#define __SYSCALL_64(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
+#define __SYSCALL(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 #include <asm/syscalls_64.h>
 
-#undef __SYSCALL_64
-#define __SYSCALL_64(nr, sym) [ nr ] = sym,
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) sym,
 
 extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 
 const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_syscall_max] = &sys_ni_syscall,
 #include <asm/syscalls_64.h>
 };
 
index e87699a..0314942 100644 (file)
@@ -592,8 +592,10 @@ DEFINE_IDTENTRY_RAW(xenpv_exc_debug)
 DEFINE_IDTENTRY_RAW(exc_xen_unknown_trap)
 {
        /* This should never happen and there is no way to handle it. */
+       instrumentation_begin();
        pr_err("Unknown trap in Xen PV mode.");
        BUG();
+       instrumentation_end();
 }
 
 #ifdef CONFIG_X86_MCE
index 744c2f4..4361fe4 100644 (file)
@@ -43,7 +43,7 @@
  *
  * Atomically reads the value of @v.
  */
-#define atomic_read(v)         READ_ONCE((v)->counter)
+#define arch_atomic_read(v)            READ_ONCE((v)->counter)
 
 /**
  * atomic_set - set atomic variable
  *
  * Atomically sets the value of @v to @i.
  */
-#define atomic_set(v,i)                WRITE_ONCE((v)->counter, (i))
+#define arch_atomic_set(v,i)           WRITE_ONCE((v)->counter, (i))
 
 #if XCHAL_HAVE_EXCLUSIVE
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void arch_atomic_##op(int i, atomic_t *v)                        \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -74,7 +74,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int arch_atomic_##op##_return(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -95,7 +95,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int arch_atomic_fetch_##op(int i, atomic_t *v)           \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -116,7 +116,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                     \
 
 #elif XCHAL_HAVE_S32C1I
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t * v)                    \
+static inline void arch_atomic_##op(int i, atomic_t * v)               \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -135,7 +135,7 @@ static inline void atomic_##op(int i, atomic_t * v)                 \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t * v)            \
+static inline int arch_atomic_##op##_return(int i, atomic_t * v)       \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -157,7 +157,7 @@ static inline int atomic_##op##_return(int i, atomic_t * v)         \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t * v)               \
+static inline int arch_atomic_fetch_##op(int i, atomic_t * v)          \
 {                                                                      \
        unsigned long tmp;                                              \
        int result;                                                     \
@@ -180,7 +180,7 @@ static inline int atomic_fetch_##op(int i, atomic_t * v)            \
 #else /* XCHAL_HAVE_S32C1I */
 
 #define ATOMIC_OP(op)                                                  \
-static inline void atomic_##op(int i, atomic_t * v)                    \
+static inline void arch_atomic_##op(int i, atomic_t * v)               \
 {                                                                      \
        unsigned int vval;                                              \
                                                                        \
@@ -198,7 +198,7 @@ static inline void atomic_##op(int i, atomic_t * v)                 \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op)                                           \
-static inline int atomic_##op##_return(int i, atomic_t * v)            \
+static inline int arch_atomic_##op##_return(int i, atomic_t * v)       \
 {                                                                      \
        unsigned int vval;                                              \
                                                                        \
@@ -218,7 +218,7 @@ static inline int atomic_##op##_return(int i, atomic_t * v)         \
 }
 
 #define ATOMIC_FETCH_OP(op)                                            \
-static inline int atomic_fetch_##op(int i, atomic_t * v)               \
+static inline int arch_atomic_fetch_##op(int i, atomic_t * v)          \
 {                                                                      \
        unsigned int tmp, vval;                                         \
                                                                        \
@@ -257,7 +257,7 @@ ATOMIC_OPS(xor)
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define arch_atomic_cmpxchg(v, o, n) ((int)arch_cmpxchg(&((v)->counter), (o), (n)))
+#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 
 #endif /* _XTENSA_ATOMIC_H */
index a175f8a..3699e28 100644 (file)
@@ -80,7 +80,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        }
 }
 
-#define cmpxchg(ptr,o,n)                                                     \
+#define arch_cmpxchg(ptr,o,n)                                                \
        ({ __typeof__(*(ptr)) _o_ = (o);                                      \
           __typeof__(*(ptr)) _n_ = (n);                                      \
           (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,          \
@@ -97,7 +97,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        case 4:
                return __cmpxchg_u32(ptr, old, new);
        default:
-               return __cmpxchg_local_generic(ptr, old, new, size);
+               return __generic_cmpxchg_local(ptr, old, new, size);
        }
 
        return old;
@@ -107,11 +107,11 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
  * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
  * them available.
  */
-#define cmpxchg_local(ptr, o, n)                                              \
-       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
+#define arch_cmpxchg_local(ptr, o, n)                                         \
+       ((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o),\
                        (unsigned long)(n), sizeof(*(ptr))))
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-#define cmpxchg64(ptr, o, n)    cmpxchg64_local((ptr), (o), (n))
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
+#define arch_cmpxchg64(ptr, o, n)    arch_cmpxchg64_local((ptr), (o), (n))
 
 /*
  * xchg_u32
@@ -169,7 +169,7 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 #endif
 }
 
-#define xchg(ptr,x) \
+#define arch_xchg(ptr,x) \
        ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
index 9534ef5..0601653 100644 (file)
@@ -304,7 +304,7 @@ unsigned long get_wchan(struct task_struct *p)
        unsigned long stack_page = (unsigned long) task_stack_page(p);
        int count = 0;
 
-       if (!p || p == current || p->state == TASK_RUNNING)
+       if (!p || p == current || task_is_running(p))
                return 0;
 
        sp = p->thread.sp;
index cd85a7a..1254da0 100644 (file)
@@ -145,7 +145,6 @@ void secondary_start_kernel(void)
        cpumask_set_cpu(cpu, mm_cpumask(mm));
        enter_lazy_tlb(mm, current);
 
-       preempt_disable();
        trace_hardirqs_off();
 
        calibrate_delay();
index c86c01b..e41edae 100644 (file)
@@ -3886,7 +3886,7 @@ static bool blk_mq_poll_hybrid(struct request_queue *q,
 int blk_poll(struct request_queue *q, blk_qc_t cookie, bool spin)
 {
        struct blk_mq_hw_ctx *hctx;
-       long state;
+       unsigned int state;
 
        if (!blk_qc_t_valid(cookie) ||
            !test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
@@ -3910,7 +3910,7 @@ int blk_poll(struct request_queue *q, blk_qc_t cookie, bool spin)
 
        hctx->poll_considered++;
 
-       state = current->state;
+       state = get_current_state();
        do {
                int ret;
 
@@ -3926,7 +3926,7 @@ int blk_poll(struct request_queue *q, blk_qc_t cookie, bool spin)
                if (signal_pending_state(state, current))
                        __set_current_state(TASK_RUNNING);
 
-               if (current->state == TASK_RUNNING)
+               if (task_is_running(current))
                        return 1;
                if (ret < 0 || !spin)
                        break;
index 18cc82d..8bd288d 100644 (file)
@@ -411,7 +411,7 @@ int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
        if (n < 0)
                return n;
 
-       npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       npages = DIV_ROUND_UP(off + n, PAGE_SIZE);
        if (WARN_ON(npages == 0))
                return -EINVAL;
        /* Add one extra for linking */
index fdabf26..43f999d 100644 (file)
@@ -868,24 +868,6 @@ const char *crypto_attr_alg_name(struct rtattr *rta)
 }
 EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
 
-int crypto_attr_u32(struct rtattr *rta, u32 *num)
-{
-       struct crypto_attr_u32 *nu32;
-
-       if (!rta)
-               return -ENOENT;
-       if (RTA_PAYLOAD(rta) < sizeof(*nu32))
-               return -EINVAL;
-       if (rta->rta_type != CRYPTOA_U32)
-               return -EINVAL;
-
-       nu32 = RTA_DATA(rta);
-       *num = nu32->num;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(crypto_attr_u32);
-
 int crypto_inst_setname(struct crypto_instance *inst, const char *name,
                        struct crypto_alg *alg)
 {
index 5ebccbd..1814d2c 100644 (file)
@@ -28,16 +28,9 @@ struct cryptomgr_param {
                struct crypto_attr_type data;
        } type;
 
-       union {
+       struct {
                struct rtattr attr;
-               struct {
-                       struct rtattr attr;
-                       struct crypto_attr_alg data;
-               } alg;
-               struct {
-                       struct rtattr attr;
-                       struct crypto_attr_u32 data;
-               } nu32;
+               struct crypto_attr_alg data;
        } attrs[CRYPTO_MAX_ATTRS];
 
        char template[CRYPTO_MAX_ALG_NAME];
@@ -104,12 +97,10 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
 
        i = 0;
        for (;;) {
-               int notnum = 0;
-
                name = ++p;
 
                for (; isalnum(*p) || *p == '-' || *p == '_'; p++)
-                       notnum |= !isdigit(*p);
+                       ;
 
                if (*p == '(') {
                        int recursion = 0;
@@ -123,7 +114,6 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
                                        break;
                        }
 
-                       notnum = 1;
                        p++;
                }
 
@@ -131,18 +121,9 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
                if (!len)
                        goto err_free_param;
 
-               if (notnum) {
-                       param->attrs[i].alg.attr.rta_len =
-                               sizeof(param->attrs[i].alg);
-                       param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG;
-                       memcpy(param->attrs[i].alg.data.name, name, len);
-               } else {
-                       param->attrs[i].nu32.attr.rta_len =
-                               sizeof(param->attrs[i].nu32);
-                       param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32;
-                       param->attrs[i].nu32.data.num =
-                               simple_strtol(name, NULL, 0);
-               }
+               param->attrs[i].attr.rta_len = sizeof(param->attrs[i]);
+               param->attrs[i].attr.rta_type = CRYPTOA_ALG;
+               memcpy(param->attrs[i].data.name, name, len);
 
                param->tb[i + 1] = &param->attrs[i].attr;
                i++;
index 1b4587e..ea85d4a 100644 (file)
@@ -178,16 +178,16 @@ static const struct drbg_core drbg_cores[] = {
                .backend_cra_name = "hmac(sha384)",
        }, {
                .flags = DRBG_HMAC | DRBG_STRENGTH256,
-               .statelen = 64, /* block length of cipher */
-               .blocklen_bytes = 64,
-               .cra_name = "hmac_sha512",
-               .backend_cra_name = "hmac(sha512)",
-       }, {
-               .flags = DRBG_HMAC | DRBG_STRENGTH256,
                .statelen = 32, /* block length of cipher */
                .blocklen_bytes = 32,
                .cra_name = "hmac_sha256",
                .backend_cra_name = "hmac(sha256)",
+       }, {
+               .flags = DRBG_HMAC | DRBG_STRENGTH256,
+               .statelen = 64, /* block length of cipher */
+               .blocklen_bytes = 64,
+               .cra_name = "hmac_sha512",
+               .backend_cra_name = "hmac(sha512)",
        },
 #endif /* CONFIG_CRYPTO_DRBG_HMAC */
 };
index 04a427b..c6f61c2 100644 (file)
@@ -141,7 +141,7 @@ static struct kpp_alg ecdh_nist_p192 = {
        .init = ecdh_nist_p192_init_tfm,
        .base = {
                .cra_name = "ecdh-nist-p192",
-               .cra_driver_name = "ecdh-generic",
+               .cra_driver_name = "ecdh-nist-p192-generic",
                .cra_priority = 100,
                .cra_module = THIS_MODULE,
                .cra_ctxsize = sizeof(struct ecdh_ctx),
@@ -166,7 +166,32 @@ static struct kpp_alg ecdh_nist_p256 = {
        .init = ecdh_nist_p256_init_tfm,
        .base = {
                .cra_name = "ecdh-nist-p256",
-               .cra_driver_name = "ecdh-generic",
+               .cra_driver_name = "ecdh-nist-p256-generic",
+               .cra_priority = 100,
+               .cra_module = THIS_MODULE,
+               .cra_ctxsize = sizeof(struct ecdh_ctx),
+       },
+};
+
+static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
+{
+       struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
+
+       ctx->curve_id = ECC_CURVE_NIST_P384;
+       ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS;
+
+       return 0;
+}
+
+static struct kpp_alg ecdh_nist_p384 = {
+       .set_secret = ecdh_set_secret,
+       .generate_public_key = ecdh_compute_value,
+       .compute_shared_secret = ecdh_compute_value,
+       .max_size = ecdh_max_size,
+       .init = ecdh_nist_p384_init_tfm,
+       .base = {
+               .cra_name = "ecdh-nist-p384",
+               .cra_driver_name = "ecdh-nist-p384-generic",
                .cra_priority = 100,
                .cra_module = THIS_MODULE,
                .cra_ctxsize = sizeof(struct ecdh_ctx),
@@ -179,10 +204,27 @@ static int ecdh_init(void)
 {
        int ret;
 
+       /* NIST p192 will fail to register in FIPS mode */
        ret = crypto_register_kpp(&ecdh_nist_p192);
        ecdh_nist_p192_registered = ret == 0;
 
-       return crypto_register_kpp(&ecdh_nist_p256);
+       ret = crypto_register_kpp(&ecdh_nist_p256);
+       if (ret)
+               goto nist_p256_error;
+
+       ret = crypto_register_kpp(&ecdh_nist_p384);
+       if (ret)
+               goto nist_p384_error;
+
+       return 0;
+
+nist_p384_error:
+       crypto_unregister_kpp(&ecdh_nist_p256);
+
+nist_p256_error:
+       if (ecdh_nist_p192_registered)
+               crypto_unregister_kpp(&ecdh_nist_p192);
+       return ret;
 }
 
 static void ecdh_exit(void)
@@ -190,6 +232,7 @@ static void ecdh_exit(void)
        if (ecdh_nist_p192_registered)
                crypto_unregister_kpp(&ecdh_nist_p192);
        crypto_unregister_kpp(&ecdh_nist_p256);
+       crypto_unregister_kpp(&ecdh_nist_p384);
 }
 
 subsys_initcall(ecdh_init);
index 976ec9d..f00869a 100644 (file)
@@ -29,6 +29,18 @@ struct crypto_larval {
        u32 mask;
 };
 
+enum {
+       CRYPTOA_UNSPEC,
+       CRYPTOA_ALG,
+       CRYPTOA_TYPE,
+       __CRYPTOA_MAX,
+};
+
+#define CRYPTOA_MAX (__CRYPTOA_MAX - 1)
+
+/* Maximum number of (rtattr) parameters for each template. */
+#define CRYPTO_MAX_ATTRS 32
+
 extern struct list_head crypto_alg_list;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct blocking_notifier_head crypto_chain;
index 14ca7f1..f193399 100644 (file)
@@ -819,7 +819,7 @@ static void khazad_crypt(const u64 roundKey[KHAZAD_ROUNDS + 1],
                        T6[(int)(state >>  8) & 0xff] ^
                        T7[(int)(state      ) & 0xff] ^
                        roundKey[r];
-       }
+       }
 
        state = (T0[(int)(state >> 56)       ] & 0xff00000000000000ULL) ^
                (T1[(int)(state >> 48) & 0xff] & 0x00ff000000000000ULL) ^
index 2e3433a..0a0a50c 100644 (file)
 
 static const struct crypto_type crypto_shash_type;
 
-int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-                   unsigned int keylen)
+static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+                          unsigned int keylen)
 {
        return -ENOSYS;
 }
-EXPORT_SYMBOL_GPL(shash_no_setkey);
+
+/*
+ * Check whether an shash algorithm has a setkey function.
+ *
+ * For CFI compatibility, this must not be an inline function.  This is because
+ * when CFI is enabled, modules won't get the same address for shash_no_setkey
+ * (if it were exported, which inlining would require) as the core kernel will.
+ */
+bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+       return alg->setkey != shash_no_setkey;
+}
+EXPORT_SYMBOL_GPL(crypto_shash_alg_has_setkey);
 
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
                                  unsigned int keylen)
index b21addc..db8a4a2 100644 (file)
@@ -79,10 +79,17 @@ static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
                goto free;
 
        rc = -ENOMEM;
+
+       ec->Q = mpi_point_new(0);
+       if (!ec->Q)
+               goto free;
+
        /* mpi_ec_setup_elliptic_curve */
        ec->G = mpi_point_new(0);
-       if (!ec->G)
+       if (!ec->G) {
+               mpi_point_release(ec->Q);
                goto free;
+       }
 
        mpi_set(ec->G->x, x);
        mpi_set(ec->G->y, y);
@@ -91,6 +98,7 @@ static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
        rc = -EINVAL;
        ec->n = mpi_scanval(ecp->n);
        if (!ec->n) {
+               mpi_point_release(ec->Q);
                mpi_point_release(ec->G);
                goto free;
        }
@@ -386,27 +394,15 @@ static int sm2_set_pub_key(struct crypto_akcipher *tfm,
        MPI a;
        int rc;
 
-       ec->Q = mpi_point_new(0);
-       if (!ec->Q)
-               return -ENOMEM;
-
        /* include the uncompressed flag '0x04' */
-       rc = -ENOMEM;
        a = mpi_read_raw_data(key, keylen);
        if (!a)
-               goto error;
+               return -ENOMEM;
 
        mpi_normalize(a);
        rc = sm2_ecc_os2ec(ec->Q, a);
        mpi_free(a);
-       if (rc)
-               goto error;
-
-       return 0;
 
-error:
-       mpi_point_release(ec->Q);
-       ec->Q = NULL;
        return rc;
 }
 
index 6b7c158..f8d06da 100644 (file)
@@ -1847,10 +1847,22 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                ret += tcrypt_test("cts(cbc(aes))");
                break;
 
+        case 39:
+               ret += tcrypt_test("xxhash64");
+               break;
+
         case 40:
                ret += tcrypt_test("rmd160");
                break;
 
+       case 41:
+               ret += tcrypt_test("blake2s-256");
+               break;
+
+       case 42:
+               ret += tcrypt_test("blake2b-512");
+               break;
+
        case 43:
                ret += tcrypt_test("ecb(seed)");
                break;
@@ -2356,10 +2368,22 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                test_hash_speed("sha224", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
                fallthrough;
+       case 314:
+               test_hash_speed("xxhash64", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+               fallthrough;
        case 315:
                test_hash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
                fallthrough;
+       case 316:
+               test_hash_speed("blake2s-256", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+               fallthrough;
+       case 317:
+               test_hash_speed("blake2b-512", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+               fallthrough;
        case 318:
                klen = 16;
                test_hash_speed("ghash", sec, generic_hash_speed_template);
@@ -2456,10 +2480,22 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
                test_ahash_speed("sha224", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
                fallthrough;
+       case 414:
+               test_ahash_speed("xxhash64", sec, generic_hash_speed_template);
+               if (mode > 400 && mode < 500) break;
+               fallthrough;
        case 415:
                test_ahash_speed("rmd160", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
                fallthrough;
+       case 416:
+               test_ahash_speed("blake2s-256", sec, generic_hash_speed_template);
+               if (mode > 400 && mode < 500) break;
+               fallthrough;
+       case 417:
+               test_ahash_speed("blake2b-512", sec, generic_hash_speed_template);
+               if (mode > 400 && mode < 500) break;
+               fallthrough;
        case 418:
                test_ahash_speed("sha3-224", sec, generic_hash_speed_template);
                if (mode > 400 && mode < 500) break;
index 10c5b3b..1f7f63e 100644 (file)
@@ -4899,15 +4899,12 @@ static const struct alg_test_desc alg_test_descs[] = {
                }
        }, {
 #endif
-#ifndef CONFIG_CRYPTO_FIPS
                .alg = "ecdh-nist-p192",
                .test = alg_test_kpp,
-               .fips_allowed = 1,
                .suite = {
                        .kpp = __VECS(ecdh_p192_tv_template)
                }
        }, {
-#endif
                .alg = "ecdh-nist-p256",
                .test = alg_test_kpp,
                .fips_allowed = 1,
@@ -4915,6 +4912,13 @@ static const struct alg_test_desc alg_test_descs[] = {
                        .kpp = __VECS(ecdh_p256_tv_template)
                }
        }, {
+               .alg = "ecdh-nist-p384",
+               .test = alg_test_kpp,
+               .fips_allowed = 1,
+               .suite = {
+                       .kpp = __VECS(ecdh_p384_tv_template)
+               }
+       }, {
                .alg = "ecdsa-nist-p192",
                .test = alg_test_akcipher,
                .suite = {
index 34e4a3d..96eb7ce 100644 (file)
@@ -2685,7 +2685,6 @@ static const struct kpp_testvec curve25519_tv_template[] = {
 }
 };
 
-#ifndef CONFIG_CRYPTO_FIPS
 static const struct kpp_testvec ecdh_p192_tv_template[] = {
        {
        .secret =
@@ -2719,13 +2718,12 @@ static const struct kpp_testvec ecdh_p192_tv_template[] = {
        "\xf4\x57\xcc\x4f\x1f\x4e\x31\xcc"
        "\xe3\x40\x60\xc8\x06\x93\xc6\x2e"
        "\x99\x80\x81\x28\xaf\xc5\x51\x74",
-       .secret_size = 32,
+       .secret_size = 30,
        .b_public_size = 48,
        .expected_a_public_size = 48,
        .expected_ss_size = 24
        }
 };
-#endif
 
 static const struct kpp_testvec ecdh_p256_tv_template[] = {
        {
@@ -2766,7 +2764,7 @@ static const struct kpp_testvec ecdh_p256_tv_template[] = {
        "\x9f\x4a\x38\xcc\xc0\x2c\x49\x2f"
        "\xb1\x32\xbb\xaf\x22\x61\xda\xcb"
        "\x6f\xdb\xa9\xaa\xfc\x77\x81\xf3",
-       .secret_size = 40,
+       .secret_size = 38,
        .b_public_size = 64,
        .expected_a_public_size = 64,
        .expected_ss_size = 32
@@ -2804,8 +2802,8 @@ static const struct kpp_testvec ecdh_p256_tv_template[] = {
        "\x37\x08\xcc\x40\x5e\x7a\xfd\x6a"
        "\x6a\x02\x6e\x41\x87\x68\x38\x77"
        "\xfa\xa9\x44\x43\x2d\xef\x09\xdf",
-       .secret_size = 8,
-       .b_secret_size = 40,
+       .secret_size = 6,
+       .b_secret_size = 38,
        .b_public_size = 64,
        .expected_a_public_size = 64,
        .expected_ss_size = 32,
@@ -2814,6 +2812,67 @@ static const struct kpp_testvec ecdh_p256_tv_template[] = {
 };
 
 /*
+ * NIST P384 test vectors from RFC5903
+ */
+static const struct kpp_testvec ecdh_p384_tv_template[] = {
+       {
+       .secret =
+#ifdef __LITTLE_ENDIAN
+       "\x02\x00" /* type */
+       "\x36\x00" /* len */
+       "\x30\x00" /* key_size */
+#else
+       "\x00\x02" /* type */
+       "\x00\x36" /* len */
+       "\x00\x30" /* key_size */
+#endif
+       "\x09\x9F\x3C\x70\x34\xD4\xA2\xC6"
+       "\x99\x88\x4D\x73\xA3\x75\xA6\x7F"
+       "\x76\x24\xEF\x7C\x6B\x3C\x0F\x16"
+       "\x06\x47\xB6\x74\x14\xDC\xE6\x55"
+       "\xE3\x5B\x53\x80\x41\xE6\x49\xEE"
+       "\x3F\xAE\xF8\x96\x78\x3A\xB1\x94",
+       .b_public =
+       "\xE5\x58\xDB\xEF\x53\xEE\xCD\xE3"
+       "\xD3\xFC\xCF\xC1\xAE\xA0\x8A\x89"
+       "\xA9\x87\x47\x5D\x12\xFD\x95\x0D"
+       "\x83\xCF\xA4\x17\x32\xBC\x50\x9D"
+       "\x0D\x1A\xC4\x3A\x03\x36\xDE\xF9"
+       "\x6F\xDA\x41\xD0\x77\x4A\x35\x71"
+       "\xDC\xFB\xEC\x7A\xAC\xF3\x19\x64"
+       "\x72\x16\x9E\x83\x84\x30\x36\x7F"
+       "\x66\xEE\xBE\x3C\x6E\x70\xC4\x16"
+       "\xDD\x5F\x0C\x68\x75\x9D\xD1\xFF"
+       "\xF8\x3F\xA4\x01\x42\x20\x9D\xFF"
+       "\x5E\xAA\xD9\x6D\xB9\xE6\x38\x6C",
+       .expected_a_public =
+       "\x66\x78\x42\xD7\xD1\x80\xAC\x2C"
+       "\xDE\x6F\x74\xF3\x75\x51\xF5\x57"
+       "\x55\xC7\x64\x5C\x20\xEF\x73\xE3"
+       "\x16\x34\xFE\x72\xB4\xC5\x5E\xE6"
+       "\xDE\x3A\xC8\x08\xAC\xB4\xBD\xB4"
+       "\xC8\x87\x32\xAE\xE9\x5F\x41\xAA"
+       "\x94\x82\xED\x1F\xC0\xEE\xB9\xCA"
+       "\xFC\x49\x84\x62\x5C\xCF\xC2\x3F"
+       "\x65\x03\x21\x49\xE0\xE1\x44\xAD"
+       "\xA0\x24\x18\x15\x35\xA0\xF3\x8E"
+       "\xEB\x9F\xCF\xF3\xC2\xC9\x47\xDA"
+       "\xE6\x9B\x4C\x63\x45\x73\xA8\x1C",
+       .expected_ss =
+       "\x11\x18\x73\x31\xC2\x79\x96\x2D"
+       "\x93\xD6\x04\x24\x3F\xD5\x92\xCB"
+       "\x9D\x0A\x92\x6F\x42\x2E\x47\x18"
+       "\x75\x21\x28\x7E\x71\x56\xC5\xC4"
+       "\xD6\x03\x13\x55\x69\xB9\xE9\xD0"
+       "\x9C\xF5\xD4\xA2\x70\xF5\x97\x46",
+       .secret_size = 54,
+       .b_public_size = 96,
+       .expected_a_public_size = 96,
+       .expected_ss_size = 48
+       }
+};
+
+/*
  * MD4 test vectors from RFC1320
  */
 static const struct hash_testvec md4_tv_template[] = {
index feadc13..bf79fbb 100644 (file)
@@ -1066,33 +1066,31 @@ static int wp512_final(struct shash_desc *desc, u8 *out)
 {
        struct wp512_ctx *wctx = shash_desc_ctx(desc);
        int i;
-       u8 *buffer      = wctx->buffer;
-       u8 *bitLength   = wctx->bitLength;
-       int bufferBits  = wctx->bufferBits;
-       int bufferPos   = wctx->bufferPos;
+       u8 *buffer      = wctx->buffer;
+       u8 *bitLength   = wctx->bitLength;
+       int bufferBits  = wctx->bufferBits;
+       int bufferPos   = wctx->bufferPos;
        __be64 *digest  = (__be64 *)out;
 
-       buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
-       bufferPos++;
-       if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
-               if (bufferPos < WP512_BLOCK_SIZE) {
-               memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos);
-               }
-               wp512_process_buffer(wctx);
-               bufferPos = 0;
-       }
-       if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
-               memset(&buffer[bufferPos], 0,
+       buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
+       bufferPos++;
+       if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
+               if (bufferPos < WP512_BLOCK_SIZE)
+                       memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos);
+               wp512_process_buffer(wctx);
+               bufferPos = 0;
+       }
+       if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES)
+               memset(&buffer[bufferPos], 0,
                          (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos);
-       }
-       bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES;
-       memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES],
+       bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES;
+       memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES],
                   bitLength, WP512_LENGTHBYTES);
-       wp512_process_buffer(wctx);
+       wp512_process_buffer(wctx);
        for (i = 0; i < WP512_DIGEST_SIZE/8; i++)
                digest[i] = cpu_to_be64(wctx->hash[i]);
-       wctx->bufferBits   = bufferBits;
-       wctx->bufferPos    = bufferPos;
+       wctx->bufferBits   = bufferBits;
+       wctx->bufferPos    = bufferPos;
 
        return 0;
 }
index 47980c6..8bad634 100644 (file)
@@ -33,8 +33,6 @@ source "drivers/nvme/Kconfig"
 
 source "drivers/misc/Kconfig"
 
-source "drivers/ide/Kconfig"
-
 source "drivers/scsi/Kconfig"
 
 source "drivers/ata/Kconfig"
index 5a6d613..27c018b 100644 (file)
@@ -78,7 +78,6 @@ obj-$(CONFIG_CXL_BUS)         += cxl/
 obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-y                          += macintosh/
-obj-$(CONFIG_IDE)              += ide/
 obj-y                          += scsi/
 obj-y                          += nvme/
 obj-$(CONFIG_ATA)              += ata/
@@ -161,7 +160,7 @@ obj-$(CONFIG_SOUNDWIRE)             += soundwire/
 
 # Virtualization drivers
 obj-$(CONFIG_VIRT_DRIVERS)     += virt/
-obj-$(CONFIG_HYPERV)           += hv/
+obj-$(subst m,y,$(CONFIG_HYPERV))      += hv/
 
 obj-$(CONFIG_PM_DEVFREQ)       += devfreq/
 obj-$(CONFIG_EXTCON)           += extcon/
index 9861302..359bead 100644 (file)
@@ -246,6 +246,7 @@ static int keyboard_notifier_call(struct notifier_block *blk,
                                beep(440);
                }
        }
+               break;
        case KBD_UNBOUND_KEYCODE:
        case KBD_UNICODE:
        case KBD_KEYSYM:
index 030cb32..b7a5abe 100644 (file)
@@ -1015,11 +1015,11 @@ config PATA_CMD640_PCI
          If unsure, say N.
 
 config PATA_FALCON
-       tristate "Atari Falcon PATA support"
-       depends on M68K && ATARI
+       tristate "Atari Falcon and Q40/Q60 PATA support"
+       depends on M68K && (ATARI || Q40)
        help
          This option enables support for the on-board IDE
-         interface on the Atari Falcon.
+         interface on the Atari Falcon and Q40/Q60.
 
          If unsure, say N.
 
index 33192a8..186cbf9 100644 (file)
@@ -446,6 +446,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
 
+       /* Dell S140/S150 */
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_SUBVENDOR_ID_DELL, PCI_ANY_ID,
+         PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
+
        /* VIA */
        { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
        { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
index d1f284f..2e89499 100644 (file)
@@ -384,12 +384,15 @@ extern struct device_attribute *ahci_sdev_attrs[];
  * for ATA_BASE_SHT
  */
 #define AHCI_SHT(drv_name)                                             \
-       ATA_NCQ_SHT(drv_name),                                          \
+       __ATA_BASE_SHT(drv_name),                                       \
        .can_queue              = AHCI_MAX_CMDS,                        \
        .sg_tablesize           = AHCI_MAX_SG,                          \
        .dma_boundary           = AHCI_DMA_BOUNDARY,                    \
        .shost_attrs            = ahci_shost_attrs,                     \
-       .sdev_attrs             = ahci_sdev_attrs
+       .sdev_attrs             = ahci_sdev_attrs,                      \
+       .change_queue_depth     = ata_scsi_change_queue_depth,          \
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,                     \
+       .slave_configure        = ata_scsi_slave_config
 
 extern struct ata_port_operations ahci_ops;
 extern struct ata_port_operations ahci_platform_ops;
index cb69b73..56b6951 100644 (file)
@@ -200,7 +200,7 @@ static void ahci_sunxi_start_engine(struct ata_port *ap)
 }
 
 static const struct ata_port_info ahci_sunxi_port_info = {
-       .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .flags          = AHCI_FLAG_COMMON | ATA_FLAG_NCQ | ATA_FLAG_NO_DIPM,
        .pio_mask       = ATA_PIO4,
        .udma_mask      = ATA_UDMA6,
        .port_ops       = &ahci_platform_ops,
index d671d33..c3a65cc 100644 (file)
@@ -252,8 +252,9 @@ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
 }
 
 static struct scsi_host_template atiixp_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize           = LIBATA_DUMB_MAX_PRD,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
 };
 
 static struct ata_port_operations atiixp_port_ops = {
index d09d432..247c147 100644 (file)
@@ -95,8 +95,9 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
 }
 
 static struct scsi_host_template cs5520_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize           = LIBATA_DUMB_MAX_PRD,
+       .dma_boundary           = ATA_DMA_BOUNDARY,
 };
 
 static struct ata_port_operations cs5520_port_ops = {
index a1b4aac..d5b7ac1 100644 (file)
@@ -147,8 +147,9 @@ static unsigned int cs5530_qc_issue(struct ata_queued_cmd *qc)
 }
 
 static struct scsi_host_template cs5530_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize   = LIBATA_DUMB_MAX_PRD,
+       .dma_boundary   = ATA_DMA_BOUNDARY,
 };
 
 static struct ata_port_operations cs5530_port_ops = {
index e1486fe..5b3a7a8 100644 (file)
@@ -41,6 +41,10 @@ enum {
        CY82_INDEX_TIMEOUT      = 0x32
 };
 
+static bool enable_dma = true;
+module_param(enable_dma, bool, 0);
+MODULE_PARM_DESC(enable_dma, "Enable bus master DMA operations");
+
 /**
  *     cy82c693_set_piomode    -       set initial PIO mode data
  *     @ap: ATA interface
@@ -124,14 +128,16 @@ static struct ata_port_operations cy82c693_port_ops = {
 
 static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       static const struct ata_port_info info = {
+       static struct ata_port_info info = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
-               .mwdma_mask = ATA_MWDMA2,
                .port_ops = &cy82c693_port_ops
        };
        const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
 
+       if (enable_dma)
+               info.mwdma_mask = ATA_MWDMA2;
+
        /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
           For the moment we don't handle the secondary. FIXME */
 
index badab67..46208ec 100644 (file)
@@ -928,7 +928,7 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
        /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               err = -ENXIO;
+               err = irq;
                goto err_rel_gpio;
        }
 
index 27b0952..9d0dd8f 100644 (file)
@@ -33,8 +33,6 @@
 #define DRV_NAME "pata_falcon"
 #define DRV_VERSION "0.1.0"
 
-#define ATA_HD_CONTROL 0x39
-
 static struct scsi_host_template pata_falcon_sht = {
        ATA_PIO_SHT(DRV_NAME),
 };
@@ -121,23 +119,42 @@ static struct ata_port_operations pata_falcon_ops = {
 
 static int __init pata_falcon_init_one(struct platform_device *pdev)
 {
-       struct resource *res;
+       struct resource *base_mem_res, *ctl_mem_res;
+       struct resource *base_res, *ctl_res, *irq_res;
        struct ata_host *host;
        struct ata_port *ap;
        void __iomem *base;
+       int irq = 0;
 
-       dev_info(&pdev->dev, "Atari Falcon PATA controller\n");
+       dev_info(&pdev->dev, "Atari Falcon and Q40/Q60 PATA controller\n");
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
+       base_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (base_res && !devm_request_region(&pdev->dev, base_res->start,
+                                          resource_size(base_res), DRV_NAME)) {
+               dev_err(&pdev->dev, "resources busy\n");
+               return -EBUSY;
+       }
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), DRV_NAME)) {
+       ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+       if (ctl_res && !devm_request_region(&pdev->dev, ctl_res->start,
+                                           resource_size(ctl_res), DRV_NAME)) {
                dev_err(&pdev->dev, "resources busy\n");
                return -EBUSY;
        }
 
+       base_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!base_mem_res)
+               return -ENODEV;
+       if (!devm_request_mem_region(&pdev->dev, base_mem_res->start,
+                                    resource_size(base_mem_res), DRV_NAME)) {
+               dev_err(&pdev->dev, "resources busy\n");
+               return -EBUSY;
+       }
+
+       ctl_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!ctl_mem_res)
+               return -ENODEV;
+
        /* allocate host */
        host = ata_host_alloc(&pdev->dev, 1);
        if (!host)
@@ -147,10 +164,10 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
        ap->ops = &pata_falcon_ops;
        ap->pio_mask = ATA_PIO4;
        ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
-       ap->flags |= ATA_FLAG_PIO_POLLING;
 
-       base = (void __iomem *)res->start;
-       ap->ioaddr.data_addr            = base;
+       base = (void __iomem *)base_mem_res->start;
+       /* N.B. this assumes data_addr will be used for word-sized I/O only */
+       ap->ioaddr.data_addr            = base + 0 + 0 * 4;
        ap->ioaddr.error_addr           = base + 1 + 1 * 4;
        ap->ioaddr.feature_addr         = base + 1 + 1 * 4;
        ap->ioaddr.nsect_addr           = base + 1 + 2 * 4;
@@ -161,14 +178,25 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
        ap->ioaddr.status_addr          = base + 1 + 7 * 4;
        ap->ioaddr.command_addr         = base + 1 + 7 * 4;
 
-       ap->ioaddr.altstatus_addr       = base + ATA_HD_CONTROL;
-       ap->ioaddr.ctl_addr             = base + ATA_HD_CONTROL;
+       base = (void __iomem *)ctl_mem_res->start;
+       ap->ioaddr.altstatus_addr       = base + 1;
+       ap->ioaddr.ctl_addr             = base + 1;
 
-       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", (unsigned long)base,
-                     (unsigned long)base + ATA_HD_CONTROL);
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+                     (unsigned long)base_mem_res->start,
+                     (unsigned long)ctl_mem_res->start);
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irq_res && irq_res->start > 0) {
+               irq = irq_res->start;
+       } else {
+               ap->flags |= ATA_FLAG_PIO_POLLING;
+               ata_port_desc(ap, "no IRQ, using PIO polling");
+       }
 
        /* activate */
-       return ata_host_activate(host, 0, NULL, 0, &pata_falcon_sht);
+       return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
+                                IRQF_SHARED, &pata_falcon_sht);
 }
 
 static int __exit pata_falcon_remove_one(struct platform_device *pdev)
index e47a282..be0ca8d 100644 (file)
@@ -914,7 +914,7 @@ static int pata_macio_do_resume(struct pata_macio_priv *priv)
 #endif /* CONFIG_PM_SLEEP */
 
 static struct scsi_host_template pata_macio_sht = {
-       ATA_BASE_SHT(DRV_NAME),
+       __ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize           = MAX_DCMDS,
        /* We may not need that strict one */
        .dma_boundary           = ATA_DMA_BOUNDARY,
@@ -923,6 +923,9 @@ static struct scsi_host_template pata_macio_sht = {
         */
        .max_segment_size       = MAX_DBDMA_SEG,
        .slave_configure        = pata_macio_slave_config,
+       .sdev_attrs             = ata_common_sdev_attrs,
+       .can_queue              = ATA_DEF_QUEUE,
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,
 };
 
 static struct ata_port_operations pata_macio_ops = {
index bd87476..b5a3f71 100644 (file)
@@ -898,10 +898,11 @@ static int octeon_cf_probe(struct platform_device *pdev)
                                        return -EINVAL;
                                }
 
-                               irq_handler = octeon_cf_interrupt;
                                i = platform_get_irq(dma_dev, 0);
-                               if (i > 0)
+                               if (i > 0) {
                                        irq = i;
+                                       irq_handler = octeon_cf_interrupt;
+                               }
                        }
                        of_node_put(dma_node);
                }
index 479c4b2..2e110ae 100644 (file)
@@ -115,10 +115,10 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(&pdev->dev, "no IRQ resource found\n");
-               return -ENOENT;
-       }
+       if (irq < 0)
+               return irq;
+       if (!irq)
+               return -EINVAL;
 
        gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
        if (IS_ERR(gpiod)) {
index 3b8c111..f28daf6 100644 (file)
@@ -193,8 +193,9 @@ static int sc1200_qc_defer(struct ata_queued_cmd *qc)
 }
 
 static struct scsi_host_template sc1200_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize   = LIBATA_DUMB_MAX_PRD,
+       .dma_boundary   = ATA_DMA_BOUNDARY,
 };
 
 static struct ata_port_operations sc1200_port_ops = {
index 7511e11..b602e30 100644 (file)
@@ -253,8 +253,9 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev
 }
 
 static struct scsi_host_template serverworks_osb4_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize   = LIBATA_DUMB_MAX_PRD,
+       .dma_boundary   = ATA_DMA_BOUNDARY,
 };
 
 static struct scsi_host_template serverworks_csb_sht = {
index d55ee24..e5838b2 100644 (file)
@@ -313,7 +313,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
 
        DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
                        intr_coalescing_count, intr_coalescing_ticks);
-       DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
+       DPRINTK("ICC register status: (hcr base: %p) = 0x%x\n",
                        hcr_base, ioread32(hcr_base + ICC));
 }
 
index 64b2ef1..8440203 100644 (file)
@@ -469,10 +469,12 @@ static int ahci_highbank_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
+       if (irq < 0) {
                dev_err(dev, "no irq\n");
-               return -EINVAL;
+               return irq;
        }
+       if (!irq)
+               return -EINVAL;
 
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv) {
index c8867c1..9d86203 100644 (file)
@@ -666,10 +666,14 @@ static struct scsi_host_template mv5_sht = {
 };
 #endif
 static struct scsi_host_template mv6_sht = {
-       ATA_NCQ_SHT(DRV_NAME),
+       __ATA_BASE_SHT(DRV_NAME),
        .can_queue              = MV_MAX_Q_DEPTH - 1,
        .sg_tablesize           = MV_MAX_SG_CT / 2,
        .dma_boundary           = MV_DMA_BOUNDARY,
+       .sdev_attrs             = ata_ncq_sdev_attrs,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,
+       .slave_configure        = ata_scsi_slave_config
 };
 
 static struct ata_port_operations mv5_ops = {
index 20190f6..c385d18 100644 (file)
@@ -375,19 +375,25 @@ static struct scsi_host_template nv_sht = {
 };
 
 static struct scsi_host_template nv_adma_sht = {
-       ATA_NCQ_SHT(DRV_NAME),
+       __ATA_BASE_SHT(DRV_NAME),
        .can_queue              = NV_ADMA_MAX_CPBS,
        .sg_tablesize           = NV_ADMA_SGTBL_TOTAL_LEN,
        .dma_boundary           = NV_ADMA_DMA_BOUNDARY,
        .slave_configure        = nv_adma_slave_config,
+       .sdev_attrs             = ata_ncq_sdev_attrs,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,
 };
 
 static struct scsi_host_template nv_swncq_sht = {
-       ATA_NCQ_SHT(DRV_NAME),
+       __ATA_BASE_SHT(DRV_NAME),
        .can_queue              = ATA_MAX_QUEUE - 1,
        .sg_tablesize           = LIBATA_MAX_PRD,
        .dma_boundary           = ATA_DMA_BOUNDARY,
        .slave_configure        = nv_swncq_slave_config,
+       .sdev_attrs             = ata_ncq_sdev_attrs,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,
 };
 
 /*
@@ -2118,7 +2124,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
                 */
                lack_dhfis = 1;
 
-       DPRINTK("id 0x%x QC: qc_active 0x%x,"
+       DPRINTK("id 0x%x QC: qc_active 0x%llx,"
                "SWNCQ:qc_active 0x%X defer_bits %X "
                "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
                ap->print_id, ap->qc_active, pp->qc_active,
index 560070d..06a1e27 100644 (file)
@@ -374,11 +374,14 @@ static struct pci_driver sil24_pci_driver = {
 };
 
 static struct scsi_host_template sil24_sht = {
-       ATA_NCQ_SHT(DRV_NAME),
+       __ATA_BASE_SHT(DRV_NAME),
        .can_queue              = SIL24_MAX_CMDS,
        .sg_tablesize           = SIL24_MAX_SGE,
        .dma_boundary           = ATA_DMA_BOUNDARY,
        .tag_alloc_policy       = BLK_TAG_ALLOC_FIFO,
+       .sdev_attrs             = ata_ncq_sdev_attrs,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .slave_configure        = ata_scsi_slave_config
 };
 
 static struct ata_port_operations sil24_ops = {
index b508df2..fb2be35 100644 (file)
@@ -420,6 +420,7 @@ fore200e_shutdown(struct fore200e* fore200e)
        /* XXX shouldn't we *start* by deregistering the device? */
        atm_dev_deregister(fore200e->atm_dev);
 
+       fallthrough;
     case FORE200E_STATE_BLANK:
        /* nothing to do for that state */
        break;
index b6a782c..ab0b740 100644 (file)
@@ -379,6 +379,44 @@ err:
        return ret;
 }
 
+static int genpd_set_performance_state(struct device *dev, unsigned int state)
+{
+       struct generic_pm_domain *genpd = dev_to_genpd(dev);
+       struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+       unsigned int prev_state;
+       int ret;
+
+       prev_state = gpd_data->performance_state;
+       if (prev_state == state)
+               return 0;
+
+       gpd_data->performance_state = state;
+       state = _genpd_reeval_performance_state(genpd, state);
+
+       ret = _genpd_set_performance_state(genpd, state, 0);
+       if (ret)
+               gpd_data->performance_state = prev_state;
+
+       return ret;
+}
+
+static int genpd_drop_performance_state(struct device *dev)
+{
+       unsigned int prev_state = dev_gpd_data(dev)->performance_state;
+
+       if (!genpd_set_performance_state(dev, 0))
+               return prev_state;
+
+       return 0;
+}
+
+static void genpd_restore_performance_state(struct device *dev,
+                                           unsigned int state)
+{
+       if (state)
+               genpd_set_performance_state(dev, state);
+}
+
 /**
  * dev_pm_genpd_set_performance_state- Set performance state of device's power
  * domain.
@@ -397,8 +435,6 @@ err:
 int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
 {
        struct generic_pm_domain *genpd;
-       struct generic_pm_domain_data *gpd_data;
-       unsigned int prev;
        int ret;
 
        genpd = dev_to_genpd_safe(dev);
@@ -410,16 +446,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
                return -EINVAL;
 
        genpd_lock(genpd);
-
-       gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
-       prev = gpd_data->performance_state;
-       gpd_data->performance_state = state;
-
-       state = _genpd_reeval_performance_state(genpd, state);
-       ret = _genpd_set_performance_state(genpd, state, 0);
-       if (ret)
-               gpd_data->performance_state = prev;
-
+       ret = genpd_set_performance_state(dev, state);
        genpd_unlock(genpd);
 
        return ret;
@@ -572,6 +599,7 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
  * RPM status of the releated device is in an intermediate state, not yet turned
  * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not
  * be RPM_SUSPENDED, while it tries to power off the PM domain.
+ * @depth: nesting count for lockdep.
  *
  * If all of the @genpd's devices have been suspended and all of its subdomains
  * have been powered down, remove power from @genpd.
@@ -832,7 +860,8 @@ static int genpd_runtime_suspend(struct device *dev)
 {
        struct generic_pm_domain *genpd;
        bool (*suspend_ok)(struct device *__dev);
-       struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+       struct gpd_timing_data *td = &gpd_data->td;
        bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
@@ -889,6 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
                return 0;
 
        genpd_lock(genpd);
+       gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
        genpd_power_off(genpd, true, 0);
        genpd_unlock(genpd);
 
@@ -906,7 +936,8 @@ static int genpd_runtime_suspend(struct device *dev)
 static int genpd_runtime_resume(struct device *dev)
 {
        struct generic_pm_domain *genpd;
-       struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+       struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+       struct gpd_timing_data *td = &gpd_data->td;
        bool runtime_pm = pm_runtime_enabled(dev);
        ktime_t time_start;
        s64 elapsed_ns;
@@ -930,6 +961,8 @@ static int genpd_runtime_resume(struct device *dev)
 
        genpd_lock(genpd);
        ret = genpd_power_on(genpd, 0);
+       if (!ret)
+               genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
        genpd_unlock(genpd);
 
        if (ret)
@@ -968,6 +1001,7 @@ err_stop:
 err_poweroff:
        if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
                genpd_lock(genpd);
+               gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
                genpd_power_off(genpd, true, 0);
                genpd_unlock(genpd);
        }
@@ -2505,7 +2539,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain);
 
 /**
  * of_genpd_remove_last - Remove the last PM domain registered for a provider
- * @provider: Pointer to device structure associated with provider
+ * @np: Pointer to device node associated with provider
  *
  * Find the last PM domain that was added by a particular provider and
  * remove this PM domain from the list of PM domains. The provider is
index c6c2187..cd08c58 100644 (file)
@@ -252,6 +252,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
 /**
  * _default_power_down_ok - Default generic PM domain power off governor routine.
  * @pd: PM domain to check.
+ * @now: current ktime.
  *
  * This routine must be executed under the PM domain's lock.
  */
index b570848..8a66eaf 100644 (file)
@@ -345,7 +345,7 @@ static void rpm_suspend_suppliers(struct device *dev)
 static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
        __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
-       int retval, idx;
+       int retval = 0, idx;
        bool use_links = dev->power.links_count > 0;
 
        if (dev->power.irq_safe) {
@@ -373,7 +373,8 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
                }
        }
 
-       retval = cb(dev);
+       if (cb)
+               retval = cb(dev);
 
        if (dev->power.irq_safe) {
                spin_lock(&dev->power.lock);
@@ -446,7 +447,10 @@ static int rpm_idle(struct device *dev, int rpmflags)
        /* Pending requests need to be canceled. */
        dev->power.request = RPM_REQ_NONE;
 
-       if (dev->power.no_callbacks)
+       callback = RPM_GET_CALLBACK(dev, runtime_idle);
+
+       /* If no callback assume success. */
+       if (!callback || dev->power.no_callbacks)
                goto out;
 
        /* Carry out an asynchronous or a synchronous idle notification. */
@@ -462,10 +466,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
 
        dev->power.idle_notification = true;
 
-       callback = RPM_GET_CALLBACK(dev, runtime_idle);
-
-       if (callback)
-               retval = __rpm_callback(callback, dev);
+       retval = __rpm_callback(callback, dev);
 
        dev->power.idle_notification = false;
        wake_up_all(&dev->power.wait_queue);
@@ -484,9 +485,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
 {
        int retval;
 
-       if (!cb)
-               return -ENOSYS;
-
        if (dev->power.memalloc_noio) {
                unsigned int noio_flag;
 
index 8e02108..3bad326 100644 (file)
@@ -182,7 +182,6 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
 
        wirq->dev = dev;
        wirq->irq = irq;
-       irq_set_status_flags(irq, IRQ_NOAUTOEN);
 
        /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
        irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
@@ -192,7 +191,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
         * so we use a threaded irq.
         */
        err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
-                                  IRQF_ONESHOT, wirq->name, wirq);
+                                  IRQF_ONESHOT | IRQF_NO_AUTOEN,
+                                  wirq->name, wirq);
        if (err)
                goto err_free_name;
 
index 50b1e2d..159bac6 100644 (file)
@@ -4,8 +4,9 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
-       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
+       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO)
        select IRQ_DOMAIN if REGMAP_IRQ
+       select MDIO_BUS if REGMAP_MDIO
        bool
 
 config REGCACHE_COMPRESSED
@@ -36,6 +37,9 @@ config REGMAP_W1
        tristate
        depends on W1
 
+config REGMAP_MDIO
+       tristate
+
 config REGMAP_MMIO
        tristate
 
index 33f63ad..11facb3 100644 (file)
@@ -19,3 +19,4 @@ obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o
 obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
 obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
 obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
+obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
index 62b95a9..980e5ce 100644 (file)
@@ -306,33 +306,64 @@ static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
 static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
                                        const struct regmap_config *config)
 {
+       const struct i2c_adapter_quirks *quirks;
+       const struct regmap_bus *bus = NULL;
+       struct regmap_bus *ret_bus;
+       u16 max_read = 0, max_write = 0;
+
        if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
-               return &regmap_i2c;
+               bus = &regmap_i2c;
        else if (config->val_bits == 8 && config->reg_bits == 8 &&
                 i2c_check_functionality(i2c->adapter,
                                         I2C_FUNC_SMBUS_I2C_BLOCK))
-               return &regmap_i2c_smbus_i2c_block;
+               bus = &regmap_i2c_smbus_i2c_block;
        else if (config->val_bits == 8 && config->reg_bits == 16 &&
                i2c_check_functionality(i2c->adapter,
                                        I2C_FUNC_SMBUS_I2C_BLOCK))
-               return &regmap_i2c_smbus_i2c_block_reg16;
+               bus = &regmap_i2c_smbus_i2c_block_reg16;
        else if (config->val_bits == 16 && config->reg_bits == 8 &&
                 i2c_check_functionality(i2c->adapter,
                                         I2C_FUNC_SMBUS_WORD_DATA))
                switch (regmap_get_val_endian(&i2c->dev, NULL, config)) {
                case REGMAP_ENDIAN_LITTLE:
-                       return &regmap_smbus_word;
+                       bus = &regmap_smbus_word;
+                       break;
                case REGMAP_ENDIAN_BIG:
-                       return &regmap_smbus_word_swapped;
+                       bus = &regmap_smbus_word_swapped;
+                       break;
                default:                /* everything else is not supported */
                        break;
                }
        else if (config->val_bits == 8 && config->reg_bits == 8 &&
                 i2c_check_functionality(i2c->adapter,
                                         I2C_FUNC_SMBUS_BYTE_DATA))
-               return &regmap_smbus_byte;
+               bus = &regmap_smbus_byte;
+
+       if (!bus)
+               return ERR_PTR(-ENOTSUPP);
+
+       quirks = i2c->adapter->quirks;
+       if (quirks) {
+               if (quirks->max_read_len &&
+                   (bus->max_raw_read == 0 || bus->max_raw_read > quirks->max_read_len))
+                       max_read = quirks->max_read_len;
+
+               if (quirks->max_write_len &&
+                   (bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len))
+                       max_write = quirks->max_write_len;
+
+               if (max_read || max_write) {
+                       ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL);
+                       if (!ret_bus)
+                               return ERR_PTR(-ENOMEM);
+                       ret_bus->free_on_exit = true;
+                       ret_bus->max_raw_read = max_read;
+                       ret_bus->max_raw_write = max_write;
+                       bus = ret_bus;
+               }
+       }
 
-       return ERR_PTR(-ENOTSUPP);
+       return bus;
 }
 
 struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
index 760296a..d265658 100644 (file)
@@ -531,6 +531,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+       if (chip->status_invert)
+               for (i = 0; i < data->chip->num_regs; i++)
+                       data->status_buf[i] = ~data->status_buf[i];
+
        /*
         * Ignore masked IRQs and ack if we need to; we ack early so
         * there is no race between handling and acknowleding the
@@ -800,6 +804,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
                        goto err_alloc;
                }
 
+               if (chip->status_invert)
+                       d->status_buf[i] = ~d->status_buf[i];
+
                if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
                        reg = sub_irq_reg(d, d->chip->ack_base, i);
                        if (chip->ack_invert)
diff --git a/drivers/base/regmap/regmap-mdio.c b/drivers/base/regmap/regmap-mdio.c
new file mode 100644 (file)
index 0000000..6a20201
--- /dev/null
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/errno.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define REGVAL_MASK            GENMASK(15, 0)
+#define REGNUM_C22_MASK                GENMASK(4, 0)
+/* Clause-45 mask includes the device type (5 bit) and actual register number (16 bit) */
+#define REGNUM_C45_MASK                GENMASK(20, 0)
+
+static int regmap_mdio_read(struct mdio_device *mdio_dev, u32 reg, unsigned int *val)
+{
+       int ret;
+
+       ret = mdiobus_read(mdio_dev->bus, mdio_dev->addr, reg);
+       if (ret < 0)
+               return ret;
+
+       *val = ret & REGVAL_MASK;
+       return 0;
+}
+
+static int regmap_mdio_write(struct mdio_device *mdio_dev, u32 reg, unsigned int val)
+{
+       return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val);
+}
+
+static int regmap_mdio_c22_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct mdio_device *mdio_dev = context;
+
+       if (unlikely(reg & ~REGNUM_C22_MASK))
+               return -ENXIO;
+
+       return regmap_mdio_read(mdio_dev, reg, val);
+}
+
+static int regmap_mdio_c22_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct mdio_device *mdio_dev = context;
+
+       if (unlikely(reg & ~REGNUM_C22_MASK))
+               return -ENXIO;
+
+       return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val);
+}
+
+static const struct regmap_bus regmap_mdio_c22_bus = {
+       .reg_write = regmap_mdio_c22_write,
+       .reg_read = regmap_mdio_c22_read,
+};
+
+static int regmap_mdio_c45_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct mdio_device *mdio_dev = context;
+
+       if (unlikely(reg & ~REGNUM_C45_MASK))
+               return -ENXIO;
+
+       return regmap_mdio_read(mdio_dev, MII_ADDR_C45 | reg, val);
+}
+
+static int regmap_mdio_c45_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct mdio_device *mdio_dev = context;
+
+       if (unlikely(reg & ~REGNUM_C45_MASK))
+               return -ENXIO;
+
+       return regmap_mdio_write(mdio_dev, MII_ADDR_C45 | reg, val);
+}
+
+static const struct regmap_bus regmap_mdio_c45_bus = {
+       .reg_write = regmap_mdio_c45_write,
+       .reg_read = regmap_mdio_c45_read,
+};
+
+struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,
+       const struct regmap_config *config, struct lock_class_key *lock_key,
+       const char *lock_name)
+{
+       const struct regmap_bus *bus;
+
+       if (config->reg_bits == 5 && config->val_bits == 16)
+               bus = &regmap_mdio_c22_bus;
+       else if (config->reg_bits == 21 && config->val_bits == 16)
+               bus = &regmap_mdio_c45_bus;
+       else
+               return ERR_PTR(-EOPNOTSUPP);
+
+       return __regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__regmap_init_mdio);
+
+struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,
+       const struct regmap_config *config, struct lock_class_key *lock_key,
+       const char *lock_name)
+{
+       const struct regmap_bus *bus;
+
+       if (config->reg_bits == 5 && config->val_bits == 16)
+               bus = &regmap_mdio_c22_bus;
+       else if (config->reg_bits == 21 && config->val_bits == 16)
+               bus = &regmap_mdio_c45_bus;
+       else
+               return ERR_PTR(-EOPNOTSUPP);
+
+       return __devm_regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio);
+
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Regmap MDIO Module");
+MODULE_LICENSE("GPL v2");
index 297e95b..fe3e38d 100644 (file)
@@ -243,6 +243,16 @@ static void regmap_format_7_9_write(struct regmap *map,
        *out = cpu_to_be16((reg << 9) | val);
 }
 
+static void regmap_format_7_17_write(struct regmap *map,
+                                   unsigned int reg, unsigned int val)
+{
+       u8 *out = map->work_buf;
+
+       out[2] = val;
+       out[1] = val >> 8;
+       out[0] = (val >> 16) | (reg << 1);
+}
+
 static void regmap_format_10_14_write(struct regmap *map,
                                    unsigned int reg, unsigned int val)
 {
@@ -885,6 +895,9 @@ struct regmap *__regmap_init(struct device *dev,
                case 9:
                        map->format.format_write = regmap_format_7_9_write;
                        break;
+               case 17:
+                       map->format.format_write = regmap_format_7_17_write;
+                       break;
                default:
                        goto err_hwlock;
                }
@@ -1496,6 +1509,8 @@ void regmap_exit(struct regmap *map)
                mutex_destroy(&map->mutex);
        kfree_const(map->name);
        kfree(map->patch);
+       if (map->bus && map->bus->free_on_exit)
+               kfree(map->bus);
        kfree(map);
 }
 EXPORT_SYMBOL_GPL(regmap_exit);
index 3cc11b8..d1f1a82 100644 (file)
@@ -1045,7 +1045,15 @@ int device_add_software_node(struct device *dev, const struct software_node *nod
        }
 
        set_secondary_fwnode(dev, &swnode->fwnode);
-       software_node_notify(dev, KOBJ_ADD);
+
+       /*
+        * If the device has been fully registered by the time this function is
+        * called, software_node_notify() must be called separately so that the
+        * symlinks get created and the reference count of the node is kept in
+        * balance.
+        */
+       if (device_is_registered(dev))
+               software_node_notify(dev, KOBJ_ADD);
 
        return 0;
 }
@@ -1065,7 +1073,8 @@ void device_remove_software_node(struct device *dev)
        if (!swnode)
                return;
 
-       software_node_notify(dev, KOBJ_REMOVE);
+       if (device_is_registered(dev))
+               software_node_notify(dev, KOBJ_REMOVE);
        set_secondary_fwnode(dev, NULL);
        kobject_put(&swnode->kobj);
 }
@@ -1119,8 +1128,7 @@ int software_node_notify(struct device *dev, unsigned long action)
 
        switch (action) {
        case KOBJ_ADD:
-               ret = sysfs_create_link_nowarn(&dev->kobj, &swnode->kobj,
-                                              "software_node");
+               ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
                if (ret)
                        break;
 
index 1fe006f..c11f12d 100644 (file)
@@ -165,17 +165,17 @@ config HW_RANDOM_IXP4XX
 
 config HW_RANDOM_OMAP
        tristate "OMAP Random Number Generator support"
-       depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU
+       depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU || ARCH_K3
        default HW_RANDOM
        help
-         This driver provides kernel-side support for the Random Number
+         This driver provides kernel-side support for the Random Number
          Generator hardware found on OMAP16xx, OMAP2/3/4/5, AM33xx/AM43xx
          multimedia processors, and Marvell Armada 7k/8k SoCs.
 
          To compile this driver as a module, choose M here: the
          module will be called omap-rng.
 
-         If unsure, say Y.
+         If unsure, say Y.
 
 config HW_RANDOM_OMAP3_ROM
        tristate "OMAP3 ROM Random Number Generator support"
@@ -485,13 +485,13 @@ config HW_RANDOM_NPCM
        depends on ARCH_NPCM || COMPILE_TEST
        default HW_RANDOM
        help
-         This driver provides support for the Random Number
+         This driver provides support for the Random Number
          Generator hardware available in Nuvoton NPCM SoCs.
 
          To compile this driver as a module, choose M here: the
          module will be called npcm-rng.
 
-         If unsure, say Y.
+         If unsure, say Y.
 
 config HW_RANDOM_KEYSTONE
        depends on ARCH_KEYSTONE || COMPILE_TEST
index 9959c76..d8d4ef5 100644 (file)
@@ -126,7 +126,7 @@ static struct hwrng amd_rng = {
 
 static int __init mod_init(void)
 {
-       int err = -ENODEV;
+       int err;
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *ent;
        u32 pmbase;
index adb3c2b..a3db279 100644 (file)
@@ -319,11 +319,11 @@ static int enable_best_rng(void)
        return ret;
 }
 
-static ssize_t hwrng_attr_current_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t len)
+static ssize_t rng_current_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len)
 {
-       int err = -ENODEV;
+       int err;
        struct hwrng *rng, *old_rng, *new_rng;
 
        err = mutex_lock_interruptible(&rng_mutex);
@@ -354,9 +354,9 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
        return err ? : len;
 }
 
-static ssize_t hwrng_attr_current_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf)
+static ssize_t rng_current_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
 {
        ssize_t ret;
        struct hwrng *rng;
@@ -371,9 +371,9 @@ static ssize_t hwrng_attr_current_show(struct device *dev,
        return ret;
 }
 
-static ssize_t hwrng_attr_available_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
+static ssize_t rng_available_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        int err;
        struct hwrng *rng;
@@ -392,22 +392,16 @@ static ssize_t hwrng_attr_available_show(struct device *dev,
        return strlen(buf);
 }
 
-static ssize_t hwrng_attr_selected_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
+static ssize_t rng_selected_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
 {
        return sysfs_emit(buf, "%d\n", cur_rng_set_by_user);
 }
 
-static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
-                  hwrng_attr_current_show,
-                  hwrng_attr_current_store);
-static DEVICE_ATTR(rng_available, S_IRUGO,
-                  hwrng_attr_available_show,
-                  NULL);
-static DEVICE_ATTR(rng_selected, S_IRUGO,
-                  hwrng_attr_selected_show,
-                  NULL);
+static DEVICE_ATTR_RW(rng_current);
+static DEVICE_ATTR_RO(rng_available);
+static DEVICE_ATTR_RO(rng_selected);
 
 static struct attribute *rng_dev_attrs[] = {
        &dev_attr_rng_current.attr,
index 8e1fe3f..9cc3d54 100644 (file)
@@ -132,7 +132,7 @@ static int exynos_trng_probe(struct platform_device *pdev)
                return PTR_ERR(trng->mem);
 
        pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "Could not get runtime PM.\n");
                goto err_pm_get;
@@ -165,7 +165,7 @@ err_register:
        clk_disable_unprepare(trng->clk);
 
 err_clock:
-       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
 
 err_pm_get:
        pm_runtime_disable(&pdev->dev);
@@ -196,10 +196,9 @@ static int __maybe_unused exynos_trng_resume(struct device *dev)
 {
        int ret;
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "Could not get runtime PM.\n");
-               pm_runtime_put_noidle(dev);
                return ret;
        }
 
index 8f1d47f..2f2f21f 100644 (file)
@@ -241,10 +241,9 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "Failed to enable SA power-domain\n");
-               pm_runtime_put_noidle(dev);
                pm_runtime_disable(dev);
                return ret;
        }
index cede9f1..00ff967 100644 (file)
@@ -454,10 +454,9 @@ static int omap_rng_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
-               pm_runtime_put_noidle(&pdev->dev);
                goto err_ioremap;
        }
 
@@ -543,10 +542,9 @@ static int __maybe_unused omap_rng_resume(struct device *dev)
        struct omap_rng_dev *priv = dev_get_drvdata(dev);
        int ret;
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "Failed to runtime_get device: %d\n", ret);
-               pm_runtime_put_noidle(dev);
                return ret;
        }
 
index 39aa21d..9fa2823 100644 (file)
@@ -358,6 +358,20 @@ config ARM_GLOBAL_TIMER
        help
          This option enables support for the ARM global timer unit.
 
+config ARM_GT_INITIAL_PRESCALER_VAL
+       int "ARM global timer initial prescaler value"
+       default 2 if ARCH_ZYNQ
+       default 1
+       depends on ARM_GLOBAL_TIMER
+       help
+         When the ARM global timer initializes, its current rate is declared
+         to the kernel and maintained forever. Should it's parent clock
+         change, the driver tries to fix the timer's internal prescaler.
+         On some machs (i.e. Zynq) the initial prescaler value thus poses
+         bounds about how much the parent clock is allowed to decrease or
+         increase wrt the initial clock value.
+         This affects CPU_FREQ max delta from the initial frequency.
+
 config ARM_TIMER_SP804
        bool "Support for Dual Timer SP804 module" if COMPILE_TEST
        depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
index fe1a826..be6d741 100644 (file)
@@ -64,7 +64,6 @@ struct arch_timer {
 #define to_arch_timer(e) container_of(e, struct arch_timer, evt)
 
 static u32 arch_timer_rate __ro_after_init;
-u32 arch_timer_rate1 __ro_after_init;
 static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init;
 
 static const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = {
@@ -365,7 +364,7 @@ static u64 notrace arm64_858921_read_cntvct_el0(void)
        do {                                                            \
                _val = read_sysreg(reg);                                \
                _retries--;                                             \
-       } while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries);        \
+       } while (((_val + 1) & GENMASK(8, 0)) <= 1 && _retries);        \
                                                                        \
        WARN_ON_ONCE(!_retries);                                        \
        _val;                                                           \
index 88b2d38..44a61dc 100644 (file)
 #define GT_CONTROL_COMP_ENABLE         BIT(1)  /* banked */
 #define GT_CONTROL_IRQ_ENABLE          BIT(2)  /* banked */
 #define GT_CONTROL_AUTO_INC            BIT(3)  /* banked */
+#define GT_CONTROL_PRESCALER_SHIFT      8
+#define GT_CONTROL_PRESCALER_MAX        0xF
+#define GT_CONTROL_PRESCALER_MASK       (GT_CONTROL_PRESCALER_MAX << \
+                                        GT_CONTROL_PRESCALER_SHIFT)
 
 #define GT_INT_STATUS  0x0c
 #define GT_INT_STATUS_EVENT_FLAG       BIT(0)
@@ -39,6 +43,7 @@
 #define GT_COMP1       0x14
 #define GT_AUTO_INC    0x18
 
+#define MAX_F_ERR 50
 /*
  * We are expecting to be clocked by the ARM peripheral clock.
  *
@@ -46,7 +51,8 @@
  * the units for all operations.
  */
 static void __iomem *gt_base;
-static unsigned long gt_clk_rate;
+static struct notifier_block gt_clk_rate_change_nb;
+static u32 gt_psv_new, gt_psv_bck, gt_target_rate;
 static int gt_ppi;
 static struct clock_event_device __percpu *gt_evt;
 
@@ -96,7 +102,10 @@ static void gt_compare_set(unsigned long delta, int periodic)
        unsigned long ctrl;
 
        counter += delta;
-       ctrl = GT_CONTROL_TIMER_ENABLE;
+       ctrl = readl(gt_base + GT_CONTROL);
+       ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE |
+                 GT_CONTROL_AUTO_INC);
+       ctrl |= GT_CONTROL_TIMER_ENABLE;
        writel_relaxed(ctrl, gt_base + GT_CONTROL);
        writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0);
        writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1);
@@ -123,7 +132,7 @@ static int gt_clockevent_shutdown(struct clock_event_device *evt)
 
 static int gt_clockevent_set_periodic(struct clock_event_device *evt)
 {
-       gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
+       gt_compare_set(DIV_ROUND_CLOSEST(gt_target_rate, HZ), 1);
        return 0;
 }
 
@@ -177,7 +186,7 @@ static int gt_starting_cpu(unsigned int cpu)
        clk->cpumask = cpumask_of(cpu);
        clk->rating = 300;
        clk->irq = gt_ppi;
-       clockevents_config_and_register(clk, gt_clk_rate,
+       clockevents_config_and_register(clk, gt_target_rate,
                                        1, 0xffffffff);
        enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
        return 0;
@@ -232,9 +241,28 @@ static struct delay_timer gt_delay_timer = {
        .read_current_timer = gt_read_long,
 };
 
+static void gt_write_presc(u32 psv)
+{
+       u32 reg;
+
+       reg = readl(gt_base + GT_CONTROL);
+       reg &= ~GT_CONTROL_PRESCALER_MASK;
+       reg |= psv << GT_CONTROL_PRESCALER_SHIFT;
+       writel(reg, gt_base + GT_CONTROL);
+}
+
+static u32 gt_read_presc(void)
+{
+       u32 reg;
+
+       reg = readl(gt_base + GT_CONTROL);
+       reg &= GT_CONTROL_PRESCALER_MASK;
+       return reg >> GT_CONTROL_PRESCALER_SHIFT;
+}
+
 static void __init gt_delay_timer_init(void)
 {
-       gt_delay_timer.freq = gt_clk_rate;
+       gt_delay_timer.freq = gt_target_rate;
        register_current_timer_delay(&gt_delay_timer);
 }
 
@@ -243,18 +271,81 @@ static int __init gt_clocksource_init(void)
        writel(0, gt_base + GT_CONTROL);
        writel(0, gt_base + GT_COUNTER0);
        writel(0, gt_base + GT_COUNTER1);
-       /* enables timer on all the cores */
-       writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+       /* set prescaler and enable timer on all the cores */
+       writel(((CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) <<
+               GT_CONTROL_PRESCALER_SHIFT)
+              | GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
-       sched_clock_register(gt_sched_clock_read, 64, gt_clk_rate);
+       sched_clock_register(gt_sched_clock_read, 64, gt_target_rate);
 #endif
-       return clocksource_register_hz(&gt_clocksource, gt_clk_rate);
+       return clocksource_register_hz(&gt_clocksource, gt_target_rate);
+}
+
+static int gt_clk_rate_change_cb(struct notifier_block *nb,
+                                unsigned long event, void *data)
+{
+       struct clk_notifier_data *ndata = data;
+
+       switch (event) {
+       case PRE_RATE_CHANGE:
+       {
+               int psv;
+
+               psv = DIV_ROUND_CLOSEST(ndata->new_rate,
+                                       gt_target_rate);
+
+               if (abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
+                       return NOTIFY_BAD;
+
+               psv--;
+
+               /* prescaler within legal range? */
+               if (psv < 0 || psv > GT_CONTROL_PRESCALER_MAX)
+                       return NOTIFY_BAD;
+
+               /*
+                * store timer clock ctrl register so we can restore it in case
+                * of an abort.
+                */
+               gt_psv_bck = gt_read_presc();
+               gt_psv_new = psv;
+               /* scale down: adjust divider in post-change notification */
+               if (ndata->new_rate < ndata->old_rate)
+                       return NOTIFY_DONE;
+
+               /* scale up: adjust divider now - before frequency change */
+               gt_write_presc(psv);
+               break;
+       }
+       case POST_RATE_CHANGE:
+               /* scale up: pre-change notification did the adjustment */
+               if (ndata->new_rate > ndata->old_rate)
+                       return NOTIFY_OK;
+
+               /* scale down: adjust divider now - after frequency change */
+               gt_write_presc(gt_psv_new);
+               break;
+
+       case ABORT_RATE_CHANGE:
+               /* we have to undo the adjustment in case we scale up */
+               if (ndata->new_rate < ndata->old_rate)
+                       return NOTIFY_OK;
+
+               /* restore original register value */
+               gt_write_presc(gt_psv_bck);
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+
+       return NOTIFY_DONE;
 }
 
 static int __init global_timer_of_register(struct device_node *np)
 {
        struct clk *gt_clk;
+       static unsigned long gt_clk_rate;
        int err = 0;
 
        /*
@@ -292,11 +383,20 @@ static int __init global_timer_of_register(struct device_node *np)
        }
 
        gt_clk_rate = clk_get_rate(gt_clk);
+       gt_target_rate = gt_clk_rate / CONFIG_ARM_GT_INITIAL_PRESCALER_VAL;
+       gt_clk_rate_change_nb.notifier_call =
+               gt_clk_rate_change_cb;
+       err = clk_notifier_register(gt_clk, &gt_clk_rate_change_nb);
+       if (err) {
+               pr_warn("Unable to register clock notifier\n");
+               goto out_clk;
+       }
+
        gt_evt = alloc_percpu(struct clock_event_device);
        if (!gt_evt) {
                pr_warn("global-timer: can't allocate memory\n");
                err = -ENOMEM;
-               goto out_clk;
+               goto out_clk_nb;
        }
 
        err = request_percpu_irq(gt_ppi, gt_clockevent_interrupt,
@@ -326,6 +426,8 @@ out_irq:
        free_percpu_irq(gt_ppi, gt_evt);
 out_free:
        free_percpu(gt_evt);
+out_clk_nb:
+       clk_notifier_unregister(gt_clk, &gt_clk_rate_change_nb);
 out_clk:
        clk_disable_unprepare(gt_clk);
 out_unmap:
index e77d584..a129840 100644 (file)
@@ -186,7 +186,7 @@ static const struct clk_ops ingenic_ost_global_timer_ops = {
 
 static const char * const ingenic_ost_clk_parents[] = { "ext" };
 
-static const struct ingenic_ost_clk_info ingenic_ost_clk_info[] = {
+static const struct ingenic_ost_clk_info x1000_ost_clk_info[] = {
        [OST_CLK_PERCPU_TIMER] = {
                .init_data = {
                        .name = "percpu timer",
@@ -414,14 +414,14 @@ static const struct ingenic_soc_info x1000_soc_info = {
        .num_channels = 2,
 };
 
-static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = {
-       { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, },
+static const struct of_device_id __maybe_unused ingenic_ost_of_matches[] __initconst = {
+       { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info },
        { /* sentinel */ }
 };
 
 static int __init ingenic_ost_probe(struct device_node *np)
 {
-       const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np);
+       const struct of_device_id *id = of_match_node(ingenic_ost_of_matches, np);
        struct ingenic_ost *ost;
        unsigned int i;
        int ret;
@@ -462,7 +462,7 @@ static int __init ingenic_ost_probe(struct device_node *np)
        ost->clocks->num = ost->soc_info->num_channels;
 
        for (i = 0; i < ost->clocks->num; i++) {
-               ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks);
+               ret = ingenic_ost_register_clock(ost, i, &x1000_ost_clk_info[i], ost->clocks);
                if (ret) {
                        pr_crit("%s: Cannot register clock %d\n", __func__, i);
                        goto err_unregister_ost_clocks;
index f760229..6e46781 100644 (file)
@@ -4,7 +4,7 @@
  *             http://www.samsung.com/
  *
  * samsung - Common hr-timer support (s3c and s5p)
-*/
+ */
 
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -22,7 +22,6 @@
 
 #include <clocksource/samsung_pwm.h>
 
-
 /*
  * Clocksource driver
  */
@@ -38,8 +37,8 @@
 #define TCFG0_PRESCALER_MASK           0xff
 #define TCFG0_PRESCALER1_SHIFT         8
 
-#define TCFG1_SHIFT(x)                 ((x) * 4)
-#define TCFG1_MUX_MASK                 0xf
+#define TCFG1_SHIFT(x)                 ((x) * 4)
+#define TCFG1_MUX_MASK                 0xf
 
 /*
  * Each channel occupies 4 bits in TCON register, but there is a gap of 4
@@ -62,7 +61,7 @@ EXPORT_SYMBOL(samsung_pwm_lock);
 
 struct samsung_pwm_clocksource {
        void __iomem *base;
-       void __iomem *source_reg;
+       const void __iomem *source_reg;
        unsigned int irq[SAMSUNG_PWM_NUM];
        struct samsung_pwm_variant variant;
 
@@ -183,7 +182,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
 }
 
 static int samsung_set_next_event(unsigned long cycles,
-                               struct clock_event_device *evt)
+                                 struct clock_event_device *evt)
 {
        /*
         * This check is needed to account for internal rounding
@@ -225,6 +224,7 @@ static void samsung_clockevent_resume(struct clock_event_device *cev)
 
        if (pwm.variant.has_tint_cstat) {
                u32 mask = (1 << pwm.event_id);
+
                writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
        }
 }
@@ -248,6 +248,7 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
 
        if (pwm.variant.has_tint_cstat) {
                u32 mask = (1 << pwm.event_id);
+
                writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
        }
 
@@ -272,7 +273,7 @@ static void __init samsung_clockevent_init(void)
 
        time_event_device.cpumask = cpumask_of(0);
        clockevents_config_and_register(&time_event_device,
-                                               clock_rate, 1, pwm.tcnt_max);
+                                       clock_rate, 1, pwm.tcnt_max);
 
        irq_number = pwm.irq[pwm.event_id];
        if (request_irq(irq_number, samsung_clock_event_isr,
@@ -282,6 +283,7 @@ static void __init samsung_clockevent_init(void)
 
        if (pwm.variant.has_tint_cstat) {
                u32 mask = (1 << pwm.event_id);
+
                writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
        }
 }
@@ -347,7 +349,7 @@ static int __init samsung_clocksource_init(void)
                pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14;
 
        sched_clock_register(samsung_read_sched_clock,
-                                               pwm.variant.bits, clock_rate);
+                            pwm.variant.bits, clock_rate);
 
        samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits);
        return clocksource_register_hz(&samsung_clocksource, clock_rate);
@@ -398,7 +400,8 @@ static int __init _samsung_pwm_clocksource_init(void)
 }
 
 void __init samsung_pwm_clocksource_init(void __iomem *base,
-                       unsigned int *irqs, struct samsung_pwm_variant *variant)
+                                        unsigned int *irqs,
+                                        const struct samsung_pwm_variant *variant)
 {
        pwm.base = base;
        memcpy(&pwm.variant, variant, sizeof(pwm.variant));
@@ -418,7 +421,7 @@ static int __init samsung_pwm_alloc(struct device_node *np,
        struct property *prop;
        const __be32 *cur;
        u32 val;
-       int i;
+       int i, ret;
 
        memcpy(&pwm.variant, variant, sizeof(pwm.variant));
        for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
@@ -441,10 +444,24 @@ static int __init samsung_pwm_alloc(struct device_node *np,
        pwm.timerclk = of_clk_get_by_name(np, "timers");
        if (IS_ERR(pwm.timerclk)) {
                pr_crit("failed to get timers clock for timer\n");
-               return PTR_ERR(pwm.timerclk);
+               ret = PTR_ERR(pwm.timerclk);
+               goto err_clk;
        }
 
-       return _samsung_pwm_clocksource_init();
+       ret = _samsung_pwm_clocksource_init();
+       if (ret)
+               goto err_clocksource;
+
+       return 0;
+
+err_clocksource:
+       clk_put(pwm.timerclk);
+       pwm.timerclk = NULL;
+err_clk:
+       iounmap(pwm.base);
+       pwm.base = NULL;
+
+       return ret;
 }
 
 static const struct samsung_pwm_variant s3c24xx_variant = {
index 9318edc..ab63b95 100644 (file)
@@ -241,6 +241,28 @@ static void mtk_gpt_enable_irq(struct timer_of *to, u8 timer)
               timer_of_base(to) + GPT_IRQ_EN_REG);
 }
 
+static void mtk_gpt_resume(struct clock_event_device *clk)
+{
+       struct timer_of *to = to_timer_of(clk);
+
+       mtk_gpt_enable_irq(to, TIMER_CLK_EVT);
+}
+
+static void mtk_gpt_suspend(struct clock_event_device *clk)
+{
+       struct timer_of *to = to_timer_of(clk);
+
+       /* Disable all interrupts */
+       writel(0x0, timer_of_base(to) + GPT_IRQ_EN_REG);
+
+       /*
+        * This is called with interrupts disabled,
+        * so we need to ack any interrupt that is pending
+        * or for example ATF will prevent a suspend from completing.
+        */
+       writel(0x3f, timer_of_base(to) + GPT_IRQ_ACK_REG);
+}
+
 static struct timer_of to = {
        .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
 
@@ -286,6 +308,8 @@ static int __init mtk_gpt_init(struct device_node *node)
        to.clkevt.set_state_oneshot = mtk_gpt_clkevt_shutdown;
        to.clkevt.tick_resume = mtk_gpt_clkevt_shutdown;
        to.clkevt.set_next_event = mtk_gpt_clkevt_next_event;
+       to.clkevt.suspend = mtk_gpt_suspend;
+       to.clkevt.resume = mtk_gpt_resume;
        to.of_irq.handler = mtk_gpt_interrupt;
 
        ret = timer_of_init(node, &to);
index 33eeabf..3e52c52 100644 (file)
@@ -78,6 +78,9 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 
 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 {
+       __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+                             timer->context.ocp_cfg, 0);
+
        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
                                timer->context.twer);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -95,6 +98,9 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
 
 static void omap_timer_save_context(struct omap_dm_timer *timer)
 {
+       timer->context.ocp_cfg =
+               __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
+
        timer->context.tclr =
                        omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        timer->context.twer =
@@ -122,7 +128,8 @@ static int omap_timer_context_notifier(struct notifier_block *nb,
                        break;
                omap_timer_save_context(timer);
                break;
-       case CPU_CLUSTER_PM_ENTER_FAILED:
+       case CPU_CLUSTER_PM_ENTER_FAILED:       /* No need to restore context */
+               break;
        case CPU_CLUSTER_PM_EXIT:
                if ((timer->capability & OMAP_TIMER_ALWON) ||
                    !atomic_read(&timer->enabled))
index a5c5f70..e65e0a4 100644 (file)
@@ -19,16 +19,6 @@ config ACPI_CPPC_CPUFREQ
 
          If in doubt, say N.
 
-config ACPI_CPPC_CPUFREQ_FIE
-       bool "Frequency Invariance support for CPPC cpufreq driver"
-       depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
-       default y
-       help
-         This extends frequency invariance support in the CPPC cpufreq driver,
-         by using CPPC delivered and reference performance counters.
-
-         If in doubt, say N.
-
 config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
        tristate "Allwinner nvmem based SUN50I CPUFreq driver"
        depends on ARCH_SUNXI
index 3848b4c..2f769b1 100644 (file)
 
 #define pr_fmt(fmt)    "CPPC Cpufreq:" fmt
 
-#include <linux/arch_topology.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/dmi.h>
-#include <linux/irq_work.h>
-#include <linux/kthread.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
-#include <uapi/linux/sched/types.h>
 
 #include <asm/unaligned.h>
 
@@ -61,204 +57,6 @@ static struct cppc_workaround_oem_info wa_info[] = {
        }
 };
 
-#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
-
-/* Frequency invariance support */
-struct cppc_freq_invariance {
-       int cpu;
-       struct irq_work irq_work;
-       struct kthread_work work;
-       struct cppc_perf_fb_ctrs prev_perf_fb_ctrs;
-       struct cppc_cpudata *cpu_data;
-};
-
-static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
-static struct kthread_worker *kworker_fie;
-static bool fie_disabled;
-
-static struct cpufreq_driver cppc_cpufreq_driver;
-static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu);
-static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
-                                struct cppc_perf_fb_ctrs fb_ctrs_t0,
-                                struct cppc_perf_fb_ctrs fb_ctrs_t1);
-
-/**
- * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
- * @work: The work item.
- *
- * The CPPC driver register itself with the topology core to provide its own
- * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
- * gets called by the scheduler on every tick.
- *
- * Note that the arch specific counters have higher priority than CPPC counters,
- * if available, though the CPPC driver doesn't need to have any special
- * handling for that.
- *
- * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
- * reach here from hard-irq context), which then schedules a normal work item
- * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
- * based on the counter updates since the last tick.
- */
-static void cppc_scale_freq_workfn(struct kthread_work *work)
-{
-       struct cppc_freq_invariance *cppc_fi;
-       struct cppc_perf_fb_ctrs fb_ctrs = {0};
-       struct cppc_cpudata *cpu_data;
-       unsigned long local_freq_scale;
-       u64 perf;
-
-       cppc_fi = container_of(work, struct cppc_freq_invariance, work);
-       cpu_data = cppc_fi->cpu_data;
-
-       if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
-               pr_warn("%s: failed to read perf counters\n", __func__);
-               return;
-       }
-
-       cppc_fi->prev_perf_fb_ctrs = fb_ctrs;
-       perf = cppc_perf_from_fbctrs(cpu_data, cppc_fi->prev_perf_fb_ctrs,
-                                    fb_ctrs);
-
-       perf <<= SCHED_CAPACITY_SHIFT;
-       local_freq_scale = div64_u64(perf, cpu_data->perf_caps.highest_perf);
-       if (WARN_ON(local_freq_scale > 1024))
-               local_freq_scale = 1024;
-
-       per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
-}
-
-static void cppc_irq_work(struct irq_work *irq_work)
-{
-       struct cppc_freq_invariance *cppc_fi;
-
-       cppc_fi = container_of(irq_work, struct cppc_freq_invariance, irq_work);
-       kthread_queue_work(kworker_fie, &cppc_fi->work);
-}
-
-static void cppc_scale_freq_tick(void)
-{
-       struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());
-
-       /*
-        * cppc_get_perf_ctrs() can potentially sleep, call that from the right
-        * context.
-        */
-       irq_work_queue(&cppc_fi->irq_work);
-}
-
-static struct scale_freq_data cppc_sftd = {
-       .source = SCALE_FREQ_SOURCE_CPPC,
-       .set_freq_scale = cppc_scale_freq_tick,
-};
-
-static void cppc_freq_invariance_policy_init(struct cpufreq_policy *policy,
-                                            struct cppc_cpudata *cpu_data)
-{
-       struct cppc_perf_fb_ctrs fb_ctrs = {0};
-       struct cppc_freq_invariance *cppc_fi;
-       int i, ret;
-
-       if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
-               return;
-
-       if (fie_disabled)
-               return;
-
-       for_each_cpu(i, policy->cpus) {
-               cppc_fi = &per_cpu(cppc_freq_inv, i);
-               cppc_fi->cpu = i;
-               cppc_fi->cpu_data = cpu_data;
-               kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
-               init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
-
-               ret = cppc_get_perf_ctrs(i, &fb_ctrs);
-               if (ret) {
-                       pr_warn("%s: failed to read perf counters: %d\n",
-                               __func__, ret);
-                       fie_disabled = true;
-               } else {
-                       cppc_fi->prev_perf_fb_ctrs = fb_ctrs;
-               }
-       }
-}
-
-static void __init cppc_freq_invariance_init(void)
-{
-       struct sched_attr attr = {
-               .size           = sizeof(struct sched_attr),
-               .sched_policy   = SCHED_DEADLINE,
-               .sched_nice     = 0,
-               .sched_priority = 0,
-               /*
-                * Fake (unused) bandwidth; workaround to "fix"
-                * priority inheritance.
-                */
-               .sched_runtime  = 1000000,
-               .sched_deadline = 10000000,
-               .sched_period   = 10000000,
-       };
-       int ret;
-
-       if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
-               return;
-
-       if (fie_disabled)
-               return;
-
-       kworker_fie = kthread_create_worker(0, "cppc_fie");
-       if (IS_ERR(kworker_fie))
-               return;
-
-       ret = sched_setattr_nocheck(kworker_fie->task, &attr);
-       if (ret) {
-               pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__,
-                       ret);
-               kthread_destroy_worker(kworker_fie);
-               return;
-       }
-
-       /* Register for freq-invariance */
-       topology_set_scale_freq_source(&cppc_sftd, cpu_present_mask);
-}
-
-static void cppc_freq_invariance_exit(void)
-{
-       struct cppc_freq_invariance *cppc_fi;
-       int i;
-
-       if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
-               return;
-
-       if (fie_disabled)
-               return;
-
-       topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, cpu_present_mask);
-
-       for_each_possible_cpu(i) {
-               cppc_fi = &per_cpu(cppc_freq_inv, i);
-               irq_work_sync(&cppc_fi->irq_work);
-       }
-
-       kthread_destroy_worker(kworker_fie);
-       kworker_fie = NULL;
-}
-
-#else
-static inline void
-cppc_freq_invariance_policy_init(struct cpufreq_policy *policy,
-                                struct cppc_cpudata *cpu_data)
-{
-}
-
-static inline void cppc_freq_invariance_init(void)
-{
-}
-
-static inline void cppc_freq_invariance_exit(void)
-{
-}
-#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
-
 /* Callback function used to retrieve the max frequency from DMI */
 static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
 {
@@ -547,12 +345,9 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
        cpu_data->perf_ctrls.desired_perf =  caps->highest_perf;
 
        ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
-       if (ret) {
+       if (ret)
                pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
                         caps->highest_perf, cpu, ret);
-       } else {
-               cppc_freq_invariance_policy_init(policy, cpu_data);
-       }
 
        return ret;
 }
@@ -565,12 +360,12 @@ static inline u64 get_delta(u64 t1, u64 t0)
        return (u32)t1 - (u32)t0;
 }
 
-static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
-                                struct cppc_perf_fb_ctrs fb_ctrs_t0,
-                                struct cppc_perf_fb_ctrs fb_ctrs_t1)
+static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
+                                    struct cppc_perf_fb_ctrs fb_ctrs_t0,
+                                    struct cppc_perf_fb_ctrs fb_ctrs_t1)
 {
        u64 delta_reference, delta_delivered;
-       u64 reference_perf;
+       u64 reference_perf, delivered_perf;
 
        reference_perf = fb_ctrs_t0.reference_perf;
 
@@ -579,21 +374,12 @@ static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
        delta_delivered = get_delta(fb_ctrs_t1.delivered,
                                    fb_ctrs_t0.delivered);
 
-       /* Check to avoid divide-by zero and invalid delivered_perf */
-       if (!delta_reference || !delta_delivered)
-               return cpu_data->perf_ctrls.desired_perf;
-
-       return (reference_perf * delta_delivered) / delta_reference;
-}
-
-static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
-                                    struct cppc_perf_fb_ctrs fb_ctrs_t0,
-                                    struct cppc_perf_fb_ctrs fb_ctrs_t1)
-{
-       u64 delivered_perf;
-
-       delivered_perf = cppc_perf_from_fbctrs(cpu_data, fb_ctrs_t0,
-                                              fb_ctrs_t1);
+       /* Check to avoid divide-by zero */
+       if (delta_reference || delta_delivered)
+               delivered_perf = (reference_perf * delta_delivered) /
+                                       delta_reference;
+       else
+               delivered_perf = cpu_data->perf_ctrls.desired_perf;
 
        return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf);
 }
@@ -718,8 +504,6 @@ static void cppc_check_hisi_workaround(void)
 
 static int __init cppc_cpufreq_init(void)
 {
-       int ret;
-
        if ((acpi_disabled) || !acpi_cpc_valid())
                return -ENODEV;
 
@@ -727,11 +511,7 @@ static int __init cppc_cpufreq_init(void)
 
        cppc_check_hisi_workaround();
 
-       ret = cpufreq_register_driver(&cppc_cpufreq_driver);
-       if (!ret)
-               cppc_freq_invariance_init();
-
-       return ret;
+       return cpufreq_register_driver(&cppc_cpufreq_driver);
 }
 
 static inline void free_cpu_data(void)
@@ -748,7 +528,6 @@ static inline void free_cpu_data(void)
 
 static void __exit cppc_cpufreq_exit(void)
 {
-       cppc_freq_invariance_exit();
        cpufreq_unregister_driver(&cppc_cpufreq_driver);
 
        free_cpu_data();
index 802abc9..cbab834 100644 (file)
@@ -1367,9 +1367,14 @@ static int cpufreq_online(unsigned int cpu)
                        goto out_free_policy;
                }
 
+               /*
+                * The initialization has succeeded and the policy is online.
+                * If there is a problem with its frequency table, take it
+                * offline and drop it.
+                */
                ret = cpufreq_table_validate_and_sort(policy);
                if (ret)
-                       goto out_exit_policy;
+                       goto out_offline_policy;
 
                /* related_cpus should at least include policy->cpus. */
                cpumask_copy(policy->related_cpus, policy->cpus);
@@ -1515,6 +1520,10 @@ out_destroy_policy:
 
        up_write(&policy->rwsem);
 
+out_offline_policy:
+       if (cpufreq_driver->offline)
+               cpufreq_driver->offline(policy);
+
 out_exit_policy:
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
index da717f7..1570d6f 100644 (file)
@@ -211,7 +211,7 @@ void cpufreq_stats_free_table(struct cpufreq_policy *policy)
 
 void cpufreq_stats_create_table(struct cpufreq_policy *policy)
 {
-       unsigned int i = 0, count = 0, ret = -ENOMEM;
+       unsigned int i = 0, count;
        struct cpufreq_stats *stats;
        unsigned int alloc_size;
        struct cpufreq_frequency_table *pos;
@@ -253,8 +253,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
        stats->last_index = freq_table_get_index(stats, policy->cur);
 
        policy->stats = stats;
-       ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
-       if (!ret)
+       if (!sysfs_create_group(&policy->kobj, &stats_attr_group))
                return;
 
        /* We failed, release resources */
index 0e69dff..6012964 100644 (file)
@@ -121,9 +121,10 @@ struct sample {
  * @max_pstate_physical:This is physical Max P state for a processor
  *                     This can be higher than the max_pstate which can
  *                     be limited by platform thermal design power limits
- * @scaling:           Scaling factor to  convert frequency to cpufreq
- *                     frequency units
+ * @perf_ctl_scaling:  PERF_CTL P-state to frequency scaling factor
+ * @scaling:           Scaling factor between performance and frequency
  * @turbo_pstate:      Max Turbo P state possible for this platform
+ * @min_freq:          @min_pstate frequency in cpufreq units
  * @max_freq:          @max_pstate frequency in cpufreq units
  * @turbo_freq:                @turbo_pstate frequency in cpufreq units
  *
@@ -134,8 +135,10 @@ struct pstate_data {
        int     min_pstate;
        int     max_pstate;
        int     max_pstate_physical;
+       int     perf_ctl_scaling;
        int     scaling;
        int     turbo_pstate;
+       unsigned int min_freq;
        unsigned int max_freq;
        unsigned int turbo_freq;
 };
@@ -366,7 +369,7 @@ static void intel_pstate_set_itmt_prio(int cpu)
        }
 }
 
-static int intel_pstate_get_cppc_guranteed(int cpu)
+static int intel_pstate_get_cppc_guaranteed(int cpu)
 {
        struct cppc_perf_caps cppc_perf;
        int ret;
@@ -382,7 +385,7 @@ static int intel_pstate_get_cppc_guranteed(int cpu)
 }
 
 #else /* CONFIG_ACPI_CPPC_LIB */
-static void intel_pstate_set_itmt_prio(int cpu)
+static inline void intel_pstate_set_itmt_prio(int cpu)
 {
 }
 #endif /* CONFIG_ACPI_CPPC_LIB */
@@ -467,6 +470,20 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
 
        acpi_processor_unregister_performance(policy->cpu);
 }
+
+static bool intel_pstate_cppc_perf_valid(u32 perf, struct cppc_perf_caps *caps)
+{
+       return perf && perf <= caps->highest_perf && perf >= caps->lowest_perf;
+}
+
+static bool intel_pstate_cppc_perf_caps(struct cpudata *cpu,
+                                       struct cppc_perf_caps *caps)
+{
+       if (cppc_get_perf_caps(cpu->cpu, caps))
+               return false;
+
+       return caps->highest_perf && caps->lowest_perf <= caps->highest_perf;
+}
 #else /* CONFIG_ACPI */
 static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
 {
@@ -483,12 +500,146 @@ static inline bool intel_pstate_acpi_pm_profile_server(void)
 #endif /* CONFIG_ACPI */
 
 #ifndef CONFIG_ACPI_CPPC_LIB
-static int intel_pstate_get_cppc_guranteed(int cpu)
+static inline int intel_pstate_get_cppc_guaranteed(int cpu)
 {
        return -ENOTSUPP;
 }
 #endif /* CONFIG_ACPI_CPPC_LIB */
 
+static void intel_pstate_hybrid_hwp_perf_ctl_parity(struct cpudata *cpu)
+{
+       pr_debug("CPU%d: Using PERF_CTL scaling for HWP\n", cpu->cpu);
+
+       cpu->pstate.scaling = cpu->pstate.perf_ctl_scaling;
+}
+
+/**
+ * intel_pstate_hybrid_hwp_calibrate - Calibrate HWP performance levels.
+ * @cpu: Target CPU.
+ *
+ * On hybrid processors, HWP may expose more performance levels than there are
+ * P-states accessible through the PERF_CTL interface.  If that happens, the
+ * scaling factor between HWP performance levels and CPU frequency will be less
+ * than the scaling factor between P-state values and CPU frequency.
+ *
+ * In that case, the scaling factor between HWP performance levels and CPU
+ * frequency needs to be determined which can be done with the help of the
+ * observation that certain HWP performance levels should correspond to certain
+ * P-states, like for example the HWP highest performance should correspond
+ * to the maximum turbo P-state of the CPU.
+ */
+static void intel_pstate_hybrid_hwp_calibrate(struct cpudata *cpu)
+{
+       int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
+       int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+       int perf_ctl_turbo = pstate_funcs.get_turbo();
+       int turbo_freq = perf_ctl_turbo * perf_ctl_scaling;
+       int perf_ctl_max = pstate_funcs.get_max();
+       int max_freq = perf_ctl_max * perf_ctl_scaling;
+       int scaling = INT_MAX;
+       int freq;
+
+       pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
+       pr_debug("CPU%d: perf_ctl_max = %d\n", cpu->cpu, perf_ctl_max);
+       pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo);
+       pr_debug("CPU%d: perf_ctl_scaling = %d\n", cpu->cpu, perf_ctl_scaling);
+
+       pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpu->cpu, cpu->pstate.max_pstate);
+       pr_debug("CPU%d: HWP_CAP highest = %d\n", cpu->cpu, cpu->pstate.turbo_pstate);
+
+#ifdef CONFIG_ACPI
+       if (IS_ENABLED(CONFIG_ACPI_CPPC_LIB)) {
+               struct cppc_perf_caps caps;
+
+               if (intel_pstate_cppc_perf_caps(cpu, &caps)) {
+                       if (intel_pstate_cppc_perf_valid(caps.nominal_perf, &caps)) {
+                               pr_debug("CPU%d: Using CPPC nominal\n", cpu->cpu);
+
+                               /*
+                                * If the CPPC nominal performance is valid, it
+                                * can be assumed to correspond to cpu_khz.
+                                */
+                               if (caps.nominal_perf == perf_ctl_max_phys) {
+                                       intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+                                       return;
+                               }
+                               scaling = DIV_ROUND_UP(cpu_khz, caps.nominal_perf);
+                       } else if (intel_pstate_cppc_perf_valid(caps.guaranteed_perf, &caps)) {
+                               pr_debug("CPU%d: Using CPPC guaranteed\n", cpu->cpu);
+
+                               /*
+                                * If the CPPC guaranteed performance is valid,
+                                * it can be assumed to correspond to max_freq.
+                                */
+                               if (caps.guaranteed_perf == perf_ctl_max) {
+                                       intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+                                       return;
+                               }
+                               scaling = DIV_ROUND_UP(max_freq, caps.guaranteed_perf);
+                       }
+               }
+       }
+#endif
+       /*
+        * If using the CPPC data to compute the HWP-to-frequency scaling factor
+        * doesn't work, use the HWP_CAP gauranteed perf for this purpose with
+        * the assumption that it corresponds to max_freq.
+        */
+       if (scaling > perf_ctl_scaling) {
+               pr_debug("CPU%d: Using HWP_CAP guaranteed\n", cpu->cpu);
+
+               if (cpu->pstate.max_pstate == perf_ctl_max) {
+                       intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+                       return;
+               }
+               scaling = DIV_ROUND_UP(max_freq, cpu->pstate.max_pstate);
+               if (scaling > perf_ctl_scaling) {
+                       /*
+                        * This should not happen, because it would mean that
+                        * the number of HWP perf levels was less than the
+                        * number of P-states, so use the PERF_CTL scaling in
+                        * that case.
+                        */
+                       pr_debug("CPU%d: scaling (%d) out of range\n", cpu->cpu,
+                               scaling);
+
+                       intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+                       return;
+               }
+       }
+
+       /*
+        * If the product of the HWP performance scaling factor obtained above
+        * and the HWP_CAP highest performance is greater than the maximum turbo
+        * frequency corresponding to the pstate_funcs.get_turbo() return value,
+        * the scaling factor is too high, so recompute it so that the HWP_CAP
+        * highest performance corresponds to the maximum turbo frequency.
+        */
+       if (turbo_freq < cpu->pstate.turbo_pstate * scaling) {
+               pr_debug("CPU%d: scaling too high (%d)\n", cpu->cpu, scaling);
+
+               cpu->pstate.turbo_freq = turbo_freq;
+               scaling = DIV_ROUND_UP(turbo_freq, cpu->pstate.turbo_pstate);
+       }
+
+       cpu->pstate.scaling = scaling;
+
+       pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
+
+       cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
+                                        perf_ctl_scaling);
+
+       freq = perf_ctl_max_phys * perf_ctl_scaling;
+       cpu->pstate.max_pstate_physical = DIV_ROUND_UP(freq, scaling);
+
+       cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+       /*
+        * Cast the min P-state value retrieved via pstate_funcs.get_min() to
+        * the effective range of HWP performance levels.
+        */
+       cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling);
+}
+
 static inline void update_turbo_state(void)
 {
        u64 misc_en;
@@ -795,19 +946,22 @@ cpufreq_freq_attr_rw(energy_performance_preference);
 
 static ssize_t show_base_frequency(struct cpufreq_policy *policy, char *buf)
 {
-       struct cpudata *cpu;
-       u64 cap;
-       int ratio;
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+       int ratio, freq;
 
-       ratio = intel_pstate_get_cppc_guranteed(policy->cpu);
+       ratio = intel_pstate_get_cppc_guaranteed(policy->cpu);
        if (ratio <= 0) {
+               u64 cap;
+
                rdmsrl_on_cpu(policy->cpu, MSR_HWP_CAPABILITIES, &cap);
                ratio = HWP_GUARANTEED_PERF(cap);
        }
 
-       cpu = all_cpu_data[policy->cpu];
+       freq = ratio * cpu->pstate.scaling;
+       if (cpu->pstate.scaling != cpu->pstate.perf_ctl_scaling)
+               freq = rounddown(freq, cpu->pstate.perf_ctl_scaling);
 
-       return sprintf(buf, "%d\n", ratio * cpu->pstate.scaling);
+       return sprintf(buf, "%d\n", freq);
 }
 
 cpufreq_freq_attr_ro(base_frequency);
@@ -831,9 +985,20 @@ static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
 
 static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
 {
+       int scaling = cpu->pstate.scaling;
+
        __intel_pstate_get_hwp_cap(cpu);
-       cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
-       cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+
+       cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
+       cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
+       if (scaling != cpu->pstate.perf_ctl_scaling) {
+               int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+
+               cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq,
+                                                perf_ctl_scaling);
+               cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq,
+                                                  perf_ctl_scaling);
+       }
 }
 
 static void intel_pstate_hwp_set(unsigned int cpu)
@@ -1365,8 +1530,6 @@ define_one_global_rw(energy_efficiency);
 static struct attribute *intel_pstate_attributes[] = {
        &status.attr,
        &no_turbo.attr,
-       &turbo_pct.attr,
-       &num_pstates.attr,
        NULL
 };
 
@@ -1391,6 +1554,14 @@ static void __init intel_pstate_sysfs_expose_params(void)
        if (WARN_ON(rc))
                return;
 
+       if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+               rc = sysfs_create_file(intel_pstate_kobject, &turbo_pct.attr);
+               WARN_ON(rc);
+
+               rc = sysfs_create_file(intel_pstate_kobject, &num_pstates.attr);
+               WARN_ON(rc);
+       }
+
        /*
         * If per cpu limits are enforced there are no global limits, so
         * return without creating max/min_perf_pct attributes
@@ -1417,6 +1588,11 @@ static void __init intel_pstate_sysfs_remove(void)
 
        sysfs_remove_group(intel_pstate_kobject, &intel_pstate_attr_group);
 
+       if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+               sysfs_remove_file(intel_pstate_kobject, &num_pstates.attr);
+               sysfs_remove_file(intel_pstate_kobject, &turbo_pct.attr);
+       }
+
        if (!per_cpu_limits) {
                sysfs_remove_file(intel_pstate_kobject, &max_perf_pct.attr);
                sysfs_remove_file(intel_pstate_kobject, &min_perf_pct.attr);
@@ -1713,19 +1889,33 @@ static void intel_pstate_max_within_limits(struct cpudata *cpu)
 
 static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 {
+       bool hybrid_cpu = boot_cpu_has(X86_FEATURE_HYBRID_CPU);
+       int perf_ctl_max_phys = pstate_funcs.get_max_physical();
+       int perf_ctl_scaling = hybrid_cpu ? cpu_khz / perf_ctl_max_phys :
+                                           pstate_funcs.get_scaling();
+
        cpu->pstate.min_pstate = pstate_funcs.get_min();
-       cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
-       cpu->pstate.scaling = pstate_funcs.get_scaling();
+       cpu->pstate.max_pstate_physical = perf_ctl_max_phys;
+       cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
 
        if (hwp_active && !hwp_mode_bdw) {
                __intel_pstate_get_hwp_cap(cpu);
+
+               if (hybrid_cpu)
+                       intel_pstate_hybrid_hwp_calibrate(cpu);
+               else
+                       cpu->pstate.scaling = perf_ctl_scaling;
        } else {
+               cpu->pstate.scaling = perf_ctl_scaling;
                cpu->pstate.max_pstate = pstate_funcs.get_max();
                cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
        }
 
-       cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
-       cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+       if (cpu->pstate.scaling == perf_ctl_scaling) {
+               cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+               cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling;
+               cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling;
+       }
 
        if (pstate_funcs.get_aperf_mperf_shift)
                cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
@@ -2087,6 +2277,8 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        X86_MATCH(ATOM_GOLDMONT,        core_funcs),
        X86_MATCH(ATOM_GOLDMONT_PLUS,   core_funcs),
        X86_MATCH(SKYLAKE_X,            core_funcs),
+       X86_MATCH(COMETLAKE,            core_funcs),
+       X86_MATCH(ICELAKE_X,            core_funcs),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -2195,23 +2387,34 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
                                            unsigned int policy_min,
                                            unsigned int policy_max)
 {
-       int scaling = cpu->pstate.scaling;
+       int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
        int32_t max_policy_perf, min_policy_perf;
 
+       max_policy_perf = policy_max / perf_ctl_scaling;
+       if (policy_max == policy_min) {
+               min_policy_perf = max_policy_perf;
+       } else {
+               min_policy_perf = policy_min / perf_ctl_scaling;
+               min_policy_perf = clamp_t(int32_t, min_policy_perf,
+                                         0, max_policy_perf);
+       }
+
        /*
         * HWP needs some special consideration, because HWP_REQUEST uses
         * abstract values to represent performance rather than pure ratios.
         */
-       if (hwp_active)
+       if (hwp_active) {
                intel_pstate_get_hwp_cap(cpu);
 
-       max_policy_perf = policy_max / scaling;
-       if (policy_max == policy_min) {
-               min_policy_perf = max_policy_perf;
-       } else {
-               min_policy_perf = policy_min / scaling;
-               min_policy_perf = clamp_t(int32_t, min_policy_perf,
-                                         0, max_policy_perf);
+               if (cpu->pstate.scaling != perf_ctl_scaling) {
+                       int scaling = cpu->pstate.scaling;
+                       int freq;
+
+                       freq = max_policy_perf * perf_ctl_scaling;
+                       max_policy_perf = DIV_ROUND_UP(freq, scaling);
+                       freq = min_policy_perf * perf_ctl_scaling;
+                       min_policy_perf = DIV_ROUND_UP(freq, scaling);
+               }
        }
 
        pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
@@ -2405,7 +2608,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
        cpu->min_perf_ratio = 0;
 
        /* cpuinfo and default policy values */
-       policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
+       policy->cpuinfo.min_freq = cpu->pstate.min_freq;
        update_turbo_state();
        global.turbo_disabled_mf = global.turbo_disabled;
        policy->cpuinfo.max_freq = global.turbo_disabled ?
@@ -3135,6 +3338,8 @@ hwp_cpu_matched:
                }
 
                pr_info("HWP enabled\n");
+       } else if (boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+               pr_warn("Problematic setup: Hybrid processor with disabled HWP\n");
        }
 
        return 0;
index d05e761..afc59b2 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/cpufreq.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/sched.h>       /* set_cpus_allowed() */
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 
index 73a2085..330c8d6 100644 (file)
@@ -42,6 +42,7 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
        default:
                pr_err("error: cpuctl register has unexpected value %02x\n",
                       clockspeed_reg);
+               fallthrough;
        case 0x01:
                return 100000;
        case 0x02:
index 0ac265d..1a251e6 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/cpumask.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
-#include <linux/sched.h>       /* set_cpus_allowed() */
 #include <linux/clk.h>
 #include <linux/percpu.h>
 #include <linux/sh_clk.h>
index c3aa8d6..2e56704 100644 (file)
@@ -117,7 +117,7 @@ struct menu_device {
        int             interval_ptr;
 };
 
-static inline int which_bucket(u64 duration_ns, unsigned long nr_iowaiters)
+static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters)
 {
        int bucket = 0;
 
@@ -150,7 +150,7 @@ static inline int which_bucket(u64 duration_ns, unsigned long nr_iowaiters)
  * to be, the higher this multiplier, and thus the higher
  * the barrier to go to an expensive C state.
  */
-static inline int performance_multiplier(unsigned long nr_iowaiters)
+static inline int performance_multiplier(unsigned int nr_iowaiters)
 {
        /* for IO wait tasks (per cpu!) we add 10x each */
        return 1 + 10 * nr_iowaiters;
@@ -270,7 +270,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
        unsigned int predicted_us;
        u64 predicted_ns;
        u64 interactivity_req;
-       unsigned long nr_iowaiters;
+       unsigned int nr_iowaiters;
        ktime_t delta, delta_tick;
        int i, idx;
 
index ac4bb27..7b91060 100644 (file)
 /*
  * Timer events oriented CPU idle governor
  *
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 - 2021 Intel Corporation
  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ */
+
+/**
+ * DOC: teo-description
  *
  * The idea of this governor is based on the observation that on many systems
  * timer events are two or more orders of magnitude more frequent than any
- * other interrupts, so they are likely to be the most significant source of CPU
+ * other interrupts, so they are likely to be the most significant cause of CPU
  * wakeups from idle states.  Moreover, information about what happened in the
  * (relatively recent) past can be used to estimate whether or not the deepest
- * idle state with target residency within the time to the closest timer is
- * likely to be suitable for the upcoming idle time of the CPU and, if not, then
- * which of the shallower idle states to choose.
+ * idle state with target residency within the (known) time till the closest
+ * timer event, referred to as the sleep length, is likely to be suitable for
+ * the upcoming CPU idle period and, if not, then which of the shallower idle
+ * states to choose instead of it.
+ *
+ * Of course, non-timer wakeup sources are more important in some use cases
+ * which can be covered by taking a few most recent idle time intervals of the
+ * CPU into account.  However, even in that context it is not necessary to
+ * consider idle duration values greater than the sleep length, because the
+ * closest timer will ultimately wake up the CPU anyway unless it is woken up
+ * earlier.
+ *
+ * Thus this governor estimates whether or not the prospective idle duration of
+ * a CPU is likely to be significantly shorter than the sleep length and selects
+ * an idle state for it accordingly.
+ *
+ * The computations carried out by this governor are based on using bins whose
+ * boundaries are aligned with the target residency parameter values of the CPU
+ * idle states provided by the %CPUIdle driver in the ascending order.  That is,
+ * the first bin spans from 0 up to, but not including, the target residency of
+ * the second idle state (idle state 1), the second bin spans from the target
+ * residency of idle state 1 up to, but not including, the target residency of
+ * idle state 2, the third bin spans from the target residency of idle state 2
+ * up to, but not including, the target residency of idle state 3 and so on.
+ * The last bin spans from the target residency of the deepest idle state
+ * supplied by the driver to infinity.
+ *
+ * Two metrics called "hits" and "intercepts" are associated with each bin.
+ * They are updated every time before selecting an idle state for the given CPU
+ * in accordance with what happened last time.
+ *
+ * The "hits" metric reflects the relative frequency of situations in which the
+ * sleep length and the idle duration measured after CPU wakeup fall into the
+ * same bin (that is, the CPU appears to wake up "on time" relative to the sleep
+ * length).  In turn, the "intercepts" metric reflects the relative frequency of
+ * situations in which the measured idle duration is so much shorter than the
+ * sleep length that the bin it falls into corresponds to an idle state
+ * shallower than the one whose bin is fallen into by the sleep length (these
+ * situations are referred to as "intercepts" below).
+ *
+ * In addition to the metrics described above, the governor counts recent
+ * intercepts (that is, intercepts that have occurred during the last
+ * %NR_RECENT invocations of it for the given CPU) for each bin.
  *
- * Of course, non-timer wakeup sources are more important in some use cases and
- * they can be covered by taking a few most recent idle time intervals of the
- * CPU into account.  However, even in that case it is not necessary to consider
- * idle duration values greater than the time till the closest timer, as the
- * patterns that they may belong to produce average values close enough to
- * the time till the closest timer (sleep length) anyway.
+ * In order to select an idle state for a CPU, the governor takes the following
+ * steps (modulo the possible latency constraint that must be taken into account
+ * too):
  *
- * Thus this governor estimates whether or not the upcoming idle time of the CPU
- * is likely to be significantly shorter than the sleep length and selects an
- * idle state for it in accordance with that, as follows:
+ * 1. Find the deepest CPU idle state whose target residency does not exceed
+ *    the current sleep length (the candidate idle state) and compute 3 sums as
+ *    follows:
  *
- * - Find an idle state on the basis of the sleep length and state statistics
- *   collected over time:
+ *    - The sum of the "hits" and "intercepts" metrics for the candidate state
+ *      and all of the deeper idle states (it represents the cases in which the
+ *      CPU was idle long enough to avoid being intercepted if the sleep length
+ *      had been equal to the current one).
  *
- *   o Find the deepest idle state whose target residency is less than or equal
- *     to the sleep length.
+ *    - The sum of the "intercepts" metrics for all of the idle states shallower
+ *      than the candidate one (it represents the cases in which the CPU was not
+ *      idle long enough to avoid being intercepted if the sleep length had been
+ *      equal to the current one).
  *
- *   o Select it if it matched both the sleep length and the observed idle
- *     duration in the past more often than it matched the sleep length alone
- *     (i.e. the observed idle duration was significantly shorter than the sleep
- *     length matched by it).
+ *    - The sum of the numbers of recent intercepts for all of the idle states
+ *      shallower than the candidate one.
  *
- *   o Otherwise, select the shallower state with the greatest matched "early"
- *     wakeups metric.
+ * 2. If the second sum is greater than the first one or the third sum is
+ *    greater than %NR_RECENT / 2, the CPU is likely to wake up early, so look
+ *    for an alternative idle state to select.
  *
- * - If the majority of the most recent idle duration values are below the
- *   target residency of the idle state selected so far, use those values to
- *   compute the new expected idle duration and find an idle state matching it
- *   (which has to be shallower than the one selected so far).
+ *    - Traverse the idle states shallower than the candidate one in the
+ *      descending order.
+ *
+ *    - For each of them compute the sum of the "intercepts" metrics and the sum
+ *      of the numbers of recent intercepts over all of the idle states between
+ *      it and the candidate one (including the former and excluding the
+ *      latter).
+ *
+ *    - If each of these sums that needs to be taken into account (because the
+ *      check related to it has indicated that the CPU is likely to wake up
+ *      early) is greater than a half of the corresponding sum computed in step
+ *      1 (which means that the target residency of the state in question had
+ *      not exceeded the idle duration in over a half of the relevant cases),
+ *      select the given idle state instead of the candidate one.
+ *
+ * 3. By default, select the candidate state.
  */
 
 #include <linux/cpuidle.h>
 
 /*
  * Number of the most recent idle duration values to take into consideration for
- * the detection of wakeup patterns.
+ * the detection of recent early wakeup patterns.
  */
-#define INTERVALS      8
+#define NR_RECENT      9
 
 /**
- * struct teo_idle_state - Idle state data used by the TEO cpuidle governor.
- * @early_hits: "Early" CPU wakeups "matching" this state.
- * @hits: "On time" CPU wakeups "matching" this state.
- * @misses: CPU wakeups "missing" this state.
- *
- * A CPU wakeup is "matched" by a given idle state if the idle duration measured
- * after the wakeup is between the target residency of that state and the target
- * residency of the next one (or if this is the deepest available idle state, it
- * "matches" a CPU wakeup when the measured idle duration is at least equal to
- * its target residency).
- *
- * Also, from the TEO governor perspective, a CPU wakeup from idle is "early" if
- * it occurs significantly earlier than the closest expected timer event (that
- * is, early enough to match an idle state shallower than the one matching the
- * time till the closest timer event).  Otherwise, the wakeup is "on time", or
- * it is a "hit".
- *
- * A "miss" occurs when the given state doesn't match the wakeup, but it matches
- * the time till the closest timer event used for idle state selection.
+ * struct teo_bin - Metrics used by the TEO cpuidle governor.
+ * @intercepts: The "intercepts" metric.
+ * @hits: The "hits" metric.
+ * @recent: The number of recent "intercepts".
  */
-struct teo_idle_state {
-       unsigned int early_hits;
+struct teo_bin {
+       unsigned int intercepts;
        unsigned int hits;
-       unsigned int misses;
+       unsigned int recent;
 };
 
 /**
  * struct teo_cpu - CPU data used by the TEO cpuidle governor.
  * @time_span_ns: Time between idle state selection and post-wakeup update.
  * @sleep_length_ns: Time till the closest timer event (at the selection time).
- * @states: Idle states data corresponding to this CPU.
- * @interval_idx: Index of the most recent saved idle interval.
- * @intervals: Saved idle duration values.
+ * @state_bins: Idle state data bins for this CPU.
+ * @total: Grand total of the "intercepts" and "hits" mertics for all bins.
+ * @next_recent_idx: Index of the next @recent_idx entry to update.
+ * @recent_idx: Indices of bins corresponding to recent "intercepts".
  */
 struct teo_cpu {
        s64 time_span_ns;
        s64 sleep_length_ns;
-       struct teo_idle_state states[CPUIDLE_STATE_MAX];
-       int interval_idx;
-       u64 intervals[INTERVALS];
+       struct teo_bin state_bins[CPUIDLE_STATE_MAX];
+       unsigned int total;
+       int next_recent_idx;
+       int recent_idx[NR_RECENT];
 };
 
 static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
 
 /**
- * teo_update - Update CPU data after wakeup.
+ * teo_update - Update CPU metrics after wakeup.
  * @drv: cpuidle driver containing state data.
  * @dev: Target CPU.
  */
 static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
        struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
-       int i, idx_hit = 0, idx_timer = 0;
-       unsigned int hits, misses;
+       int i, idx_timer = 0, idx_duration = 0;
        u64 measured_ns;
 
        if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) {
@@ -151,53 +193,52 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                        measured_ns /= 2;
        }
 
+       cpu_data->total = 0;
+
        /*
-        * Decay the "early hits" metric for all of the states and find the
-        * states matching the sleep length and the measured idle duration.
+        * Decay the "hits" and "intercepts" metrics for all of the bins and
+        * find the bins that the sleep length and the measured idle duration
+        * fall into.
         */
        for (i = 0; i < drv->state_count; i++) {
-               unsigned int early_hits = cpu_data->states[i].early_hits;
+               s64 target_residency_ns = drv->states[i].target_residency_ns;
+               struct teo_bin *bin = &cpu_data->state_bins[i];
 
-               cpu_data->states[i].early_hits -= early_hits >> DECAY_SHIFT;
+               bin->hits -= bin->hits >> DECAY_SHIFT;
+               bin->intercepts -= bin->intercepts >> DECAY_SHIFT;
 
-               if (drv->states[i].target_residency_ns <= cpu_data->sleep_length_ns) {
+               cpu_data->total += bin->hits + bin->intercepts;
+
+               if (target_residency_ns <= cpu_data->sleep_length_ns) {
                        idx_timer = i;
-                       if (drv->states[i].target_residency_ns <= measured_ns)
-                               idx_hit = i;
+                       if (target_residency_ns <= measured_ns)
+                               idx_duration = i;
                }
        }
 
-       /*
-        * Update the "hits" and "misses" data for the state matching the sleep
-        * length.  If it matches the measured idle duration too, this is a hit,
-        * so increase the "hits" metric for it then.  Otherwise, this is a
-        * miss, so increase the "misses" metric for it.  In the latter case
-        * also increase the "early hits" metric for the state that actually
-        * matches the measured idle duration.
-        */
-       hits = cpu_data->states[idx_timer].hits;
-       hits -= hits >> DECAY_SHIFT;
+       i = cpu_data->next_recent_idx++;
+       if (cpu_data->next_recent_idx >= NR_RECENT)
+               cpu_data->next_recent_idx = 0;
 
-       misses = cpu_data->states[idx_timer].misses;
-       misses -= misses >> DECAY_SHIFT;
+       if (cpu_data->recent_idx[i] >= 0)
+               cpu_data->state_bins[cpu_data->recent_idx[i]].recent--;
 
-       if (idx_timer == idx_hit) {
-               hits += PULSE;
+       /*
+        * If the measured idle duration falls into the same bin as the sleep
+        * length, this is a "hit", so update the "hits" metric for that bin.
+        * Otherwise, update the "intercepts" metric for the bin fallen into by
+        * the measured idle duration.
+        */
+       if (idx_timer == idx_duration) {
+               cpu_data->state_bins[idx_timer].hits += PULSE;
+               cpu_data->recent_idx[i] = -1;
        } else {
-               misses += PULSE;
-               cpu_data->states[idx_hit].early_hits += PULSE;
+               cpu_data->state_bins[idx_duration].intercepts += PULSE;
+               cpu_data->state_bins[idx_duration].recent++;
+               cpu_data->recent_idx[i] = idx_duration;
        }
 
-       cpu_data->states[idx_timer].misses = misses;
-       cpu_data->states[idx_timer].hits = hits;
-
-       /*
-        * Save idle duration values corresponding to non-timer wakeups for
-        * pattern detection.
-        */
-       cpu_data->intervals[cpu_data->interval_idx++] = measured_ns;
-       if (cpu_data->interval_idx >= INTERVALS)
-               cpu_data->interval_idx = 0;
+       cpu_data->total += PULSE;
 }
 
 static bool teo_time_ok(u64 interval_ns)
@@ -205,6 +246,12 @@ static bool teo_time_ok(u64 interval_ns)
        return !tick_nohz_tick_stopped() || interval_ns >= TICK_NSEC;
 }
 
+static s64 teo_middle_of_bin(int idx, struct cpuidle_driver *drv)
+{
+       return (drv->states[idx].target_residency_ns +
+               drv->states[idx+1].target_residency_ns) / 2;
+}
+
 /**
  * teo_find_shallower_state - Find shallower idle state matching given duration.
  * @drv: cpuidle driver containing state data.
@@ -240,10 +287,18 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
 {
        struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
        s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
-       int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i;
-       unsigned int hits, misses, early_hits;
+       unsigned int idx_intercept_sum = 0;
+       unsigned int intercept_sum = 0;
+       unsigned int idx_recent_sum = 0;
+       unsigned int recent_sum = 0;
+       unsigned int idx_hit_sum = 0;
+       unsigned int hit_sum = 0;
+       int constraint_idx = 0;
+       int idx0 = 0, idx = -1;
+       bool alt_intercepts, alt_recent;
        ktime_t delta_tick;
        s64 duration_ns;
+       int i;
 
        if (dev->last_state_idx >= 0) {
                teo_update(drv, dev);
@@ -255,171 +310,136 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
        duration_ns = tick_nohz_get_sleep_length(&delta_tick);
        cpu_data->sleep_length_ns = duration_ns;
 
-       hits = 0;
-       misses = 0;
-       early_hits = 0;
-       max_early_idx = -1;
-       prev_max_early_idx = -1;
-       constraint_idx = drv->state_count;
-       idx = -1;
-       idx0 = idx;
+       /* Check if there is any choice in the first place. */
+       if (drv->state_count < 2) {
+               idx = 0;
+               goto end;
+       }
+       if (!dev->states_usage[0].disable) {
+               idx = 0;
+               if (drv->states[1].target_residency_ns > duration_ns)
+                       goto end;
+       }
 
-       for (i = 0; i < drv->state_count; i++) {
+       /*
+        * Find the deepest idle state whose target residency does not exceed
+        * the current sleep length and the deepest idle state not deeper than
+        * the former whose exit latency does not exceed the current latency
+        * constraint.  Compute the sums of metrics for early wakeup pattern
+        * detection.
+        */
+       for (i = 1; i < drv->state_count; i++) {
+               struct teo_bin *prev_bin = &cpu_data->state_bins[i-1];
                struct cpuidle_state *s = &drv->states[i];
 
-               if (dev->states_usage[i].disable) {
-                       /*
-                        * Ignore disabled states with target residencies beyond
-                        * the anticipated idle duration.
-                        */
-                       if (s->target_residency_ns > duration_ns)
-                               continue;
-
-                       /*
-                        * This state is disabled, so the range of idle duration
-                        * values corresponding to it is covered by the current
-                        * candidate state, but still the "hits" and "misses"
-                        * metrics of the disabled state need to be used to
-                        * decide whether or not the state covering the range in
-                        * question is good enough.
-                        */
-                       hits = cpu_data->states[i].hits;
-                       misses = cpu_data->states[i].misses;
-
-                       if (early_hits >= cpu_data->states[i].early_hits ||
-                           idx < 0)
-                               continue;
-
-                       /*
-                        * If the current candidate state has been the one with
-                        * the maximum "early hits" metric so far, the "early
-                        * hits" metric of the disabled state replaces the
-                        * current "early hits" count to avoid selecting a
-                        * deeper state with lower "early hits" metric.
-                        */
-                       if (max_early_idx == idx) {
-                               early_hits = cpu_data->states[i].early_hits;
-                               continue;
-                       }
-
-                       /*
-                        * The current candidate state is closer to the disabled
-                        * one than the current maximum "early hits" state, so
-                        * replace the latter with it, but in case the maximum
-                        * "early hits" state index has not been set so far,
-                        * check if the current candidate state is not too
-                        * shallow for that role.
-                        */
-                       if (teo_time_ok(drv->states[idx].target_residency_ns)) {
-                               prev_max_early_idx = max_early_idx;
-                               early_hits = cpu_data->states[i].early_hits;
-                               max_early_idx = idx;
-                       }
+               /*
+                * Update the sums of idle state mertics for all of the states
+                * shallower than the current one.
+                */
+               intercept_sum += prev_bin->intercepts;
+               hit_sum += prev_bin->hits;
+               recent_sum += prev_bin->recent;
 
+               if (dev->states_usage[i].disable)
                        continue;
-               }
 
                if (idx < 0) {
                        idx = i; /* first enabled state */
-                       hits = cpu_data->states[i].hits;
-                       misses = cpu_data->states[i].misses;
                        idx0 = i;
                }
 
                if (s->target_residency_ns > duration_ns)
                        break;
 
-               if (s->exit_latency_ns > latency_req && constraint_idx > i)
+               idx = i;
+
+               if (s->exit_latency_ns <= latency_req)
                        constraint_idx = i;
 
-               idx = i;
-               hits = cpu_data->states[i].hits;
-               misses = cpu_data->states[i].misses;
-
-               if (early_hits < cpu_data->states[i].early_hits &&
-                   teo_time_ok(drv->states[i].target_residency_ns)) {
-                       prev_max_early_idx = max_early_idx;
-                       early_hits = cpu_data->states[i].early_hits;
-                       max_early_idx = i;
-               }
+               idx_intercept_sum = intercept_sum;
+               idx_hit_sum = hit_sum;
+               idx_recent_sum = recent_sum;
        }
 
-       /*
-        * If the "hits" metric of the idle state matching the sleep length is
-        * greater than its "misses" metric, that is the one to use.  Otherwise,
-        * it is more likely that one of the shallower states will match the
-        * idle duration observed after wakeup, so take the one with the maximum
-        * "early hits" metric, but if that cannot be determined, just use the
-        * state selected so far.
-        */
-       if (hits <= misses) {
-               /*
-                * The current candidate state is not suitable, so take the one
-                * whose "early hits" metric is the maximum for the range of
-                * shallower states.
-                */
-               if (idx == max_early_idx)
-                       max_early_idx = prev_max_early_idx;
-
-               if (max_early_idx >= 0) {
-                       idx = max_early_idx;
-                       duration_ns = drv->states[idx].target_residency_ns;
-               }
+       /* Avoid unnecessary overhead. */
+       if (idx < 0) {
+               idx = 0; /* No states enabled, must use 0. */
+               goto end;
+       } else if (idx == idx0) {
+               goto end;
        }
 
        /*
-        * If there is a latency constraint, it may be necessary to use a
-        * shallower idle state than the one selected so far.
+        * If the sum of the intercepts metric for all of the idle states
+        * shallower than the current candidate one (idx) is greater than the
+        * sum of the intercepts and hits metrics for the candidate state and
+        * all of the deeper states, or the sum of the numbers of recent
+        * intercepts over all of the states shallower than the candidate one
+        * is greater than a half of the number of recent events taken into
+        * account, the CPU is likely to wake up early, so find an alternative
+        * idle state to select.
         */
-       if (constraint_idx < idx)
-               idx = constraint_idx;
-
-       if (idx < 0) {
-               idx = 0; /* No states enabled. Must use 0. */
-       } else if (idx > idx0) {
-               unsigned int count = 0;
-               u64 sum = 0;
+       alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum;
+       alt_recent = idx_recent_sum > NR_RECENT / 2;
+       if (alt_recent || alt_intercepts) {
+               s64 last_enabled_span_ns = duration_ns;
+               int last_enabled_idx = idx;
 
                /*
-                * The target residencies of at least two different enabled idle
-                * states are less than or equal to the current expected idle
-                * duration.  Try to refine the selection using the most recent
-                * measured idle duration values.
+                * Look for the deepest idle state whose target residency had
+                * not exceeded the idle duration in over a half of the relevant
+                * cases (both with respect to intercepts overall and with
+                * respect to the recent intercepts only) in the past.
                 *
-                * Count and sum the most recent idle duration values less than
-                * the current expected idle duration value.
+                * Take the possible latency constraint and duration limitation
+                * present if the tick has been stopped already into account.
                 */
-               for (i = 0; i < INTERVALS; i++) {
-                       u64 val = cpu_data->intervals[i];
+               intercept_sum = 0;
+               recent_sum = 0;
+
+               for (i = idx - 1; i >= idx0; i--) {
+                       struct teo_bin *bin = &cpu_data->state_bins[i];
+                       s64 span_ns;
 
-                       if (val >= duration_ns)
+                       intercept_sum += bin->intercepts;
+                       recent_sum += bin->recent;
+
+                       if (dev->states_usage[i].disable)
                                continue;
 
-                       count++;
-                       sum += val;
-               }
+                       span_ns = teo_middle_of_bin(i, drv);
+                       if (!teo_time_ok(span_ns)) {
+                               /*
+                                * The current state is too shallow, so select
+                                * the first enabled deeper state.
+                                */
+                               duration_ns = last_enabled_span_ns;
+                               idx = last_enabled_idx;
+                               break;
+                       }
 
-               /*
-                * Give up unless the majority of the most recent idle duration
-                * values are in the interesting range.
-                */
-               if (count > INTERVALS / 2) {
-                       u64 avg_ns = div64_u64(sum, count);
-
-                       /*
-                        * Avoid spending too much time in an idle state that
-                        * would be too shallow.
-                        */
-                       if (teo_time_ok(avg_ns)) {
-                               duration_ns = avg_ns;
-                               if (drv->states[idx].target_residency_ns > avg_ns)
-                                       idx = teo_find_shallower_state(drv, dev,
-                                                                      idx, avg_ns);
+                       if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
+                           (!alt_intercepts ||
+                            2 * intercept_sum > idx_intercept_sum)) {
+                               idx = i;
+                               duration_ns = span_ns;
+                               break;
                        }
+
+                       last_enabled_span_ns = span_ns;
+                       last_enabled_idx = i;
                }
        }
 
        /*
+        * If there is a latency constraint, it may be necessary to select an
+        * idle state shallower than the current candidate one.
+        */
+       if (idx > constraint_idx)
+               idx = constraint_idx;
+
+end:
+       /*
         * Don't stop the tick if the selected state is a polling one or if the
         * expected idle duration is shorter than the tick period length.
         */
@@ -478,8 +498,8 @@ static int teo_enable_device(struct cpuidle_driver *drv,
 
        memset(cpu_data, 0, sizeof(*cpu_data));
 
-       for (i = 0; i < INTERVALS; i++)
-               cpu_data->intervals[i] = U64_MAX;
+       for (i = 0; i < NR_RECENT; i++)
+               cpu_data->recent_idx[i] = -1;
 
        return 0;
 }
index 9a4c275..ebcec46 100644 (file)
@@ -266,6 +266,27 @@ config CRYPTO_DEV_NIAGARA2
          Group, which can perform encryption, decryption, hashing,
          checksumming, and raw copies.
 
+config CRYPTO_DEV_SL3516
+       tristate "Stormlink SL3516 crypto offloader"
+       depends on HAS_IOMEM
+       select CRYPTO_SKCIPHER
+       select CRYPTO_ENGINE
+       select CRYPTO_ECB
+       select CRYPTO_AES
+       select HW_RANDOM
+       depends on PM
+       help
+         This option allows you to have support for SL3516 crypto offloader.
+
+config CRYPTO_DEV_SL3516_DEBUG
+       bool "Enable SL3516 stats"
+       depends on CRYPTO_DEV_SL3516
+       depends on DEBUG_FS
+       help
+         Say y to enable SL3516 debug stats.
+         This will create /sys/kernel/debug/sl3516/stats for displaying
+         the number of requests per algorithm and other internal stats.
+
 config CRYPTO_DEV_HIFN_795X
        tristate "Driver HIFN 795x crypto accelerator chips"
        select CRYPTO_LIB_DES
@@ -325,6 +346,11 @@ config CRYPTO_DEV_TALITOS2
 config CRYPTO_DEV_IXP4XX
        tristate "Driver for IXP4xx crypto hardware acceleration"
        depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE
+       select CRYPTO_AES
+       select CRYPTO_DES
+       select CRYPTO_ECB
+       select CRYPTO_CBC
+       select CRYPTO_CTR
        select CRYPTO_LIB_DES
        select CRYPTO_AEAD
        select CRYPTO_AUTHENC
@@ -627,6 +653,12 @@ config CRYPTO_DEV_QCE_SHA
        select CRYPTO_SHA1
        select CRYPTO_SHA256
 
+config CRYPTO_DEV_QCE_AEAD
+       bool
+       depends on CRYPTO_DEV_QCE
+       select CRYPTO_AUTHENC
+       select CRYPTO_LIB_DES
+
 choice
        prompt "Algorithms enabled for QCE acceleration"
        default CRYPTO_DEV_QCE_ENABLE_ALL
@@ -647,6 +679,7 @@ choice
                bool "All supported algorithms"
                select CRYPTO_DEV_QCE_SKCIPHER
                select CRYPTO_DEV_QCE_SHA
+               select CRYPTO_DEV_QCE_AEAD
                help
                  Enable all supported algorithms:
                        - AES (CBC, CTR, ECB, XTS)
@@ -672,6 +705,14 @@ choice
                        - SHA1, HMAC-SHA1
                        - SHA256, HMAC-SHA256
 
+       config CRYPTO_DEV_QCE_ENABLE_AEAD
+               bool "AEAD algorithms only"
+               select CRYPTO_DEV_QCE_AEAD
+               help
+                 Enable AEAD algorithms only:
+                       - authenc()
+                       - ccm(aes)
+                       - rfc4309(ccm(aes))
 endchoice
 
 config CRYPTO_DEV_QCE_SW_MAX_LEN
index fa22cb1..1fe5120 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
 obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/
 obj-$(CONFIG_ARCH_STM32) += stm32/
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
index 06ee42e..8c32d0e 100644 (file)
@@ -401,7 +401,7 @@ static void cpt_disable_all_cores(struct cpt_device *cpt)
        cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 0);
 }
 
-/**
+/*
  * Ensure all cores are disengaged from all groups by
  * calling cpt_disable_all_cores() before calling this
  * function.
index 4fe7898..153004b 100644 (file)
@@ -9,8 +9,8 @@
 
 /**
  * get_free_pending_entry - get free entry from pending queue
- * @param pqinfo: pending_qinfo structure
- * @param qno: queue number
+ * @q: pending queue
+ * @qlen: queue length
  */
 static struct pending_entry *get_free_pending_entry(struct pending_queue *q,
                                                    int qlen)
@@ -244,11 +244,7 @@ static int send_cpt_command(struct cpt_vf *cptvf, union cpt_inst_s *cmd,
        memcpy(ent, (void *)cmd, qinfo->cmd_size);
 
        if (++queue->idx >= queue->qhead->size / 64) {
-               struct hlist_node *node;
-
-               hlist_for_each(node, &queue->chead) {
-                       chunk = hlist_entry(node, struct command_chunk,
-                                           nextchunk);
+               hlist_for_each_entry(chunk, &queue->chead, nextchunk) {
                        if (chunk == queue->qhead) {
                                continue;
                        } else {
index c288c4b..f19e520 100644 (file)
@@ -307,6 +307,10 @@ int nitrox_register_interrupts(struct nitrox_device *ndev)
         * Entry 192: NPS_CORE_INT_ACTIVE
         */
        nr_vecs = pci_msix_vec_count(pdev);
+       if (nr_vecs < 0) {
+               dev_err(DEV(ndev), "Error in getting vec count %d\n", nr_vecs);
+               return nr_vecs;
+       }
 
        /* Enable MSI-X */
        ret = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX);
index d385daf..96bc7b5 100644 (file)
@@ -35,7 +35,7 @@ static LIST_HEAD(ndevlist);
 static DEFINE_MUTEX(devlist_lock);
 static unsigned int num_devices;
 
-/**
+/*
  * nitrox_pci_tbl - PCI Device ID Table
  */
 static const struct pci_device_id nitrox_pci_tbl[] = {
@@ -65,7 +65,7 @@ struct ucode {
        u64 code[];
 };
 
-/**
+/*
  * write_to_ucd_unit - Write Firmware to NITROX UCD unit
  */
 static void write_to_ucd_unit(struct nitrox_device *ndev, u32 ucode_size,
@@ -424,8 +424,7 @@ static int nitrox_probe(struct pci_dev *pdev,
        err = nitrox_device_flr(pdev);
        if (err) {
                dev_err(&pdev->dev, "FLR failed\n");
-               pci_disable_device(pdev);
-               return err;
+               goto flr_fail;
        }
 
        if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
@@ -434,16 +433,13 @@ static int nitrox_probe(struct pci_dev *pdev,
                err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
                        dev_err(&pdev->dev, "DMA configuration failed\n");
-                       pci_disable_device(pdev);
-                       return err;
+                       goto flr_fail;
                }
        }
 
        err = pci_request_mem_regions(pdev, nitrox_driver_name);
-       if (err) {
-               pci_disable_device(pdev);
-               return err;
-       }
+       if (err)
+               goto flr_fail;
        pci_set_master(pdev);
 
        ndev = kzalloc(sizeof(*ndev), GFP_KERNEL);
@@ -479,7 +475,7 @@ static int nitrox_probe(struct pci_dev *pdev,
 
        err = nitrox_pf_sw_init(ndev);
        if (err)
-               goto ioremap_err;
+               goto pf_sw_fail;
 
        err = nitrox_pf_hw_init(ndev);
        if (err)
@@ -509,12 +505,15 @@ crypto_fail:
        smp_mb__after_atomic();
 pf_hw_fail:
        nitrox_pf_sw_cleanup(ndev);
+pf_sw_fail:
+       iounmap(ndev->bar_addr);
 ioremap_err:
        nitrox_remove_from_devlist(ndev);
        kfree(ndev);
        pci_set_drvdata(pdev, NULL);
 ndev_fail:
        pci_release_mem_regions(pdev);
+flr_fail:
        pci_disable_device(pdev);
        return err;
 }
index c1af9d4..2e9c0d2 100644 (file)
@@ -8,7 +8,7 @@
 
 #define RING_TO_VFNO(_x, _y)   ((_x) / (_y))
 
-/**
+/*
  * mbx_msg_type - Mailbox message types
  */
 enum mbx_msg_type {
@@ -18,7 +18,7 @@ enum mbx_msg_type {
        MBX_MSG_TYPE_NACK,
 };
 
-/**
+/*
  * mbx_msg_opcode - Mailbox message opcodes
  */
 enum mbx_msg_opcode {
index df95ba2..55c18da 100644 (file)
@@ -19,7 +19,7 @@
 #define REQ_BACKLOG    2
 #define REQ_POSTED     3
 
-/**
+/*
  * Response codes from SE microcode
  * 0x00 - Success
  *   Completion with no error
@@ -159,7 +159,7 @@ static int dma_map_inbufs(struct nitrox_softreq *sr,
                          struct se_crypto_request *req)
 {
        struct device *dev = DEV(sr->ndev);
-       struct scatterlist *sg = req->src;
+       struct scatterlist *sg;
        int i, nents, ret = 0;
 
        nents = dma_map_sg(dev, req->src, sg_nents(req->src),
@@ -279,6 +279,7 @@ static inline bool cmdq_full(struct nitrox_cmdq *cmdq, int qlen)
 /**
  * post_se_instr - Post SE instruction to Packet Input ring
  * @sr: Request structure
+ * @cmdq: Command queue structure
  *
  * Returns 0 if successful or a negative error code,
  * if no space in ring.
@@ -369,9 +370,11 @@ static int nitrox_enqueue_request(struct nitrox_softreq *sr)
 }
 
 /**
- * nitrox_se_request - Send request to SE core
+ * nitrox_process_se_request - Send request to SE core
  * @ndev: NITROX device
  * @req: Crypto request
+ * @callback: Completion callback
+ * @cb_arg: Completion callback arguments
  *
  * Returns 0 on success, or a negative error code.
  */
@@ -526,9 +529,8 @@ static bool sr_completed(struct nitrox_softreq *sr)
 }
 
 /**
- * process_request_list - process completed requests
- * @ndev: N5 device
- * @qno: queue to operate
+ * process_response_list - process completed requests
+ * @cmdq: Command queue structure
  *
  * Returns the number of responses processed.
  */
@@ -578,7 +580,7 @@ static void process_response_list(struct nitrox_cmdq *cmdq)
        }
 }
 
-/**
+/*
  * pkt_slc_resp_tasklet - post processing of SE responses
  */
 void pkt_slc_resp_tasklet(unsigned long data)
index a553ac6..248b4ff 100644 (file)
@@ -20,7 +20,7 @@ struct nitrox_cipher {
        enum flexi_cipher value;
 };
 
-/**
+/*
  * supported cipher list
  */
 static const struct nitrox_cipher flexi_cipher_table[] = {
index 6777582..9ce4b68 100644 (file)
@@ -470,7 +470,7 @@ int ccp_cmd_queue_thread(void *data)
 /**
  * ccp_alloc_struct - allocate and initialize the ccp_device struct
  *
- * @dev: device struct of the CCP
+ * @sp: sp_device struct of the CCP
  */
 struct ccp_device *ccp_alloc_struct(struct sp_device *sp)
 {
index 0770a83..d718db2 100644 (file)
@@ -307,8 +307,7 @@ static dma_cookie_t ccp_tx_submit(struct dma_async_tx_descriptor *tx_desc)
        spin_lock_irqsave(&chan->lock, flags);
 
        cookie = dma_cookie_assign(tx_desc);
-       list_del(&desc->entry);
-       list_add_tail(&desc->entry, &chan->pending);
+       list_move_tail(&desc->entry, &chan->pending);
 
        spin_unlock_irqrestore(&chan->lock, flags);
 
index 3506b20..9180840 100644 (file)
@@ -43,6 +43,10 @@ static int psp_probe_timeout = 5;
 module_param(psp_probe_timeout, int, 0644);
 MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");
 
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model0xh.sbin"); /* 1st gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model3xh.sbin"); /* 2nd gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam19h_model0xh.sbin"); /* 3rd gen EPYC */
+
 static bool psp_dead;
 static int psp_timeout;
 
index f468594..6fb6ba3 100644 (file)
@@ -222,7 +222,7 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                if (ret) {
                        dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
                                ret);
-                       goto e_err;
+                       goto free_irqs;
                }
        }
 
@@ -230,10 +230,12 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ret = sp_init(sp);
        if (ret)
-               goto e_err;
+               goto free_irqs;
 
        return 0;
 
+free_irqs:
+       sp_free_irqs(sp);
 e_err:
        dev_notice(dev, "initialization failed\n");
        return ret;
diff --git a/drivers/crypto/gemini/Makefile b/drivers/crypto/gemini/Makefile
new file mode 100644 (file)
index 0000000..c73c8b6
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_SL3516) += sl3516-ce.o
+sl3516-ce-y += sl3516-ce-core.o sl3516-ce-cipher.o sl3516-ce-rng.o
diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemini/sl3516-ce-cipher.c
new file mode 100644 (file)
index 0000000..b41c2f5
--- /dev/null
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-cipher.c - hardware cryptographic offloader for Stormlink SL3516 SoC
+ *
+ * Copyright (C) 2021 Corentin LABBE <clabbe@baylibre.com>
+ *
+ * This file adds support for AES cipher with 128,192,256 bits keysize in
+ * ECB mode.
+ */
+
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/skcipher.h>
+#include "sl3516-ce.h"
+
+/* sl3516_ce_need_fallback - check if a request can be handled by the CE */
+static bool sl3516_ce_need_fallback(struct skcipher_request *areq)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_dev *ce = op->ce;
+       struct scatterlist *in_sg = areq->src;
+       struct scatterlist *out_sg = areq->dst;
+       struct scatterlist *sg;
+
+       if (areq->cryptlen == 0 || areq->cryptlen % 16) {
+               ce->fallback_mod16++;
+               return true;
+       }
+
+       /*
+        * check if we have enough descriptors for TX
+        * Note: TX need one control desc for each SG
+        */
+       if (sg_nents(areq->src) > MAXDESC / 2) {
+               ce->fallback_sg_count_tx++;
+               return true;
+       }
+       /* check if we have enough descriptors for RX */
+       if (sg_nents(areq->dst) > MAXDESC) {
+               ce->fallback_sg_count_rx++;
+               return true;
+       }
+
+       sg = areq->src;
+       while (sg) {
+               if ((sg->length % 16) != 0) {
+                       ce->fallback_mod16++;
+                       return true;
+               }
+               if ((sg_dma_len(sg) % 16) != 0) {
+                       ce->fallback_mod16++;
+                       return true;
+               }
+               if (!IS_ALIGNED(sg->offset, 16)) {
+                       ce->fallback_align16++;
+                       return true;
+               }
+               sg = sg_next(sg);
+       }
+       sg = areq->dst;
+       while (sg) {
+               if ((sg->length % 16) != 0) {
+                       ce->fallback_mod16++;
+                       return true;
+               }
+               if ((sg_dma_len(sg) % 16) != 0) {
+                       ce->fallback_mod16++;
+                       return true;
+               }
+               if (!IS_ALIGNED(sg->offset, 16)) {
+                       ce->fallback_align16++;
+                       return true;
+               }
+               sg = sg_next(sg);
+       }
+
+       /* need same numbers of SG (with same length) for source and destination */
+       in_sg = areq->src;
+       out_sg = areq->dst;
+       while (in_sg && out_sg) {
+               if (in_sg->length != out_sg->length) {
+                       ce->fallback_not_same_len++;
+                       return true;
+               }
+               in_sg = sg_next(in_sg);
+               out_sg = sg_next(out_sg);
+       }
+       if (in_sg || out_sg)
+               return true;
+
+       return false;
+}
+
+static int sl3516_ce_cipher_fallback(struct skcipher_request *areq)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+       struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+       struct sl3516_ce_alg_template *algt;
+       int err;
+
+       algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+       algt->stat_fb++;
+
+       skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+       skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+                                     areq->base.complete, areq->base.data);
+       skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+                                  areq->cryptlen, areq->iv);
+       if (rctx->op_dir == CE_DECRYPTION)
+               err = crypto_skcipher_decrypt(&rctx->fallback_req);
+       else
+               err = crypto_skcipher_encrypt(&rctx->fallback_req);
+       return err;
+}
+
+static int sl3516_ce_cipher(struct skcipher_request *areq)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_dev *ce = op->ce;
+       struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+       struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+       struct sl3516_ce_alg_template *algt;
+       struct scatterlist *sg;
+       unsigned int todo, len;
+       struct pkt_control_ecb *ecb;
+       int nr_sgs = 0;
+       int nr_sgd = 0;
+       int err = 0;
+       int i;
+
+       algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+
+       dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
+               crypto_tfm_alg_name(areq->base.tfm),
+               areq->cryptlen,
+               rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm),
+               op->keylen);
+
+       algt->stat_req++;
+
+       if (areq->src == areq->dst) {
+               nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
+                                   DMA_BIDIRECTIONAL);
+               if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
+                       dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
+                       err = -EINVAL;
+                       goto theend;
+               }
+               nr_sgd = nr_sgs;
+       } else {
+               nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
+                                   DMA_TO_DEVICE);
+               if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
+                       dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
+                       err = -EINVAL;
+                       goto theend;
+               }
+               nr_sgd = dma_map_sg(ce->dev, areq->dst, sg_nents(areq->dst),
+                                   DMA_FROM_DEVICE);
+               if (nr_sgd <= 0 || nr_sgd > MAXDESC) {
+                       dev_err(ce->dev, "Invalid sg number %d\n", nr_sgd);
+                       err = -EINVAL;
+                       goto theend_sgs;
+               }
+       }
+
+       len = areq->cryptlen;
+       i = 0;
+       sg = areq->src;
+       while (i < nr_sgs && sg && len) {
+               if (sg_dma_len(sg) == 0)
+                       goto sgs_next;
+               rctx->t_src[i].addr = sg_dma_address(sg);
+               todo = min(len, sg_dma_len(sg));
+               rctx->t_src[i].len = todo;
+               dev_dbg(ce->dev, "%s total=%u SGS(%d %u off=%d) todo=%u\n", __func__,
+                       areq->cryptlen, i, rctx->t_src[i].len, sg->offset, todo);
+               len -= todo;
+               i++;
+sgs_next:
+               sg = sg_next(sg);
+       }
+       if (len > 0) {
+               dev_err(ce->dev, "remaining len %d/%u nr_sgs=%d\n", len, areq->cryptlen, nr_sgs);
+               err = -EINVAL;
+               goto theend_sgs;
+       }
+
+       len = areq->cryptlen;
+       i = 0;
+       sg = areq->dst;
+       while (i < nr_sgd && sg && len) {
+               if (sg_dma_len(sg) == 0)
+                       goto sgd_next;
+               rctx->t_dst[i].addr = sg_dma_address(sg);
+               todo = min(len, sg_dma_len(sg));
+               rctx->t_dst[i].len = todo;
+               dev_dbg(ce->dev, "%s total=%u SGD(%d %u off=%d) todo=%u\n", __func__,
+                       areq->cryptlen, i, rctx->t_dst[i].len, sg->offset, todo);
+               len -= todo;
+               i++;
+
+sgd_next:
+               sg = sg_next(sg);
+       }
+       if (len > 0) {
+               dev_err(ce->dev, "remaining len %d\n", len);
+               err = -EINVAL;
+               goto theend_sgs;
+       }
+
+       switch (algt->mode) {
+       case ECB_AES:
+               rctx->pctrllen = sizeof(struct pkt_control_ecb);
+               ecb = (struct pkt_control_ecb *)ce->pctrl;
+
+               rctx->tqflag = TQ0_TYPE_CTRL;
+               rctx->tqflag |= TQ1_CIPHER;
+               ecb->control.op_mode = rctx->op_dir;
+               ecb->control.cipher_algorithm = ECB_AES;
+               ecb->cipher.header_len = 0;
+               ecb->cipher.algorithm_len = areq->cryptlen;
+               cpu_to_be32_array((__be32 *)ecb->key, (u32 *)op->key, op->keylen / 4);
+               rctx->h = &ecb->cipher;
+
+               rctx->tqflag |= TQ4_KEY0;
+               rctx->tqflag |= TQ5_KEY4;
+               rctx->tqflag |= TQ6_KEY6;
+               ecb->control.aesnk = op->keylen / 4;
+               break;
+       }
+
+       rctx->nr_sgs = nr_sgs;
+       rctx->nr_sgd = nr_sgd;
+       err = sl3516_ce_run_task(ce, rctx, crypto_tfm_alg_name(areq->base.tfm));
+
+theend_sgs:
+       if (areq->src == areq->dst) {
+               dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
+                            DMA_BIDIRECTIONAL);
+       } else {
+               dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
+                            DMA_TO_DEVICE);
+               dma_unmap_sg(ce->dev, areq->dst, sg_nents(areq->dst),
+                            DMA_FROM_DEVICE);
+       }
+
+theend:
+
+       return err;
+}
+
+static int sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
+{
+       int err;
+       struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
+
+       err = sl3516_ce_cipher(breq);
+       crypto_finalize_skcipher_request(engine, breq, err);
+
+       return 0;
+}
+
+int sl3516_ce_skdecrypt(struct skcipher_request *areq)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+       struct crypto_engine *engine;
+
+       memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
+       rctx->op_dir = CE_DECRYPTION;
+
+       if (sl3516_ce_need_fallback(areq))
+               return sl3516_ce_cipher_fallback(areq);
+
+       engine = op->ce->engine;
+
+       return crypto_transfer_skcipher_request_to_engine(engine, areq);
+}
+
+int sl3516_ce_skencrypt(struct skcipher_request *areq)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+       struct crypto_engine *engine;
+
+       memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
+       rctx->op_dir = CE_ENCRYPTION;
+
+       if (sl3516_ce_need_fallback(areq))
+               return sl3516_ce_cipher_fallback(areq);
+
+       engine = op->ce->engine;
+
+       return crypto_transfer_skcipher_request_to_engine(engine, areq);
+}
+
+int sl3516_ce_cipher_init(struct crypto_tfm *tfm)
+{
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
+       struct sl3516_ce_alg_template *algt;
+       const char *name = crypto_tfm_alg_name(tfm);
+       struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm);
+       struct skcipher_alg *alg = crypto_skcipher_alg(sktfm);
+       int err;
+
+       memset(op, 0, sizeof(struct sl3516_ce_cipher_tfm_ctx));
+
+       algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+       op->ce = algt->ce;
+
+       op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(op->fallback_tfm)) {
+               dev_err(op->ce->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
+                       name, PTR_ERR(op->fallback_tfm));
+               return PTR_ERR(op->fallback_tfm);
+       }
+
+       sktfm->reqsize = sizeof(struct sl3516_ce_cipher_req_ctx) +
+                        crypto_skcipher_reqsize(op->fallback_tfm);
+
+       dev_info(op->ce->dev, "Fallback for %s is %s\n",
+                crypto_tfm_alg_driver_name(&sktfm->base),
+                crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)));
+
+       op->enginectx.op.do_one_request = sl3516_ce_handle_cipher_request;
+       op->enginectx.op.prepare_request = NULL;
+       op->enginectx.op.unprepare_request = NULL;
+
+       err = pm_runtime_get_sync(op->ce->dev);
+       if (err < 0)
+               goto error_pm;
+
+       return 0;
+error_pm:
+       pm_runtime_put_noidle(op->ce->dev);
+       crypto_free_skcipher(op->fallback_tfm);
+       return err;
+}
+
+void sl3516_ce_cipher_exit(struct crypto_tfm *tfm)
+{
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
+
+       kfree_sensitive(op->key);
+       crypto_free_skcipher(op->fallback_tfm);
+       pm_runtime_put_sync_suspend(op->ce->dev);
+}
+
+int sl3516_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
+                        unsigned int keylen)
+{
+       struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+       struct sl3516_ce_dev *ce = op->ce;
+
+       switch (keylen) {
+       case 128 / 8:
+               break;
+       case 192 / 8:
+               break;
+       case 256 / 8:
+               break;
+       default:
+               dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
+               return -EINVAL;
+       }
+       kfree_sensitive(op->key);
+       op->keylen = keylen;
+       op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
+       if (!op->key)
+               return -ENOMEM;
+
+       crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+       crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+
+       return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
+}
diff --git a/drivers/crypto/gemini/sl3516-ce-core.c b/drivers/crypto/gemini/sl3516-ce-core.c
new file mode 100644 (file)
index 0000000..da6cd52
--- /dev/null
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-core.c - hardware cryptographic offloader for Stormlink SL3516 SoC
+ *
+ * Copyright (C) 2021 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * Core file which registers crypto algorithms supported by the CryptoEngine
+ */
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/internal/rng.h>
+#include <crypto/internal/skcipher.h>
+
+#include "sl3516-ce.h"
+
+static int sl3516_ce_desc_init(struct sl3516_ce_dev *ce)
+{
+       const size_t sz = sizeof(struct descriptor) * MAXDESC;
+       int i;
+
+       ce->tx = dma_alloc_coherent(ce->dev, sz, &ce->dtx, GFP_KERNEL);
+       if (!ce->tx)
+               return -ENOMEM;
+       ce->rx = dma_alloc_coherent(ce->dev, sz, &ce->drx, GFP_KERNEL);
+       if (!ce->rx)
+               goto err_rx;
+
+       for (i = 0; i < MAXDESC; i++) {
+               ce->tx[i].frame_ctrl.bits.own = CE_CPU;
+               ce->tx[i].next_desc.next_descriptor = ce->dtx + (i + 1) * sizeof(struct descriptor);
+       }
+       ce->tx[MAXDESC - 1].next_desc.next_descriptor = ce->dtx;
+
+       for (i = 0; i < MAXDESC; i++) {
+               ce->rx[i].frame_ctrl.bits.own = CE_CPU;
+               ce->rx[i].next_desc.next_descriptor = ce->drx + (i + 1) * sizeof(struct descriptor);
+       }
+       ce->rx[MAXDESC - 1].next_desc.next_descriptor = ce->drx;
+
+       ce->pctrl = dma_alloc_coherent(ce->dev, sizeof(struct pkt_control_ecb),
+                                      &ce->dctrl, GFP_KERNEL);
+       if (!ce->pctrl)
+               goto err_pctrl;
+
+       return 0;
+err_pctrl:
+       dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
+err_rx:
+       dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
+       return -ENOMEM;
+}
+
+static void sl3516_ce_free_descs(struct sl3516_ce_dev *ce)
+{
+       const size_t sz = sizeof(struct descriptor) * MAXDESC;
+
+       dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
+       dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
+       dma_free_coherent(ce->dev, sizeof(struct pkt_control_ecb), ce->pctrl,
+                         ce->dctrl);
+}
+
+static void start_dma_tx(struct sl3516_ce_dev *ce)
+{
+       u32 v;
+
+       v = TXDMA_CTRL_START | TXDMA_CTRL_CHAIN_MODE | TXDMA_CTRL_CONTINUE | \
+               TXDMA_CTRL_INT_FAIL | TXDMA_CTRL_INT_PERR | TXDMA_CTRL_BURST_UNK;
+
+       writel(v, ce->base + IPSEC_TXDMA_CTRL);
+}
+
+static void start_dma_rx(struct sl3516_ce_dev *ce)
+{
+       u32 v;
+
+       v = RXDMA_CTRL_START | RXDMA_CTRL_CHAIN_MODE | RXDMA_CTRL_CONTINUE | \
+               RXDMA_CTRL_BURST_UNK | RXDMA_CTRL_INT_FINISH | \
+               RXDMA_CTRL_INT_FAIL | RXDMA_CTRL_INT_PERR | \
+               RXDMA_CTRL_INT_EOD | RXDMA_CTRL_INT_EOF;
+
+       writel(v, ce->base + IPSEC_RXDMA_CTRL);
+}
+
+static struct descriptor *get_desc_tx(struct sl3516_ce_dev *ce)
+{
+       struct descriptor *dd;
+
+       dd = &ce->tx[ce->ctx];
+       ce->ctx++;
+       if (ce->ctx >= MAXDESC)
+               ce->ctx = 0;
+       return dd;
+}
+
+static struct descriptor *get_desc_rx(struct sl3516_ce_dev *ce)
+{
+       struct descriptor *rdd;
+
+       rdd = &ce->rx[ce->crx];
+       ce->crx++;
+       if (ce->crx >= MAXDESC)
+               ce->crx = 0;
+       return rdd;
+}
+
+int sl3516_ce_run_task(struct sl3516_ce_dev *ce, struct sl3516_ce_cipher_req_ctx *rctx,
+                      const char *name)
+{
+       struct descriptor *dd, *rdd = NULL;
+       u32 v;
+       int i, err = 0;
+
+       ce->stat_req++;
+
+       reinit_completion(&ce->complete);
+       ce->status = 0;
+
+       for (i = 0; i < rctx->nr_sgd; i++) {
+               dev_dbg(ce->dev, "%s handle DST SG %d/%d len=%d\n", __func__,
+                       i, rctx->nr_sgd, rctx->t_dst[i].len);
+               rdd = get_desc_rx(ce);
+               rdd->buf_adr = rctx->t_dst[i].addr;
+               rdd->frame_ctrl.bits.buffer_size = rctx->t_dst[i].len;
+               rdd->frame_ctrl.bits.own = CE_DMA;
+       }
+       rdd->next_desc.bits.eofie = 1;
+
+       for (i = 0; i < rctx->nr_sgs; i++) {
+               dev_dbg(ce->dev, "%s handle SRC SG %d/%d len=%d\n", __func__,
+                       i, rctx->nr_sgs, rctx->t_src[i].len);
+               rctx->h->algorithm_len = rctx->t_src[i].len;
+
+               dd = get_desc_tx(ce);
+               dd->frame_ctrl.raw = 0;
+               dd->flag_status.raw = 0;
+               dd->frame_ctrl.bits.buffer_size = rctx->pctrllen;
+               dd->buf_adr = ce->dctrl;
+               dd->flag_status.tx_flag.tqflag = rctx->tqflag;
+               dd->next_desc.bits.eofie = 0;
+               dd->next_desc.bits.dec = 0;
+               dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
+               dd->frame_ctrl.bits.own = CE_DMA;
+
+               dd = get_desc_tx(ce);
+               dd->frame_ctrl.raw = 0;
+               dd->flag_status.raw = 0;
+               dd->frame_ctrl.bits.buffer_size = rctx->t_src[i].len;
+               dd->buf_adr = rctx->t_src[i].addr;
+               dd->flag_status.tx_flag.tqflag = 0;
+               dd->next_desc.bits.eofie = 0;
+               dd->next_desc.bits.dec = 0;
+               dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
+               dd->frame_ctrl.bits.own = CE_DMA;
+               start_dma_tx(ce);
+               start_dma_rx(ce);
+       }
+       wait_for_completion_interruptible_timeout(&ce->complete,
+                                                 msecs_to_jiffies(5000));
+       if (ce->status == 0) {
+               dev_err(ce->dev, "DMA timeout for %s\n", name);
+               err = -EFAULT;
+       }
+       v = readl(ce->base + IPSEC_STATUS_REG);
+       if (v & 0xFFF) {
+               dev_err(ce->dev, "IPSEC_STATUS_REG %x\n", v);
+               err = -EFAULT;
+       }
+
+       return err;
+}
+
+static irqreturn_t ce_irq_handler(int irq, void *data)
+{
+       struct sl3516_ce_dev *ce = (struct sl3516_ce_dev *)data;
+       u32 v;
+
+       ce->stat_irq++;
+
+       v = readl(ce->base + IPSEC_DMA_STATUS);
+       writel(v, ce->base + IPSEC_DMA_STATUS);
+
+       if (v & DMA_STATUS_TS_DERR)
+               dev_err(ce->dev, "AHB bus Error While Tx !!!\n");
+       if (v & DMA_STATUS_TS_PERR)
+               dev_err(ce->dev, "Tx Descriptor Protocol Error !!!\n");
+       if (v & DMA_STATUS_RS_DERR)
+               dev_err(ce->dev, "AHB bus Error While Rx !!!\n");
+       if (v & DMA_STATUS_RS_PERR)
+               dev_err(ce->dev, "Rx Descriptor Protocol Error !!!\n");
+
+       if (v & DMA_STATUS_TS_EOFI)
+               ce->stat_irq_tx++;
+       if (v & DMA_STATUS_RS_EOFI) {
+               ce->status = 1;
+               complete(&ce->complete);
+               ce->stat_irq_rx++;
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct sl3516_ce_alg_template ce_algs[] = {
+{
+       .type = CRYPTO_ALG_TYPE_SKCIPHER,
+       .mode = ECB_AES,
+       .alg.skcipher = {
+               .base = {
+                       .cra_name = "ecb(aes)",
+                       .cra_driver_name = "ecb-aes-sl3516",
+                       .cra_priority = 400,
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
+                               CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+                       .cra_ctxsize = sizeof(struct sl3516_ce_cipher_tfm_ctx),
+                       .cra_module = THIS_MODULE,
+                       .cra_alignmask = 0xf,
+                       .cra_init = sl3516_ce_cipher_init,
+                       .cra_exit = sl3516_ce_cipher_exit,
+               },
+               .min_keysize    = AES_MIN_KEY_SIZE,
+               .max_keysize    = AES_MAX_KEY_SIZE,
+               .setkey         = sl3516_ce_aes_setkey,
+               .encrypt        = sl3516_ce_skencrypt,
+               .decrypt        = sl3516_ce_skdecrypt,
+       }
+},
+};
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+static int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
+{
+       struct sl3516_ce_dev *ce = seq->private;
+       unsigned int i;
+
+       seq_printf(seq, "HWRNG %lu %lu\n",
+                  ce->hwrng_stat_req, ce->hwrng_stat_bytes);
+       seq_printf(seq, "IRQ %lu\n", ce->stat_irq);
+       seq_printf(seq, "IRQ TX %lu\n", ce->stat_irq_tx);
+       seq_printf(seq, "IRQ RX %lu\n", ce->stat_irq_rx);
+       seq_printf(seq, "nreq %lu\n", ce->stat_req);
+       seq_printf(seq, "fallback SG count TX %lu\n", ce->fallback_sg_count_tx);
+       seq_printf(seq, "fallback SG count RX %lu\n", ce->fallback_sg_count_rx);
+       seq_printf(seq, "fallback modulo16 %lu\n", ce->fallback_mod16);
+       seq_printf(seq, "fallback align16 %lu\n", ce->fallback_align16);
+       seq_printf(seq, "fallback not same len %lu\n", ce->fallback_not_same_len);
+
+       for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+               if (!ce_algs[i].ce)
+                       continue;
+               switch (ce_algs[i].type) {
+               case CRYPTO_ALG_TYPE_SKCIPHER:
+                       seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+                                  ce_algs[i].alg.skcipher.base.cra_driver_name,
+                                  ce_algs[i].alg.skcipher.base.cra_name,
+                                  ce_algs[i].stat_req, ce_algs[i].stat_fb);
+                       break;
+               }
+       }
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(sl3516_ce_debugfs);
+#endif
+
+static int sl3516_ce_register_algs(struct sl3516_ce_dev *ce)
+{
+       int err;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+               ce_algs[i].ce = ce;
+               switch (ce_algs[i].type) {
+               case CRYPTO_ALG_TYPE_SKCIPHER:
+                       dev_info(ce->dev, "DEBUG: Register %s\n",
+                                ce_algs[i].alg.skcipher.base.cra_name);
+                       err = crypto_register_skcipher(&ce_algs[i].alg.skcipher);
+                       if (err) {
+                               dev_err(ce->dev, "Fail to register %s\n",
+                                       ce_algs[i].alg.skcipher.base.cra_name);
+                               ce_algs[i].ce = NULL;
+                               return err;
+                       }
+                       break;
+               default:
+                       ce_algs[i].ce = NULL;
+                       dev_err(ce->dev, "ERROR: tried to register an unknown algo\n");
+               }
+       }
+       return 0;
+}
+
+static void sl3516_ce_unregister_algs(struct sl3516_ce_dev *ce)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+               if (!ce_algs[i].ce)
+                       continue;
+               switch (ce_algs[i].type) {
+               case CRYPTO_ALG_TYPE_SKCIPHER:
+                       dev_info(ce->dev, "Unregister %d %s\n", i,
+                                ce_algs[i].alg.skcipher.base.cra_name);
+                       crypto_unregister_skcipher(&ce_algs[i].alg.skcipher);
+                       break;
+               }
+       }
+}
+
+static void sl3516_ce_start(struct sl3516_ce_dev *ce)
+{
+       ce->ctx = 0;
+       ce->crx = 0;
+       writel(ce->dtx, ce->base + IPSEC_TXDMA_CURR_DESC);
+       writel(ce->drx, ce->base + IPSEC_RXDMA_CURR_DESC);
+       writel(0, ce->base + IPSEC_DMA_STATUS);
+}
+
+/*
+ * Power management strategy: The device is suspended unless a TFM exists for
+ * one of the algorithms proposed by this driver.
+ */
+static int sl3516_ce_pm_suspend(struct device *dev)
+{
+       struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
+
+       reset_control_assert(ce->reset);
+       clk_disable_unprepare(ce->clks);
+       return 0;
+}
+
+static int sl3516_ce_pm_resume(struct device *dev)
+{
+       struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
+       int err;
+
+       err = clk_prepare_enable(ce->clks);
+       if (err) {
+               dev_err(ce->dev, "Cannot prepare_enable\n");
+               goto error;
+       }
+       err = reset_control_deassert(ce->reset);
+       if (err) {
+               dev_err(ce->dev, "Cannot deassert reset control\n");
+               goto error;
+       }
+
+       sl3516_ce_start(ce);
+
+       return 0;
+error:
+       sl3516_ce_pm_suspend(dev);
+       return err;
+}
+
+static const struct dev_pm_ops sl3516_ce_pm_ops = {
+       SET_RUNTIME_PM_OPS(sl3516_ce_pm_suspend, sl3516_ce_pm_resume, NULL)
+};
+
+static int sl3516_ce_pm_init(struct sl3516_ce_dev *ce)
+{
+       int err;
+
+       pm_runtime_use_autosuspend(ce->dev);
+       pm_runtime_set_autosuspend_delay(ce->dev, 2000);
+
+       err = pm_runtime_set_suspended(ce->dev);
+       if (err)
+               return err;
+       pm_runtime_enable(ce->dev);
+       return err;
+}
+
+static void sl3516_ce_pm_exit(struct sl3516_ce_dev *ce)
+{
+       pm_runtime_disable(ce->dev);
+}
+
+static int sl3516_ce_probe(struct platform_device *pdev)
+{
+       struct sl3516_ce_dev *ce;
+       int err, irq;
+       u32 v;
+
+       ce = devm_kzalloc(&pdev->dev, sizeof(*ce), GFP_KERNEL);
+       if (!ce)
+               return -ENOMEM;
+
+       ce->dev = &pdev->dev;
+       platform_set_drvdata(pdev, ce);
+
+       ce->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(ce->base))
+               return PTR_ERR(ce->base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       err = devm_request_irq(&pdev->dev, irq, ce_irq_handler, 0, "crypto", ce);
+       if (err) {
+               dev_err(ce->dev, "Cannot request Crypto Engine IRQ (err=%d)\n", err);
+               return err;
+       }
+
+       ce->reset = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(ce->reset))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ce->reset),
+                                    "No reset control found\n");
+       ce->clks = devm_clk_get(ce->dev, NULL);
+       if (IS_ERR(ce->clks)) {
+               err = PTR_ERR(ce->clks);
+               dev_err(ce->dev, "Cannot get clock err=%d\n", err);
+               return err;
+       }
+
+       err = sl3516_ce_desc_init(ce);
+       if (err)
+               return err;
+
+       err = sl3516_ce_pm_init(ce);
+       if (err)
+               goto error_pm;
+
+       init_completion(&ce->complete);
+
+       ce->engine = crypto_engine_alloc_init(ce->dev, true);
+       if (!ce->engine) {
+               dev_err(ce->dev, "Cannot allocate engine\n");
+               err = -ENOMEM;
+               goto error_engine;
+       }
+
+       err = crypto_engine_start(ce->engine);
+       if (err) {
+               dev_err(ce->dev, "Cannot start engine\n");
+               goto error_engine;
+       }
+
+       err = sl3516_ce_register_algs(ce);
+       if (err)
+               goto error_alg;
+
+       err = sl3516_ce_rng_register(ce);
+       if (err)
+               goto error_rng;
+
+       err = pm_runtime_resume_and_get(ce->dev);
+       if (err < 0)
+               goto error_pmuse;
+
+       v = readl(ce->base + IPSEC_ID);
+       dev_info(ce->dev, "SL3516 dev %lx rev %lx\n",
+                v & GENMASK(31, 4),
+                v & GENMASK(3, 0));
+       v = readl(ce->base + IPSEC_DMA_DEVICE_ID);
+       dev_info(ce->dev, "SL3516 DMA dev %lx rev %lx\n",
+                v & GENMASK(15, 4),
+                v & GENMASK(3, 0));
+
+       pm_runtime_put_sync(ce->dev);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+       /* Ignore error of debugfs */
+       ce->dbgfs_dir = debugfs_create_dir("sl3516", NULL);
+       ce->dbgfs_stats = debugfs_create_file("stats", 0444,
+                                             ce->dbgfs_dir, ce,
+                                             &sl3516_ce_debugfs_fops);
+#endif
+
+       return 0;
+error_pmuse:
+       sl3516_ce_rng_unregister(ce);
+error_rng:
+       sl3516_ce_unregister_algs(ce);
+error_alg:
+       crypto_engine_exit(ce->engine);
+error_engine:
+       sl3516_ce_pm_exit(ce);
+error_pm:
+       sl3516_ce_free_descs(ce);
+       return err;
+}
+
+static int sl3516_ce_remove(struct platform_device *pdev)
+{
+       struct sl3516_ce_dev *ce = platform_get_drvdata(pdev);
+
+       sl3516_ce_rng_unregister(ce);
+       sl3516_ce_unregister_algs(ce);
+       crypto_engine_exit(ce->engine);
+       sl3516_ce_pm_exit(ce);
+       sl3516_ce_free_descs(ce);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+       debugfs_remove_recursive(ce->dbgfs_dir);
+#endif
+
+       return 0;
+}
+
+static const struct of_device_id sl3516_ce_crypto_of_match_table[] = {
+       { .compatible = "cortina,sl3516-crypto"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, sl3516_ce_crypto_of_match_table);
+
+static struct platform_driver sl3516_ce_driver = {
+       .probe           = sl3516_ce_probe,
+       .remove          = sl3516_ce_remove,
+       .driver          = {
+               .name           = "sl3516-crypto",
+               .pm             = &sl3516_ce_pm_ops,
+               .of_match_table = sl3516_ce_crypto_of_match_table,
+       },
+};
+
+module_platform_driver(sl3516_ce_driver);
+
+MODULE_DESCRIPTION("SL3516 cryptographic offloader");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
diff --git a/drivers/crypto/gemini/sl3516-ce-rng.c b/drivers/crypto/gemini/sl3516-ce-rng.c
new file mode 100644 (file)
index 0000000..76931ec
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-rng.c - hardware cryptographic offloader for SL3516 SoC.
+ *
+ * Copyright (C) 2021 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file handle the RNG found in the SL3516 crypto engine
+ */
+#include "sl3516-ce.h"
+#include <linux/pm_runtime.h>
+#include <linux/hw_random.h>
+
+static int sl3516_ce_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+       struct sl3516_ce_dev *ce;
+       u32 *data = buf;
+       size_t read = 0;
+       int err;
+
+       ce = container_of(rng, struct sl3516_ce_dev, trng);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+       ce->hwrng_stat_req++;
+       ce->hwrng_stat_bytes += max;
+#endif
+
+       err = pm_runtime_get_sync(ce->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(ce->dev);
+               return err;
+       }
+
+       while (read < max) {
+               *data = readl(ce->base + IPSEC_RAND_NUM_REG);
+               data++;
+               read += 4;
+       }
+
+       pm_runtime_put(ce->dev);
+
+       return read;
+}
+
+int sl3516_ce_rng_register(struct sl3516_ce_dev *ce)
+{
+       int ret;
+
+       ce->trng.name = "SL3516 Crypto Engine RNG";
+       ce->trng.read = sl3516_ce_rng_read;
+       ce->trng.quality = 700;
+
+       ret = hwrng_register(&ce->trng);
+       if (ret)
+               dev_err(ce->dev, "Fail to register the RNG\n");
+       return ret;
+}
+
+void sl3516_ce_rng_unregister(struct sl3516_ce_dev *ce)
+{
+       hwrng_unregister(&ce->trng);
+}
diff --git a/drivers/crypto/gemini/sl3516-ce.h b/drivers/crypto/gemini/sl3516-ce.h
new file mode 100644 (file)
index 0000000..4c0ec6c
--- /dev/null
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * sl3516-ce.h - hardware cryptographic offloader for cortina/gemini SoC
+ *
+ * Copyright (C) 2021 Corentin LABBE <clabbe@baylibre.com>
+ *
+ * General notes on this driver:
+ * Called either Crypto Acceleration Engine Module, Security Acceleration Engine
+ * or IPSEC module in the datasheet, it will be called Crypto Engine for short
+ * in this driver.
+ * The CE was designed to handle IPSEC and wifi(TKIP WEP) protocol.
+ * It can handle AES, DES, 3DES, MD5, WEP, TKIP, SHA1, HMAC(MD5), HMAC(SHA1),
+ * Michael cipher/digest suites.
+ * It acts the same as a network hw, with both RX and TX chained descriptors.
+ */
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/hw_random.h>
+
+#define TQ0_TYPE_DATA 0
+#define TQ0_TYPE_CTRL BIT(0)
+#define TQ1_CIPHER BIT(1)
+#define TQ2_AUTH BIT(2)
+#define TQ3_IV BIT(3)
+#define TQ4_KEY0 BIT(4)
+#define TQ5_KEY4 BIT(5)
+#define TQ6_KEY6 BIT(6)
+#define TQ7_AKEY0 BIT(7)
+#define TQ8_AKEY2 BIT(8)
+#define TQ9_AKEY2 BIT(9)
+
+#define ECB_AES       0x2
+
+#define DESC_LAST 0x01
+#define DESC_FIRST 0x02
+
+#define IPSEC_ID               0x0000
+#define IPSEC_STATUS_REG       0x00a8
+#define IPSEC_RAND_NUM_REG     0x00ac
+#define IPSEC_DMA_DEVICE_ID    0xff00
+#define IPSEC_DMA_STATUS       0xff04
+#define IPSEC_TXDMA_CTRL       0xff08
+#define IPSEC_TXDMA_FIRST_DESC 0xff0c
+#define IPSEC_TXDMA_CURR_DESC  0xff10
+#define IPSEC_RXDMA_CTRL       0xff14
+#define IPSEC_RXDMA_FIRST_DESC 0xff18
+#define IPSEC_RXDMA_CURR_DESC  0xff1c
+#define IPSEC_TXDMA_BUF_ADDR   0xff28
+#define IPSEC_RXDMA_BUF_ADDR   0xff38
+#define IPSEC_RXDMA_BUF_SIZE   0xff30
+
+#define CE_ENCRYPTION          0x01
+#define CE_DECRYPTION          0x03
+
+#define MAXDESC 6
+
+#define DMA_STATUS_RS_EOFI     BIT(22)
+#define DMA_STATUS_RS_PERR     BIT(24)
+#define DMA_STATUS_RS_DERR     BIT(25)
+#define DMA_STATUS_TS_EOFI     BIT(27)
+#define DMA_STATUS_TS_PERR     BIT(29)
+#define DMA_STATUS_TS_DERR     BIT(30)
+
+#define TXDMA_CTRL_START BIT(31)
+#define TXDMA_CTRL_CONTINUE BIT(30)
+#define TXDMA_CTRL_CHAIN_MODE BIT(29)
+/* the burst value is not documented in the datasheet */
+#define TXDMA_CTRL_BURST_UNK BIT(22)
+#define TXDMA_CTRL_INT_FAIL BIT(17)
+#define TXDMA_CTRL_INT_PERR BIT(16)
+
+#define RXDMA_CTRL_START BIT(31)
+#define RXDMA_CTRL_CONTINUE BIT(30)
+#define RXDMA_CTRL_CHAIN_MODE BIT(29)
+/* the burst value is not documented in the datasheet */
+#define RXDMA_CTRL_BURST_UNK BIT(22)
+#define RXDMA_CTRL_INT_FINISH BIT(18)
+#define RXDMA_CTRL_INT_FAIL BIT(17)
+#define RXDMA_CTRL_INT_PERR BIT(16)
+#define RXDMA_CTRL_INT_EOD BIT(15)
+#define RXDMA_CTRL_INT_EOF BIT(14)
+
+#define CE_CPU 0
+#define CE_DMA 1
+
+/*
+ * struct sl3516_ce_descriptor - descriptor for CE operations
+ * @frame_ctrl:                Information for the current descriptor
+ * @flag_status:       For send packet, describe flag of operations.
+ * @buf_adr:           pointer to a send/recv buffer for data packet
+ * @next_desc:         control linking to other descriptors
+ */
+struct descriptor {
+       union {
+               u32 raw;
+               /*
+                * struct desc_frame_ctrl - Information for the current descriptor
+                * @buffer_size:        the size of buffer at buf_adr
+                * @desc_count:         Upon completion of a DMA operation, DMA
+                *                      write the number of descriptors used
+                *                      for the current frame
+                * @checksum:           unknown
+                * @authcomp:           unknown
+                * @perr:               Protocol error during processing this descriptor
+                * @derr:               Data error during processing this descriptor
+                * @own:                0 if owned by CPU, 1 for DMA
+                */
+               struct desc_frame_ctrl {
+                       u32 buffer_size :16;
+                       u32 desc_count  :6;
+                       u32 checksum    :6;
+                       u32 authcomp    :1;
+                       u32 perr        :1;
+                       u32 derr        :1;
+                       u32 own         :1;
+               } bits;
+       } frame_ctrl;
+
+       union {
+               u32 raw;
+               /*
+                * struct desc_flag_status - flag for this descriptor
+                * @tqflag:     list of flag describing the type of operation
+                *              to be performed.
+                */
+               struct desc_tx_flag_status {
+                       u32 tqflag      :10;
+                       u32 unused      :22;
+               } tx_flag;
+       } flag_status;
+
+       u32 buf_adr;
+
+       union {
+               u32 next_descriptor;
+               /*
+                * struct desc_next - describe chaining of descriptors
+                * @sof_eof:    does the descriptor is first (0x11),
+                *              the last (0x01), middle of a chan (0x00)
+                *              or the only one (0x11)
+                * @dec:        AHB bus address increase (0), decrease (1)
+                * @eofie:      End of frame interrupt enable
+                * @ndar:       Next descriptor address
+                */
+               struct desc_next {
+                       u32 sof_eof     :2;
+                       u32 dec         :1;
+                       u32 eofie       :1;
+                       u32 ndar        :28;
+               } bits;
+       } next_desc;
+};
+
+/*
+ * struct control - The value of this register is used to set the
+ *                     operation mode of the IPSec Module.
+ * @process_id:                Used to identify the process. The number will be copied
+ *                     to the descriptor status of the received packet.
+ * @auth_check_len:    Number of 32-bit words to be checked or appended by the
+ *                     authentication module
+ * @auth_algorithm:
+ * @auth_mode:         0:append 1:Check Authentication Result
+ * @fcs_stream_copy:   0:enable 1:disable authentication stream copy
+ * @mix_key_sel:       0:use rCipherKey0-3  1:use Key Mixer
+ * @aesnk:             AES Key Size
+ * @cipher_algorithm:  choice of CBC/ECE and AES/DES/3DES
+ * @op_mode:           Operation Mode for the IPSec Module
+ */
+struct pkt_control_header {
+       u32 process_id          :8;
+       u32 auth_check_len      :3;
+       u32 un1                 :1;
+       u32 auth_algorithm      :3;
+       u32 auth_mode           :1;
+       u32 fcs_stream_copy     :1;
+       u32 un2                 :2;
+       u32 mix_key_sel         :1;
+       u32 aesnk               :4;
+       u32 cipher_algorithm    :3;
+       u32 un3                 :1;
+       u32 op_mode             :4;
+};
+
+struct pkt_control_cipher {
+       u32 algorithm_len       :16;
+       u32 header_len          :16;
+};
+
+/*
+ * struct pkt_control_ecb - control packet for ECB
+ */
+struct pkt_control_ecb {
+       struct pkt_control_header control;
+       struct pkt_control_cipher cipher;
+       unsigned char key[AES_MAX_KEY_SIZE];
+};
+
+/*
+ * struct sl3516_ce_dev - main container for all this driver information
+ * @base:      base address
+ * @clks:      clocks used
+ * @reset:     pointer to reset controller
+ * @dev:       the platform device
+ * @engine:    ptr to the crypto/crypto_engine
+ * @complete:  completion for the current task on this flow
+ * @status:    set to 1 by interrupt if task is done
+ * @dtx:       base DMA address for TX descriptors
+ * @tx         base address of TX descriptors
+ * @drx:       base DMA address for RX descriptors
+ * @rx         base address of RX descriptors
+ * @ctx                current used TX descriptor
+ * @crx                current used RX descriptor
+ * @trng       hw_random structure for RNG
+ * @hwrng_stat_req     number of HWRNG requests
+ * @hwrng_stat_bytes   total number of bytes generated by RNG
+ * @stat_irq   number of IRQ handled by CE
+ * @stat_irq_tx        number of TX IRQ handled by CE
+ * @stat_irq_rx        number of RX IRQ handled by CE
+ * @stat_req   number of requests handled by CE
+ * @fallbak_sg_count_tx                number of fallback due to destination SG count
+ * @fallbak_sg_count_rx                number of fallback due to source SG count
+ * @fallbak_not_same_len       number of fallback due to difference in SG length
+ * @dbgfs_dir: Debugfs dentry for statistic directory
+ * @dbgfs_stats: Debugfs dentry for statistic counters
+ */
+struct sl3516_ce_dev {
+       void __iomem *base;
+       struct clk *clks;
+       struct reset_control *reset;
+       struct device *dev;
+       struct crypto_engine *engine;
+       struct completion complete;
+       int status;
+       dma_addr_t dtx;
+       struct descriptor *tx;
+       dma_addr_t drx;
+       struct descriptor *rx;
+       int ctx;
+       int crx;
+       struct hwrng trng;
+       unsigned long hwrng_stat_req;
+       unsigned long hwrng_stat_bytes;
+       unsigned long stat_irq;
+       unsigned long stat_irq_tx;
+       unsigned long stat_irq_rx;
+       unsigned long stat_req;
+       unsigned long fallback_sg_count_tx;
+       unsigned long fallback_sg_count_rx;
+       unsigned long fallback_not_same_len;
+       unsigned long fallback_mod16;
+       unsigned long fallback_align16;
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+       struct dentry *dbgfs_dir;
+       struct dentry *dbgfs_stats;
+#endif
+       void *pctrl;
+       dma_addr_t dctrl;
+};
+
+struct sginfo {
+       u32 addr;
+       u32 len;
+};
+
+/*
+ * struct sl3516_ce_cipher_req_ctx - context for a skcipher request
+ * @t_src:             list of mapped SGs with their size
+ * @t_dst:             list of mapped SGs with their size
+ * @op_dir:            direction (encrypt vs decrypt) for this request
+ * @pctrllen:          the length of the ctrl packet
+ * @tqflag:            the TQflag to set in data packet
+ * @h                  pointer to the pkt_control_cipher header
+ * @nr_sgs:            number of source SG
+ * @nr_sgd:            number of destination SG
+ * @fallback_req:      request struct for invoking the fallback skcipher TFM
+ */
+struct sl3516_ce_cipher_req_ctx {
+       struct sginfo t_src[MAXDESC];
+       struct sginfo t_dst[MAXDESC];
+       u32 op_dir;
+       unsigned int pctrllen;
+       u32 tqflag;
+       struct pkt_control_cipher *h;
+       int nr_sgs;
+       int nr_sgd;
+       struct skcipher_request fallback_req;   // keep at the end
+};
+
+/*
+ * struct sl3516_ce_cipher_tfm_ctx - context for a skcipher TFM
+ * @enginectx:         crypto_engine used by this TFM
+ * @key:               pointer to key data
+ * @keylen:            len of the key
+ * @ce:                        pointer to the private data of driver handling this TFM
+ * @fallback_tfm:      pointer to the fallback TFM
+ *
+ * enginectx must be the first element
+ */
+struct sl3516_ce_cipher_tfm_ctx {
+       struct crypto_engine_ctx enginectx;
+       u32 *key;
+       u32 keylen;
+       struct sl3516_ce_dev *ce;
+       struct crypto_skcipher *fallback_tfm;
+};
+
+/*
+ * struct sl3516_ce_alg_template - crypto_alg template
+ * @type:              the CRYPTO_ALG_TYPE for this template
+ * @mode:              value to be used in control packet for this algorithm
+ * @ce:                        pointer to the sl3516_ce_dev structure associated with
+ *                     this template
+ * @alg:               one of sub struct must be used
+ * @stat_req:          number of request done on this template
+ * @stat_fb:           number of request which has fallbacked
+ * @stat_bytes:                total data size done by this template
+ */
+struct sl3516_ce_alg_template {
+       u32 type;
+       u32 mode;
+       struct sl3516_ce_dev *ce;
+       union {
+               struct skcipher_alg skcipher;
+       } alg;
+       unsigned long stat_req;
+       unsigned long stat_fb;
+       unsigned long stat_bytes;
+};
+
+int sl3516_ce_enqueue(struct crypto_async_request *areq, u32 type);
+
+int sl3516_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
+                        unsigned int keylen);
+int sl3516_ce_cipher_init(struct crypto_tfm *tfm);
+void sl3516_ce_cipher_exit(struct crypto_tfm *tfm);
+int sl3516_ce_skdecrypt(struct skcipher_request *areq);
+int sl3516_ce_skencrypt(struct skcipher_request *areq);
+
+int sl3516_ce_run_task(struct sl3516_ce_dev *ce,
+                      struct sl3516_ce_cipher_req_ctx *rctx, const char *name);
+
+int sl3516_ce_rng_register(struct sl3516_ce_dev *ce);
+void sl3516_ce_rng_unregister(struct sl3516_ce_dev *ce);
index a380087..a032c19 100644 (file)
@@ -5,6 +5,7 @@
 #include <crypto/dh.h>
 #include <crypto/ecc_curve.h>
 #include <crypto/ecdh.h>
+#include <crypto/rng.h>
 #include <crypto/internal/akcipher.h>
 #include <crypto/internal/kpp.h>
 #include <crypto/internal/rsa.h>
@@ -30,7 +31,6 @@ struct hpre_ctx;
 #define HPRE_DH_G_FLAG         0x02
 #define HPRE_TRY_SEND_TIMES    100
 #define HPRE_INVLD_REQ_ID              (-1)
-#define HPRE_DEV(ctx)          (&((ctx)->qp->qm->pdev->dev))
 
 #define HPRE_SQE_ALG_BITS      5
 #define HPRE_SQE_DONE_SHIFT    30
@@ -39,12 +39,17 @@ struct hpre_ctx;
 #define HPRE_DFX_SEC_TO_US     1000000
 #define HPRE_DFX_US_TO_NS      1000
 
+/* due to nist p521  */
+#define HPRE_ECC_MAX_KSZ       66
+
 /* size in bytes of the n prime */
 #define HPRE_ECC_NIST_P192_N_SIZE      24
 #define HPRE_ECC_NIST_P256_N_SIZE      32
+#define HPRE_ECC_NIST_P384_N_SIZE      48
 
 /* size in bytes */
 #define HPRE_ECC_HW256_KSZ_B   32
+#define HPRE_ECC_HW384_KSZ_B   48
 
 typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe);
 
@@ -102,6 +107,7 @@ struct hpre_curve25519_ctx {
 
 struct hpre_ctx {
        struct hisi_qp *qp;
+       struct device *dev;
        struct hpre_asym_request **req_list;
        struct hpre *hpre;
        spinlock_t req_lock;
@@ -214,8 +220,7 @@ static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req,
                                  struct scatterlist *data, unsigned int len,
                                  int is_src, dma_addr_t *tmp)
 {
-       struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = hpre_req->ctx->dev;
        enum dma_data_direction dma_dir;
 
        if (is_src) {
@@ -239,7 +244,7 @@ static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req,
                                int is_src, dma_addr_t *tmp)
 {
        struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        void *ptr;
        int shift;
 
@@ -293,11 +298,13 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
                                 struct scatterlist *dst,
                                 struct scatterlist *src)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        struct hpre_sqe *sqe = &req->req;
        dma_addr_t tmp;
 
        tmp = le64_to_cpu(sqe->in);
+       if (unlikely(dma_mapping_error(dev, tmp)))
+               return;
 
        if (src) {
                if (req->src)
@@ -307,6 +314,8 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
        }
 
        tmp = le64_to_cpu(sqe->out);
+       if (unlikely(dma_mapping_error(dev, tmp)))
+               return;
 
        if (req->dst) {
                if (dst)
@@ -321,16 +330,15 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
 static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe,
                                void **kreq)
 {
-       struct device *dev = HPRE_DEV(ctx);
        struct hpre_asym_request *req;
        unsigned int err, done, alg;
        int id;
 
 #define HPRE_NO_HW_ERR         0
 #define HPRE_HW_TASK_DONE      3
-#define HREE_HW_ERR_MASK       0x7ff
-#define HREE_SQE_DONE_MASK     0x3
-#define HREE_ALG_TYPE_MASK     0x1f
+#define HREE_HW_ERR_MASK       GENMASK(10, 0)
+#define HREE_SQE_DONE_MASK     GENMASK(1, 0)
+#define HREE_ALG_TYPE_MASK     GENMASK(4, 0)
        id = (int)le16_to_cpu(sqe->tag);
        req = ctx->req_list[id];
        hpre_rm_req_from_ctx(req);
@@ -346,7 +354,7 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe,
                return 0;
 
        alg = le32_to_cpu(sqe->dw0) & HREE_ALG_TYPE_MASK;
-       dev_err_ratelimited(dev, "alg[0x%x] error: done[0x%x], etype[0x%x]\n",
+       dev_err_ratelimited(ctx->dev, "alg[0x%x] error: done[0x%x], etype[0x%x]\n",
                alg, done, err);
 
        return -EINVAL;
@@ -361,6 +369,7 @@ static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen)
 
        spin_lock_init(&ctx->req_lock);
        ctx->qp = qp;
+       ctx->dev = &qp->qm->pdev->dev;
 
        hpre = container_of(ctx->qp->qm, struct hpre, qm);
        ctx->hpre = hpre;
@@ -524,6 +533,8 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa)
                msg->key = cpu_to_le64(ctx->dh.dma_xa_p);
        }
 
+       msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+       msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
        msg->dw0 |= cpu_to_le32(0x1 << HPRE_SQE_DONE_SHIFT);
        msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1;
        h_req->ctx = ctx;
@@ -618,14 +629,14 @@ static int hpre_is_dh_params_length_valid(unsigned int key_sz)
        case _HPRE_DH_GRP15:
        case _HPRE_DH_GRP16:
                return 0;
+       default:
+               return -EINVAL;
        }
-
-       return -EINVAL;
 }
 
 static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int sz;
 
        if (params->p_size > HPRE_DH_MAX_P_SZ)
@@ -664,7 +675,7 @@ static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params)
 
 static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int sz = ctx->key_sz;
 
        if (is_clear_all)
@@ -877,18 +888,18 @@ static int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value,
        if (!hpre_rsa_key_size_is_support(ctx->key_sz))
                return 0;
 
-       ctx->rsa.pubkey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+       ctx->rsa.pubkey = dma_alloc_coherent(ctx->dev, vlen << 1,
                                             &ctx->rsa.dma_pubkey,
                                             GFP_KERNEL);
        if (!ctx->rsa.pubkey)
                return -ENOMEM;
 
        if (private) {
-               ctx->rsa.prikey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+               ctx->rsa.prikey = dma_alloc_coherent(ctx->dev, vlen << 1,
                                                     &ctx->rsa.dma_prikey,
                                                     GFP_KERNEL);
                if (!ctx->rsa.prikey) {
-                       dma_free_coherent(HPRE_DEV(ctx), vlen << 1,
+                       dma_free_coherent(ctx->dev, vlen << 1,
                                          ctx->rsa.pubkey,
                                          ctx->rsa.dma_pubkey);
                        ctx->rsa.pubkey = NULL;
@@ -950,7 +961,7 @@ static int hpre_crt_para_get(char *para, size_t para_sz,
 static int hpre_rsa_setkey_crt(struct hpre_ctx *ctx, struct rsa_key *rsa_key)
 {
        unsigned int hlf_ksz = ctx->key_sz >> 1;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        u64 offset;
        int ret;
 
@@ -1008,7 +1019,7 @@ free_key:
 static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
 {
        unsigned int half_key_sz = ctx->key_sz >> 1;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
 
        if (is_clear_all)
                hisi_qm_stop_qp(ctx->qp);
@@ -1179,7 +1190,7 @@ static void hpre_key_to_big_end(u8 *data, int len)
 static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all,
                               bool is_ecdh)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int sz = ctx->key_sz;
        unsigned int shift = sz << 1;
 
@@ -1202,12 +1213,21 @@ static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all,
        hpre_ctx_clear(ctx, is_clear_all);
 }
 
+/*
+ * The bits of 192/224/256/384/521 are supported by HPRE,
+ * and convert the bits like:
+ * bits<=256, bits=256; 256<bits<=384, bits=384; 384<bits<=576, bits=576;
+ * If the parameter bit width is insufficient, then we fill in the
+ * high-order zeros by soft, so TASK_LENGTH1 is 0x3/0x5/0x8;
+ */
 static unsigned int hpre_ecdh_supported_curve(unsigned short id)
 {
        switch (id) {
        case ECC_CURVE_NIST_P192:
        case ECC_CURVE_NIST_P256:
                return HPRE_ECC_HW256_KSZ_B;
+       case ECC_CURVE_NIST_P384:
+               return HPRE_ECC_HW384_KSZ_B;
        default:
                break;
        }
@@ -1272,6 +1292,8 @@ static unsigned int hpre_ecdh_get_curvesz(unsigned short id)
                return HPRE_ECC_NIST_P192_N_SIZE;
        case ECC_CURVE_NIST_P256:
                return HPRE_ECC_NIST_P256_N_SIZE;
+       case ECC_CURVE_NIST_P384:
+               return HPRE_ECC_NIST_P384_N_SIZE;
        default:
                break;
        }
@@ -1281,7 +1303,7 @@ static unsigned int hpre_ecdh_get_curvesz(unsigned short id)
 
 static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int sz, shift, curve_sz;
        int ret;
 
@@ -1328,11 +1350,32 @@ static bool hpre_key_is_zero(char *key, unsigned short key_sz)
        return true;
 }
 
+static int ecdh_gen_privkey(struct hpre_ctx *ctx, struct ecdh *params)
+{
+       struct device *dev = ctx->dev;
+       int ret;
+
+       ret = crypto_get_default_rng();
+       if (ret) {
+               dev_err(dev, "failed to get default rng, ret = %d!\n", ret);
+               return ret;
+       }
+
+       ret = crypto_rng_get_bytes(crypto_default_rng, (u8 *)params->key,
+                                  params->key_size);
+       crypto_put_default_rng();
+       if (ret)
+               dev_err(dev, "failed to get rng, ret = %d!\n", ret);
+
+       return ret;
+}
+
 static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
                                unsigned int len)
 {
        struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
+       char key[HPRE_ECC_MAX_KSZ];
        unsigned int sz, sz_shift;
        struct ecdh params;
        int ret;
@@ -1342,6 +1385,15 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
                return -EINVAL;
        }
 
+       /* Use stdrng to generate private key */
+       if (!params.key || !params.key_size) {
+               params.key = key;
+               params.key_size = hpre_ecdh_get_curvesz(ctx->curve_id);
+               ret = ecdh_gen_privkey(ctx, &params);
+               if (ret)
+                       return ret;
+       }
+
        if (hpre_key_is_zero(params.key, params.key_size)) {
                dev_err(dev, "Invalid hpre key!\n");
                return -EINVAL;
@@ -1367,16 +1419,20 @@ static void hpre_ecdh_hw_data_clr_all(struct hpre_ctx *ctx,
                                      struct scatterlist *dst,
                                      struct scatterlist *src)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        struct hpre_sqe *sqe = &req->req;
        dma_addr_t dma;
 
        dma = le64_to_cpu(sqe->in);
+       if (unlikely(dma_mapping_error(dev, dma)))
+               return;
 
        if (src && req->src)
                dma_free_coherent(dev, ctx->key_sz << 2, req->src, dma);
 
        dma = le64_to_cpu(sqe->out);
+       if (unlikely(dma_mapping_error(dev, dma)))
+               return;
 
        if (req->dst)
                dma_free_coherent(dev, ctx->key_sz << 1, req->dst, dma);
@@ -1431,6 +1487,8 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx,
        h_req->areq.ecdh = req;
        msg = &h_req->req;
        memset(msg, 0, sizeof(*msg));
+       msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+       msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
        msg->key = cpu_to_le64(ctx->ecdh.dma_p);
 
        msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT);
@@ -1450,7 +1508,7 @@ static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req,
 {
        struct hpre_sqe *msg = &hpre_req->req;
        struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int tmpshift;
        dma_addr_t dma = 0;
        void *ptr;
@@ -1480,8 +1538,8 @@ static int hpre_ecdh_dst_data_init(struct hpre_asym_request *hpre_req,
 {
        struct hpre_sqe *msg = &hpre_req->req;
        struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
-       dma_addr_t dma = 0;
+       struct device *dev = ctx->dev;
+       dma_addr_t dma;
 
        if (unlikely(!data || !sg_is_last(data) || len != ctx->key_sz << 1)) {
                dev_err(dev, "data or data length is illegal!\n");
@@ -1503,7 +1561,7 @@ static int hpre_ecdh_compute_value(struct kpp_request *req)
 {
        struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
        struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        void *tmp = kpp_request_ctx(req);
        struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
        struct hpre_sqe *msg = &hpre_req->req;
@@ -1568,6 +1626,15 @@ static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
        return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE);
 }
 
+static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
+{
+       struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+       ctx->curve_id = ECC_CURVE_NIST_P384;
+
+       return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE);
+}
+
 static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm)
 {
        struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
@@ -1609,7 +1676,7 @@ static void hpre_curve25519_fill_curve(struct hpre_ctx *ctx, const void *buf,
 static int hpre_curve25519_set_param(struct hpre_ctx *ctx, const void *buf,
                                     unsigned int len)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        unsigned int sz = ctx->key_sz;
        unsigned int shift = sz << 1;
 
@@ -1634,7 +1701,7 @@ static int hpre_curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
                                      unsigned int len)
 {
        struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        int ret = -EINVAL;
 
        if (len != CURVE25519_KEY_SIZE ||
@@ -1662,16 +1729,20 @@ static void hpre_curve25519_hw_data_clr_all(struct hpre_ctx *ctx,
                                            struct scatterlist *dst,
                                            struct scatterlist *src)
 {
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        struct hpre_sqe *sqe = &req->req;
        dma_addr_t dma;
 
        dma = le64_to_cpu(sqe->in);
+       if (unlikely(dma_mapping_error(dev, dma)))
+               return;
 
        if (src && req->src)
                dma_free_coherent(dev, ctx->key_sz, req->src, dma);
 
        dma = le64_to_cpu(sqe->out);
+       if (unlikely(dma_mapping_error(dev, dma)))
+               return;
 
        if (req->dst)
                dma_free_coherent(dev, ctx->key_sz, req->dst, dma);
@@ -1722,6 +1793,8 @@ static int hpre_curve25519_msg_request_set(struct hpre_ctx *ctx,
        h_req->areq.curve25519 = req;
        msg = &h_req->req;
        memset(msg, 0, sizeof(*msg));
+       msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+       msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
        msg->key = cpu_to_le64(ctx->curve25519.dma_p);
 
        msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT);
@@ -1752,7 +1825,7 @@ static int hpre_curve25519_src_init(struct hpre_asym_request *hpre_req,
 {
        struct hpre_sqe *msg = &hpre_req->req;
        struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        u8 p[CURVE25519_KEY_SIZE] = { 0 };
        const struct ecc_curve *curve;
        dma_addr_t dma = 0;
@@ -1790,8 +1863,12 @@ static int hpre_curve25519_src_init(struct hpre_asym_request *hpre_req,
         * When src_data equals (2^255 - 19) ~  (2^255 - 1), it is out of p,
         * we get its modulus to p, and then use it.
         */
-       if (memcmp(ptr, p, ctx->key_sz) >= 0)
+       if (memcmp(ptr, p, ctx->key_sz) == 0) {
+               dev_err(dev, "gx is p!\n");
+               return -EINVAL;
+       } else if (memcmp(ptr, p, ctx->key_sz) > 0) {
                hpre_curve25519_src_modulo_p(ptr);
+       }
 
        hpre_req->src = ptr;
        msg->in = cpu_to_le64(dma);
@@ -1807,8 +1884,8 @@ static int hpre_curve25519_dst_init(struct hpre_asym_request *hpre_req,
 {
        struct hpre_sqe *msg = &hpre_req->req;
        struct hpre_ctx *ctx = hpre_req->ctx;
-       struct device *dev = HPRE_DEV(ctx);
-       dma_addr_t dma = 0;
+       struct device *dev = ctx->dev;
+       dma_addr_t dma;
 
        if (!data || !sg_is_last(data) || len != ctx->key_sz) {
                dev_err(dev, "data or data length is illegal!\n");
@@ -1830,7 +1907,7 @@ static int hpre_curve25519_compute_value(struct kpp_request *req)
 {
        struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
        struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
-       struct device *dev = HPRE_DEV(ctx);
+       struct device *dev = ctx->dev;
        void *tmp = kpp_request_ctx(req);
        struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
        struct hpre_sqe *msg = &hpre_req->req;
@@ -1940,7 +2017,7 @@ static struct kpp_alg ecdh_nist_p192 = {
                .cra_ctxsize = sizeof(struct hpre_ctx),
                .cra_priority = HPRE_CRYPTO_ALG_PRI,
                .cra_name = "ecdh-nist-p192",
-               .cra_driver_name = "hpre-ecdh",
+               .cra_driver_name = "hpre-ecdh-nist-p192",
                .cra_module = THIS_MODULE,
        },
 };
@@ -1957,7 +2034,24 @@ static struct kpp_alg ecdh_nist_p256 = {
                .cra_ctxsize = sizeof(struct hpre_ctx),
                .cra_priority = HPRE_CRYPTO_ALG_PRI,
                .cra_name = "ecdh-nist-p256",
-               .cra_driver_name = "hpre-ecdh",
+               .cra_driver_name = "hpre-ecdh-nist-p256",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static struct kpp_alg ecdh_nist_p384 = {
+       .set_secret = hpre_ecdh_set_secret,
+       .generate_public_key = hpre_ecdh_compute_value,
+       .compute_shared_secret = hpre_ecdh_compute_value,
+       .max_size = hpre_ecdh_max_size,
+       .init = hpre_ecdh_nist_p384_init_tfm,
+       .exit = hpre_ecdh_exit_tfm,
+       .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ,
+       .base = {
+               .cra_ctxsize = sizeof(struct hpre_ctx),
+               .cra_priority = HPRE_CRYPTO_ALG_PRI,
+               .cra_name = "ecdh-nist-p384",
+               .cra_driver_name = "hpre-ecdh-nist-p384",
                .cra_module = THIS_MODULE,
        },
 };
@@ -1989,16 +2083,25 @@ static int hpre_register_ecdh(void)
                return ret;
 
        ret = crypto_register_kpp(&ecdh_nist_p256);
-       if (ret) {
-               crypto_unregister_kpp(&ecdh_nist_p192);
-               return ret;
-       }
+       if (ret)
+               goto unregister_ecdh_p192;
+
+       ret = crypto_register_kpp(&ecdh_nist_p384);
+       if (ret)
+               goto unregister_ecdh_p256;
 
        return 0;
+
+unregister_ecdh_p256:
+       crypto_unregister_kpp(&ecdh_nist_p256);
+unregister_ecdh_p192:
+       crypto_unregister_kpp(&ecdh_nist_p192);
+       return ret;
 }
 
 static void hpre_unregister_ecdh(void)
 {
+       crypto_unregister_kpp(&ecdh_nist_p384);
        crypto_unregister_kpp(&ecdh_nist_p256);
        crypto_unregister_kpp(&ecdh_nist_p192);
 }
index 046bc96..8b0640f 100644 (file)
@@ -36,7 +36,7 @@
 #define HPRE_INT_MASK                  0x301400
 #define HPRE_INT_STATUS                        0x301800
 #define HPRE_CORE_INT_ENABLE           0
-#define HPRE_CORE_INT_DISABLE          0x003fffff
+#define HPRE_CORE_INT_DISABLE          GENMASK(21, 0)
 #define HPRE_RDCHN_INI_ST              0x301a00
 #define HPRE_CLSTR_BASE                        0x302000
 #define HPRE_CORE_EN_OFFSET            0x04
@@ -50,6 +50,7 @@
 #define HPRE_RAS_NFE_ENB               0x301414
 #define HPRE_HAC_RAS_NFE_ENABLE                0x3ffffe
 #define HPRE_RAS_FE_ENB                        0x301418
+#define HPRE_OOO_SHUTDOWN_SEL          0x301a3c
 #define HPRE_HAC_RAS_FE_ENABLE         0
 
 #define HPRE_CORE_ENB          (HPRE_CLSTR_BASE + HPRE_CORE_EN_OFFSET)
@@ -57,7 +58,6 @@
 #define HPRE_CORE_INI_STATUS (HPRE_CLSTR_BASE + HPRE_CORE_INI_STATUS_OFFSET)
 #define HPRE_HAC_ECC1_CNT              0x301a04
 #define HPRE_HAC_ECC2_CNT              0x301a08
-#define HPRE_HAC_INT_STATUS            0x301800
 #define HPRE_HAC_SOURCE_INT            0x301600
 #define HPRE_CLSTR_ADDR_INTRVL         0x1000
 #define HPRE_CLUSTER_INQURY            0x100
 #define HPRE_DBGFS_VAL_MAX_LEN         20
 #define HPRE_PCI_DEVICE_ID             0xa258
 #define HPRE_PCI_VF_DEVICE_ID          0xa259
-#define HPRE_ADDR(qm, offset)          ((qm)->io_base + (offset))
-#define HPRE_QM_USR_CFG_MASK           0xfffffffe
-#define HPRE_QM_AXI_CFG_MASK           0xffff
-#define HPRE_QM_VFG_AX_MASK            0xff
-#define HPRE_BD_USR_MASK               0x3
-#define HPRE_CLUSTER_CORE_MASK_V2      0xf
-#define HPRE_CLUSTER_CORE_MASK_V3      0xff
+#define HPRE_QM_USR_CFG_MASK           GENMASK(31, 1)
+#define HPRE_QM_AXI_CFG_MASK           GENMASK(15, 0)
+#define HPRE_QM_VFG_AX_MASK            GENMASK(7, 0)
+#define HPRE_BD_USR_MASK               GENMASK(1, 0)
+#define HPRE_CLUSTER_CORE_MASK_V2      GENMASK(3, 0)
+#define HPRE_CLUSTER_CORE_MASK_V3      GENMASK(7, 0)
+#define HPRE_PREFETCH_CFG              0x301130
+#define HPRE_SVA_PREFTCH_DFX           0x30115C
+#define HPRE_PREFETCH_ENABLE           (~(BIT(0) | BIT(30)))
+#define HPRE_PREFETCH_DISABLE          BIT(30)
+#define HPRE_SVA_DISABLE_READY         (BIT(4) | BIT(8))
 
 #define HPRE_AM_OOO_SHUTDOWN_ENB       0x301044
 #define HPRE_AM_OOO_SHUTDOWN_ENABLE    BIT(0)
 #define HPRE_QM_PM_FLR                 BIT(11)
 #define HPRE_QM_SRIOV_FLR              BIT(12)
 
-#define HPRE_CLUSTERS_NUM(qm)          \
-       (((qm)->ver >= QM_HW_V3) ? HPRE_CLUSTERS_NUM_V3 : HPRE_CLUSTERS_NUM_V2)
-#define HPRE_CLUSTER_CORE_MASK(qm)     \
-       (((qm)->ver >= QM_HW_V3) ? HPRE_CLUSTER_CORE_MASK_V3 :\
-               HPRE_CLUSTER_CORE_MASK_V2)
+#define HPRE_SHAPER_TYPE_RATE          128
 #define HPRE_VIA_MSI_DSM               1
 #define HPRE_SQE_MASK_OFFSET           8
 #define HPRE_SQE_MASK_LEN              24
@@ -123,21 +123,49 @@ static const char * const hpre_debug_file_name[] = {
 };
 
 static const struct hpre_hw_error hpre_hw_errors[] = {
-       { .int_msk = BIT(0), .msg = "core_ecc_1bit_err_int_set" },
-       { .int_msk = BIT(1), .msg = "core_ecc_2bit_err_int_set" },
-       { .int_msk = BIT(2), .msg = "dat_wb_poison_int_set" },
-       { .int_msk = BIT(3), .msg = "dat_rd_poison_int_set" },
-       { .int_msk = BIT(4), .msg = "bd_rd_poison_int_set" },
-       { .int_msk = BIT(5), .msg = "ooo_ecc_2bit_err_int_set" },
-       { .int_msk = BIT(6), .msg = "cluster1_shb_timeout_int_set" },
-       { .int_msk = BIT(7), .msg = "cluster2_shb_timeout_int_set" },
-       { .int_msk = BIT(8), .msg = "cluster3_shb_timeout_int_set" },
-       { .int_msk = BIT(9), .msg = "cluster4_shb_timeout_int_set" },
-       { .int_msk = GENMASK(15, 10), .msg = "ooo_rdrsp_err_int_set" },
-       { .int_msk = GENMASK(21, 16), .msg = "ooo_wrrsp_err_int_set" },
-       { .int_msk = BIT(22), .msg = "pt_rng_timeout_int_set"},
-       { .int_msk = BIT(23), .msg = "sva_fsm_timeout_int_set"},
        {
+               .int_msk = BIT(0),
+               .msg = "core_ecc_1bit_err_int_set"
+       }, {
+               .int_msk = BIT(1),
+               .msg = "core_ecc_2bit_err_int_set"
+       }, {
+               .int_msk = BIT(2),
+               .msg = "dat_wb_poison_int_set"
+       }, {
+               .int_msk = BIT(3),
+               .msg = "dat_rd_poison_int_set"
+       }, {
+               .int_msk = BIT(4),
+               .msg = "bd_rd_poison_int_set"
+       }, {
+               .int_msk = BIT(5),
+               .msg = "ooo_ecc_2bit_err_int_set"
+       }, {
+               .int_msk = BIT(6),
+               .msg = "cluster1_shb_timeout_int_set"
+       }, {
+               .int_msk = BIT(7),
+               .msg = "cluster2_shb_timeout_int_set"
+       }, {
+               .int_msk = BIT(8),
+               .msg = "cluster3_shb_timeout_int_set"
+       }, {
+               .int_msk = BIT(9),
+               .msg = "cluster4_shb_timeout_int_set"
+       }, {
+               .int_msk = GENMASK(15, 10),
+               .msg = "ooo_rdrsp_err_int_set"
+       }, {
+               .int_msk = GENMASK(21, 16),
+               .msg = "ooo_wrrsp_err_int_set"
+       }, {
+               .int_msk = BIT(22),
+               .msg = "pt_rng_timeout_int_set"
+       }, {
+               .int_msk = BIT(23),
+               .msg = "sva_fsm_timeout_int_set"
+       }, {
                /* sentinel */
        }
 };
@@ -224,6 +252,18 @@ static u32 vfs_num;
 module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
 MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)");
 
+static inline int hpre_cluster_num(struct hisi_qm *qm)
+{
+       return (qm->ver >= QM_HW_V3) ? HPRE_CLUSTERS_NUM_V3 :
+               HPRE_CLUSTERS_NUM_V2;
+}
+
+static inline int hpre_cluster_core_mask(struct hisi_qm *qm)
+{
+       return (qm->ver >= QM_HW_V3) ?
+               HPRE_CLUSTER_CORE_MASK_V3 : HPRE_CLUSTER_CORE_MASK_V2;
+}
+
 struct hisi_qp *hpre_create_qp(u8 type)
 {
        int node = cpu_to_node(smp_processor_id());
@@ -290,8 +330,8 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm)
 
 static int hpre_set_cluster(struct hisi_qm *qm)
 {
-       u32 cluster_core_mask = HPRE_CLUSTER_CORE_MASK(qm);
-       u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+       u32 cluster_core_mask = hpre_cluster_core_mask(qm);
+       u8 clusters_num = hpre_cluster_num(qm);
        struct device *dev = &qm->pdev->dev;
        unsigned long offset;
        u32 val = 0;
@@ -302,10 +342,10 @@ static int hpre_set_cluster(struct hisi_qm *qm)
 
                /* clusters initiating */
                writel(cluster_core_mask,
-                      HPRE_ADDR(qm, offset + HPRE_CORE_ENB));
-               writel(0x1, HPRE_ADDR(qm, offset + HPRE_CORE_INI_CFG));
-               ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, offset +
-                                       HPRE_CORE_INI_STATUS), val,
+                      qm->io_base + offset + HPRE_CORE_ENB);
+               writel(0x1, qm->io_base + offset + HPRE_CORE_INI_CFG);
+               ret = readl_relaxed_poll_timeout(qm->io_base + offset +
+                                       HPRE_CORE_INI_STATUS, val,
                                        ((val & cluster_core_mask) ==
                                        cluster_core_mask),
                                        HPRE_REG_RD_INTVRL_US,
@@ -329,11 +369,52 @@ static void disable_flr_of_bme(struct hisi_qm *qm)
 {
        u32 val;
 
-       val = readl(HPRE_ADDR(qm, QM_PEH_AXUSER_CFG));
+       val = readl(qm->io_base + QM_PEH_AXUSER_CFG);
        val &= ~(HPRE_QM_BME_FLR | HPRE_QM_SRIOV_FLR);
        val |= HPRE_QM_PM_FLR;
-       writel(val, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG));
-       writel(PEH_AXUSER_CFG_ENABLE, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG_ENABLE));
+       writel(val, qm->io_base + QM_PEH_AXUSER_CFG);
+       writel(PEH_AXUSER_CFG_ENABLE, qm->io_base + QM_PEH_AXUSER_CFG_ENABLE);
+}
+
+static void hpre_open_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       /* Enable prefetch */
+       val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG);
+       val &= HPRE_PREFETCH_ENABLE;
+       writel(val, qm->io_base + HPRE_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_PREFETCH_CFG,
+                                        val, !(val & HPRE_PREFETCH_DISABLE),
+                                        HPRE_REG_RD_INTVRL_US,
+                                        HPRE_REG_RD_TMOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void hpre_close_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG);
+       val |= HPRE_PREFETCH_DISABLE;
+       writel(val, qm->io_base + HPRE_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_SVA_PREFTCH_DFX,
+                                        val, !(val & HPRE_SVA_DISABLE_READY),
+                                        HPRE_REG_RD_INTVRL_US,
+                                        HPRE_REG_RD_TMOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to close sva prefetch\n");
 }
 
 static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
@@ -342,33 +423,33 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
        u32 val;
        int ret;
 
-       writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_ARUSER_M_CFG_ENABLE));
-       writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_AWUSER_M_CFG_ENABLE));
-       writel_relaxed(HPRE_QM_AXI_CFG_MASK, HPRE_ADDR(qm, QM_AXI_M_CFG));
+       writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_ARUSER_M_CFG_ENABLE);
+       writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_AWUSER_M_CFG_ENABLE);
+       writel_relaxed(HPRE_QM_AXI_CFG_MASK, qm->io_base + QM_AXI_M_CFG);
 
        /* HPRE need more time, we close this interrupt */
-       val = readl_relaxed(HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+       val = readl_relaxed(qm->io_base + HPRE_QM_ABNML_INT_MASK);
        val |= BIT(HPRE_TIMEOUT_ABNML_BIT);
-       writel_relaxed(val, HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+       writel_relaxed(val, qm->io_base + HPRE_QM_ABNML_INT_MASK);
 
        if (qm->ver >= QM_HW_V3)
                writel(HPRE_RSA_ENB | HPRE_ECC_ENB,
-                       HPRE_ADDR(qm, HPRE_TYPES_ENB));
+                       qm->io_base + HPRE_TYPES_ENB);
        else
-               writel(HPRE_RSA_ENB, HPRE_ADDR(qm, HPRE_TYPES_ENB));
-
-       writel(HPRE_QM_VFG_AX_MASK, HPRE_ADDR(qm, HPRE_VFG_AXCACHE));
-       writel(0x0, HPRE_ADDR(qm, HPRE_BD_ENDIAN));
-       writel(0x0, HPRE_ADDR(qm, HPRE_INT_MASK));
-       writel(0x0, HPRE_ADDR(qm, HPRE_POISON_BYPASS));
-       writel(0x0, HPRE_ADDR(qm, HPRE_COMM_CNT_CLR_CE));
-       writel(0x0, HPRE_ADDR(qm, HPRE_ECC_BYPASS));
-
-       writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_ARUSR_CFG));
-       writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_AWUSR_CFG));
-       writel(0x1, HPRE_ADDR(qm, HPRE_RDCHN_INI_CFG));
-       ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, HPRE_RDCHN_INI_ST), val,
-                                        val & BIT(0),
+               writel(HPRE_RSA_ENB, qm->io_base + HPRE_TYPES_ENB);
+
+       writel(HPRE_QM_VFG_AX_MASK, qm->io_base + HPRE_VFG_AXCACHE);
+       writel(0x0, qm->io_base + HPRE_BD_ENDIAN);
+       writel(0x0, qm->io_base + HPRE_INT_MASK);
+       writel(0x0, qm->io_base + HPRE_POISON_BYPASS);
+       writel(0x0, qm->io_base + HPRE_COMM_CNT_CLR_CE);
+       writel(0x0, qm->io_base + HPRE_ECC_BYPASS);
+
+       writel(HPRE_BD_USR_MASK, qm->io_base + HPRE_BD_ARUSR_CFG);
+       writel(HPRE_BD_USR_MASK, qm->io_base + HPRE_BD_AWUSR_CFG);
+       writel(0x1, qm->io_base + HPRE_RDCHN_INI_CFG);
+       ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_RDCHN_INI_ST, val,
+                       val & BIT(0),
                        HPRE_REG_RD_INTVRL_US,
                        HPRE_REG_RD_TMOUT_US);
        if (ret) {
@@ -397,7 +478,7 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
 
 static void hpre_cnt_regs_clear(struct hisi_qm *qm)
 {
-       u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+       u8 clusters_num = hpre_cluster_num(qm);
        unsigned long offset;
        int i;
 
@@ -413,36 +494,49 @@ static void hpre_cnt_regs_clear(struct hisi_qm *qm)
        hisi_qm_debug_regs_clear(qm);
 }
 
-static void hpre_hw_error_disable(struct hisi_qm *qm)
+static void hpre_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
 {
-       u32 val;
+       u32 val1, val2;
+
+       val1 = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+       if (enable) {
+               val1 |= HPRE_AM_OOO_SHUTDOWN_ENABLE;
+               val2 = HPRE_HAC_RAS_NFE_ENABLE;
+       } else {
+               val1 &= ~HPRE_AM_OOO_SHUTDOWN_ENABLE;
+               val2 = 0x0;
+       }
+
+       if (qm->ver > QM_HW_V2)
+               writel(val2, qm->io_base + HPRE_OOO_SHUTDOWN_SEL);
+
+       writel(val1, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+}
 
+static void hpre_hw_error_disable(struct hisi_qm *qm)
+{
        /* disable hpre hw error interrupts */
        writel(HPRE_CORE_INT_DISABLE, qm->io_base + HPRE_INT_MASK);
 
-       /* disable HPRE block master OOO when m-bit error occur */
-       val = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
-       val &= ~HPRE_AM_OOO_SHUTDOWN_ENABLE;
-       writel(val, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+       /* disable HPRE block master OOO when nfe occurs on Kunpeng930 */
+       hpre_master_ooo_ctrl(qm, false);
 }
 
 static void hpre_hw_error_enable(struct hisi_qm *qm)
 {
-       u32 val;
-
        /* clear HPRE hw error source if having */
        writel(HPRE_CORE_INT_DISABLE, qm->io_base + HPRE_HAC_SOURCE_INT);
 
-       /* enable hpre hw error interrupts */
-       writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK);
+       /* configure error type */
        writel(HPRE_HAC_RAS_CE_ENABLE, qm->io_base + HPRE_RAS_CE_ENB);
        writel(HPRE_HAC_RAS_NFE_ENABLE, qm->io_base + HPRE_RAS_NFE_ENB);
        writel(HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_RAS_FE_ENB);
 
-       /* enable HPRE block master OOO when m-bit error occur */
-       val = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
-       val |= HPRE_AM_OOO_SHUTDOWN_ENABLE;
-       writel(val, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+       /* enable HPRE block master OOO when nfe occurs on Kunpeng930 */
+       hpre_master_ooo_ctrl(qm, true);
+
+       /* enable hpre hw error interrupts */
+       writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK);
 }
 
 static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file)
@@ -650,7 +744,7 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm)
 
 static int hpre_cluster_debugfs_init(struct hisi_qm *qm)
 {
-       u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+       u8 clusters_num = hpre_cluster_num(qm);
        struct device *dev = &qm->pdev->dev;
        char buf[HPRE_DBGFS_VAL_MAX_LEN];
        struct debugfs_regset32 *regset;
@@ -788,7 +882,7 @@ static void hpre_log_hw_error(struct hisi_qm *qm, u32 err_sts)
 
 static u32 hpre_get_hw_err_status(struct hisi_qm *qm)
 {
-       return readl(qm->io_base + HPRE_HAC_INT_STATUS);
+       return readl(qm->io_base + HPRE_INT_STATUS);
 }
 
 static void hpre_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
@@ -802,9 +896,9 @@ static void hpre_open_axi_master_ooo(struct hisi_qm *qm)
 
        value = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
        writel(value & ~HPRE_AM_OOO_SHUTDOWN_ENABLE,
-              HPRE_ADDR(qm, HPRE_AM_OOO_SHUTDOWN_ENB));
+              qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
        writel(value | HPRE_AM_OOO_SHUTDOWN_ENABLE,
-              HPRE_ADDR(qm, HPRE_AM_OOO_SHUTDOWN_ENB));
+              qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
 }
 
 static void hpre_err_info_init(struct hisi_qm *qm)
@@ -829,6 +923,8 @@ static const struct hisi_qm_err_ini hpre_err_ini = {
        .clear_dev_hw_err_status = hpre_clear_hw_err_status,
        .log_dev_hw_err         = hpre_log_hw_error,
        .open_axi_master_ooo    = hpre_open_axi_master_ooo,
+       .open_sva_prefetch      = hpre_open_sva_prefetch,
+       .close_sva_prefetch     = hpre_close_sva_prefetch,
        .err_info_init          = hpre_err_info_init,
 };
 
@@ -841,6 +937,8 @@ static int hpre_pf_probe_init(struct hpre *hpre)
        if (ret)
                return ret;
 
+       hpre_open_sva_prefetch(qm);
+
        qm->err_ini = &hpre_err_ini;
        qm->err_ini->err_info_init(qm);
        hisi_qm_dev_err_init(qm);
@@ -850,6 +948,7 @@ static int hpre_pf_probe_init(struct hpre *hpre)
 
 static int hpre_probe_init(struct hpre *hpre)
 {
+       u32 type_rate = HPRE_SHAPER_TYPE_RATE;
        struct hisi_qm *qm = &hpre->qm;
        int ret;
 
@@ -857,6 +956,11 @@ static int hpre_probe_init(struct hpre *hpre)
                ret = hpre_pf_probe_init(hpre);
                if (ret)
                        return ret;
+               /* Enable shaper type 0 */
+               if (qm->ver >= QM_HW_V3) {
+                       type_rate |= QM_SHAPER_ENABLE;
+                       qm->type_rate = type_rate;
+               }
        }
 
        return 0;
index ce439a0..1d67f94 100644 (file)
 #define QM_IRQ_NUM_V1                  1
 #define QM_IRQ_NUM_PF_V2               4
 #define QM_IRQ_NUM_VF_V2               2
+#define QM_IRQ_NUM_VF_V3               3
 
 #define QM_EQ_EVENT_IRQ_VECTOR         0
 #define QM_AEQ_EVENT_IRQ_VECTOR                1
+#define QM_CMD_EVENT_IRQ_VECTOR                2
 #define QM_ABNORMAL_EVENT_IRQ_VECTOR   3
 
 /* mailbox */
@@ -39,6 +41,8 @@
 #define QM_MB_CMD_CQC_BT               0x5
 #define QM_MB_CMD_SQC_VFT_V2           0x6
 #define QM_MB_CMD_STOP_QP              0x8
+#define QM_MB_CMD_SRC                  0xc
+#define QM_MB_CMD_DST                  0xd
 
 #define QM_MB_CMD_SEND_BASE            0x300
 #define QM_MB_EVENT_SHIFT              8
@@ -46,6 +50,9 @@
 #define QM_MB_OP_SHIFT                 14
 #define QM_MB_CMD_DATA_ADDR_L          0x304
 #define QM_MB_CMD_DATA_ADDR_H          0x308
+#define QM_MB_PING_ALL_VFS             0xffff
+#define QM_MB_CMD_DATA_SHIFT           32
+#define QM_MB_CMD_DATA_MASK            GENMASK(31, 0)
 
 /* sqc shift */
 #define QM_SQ_HOP_NUM_SHIFT            0
 #define QM_DOORBELL_SQ_CQ_BASE_V2      0x1000
 #define QM_DOORBELL_EQ_AEQ_BASE_V2     0x2000
 #define QM_QUE_ISO_CFG_V               0x0030
+#define QM_PAGE_SIZE                   0x0034
 #define QM_QUE_ISO_EN                  0x100154
 #define QM_CAPBILITY                   0x100158
 #define QM_QP_NUN_MASK                 GENMASK(10, 0)
 #define QM_RAS_CE_THRESHOLD            0x1000f8
 #define QM_RAS_CE_TIMES_PER_IRQ                1
 #define QM_RAS_MSI_INT_SEL             0x1040f4
+#define QM_OOO_SHUTDOWN_SEL            0x1040f8
 
 #define QM_RESET_WAIT_TIMEOUT          400
 #define QM_PEH_VENDOR_ID               0x1000d8
 #define ACC_VENDOR_ID_VALUE            0x5a5a
 #define QM_PEH_DFX_INFO0               0x1000fc
+#define QM_PEH_DFX_INFO1               0x100100
+#define QM_PEH_DFX_MASK                        (BIT(0) | BIT(2))
+#define QM_PEH_MSI_FINISH_MASK         GENMASK(19, 16)
 #define ACC_PEH_SRIOV_CTRL_VF_MSE_SHIFT        3
 #define ACC_PEH_MSI_DISABLE            GENMASK(31, 0)
 #define ACC_MASTER_GLOBAL_CTRL_SHUTDOWN        0x1
 #define QM_RAS_NFE_MBIT_DISABLE                ~QM_ECC_MBIT
 #define ACC_AM_ROB_ECC_INT_STS         0x300104
 #define ACC_ROB_ECC_ERR_MULTPL         BIT(1)
+#define QM_MSI_CAP_ENABLE              BIT(16)
+
+/* interfunction communication */
+#define QM_IFC_READY_STATUS            0x100128
+#define QM_IFC_C_STS_M                 0x10012C
+#define QM_IFC_INT_SET_P               0x100130
+#define QM_IFC_INT_CFG                 0x100134
+#define QM_IFC_INT_SOURCE_P            0x100138
+#define QM_IFC_INT_SOURCE_V            0x0020
+#define QM_IFC_INT_MASK                        0x0024
+#define QM_IFC_INT_STATUS              0x0028
+#define QM_IFC_INT_SET_V               0x002C
+#define QM_IFC_SEND_ALL_VFS            GENMASK(6, 0)
+#define QM_IFC_INT_SOURCE_CLR          GENMASK(63, 0)
+#define QM_IFC_INT_SOURCE_MASK         BIT(0)
+#define QM_IFC_INT_DISABLE             BIT(0)
+#define QM_IFC_INT_STATUS_MASK         BIT(0)
+#define QM_IFC_INT_SET_MASK            BIT(0)
+#define QM_WAIT_DST_ACK                        10
+#define QM_MAX_PF_WAIT_COUNT           10
+#define QM_MAX_VF_WAIT_COUNT           40
+#define QM_VF_RESET_WAIT_US            20000
+#define QM_VF_RESET_WAIT_CNT           3000
+#define QM_VF_RESET_WAIT_TIMEOUT_US    \
+       (QM_VF_RESET_WAIT_US * QM_VF_RESET_WAIT_CNT)
 
 #define QM_DFX_MB_CNT_VF               0x104010
 #define QM_DFX_DB_CNT_VF               0x104020
 #define QM_DRIVER_REMOVING             0
 #define QM_RST_SCHED                   1
 #define QM_RESETTING                   2
+#define QM_QOS_PARAM_NUM               2
+#define QM_QOS_VAL_NUM                 1
+#define QM_QOS_BDF_PARAM_NUM           4
+#define QM_QOS_MAX_VAL                 1000
+#define QM_QOS_RATE                    100
+#define QM_QOS_EXPAND_RATE             1000
+#define QM_SHAPER_CIR_B_MASK           GENMASK(7, 0)
+#define QM_SHAPER_CIR_U_MASK           GENMASK(10, 8)
+#define QM_SHAPER_CIR_S_MASK           GENMASK(14, 11)
+#define QM_SHAPER_FACTOR_CIR_U_SHIFT   8
+#define QM_SHAPER_FACTOR_CIR_S_SHIFT   11
+#define QM_SHAPER_FACTOR_CBS_B_SHIFT   15
+#define QM_SHAPER_FACTOR_CBS_S_SHIFT   19
+#define QM_SHAPER_CBS_B                        1
+#define QM_SHAPER_CBS_S                        16
+#define QM_SHAPER_VFT_OFFSET           6
+#define WAIT_FOR_QOS_VF                        100
+#define QM_QOS_MIN_ERROR_RATE          5
+#define QM_QOS_TYPICAL_NUM             8
+#define QM_SHAPER_MIN_CBS_S            8
+#define QM_QOS_TICK                    0x300U
+#define QM_QOS_DIVISOR_CLK             0x1f40U
+#define QM_QOS_MAX_CIR_B               200
+#define QM_QOS_MIN_CIR_B               100
+#define QM_QOS_MAX_CIR_U               6
+#define QM_QOS_MAX_CIR_S               11
+#define QM_QOS_VAL_MAX_LEN             32
 
 #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \
        (((hop_num) << QM_CQ_HOP_NUM_SHIFT)     | \
 enum vft_type {
        SQC_VFT = 0,
        CQC_VFT,
+       SHAPER_VFT,
 };
 
 enum acc_err_result {
@@ -253,6 +318,23 @@ enum acc_err_result {
        ACC_ERR_RECOVERED,
 };
 
+enum qm_alg_type {
+       ALG_TYPE_0,
+       ALG_TYPE_1,
+};
+
+enum qm_mb_cmd {
+       QM_PF_FLR_PREPARE = 0x01,
+       QM_PF_SRST_PREPARE,
+       QM_PF_RESET_DONE,
+       QM_VF_PREPARE_DONE,
+       QM_VF_PREPARE_FAIL,
+       QM_VF_START_DONE,
+       QM_VF_START_FAIL,
+       QM_PF_SET_QOS,
+       QM_VF_GET_QOS,
+};
+
 struct qm_cqe {
        __le32 rsvd0;
        __le16 cmd_id;
@@ -351,6 +433,9 @@ struct hisi_qm_hw_ops {
        void (*hw_error_uninit)(struct hisi_qm *qm);
        enum acc_err_result (*hw_error_handle)(struct hisi_qm *qm);
        int (*stop_qp)(struct hisi_qp *qp);
+       int (*set_msi)(struct hisi_qm *qm, bool set);
+       int (*ping_all_vfs)(struct hisi_qm *qm, u64 cmd);
+       int (*ping_pf)(struct hisi_qm *qm, u64 cmd);
 };
 
 struct qm_dfx_item {
@@ -412,6 +497,11 @@ static const char * const qp_s[] = {
        "none", "init", "start", "stop", "close",
 };
 
+static const u32 typical_qos_val[QM_QOS_TYPICAL_NUM] = {100, 250, 500, 1000,
+                                               10000, 25000, 50000, 100000};
+static const u32 typical_qos_cbs_s[QM_QOS_TYPICAL_NUM] = {9, 10, 11, 12, 16,
+                                                        17, 18, 19};
+
 static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new)
 {
        enum qm_state curr = atomic_read(&qm->status.flags);
@@ -491,6 +581,18 @@ static bool qm_qp_avail_state(struct hisi_qm *qm, struct hisi_qp *qp,
        return avail;
 }
 
+static void qm_mb_pre_init(struct qm_mailbox *mailbox, u8 cmd,
+                          u64 base, u16 queue, bool op)
+{
+       mailbox->w0 = cpu_to_le16((cmd) |
+               ((op) ? 0x1 << QM_MB_OP_SHIFT : 0) |
+               (0x1 << QM_MB_BUSY_SHIFT));
+       mailbox->queue_num = cpu_to_le16(queue);
+       mailbox->base_l = cpu_to_le32(lower_32_bits(base));
+       mailbox->base_h = cpu_to_le32(upper_32_bits(base));
+       mailbox->rsvd = 0;
+}
+
 /* return 0 mailbox ready, -ETIMEDOUT hardware timeout */
 static int qm_wait_mb_ready(struct hisi_qm *qm)
 {
@@ -523,44 +625,42 @@ static void qm_mb_write(struct hisi_qm *qm, const void *src)
                     : "memory");
 }
 
-static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue,
-                bool op)
+static int qm_mb_nolock(struct hisi_qm *qm, struct qm_mailbox *mailbox)
 {
-       struct qm_mailbox mailbox;
-       int ret = 0;
-
-       dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n",
-               queue, cmd, (unsigned long long)dma_addr);
-
-       mailbox.w0 = cpu_to_le16(cmd |
-                    (op ? 0x1 << QM_MB_OP_SHIFT : 0) |
-                    (0x1 << QM_MB_BUSY_SHIFT));
-       mailbox.queue_num = cpu_to_le16(queue);
-       mailbox.base_l = cpu_to_le32(lower_32_bits(dma_addr));
-       mailbox.base_h = cpu_to_le32(upper_32_bits(dma_addr));
-       mailbox.rsvd = 0;
-
-       mutex_lock(&qm->mailbox_lock);
-
        if (unlikely(qm_wait_mb_ready(qm))) {
-               ret = -EBUSY;
                dev_err(&qm->pdev->dev, "QM mailbox is busy to start!\n");
-               goto busy_unlock;
+               goto mb_busy;
        }
 
-       qm_mb_write(qm, &mailbox);
+       qm_mb_write(qm, mailbox);
 
        if (unlikely(qm_wait_mb_ready(qm))) {
-               ret = -EBUSY;
                dev_err(&qm->pdev->dev, "QM mailbox operation timeout!\n");
-               goto busy_unlock;
+               goto mb_busy;
        }
 
-busy_unlock:
+       return 0;
+
+mb_busy:
+       atomic64_inc(&qm->debug.dfx.mb_err_cnt);
+       return -EBUSY;
+}
+
+static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue,
+                bool op)
+{
+       struct qm_mailbox mailbox;
+       int ret;
+
+       dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n",
+               queue, cmd, (unsigned long long)dma_addr);
+
+       qm_mb_pre_init(&mailbox, cmd, dma_addr, queue, op);
+
+       mutex_lock(&qm->mailbox_lock);
+       ret = qm_mb_nolock(qm, &mailbox);
        mutex_unlock(&qm->mailbox_lock);
 
-       if (ret)
-               atomic64_inc(&qm->debug.dfx.mb_err_cnt);
        return ret;
 }
 
@@ -626,6 +726,14 @@ static u32 qm_get_irq_num_v2(struct hisi_qm *qm)
                return QM_IRQ_NUM_VF_V2;
 }
 
+static u32 qm_get_irq_num_v3(struct hisi_qm *qm)
+{
+       if (qm->fun_type == QM_HW_PF)
+               return QM_IRQ_NUM_PF_V2;
+
+       return QM_IRQ_NUM_VF_V3;
+}
+
 static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe)
 {
        u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
@@ -730,6 +838,21 @@ static irqreturn_t qm_irq(int irq, void *data)
        return IRQ_NONE;
 }
 
+static irqreturn_t qm_mb_cmd_irq(int irq, void *data)
+{
+       struct hisi_qm *qm = data;
+       u32 val;
+
+       val = readl(qm->io_base + QM_IFC_INT_STATUS);
+       val &= QM_IFC_INT_STATUS_MASK;
+       if (!val)
+               return IRQ_NONE;
+
+       schedule_work(&qm->cmd_process);
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t qm_aeq_irq(int irq, void *data)
 {
        struct hisi_qm *qm = data;
@@ -770,14 +893,16 @@ static void qm_irq_unregister(struct hisi_qm *qm)
 
        free_irq(pci_irq_vector(pdev, QM_EQ_EVENT_IRQ_VECTOR), qm);
 
-       if (qm->ver == QM_HW_V1)
-               return;
+       if (qm->ver > QM_HW_V1) {
+               free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
 
-       free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
+               if (qm->fun_type == QM_HW_PF)
+                       free_irq(pci_irq_vector(pdev,
+                                QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
+       }
 
-       if (qm->fun_type == QM_HW_PF)
-               free_irq(pci_irq_vector(pdev,
-                        QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
+       if (qm->ver > QM_HW_V2)
+               free_irq(pci_irq_vector(pdev, QM_CMD_EVENT_IRQ_VECTOR), qm);
 }
 
 static void qm_init_qp_status(struct hisi_qp *qp)
@@ -790,8 +915,95 @@ static void qm_init_qp_status(struct hisi_qp *qp)
        atomic_set(&qp_status->used, 0);
 }
 
+static void qm_init_prefetch(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       u32 page_type = 0x0;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       switch (PAGE_SIZE) {
+       case SZ_4K:
+               page_type = 0x0;
+               break;
+       case SZ_16K:
+               page_type = 0x1;
+               break;
+       case SZ_64K:
+               page_type = 0x2;
+               break;
+       default:
+               dev_err(dev, "system page size is not support: %lu, default set to 4KB",
+                       PAGE_SIZE);
+       }
+
+       writel(page_type, qm->io_base + QM_PAGE_SIZE);
+}
+
+/*
+ * the formula:
+ * IR = X Mbps if ir = 1 means IR = 100 Mbps, if ir = 10000 means = 10Gbps
+ *
+ *                     IR_b * (2 ^ IR_u) * 8
+ * IR(Mbps) * 10 ^ -3 = -------------------------
+ *                     Tick * (2 ^ IR_s)
+ */
+static u32 acc_shaper_para_calc(u64 cir_b, u64 cir_u, u64 cir_s)
+{
+       return ((cir_b * QM_QOS_DIVISOR_CLK) * (1 << cir_u)) /
+                                       (QM_QOS_TICK * (1 << cir_s));
+}
+
+static u32 acc_shaper_calc_cbs_s(u32 ir)
+{
+       int i;
+
+       if (ir < typical_qos_val[0])
+               return QM_SHAPER_MIN_CBS_S;
+
+       for (i = 1; i < QM_QOS_TYPICAL_NUM; i++) {
+               if (ir >= typical_qos_val[i - 1] && ir < typical_qos_val[i])
+                       return typical_qos_cbs_s[i - 1];
+       }
+
+       return typical_qos_cbs_s[QM_QOS_TYPICAL_NUM - 1];
+}
+
+static int qm_get_shaper_para(u32 ir, struct qm_shaper_factor *factor)
+{
+       u32 cir_b, cir_u, cir_s, ir_calc;
+       u32 error_rate;
+
+       factor->cbs_s = acc_shaper_calc_cbs_s(ir);
+
+       for (cir_b = QM_QOS_MIN_CIR_B; cir_b <= QM_QOS_MAX_CIR_B; cir_b++) {
+               for (cir_u = 0; cir_u <= QM_QOS_MAX_CIR_U; cir_u++) {
+                       for (cir_s = 0; cir_s <= QM_QOS_MAX_CIR_S; cir_s++) {
+                               /** the formula is changed to:
+                                *         IR_b * (2 ^ IR_u) * DIVISOR_CLK
+                                * IR(Mbps) = -------------------------
+                                *             768 * (2 ^ IR_s)
+                                */
+                               ir_calc = acc_shaper_para_calc(cir_b, cir_u,
+                                                              cir_s);
+                               error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
+                               if (error_rate <= QM_QOS_MIN_ERROR_RATE) {
+                                       factor->cir_b = cir_b;
+                                       factor->cir_u = cir_u;
+                                       factor->cir_s = cir_s;
+
+                                       return 0;
+                               }
+                       }
+               }
+       }
+
+       return -EINVAL;
+}
+
 static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
-                           u32 number)
+                           u32 number, struct qm_shaper_factor *factor)
 {
        u64 tmp = 0;
 
@@ -820,6 +1032,15 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
                                tmp = QM_CQC_VFT_VALID;
                        }
                        break;
+               case SHAPER_VFT:
+                       if (qm->ver >= QM_HW_V3) {
+                               tmp = factor->cir_b |
+                               (factor->cir_u << QM_SHAPER_FACTOR_CIR_U_SHIFT) |
+                               (factor->cir_s << QM_SHAPER_FACTOR_CIR_S_SHIFT) |
+                               (QM_SHAPER_CBS_B << QM_SHAPER_FACTOR_CBS_B_SHIFT) |
+                               (factor->cbs_s << QM_SHAPER_FACTOR_CBS_S_SHIFT);
+                       }
+                       break;
                }
        }
 
@@ -830,6 +1051,7 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
 static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
                             u32 fun_num, u32 base, u32 number)
 {
+       struct qm_shaper_factor *factor = &qm->factor[fun_num];
        unsigned int val;
        int ret;
 
@@ -841,9 +1063,12 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
 
        writel(0x0, qm->io_base + QM_VFT_CFG_OP_WR);
        writel(type, qm->io_base + QM_VFT_CFG_TYPE);
+       if (type == SHAPER_VFT)
+               fun_num |= base << QM_SHAPER_VFT_OFFSET;
+
        writel(fun_num, qm->io_base + QM_VFT_CFG);
 
-       qm_vft_data_cfg(qm, type, base, number);
+       qm_vft_data_cfg(qm, type, base, number, factor);
 
        writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
        writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
@@ -853,6 +1078,27 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
                                          POLL_TIMEOUT);
 }
 
+static int qm_shaper_init_vft(struct hisi_qm *qm, u32 fun_num)
+{
+       int ret, i;
+
+       qm->factor[fun_num].func_qos = QM_QOS_MAX_VAL;
+       ret = qm_get_shaper_para(QM_QOS_MAX_VAL * QM_QOS_RATE, &qm->factor[fun_num]);
+       if (ret) {
+               dev_err(&qm->pdev->dev, "failed to calculate shaper parameter!\n");
+               return ret;
+       }
+       writel(qm->type_rate, qm->io_base + QM_SHAPER_CFG);
+       for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
+               /* The base number of queue reuse for different alg type */
+               ret = qm_set_vft_common(qm, SHAPER_VFT, fun_num, i, 1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /* The config should be conducted after qm_dev_mem_reset() */
 static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
                              u32 number)
@@ -865,7 +1111,21 @@ static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
                        return ret;
        }
 
+       /* init default shaper qos val */
+       if (qm->ver >= QM_HW_V3) {
+               ret = qm_shaper_init_vft(qm, fun_num);
+               if (ret)
+                       goto back_sqc_cqc;
+       }
+
        return 0;
+back_sqc_cqc:
+       for (i = SQC_VFT; i <= CQC_VFT; i++) {
+               ret = qm_set_vft_common(qm, i, fun_num, 0, 0);
+               if (ret)
+                       return ret;
+       }
+       return ret;
 }
 
 static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number)
@@ -1570,16 +1830,9 @@ static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer,
        if (count > QM_DBG_WRITE_LEN)
                return -ENOSPC;
 
-       cmd_buf = kzalloc(count + 1, GFP_KERNEL);
-       if (!cmd_buf)
-               return -ENOMEM;
-
-       if (copy_from_user(cmd_buf, buffer, count)) {
-               kfree(cmd_buf);
-               return -EFAULT;
-       }
-
-       cmd_buf[count] = '\0';
+       cmd_buf = memdup_user_nul(buffer, count);
+       if (IS_ERR(cmd_buf))
+               return PTR_ERR(cmd_buf);
 
        cmd_buf_tmp = strchr(cmd_buf, '\n');
        if (cmd_buf_tmp) {
@@ -1623,13 +1876,9 @@ static void qm_hw_error_init_v1(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
        writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
 }
 
-static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+static void qm_hw_error_cfg(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
 {
-       u32 irq_enable = ce | nfe | fe;
-       u32 irq_unmask = ~irq_enable;
-
        qm->error_mask = ce | nfe | fe;
-
        /* clear QM hw residual error source */
        writel(QM_ABNORMAL_INT_SOURCE_CLR,
               qm->io_base + QM_ABNORMAL_INT_SOURCE);
@@ -1639,6 +1888,14 @@ static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
        writel(QM_RAS_CE_TIMES_PER_IRQ, qm->io_base + QM_RAS_CE_THRESHOLD);
        writel(nfe, qm->io_base + QM_RAS_NFE_ENABLE);
        writel(fe, qm->io_base + QM_RAS_FE_ENABLE);
+}
+
+static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+{
+       u32 irq_enable = ce | nfe | fe;
+       u32 irq_unmask = ~irq_enable;
+
+       qm_hw_error_cfg(qm, ce, nfe, fe);
 
        irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK);
        writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK);
@@ -1649,6 +1906,28 @@ static void qm_hw_error_uninit_v2(struct hisi_qm *qm)
        writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
 }
 
+static void qm_hw_error_init_v3(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+{
+       u32 irq_enable = ce | nfe | fe;
+       u32 irq_unmask = ~irq_enable;
+
+       qm_hw_error_cfg(qm, ce, nfe, fe);
+
+       /* enable close master ooo when hardware error happened */
+       writel(nfe & (~QM_DB_RANDOM_INVALID), qm->io_base + QM_OOO_SHUTDOWN_SEL);
+
+       irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK);
+       writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK);
+}
+
+static void qm_hw_error_uninit_v3(struct hisi_qm *qm)
+{
+       writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
+
+       /* disable close master ooo when hardware error happened */
+       writel(0x0, qm->io_base + QM_OOO_SHUTDOWN_SEL);
+}
+
 static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status)
 {
        const struct hisi_qm_hw_error *err;
@@ -1715,104 +1994,464 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm)
        return ACC_ERR_RECOVERED;
 }
 
-static int qm_stop_qp(struct hisi_qp *qp)
+static u32 qm_get_hw_error_status(struct hisi_qm *qm)
 {
-       return qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0);
+       return readl(qm->io_base + QM_ABNORMAL_INT_STATUS);
 }
 
-static const struct hisi_qm_hw_ops qm_hw_ops_v1 = {
-       .qm_db = qm_db_v1,
-       .get_irq_num = qm_get_irq_num_v1,
-       .hw_error_init = qm_hw_error_init_v1,
-};
+static u32 qm_get_dev_err_status(struct hisi_qm *qm)
+{
+       return qm->err_ini->get_dev_hw_err_status(qm);
+}
 
-static const struct hisi_qm_hw_ops qm_hw_ops_v2 = {
-       .get_vft = qm_get_vft_v2,
-       .qm_db = qm_db_v2,
-       .get_irq_num = qm_get_irq_num_v2,
-       .hw_error_init = qm_hw_error_init_v2,
-       .hw_error_uninit = qm_hw_error_uninit_v2,
-       .hw_error_handle = qm_hw_error_handle_v2,
-};
+/* Check if the error causes the master ooo block */
+static int qm_check_dev_error(struct hisi_qm *qm)
+{
+       u32 val, dev_val;
 
-static const struct hisi_qm_hw_ops qm_hw_ops_v3 = {
-       .get_vft = qm_get_vft_v2,
-       .qm_db = qm_db_v2,
-       .get_irq_num = qm_get_irq_num_v2,
-       .hw_error_init = qm_hw_error_init_v2,
-       .hw_error_uninit = qm_hw_error_uninit_v2,
-       .hw_error_handle = qm_hw_error_handle_v2,
-       .stop_qp = qm_stop_qp,
-};
+       if (qm->fun_type == QM_HW_VF)
+               return 0;
 
-static void *qm_get_avail_sqe(struct hisi_qp *qp)
-{
-       struct hisi_qp_status *qp_status = &qp->qp_status;
-       u16 sq_tail = qp_status->sq_tail;
+       val = qm_get_hw_error_status(qm);
+       dev_val = qm_get_dev_err_status(qm);
 
-       if (unlikely(atomic_read(&qp->qp_status.used) == QM_Q_DEPTH - 1))
-               return NULL;
+       if (qm->ver < QM_HW_V3)
+               return (val & QM_ECC_MBIT) ||
+                      (dev_val & qm->err_info.ecc_2bits_mask);
 
-       return qp->sqe + sq_tail * qp->qm->sqe_size;
+       return (val & readl(qm->io_base + QM_OOO_SHUTDOWN_SEL)) ||
+              (dev_val & (~qm->err_info.dev_ce_mask));
 }
 
-static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type)
+static int qm_get_mb_cmd(struct hisi_qm *qm, u64 *msg, u16 fun_num)
 {
-       struct device *dev = &qm->pdev->dev;
-       struct hisi_qp *qp;
-       int qp_id;
-
-       if (!qm_qp_avail_state(qm, NULL, QP_INIT))
-               return ERR_PTR(-EPERM);
+       struct qm_mailbox mailbox;
+       int ret;
 
-       if (qm->qp_in_used == qm->qp_num) {
-               dev_info_ratelimited(dev, "All %u queues of QM are busy!\n",
-                                    qm->qp_num);
-               atomic64_inc(&qm->debug.dfx.create_qp_err_cnt);
-               return ERR_PTR(-EBUSY);
-       }
+       qm_mb_pre_init(&mailbox, QM_MB_CMD_DST, 0, fun_num, 0);
+       mutex_lock(&qm->mailbox_lock);
+       ret = qm_mb_nolock(qm, &mailbox);
+       if (ret)
+               goto err_unlock;
 
-       qp_id = idr_alloc_cyclic(&qm->qp_idr, NULL, 0, qm->qp_num, GFP_ATOMIC);
-       if (qp_id < 0) {
-               dev_info_ratelimited(dev, "All %u queues of QM are busy!\n",
-                                   qm->qp_num);
-               atomic64_inc(&qm->debug.dfx.create_qp_err_cnt);
-               return ERR_PTR(-EBUSY);
-       }
+       *msg = readl(qm->io_base + QM_MB_CMD_DATA_ADDR_L) |
+                 ((u64)readl(qm->io_base + QM_MB_CMD_DATA_ADDR_H) << 32);
 
-       qp = &qm->qp_array[qp_id];
+err_unlock:
+       mutex_unlock(&qm->mailbox_lock);
+       return ret;
+}
 
-       memset(qp->cqe, 0, sizeof(struct qm_cqe) * QM_Q_DEPTH);
+static void qm_clear_cmd_interrupt(struct hisi_qm *qm, u64 vf_mask)
+{
+       u32 val;
 
-       qp->event_cb = NULL;
-       qp->req_cb = NULL;
-       qp->qp_id = qp_id;
-       qp->alg_type = alg_type;
-       qp->is_in_kernel = true;
-       qm->qp_in_used++;
-       atomic_set(&qp->qp_status.flags, QP_INIT);
+       if (qm->fun_type == QM_HW_PF)
+               writeq(vf_mask, qm->io_base + QM_IFC_INT_SOURCE_P);
 
-       return qp;
+       val = readl(qm->io_base + QM_IFC_INT_SOURCE_V);
+       val |= QM_IFC_INT_SOURCE_MASK;
+       writel(val, qm->io_base + QM_IFC_INT_SOURCE_V);
 }
 
-/**
- * hisi_qm_create_qp() - Create a queue pair from qm.
- * @qm: The qm we create a qp from.
- * @alg_type: Accelerator specific algorithm type in sqc.
- *
- * return created qp, -EBUSY if all qps in qm allocated, -ENOMEM if allocating
- * qp memory fails.
- */
-struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type)
+static void qm_handle_vf_msg(struct hisi_qm *qm, u32 vf_id)
 {
-       struct hisi_qp *qp;
+       struct device *dev = &qm->pdev->dev;
+       u32 cmd;
+       u64 msg;
+       int ret;
 
-       down_write(&qm->qps_lock);
-       qp = qm_create_qp_nolock(qm, alg_type);
-       up_write(&qm->qps_lock);
+       ret = qm_get_mb_cmd(qm, &msg, vf_id);
+       if (ret) {
+               dev_err(dev, "failed to get msg from VF(%u)!\n", vf_id);
+               return;
+       }
 
-       return qp;
-}
+       cmd = msg & QM_MB_CMD_DATA_MASK;
+       switch (cmd) {
+       case QM_VF_PREPARE_FAIL:
+               dev_err(dev, "failed to stop VF(%u)!\n", vf_id);
+               break;
+       case QM_VF_START_FAIL:
+               dev_err(dev, "failed to start VF(%u)!\n", vf_id);
+               break;
+       case QM_VF_PREPARE_DONE:
+       case QM_VF_START_DONE:
+               break;
+       default:
+               dev_err(dev, "unsupported cmd %u sent by VF(%u)!\n", cmd, vf_id);
+               break;
+       }
+}
+
+static int qm_wait_vf_prepare_finish(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       u32 vfs_num = qm->vfs_num;
+       int cnt = 0;
+       int ret = 0;
+       u64 val;
+       u32 i;
+
+       if (!qm->vfs_num || qm->ver < QM_HW_V3)
+               return 0;
+
+       while (true) {
+               val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
+               /* All VFs send command to PF, break */
+               if ((val & GENMASK(vfs_num, 1)) == GENMASK(vfs_num, 1))
+                       break;
+
+               if (++cnt > QM_MAX_PF_WAIT_COUNT) {
+                       ret = -EBUSY;
+                       break;
+               }
+
+               msleep(QM_WAIT_DST_ACK);
+       }
+
+       /* PF check VFs msg */
+       for (i = 1; i <= vfs_num; i++) {
+               if (val & BIT(i))
+                       qm_handle_vf_msg(qm, i);
+               else
+                       dev_err(dev, "VF(%u) not ping PF!\n", i);
+       }
+
+       /* PF clear interrupt to ack VFs */
+       qm_clear_cmd_interrupt(qm, val);
+
+       return ret;
+}
+
+static void qm_trigger_vf_interrupt(struct hisi_qm *qm, u32 fun_num)
+{
+       u32 val;
+
+       val = readl(qm->io_base + QM_IFC_INT_CFG);
+       val &= ~QM_IFC_SEND_ALL_VFS;
+       val |= fun_num;
+       writel(val, qm->io_base + QM_IFC_INT_CFG);
+
+       val = readl(qm->io_base + QM_IFC_INT_SET_P);
+       val |= QM_IFC_INT_SET_MASK;
+       writel(val, qm->io_base + QM_IFC_INT_SET_P);
+}
+
+static void qm_trigger_pf_interrupt(struct hisi_qm *qm)
+{
+       u32 val;
+
+       val = readl(qm->io_base + QM_IFC_INT_SET_V);
+       val |= QM_IFC_INT_SET_MASK;
+       writel(val, qm->io_base + QM_IFC_INT_SET_V);
+}
+
+static int qm_ping_single_vf(struct hisi_qm *qm, u64 cmd, u32 fun_num)
+{
+       struct device *dev = &qm->pdev->dev;
+       struct qm_mailbox mailbox;
+       int cnt = 0;
+       u64 val;
+       int ret;
+
+       qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, fun_num, 0);
+       mutex_lock(&qm->mailbox_lock);
+       ret = qm_mb_nolock(qm, &mailbox);
+       if (ret) {
+               dev_err(dev, "failed to send command to vf(%u)!\n", fun_num);
+               goto err_unlock;
+       }
+
+       qm_trigger_vf_interrupt(qm, fun_num);
+       while (true) {
+               msleep(QM_WAIT_DST_ACK);
+               val = readq(qm->io_base + QM_IFC_READY_STATUS);
+               /* if VF respond, PF notifies VF successfully. */
+               if (!(val & BIT(fun_num)))
+                       goto err_unlock;
+
+               if (++cnt > QM_MAX_PF_WAIT_COUNT) {
+                       dev_err(dev, "failed to get response from VF(%u)!\n", fun_num);
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+       }
+
+err_unlock:
+       mutex_unlock(&qm->mailbox_lock);
+       return ret;
+}
+
+static int qm_ping_all_vfs(struct hisi_qm *qm, u64 cmd)
+{
+       struct device *dev = &qm->pdev->dev;
+       u32 vfs_num = qm->vfs_num;
+       struct qm_mailbox mailbox;
+       u64 val = 0;
+       int cnt = 0;
+       int ret;
+       u32 i;
+
+       qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, QM_MB_PING_ALL_VFS, 0);
+       mutex_lock(&qm->mailbox_lock);
+       /* PF sends command to all VFs by mailbox */
+       ret = qm_mb_nolock(qm, &mailbox);
+       if (ret) {
+               dev_err(dev, "failed to send command to VFs!\n");
+               mutex_unlock(&qm->mailbox_lock);
+               return ret;
+       }
+
+       qm_trigger_vf_interrupt(qm, QM_IFC_SEND_ALL_VFS);
+       while (true) {
+               msleep(QM_WAIT_DST_ACK);
+               val = readq(qm->io_base + QM_IFC_READY_STATUS);
+               /* If all VFs acked, PF notifies VFs successfully. */
+               if (!(val & GENMASK(vfs_num, 1))) {
+                       mutex_unlock(&qm->mailbox_lock);
+                       return 0;
+               }
+
+               if (++cnt > QM_MAX_PF_WAIT_COUNT)
+                       break;
+       }
+
+       mutex_unlock(&qm->mailbox_lock);
+
+       /* Check which vf respond timeout. */
+       for (i = 1; i <= vfs_num; i++) {
+               if (val & BIT(i))
+                       dev_err(dev, "failed to get response from VF(%u)!\n", i);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int qm_ping_pf(struct hisi_qm *qm, u64 cmd)
+{
+       struct qm_mailbox mailbox;
+       int cnt = 0;
+       u32 val;
+       int ret;
+
+       qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, 0, 0);
+       mutex_lock(&qm->mailbox_lock);
+       ret = qm_mb_nolock(qm, &mailbox);
+       if (ret) {
+               dev_err(&qm->pdev->dev, "failed to send command to PF!\n");
+               goto unlock;
+       }
+
+       qm_trigger_pf_interrupt(qm);
+       /* Waiting for PF response */
+       while (true) {
+               msleep(QM_WAIT_DST_ACK);
+               val = readl(qm->io_base + QM_IFC_INT_SET_V);
+               if (!(val & QM_IFC_INT_STATUS_MASK))
+                       break;
+
+               if (++cnt > QM_MAX_VF_WAIT_COUNT) {
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+       }
+
+unlock:
+       mutex_unlock(&qm->mailbox_lock);
+       return ret;
+}
+
+static int qm_stop_qp(struct hisi_qp *qp)
+{
+       return qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0);
+}
+
+static int qm_set_msi(struct hisi_qm *qm, bool set)
+{
+       struct pci_dev *pdev = qm->pdev;
+
+       if (set) {
+               pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
+                                      0);
+       } else {
+               pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
+                                      ACC_PEH_MSI_DISABLE);
+               if (qm->err_status.is_qm_ecc_mbit ||
+                   qm->err_status.is_dev_ecc_mbit)
+                       return 0;
+
+               mdelay(1);
+               if (readl(qm->io_base + QM_PEH_DFX_INFO0))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static void qm_wait_msi_finish(struct hisi_qm *qm)
+{
+       struct pci_dev *pdev = qm->pdev;
+       u32 cmd = ~0;
+       int cnt = 0;
+       u32 val;
+       int ret;
+
+       while (true) {
+               pci_read_config_dword(pdev, pdev->msi_cap +
+                                     PCI_MSI_PENDING_64, &cmd);
+               if (!cmd)
+                       break;
+
+               if (++cnt > MAX_WAIT_COUNTS) {
+                       pci_warn(pdev, "failed to empty MSI PENDING!\n");
+                       break;
+               }
+
+               udelay(1);
+       }
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_DFX_INFO0,
+                                        val, !(val & QM_PEH_DFX_MASK),
+                                        POLL_PERIOD, POLL_TIMEOUT);
+       if (ret)
+               pci_warn(pdev, "failed to empty PEH MSI!\n");
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_DFX_INFO1,
+                                        val, !(val & QM_PEH_MSI_FINISH_MASK),
+                                        POLL_PERIOD, POLL_TIMEOUT);
+       if (ret)
+               pci_warn(pdev, "failed to finish MSI operation!\n");
+}
+
+static int qm_set_msi_v3(struct hisi_qm *qm, bool set)
+{
+       struct pci_dev *pdev = qm->pdev;
+       int ret = -ETIMEDOUT;
+       u32 cmd, i;
+
+       pci_read_config_dword(pdev, pdev->msi_cap, &cmd);
+       if (set)
+               cmd |= QM_MSI_CAP_ENABLE;
+       else
+               cmd &= ~QM_MSI_CAP_ENABLE;
+
+       pci_write_config_dword(pdev, pdev->msi_cap, cmd);
+       if (set) {
+               for (i = 0; i < MAX_WAIT_COUNTS; i++) {
+                       pci_read_config_dword(pdev, pdev->msi_cap, &cmd);
+                       if (cmd & QM_MSI_CAP_ENABLE)
+                               return 0;
+
+                       udelay(1);
+               }
+       } else {
+               udelay(WAIT_PERIOD_US_MIN);
+               qm_wait_msi_finish(qm);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static const struct hisi_qm_hw_ops qm_hw_ops_v1 = {
+       .qm_db = qm_db_v1,
+       .get_irq_num = qm_get_irq_num_v1,
+       .hw_error_init = qm_hw_error_init_v1,
+       .set_msi = qm_set_msi,
+};
+
+static const struct hisi_qm_hw_ops qm_hw_ops_v2 = {
+       .get_vft = qm_get_vft_v2,
+       .qm_db = qm_db_v2,
+       .get_irq_num = qm_get_irq_num_v2,
+       .hw_error_init = qm_hw_error_init_v2,
+       .hw_error_uninit = qm_hw_error_uninit_v2,
+       .hw_error_handle = qm_hw_error_handle_v2,
+       .set_msi = qm_set_msi,
+};
+
+static const struct hisi_qm_hw_ops qm_hw_ops_v3 = {
+       .get_vft = qm_get_vft_v2,
+       .qm_db = qm_db_v2,
+       .get_irq_num = qm_get_irq_num_v3,
+       .hw_error_init = qm_hw_error_init_v3,
+       .hw_error_uninit = qm_hw_error_uninit_v3,
+       .hw_error_handle = qm_hw_error_handle_v2,
+       .stop_qp = qm_stop_qp,
+       .set_msi = qm_set_msi_v3,
+       .ping_all_vfs = qm_ping_all_vfs,
+       .ping_pf = qm_ping_pf,
+};
+
+static void *qm_get_avail_sqe(struct hisi_qp *qp)
+{
+       struct hisi_qp_status *qp_status = &qp->qp_status;
+       u16 sq_tail = qp_status->sq_tail;
+
+       if (unlikely(atomic_read(&qp->qp_status.used) == QM_Q_DEPTH - 1))
+               return NULL;
+
+       return qp->sqe + sq_tail * qp->qm->sqe_size;
+}
+
+static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type)
+{
+       struct device *dev = &qm->pdev->dev;
+       struct hisi_qp *qp;
+       int qp_id;
+
+       if (!qm_qp_avail_state(qm, NULL, QP_INIT))
+               return ERR_PTR(-EPERM);
+
+       if (qm->qp_in_used == qm->qp_num) {
+               dev_info_ratelimited(dev, "All %u queues of QM are busy!\n",
+                                    qm->qp_num);
+               atomic64_inc(&qm->debug.dfx.create_qp_err_cnt);
+               return ERR_PTR(-EBUSY);
+       }
+
+       qp_id = idr_alloc_cyclic(&qm->qp_idr, NULL, 0, qm->qp_num, GFP_ATOMIC);
+       if (qp_id < 0) {
+               dev_info_ratelimited(dev, "All %u queues of QM are busy!\n",
+                                   qm->qp_num);
+               atomic64_inc(&qm->debug.dfx.create_qp_err_cnt);
+               return ERR_PTR(-EBUSY);
+       }
+
+       qp = &qm->qp_array[qp_id];
+
+       memset(qp->cqe, 0, sizeof(struct qm_cqe) * QM_Q_DEPTH);
+
+       qp->event_cb = NULL;
+       qp->req_cb = NULL;
+       qp->qp_id = qp_id;
+       qp->alg_type = alg_type;
+       qp->is_in_kernel = true;
+       qm->qp_in_used++;
+       atomic_set(&qp->qp_status.flags, QP_INIT);
+
+       return qp;
+}
+
+/**
+ * hisi_qm_create_qp() - Create a queue pair from qm.
+ * @qm: The qm we create a qp from.
+ * @alg_type: Accelerator specific algorithm type in sqc.
+ *
+ * return created qp, -EBUSY if all qps in qm allocated, -ENOMEM if allocating
+ * qp memory fails.
+ */
+struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type)
+{
+       struct hisi_qp *qp;
+
+       down_write(&qm->qps_lock);
+       qp = qm_create_qp_nolock(qm, alg_type);
+       up_write(&qm->qps_lock);
+
+       return qp;
+}
 EXPORT_SYMBOL_GPL(hisi_qm_create_qp);
 
 /**
@@ -2017,11 +2656,8 @@ static int qm_drain_qp(struct hisi_qp *qp)
        int ret = 0, i = 0;
        void *addr;
 
-       /*
-        * No need to judge if ECC multi-bit error occurs because the
-        * master OOO will be blocked.
-        */
-       if (qm->err_status.is_qm_ecc_mbit || qm->err_status.is_dev_ecc_mbit)
+       /* No need to judge if master OOO is blocked. */
+       if (qm_check_dev_error(qm))
                return 0;
 
        /* Kunpeng930 supports drain qp by device */
@@ -2290,6 +2926,23 @@ static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
        hisi_qm_stop_qp(q->priv);
 }
 
+static int hisi_qm_is_q_updated(struct uacce_queue *q)
+{
+       struct hisi_qp *qp = q->priv;
+       struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
+       int updated = 0;
+
+       while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
+               /* make sure to read data from memory */
+               dma_rmb();
+               qm_cq_head_update(qp);
+               cqe = qp->cqe + qp->qp_status.cq_head;
+               updated = 1;
+       }
+
+       return updated;
+}
+
 static void qm_set_sqctype(struct uacce_queue *q, u16 type)
 {
        struct hisi_qm *qm = q->uacce->priv;
@@ -2335,6 +2988,7 @@ static const struct uacce_ops uacce_qm_ops = {
        .stop_queue = hisi_qm_uacce_stop_queue,
        .mmap = hisi_qm_uacce_mmap,
        .ioctl = hisi_qm_uacce_ioctl,
+       .is_q_updated = hisi_qm_is_q_updated,
 };
 
 static int qm_alloc_uacce(struct hisi_qm *qm)
@@ -2530,62 +3184,6 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id)
        return 0;
 }
 
-static int hisi_qm_memory_init(struct hisi_qm *qm)
-{
-       struct device *dev = &qm->pdev->dev;
-       size_t qp_dma_size, off = 0;
-       int i, ret = 0;
-
-#define QM_INIT_BUF(qm, type, num) do { \
-       (qm)->type = ((qm)->qdma.va + (off)); \
-       (qm)->type##_dma = (qm)->qdma.dma + (off); \
-       off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \
-} while (0)
-
-       idr_init(&qm->qp_idr);
-       qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) +
-                       QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) +
-                       QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
-                       QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num);
-       qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, &qm->qdma.dma,
-                                        GFP_ATOMIC);
-       dev_dbg(dev, "allocate qm dma buf size=%zx)\n", qm->qdma.size);
-       if (!qm->qdma.va)
-               return -ENOMEM;
-
-       QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH);
-       QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH);
-       QM_INIT_BUF(qm, sqc, qm->qp_num);
-       QM_INIT_BUF(qm, cqc, qm->qp_num);
-
-       qm->qp_array = kcalloc(qm->qp_num, sizeof(struct hisi_qp), GFP_KERNEL);
-       if (!qm->qp_array) {
-               ret = -ENOMEM;
-               goto err_alloc_qp_array;
-       }
-
-       /* one more page for device or qp statuses */
-       qp_dma_size = qm->sqe_size * QM_Q_DEPTH +
-                     sizeof(struct qm_cqe) * QM_Q_DEPTH;
-       qp_dma_size = PAGE_ALIGN(qp_dma_size);
-       for (i = 0; i < qm->qp_num; i++) {
-               ret = hisi_qp_memory_init(qm, qp_dma_size, i);
-               if (ret)
-                       goto err_init_qp_mem;
-
-               dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size);
-       }
-
-       return ret;
-
-err_init_qp_mem:
-       hisi_qp_memory_uninit(qm, i);
-err_alloc_qp_array:
-       dma_free_coherent(dev, qm->qdma.size, qm->qdma.va, qm->qdma.dma);
-
-       return ret;
-}
-
 static void hisi_qm_pre_init(struct hisi_qm *qm)
 {
        struct pci_dev *pdev = qm->pdev;
@@ -2604,6 +3202,34 @@ static void hisi_qm_pre_init(struct hisi_qm *qm)
        qm->misc_ctl = false;
 }
 
+static void qm_cmd_uninit(struct hisi_qm *qm)
+{
+       u32 val;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       val = readl(qm->io_base + QM_IFC_INT_MASK);
+       val |= QM_IFC_INT_DISABLE;
+       writel(val, qm->io_base + QM_IFC_INT_MASK);
+}
+
+static void qm_cmd_init(struct hisi_qm *qm)
+{
+       u32 val;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       /* Clear communication interrupt source */
+       qm_clear_cmd_interrupt(qm, QM_IFC_INT_SOURCE_CLR);
+
+       /* Enable pf to vf communication reg. */
+       val = readl(qm->io_base + QM_IFC_INT_MASK);
+       val &= ~QM_IFC_INT_DISABLE;
+       writel(val, qm->io_base + QM_IFC_INT_MASK);
+}
+
 static void qm_put_pci_res(struct hisi_qm *qm)
 {
        struct pci_dev *pdev = qm->pdev;
@@ -2635,6 +3261,8 @@ void hisi_qm_uninit(struct hisi_qm *qm)
        struct pci_dev *pdev = qm->pdev;
        struct device *dev = &pdev->dev;
 
+       qm_cmd_uninit(qm);
+       kfree(qm->factor);
        down_write(&qm->qps_lock);
 
        if (!qm_avail_state(qm, QM_CLOSE)) {
@@ -2826,6 +3454,8 @@ static int __hisi_qm_start(struct hisi_qm *qm)
        if (ret)
                return ret;
 
+       qm_init_prefetch(qm);
+
        writel(0x0, qm->io_base + QM_VF_EQ_INT_MASK);
        writel(0x0, qm->io_base + QM_VF_AEQ_INT_MASK);
 
@@ -3002,110 +3632,37 @@ static ssize_t qm_status_read(struct file *filp, char __user *buffer,
        char buf[QM_DBG_READ_LEN];
        int val, len;
 
-       val = atomic_read(&qm->status.flags);
-       len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", qm_s[val]);
-
-       return simple_read_from_buffer(buffer, count, pos, buf, len);
-}
-
-static const struct file_operations qm_status_fops = {
-       .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = qm_status_read,
-};
-
-static int qm_debugfs_atomic64_set(void *data, u64 val)
-{
-       if (val)
-               return -EINVAL;
-
-       atomic64_set((atomic64_t *)data, 0);
-
-       return 0;
-}
-
-static int qm_debugfs_atomic64_get(void *data, u64 *val)
-{
-       *val = atomic64_read((atomic64_t *)data);
-
-       return 0;
-}
-
-DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
-                        qm_debugfs_atomic64_set, "%llu\n");
-
-/**
- * hisi_qm_debug_init() - Initialize qm related debugfs files.
- * @qm: The qm for which we want to add debugfs files.
- *
- * Create qm related debugfs files.
- */
-void hisi_qm_debug_init(struct hisi_qm *qm)
-{
-       struct qm_dfx *dfx = &qm->debug.dfx;
-       struct dentry *qm_d;
-       void *data;
-       int i;
-
-       qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
-       qm->debug.qm_d = qm_d;
-
-       /* only show this in PF */
-       if (qm->fun_type == QM_HW_PF) {
-               qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
-               for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
-                       qm_create_debugfs_file(qm, qm_d, i);
-       }
-
-       debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
-
-       debugfs_create_file("cmd", 0444, qm->debug.qm_d, qm, &qm_cmd_fops);
-
-       debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
-                       &qm_status_fops);
-       for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
-               data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
-               debugfs_create_file(qm_dfx_files[i].name,
-                       0644,
-                       qm_d,
-                       data,
-                       &qm_atomic64_ops);
-       }
+       val = atomic_read(&qm->status.flags);
+       len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", qm_s[val]);
+
+       return simple_read_from_buffer(buffer, count, pos, buf, len);
 }
-EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
 
-/**
- * hisi_qm_debug_regs_clear() - clear qm debug related registers.
- * @qm: The qm for which we want to clear its debug registers.
- */
-void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
-{
-       struct qm_dfx_registers *regs;
-       int i;
+static const struct file_operations qm_status_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = qm_status_read,
+};
 
-       /* clear current_qm */
-       writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
-       writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+static int qm_debugfs_atomic64_set(void *data, u64 val)
+{
+       if (val)
+               return -EINVAL;
 
-       /* clear current_q */
-       writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
-       writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
+       atomic64_set((atomic64_t *)data, 0);
 
-       /*
-        * these registers are reading and clearing, so clear them after
-        * reading them.
-        */
-       writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
+       return 0;
+}
 
-       regs = qm_dfx_regs;
-       for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
-               readl(qm->io_base + regs->reg_offset);
-               regs++;
-       }
+static int qm_debugfs_atomic64_get(void *data, u64 *val)
+{
+       *val = atomic64_read((atomic64_t *)data);
 
-       writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
+
+DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
+                        qm_debugfs_atomic64_set, "%llu\n");
 
 static void qm_hw_error_init(struct hisi_qm *qm)
 {
@@ -3260,107 +3817,461 @@ static int hisi_qm_sort_devices(int node, struct list_head *head,
 int hisi_qm_alloc_qps_node(struct hisi_qm_list *qm_list, int qp_num,
                           u8 alg_type, int node, struct hisi_qp **qps)
 {
-       struct hisi_qm_resource *tmp;
-       int ret = -ENODEV;
-       LIST_HEAD(head);
-       int i;
+       struct hisi_qm_resource *tmp;
+       int ret = -ENODEV;
+       LIST_HEAD(head);
+       int i;
+
+       if (!qps || !qm_list || qp_num <= 0)
+               return -EINVAL;
+
+       mutex_lock(&qm_list->lock);
+       if (hisi_qm_sort_devices(node, &head, qm_list)) {
+               mutex_unlock(&qm_list->lock);
+               goto err;
+       }
+
+       list_for_each_entry(tmp, &head, list) {
+               for (i = 0; i < qp_num; i++) {
+                       qps[i] = hisi_qm_create_qp(tmp->qm, alg_type);
+                       if (IS_ERR(qps[i])) {
+                               hisi_qm_free_qps(qps, i);
+                               break;
+                       }
+               }
+
+               if (i == qp_num) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       mutex_unlock(&qm_list->lock);
+       if (ret)
+               pr_info("Failed to create qps, node[%d], alg[%u], qp[%d]!\n",
+                       node, alg_type, qp_num);
+
+err:
+       free_list(&head);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_alloc_qps_node);
+
+static int qm_vf_q_assign(struct hisi_qm *qm, u32 num_vfs)
+{
+       u32 remain_q_num, vfs_q_num, act_q_num, q_num, i, j;
+       u32 max_qp_num = qm->max_qp_num;
+       u32 q_base = qm->qp_num;
+       int ret;
+
+       if (!num_vfs)
+               return -EINVAL;
+
+       vfs_q_num = qm->ctrl_qp_num - qm->qp_num;
+
+       /* If vfs_q_num is less than num_vfs, return error. */
+       if (vfs_q_num < num_vfs)
+               return -EINVAL;
+
+       q_num = vfs_q_num / num_vfs;
+       remain_q_num = vfs_q_num % num_vfs;
+
+       for (i = num_vfs; i > 0; i--) {
+               /*
+                * if q_num + remain_q_num > max_qp_num in last vf, divide the
+                * remaining queues equally.
+                */
+               if (i == num_vfs && q_num + remain_q_num <= max_qp_num) {
+                       act_q_num = q_num + remain_q_num;
+                       remain_q_num = 0;
+               } else if (remain_q_num > 0) {
+                       act_q_num = q_num + 1;
+                       remain_q_num--;
+               } else {
+                       act_q_num = q_num;
+               }
+
+               act_q_num = min_t(int, act_q_num, max_qp_num);
+               ret = hisi_qm_set_vft(qm, i, q_base, act_q_num);
+               if (ret) {
+                       for (j = num_vfs; j > i; j--)
+                               hisi_qm_set_vft(qm, j, 0, 0);
+                       return ret;
+               }
+               q_base += act_q_num;
+       }
+
+       return 0;
+}
+
+static int qm_clear_vft_config(struct hisi_qm *qm)
+{
+       int ret;
+       u32 i;
+
+       for (i = 1; i <= qm->vfs_num; i++) {
+               ret = hisi_qm_set_vft(qm, i, 0, 0);
+               if (ret)
+                       return ret;
+       }
+       qm->vfs_num = 0;
+
+       return 0;
+}
+
+static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos)
+{
+       struct device *dev = &qm->pdev->dev;
+       u32 ir = qos * QM_QOS_RATE;
+       int ret, total_vfs, i;
+
+       total_vfs = pci_sriov_get_totalvfs(qm->pdev);
+       if (fun_index > total_vfs)
+               return -EINVAL;
+
+       qm->factor[fun_index].func_qos = qos;
+
+       ret = qm_get_shaper_para(ir, &qm->factor[fun_index]);
+       if (ret) {
+               dev_err(dev, "failed to calculate shaper parameter!\n");
+               return -EINVAL;
+       }
+
+       for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
+               /* The base number of queue reuse for different alg type */
+               ret = qm_set_vft_common(qm, SHAPER_VFT, fun_index, i, 1);
+               if (ret) {
+                       dev_err(dev, "type: %d, failed to set shaper vft!\n", i);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static u32 qm_get_shaper_vft_qos(struct hisi_qm *qm, u32 fun_index)
+{
+       u64 cir_u = 0, cir_b = 0, cir_s = 0;
+       u64 shaper_vft, ir_calc, ir;
+       unsigned int val;
+       u32 error_rate;
+       int ret;
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+                                        val & BIT(0), POLL_PERIOD,
+                                        POLL_TIMEOUT);
+       if (ret)
+               return 0;
+
+       writel(0x1, qm->io_base + QM_VFT_CFG_OP_WR);
+       writel(SHAPER_VFT, qm->io_base + QM_VFT_CFG_TYPE);
+       writel(fun_index, qm->io_base + QM_VFT_CFG);
+
+       writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
+       writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+                                        val & BIT(0), POLL_PERIOD,
+                                        POLL_TIMEOUT);
+       if (ret)
+               return 0;
+
+       shaper_vft = readl(qm->io_base + QM_VFT_CFG_DATA_L) |
+                 ((u64)readl(qm->io_base + QM_VFT_CFG_DATA_H) << 32);
+
+       cir_b = shaper_vft & QM_SHAPER_CIR_B_MASK;
+       cir_u = shaper_vft & QM_SHAPER_CIR_U_MASK;
+       cir_u = cir_u >> QM_SHAPER_FACTOR_CIR_U_SHIFT;
+
+       cir_s = shaper_vft & QM_SHAPER_CIR_S_MASK;
+       cir_s = cir_s >> QM_SHAPER_FACTOR_CIR_S_SHIFT;
+
+       ir_calc = acc_shaper_para_calc(cir_b, cir_u, cir_s);
+
+       ir = qm->factor[fun_index].func_qos * QM_QOS_RATE;
+
+       error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
+       if (error_rate > QM_QOS_MIN_ERROR_RATE) {
+               pci_err(qm->pdev, "error_rate: %u, get function qos is error!\n", error_rate);
+               return 0;
+       }
+
+       return ir;
+}
+
+static void qm_vf_get_qos(struct hisi_qm *qm, u32 fun_num)
+{
+       struct device *dev = &qm->pdev->dev;
+       u64 mb_cmd;
+       u32 qos;
+       int ret;
+
+       qos = qm_get_shaper_vft_qos(qm, fun_num);
+       if (!qos) {
+               dev_err(dev, "function(%u) failed to get qos by PF!\n", fun_num);
+               return;
+       }
+
+       mb_cmd = QM_PF_SET_QOS | (u64)qos << QM_MB_CMD_DATA_SHIFT;
+       ret = qm_ping_single_vf(qm, mb_cmd, fun_num);
+       if (ret)
+               dev_err(dev, "failed to send cmd to VF(%u)!\n", fun_num);
+}
+
+static int qm_vf_read_qos(struct hisi_qm *qm)
+{
+       int cnt = 0;
+       int ret;
+
+       /* reset mailbox qos val */
+       qm->mb_qos = 0;
+
+       /* vf ping pf to get function qos */
+       if (qm->ops->ping_pf) {
+               ret = qm->ops->ping_pf(qm, QM_VF_GET_QOS);
+               if (ret) {
+                       pci_err(qm->pdev, "failed to send cmd to PF to get qos!\n");
+                       return ret;
+               }
+       }
+
+       while (true) {
+               msleep(QM_WAIT_DST_ACK);
+               if (qm->mb_qos)
+                       break;
+
+               if (++cnt > QM_MAX_VF_WAIT_COUNT) {
+                       pci_err(qm->pdev, "PF ping VF timeout!\n");
+                       return  -ETIMEDOUT;
+               }
+       }
+
+       return ret;
+}
+
+static ssize_t qm_algqos_read(struct file *filp, char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       struct hisi_qm *qm = filp->private_data;
+       char tbuf[QM_DBG_READ_LEN];
+       u32 qos_val, ir;
+       int ret;
+
+       /* Mailbox and reset cannot be operated at the same time */
+       if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
+               pci_err(qm->pdev, "dev resetting, read alg qos failed!\n");
+               return  -EAGAIN;
+       }
+
+       if (qm->fun_type == QM_HW_PF) {
+               ir = qm_get_shaper_vft_qos(qm, 0);
+       } else {
+               ret = qm_vf_read_qos(qm);
+               if (ret)
+                       goto err_get_status;
+               ir = qm->mb_qos;
+       }
+
+       qos_val = ir / QM_QOS_RATE;
+       ret = scnprintf(tbuf, QM_DBG_READ_LEN, "%u\n", qos_val);
+
+       ret =  simple_read_from_buffer(buf, count, pos, tbuf, ret);
+
+err_get_status:
+       clear_bit(QM_RESETTING, &qm->misc_ctl);
+       return ret;
+}
+
+static ssize_t qm_qos_value_init(const char *buf, unsigned long *val)
+{
+       int buflen = strlen(buf);
+       int ret, i;
+
+       for (i = 0; i < buflen; i++) {
+               if (!isdigit(buf[i]))
+                       return -EINVAL;
+       }
+
+       ret = sscanf(buf, "%ld", val);
+       if (ret != QM_QOS_VAL_NUM)
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t qm_algqos_write(struct file *filp, const char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       struct hisi_qm *qm = filp->private_data;
+       char tbuf[QM_DBG_READ_LEN];
+       int tmp1, bus, device, function;
+       char tbuf_bdf[QM_DBG_READ_LEN] = {0};
+       char val_buf[QM_QOS_VAL_MAX_LEN] = {0};
+       unsigned int fun_index;
+       unsigned long val = 0;
+       int len, ret;
 
-       if (!qps || !qm_list || qp_num <= 0)
+       if (qm->fun_type == QM_HW_VF)
                return -EINVAL;
 
-       mutex_lock(&qm_list->lock);
-       if (hisi_qm_sort_devices(node, &head, qm_list)) {
-               mutex_unlock(&qm_list->lock);
-               goto err;
+       /* Mailbox and reset cannot be operated at the same time */
+       if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
+               pci_err(qm->pdev, "dev resetting, write alg qos failed!\n");
+               return -EAGAIN;
        }
 
-       list_for_each_entry(tmp, &head, list) {
-               for (i = 0; i < qp_num; i++) {
-                       qps[i] = hisi_qm_create_qp(tmp->qm, alg_type);
-                       if (IS_ERR(qps[i])) {
-                               hisi_qm_free_qps(qps, i);
-                               break;
-                       }
-               }
+       if (*pos != 0) {
+               ret = 0;
+               goto err_get_status;
+       }
 
-               if (i == qp_num) {
-                       ret = 0;
-                       break;
-               }
+       if (count >= QM_DBG_READ_LEN) {
+               ret = -ENOSPC;
+               goto err_get_status;
        }
 
-       mutex_unlock(&qm_list->lock);
-       if (ret)
-               pr_info("Failed to create qps, node[%d], alg[%u], qp[%d]!\n",
-                       node, alg_type, qp_num);
+       len = simple_write_to_buffer(tbuf, QM_DBG_READ_LEN - 1, pos, buf, count);
+       if (len < 0) {
+               ret = len;
+               goto err_get_status;
+       }
 
-err:
-       free_list(&head);
+       tbuf[len] = '\0';
+       ret = sscanf(tbuf, "%s %s", tbuf_bdf, val_buf);
+       if (ret != QM_QOS_PARAM_NUM) {
+               ret = -EINVAL;
+               goto err_get_status;
+       }
+
+       ret = qm_qos_value_init(val_buf, &val);
+       if (val == 0 || val > QM_QOS_MAX_VAL || ret) {
+               pci_err(qm->pdev, "input qos value is error, please set 1~1000!\n");
+               ret = -EINVAL;
+               goto err_get_status;
+       }
+
+       ret = sscanf(tbuf_bdf, "%d:%x:%d.%d", &tmp1, &bus, &device, &function);
+       if (ret != QM_QOS_BDF_PARAM_NUM) {
+               pci_err(qm->pdev, "input pci bdf value is error!\n");
+               ret = -EINVAL;
+               goto err_get_status;
+       }
+
+       fun_index = device * 8 + function;
+
+       ret = qm_func_shaper_enable(qm, fun_index, val);
+       if (ret) {
+               pci_err(qm->pdev, "failed to enable function shaper!\n");
+               ret = -EINVAL;
+               goto err_get_status;
+       }
+
+       ret =  count;
+
+err_get_status:
+       clear_bit(QM_RESETTING, &qm->misc_ctl);
        return ret;
 }
-EXPORT_SYMBOL_GPL(hisi_qm_alloc_qps_node);
 
-static int qm_vf_q_assign(struct hisi_qm *qm, u32 num_vfs)
+static const struct file_operations qm_algqos_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = qm_algqos_read,
+       .write = qm_algqos_write,
+};
+
+/**
+ * hisi_qm_set_algqos_init() - Initialize function qos debugfs files.
+ * @qm: The qm for which we want to add debugfs files.
+ *
+ * Create function qos debugfs files.
+ */
+static void hisi_qm_set_algqos_init(struct hisi_qm *qm)
 {
-       u32 remain_q_num, vfs_q_num, act_q_num, q_num, i, j;
-       u32 max_qp_num = qm->max_qp_num;
-       u32 q_base = qm->qp_num;
-       int ret;
+       if (qm->fun_type == QM_HW_PF)
+               debugfs_create_file("alg_qos", 0644, qm->debug.debug_root,
+                                   qm, &qm_algqos_fops);
+       else
+               debugfs_create_file("alg_qos", 0444, qm->debug.debug_root,
+                                   qm, &qm_algqos_fops);
+}
 
-       if (!num_vfs)
-               return -EINVAL;
+/**
+ * hisi_qm_debug_init() - Initialize qm related debugfs files.
+ * @qm: The qm for which we want to add debugfs files.
+ *
+ * Create qm related debugfs files.
+ */
+void hisi_qm_debug_init(struct hisi_qm *qm)
+{
+       struct qm_dfx *dfx = &qm->debug.dfx;
+       struct dentry *qm_d;
+       void *data;
+       int i;
 
-       vfs_q_num = qm->ctrl_qp_num - qm->qp_num;
+       qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
+       qm->debug.qm_d = qm_d;
 
-       /* If vfs_q_num is less than num_vfs, return error. */
-       if (vfs_q_num < num_vfs)
-               return -EINVAL;
+       /* only show this in PF */
+       if (qm->fun_type == QM_HW_PF) {
+               qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
+               for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
+                       qm_create_debugfs_file(qm, qm->debug.qm_d, i);
+       }
 
-       q_num = vfs_q_num / num_vfs;
-       remain_q_num = vfs_q_num % num_vfs;
+       debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
 
-       for (i = num_vfs; i > 0; i--) {
-               /*
-                * if q_num + remain_q_num > max_qp_num in last vf, divide the
-                * remaining queues equally.
-                */
-               if (i == num_vfs && q_num + remain_q_num <= max_qp_num) {
-                       act_q_num = q_num + remain_q_num;
-                       remain_q_num = 0;
-               } else if (remain_q_num > 0) {
-                       act_q_num = q_num + 1;
-                       remain_q_num--;
-               } else {
-                       act_q_num = q_num;
-               }
+       debugfs_create_file("cmd", 0600, qm->debug.qm_d, qm, &qm_cmd_fops);
 
-               act_q_num = min_t(int, act_q_num, max_qp_num);
-               ret = hisi_qm_set_vft(qm, i, q_base, act_q_num);
-               if (ret) {
-                       for (j = num_vfs; j > i; j--)
-                               hisi_qm_set_vft(qm, j, 0, 0);
-                       return ret;
-               }
-               q_base += act_q_num;
+       debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
+                       &qm_status_fops);
+       for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
+               data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
+               debugfs_create_file(qm_dfx_files[i].name,
+                       0644,
+                       qm_d,
+                       data,
+                       &qm_atomic64_ops);
        }
 
-       return 0;
+       if (qm->ver >= QM_HW_V3)
+               hisi_qm_set_algqos_init(qm);
 }
+EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
 
-static int qm_clear_vft_config(struct hisi_qm *qm)
+/**
+ * hisi_qm_debug_regs_clear() - clear qm debug related registers.
+ * @qm: The qm for which we want to clear its debug registers.
+ */
+void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
 {
-       int ret;
-       u32 i;
+       struct qm_dfx_registers *regs;
+       int i;
 
-       for (i = 1; i <= qm->vfs_num; i++) {
-               ret = hisi_qm_set_vft(qm, i, 0, 0);
-               if (ret)
-                       return ret;
+       /* clear current_qm */
+       writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
+       writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+
+       /* clear current_q */
+       writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
+       writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
+
+       /*
+        * these registers are reading and clearing, so clear them after
+        * reading them.
+        */
+       writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
+
+       regs = qm_dfx_regs;
+       for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
+               readl(qm->io_base + regs->reg_offset);
+               regs++;
        }
-       qm->vfs_num = 0;
 
-       return 0;
+       /* clear clear_enable */
+       writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
 }
+EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
 
 /**
  * hisi_qm_sriov_enable() - enable virtual functions
@@ -3416,6 +4327,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_enable);
 int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
 {
        struct hisi_qm *qm = pci_get_drvdata(pdev);
+       int total_vfs = pci_sriov_get_totalvfs(qm->pdev);
 
        if (pci_vfs_assigned(pdev)) {
                pci_err(pdev, "Failed to disable VFs as VFs are assigned!\n");
@@ -3429,6 +4341,9 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
        }
 
        pci_disable_sriov(pdev);
+       /* clear vf function shaper configure array */
+       memset(qm->factor + 1, 0, sizeof(struct qm_shaper_factor) * total_vfs);
+
        return qm_clear_vft_config(qm);
 }
 EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable);
@@ -3527,17 +4442,15 @@ pci_ers_result_t hisi_qm_dev_err_detected(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL_GPL(hisi_qm_dev_err_detected);
 
-static u32 qm_get_hw_error_status(struct hisi_qm *qm)
-{
-       return readl(qm->io_base + QM_ABNORMAL_INT_STATUS);
-}
-
 static int qm_check_req_recv(struct hisi_qm *qm)
 {
        struct pci_dev *pdev = qm->pdev;
        int ret;
        u32 val;
 
+       if (qm->ver >= QM_HW_V3)
+               return 0;
+
        writel(ACC_VENDOR_ID_VALUE, qm->io_base + QM_PEH_VENDOR_ID);
        ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_VENDOR_ID, val,
                                         (val == ACC_VENDOR_ID_VALUE),
@@ -3608,28 +4521,6 @@ static int qm_set_vf_mse(struct hisi_qm *qm, bool set)
        return -ETIMEDOUT;
 }
 
-static int qm_set_msi(struct hisi_qm *qm, bool set)
-{
-       struct pci_dev *pdev = qm->pdev;
-
-       if (set) {
-               pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
-                                      0);
-       } else {
-               pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
-                                      ACC_PEH_MSI_DISABLE);
-               if (qm->err_status.is_qm_ecc_mbit ||
-                   qm->err_status.is_dev_ecc_mbit)
-                       return 0;
-
-               mdelay(1);
-               if (readl(qm->io_base + QM_PEH_DFX_INFO0))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
 static int qm_vf_reset_prepare(struct hisi_qm *qm,
                               enum qm_stop_reason stop_reason)
 {
@@ -3660,14 +4551,35 @@ stop_fail:
        return ret;
 }
 
-static int qm_reset_prepare_ready(struct hisi_qm *qm)
+static int qm_try_stop_vfs(struct hisi_qm *qm, u64 cmd,
+                          enum qm_stop_reason stop_reason)
 {
        struct pci_dev *pdev = qm->pdev;
-       struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+       int ret;
+
+       if (!qm->vfs_num)
+               return 0;
+
+       /* Kunpeng930 supports to notify VFs to stop before PF reset */
+       if (qm->ops->ping_all_vfs) {
+               ret = qm->ops->ping_all_vfs(qm, cmd);
+               if (ret)
+                       pci_err(pdev, "failed to send cmd to all VFs before PF reset!\n");
+       } else {
+               ret = qm_vf_reset_prepare(qm, stop_reason);
+               if (ret)
+                       pci_err(pdev, "failed to prepare reset, ret = %d.\n", ret);
+       }
+
+       return ret;
+}
+
+static int qm_wait_reset_finish(struct hisi_qm *qm)
+{
        int delay = 0;
 
        /* All reset requests need to be queued for processing */
-       while (test_and_set_bit(QM_RESETTING, &pf_qm->misc_ctl)) {
+       while (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
                msleep(++delay);
                if (delay > QM_RESET_WAIT_TIMEOUT)
                        return -EBUSY;
@@ -3676,6 +4588,32 @@ static int qm_reset_prepare_ready(struct hisi_qm *qm)
        return 0;
 }
 
+static int qm_reset_prepare_ready(struct hisi_qm *qm)
+{
+       struct pci_dev *pdev = qm->pdev;
+       struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+
+       /*
+        * PF and VF on host doesnot support resetting at the
+        * same time on Kunpeng920.
+        */
+       if (qm->ver < QM_HW_V3)
+               return qm_wait_reset_finish(pf_qm);
+
+       return qm_wait_reset_finish(qm);
+}
+
+static void qm_reset_bit_clear(struct hisi_qm *qm)
+{
+       struct pci_dev *pdev = qm->pdev;
+       struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+
+       if (qm->ver < QM_HW_V3)
+               clear_bit(QM_RESETTING, &pf_qm->misc_ctl);
+
+       clear_bit(QM_RESETTING, &qm->misc_ctl);
+}
+
 static int qm_controller_reset_prepare(struct hisi_qm *qm)
 {
        struct pci_dev *pdev = qm->pdev;
@@ -3687,22 +4625,25 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
                return ret;
        }
 
-       if (qm->vfs_num) {
-               ret = qm_vf_reset_prepare(qm, QM_SOFT_RESET);
-               if (ret) {
-                       pci_err(pdev, "Fails to stop VFs!\n");
-                       clear_bit(QM_RESETTING, &qm->misc_ctl);
-                       return ret;
-               }
-       }
+       /* PF obtains the information of VF by querying the register. */
+       qm_cmd_uninit(qm);
+
+       /* Whether VFs stop successfully, soft reset will continue. */
+       ret = qm_try_stop_vfs(qm, QM_PF_SRST_PREPARE, QM_SOFT_RESET);
+       if (ret)
+               pci_err(pdev, "failed to stop vfs by pf in soft reset.\n");
 
        ret = hisi_qm_stop(qm, QM_SOFT_RESET);
        if (ret) {
                pci_err(pdev, "Fails to stop QM!\n");
-               clear_bit(QM_RESETTING, &qm->misc_ctl);
+               qm_reset_bit_clear(qm);
                return ret;
        }
 
+       ret = qm_wait_vf_prepare_finish(qm);
+       if (ret)
+               pci_err(pdev, "failed to stop by vfs in soft reset!\n");
+
        clear_bit(QM_RST_SCHED, &qm->misc_ctl);
 
        return 0;
@@ -3712,6 +4653,10 @@ static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm)
 {
        u32 nfe_enb = 0;
 
+       /* Kunpeng930 hardware automatically close master ooo when NFE occurs */
+       if (qm->ver >= QM_HW_V3)
+               return;
+
        if (!qm->err_status.is_dev_ecc_mbit &&
            qm->err_status.is_qm_ecc_mbit &&
            qm->err_ini->close_axi_master_ooo) {
@@ -3748,7 +4693,7 @@ static int qm_soft_reset(struct hisi_qm *qm)
                }
        }
 
-       ret = qm_set_msi(qm, false);
+       ret = qm->ops->set_msi(qm, false);
        if (ret) {
                pci_err(pdev, "Fails to disable PEH MSI bit.\n");
                return ret;
@@ -3770,6 +4715,9 @@ static int qm_soft_reset(struct hisi_qm *qm)
                return ret;
        }
 
+       if (qm->err_ini->close_sva_prefetch)
+               qm->err_ini->close_sva_prefetch(qm);
+
        ret = qm_set_pf_mse(qm, false);
        if (ret) {
                pci_err(pdev, "Fails to disable pf MSE bit.\n");
@@ -3830,9 +4778,32 @@ restart_fail:
        return ret;
 }
 
-static u32 qm_get_dev_err_status(struct hisi_qm *qm)
+static int qm_try_start_vfs(struct hisi_qm *qm, enum qm_mb_cmd cmd)
 {
-       return qm->err_ini->get_dev_hw_err_status(qm);
+       struct pci_dev *pdev = qm->pdev;
+       int ret;
+
+       if (!qm->vfs_num)
+               return 0;
+
+       ret = qm_vf_q_assign(qm, qm->vfs_num);
+       if (ret) {
+               pci_err(pdev, "failed to assign VFs, ret = %d.\n", ret);
+               return ret;
+       }
+
+       /* Kunpeng930 supports to notify VFs to start after PF reset. */
+       if (qm->ops->ping_all_vfs) {
+               ret = qm->ops->ping_all_vfs(qm, cmd);
+               if (ret)
+                       pci_warn(pdev, "failed to send cmd to all VFs after PF reset!\n");
+       } else {
+               ret = qm_vf_reset_done(qm);
+               if (ret)
+                       pci_warn(pdev, "failed to start vfs, ret = %d.\n", ret);
+       }
+
+       return ret;
 }
 
 static int qm_dev_hw_init(struct hisi_qm *qm)
@@ -3844,6 +4815,12 @@ static void qm_restart_prepare(struct hisi_qm *qm)
 {
        u32 value;
 
+       if (qm->err_ini->open_sva_prefetch)
+               qm->err_ini->open_sva_prefetch(qm);
+
+       if (qm->ver >= QM_HW_V3)
+               return;
+
        if (!qm->err_status.is_qm_ecc_mbit &&
            !qm->err_status.is_dev_ecc_mbit)
                return;
@@ -3863,15 +4840,15 @@ static void qm_restart_prepare(struct hisi_qm *qm)
 
        /* clear AM Reorder Buffer ecc mbit source */
        writel(ACC_ROB_ECC_ERR_MULTPL, qm->io_base + ACC_AM_ROB_ECC_INT_STS);
-
-       if (qm->err_ini->open_axi_master_ooo)
-               qm->err_ini->open_axi_master_ooo(qm);
 }
 
 static void qm_restart_done(struct hisi_qm *qm)
 {
        u32 value;
 
+       if (qm->ver >= QM_HW_V3)
+               goto clear_flags;
+
        if (!qm->err_status.is_qm_ecc_mbit &&
            !qm->err_status.is_dev_ecc_mbit)
                return;
@@ -3881,6 +4858,7 @@ static void qm_restart_done(struct hisi_qm *qm)
        value |= qm->err_info.msi_wr_port;
        writel(value, qm->io_base + ACC_AM_CFG_PORT_WR_EN);
 
+clear_flags:
        qm->err_status.is_qm_ecc_mbit = false;
        qm->err_status.is_dev_ecc_mbit = false;
 }
@@ -3890,7 +4868,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
        struct pci_dev *pdev = qm->pdev;
        int ret;
 
-       ret = qm_set_msi(qm, true);
+       ret = qm->ops->set_msi(qm, true);
        if (ret) {
                pci_err(pdev, "Fails to enable PEH MSI bit!\n");
                return ret;
@@ -3917,6 +4895,9 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
        }
 
        qm_restart_prepare(qm);
+       hisi_qm_dev_err_init(qm);
+       if (qm->err_ini->open_axi_master_ooo)
+               qm->err_ini->open_axi_master_ooo(qm);
 
        ret = qm_restart(qm);
        if (ret) {
@@ -3924,24 +4905,18 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
                return ret;
        }
 
-       if (qm->vfs_num) {
-               ret = qm_vf_q_assign(qm, qm->vfs_num);
-               if (ret) {
-                       pci_err(pdev, "Failed to assign queue!\n");
-                       return ret;
-               }
-       }
+       ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
+       if (ret)
+               pci_err(pdev, "failed to start vfs by pf in soft reset.\n");
 
-       ret = qm_vf_reset_done(qm);
-       if (ret) {
-               pci_err(pdev, "Failed to start VFs!\n");
-               return -EPERM;
-       }
+       ret = qm_wait_vf_prepare_finish(qm);
+       if (ret)
+               pci_err(pdev, "failed to start by vfs in soft reset!\n");
 
-       hisi_qm_dev_err_init(qm);
+       qm_cmd_init(qm);
        qm_restart_done(qm);
 
-       clear_bit(QM_RESETTING, &qm->misc_ctl);
+       qm_reset_bit_clear(qm);
 
        return 0;
 }
@@ -3962,13 +4937,13 @@ static int qm_controller_reset(struct hisi_qm *qm)
        ret = qm_soft_reset(qm);
        if (ret) {
                pci_err(pdev, "Controller reset failed (%d)\n", ret);
-               clear_bit(QM_RESETTING, &qm->misc_ctl);
+               qm_reset_bit_clear(qm);
                return ret;
        }
 
        ret = qm_controller_reset_done(qm);
        if (ret) {
-               clear_bit(QM_RESETTING, &qm->misc_ctl);
+               qm_reset_bit_clear(qm);
                return ret;
        }
 
@@ -4005,21 +4980,6 @@ pci_ers_result_t hisi_qm_dev_slot_reset(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL_GPL(hisi_qm_dev_slot_reset);
 
-/* check the interrupt is ecc-mbit error or not */
-static int qm_check_dev_error(struct hisi_qm *qm)
-{
-       int ret;
-
-       if (qm->fun_type == QM_HW_VF)
-               return 0;
-
-       ret = qm_get_hw_error_status(qm) & QM_ECC_MBIT;
-       if (ret)
-               return ret;
-
-       return (qm_get_dev_err_status(qm) & qm->err_info.ecc_2bits_mask);
-}
-
 void hisi_qm_reset_prepare(struct pci_dev *pdev)
 {
        struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
@@ -4045,14 +5005,13 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
                return;
        }
 
-       if (qm->vfs_num) {
-               ret = qm_vf_reset_prepare(qm, QM_FLR);
-               if (ret) {
-                       pci_err(pdev, "Failed to prepare reset, ret = %d.\n",
-                               ret);
-                       return;
-               }
-       }
+       /* PF obtains the information of VF by querying the register. */
+       if (qm->fun_type == QM_HW_PF)
+               qm_cmd_uninit(qm);
+
+       ret = qm_try_stop_vfs(qm, QM_PF_FLR_PREPARE, QM_FLR);
+       if (ret)
+               pci_err(pdev, "failed to stop vfs by pf in FLR.\n");
 
        ret = hisi_qm_stop(qm, QM_FLR);
        if (ret) {
@@ -4060,6 +5019,10 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
                return;
        }
 
+       ret = qm_wait_vf_prepare_finish(qm);
+       if (ret)
+               pci_err(pdev, "failed to stop by vfs in FLR!\n");
+
        pci_info(pdev, "FLR resetting...\n");
 }
 EXPORT_SYMBOL_GPL(hisi_qm_reset_prepare);
@@ -4085,42 +5048,38 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
        struct hisi_qm *qm = pci_get_drvdata(pdev);
        int ret;
 
-       hisi_qm_dev_err_init(pf_qm);
-
-       ret = qm_restart(qm);
-       if (ret) {
-               pci_err(pdev, "Failed to start QM, ret = %d.\n", ret);
-               goto flr_done;
-       }
-
        if (qm->fun_type == QM_HW_PF) {
                ret = qm_dev_hw_init(qm);
                if (ret) {
                        pci_err(pdev, "Failed to init PF, ret = %d.\n", ret);
                        goto flr_done;
                }
+       }
 
-               if (!qm->vfs_num)
-                       goto flr_done;
-
-               ret = qm_vf_q_assign(qm, qm->vfs_num);
-               if (ret) {
-                       pci_err(pdev, "Failed to assign VFs, ret = %d.\n", ret);
-                       goto flr_done;
-               }
+       hisi_qm_dev_err_init(pf_qm);
 
-               ret = qm_vf_reset_done(qm);
-               if (ret) {
-                       pci_err(pdev, "Failed to start VFs, ret = %d.\n", ret);
-                       goto flr_done;
-               }
+       ret = qm_restart(qm);
+       if (ret) {
+               pci_err(pdev, "Failed to start QM, ret = %d.\n", ret);
+               goto flr_done;
        }
 
+       ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
+       if (ret)
+               pci_err(pdev, "failed to start vfs by pf in FLR.\n");
+
+       ret = qm_wait_vf_prepare_finish(qm);
+       if (ret)
+               pci_err(pdev, "failed to start by vfs in FLR!\n");
+
 flr_done:
+       if (qm->fun_type == QM_HW_PF)
+               qm_cmd_init(qm);
+
        if (qm_flr_reset_complete(pdev))
                pci_info(pdev, "FLR reset complete\n");
 
-       clear_bit(QM_RESETTING, &qm->misc_ctl);
+       qm_reset_bit_clear(qm);
 }
 EXPORT_SYMBOL_GPL(hisi_qm_reset_done);
 
@@ -4149,7 +5108,7 @@ static int qm_irq_register(struct hisi_qm *qm)
        if (ret)
                return ret;
 
-       if (qm->ver != QM_HW_V1) {
+       if (qm->ver > QM_HW_V1) {
                ret = request_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR),
                                  qm_aeq_irq, 0, qm->dev_name, qm);
                if (ret)
@@ -4164,8 +5123,18 @@ static int qm_irq_register(struct hisi_qm *qm)
                }
        }
 
+       if (qm->ver > QM_HW_V2) {
+               ret = request_irq(pci_irq_vector(pdev, QM_CMD_EVENT_IRQ_VECTOR),
+                               qm_mb_cmd_irq, 0, qm->dev_name, qm);
+               if (ret)
+                       goto err_mb_cmd_irq;
+       }
+
        return 0;
 
+err_mb_cmd_irq:
+       if (qm->fun_type == QM_HW_PF)
+               free_irq(pci_irq_vector(pdev, QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
 err_abonormal_irq:
        free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
 err_aeq_irq:
@@ -4202,6 +5171,183 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
 
 }
 
+static void qm_pf_reset_vf_prepare(struct hisi_qm *qm,
+                                  enum qm_stop_reason stop_reason)
+{
+       enum qm_mb_cmd cmd = QM_VF_PREPARE_DONE;
+       struct pci_dev *pdev = qm->pdev;
+       int ret;
+
+       ret = qm_reset_prepare_ready(qm);
+       if (ret) {
+               dev_err(&pdev->dev, "reset prepare not ready!\n");
+               atomic_set(&qm->status.flags, QM_STOP);
+               cmd = QM_VF_PREPARE_FAIL;
+               goto err_prepare;
+       }
+
+       ret = hisi_qm_stop(qm, stop_reason);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to stop QM, ret = %d.\n", ret);
+               atomic_set(&qm->status.flags, QM_STOP);
+               cmd = QM_VF_PREPARE_FAIL;
+               goto err_prepare;
+       }
+
+err_prepare:
+       pci_save_state(pdev);
+       ret = qm->ops->ping_pf(qm, cmd);
+       if (ret)
+               dev_warn(&pdev->dev, "PF responds timeout in reset prepare!\n");
+}
+
+static void qm_pf_reset_vf_done(struct hisi_qm *qm)
+{
+       enum qm_mb_cmd cmd = QM_VF_START_DONE;
+       struct pci_dev *pdev = qm->pdev;
+       int ret;
+
+       pci_restore_state(pdev);
+       ret = hisi_qm_start(qm);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to start QM, ret = %d.\n", ret);
+               cmd = QM_VF_START_FAIL;
+       }
+
+       ret = qm->ops->ping_pf(qm, cmd);
+       if (ret)
+               dev_warn(&pdev->dev, "PF responds timeout in reset done!\n");
+
+       qm_reset_bit_clear(qm);
+}
+
+static int qm_wait_pf_reset_finish(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       u32 val, cmd;
+       u64 msg;
+       int ret;
+
+       /* Wait for reset to finish */
+       ret = readl_relaxed_poll_timeout(qm->io_base + QM_IFC_INT_SOURCE_V, val,
+                                        val == BIT(0), QM_VF_RESET_WAIT_US,
+                                        QM_VF_RESET_WAIT_TIMEOUT_US);
+       /* hardware completion status should be available by this time */
+       if (ret) {
+               dev_err(dev, "couldn't get reset done status from PF, timeout!\n");
+               return -ETIMEDOUT;
+       }
+
+       /*
+        * Whether message is got successfully,
+        * VF needs to ack PF by clearing the interrupt.
+        */
+       ret = qm_get_mb_cmd(qm, &msg, 0);
+       qm_clear_cmd_interrupt(qm, 0);
+       if (ret) {
+               dev_err(dev, "failed to get msg from PF in reset done!\n");
+               return ret;
+       }
+
+       cmd = msg & QM_MB_CMD_DATA_MASK;
+       if (cmd != QM_PF_RESET_DONE) {
+               dev_err(dev, "the cmd(%u) is not reset done!\n", cmd);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void qm_pf_reset_vf_process(struct hisi_qm *qm,
+                                  enum qm_stop_reason stop_reason)
+{
+       struct device *dev = &qm->pdev->dev;
+       int ret;
+
+       dev_info(dev, "device reset start...\n");
+
+       /* The message is obtained by querying the register during resetting */
+       qm_cmd_uninit(qm);
+       qm_pf_reset_vf_prepare(qm, stop_reason);
+
+       ret = qm_wait_pf_reset_finish(qm);
+       if (ret)
+               goto err_get_status;
+
+       qm_pf_reset_vf_done(qm);
+       qm_cmd_init(qm);
+
+       dev_info(dev, "device reset done.\n");
+
+       return;
+
+err_get_status:
+       qm_cmd_init(qm);
+       qm_reset_bit_clear(qm);
+}
+
+static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num)
+{
+       struct device *dev = &qm->pdev->dev;
+       u64 msg;
+       u32 cmd;
+       int ret;
+
+       /*
+        * Get the msg from source by sending mailbox. Whether message is got
+        * successfully, destination needs to ack source by clearing the interrupt.
+        */
+       ret = qm_get_mb_cmd(qm, &msg, fun_num);
+       qm_clear_cmd_interrupt(qm, BIT(fun_num));
+       if (ret) {
+               dev_err(dev, "failed to get msg from source!\n");
+               return;
+       }
+
+       cmd = msg & QM_MB_CMD_DATA_MASK;
+       switch (cmd) {
+       case QM_PF_FLR_PREPARE:
+               qm_pf_reset_vf_process(qm, QM_FLR);
+               break;
+       case QM_PF_SRST_PREPARE:
+               qm_pf_reset_vf_process(qm, QM_SOFT_RESET);
+               break;
+       case QM_VF_GET_QOS:
+               qm_vf_get_qos(qm, fun_num);
+               break;
+       case QM_PF_SET_QOS:
+               qm->mb_qos = msg >> QM_MB_CMD_DATA_SHIFT;
+               break;
+       default:
+               dev_err(dev, "unsupported cmd %u sent by function(%u)!\n", cmd, fun_num);
+               break;
+       }
+}
+
+static void qm_cmd_process(struct work_struct *cmd_process)
+{
+       struct hisi_qm *qm = container_of(cmd_process,
+                                       struct hisi_qm, cmd_process);
+       u32 vfs_num = qm->vfs_num;
+       u64 val;
+       u32 i;
+
+       if (qm->fun_type == QM_HW_PF) {
+               val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
+               if (!val)
+                       return;
+
+               for (i = 1; i <= vfs_num; i++) {
+                       if (val & BIT(i))
+                               qm_handle_cmd_msg(qm, i);
+               }
+
+               return;
+       }
+
+       qm_handle_cmd_msg(qm, 0);
+}
+
 /**
  * hisi_qm_alg_register() - Register alg to crypto and add qm to qm_list.
  * @qm: The qm needs add.
@@ -4212,11 +5358,9 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
  */
 int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
 {
+       struct device *dev = &qm->pdev->dev;
        int flag = 0;
        int ret = 0;
-       /* HW V2 not support both use uacce sva mode and hardware crypto algs */
-       if (qm->ver <= QM_HW_V2 && qm->use_sva)
-               return 0;
 
        mutex_lock(&qm_list->lock);
        if (list_empty(&qm_list->list))
@@ -4224,6 +5368,11 @@ int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
        list_add_tail(&qm->list, &qm_list->list);
        mutex_unlock(&qm_list->lock);
 
+       if (qm->ver <= QM_HW_V2 && qm->use_sva) {
+               dev_info(dev, "HW V2 not both use uacce sva mode and hardware crypto algs.\n");
+               return 0;
+       }
+
        if (flag) {
                ret = qm_list->register_to_crypto(qm);
                if (ret) {
@@ -4248,13 +5397,13 @@ EXPORT_SYMBOL_GPL(hisi_qm_alg_register);
  */
 void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
 {
-       if (qm->ver <= QM_HW_V2 && qm->use_sva)
-               return;
-
        mutex_lock(&qm_list->lock);
        list_del(&qm->list);
        mutex_unlock(&qm_list->lock);
 
+       if (qm->ver <= QM_HW_V2 && qm->use_sva)
+               return;
+
        if (list_empty(&qm_list->list))
                qm_list->unregister_from_crypto(qm);
 }
@@ -4389,6 +5538,94 @@ err_disable_pcidev:
        return ret;
 }
 
+static void hisi_qm_init_work(struct hisi_qm *qm)
+{
+       INIT_WORK(&qm->work, qm_work_process);
+       if (qm->fun_type == QM_HW_PF)
+               INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
+
+       if (qm->ver > QM_HW_V2)
+               INIT_WORK(&qm->cmd_process, qm_cmd_process);
+}
+
+static int hisi_qp_alloc_memory(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       size_t qp_dma_size;
+       int i, ret;
+
+       qm->qp_array = kcalloc(qm->qp_num, sizeof(struct hisi_qp), GFP_KERNEL);
+       if (!qm->qp_array)
+               return -ENOMEM;
+
+       /* one more page for device or qp statuses */
+       qp_dma_size = qm->sqe_size * QM_Q_DEPTH +
+                     sizeof(struct qm_cqe) * QM_Q_DEPTH;
+       qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE;
+       for (i = 0; i < qm->qp_num; i++) {
+               ret = hisi_qp_memory_init(qm, qp_dma_size, i);
+               if (ret)
+                       goto err_init_qp_mem;
+
+               dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size);
+       }
+
+       return 0;
+err_init_qp_mem:
+       hisi_qp_memory_uninit(qm, i);
+
+       return ret;
+}
+
+static int hisi_qm_memory_init(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       int ret, total_vfs;
+       size_t off = 0;
+
+       total_vfs = pci_sriov_get_totalvfs(qm->pdev);
+       qm->factor = kcalloc(total_vfs + 1, sizeof(struct qm_shaper_factor), GFP_KERNEL);
+       if (!qm->factor)
+               return -ENOMEM;
+
+#define QM_INIT_BUF(qm, type, num) do { \
+       (qm)->type = ((qm)->qdma.va + (off)); \
+       (qm)->type##_dma = (qm)->qdma.dma + (off); \
+       off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \
+} while (0)
+
+       idr_init(&qm->qp_idr);
+       qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) +
+                       QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) +
+                       QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
+                       QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num);
+       qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, &qm->qdma.dma,
+                                        GFP_ATOMIC);
+       dev_dbg(dev, "allocate qm dma buf size=%zx)\n", qm->qdma.size);
+       if (!qm->qdma.va) {
+               ret =  -ENOMEM;
+               goto err_alloc_qdma;
+       }
+
+       QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH);
+       QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH);
+       QM_INIT_BUF(qm, sqc, qm->qp_num);
+       QM_INIT_BUF(qm, cqc, qm->qp_num);
+
+       ret = hisi_qp_alloc_memory(qm);
+       if (ret)
+               goto err_alloc_qp_array;
+
+       return 0;
+
+err_alloc_qp_array:
+       dma_free_coherent(dev, qm->qdma.size, qm->qdma.va, qm->qdma.dma);
+err_alloc_qdma:
+       kfree(qm->factor);
+
+       return ret;
+}
+
 /**
  * hisi_qm_init() - Initialize configures about qm.
  * @qm: The qm needing init.
@@ -4426,10 +5663,8 @@ int hisi_qm_init(struct hisi_qm *qm)
        if (ret)
                goto err_alloc_uacce;
 
-       INIT_WORK(&qm->work, qm_work_process);
-       if (qm->fun_type == QM_HW_PF)
-               INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
-
+       hisi_qm_init_work(qm);
+       qm_cmd_init(qm);
        atomic_set(&qm->status.flags, QM_INIT);
 
        return 0;
index acefdf8..035eaf8 100644 (file)
@@ -76,6 +76,9 @@
 #define QM_Q_DEPTH                     1024
 #define QM_MIN_QNUM                     2
 #define HISI_ACC_SGL_SGE_NR_MAX                255
+#define QM_SHAPER_CFG                  0x100164
+#define QM_SHAPER_ENABLE               BIT(30)
+#define QM_SHAPER_TYPE1_OFFSET         10
 
 /* page number for queue file region */
 #define QM_DOORBELL_PAGE_NR            1
@@ -148,6 +151,14 @@ struct qm_debug {
        struct debugfs_file files[DEBUG_FILE_NUM];
 };
 
+struct qm_shaper_factor {
+       u32 func_qos;
+       u64 cir_b;
+       u64 cir_u;
+       u64 cir_s;
+       u64 cbs_s;
+};
+
 struct qm_dma {
        void *va;
        dma_addr_t dma;
@@ -188,6 +199,8 @@ struct hisi_qm_err_ini {
        void (*clear_dev_hw_err_status)(struct hisi_qm *qm, u32 err_sts);
        void (*open_axi_master_ooo)(struct hisi_qm *qm);
        void (*close_axi_master_ooo)(struct hisi_qm *qm);
+       void (*open_sva_prefetch)(struct hisi_qm *qm);
+       void (*close_sva_prefetch)(struct hisi_qm *qm);
        void (*log_dev_hw_err)(struct hisi_qm *qm, u32 err_sts);
        void (*err_info_init)(struct hisi_qm *qm);
 };
@@ -248,6 +261,7 @@ struct hisi_qm {
        struct workqueue_struct *wq;
        struct work_struct work;
        struct work_struct rst_work;
+       struct work_struct cmd_process;
 
        const char *algs;
        bool use_sva;
@@ -259,6 +273,9 @@ struct hisi_qm {
        resource_size_t db_phys_base;
        struct uacce_device *uacce;
        int mode;
+       struct qm_shaper_factor *factor;
+       u32 mb_qos;
+       u32 type_rate;
 };
 
 struct hisi_qp_status {
index dfdce2f..018415b 100644 (file)
@@ -13,14 +13,14 @@ struct sec_alg_res {
        dma_addr_t pbuf_dma;
        u8 *c_ivin;
        dma_addr_t c_ivin_dma;
+       u8 *a_ivin;
+       dma_addr_t a_ivin_dma;
        u8 *out_mac;
        dma_addr_t out_mac_dma;
 };
 
 /* Cipher request of SEC private */
 struct sec_cipher_req {
-       struct hisi_acc_hw_sgl *c_in;
-       dma_addr_t c_in_dma;
        struct hisi_acc_hw_sgl *c_out;
        dma_addr_t c_out_dma;
        u8 *c_ivin;
@@ -33,15 +33,25 @@ struct sec_cipher_req {
 struct sec_aead_req {
        u8 *out_mac;
        dma_addr_t out_mac_dma;
+       u8 *a_ivin;
+       dma_addr_t a_ivin_dma;
        struct aead_request *aead_req;
 };
 
 /* SEC request of Crypto */
 struct sec_req {
-       struct sec_sqe sec_sqe;
+       union {
+               struct sec_sqe sec_sqe;
+               struct sec_sqe3 sec_sqe3;
+       };
        struct sec_ctx *ctx;
        struct sec_qp_ctx *qp_ctx;
 
+       /**
+        * Common parameter of the SEC request.
+        */
+       struct hisi_acc_hw_sgl *in;
+       dma_addr_t in_dma;
        struct sec_cipher_req c_req;
        struct sec_aead_req aead_req;
        struct list_head backlog_head;
@@ -81,7 +91,9 @@ struct sec_auth_ctx {
        u8 a_key_len;
        u8 mac_len;
        u8 a_alg;
+       bool fallback;
        struct crypto_shash *hash_tfm;
+       struct crypto_aead *fallback_aead_tfm;
 };
 
 /* SEC cipher context which cipher's relatives */
@@ -94,6 +106,10 @@ struct sec_cipher_ctx {
        u8 c_mode;
        u8 c_alg;
        u8 c_key_len;
+
+       /* add software support */
+       bool fallback;
+       struct crypto_sync_skcipher *fbtfm;
 };
 
 /* SEC queue context which defines queue's relatives */
@@ -137,6 +153,7 @@ struct sec_ctx {
        bool pbuf_supported;
        struct sec_cipher_ctx c_ctx;
        struct sec_auth_ctx a_ctx;
+       u8 type_supported;
        struct device *dev;
 };
 
index 133aede..6a45bd2 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2019 HiSilicon Limited. */
 
 #include <crypto/aes.h>
+#include <crypto/aead.h>
 #include <crypto/algapi.h>
 #include <crypto/authenc.h>
 #include <crypto/des.h>
@@ -21,6 +22,7 @@
 
 #define SEC_PRIORITY           4001
 #define SEC_XTS_MIN_KEY_SIZE   (2 * AES_MIN_KEY_SIZE)
+#define SEC_XTS_MID_KEY_SIZE   (3 * AES_MIN_KEY_SIZE)
 #define SEC_XTS_MAX_KEY_SIZE   (2 * AES_MAX_KEY_SIZE)
 #define SEC_DES3_2KEY_SIZE     (2 * DES_KEY_SIZE)
 #define SEC_DES3_3KEY_SIZE     (3 * DES_KEY_SIZE)
 #define SEC_AEAD_ALG_OFFSET     11
 #define SEC_AUTH_OFFSET                6
 
+#define SEC_DE_OFFSET_V3               9
+#define SEC_SCENE_OFFSET_V3    5
+#define SEC_CKEY_OFFSET_V3     13
+#define SEC_SRC_SGL_OFFSET_V3  11
+#define SEC_DST_SGL_OFFSET_V3  14
+#define SEC_CALG_OFFSET_V3     4
+#define SEC_AKEY_OFFSET_V3     9
+#define SEC_MAC_OFFSET_V3      4
+#define SEC_AUTH_ALG_OFFSET_V3 15
+#define SEC_CIPHER_AUTH_V3     0xbf
+#define SEC_AUTH_CIPHER_V3     0x40
 #define SEC_FLAG_OFFSET                7
 #define SEC_FLAG_MASK          0x0780
 #define SEC_TYPE_MASK          0x0F
 #define SEC_DONE_MASK          0x0001
+#define SEC_ICV_MASK           0x000E
+#define SEC_SQE_LEN_RATE_MASK  0x3
 
 #define SEC_TOTAL_IV_SZ                (SEC_IV_SIZE * QM_Q_DEPTH)
 #define SEC_SGL_SGE_NR         128
 #define SEC_SQE_CFLAG          2
 #define SEC_SQE_AEAD_FLAG      3
 #define SEC_SQE_DONE           0x1
+#define SEC_ICV_ERR            0x2
+#define MIN_MAC_LEN            4
+#define MAC_LEN_MASK           0x1U
+#define MAX_INPUT_DATA_LEN     0xFFFE00
+#define BITS_MASK              0xFF
+#define BYTE_BITS              0x8
+#define SEC_XTS_NAME_SZ                0x3
+#define IV_CM_CAL_NUM          2
+#define IV_CL_MASK             0x7
+#define IV_CL_MIN              2
+#define IV_CL_MID              4
+#define IV_CL_MAX              8
+#define IV_FLAGS_OFFSET        0x6
+#define IV_CM_OFFSET           0x3
+#define IV_LAST_BYTE1          1
+#define IV_LAST_BYTE2          2
+#define IV_LAST_BYTE_MASK      0xFF
+#define IV_CTR_INIT            0x1
+#define IV_BYTE_OFFSET         0x8
 
 /* Get an en/de-cipher queue cyclically to balance load over queues of TFM */
 static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
@@ -124,22 +158,59 @@ static void sec_free_req_id(struct sec_req *req)
        mutex_unlock(&qp_ctx->req_lock);
 }
 
-static int sec_aead_verify(struct sec_req *req)
+static u8 pre_parse_finished_bd(struct bd_status *status, void *resp)
 {
-       struct aead_request *aead_req = req->aead_req.aead_req;
-       struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
-       size_t authsize = crypto_aead_authsize(tfm);
-       u8 *mac_out = req->aead_req.out_mac;
-       u8 *mac = mac_out + SEC_MAX_MAC_LEN;
-       struct scatterlist *sgl = aead_req->src;
-       size_t sz;
+       struct sec_sqe *bd = resp;
+
+       status->done = le16_to_cpu(bd->type2.done_flag) & SEC_DONE_MASK;
+       status->icv = (le16_to_cpu(bd->type2.done_flag) & SEC_ICV_MASK) >> 1;
+       status->flag = (le16_to_cpu(bd->type2.done_flag) &
+                                       SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
+       status->tag = le16_to_cpu(bd->type2.tag);
+       status->err_type = bd->type2.error_type;
+
+       return bd->type_cipher_auth & SEC_TYPE_MASK;
+}
+
+static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp)
+{
+       struct sec_sqe3 *bd3 = resp;
+
+       status->done = le16_to_cpu(bd3->done_flag) & SEC_DONE_MASK;
+       status->icv = (le16_to_cpu(bd3->done_flag) & SEC_ICV_MASK) >> 1;
+       status->flag = (le16_to_cpu(bd3->done_flag) &
+                                       SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
+       status->tag = le64_to_cpu(bd3->tag);
+       status->err_type = bd3->error_type;
+
+       return le32_to_cpu(bd3->bd_param) & SEC_TYPE_MASK;
+}
+
+static int sec_cb_status_check(struct sec_req *req,
+                              struct bd_status *status)
+{
+       struct sec_ctx *ctx = req->ctx;
 
-       sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), mac, authsize,
-                               aead_req->cryptlen + aead_req->assoclen -
-                               authsize);
-       if (unlikely(sz != authsize || memcmp(mac_out, mac, sz))) {
-               dev_err(req->ctx->dev, "aead verify failure!\n");
-               return -EBADMSG;
+       if (unlikely(req->err_type || status->done != SEC_SQE_DONE)) {
+               dev_err_ratelimited(ctx->dev, "err_type[%d], done[%u]\n",
+                                   req->err_type, status->done);
+               return -EIO;
+       }
+
+       if (unlikely(ctx->alg_type == SEC_SKCIPHER)) {
+               if (unlikely(status->flag != SEC_SQE_CFLAG)) {
+                       dev_err_ratelimited(ctx->dev, "flag[%u]\n",
+                                           status->flag);
+                       return -EIO;
+               }
+       } else if (unlikely(ctx->alg_type == SEC_AEAD)) {
+               if (unlikely(status->flag != SEC_SQE_AEAD_FLAG ||
+                            status->icv == SEC_ICV_ERR)) {
+                       dev_err_ratelimited(ctx->dev,
+                                           "flag[%u], icv[%u]\n",
+                                           status->flag, status->icv);
+                       return -EBADMSG;
+               }
        }
 
        return 0;
@@ -149,43 +220,38 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp)
 {
        struct sec_qp_ctx *qp_ctx = qp->qp_ctx;
        struct sec_dfx *dfx = &qp_ctx->ctx->sec->debug.dfx;
-       struct sec_sqe *bd = resp;
+       u8 type_supported = qp_ctx->ctx->type_supported;
+       struct bd_status status;
        struct sec_ctx *ctx;
        struct sec_req *req;
-       u16 done, flag;
-       int err = 0;
+       int err;
        u8 type;
 
-       type = bd->type_cipher_auth & SEC_TYPE_MASK;
-       if (unlikely(type != SEC_BD_TYPE2)) {
+       if (type_supported == SEC_BD_TYPE2) {
+               type = pre_parse_finished_bd(&status, resp);
+               req = qp_ctx->req_list[status.tag];
+       } else {
+               type = pre_parse_finished_bd3(&status, resp);
+               req = (void *)(uintptr_t)status.tag;
+       }
+
+       if (unlikely(type != type_supported)) {
                atomic64_inc(&dfx->err_bd_cnt);
                pr_err("err bd type [%d]\n", type);
                return;
        }
 
-       req = qp_ctx->req_list[le16_to_cpu(bd->type2.tag)];
        if (unlikely(!req)) {
                atomic64_inc(&dfx->invalid_req_cnt);
                atomic_inc(&qp->qp_status.used);
                return;
        }
-       req->err_type = bd->type2.error_type;
+
+       req->err_type = status.err_type;
        ctx = req->ctx;
-       done = le16_to_cpu(bd->type2.done_flag) & SEC_DONE_MASK;
-       flag = (le16_to_cpu(bd->type2.done_flag) &
-               SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
-       if (unlikely(req->err_type || done != SEC_SQE_DONE ||
-           (ctx->alg_type == SEC_SKCIPHER && flag != SEC_SQE_CFLAG) ||
-           (ctx->alg_type == SEC_AEAD && flag != SEC_SQE_AEAD_FLAG))) {
-               dev_err_ratelimited(ctx->dev,
-                       "err_type[%d],done[%d],flag[%d]\n",
-                       req->err_type, done, flag);
-               err = -EIO;
+       err = sec_cb_status_check(req, &status);
+       if (err)
                atomic64_inc(&dfx->done_flag_cnt);
-       }
-
-       if (ctx->alg_type == SEC_AEAD && !req->c_req.encrypt)
-               err = sec_aead_verify(req);
 
        atomic64_inc(&dfx->recv_cnt);
 
@@ -253,6 +319,30 @@ static void sec_free_civ_resource(struct device *dev, struct sec_alg_res *res)
                                  res->c_ivin, res->c_ivin_dma);
 }
 
+static int sec_alloc_aiv_resource(struct device *dev, struct sec_alg_res *res)
+{
+       int i;
+
+       res->a_ivin = dma_alloc_coherent(dev, SEC_TOTAL_IV_SZ,
+                                        &res->a_ivin_dma, GFP_KERNEL);
+       if (!res->a_ivin)
+               return -ENOMEM;
+
+       for (i = 1; i < QM_Q_DEPTH; i++) {
+               res[i].a_ivin_dma = res->a_ivin_dma + i * SEC_IV_SIZE;
+               res[i].a_ivin = res->a_ivin + i * SEC_IV_SIZE;
+       }
+
+       return 0;
+}
+
+static void sec_free_aiv_resource(struct device *dev, struct sec_alg_res *res)
+{
+       if (res->a_ivin)
+               dma_free_coherent(dev, SEC_TOTAL_IV_SZ,
+                                 res->a_ivin, res->a_ivin_dma);
+}
+
 static int sec_alloc_mac_resource(struct device *dev, struct sec_alg_res *res)
 {
        int i;
@@ -335,9 +425,13 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
                return ret;
 
        if (ctx->alg_type == SEC_AEAD) {
+               ret = sec_alloc_aiv_resource(dev, res);
+               if (ret)
+                       goto alloc_aiv_fail;
+
                ret = sec_alloc_mac_resource(dev, res);
                if (ret)
-                       goto alloc_fail;
+                       goto alloc_mac_fail;
        }
        if (ctx->pbuf_supported) {
                ret = sec_alloc_pbuf_resource(dev, res);
@@ -352,7 +446,10 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
 alloc_pbuf_fail:
        if (ctx->alg_type == SEC_AEAD)
                sec_free_mac_resource(dev, qp_ctx->res);
-alloc_fail:
+alloc_mac_fail:
+       if (ctx->alg_type == SEC_AEAD)
+               sec_free_aiv_resource(dev, res);
+alloc_aiv_fail:
        sec_free_civ_resource(dev, res);
        return ret;
 }
@@ -382,10 +479,11 @@ static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx,
        qp = ctx->qps[qp_ctx_id];
        qp->req_type = 0;
        qp->qp_ctx = qp_ctx;
-       qp->req_cb = sec_req_cb;
        qp_ctx->qp = qp;
        qp_ctx->ctx = ctx;
 
+       qp->req_cb = sec_req_cb;
+
        mutex_init(&qp_ctx->req_lock);
        idr_init(&qp_ctx->req_idr);
        INIT_LIST_HEAD(&qp_ctx->backlog);
@@ -536,6 +634,26 @@ static void sec_auth_uninit(struct sec_ctx *ctx)
                          a_ctx->a_key, a_ctx->a_key_dma);
 }
 
+static int sec_skcipher_fbtfm_init(struct crypto_skcipher *tfm)
+{
+       const char *alg = crypto_tfm_alg_name(&tfm->base);
+       struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+
+       c_ctx->fallback = false;
+       if (likely(strncmp(alg, "xts", SEC_XTS_NAME_SZ)))
+               return 0;
+
+       c_ctx->fbtfm = crypto_alloc_sync_skcipher(alg, 0,
+                                                 CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(c_ctx->fbtfm)) {
+               pr_err("failed to alloc fallback tfm!\n");
+               return PTR_ERR(c_ctx->fbtfm);
+       }
+
+       return 0;
+}
+
 static int sec_skcipher_init(struct crypto_skcipher *tfm)
 {
        struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
@@ -557,8 +675,14 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm)
        if (ret)
                goto err_cipher_init;
 
+       ret = sec_skcipher_fbtfm_init(tfm);
+       if (ret)
+               goto err_fbtfm_init;
+
        return 0;
 
+err_fbtfm_init:
+       sec_cipher_uninit(ctx);
 err_cipher_init:
        sec_ctx_base_uninit(ctx);
        return ret;
@@ -568,6 +692,9 @@ static void sec_skcipher_uninit(struct crypto_skcipher *tfm)
 {
        struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
 
+       if (ctx->c_ctx.fbtfm)
+               crypto_free_sync_skcipher(ctx->c_ctx.fbtfm);
+
        sec_cipher_uninit(ctx);
        sec_ctx_base_uninit(ctx);
 }
@@ -607,6 +734,9 @@ static int sec_skcipher_aes_sm4_setkey(struct sec_cipher_ctx *c_ctx,
                case SEC_XTS_MIN_KEY_SIZE:
                        c_ctx->c_key_len = SEC_CKEY_128BIT;
                        break;
+               case SEC_XTS_MID_KEY_SIZE:
+                       c_ctx->fallback = true;
+                       break;
                case SEC_XTS_MAX_KEY_SIZE:
                        c_ctx->c_key_len = SEC_CKEY_256BIT;
                        break;
@@ -615,19 +745,25 @@ static int sec_skcipher_aes_sm4_setkey(struct sec_cipher_ctx *c_ctx,
                        return -EINVAL;
                }
        } else {
-               switch (keylen) {
-               case AES_KEYSIZE_128:
-                       c_ctx->c_key_len = SEC_CKEY_128BIT;
-                       break;
-               case AES_KEYSIZE_192:
-                       c_ctx->c_key_len = SEC_CKEY_192BIT;
-                       break;
-               case AES_KEYSIZE_256:
-                       c_ctx->c_key_len = SEC_CKEY_256BIT;
-                       break;
-               default:
-                       pr_err("hisi_sec2: aes key error!\n");
+               if (c_ctx->c_alg == SEC_CALG_SM4 &&
+                   keylen != AES_KEYSIZE_128) {
+                       pr_err("hisi_sec2: sm4 key error!\n");
                        return -EINVAL;
+               } else {
+                       switch (keylen) {
+                       case AES_KEYSIZE_128:
+                               c_ctx->c_key_len = SEC_CKEY_128BIT;
+                               break;
+                       case AES_KEYSIZE_192:
+                               c_ctx->c_key_len = SEC_CKEY_192BIT;
+                               break;
+                       case AES_KEYSIZE_256:
+                               c_ctx->c_key_len = SEC_CKEY_256BIT;
+                               break;
+                       default:
+                               pr_err("hisi_sec2: aes key error!\n");
+                               return -EINVAL;
+                       }
                }
        }
 
@@ -672,7 +808,13 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
        }
 
        memcpy(c_ctx->c_key, key, keylen);
-
+       if (c_ctx->fallback) {
+               ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen);
+               if (ret) {
+                       dev_err(dev, "failed to set fallback skcipher key!\n");
+                       return ret;
+               }
+       }
        return 0;
 }
 
@@ -686,22 +828,30 @@ static int sec_setkey_##name(struct crypto_skcipher *tfm, const u8 *key,\
 GEN_SEC_SETKEY_FUNC(aes_ecb, SEC_CALG_AES, SEC_CMODE_ECB)
 GEN_SEC_SETKEY_FUNC(aes_cbc, SEC_CALG_AES, SEC_CMODE_CBC)
 GEN_SEC_SETKEY_FUNC(aes_xts, SEC_CALG_AES, SEC_CMODE_XTS)
-
+GEN_SEC_SETKEY_FUNC(aes_ofb, SEC_CALG_AES, SEC_CMODE_OFB)
+GEN_SEC_SETKEY_FUNC(aes_cfb, SEC_CALG_AES, SEC_CMODE_CFB)
+GEN_SEC_SETKEY_FUNC(aes_ctr, SEC_CALG_AES, SEC_CMODE_CTR)
 GEN_SEC_SETKEY_FUNC(3des_ecb, SEC_CALG_3DES, SEC_CMODE_ECB)
 GEN_SEC_SETKEY_FUNC(3des_cbc, SEC_CALG_3DES, SEC_CMODE_CBC)
-
 GEN_SEC_SETKEY_FUNC(sm4_xts, SEC_CALG_SM4, SEC_CMODE_XTS)
 GEN_SEC_SETKEY_FUNC(sm4_cbc, SEC_CALG_SM4, SEC_CMODE_CBC)
+GEN_SEC_SETKEY_FUNC(sm4_ofb, SEC_CALG_SM4, SEC_CMODE_OFB)
+GEN_SEC_SETKEY_FUNC(sm4_cfb, SEC_CALG_SM4, SEC_CMODE_CFB)
+GEN_SEC_SETKEY_FUNC(sm4_ctr, SEC_CALG_SM4, SEC_CMODE_CTR)
 
 static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req,
                        struct scatterlist *src)
 {
-       struct aead_request *aead_req = req->aead_req.aead_req;
+       struct sec_aead_req *a_req = &req->aead_req;
+       struct aead_request *aead_req = a_req->aead_req;
        struct sec_cipher_req *c_req = &req->c_req;
        struct sec_qp_ctx *qp_ctx = req->qp_ctx;
        struct device *dev = ctx->dev;
        int copy_size, pbuf_length;
        int req_id = req->req_id;
+       struct crypto_aead *tfm;
+       size_t authsize;
+       u8 *mac_offset;
 
        if (ctx->alg_type == SEC_AEAD)
                copy_size = aead_req->cryptlen + aead_req->assoclen;
@@ -709,15 +859,20 @@ static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req,
                copy_size = c_req->c_len;
 
        pbuf_length = sg_copy_to_buffer(src, sg_nents(src),
-                                                       qp_ctx->res[req_id].pbuf,
-                                                       copy_size);
+                       qp_ctx->res[req_id].pbuf, copy_size);
        if (unlikely(pbuf_length != copy_size)) {
                dev_err(dev, "copy src data to pbuf error!\n");
                return -EINVAL;
        }
+       if (!c_req->encrypt && ctx->alg_type == SEC_AEAD) {
+               tfm = crypto_aead_reqtfm(aead_req);
+               authsize = crypto_aead_authsize(tfm);
+               mac_offset = qp_ctx->res[req_id].pbuf + copy_size - authsize;
+               memcpy(a_req->out_mac, mac_offset, authsize);
+       }
 
-       c_req->c_in_dma = qp_ctx->res[req_id].pbuf_dma;
-       c_req->c_out_dma = c_req->c_in_dma;
+       req->in_dma = qp_ctx->res[req_id].pbuf_dma;
+       c_req->c_out_dma = req->in_dma;
 
        return 0;
 }
@@ -728,7 +883,6 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req,
        struct aead_request *aead_req = req->aead_req.aead_req;
        struct sec_cipher_req *c_req = &req->c_req;
        struct sec_qp_ctx *qp_ctx = req->qp_ctx;
-       struct device *dev = ctx->dev;
        int copy_size, pbuf_length;
        int req_id = req->req_id;
 
@@ -738,10 +892,29 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req,
                copy_size = c_req->c_len;
 
        pbuf_length = sg_copy_from_buffer(dst, sg_nents(dst),
-                               qp_ctx->res[req_id].pbuf,
-                               copy_size);
+                       qp_ctx->res[req_id].pbuf, copy_size);
        if (unlikely(pbuf_length != copy_size))
-               dev_err(dev, "copy pbuf data to dst error!\n");
+               dev_err(ctx->dev, "copy pbuf data to dst error!\n");
+}
+
+static int sec_aead_mac_init(struct sec_aead_req *req)
+{
+       struct aead_request *aead_req = req->aead_req;
+       struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
+       size_t authsize = crypto_aead_authsize(tfm);
+       u8 *mac_out = req->out_mac;
+       struct scatterlist *sgl = aead_req->src;
+       size_t copy_size;
+       off_t skip_size;
+
+       /* Copy input mac */
+       skip_size = aead_req->assoclen + aead_req->cryptlen - authsize;
+       copy_size = sg_pcopy_to_buffer(sgl, sg_nents(sgl), mac_out,
+                                      authsize, skip_size);
+       if (unlikely(copy_size != authsize))
+               return -EINVAL;
+
+       return 0;
 }
 
 static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
@@ -755,37 +928,48 @@ static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
        int ret;
 
        if (req->use_pbuf) {
-               ret = sec_cipher_pbuf_map(ctx, req, src);
                c_req->c_ivin = res->pbuf + SEC_PBUF_IV_OFFSET;
                c_req->c_ivin_dma = res->pbuf_dma + SEC_PBUF_IV_OFFSET;
                if (ctx->alg_type == SEC_AEAD) {
+                       a_req->a_ivin = res->a_ivin;
+                       a_req->a_ivin_dma = res->a_ivin_dma;
                        a_req->out_mac = res->pbuf + SEC_PBUF_MAC_OFFSET;
                        a_req->out_mac_dma = res->pbuf_dma +
                                        SEC_PBUF_MAC_OFFSET;
                }
+               ret = sec_cipher_pbuf_map(ctx, req, src);
 
                return ret;
        }
        c_req->c_ivin = res->c_ivin;
        c_req->c_ivin_dma = res->c_ivin_dma;
        if (ctx->alg_type == SEC_AEAD) {
+               a_req->a_ivin = res->a_ivin;
+               a_req->a_ivin_dma = res->a_ivin_dma;
                a_req->out_mac = res->out_mac;
                a_req->out_mac_dma = res->out_mac_dma;
        }
 
-       c_req->c_in = hisi_acc_sg_buf_map_to_hw_sgl(dev, src,
-                                                   qp_ctx->c_in_pool,
-                                                   req->req_id,
-                                                   &c_req->c_in_dma);
-
-       if (IS_ERR(c_req->c_in)) {
+       req->in = hisi_acc_sg_buf_map_to_hw_sgl(dev, src,
+                                               qp_ctx->c_in_pool,
+                                               req->req_id,
+                                               &req->in_dma);
+       if (IS_ERR(req->in)) {
                dev_err(dev, "fail to dma map input sgl buffers!\n");
-               return PTR_ERR(c_req->c_in);
+               return PTR_ERR(req->in);
+       }
+
+       if (!c_req->encrypt && ctx->alg_type == SEC_AEAD) {
+               ret = sec_aead_mac_init(a_req);
+               if (unlikely(ret)) {
+                       dev_err(dev, "fail to init mac data for ICV!\n");
+                       return ret;
+               }
        }
 
        if (dst == src) {
-               c_req->c_out = c_req->c_in;
-               c_req->c_out_dma = c_req->c_in_dma;
+               c_req->c_out = req->in;
+               c_req->c_out_dma = req->in_dma;
        } else {
                c_req->c_out = hisi_acc_sg_buf_map_to_hw_sgl(dev, dst,
                                                             qp_ctx->c_out_pool,
@@ -794,7 +978,7 @@ static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
 
                if (IS_ERR(c_req->c_out)) {
                        dev_err(dev, "fail to dma map output sgl buffers!\n");
-                       hisi_acc_sg_buf_unmap(dev, src, c_req->c_in);
+                       hisi_acc_sg_buf_unmap(dev, src, req->in);
                        return PTR_ERR(c_req->c_out);
                }
        }
@@ -812,7 +996,7 @@ static void sec_cipher_unmap(struct sec_ctx *ctx, struct sec_req *req,
                sec_cipher_pbuf_unmap(ctx, req, dst);
        } else {
                if (dst != src)
-                       hisi_acc_sg_buf_unmap(dev, src, c_req->c_in);
+                       hisi_acc_sg_buf_unmap(dev, src, req->in);
 
                hisi_acc_sg_buf_unmap(dev, dst, c_req->c_out);
        }
@@ -883,6 +1067,28 @@ static int sec_aead_auth_set_key(struct sec_auth_ctx *ctx,
        return 0;
 }
 
+static int sec_aead_setauthsize(struct crypto_aead *aead, unsigned int authsize)
+{
+       struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+       struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+       if (unlikely(a_ctx->fallback_aead_tfm))
+               return crypto_aead_setauthsize(a_ctx->fallback_aead_tfm, authsize);
+
+       return 0;
+}
+
+static int sec_aead_fallback_setkey(struct sec_auth_ctx *a_ctx,
+                                   struct crypto_aead *tfm, const u8 *key,
+                                   unsigned int keylen)
+{
+       crypto_aead_clear_flags(a_ctx->fallback_aead_tfm, CRYPTO_TFM_REQ_MASK);
+       crypto_aead_set_flags(a_ctx->fallback_aead_tfm,
+                             crypto_aead_get_flags(tfm) & CRYPTO_TFM_REQ_MASK);
+       return crypto_aead_setkey(a_ctx->fallback_aead_tfm, key, keylen);
+}
+
 static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
                           const u32 keylen, const enum sec_hash_alg a_alg,
                           const enum sec_calg c_alg,
@@ -891,6 +1097,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
 {
        struct sec_ctx *ctx = crypto_aead_ctx(tfm);
        struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+       struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
        struct device *dev = ctx->dev;
        struct crypto_authenc_keys keys;
        int ret;
@@ -900,6 +1107,23 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
        ctx->a_ctx.mac_len = mac_len;
        c_ctx->c_mode = c_mode;
 
+       if (c_mode == SEC_CMODE_CCM || c_mode == SEC_CMODE_GCM) {
+               ret = sec_skcipher_aes_sm4_setkey(c_ctx, keylen, c_mode);
+               if (ret) {
+                       dev_err(dev, "set sec aes ccm cipher key err!\n");
+                       return ret;
+               }
+               memcpy(c_ctx->c_key, key, keylen);
+
+               if (unlikely(a_ctx->fallback_aead_tfm)) {
+                       ret = sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
+                       if (ret)
+                               return ret;
+               }
+
+               return 0;
+       }
+
        if (crypto_authenc_extractkeys(&keys, key, keylen))
                goto bad_key;
 
@@ -915,6 +1139,12 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
                goto bad_key;
        }
 
+       if ((ctx->a_ctx.mac_len & SEC_SQE_LEN_RATE_MASK)  ||
+           (ctx->a_ctx.a_key_len & SEC_SQE_LEN_RATE_MASK)) {
+               dev_err(dev, "MAC or AUTH key length error!\n");
+               goto bad_key;
+       }
+
        return 0;
 
 bad_key:
@@ -936,6 +1166,14 @@ GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha256, SEC_A_HMAC_SHA256,
                         SEC_CALG_AES, SEC_HMAC_SHA256_MAC, SEC_CMODE_CBC)
 GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha512, SEC_A_HMAC_SHA512,
                         SEC_CALG_AES, SEC_HMAC_SHA512_MAC, SEC_CMODE_CBC)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_ccm, 0, SEC_CALG_AES,
+                        SEC_HMAC_CCM_MAC, SEC_CMODE_CCM)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_gcm, 0, SEC_CALG_AES,
+                        SEC_HMAC_GCM_MAC, SEC_CMODE_GCM)
+GEN_SEC_AEAD_SETKEY_FUNC(sm4_ccm, 0, SEC_CALG_SM4,
+                        SEC_HMAC_CCM_MAC, SEC_CMODE_CCM)
+GEN_SEC_AEAD_SETKEY_FUNC(sm4_gcm, 0, SEC_CALG_SM4,
+                        SEC_HMAC_GCM_MAC, SEC_CMODE_GCM)
 
 static int sec_aead_sgl_map(struct sec_ctx *ctx, struct sec_req *req)
 {
@@ -998,7 +1236,7 @@ static int sec_skcipher_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
 
        sec_sqe->type2.c_key_addr = cpu_to_le64(c_ctx->c_key_dma);
        sec_sqe->type2.c_ivin_addr = cpu_to_le64(c_req->c_ivin_dma);
-       sec_sqe->type2.data_src_addr = cpu_to_le64(c_req->c_in_dma);
+       sec_sqe->type2.data_src_addr = cpu_to_le64(req->in_dma);
        sec_sqe->type2.data_dst_addr = cpu_to_le64(c_req->c_out_dma);
 
        sec_sqe->type2.icvw_kmode |= cpu_to_le16(((u16)c_ctx->c_mode) <<
@@ -1014,29 +1252,86 @@ static int sec_skcipher_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
                cipher = SEC_CIPHER_DEC << SEC_CIPHER_OFFSET;
        sec_sqe->type_cipher_auth = bd_type | cipher;
 
-       if (req->use_pbuf)
+       /* Set destination and source address type */
+       if (req->use_pbuf) {
                sa_type = SEC_PBUF << SEC_SRC_SGL_OFFSET;
-       else
+               da_type = SEC_PBUF << SEC_DST_SGL_OFFSET;
+       } else {
                sa_type = SEC_SGL << SEC_SRC_SGL_OFFSET;
+               da_type = SEC_SGL << SEC_DST_SGL_OFFSET;
+       }
+
+       sec_sqe->sdm_addr_type |= da_type;
        scene = SEC_COMM_SCENE << SEC_SCENE_OFFSET;
-       if (c_req->c_in_dma != c_req->c_out_dma)
+       if (req->in_dma != c_req->c_out_dma)
                de = 0x1 << SEC_DE_OFFSET;
 
        sec_sqe->sds_sa_type = (de | scene | sa_type);
 
-       /* Just set DST address type */
-       if (req->use_pbuf)
-               da_type = SEC_PBUF << SEC_DST_SGL_OFFSET;
-       else
-               da_type = SEC_SGL << SEC_DST_SGL_OFFSET;
-       sec_sqe->sdm_addr_type |= da_type;
-
        sec_sqe->type2.clen_ivhlen |= cpu_to_le32(c_req->c_len);
        sec_sqe->type2.tag = cpu_to_le16((u16)req->req_id);
 
        return 0;
 }
 
+static int sec_skcipher_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
+{
+       struct sec_sqe3 *sec_sqe3 = &req->sec_sqe3;
+       struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+       struct sec_cipher_req *c_req = &req->c_req;
+       u32 bd_param = 0;
+       u16 cipher;
+
+       memset(sec_sqe3, 0, sizeof(struct sec_sqe3));
+
+       sec_sqe3->c_key_addr = cpu_to_le64(c_ctx->c_key_dma);
+       sec_sqe3->no_scene.c_ivin_addr = cpu_to_le64(c_req->c_ivin_dma);
+       sec_sqe3->data_src_addr = cpu_to_le64(req->in_dma);
+       sec_sqe3->data_dst_addr = cpu_to_le64(c_req->c_out_dma);
+
+       sec_sqe3->c_mode_alg = ((u8)c_ctx->c_alg << SEC_CALG_OFFSET_V3) |
+                                               c_ctx->c_mode;
+       sec_sqe3->c_icv_key |= cpu_to_le16(((u16)c_ctx->c_key_len) <<
+                                               SEC_CKEY_OFFSET_V3);
+
+       if (c_req->encrypt)
+               cipher = SEC_CIPHER_ENC;
+       else
+               cipher = SEC_CIPHER_DEC;
+       sec_sqe3->c_icv_key |= cpu_to_le16(cipher);
+
+       if (req->use_pbuf) {
+               bd_param |= SEC_PBUF << SEC_SRC_SGL_OFFSET_V3;
+               bd_param |= SEC_PBUF << SEC_DST_SGL_OFFSET_V3;
+       } else {
+               bd_param |= SEC_SGL << SEC_SRC_SGL_OFFSET_V3;
+               bd_param |= SEC_SGL << SEC_DST_SGL_OFFSET_V3;
+       }
+
+       bd_param |= SEC_COMM_SCENE << SEC_SCENE_OFFSET_V3;
+       if (req->in_dma != c_req->c_out_dma)
+               bd_param |= 0x1 << SEC_DE_OFFSET_V3;
+
+       bd_param |= SEC_BD_TYPE3;
+       sec_sqe3->bd_param = cpu_to_le32(bd_param);
+
+       sec_sqe3->c_len_ivin |= cpu_to_le32(c_req->c_len);
+       sec_sqe3->tag = cpu_to_le64(req);
+
+       return 0;
+}
+
+/* increment counter (128-bit int) */
+static void ctr_iv_inc(__u8 *counter, __u8 bits, __u32 nums)
+{
+       do {
+               --bits;
+               nums += counter[bits];
+               counter[bits] = nums & BITS_MASK;
+               nums >>= BYTE_BITS;
+       } while (bits && nums);
+}
+
 static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
 {
        struct aead_request *aead_req = req->aead_req.aead_req;
@@ -1060,10 +1355,17 @@ static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
                cryptlen = aead_req->cryptlen;
        }
 
-       sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size,
-                               cryptlen - iv_size);
-       if (unlikely(sz != iv_size))
-               dev_err(req->ctx->dev, "copy output iv error!\n");
+       if (req->ctx->c_ctx.c_mode == SEC_CMODE_CBC) {
+               sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size,
+                                       cryptlen - iv_size);
+               if (unlikely(sz != iv_size))
+                       dev_err(req->ctx->dev, "copy output iv error!\n");
+       } else {
+               sz = cryptlen / iv_size;
+               if (cryptlen % iv_size)
+                       sz += 1;
+               ctr_iv_inc(iv, iv_size, sz);
+       }
 }
 
 static struct sec_req *sec_back_req_clear(struct sec_ctx *ctx,
@@ -1094,8 +1396,9 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
 
        sec_free_req_id(req);
 
-       /* IV output at encrypto of CBC mode */
-       if (!err && ctx->c_ctx.c_mode == SEC_CMODE_CBC && req->c_req.encrypt)
+       /* IV output at encrypto of CBC/CTR mode */
+       if (!err && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
+           ctx->c_ctx.c_mode == SEC_CMODE_CTR) && req->c_req.encrypt)
                sec_update_iv(req, SEC_SKCIPHER);
 
        while (1) {
@@ -1112,12 +1415,125 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
        sk_req->base.complete(&sk_req->base, err);
 }
 
-static void sec_aead_copy_iv(struct sec_ctx *ctx, struct sec_req *req)
+static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)
+{
+       struct aead_request *aead_req = req->aead_req.aead_req;
+       struct sec_cipher_req *c_req = &req->c_req;
+       struct sec_aead_req *a_req = &req->aead_req;
+       size_t authsize = ctx->a_ctx.mac_len;
+       u32 data_size = aead_req->cryptlen;
+       u8 flage = 0;
+       u8 cm, cl;
+
+       /* the specification has been checked in aead_iv_demension_check() */
+       cl = c_req->c_ivin[0] + 1;
+       c_req->c_ivin[ctx->c_ctx.ivsize - cl] = 0x00;
+       memset(&c_req->c_ivin[ctx->c_ctx.ivsize - cl], 0, cl);
+       c_req->c_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE1] = IV_CTR_INIT;
+
+       /* the last 3bit is L' */
+       flage |= c_req->c_ivin[0] & IV_CL_MASK;
+
+       /* the M' is bit3~bit5, the Flags is bit6 */
+       cm = (authsize - IV_CM_CAL_NUM) / IV_CM_CAL_NUM;
+       flage |= cm << IV_CM_OFFSET;
+       if (aead_req->assoclen)
+               flage |= 0x01 << IV_FLAGS_OFFSET;
+
+       memcpy(a_req->a_ivin, c_req->c_ivin, ctx->c_ctx.ivsize);
+       a_req->a_ivin[0] = flage;
+
+       /*
+        * the last 32bit is counter's initial number,
+        * but the nonce uses the first 16bit
+        * the tail 16bit fill with the cipher length
+        */
+       if (!c_req->encrypt)
+               data_size = aead_req->cryptlen - authsize;
+
+       a_req->a_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE1] =
+                       data_size & IV_LAST_BYTE_MASK;
+       data_size >>= IV_BYTE_OFFSET;
+       a_req->a_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE2] =
+                       data_size & IV_LAST_BYTE_MASK;
+}
+
+static void sec_aead_set_iv(struct sec_ctx *ctx, struct sec_req *req)
 {
        struct aead_request *aead_req = req->aead_req.aead_req;
+       struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
+       size_t authsize = crypto_aead_authsize(tfm);
        struct sec_cipher_req *c_req = &req->c_req;
+       struct sec_aead_req *a_req = &req->aead_req;
 
        memcpy(c_req->c_ivin, aead_req->iv, ctx->c_ctx.ivsize);
+
+       if (ctx->c_ctx.c_mode == SEC_CMODE_CCM) {
+               /*
+                * CCM 16Byte Cipher_IV: {1B_Flage,13B_IV,2B_counter},
+                * the  counter must set to 0x01
+                */
+               ctx->a_ctx.mac_len = authsize;
+               /* CCM 16Byte Auth_IV: {1B_AFlage,13B_IV,2B_Ptext_length} */
+               set_aead_auth_iv(ctx, req);
+       }
+
+       /* GCM 12Byte Cipher_IV == Auth_IV */
+       if (ctx->c_ctx.c_mode == SEC_CMODE_GCM) {
+               ctx->a_ctx.mac_len = authsize;
+               memcpy(a_req->a_ivin, c_req->c_ivin, SEC_AIV_SIZE);
+       }
+}
+
+static void sec_auth_bd_fill_xcm(struct sec_auth_ctx *ctx, int dir,
+                                struct sec_req *req, struct sec_sqe *sec_sqe)
+{
+       struct sec_aead_req *a_req = &req->aead_req;
+       struct aead_request *aq = a_req->aead_req;
+
+       /* C_ICV_Len is MAC size, 0x4 ~ 0x10 */
+       sec_sqe->type2.icvw_kmode |= cpu_to_le16((u16)ctx->mac_len);
+
+       /* mode set to CCM/GCM, don't set {A_Alg, AKey_Len, MAC_Len} */
+       sec_sqe->type2.a_key_addr = sec_sqe->type2.c_key_addr;
+       sec_sqe->type2.a_ivin_addr = cpu_to_le64(a_req->a_ivin_dma);
+       sec_sqe->type_cipher_auth |= SEC_NO_AUTH << SEC_AUTH_OFFSET;
+
+       if (dir)
+               sec_sqe->sds_sa_type &= SEC_CIPHER_AUTH;
+       else
+               sec_sqe->sds_sa_type |= SEC_AUTH_CIPHER;
+
+       sec_sqe->type2.alen_ivllen = cpu_to_le32(aq->assoclen);
+       sec_sqe->type2.auth_src_offset = cpu_to_le16(0x0);
+       sec_sqe->type2.cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+
+       sec_sqe->type2.mac_addr = cpu_to_le64(a_req->out_mac_dma);
+}
+
+static void sec_auth_bd_fill_xcm_v3(struct sec_auth_ctx *ctx, int dir,
+                                   struct sec_req *req, struct sec_sqe3 *sqe3)
+{
+       struct sec_aead_req *a_req = &req->aead_req;
+       struct aead_request *aq = a_req->aead_req;
+
+       /* C_ICV_Len is MAC size, 0x4 ~ 0x10 */
+       sqe3->c_icv_key |= cpu_to_le16((u16)ctx->mac_len << SEC_MAC_OFFSET_V3);
+
+       /* mode set to CCM/GCM, don't set {A_Alg, AKey_Len, MAC_Len} */
+       sqe3->a_key_addr = sqe3->c_key_addr;
+       sqe3->auth_ivin.a_ivin_addr = cpu_to_le64(a_req->a_ivin_dma);
+       sqe3->auth_mac_key |= SEC_NO_AUTH;
+
+       if (dir)
+               sqe3->huk_iv_seq &= SEC_CIPHER_AUTH_V3;
+       else
+               sqe3->huk_iv_seq |= SEC_AUTH_CIPHER_V3;
+
+       sqe3->a_len_key = cpu_to_le32(aq->assoclen);
+       sqe3->auth_src_offset = cpu_to_le16(0x0);
+       sqe3->cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+       sqe3->mac_addr = cpu_to_le64(a_req->out_mac_dma);
 }
 
 static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
@@ -1139,13 +1555,13 @@ static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
        sec_sqe->type2.mac_key_alg |=
                        cpu_to_le32((u32)(ctx->a_alg) << SEC_AEAD_ALG_OFFSET);
 
-       sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
-
-       if (dir)
+       if (dir) {
+               sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
                sec_sqe->sds_sa_type &= SEC_CIPHER_AUTH;
-       else
+       } else {
+               sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE2 << SEC_AUTH_OFFSET;
                sec_sqe->sds_sa_type |= SEC_AUTH_CIPHER;
-
+       }
        sec_sqe->type2.alen_ivllen = cpu_to_le32(c_req->c_len + aq->assoclen);
 
        sec_sqe->type2.cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
@@ -1165,7 +1581,68 @@ static int sec_aead_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
                return ret;
        }
 
-       sec_auth_bd_fill_ex(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+       if (ctx->c_ctx.c_mode == SEC_CMODE_CCM ||
+           ctx->c_ctx.c_mode == SEC_CMODE_GCM)
+               sec_auth_bd_fill_xcm(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+       else
+               sec_auth_bd_fill_ex(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+
+       return 0;
+}
+
+static void sec_auth_bd_fill_ex_v3(struct sec_auth_ctx *ctx, int dir,
+                                  struct sec_req *req, struct sec_sqe3 *sqe3)
+{
+       struct sec_aead_req *a_req = &req->aead_req;
+       struct sec_cipher_req *c_req = &req->c_req;
+       struct aead_request *aq = a_req->aead_req;
+
+       sqe3->a_key_addr = cpu_to_le64(ctx->a_key_dma);
+
+       sqe3->auth_mac_key |=
+                       cpu_to_le32((u32)(ctx->mac_len /
+                       SEC_SQE_LEN_RATE) << SEC_MAC_OFFSET_V3);
+
+       sqe3->auth_mac_key |=
+                       cpu_to_le32((u32)(ctx->a_key_len /
+                       SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET_V3);
+
+       sqe3->auth_mac_key |=
+                       cpu_to_le32((u32)(ctx->a_alg) << SEC_AUTH_ALG_OFFSET_V3);
+
+       if (dir) {
+               sqe3->auth_mac_key |= cpu_to_le32((u32)SEC_AUTH_TYPE1);
+               sqe3->huk_iv_seq &= SEC_CIPHER_AUTH_V3;
+       } else {
+               sqe3->auth_mac_key |= cpu_to_le32((u32)SEC_AUTH_TYPE1);
+               sqe3->huk_iv_seq |= SEC_AUTH_CIPHER_V3;
+       }
+       sqe3->a_len_key = cpu_to_le32(c_req->c_len + aq->assoclen);
+
+       sqe3->cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+
+       sqe3->mac_addr = cpu_to_le64(a_req->out_mac_dma);
+}
+
+static int sec_aead_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
+{
+       struct sec_auth_ctx *auth_ctx = &ctx->a_ctx;
+       struct sec_sqe3 *sec_sqe3 = &req->sec_sqe3;
+       int ret;
+
+       ret = sec_skcipher_bd_fill_v3(ctx, req);
+       if (unlikely(ret)) {
+               dev_err(ctx->dev, "skcipher bd3 fill is error!\n");
+               return ret;
+       }
+
+       if (ctx->c_ctx.c_mode == SEC_CMODE_CCM ||
+           ctx->c_ctx.c_mode == SEC_CMODE_GCM)
+               sec_auth_bd_fill_xcm_v3(auth_ctx, req->c_req.encrypt,
+                                       req, sec_sqe3);
+       else
+               sec_auth_bd_fill_ex_v3(auth_ctx, req->c_req.encrypt,
+                                      req, sec_sqe3);
 
        return 0;
 }
@@ -1254,7 +1731,8 @@ static int sec_process(struct sec_ctx *ctx, struct sec_req *req)
                goto err_uninit_req;
 
        /* Output IV as decrypto */
-       if (ctx->c_ctx.c_mode == SEC_CMODE_CBC && !req->c_req.encrypt)
+       if (!req->c_req.encrypt && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
+           ctx->c_ctx.c_mode == SEC_CMODE_CTR))
                sec_update_iv(req, ctx->alg_type);
 
        ret = ctx->req_op->bd_send(ctx, req);
@@ -1296,20 +1774,51 @@ static const struct sec_req_op sec_skcipher_req_ops = {
 static const struct sec_req_op sec_aead_req_ops = {
        .buf_map        = sec_aead_sgl_map,
        .buf_unmap      = sec_aead_sgl_unmap,
-       .do_transfer    = sec_aead_copy_iv,
+       .do_transfer    = sec_aead_set_iv,
        .bd_fill        = sec_aead_bd_fill,
        .bd_send        = sec_bd_send,
        .callback       = sec_aead_callback,
        .process        = sec_process,
 };
 
+static const struct sec_req_op sec_skcipher_req_ops_v3 = {
+       .buf_map        = sec_skcipher_sgl_map,
+       .buf_unmap      = sec_skcipher_sgl_unmap,
+       .do_transfer    = sec_skcipher_copy_iv,
+       .bd_fill        = sec_skcipher_bd_fill_v3,
+       .bd_send        = sec_bd_send,
+       .callback       = sec_skcipher_callback,
+       .process        = sec_process,
+};
+
+static const struct sec_req_op sec_aead_req_ops_v3 = {
+       .buf_map        = sec_aead_sgl_map,
+       .buf_unmap      = sec_aead_sgl_unmap,
+       .do_transfer    = sec_aead_set_iv,
+       .bd_fill        = sec_aead_bd_fill_v3,
+       .bd_send        = sec_bd_send,
+       .callback       = sec_aead_callback,
+       .process        = sec_process,
+};
+
 static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
 {
        struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+       int ret;
 
-       ctx->req_op = &sec_skcipher_req_ops;
+       ret = sec_skcipher_init(tfm);
+       if (ret)
+               return ret;
 
-       return sec_skcipher_init(tfm);
+       if (ctx->sec->qm.ver < QM_HW_V3) {
+               ctx->type_supported = SEC_BD_TYPE2;
+               ctx->req_op = &sec_skcipher_req_ops;
+       } else {
+               ctx->type_supported = SEC_BD_TYPE3;
+               ctx->req_op = &sec_skcipher_req_ops_v3;
+       }
+
+       return ret;
 }
 
 static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm)
@@ -1325,15 +1834,22 @@ static int sec_aead_init(struct crypto_aead *tfm)
        crypto_aead_set_reqsize(tfm, sizeof(struct sec_req));
        ctx->alg_type = SEC_AEAD;
        ctx->c_ctx.ivsize = crypto_aead_ivsize(tfm);
-       if (ctx->c_ctx.ivsize > SEC_IV_SIZE) {
-               dev_err(ctx->dev, "get error aead iv size!\n");
+       if (ctx->c_ctx.ivsize < SEC_AIV_SIZE ||
+           ctx->c_ctx.ivsize > SEC_IV_SIZE) {
+               pr_err("get error aead iv size!\n");
                return -EINVAL;
        }
 
-       ctx->req_op = &sec_aead_req_ops;
        ret = sec_ctx_base_init(ctx);
        if (ret)
                return ret;
+       if (ctx->sec->qm.ver < QM_HW_V3) {
+               ctx->type_supported = SEC_BD_TYPE2;
+               ctx->req_op = &sec_aead_req_ops;
+       } else {
+               ctx->type_supported = SEC_BD_TYPE3;
+               ctx->req_op = &sec_aead_req_ops_v3;
+       }
 
        ret = sec_auth_init(ctx);
        if (ret)
@@ -1391,6 +1907,41 @@ static void sec_aead_ctx_exit(struct crypto_aead *tfm)
        sec_aead_exit(tfm);
 }
 
+static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm)
+{
+       struct aead_alg *alg = crypto_aead_alg(tfm);
+       struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+       struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+       const char *aead_name = alg->base.cra_name;
+       int ret;
+
+       ret = sec_aead_init(tfm);
+       if (ret) {
+               dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n");
+               return ret;
+       }
+
+       a_ctx->fallback_aead_tfm = crypto_alloc_aead(aead_name, 0,
+                                                    CRYPTO_ALG_NEED_FALLBACK |
+                                                    CRYPTO_ALG_ASYNC);
+       if (IS_ERR(a_ctx->fallback_aead_tfm)) {
+               dev_err(ctx->dev, "aead driver alloc fallback tfm error!\n");
+               sec_aead_exit(tfm);
+               return PTR_ERR(a_ctx->fallback_aead_tfm);
+       }
+       a_ctx->fallback = false;
+
+       return 0;
+}
+
+static void sec_aead_xcm_ctx_exit(struct crypto_aead *tfm)
+{
+       struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+
+       crypto_free_aead(ctx->a_ctx.fallback_aead_tfm);
+       sec_aead_exit(tfm);
+}
+
 static int sec_aead_sha1_ctx_init(struct crypto_aead *tfm)
 {
        return sec_aead_ctx_init(tfm, "sha1");
@@ -1429,6 +1980,14 @@ static int sec_skcipher_cryptlen_ckeck(struct sec_ctx *ctx,
                        ret = -EINVAL;
                }
                break;
+       case SEC_CMODE_CFB:
+       case SEC_CMODE_OFB:
+       case SEC_CMODE_CTR:
+               if (unlikely(ctx->sec->qm.ver < QM_HW_V3)) {
+                       dev_err(dev, "skcipher HW version error!\n");
+                       ret = -EINVAL;
+               }
+               break;
        default:
                ret = -EINVAL;
        }
@@ -1442,7 +2001,8 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
        struct device *dev = ctx->dev;
        u8 c_alg = ctx->c_ctx.c_alg;
 
-       if (unlikely(!sk_req->src || !sk_req->dst)) {
+       if (unlikely(!sk_req->src || !sk_req->dst ||
+                    sk_req->cryptlen > MAX_INPUT_DATA_LEN)) {
                dev_err(dev, "skcipher input param error!\n");
                return -EINVAL;
        }
@@ -1468,6 +2028,37 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
        return -EINVAL;
 }
 
+static int sec_skcipher_soft_crypto(struct sec_ctx *ctx,
+                                   struct skcipher_request *sreq, bool encrypt)
+{
+       struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+       struct device *dev = ctx->dev;
+       int ret;
+
+       SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, c_ctx->fbtfm);
+
+       if (!c_ctx->fbtfm) {
+               dev_err(dev, "failed to check fallback tfm\n");
+               return -EINVAL;
+       }
+
+       skcipher_request_set_sync_tfm(subreq, c_ctx->fbtfm);
+
+       /* software need sync mode to do crypto */
+       skcipher_request_set_callback(subreq, sreq->base.flags,
+                                     NULL, NULL);
+       skcipher_request_set_crypt(subreq, sreq->src, sreq->dst,
+                                  sreq->cryptlen, sreq->iv);
+       if (encrypt)
+               ret = crypto_skcipher_encrypt(subreq);
+       else
+               ret = crypto_skcipher_decrypt(subreq);
+
+       skcipher_request_zero(subreq);
+
+       return ret;
+}
+
 static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(sk_req);
@@ -1475,8 +2066,11 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
        struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
        int ret;
 
-       if (!sk_req->cryptlen)
+       if (!sk_req->cryptlen) {
+               if (ctx->c_ctx.c_mode == SEC_CMODE_XTS)
+                       return -EINVAL;
                return 0;
+       }
 
        req->flag = sk_req->base.flags;
        req->c_req.sk_req = sk_req;
@@ -1487,6 +2081,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
        if (unlikely(ret))
                return -EINVAL;
 
+       if (unlikely(ctx->c_ctx.fallback))
+               return sec_skcipher_soft_crypto(ctx, sk_req, encrypt);
+
        return ctx->req_op->process(ctx, req);
 }
 
@@ -1507,7 +2104,9 @@ static int sec_skcipher_decrypt(struct skcipher_request *sk_req)
                .cra_name = sec_cra_name,\
                .cra_driver_name = "hisi_sec_"sec_cra_name,\
                .cra_priority = SEC_PRIORITY,\
-               .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,\
+               .cra_flags = CRYPTO_ALG_ASYNC |\
+                CRYPTO_ALG_ALLOCATES_MEMORY |\
+                CRYPTO_ALG_NEED_FALLBACK,\
                .cra_blocksize = blk_size,\
                .cra_ctxsize = sizeof(struct sec_ctx),\
                .cra_module = THIS_MODULE,\
@@ -1541,11 +2140,11 @@ static struct skcipher_alg sec_skciphers[] = {
                         AES_BLOCK_SIZE, AES_BLOCK_SIZE)
 
        SEC_SKCIPHER_ALG("ecb(des3_ede)", sec_setkey_3des_ecb,
-                        SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+                        SEC_DES3_3KEY_SIZE, SEC_DES3_3KEY_SIZE,
                         DES3_EDE_BLOCK_SIZE, 0)
 
        SEC_SKCIPHER_ALG("cbc(des3_ede)", sec_setkey_3des_cbc,
-                        SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+                        SEC_DES3_3KEY_SIZE, SEC_DES3_3KEY_SIZE,
                         DES3_EDE_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE)
 
        SEC_SKCIPHER_ALG("xts(sm4)", sec_setkey_sm4_xts,
@@ -1557,6 +2156,90 @@ static struct skcipher_alg sec_skciphers[] = {
                         AES_BLOCK_SIZE, AES_BLOCK_SIZE)
 };
 
+static struct skcipher_alg sec_skciphers_v3[] = {
+       SEC_SKCIPHER_ALG("ofb(aes)", sec_setkey_aes_ofb,
+                        AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+       SEC_SKCIPHER_ALG("cfb(aes)", sec_setkey_aes_cfb,
+                        AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+       SEC_SKCIPHER_ALG("ctr(aes)", sec_setkey_aes_ctr,
+                        AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+       SEC_SKCIPHER_ALG("ofb(sm4)", sec_setkey_sm4_ofb,
+                        AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+       SEC_SKCIPHER_ALG("cfb(sm4)", sec_setkey_sm4_cfb,
+                        AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+       SEC_SKCIPHER_ALG("ctr(sm4)", sec_setkey_sm4_ctr,
+                        AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+                        SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+};
+
+static int aead_iv_demension_check(struct aead_request *aead_req)
+{
+       u8 cl;
+
+       cl = aead_req->iv[0] + 1;
+       if (cl < IV_CL_MIN || cl > IV_CL_MAX)
+               return -EINVAL;
+
+       if (cl < IV_CL_MID && aead_req->cryptlen >> (BYTE_BITS * cl))
+               return -EOVERFLOW;
+
+       return 0;
+}
+
+static int sec_aead_spec_check(struct sec_ctx *ctx, struct sec_req *sreq)
+{
+       struct aead_request *req = sreq->aead_req.aead_req;
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       size_t authsize = crypto_aead_authsize(tfm);
+       u8 c_mode = ctx->c_ctx.c_mode;
+       struct device *dev = ctx->dev;
+       int ret;
+
+       if (unlikely(req->cryptlen + req->assoclen > MAX_INPUT_DATA_LEN ||
+           req->assoclen > SEC_MAX_AAD_LEN)) {
+               dev_err(dev, "aead input spec error!\n");
+               return -EINVAL;
+       }
+
+       if (unlikely((c_mode == SEC_CMODE_GCM && authsize < DES_BLOCK_SIZE) ||
+          (c_mode == SEC_CMODE_CCM && (authsize < MIN_MAC_LEN ||
+               authsize & MAC_LEN_MASK)))) {
+               dev_err(dev, "aead input mac length error!\n");
+               return -EINVAL;
+       }
+
+       if (c_mode == SEC_CMODE_CCM) {
+               ret = aead_iv_demension_check(req);
+               if (ret) {
+                       dev_err(dev, "aead input iv param error!\n");
+                       return ret;
+               }
+       }
+
+       if (sreq->c_req.encrypt)
+               sreq->c_req.c_len = req->cryptlen;
+       else
+               sreq->c_req.c_len = req->cryptlen - authsize;
+       if (c_mode == SEC_CMODE_CBC) {
+               if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) {
+                       dev_err(dev, "aead crypto length error!\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
 {
        struct aead_request *req = sreq->aead_req.aead_req;
@@ -1565,34 +2248,61 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
        struct device *dev = ctx->dev;
        u8 c_alg = ctx->c_ctx.c_alg;
 
-       if (unlikely(!req->src || !req->dst || !req->cryptlen ||
-               req->assoclen > SEC_MAX_AAD_LEN)) {
+       if (unlikely(!req->src || !req->dst)) {
                dev_err(dev, "aead input param error!\n");
                return -EINVAL;
        }
 
+       if (ctx->sec->qm.ver == QM_HW_V2) {
+               if (unlikely(!req->cryptlen || (!sreq->c_req.encrypt &&
+                   req->cryptlen <= authsize))) {
+                       dev_err(dev, "Kunpeng920 not support 0 length!\n");
+                       ctx->a_ctx.fallback = true;
+                       return -EINVAL;
+               }
+       }
+
+       /* Support AES or SM4 */
+       if (unlikely(c_alg != SEC_CALG_AES && c_alg != SEC_CALG_SM4)) {
+               dev_err(dev, "aead crypto alg error!\n");
+               return -EINVAL;
+       }
+
+       if (unlikely(sec_aead_spec_check(ctx, sreq)))
+               return -EINVAL;
+
        if (ctx->pbuf_supported && (req->cryptlen + req->assoclen) <=
                SEC_PBUF_SZ)
                sreq->use_pbuf = true;
        else
                sreq->use_pbuf = false;
 
-       /* Support AES only */
-       if (unlikely(c_alg != SEC_CALG_AES)) {
-               dev_err(dev, "aead crypto alg error!\n");
-               return -EINVAL;
-       }
-       if (sreq->c_req.encrypt)
-               sreq->c_req.c_len = req->cryptlen;
-       else
-               sreq->c_req.c_len = req->cryptlen - authsize;
+       return 0;
+}
 
-       if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) {
-               dev_err(dev, "aead crypto length error!\n");
+static int sec_aead_soft_crypto(struct sec_ctx *ctx,
+                               struct aead_request *aead_req,
+                               bool encrypt)
+{
+       struct aead_request *subreq = aead_request_ctx(aead_req);
+       struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+       struct device *dev = ctx->dev;
+
+       /* Kunpeng920 aead mode not support input 0 size */
+       if (!a_ctx->fallback_aead_tfm) {
+               dev_err(dev, "aead fallback tfm is NULL!\n");
                return -EINVAL;
        }
 
-       return 0;
+       aead_request_set_tfm(subreq, a_ctx->fallback_aead_tfm);
+       aead_request_set_callback(subreq, aead_req->base.flags,
+                                 aead_req->base.complete, aead_req->base.data);
+       aead_request_set_crypt(subreq, aead_req->src, aead_req->dst,
+                              aead_req->cryptlen, aead_req->iv);
+       aead_request_set_ad(subreq, aead_req->assoclen);
+
+       return encrypt ? crypto_aead_encrypt(subreq) :
+                  crypto_aead_decrypt(subreq);
 }
 
 static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
@@ -1608,8 +2318,11 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
        req->ctx = ctx;
 
        ret = sec_aead_param_check(ctx, req);
-       if (unlikely(ret))
+       if (unlikely(ret)) {
+               if (ctx->a_ctx.fallback)
+                       return sec_aead_soft_crypto(ctx, a_req, encrypt);
                return -EINVAL;
+       }
 
        return ctx->req_op->process(ctx, req);
 }
@@ -1624,14 +2337,16 @@ static int sec_aead_decrypt(struct aead_request *a_req)
        return sec_aead_crypto(a_req, false);
 }
 
-#define SEC_AEAD_GEN_ALG(sec_cra_name, sec_set_key, ctx_init,\
+#define SEC_AEAD_ALG(sec_cra_name, sec_set_key, ctx_init,\
                         ctx_exit, blk_size, iv_size, max_authsize)\
 {\
        .base = {\
                .cra_name = sec_cra_name,\
                .cra_driver_name = "hisi_sec_"sec_cra_name,\
                .cra_priority = SEC_PRIORITY,\
-               .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,\
+               .cra_flags = CRYPTO_ALG_ASYNC |\
+                CRYPTO_ALG_ALLOCATES_MEMORY |\
+                CRYPTO_ALG_NEED_FALLBACK,\
                .cra_blocksize = blk_size,\
                .cra_ctxsize = sizeof(struct sec_ctx),\
                .cra_module = THIS_MODULE,\
@@ -1639,28 +2354,46 @@ static int sec_aead_decrypt(struct aead_request *a_req)
        .init = ctx_init,\
        .exit = ctx_exit,\
        .setkey = sec_set_key,\
+       .setauthsize = sec_aead_setauthsize,\
        .decrypt = sec_aead_decrypt,\
        .encrypt = sec_aead_encrypt,\
        .ivsize = iv_size,\
        .maxauthsize = max_authsize,\
 }
 
-#define SEC_AEAD_ALG(algname, keyfunc, aead_init, blksize, ivsize, authsize)\
-       SEC_AEAD_GEN_ALG(algname, keyfunc, aead_init,\
-                       sec_aead_ctx_exit, blksize, ivsize, authsize)
-
 static struct aead_alg sec_aeads[] = {
        SEC_AEAD_ALG("authenc(hmac(sha1),cbc(aes))",
                     sec_setkey_aes_cbc_sha1, sec_aead_sha1_ctx_init,
-                    AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA1_DIGEST_SIZE),
+                    sec_aead_ctx_exit, AES_BLOCK_SIZE,
+                    AES_BLOCK_SIZE, SHA1_DIGEST_SIZE),
 
        SEC_AEAD_ALG("authenc(hmac(sha256),cbc(aes))",
                     sec_setkey_aes_cbc_sha256, sec_aead_sha256_ctx_init,
-                    AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA256_DIGEST_SIZE),
+                    sec_aead_ctx_exit, AES_BLOCK_SIZE,
+                    AES_BLOCK_SIZE, SHA256_DIGEST_SIZE),
 
        SEC_AEAD_ALG("authenc(hmac(sha512),cbc(aes))",
                     sec_setkey_aes_cbc_sha512, sec_aead_sha512_ctx_init,
-                    AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA512_DIGEST_SIZE),
+                    sec_aead_ctx_exit, AES_BLOCK_SIZE,
+                    AES_BLOCK_SIZE, SHA512_DIGEST_SIZE),
+
+       SEC_AEAD_ALG("ccm(aes)", sec_setkey_aes_ccm, sec_aead_xcm_ctx_init,
+                    sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+                    AES_BLOCK_SIZE, AES_BLOCK_SIZE),
+
+       SEC_AEAD_ALG("gcm(aes)", sec_setkey_aes_gcm, sec_aead_xcm_ctx_init,
+                    sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+                    SEC_AIV_SIZE, AES_BLOCK_SIZE)
+};
+
+static struct aead_alg sec_aeads_v3[] = {
+       SEC_AEAD_ALG("ccm(sm4)", sec_setkey_sm4_ccm, sec_aead_xcm_ctx_init,
+                    sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+                    AES_BLOCK_SIZE, AES_BLOCK_SIZE),
+
+       SEC_AEAD_ALG("gcm(sm4)", sec_setkey_sm4_gcm, sec_aead_xcm_ctx_init,
+                    sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+                    SEC_AIV_SIZE, AES_BLOCK_SIZE)
 };
 
 int sec_register_to_crypto(struct hisi_qm *qm)
@@ -1673,16 +2406,45 @@ int sec_register_to_crypto(struct hisi_qm *qm)
        if (ret)
                return ret;
 
+       if (qm->ver > QM_HW_V2) {
+               ret = crypto_register_skciphers(sec_skciphers_v3,
+                                               ARRAY_SIZE(sec_skciphers_v3));
+               if (ret)
+                       goto reg_skcipher_fail;
+       }
+
        ret = crypto_register_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
        if (ret)
-               crypto_unregister_skciphers(sec_skciphers,
-                                           ARRAY_SIZE(sec_skciphers));
+               goto reg_aead_fail;
+       if (qm->ver > QM_HW_V2) {
+               ret = crypto_register_aeads(sec_aeads_v3, ARRAY_SIZE(sec_aeads_v3));
+               if (ret)
+                       goto reg_aead_v3_fail;
+       }
+       return ret;
+
+reg_aead_v3_fail:
+       crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+reg_aead_fail:
+       if (qm->ver > QM_HW_V2)
+               crypto_unregister_skciphers(sec_skciphers_v3,
+                                           ARRAY_SIZE(sec_skciphers_v3));
+reg_skcipher_fail:
+       crypto_unregister_skciphers(sec_skciphers,
+                                   ARRAY_SIZE(sec_skciphers));
        return ret;
 }
 
 void sec_unregister_from_crypto(struct hisi_qm *qm)
 {
+       if (qm->ver > QM_HW_V2)
+               crypto_unregister_aeads(sec_aeads_v3,
+                                       ARRAY_SIZE(sec_aeads_v3));
+       crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+
+       if (qm->ver > QM_HW_V2)
+               crypto_unregister_skciphers(sec_skciphers_v3,
+                                           ARRAY_SIZE(sec_skciphers_v3));
        crypto_unregister_skciphers(sec_skciphers,
                                    ARRAY_SIZE(sec_skciphers));
-       crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
 }
index 9c78eda..9f71c35 100644 (file)
@@ -4,9 +4,11 @@
 #ifndef __HISI_SEC_V2_CRYPTO_H
 #define __HISI_SEC_V2_CRYPTO_H
 
+#define SEC_AIV_SIZE           12
 #define SEC_IV_SIZE            24
 #define SEC_MAX_KEY_SIZE       64
 #define SEC_COMM_SCENE         0
+#define SEC_MIN_BLOCK_SZ       1
 
 enum sec_calg {
        SEC_CALG_3DES = 0x1,
@@ -21,6 +23,11 @@ enum sec_hash_alg {
 };
 
 enum sec_mac_len {
+       SEC_HMAC_CCM_MAC   = 16,
+       SEC_HMAC_GCM_MAC   = 16,
+       SEC_SM3_MAC        = 32,
+       SEC_HMAC_SM3_MAC   = 32,
+       SEC_HMAC_MD5_MAC   = 16,
        SEC_HMAC_SHA1_MAC   = 20,
        SEC_HMAC_SHA256_MAC = 32,
        SEC_HMAC_SHA512_MAC = 64,
@@ -29,7 +36,11 @@ enum sec_mac_len {
 enum sec_cmode {
        SEC_CMODE_ECB    = 0x0,
        SEC_CMODE_CBC    = 0x1,
+       SEC_CMODE_CFB    = 0x2,
+       SEC_CMODE_OFB    = 0x3,
        SEC_CMODE_CTR    = 0x4,
+       SEC_CMODE_CCM    = 0x5,
+       SEC_CMODE_GCM    = 0x6,
        SEC_CMODE_XTS    = 0x7,
 };
 
@@ -44,6 +55,7 @@ enum sec_ckey_type {
 enum sec_bd_type {
        SEC_BD_TYPE1 = 0x1,
        SEC_BD_TYPE2 = 0x2,
+       SEC_BD_TYPE3 = 0x3,
 };
 
 enum sec_auth {
@@ -63,6 +75,24 @@ enum sec_addr_type {
        SEC_PRP  = 0x2,
 };
 
+struct bd_status {
+       u64 tag;
+       u8 done;
+       u8 err_type;
+       u16 flag;
+       u16 icv;
+};
+
+enum {
+       AUTHPAD_PAD,
+       AUTHPAD_NOPAD,
+};
+
+enum {
+       AIGEN_GEN,
+       AIGEN_NOGEN,
+};
+
 struct sec_sqe_type2 {
        /*
         * mac_len: 0~4 bits
@@ -209,6 +239,169 @@ struct sec_sqe {
        struct sec_sqe_type2 type2;
 };
 
+struct bd3_auth_ivin {
+       __le64 a_ivin_addr;
+       __le32 rsvd0;
+       __le32 rsvd1;
+} __packed __aligned(4);
+
+struct bd3_skip_data {
+       __le32 rsvd0;
+
+       /*
+        * gran_num: 0~15 bits
+        * reserved: 16~31 bits
+        */
+       __le32 gran_num;
+
+       /*
+        * src_skip_data_len: 0~24 bits
+        * reserved: 25~31 bits
+        */
+       __le32 src_skip_data_len;
+
+       /*
+        * dst_skip_data_len: 0~24 bits
+        * reserved: 25~31 bits
+        */
+       __le32 dst_skip_data_len;
+};
+
+struct bd3_stream_scene {
+       __le64 c_ivin_addr;
+       __le64 long_a_data_len;
+
+       /*
+        * auth_pad: 0~1 bits
+        * stream_protocol: 2~4 bits
+        * reserved: 5~7 bits
+        */
+       __u8 stream_auth_pad;
+       __u8 plaintext_type;
+       __le16 pad_len_1p3;
+} __packed __aligned(4);
+
+struct bd3_no_scene {
+       __le64 c_ivin_addr;
+       __le32 rsvd0;
+       __le32 rsvd1;
+       __le32 rsvd2;
+} __packed __aligned(4);
+
+struct bd3_check_sum {
+       __u8 rsvd0;
+       __u8 hac_sva_status;
+       __le16 check_sum_i;
+};
+
+struct bd3_tls_type_back {
+       __u8 tls_1p3_type_back;
+       __u8 hac_sva_status;
+       __le16 pad_len_1p3_back;
+};
+
+struct sec_sqe3 {
+       /*
+        * type: 0~3 bit
+        * bd_invalid: 4 bit
+        * scene: 5~8 bit
+        * de: 9~10 bit
+        * src_addr_type: 11~13 bit
+        * dst_addr_type: 14~16 bit
+        * mac_addr_type: 17~19 bit
+        * reserved: 20~31 bits
+        */
+       __le32 bd_param;
+
+       /*
+        * cipher: 0~1 bits
+        * ci_gen: 2~3 bit
+        * c_icv_len: 4~9 bit
+        * c_width: 10~12 bits
+        * c_key_len: 13~15 bits
+        */
+       __le16 c_icv_key;
+
+       /*
+        * c_mode : 0~3 bits
+        * c_alg : 4~7 bits
+        */
+       __u8 c_mode_alg;
+
+       /*
+        * nonce_len : 0~3 bits
+        * huk : 4 bits
+        * cal_iv_addr_en : 5 bits
+        * seq : 6 bits
+        * reserved : 7 bits
+        */
+       __u8 huk_iv_seq;
+
+       __le64 tag;
+       __le64 data_src_addr;
+       __le64 a_key_addr;
+       union {
+               struct bd3_auth_ivin auth_ivin;
+               struct bd3_skip_data skip_data;
+       };
+
+       __le64 c_key_addr;
+
+       /*
+        * auth: 0~1 bits
+        * ai_gen: 2~3 bits
+        * mac_len: 4~8 bits
+        * akey_len: 9~14 bits
+        * a_alg: 15~20 bits
+        * key_sel: 21~24 bits
+        * updata_key: 25 bits
+        * reserved: 26~31 bits
+        */
+       __le32 auth_mac_key;
+       __le32 salt;
+       __le16 auth_src_offset;
+       __le16 cipher_src_offset;
+
+       /*
+        * auth_len: 0~23 bit
+        * auth_key_offset: 24~31 bits
+        */
+       __le32 a_len_key;
+
+       /*
+        * cipher_len: 0~23 bit
+        * auth_ivin_offset: 24~31 bits
+        */
+       __le32 c_len_ivin;
+       __le64 data_dst_addr;
+       __le64 mac_addr;
+       union {
+               struct bd3_stream_scene stream_scene;
+               struct bd3_no_scene no_scene;
+       };
+
+       /*
+        * done: 0 bit
+        * icv: 1~3 bit
+        * csc: 4~6 bit
+        * flag: 7~10 bit
+        * reserved: 11~15 bit
+        */
+       __le16 done_flag;
+       __u8 error_type;
+       __u8 warning_type;
+       union {
+               __le32 mac_i;
+               __le32 kek_key_addr_l;
+       };
+       union {
+               __le32 kek_key_addr_h;
+               struct bd3_check_sum check_sum;
+               struct bd3_tls_type_back tls_type_back;
+       };
+       __le32 counter;
+} __packed __aligned(4);
+
 int sec_register_to_crypto(struct hisi_qm *qm);
 void sec_unregister_from_crypto(struct hisi_qm *qm);
 #endif
index 6f0062d..d120ce3 100644 (file)
@@ -52,6 +52,7 @@
 #define SEC_RAS_CE_ENB_MSK             0x88
 #define SEC_RAS_FE_ENB_MSK             0x0
 #define SEC_RAS_NFE_ENB_MSK            0x7c177
+#define SEC_OOO_SHUTDOWN_SEL           0x301014
 #define SEC_RAS_DISABLE                0x0
 #define SEC_MEM_START_INIT_REG 0x301100
 #define SEC_MEM_INIT_DONE_REG          0x301104
 #define SEC_USER1_SMMU_MASK            (~SEC_USER1_SVA_SET)
 #define SEC_CORE_INT_STATUS_M_ECC      BIT(2)
 
+#define SEC_PREFETCH_CFG               0x301130
+#define SEC_SVA_TRANS                  0x301EC4
+#define SEC_PREFETCH_ENABLE            (~(BIT(0) | BIT(1) | BIT(11)))
+#define SEC_PREFETCH_DISABLE           BIT(1)
+#define SEC_SVA_DISABLE_READY          (BIT(7) | BIT(11))
+
 #define SEC_DELAY_10_US                        10
 #define SEC_POLL_TIMEOUT_US            1000
 #define SEC_DBGFS_VAL_MAX_LEN          20
@@ -91,6 +98,7 @@
 
 #define SEC_SQE_MASK_OFFSET            64
 #define SEC_SQE_MASK_LEN               48
+#define SEC_SHAPER_TYPE_RATE           128
 
 struct sec_hw_error {
        u32 int_msk;
@@ -331,6 +339,42 @@ static u8 sec_get_endian(struct hisi_qm *qm)
                return SEC_64BE;
 }
 
+static void sec_open_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       /* Enable prefetch */
+       val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG);
+       val &= SEC_PREFETCH_ENABLE;
+       writel(val, qm->io_base + SEC_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + SEC_PREFETCH_CFG,
+                                        val, !(val & SEC_PREFETCH_DISABLE),
+                                        SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void sec_close_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG);
+       val |= SEC_PREFETCH_DISABLE;
+       writel(val, qm->io_base + SEC_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + SEC_SVA_TRANS,
+                                        val, !(val & SEC_SVA_DISABLE_READY),
+                                        SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to close sva prefetch\n");
+}
+
 static int sec_engine_init(struct hisi_qm *qm)
 {
        int ret;
@@ -430,53 +474,60 @@ static void sec_debug_regs_clear(struct hisi_qm *qm)
        hisi_qm_debug_regs_clear(qm);
 }
 
-static void sec_hw_error_enable(struct hisi_qm *qm)
+static void sec_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
 {
-       u32 val;
+       u32 val1, val2;
+
+       val1 = readl(qm->io_base + SEC_CONTROL_REG);
+       if (enable) {
+               val1 |= SEC_AXI_SHUTDOWN_ENABLE;
+               val2 = SEC_RAS_NFE_ENB_MSK;
+       } else {
+               val1 &= SEC_AXI_SHUTDOWN_DISABLE;
+               val2 = 0x0;
+       }
+
+       if (qm->ver > QM_HW_V2)
+               writel(val2, qm->io_base + SEC_OOO_SHUTDOWN_SEL);
+
+       writel(val1, qm->io_base + SEC_CONTROL_REG);
+}
 
+static void sec_hw_error_enable(struct hisi_qm *qm)
+{
        if (qm->ver == QM_HW_V1) {
                writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
                pci_info(qm->pdev, "V1 not support hw error handle\n");
                return;
        }
 
-       val = readl(qm->io_base + SEC_CONTROL_REG);
-
        /* clear SEC hw error source if having */
        writel(SEC_CORE_INT_CLEAR, qm->io_base + SEC_CORE_INT_SOURCE);
 
-       /* enable SEC hw error interrupts */
-       writel(SEC_CORE_INT_ENABLE, qm->io_base + SEC_CORE_INT_MASK);
-
        /* enable RAS int */
        writel(SEC_RAS_CE_ENB_MSK, qm->io_base + SEC_RAS_CE_REG);
        writel(SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_RAS_FE_REG);
        writel(SEC_RAS_NFE_ENB_MSK, qm->io_base + SEC_RAS_NFE_REG);
 
-       /* enable SEC block master OOO when m-bit error occur */
-       val = val | SEC_AXI_SHUTDOWN_ENABLE;
+       /* enable SEC block master OOO when nfe occurs on Kunpeng930 */
+       sec_master_ooo_ctrl(qm, true);
 
-       writel(val, qm->io_base + SEC_CONTROL_REG);
+       /* enable SEC hw error interrupts */
+       writel(SEC_CORE_INT_ENABLE, qm->io_base + SEC_CORE_INT_MASK);
 }
 
 static void sec_hw_error_disable(struct hisi_qm *qm)
 {
-       u32 val;
+       /* disable SEC hw error interrupts */
+       writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
 
-       val = readl(qm->io_base + SEC_CONTROL_REG);
+       /* disable SEC block master OOO when nfe occurs on Kunpeng930 */
+       sec_master_ooo_ctrl(qm, false);
 
        /* disable RAS int */
        writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_CE_REG);
        writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_FE_REG);
        writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_NFE_REG);
-
-       /* disable SEC hw error interrupts */
-       writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
-
-       /* disable SEC block master OOO when m-bit error occur */
-       val = val & SEC_AXI_SHUTDOWN_DISABLE;
-
-       writel(val, qm->io_base + SEC_CONTROL_REG);
 }
 
 static u32 sec_clear_enable_read(struct sec_debug_file *file)
@@ -743,6 +794,8 @@ static const struct hisi_qm_err_ini sec_err_ini = {
        .clear_dev_hw_err_status = sec_clear_hw_err_status,
        .log_dev_hw_err         = sec_log_hw_error,
        .open_axi_master_ooo    = sec_open_axi_master_ooo,
+       .open_sva_prefetch      = sec_open_sva_prefetch,
+       .close_sva_prefetch     = sec_close_sva_prefetch,
        .err_info_init          = sec_err_info_init,
 };
 
@@ -758,6 +811,7 @@ static int sec_pf_probe_init(struct sec_dev *sec)
        if (ret)
                return ret;
 
+       sec_open_sva_prefetch(qm);
        hisi_qm_dev_err_init(qm);
        sec_debug_regs_clear(qm);
 
@@ -821,6 +875,7 @@ static void sec_qm_uninit(struct hisi_qm *qm)
 
 static int sec_probe_init(struct sec_dev *sec)
 {
+       u32 type_rate = SEC_SHAPER_TYPE_RATE;
        struct hisi_qm *qm = &sec->qm;
        int ret;
 
@@ -828,6 +883,11 @@ static int sec_probe_init(struct sec_dev *sec)
                ret = sec_pf_probe_init(sec);
                if (ret)
                        return ret;
+               /* enable shaper type 0 */
+               if (qm->ver >= QM_HW_V3) {
+                       type_rate |= QM_SHAPER_ENABLE;
+                       qm->type_rate = type_rate;
+               }
        }
 
        return 0;
index 2178b40..f8482ce 100644 (file)
@@ -68,6 +68,7 @@
 #define HZIP_CORE_INT_RAS_CE_ENABLE    0x1
 #define HZIP_CORE_INT_RAS_NFE_ENB      0x301164
 #define HZIP_CORE_INT_RAS_FE_ENB        0x301168
+#define HZIP_OOO_SHUTDOWN_SEL          0x30120C
 #define HZIP_CORE_INT_RAS_NFE_ENABLE   0x1FFE
 #define HZIP_SRAM_ECC_ERR_NUM_SHIFT    16
 #define HZIP_SRAM_ECC_ERR_ADDR_SHIFT   24
 #define HZIP_RD_CNT_CLR_CE_EN          (HZIP_CNT_CLR_CE_EN | \
                                         HZIP_RO_CNT_CLR_CE_EN)
 
+#define HZIP_PREFETCH_CFG              0x3011B0
+#define HZIP_SVA_TRANS                 0x3011C4
+#define HZIP_PREFETCH_ENABLE           (~(BIT(26) | BIT(17) | BIT(0)))
+#define HZIP_SVA_PREFETCH_DISABLE      BIT(26)
+#define HZIP_SVA_DISABLE_READY         (BIT(26) | BIT(30))
+#define HZIP_SHAPER_RATE_COMPRESS      252
+#define HZIP_SHAPER_RATE_DECOMPRESS    229
+#define HZIP_DELAY_1_US                1
+#define HZIP_POLL_TIMEOUT_US   1000
+
 static const char hisi_zip_name[] = "hisi_zip";
 static struct dentry *hzip_debugfs_root;
 
@@ -262,6 +273,45 @@ int zip_create_qps(struct hisi_qp **qps, int qp_num, int node)
        return hisi_qm_alloc_qps_node(&zip_devices, qp_num, 0, node, qps);
 }
 
+static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       /* Enable prefetch */
+       val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG);
+       val &= HZIP_PREFETCH_ENABLE;
+       writel(val, qm->io_base + HZIP_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_PREFETCH_CFG,
+                                        val, !(val & HZIP_SVA_PREFETCH_DISABLE),
+                                        HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void hisi_zip_close_sva_prefetch(struct hisi_qm *qm)
+{
+       u32 val;
+       int ret;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG);
+       val |= HZIP_SVA_PREFETCH_DISABLE;
+       writel(val, qm->io_base + HZIP_PREFETCH_CFG);
+
+       ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_SVA_TRANS,
+                                        val, !(val & HZIP_SVA_DISABLE_READY),
+                                        HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US);
+       if (ret)
+               pci_err(qm->pdev, "failed to close sva prefetch\n");
+}
+
 static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
 {
        void __iomem *base = qm->io_base;
@@ -312,10 +362,27 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
        return 0;
 }
 
-static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
+static void hisi_zip_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
 {
-       u32 val;
+       u32 val1, val2;
+
+       val1 = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+       if (enable) {
+               val1 |= HZIP_AXI_SHUTDOWN_ENABLE;
+               val2 = HZIP_CORE_INT_RAS_NFE_ENABLE;
+       } else {
+               val1 &= ~HZIP_AXI_SHUTDOWN_ENABLE;
+               val2 = 0x0;
+       }
+
+       if (qm->ver > QM_HW_V2)
+               writel(val2, qm->io_base + HZIP_OOO_SHUTDOWN_SEL);
 
+       writel(val1, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+}
+
+static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
+{
        if (qm->ver == QM_HW_V1) {
                writel(HZIP_CORE_INT_MASK_ALL,
                       qm->io_base + HZIP_CORE_INT_MASK_REG);
@@ -333,26 +400,20 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
        writel(HZIP_CORE_INT_RAS_NFE_ENABLE,
               qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB);
 
+       /* enable ZIP block master OOO when nfe occurs on Kunpeng930 */
+       hisi_zip_master_ooo_ctrl(qm, true);
+
        /* enable ZIP hw error interrupts */
        writel(0, qm->io_base + HZIP_CORE_INT_MASK_REG);
-
-       /* enable ZIP block master OOO when m-bit error occur */
-       val = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
-       val = val | HZIP_AXI_SHUTDOWN_ENABLE;
-       writel(val, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
 }
 
 static void hisi_zip_hw_error_disable(struct hisi_qm *qm)
 {
-       u32 val;
-
        /* disable ZIP hw error interrupts */
        writel(HZIP_CORE_INT_MASK_ALL, qm->io_base + HZIP_CORE_INT_MASK_REG);
 
-       /* disable ZIP block master OOO when m-bit error occur */
-       val = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
-       val = val & ~HZIP_AXI_SHUTDOWN_ENABLE;
-       writel(val, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+       /* disable ZIP block master OOO when nfe occurs on Kunpeng930 */
+       hisi_zip_master_ooo_ctrl(qm, false);
 }
 
 static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file)
@@ -684,6 +745,8 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = {
        .log_dev_hw_err         = hisi_zip_log_hw_error,
        .open_axi_master_ooo    = hisi_zip_open_axi_master_ooo,
        .close_axi_master_ooo   = hisi_zip_close_axi_master_ooo,
+       .open_sva_prefetch      = hisi_zip_open_sva_prefetch,
+       .close_sva_prefetch     = hisi_zip_close_sva_prefetch,
        .err_info_init          = hisi_zip_err_info_init,
 };
 
@@ -702,6 +765,7 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
        qm->err_ini->err_info_init(qm);
 
        hisi_zip_set_user_domain_and_cache(qm);
+       hisi_zip_open_sva_prefetch(qm);
        hisi_qm_dev_err_init(qm);
        hisi_zip_debug_regs_clear(qm);
 
@@ -761,6 +825,7 @@ static void hisi_zip_qm_uninit(struct hisi_qm *qm)
 
 static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
 {
+       u32 type_rate = HZIP_SHAPER_RATE_COMPRESS;
        struct hisi_qm *qm = &hisi_zip->qm;
        int ret;
 
@@ -768,6 +833,14 @@ static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
                ret = hisi_zip_pf_probe_init(hisi_zip);
                if (ret)
                        return ret;
+               /* enable shaper type 0 */
+               if (qm->ver >= QM_HW_V3) {
+                       type_rate |= QM_SHAPER_ENABLE;
+
+                       /* ZIP need to enable shaper type 1 */
+                       type_rate |= HZIP_SHAPER_RATE_DECOMPRESS << QM_SHAPER_TYPE1_OFFSET;
+                       qm->type_rate = type_rate;
+               }
        }
 
        return 0;
index 0616e36..35fc5ee 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include <crypto/ctr.h>
 #include <crypto/internal/des.h>
 #define MOD_AES256  (0x0a00 | KEYLEN_256)
 
 #define MAX_IVLEN   16
-#define NPE_ID      2  /* NPE C */
 #define NPE_QLEN    16
 /* Space for registering when the first
  * NPE_QLEN crypt_ctl are busy */
 #define NPE_QLEN_TOTAL 64
 
-#define SEND_QID    29
-#define RECV_QID    30
-
 #define CTL_FLAG_UNUSED                0x0000
 #define CTL_FLAG_USED          0x1000
 #define CTL_FLAG_PERFORM_ABLK  0x0001
@@ -136,7 +133,7 @@ struct crypt_ctl {
        u32 crypto_ctx;         /* NPE Crypto Param structure address */
 
        /* Used by Host: 4*4 bytes*/
-       unsigned ctl_flags;
+       unsigned int ctl_flags;
        union {
                struct skcipher_request *ablk_req;
                struct aead_request *aead_req;
@@ -149,6 +146,9 @@ struct crypt_ctl {
 struct ablk_ctx {
        struct buffer_desc *src;
        struct buffer_desc *dst;
+       u8 iv[MAX_IVLEN];
+       bool encrypt;
+       struct skcipher_request fallback_req;   // keep at the end
 };
 
 struct aead_ctx {
@@ -181,9 +181,10 @@ struct ixp_ctx {
        u8 enckey[MAX_KEYLEN];
        u8 salt[MAX_IVLEN];
        u8 nonce[CTR_RFC3686_NONCE_SIZE];
-       unsigned salted;
+       unsigned int salted;
        atomic_t configuring;
        struct completion completion;
+       struct crypto_skcipher *fallback_tfm;
 };
 
 struct ixp_alg {
@@ -209,6 +210,7 @@ static const struct ix_hash_algo hash_alg_md5 = {
        .icv            = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
                          "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
 };
+
 static const struct ix_hash_algo hash_alg_sha1 = {
        .cfgword        = 0x00000005,
        .icv            = "\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA"
@@ -216,16 +218,17 @@ static const struct ix_hash_algo hash_alg_sha1 = {
 };
 
 static struct npe *npe_c;
-static struct dma_pool *buffer_pool = NULL;
-static struct dma_pool *ctx_pool = NULL;
 
-static struct crypt_ctl *crypt_virt = NULL;
+static unsigned int send_qid;
+static unsigned int recv_qid;
+static struct dma_pool *buffer_pool;
+static struct dma_pool *ctx_pool;
+
+static struct crypt_ctl *crypt_virt;
 static dma_addr_t crypt_phys;
 
 static int support_aes = 1;
 
-#define DRIVER_NAME "ixp4xx_crypto"
-
 static struct platform_device *pdev;
 
 static inline dma_addr_t crypt_virt2phys(struct crypt_ctl *virt)
@@ -240,12 +243,12 @@ static inline struct crypt_ctl *crypt_phys2virt(dma_addr_t phys)
 
 static inline u32 cipher_cfg_enc(struct crypto_tfm *tfm)
 {
-       return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_enc;
+       return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_enc;
 }
 
 static inline u32 cipher_cfg_dec(struct crypto_tfm *tfm)
 {
-       return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_dec;
+       return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_dec;
 }
 
 static inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm)
@@ -256,6 +259,7 @@ static inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm)
 static int setup_crypt_desc(void)
 {
        struct device *dev = &pdev->dev;
+
        BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64);
        crypt_virt = dma_alloc_coherent(dev,
                                        NPE_QLEN * sizeof(struct crypt_ctl),
@@ -269,7 +273,7 @@ static DEFINE_SPINLOCK(desc_lock);
 static struct crypt_ctl *get_crypt_desc(void)
 {
        int i;
-       static int idx = 0;
+       static int idx;
        unsigned long flags;
 
        spin_lock_irqsave(&desc_lock, flags);
@@ -286,7 +290,7 @@ static struct crypt_ctl *get_crypt_desc(void)
                        idx = 0;
                crypt_virt[i].ctl_flags = CTL_FLAG_USED;
                spin_unlock_irqrestore(&desc_lock, flags);
-               return crypt_virt +i;
+               return crypt_virt + i;
        } else {
                spin_unlock_irqrestore(&desc_lock, flags);
                return NULL;
@@ -314,7 +318,7 @@ static struct crypt_ctl *get_crypt_desc_emerg(void)
                        idx = NPE_QLEN;
                crypt_virt[i].ctl_flags = CTL_FLAG_USED;
                spin_unlock_irqrestore(&emerg_lock, flags);
-               return crypt_virt +i;
+               return crypt_virt + i;
        } else {
                spin_unlock_irqrestore(&emerg_lock, flags);
                return NULL;
@@ -330,7 +334,7 @@ static void free_buf_chain(struct device *dev, struct buffer_desc *buf,
 
                buf1 = buf->next;
                phys1 = buf->phys_next;
-               dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir);
+               dma_unmap_single(dev, buf->phys_addr, buf->buf_len, buf->dir);
                dma_pool_free(buffer_pool, buf, phys);
                buf = buf1;
                phys = phys1;
@@ -348,8 +352,8 @@ static void finish_scattered_hmac(struct crypt_ctl *crypt)
        int decryptlen = req->assoclen + req->cryptlen - authsize;
 
        if (req_ctx->encrypt) {
-               scatterwalk_map_and_copy(req_ctx->hmac_virt,
-                       req->dst, decryptlen, authsize, 1);
+               scatterwalk_map_and_copy(req_ctx->hmac_virt, req->dst,
+                                        decryptlen, authsize, 1);
        }
        dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes);
 }
@@ -372,19 +376,33 @@ static void one_packet(dma_addr_t phys)
 
                free_buf_chain(dev, req_ctx->src, crypt->src_buf);
                free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
-               if (req_ctx->hmac_virt) {
+               if (req_ctx->hmac_virt)
                        finish_scattered_hmac(crypt);
-               }
+
                req->base.complete(&req->base, failed);
                break;
        }
        case CTL_FLAG_PERFORM_ABLK: {
                struct skcipher_request *req = crypt->data.ablk_req;
                struct ablk_ctx *req_ctx = skcipher_request_ctx(req);
+               struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+               unsigned int ivsize = crypto_skcipher_ivsize(tfm);
+               unsigned int offset;
+
+               if (ivsize > 0) {
+                       offset = req->cryptlen - ivsize;
+                       if (req_ctx->encrypt) {
+                               scatterwalk_map_and_copy(req->iv, req->dst,
+                                                        offset, ivsize, 0);
+                       } else {
+                               memcpy(req->iv, req_ctx->iv, ivsize);
+                               memzero_explicit(req_ctx->iv, ivsize);
+                       }
+               }
 
-               if (req_ctx->dst) {
+               if (req_ctx->dst)
                        free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
-               }
+
                free_buf_chain(dev, req_ctx->src, crypt->src_buf);
                req->base.complete(&req->base, failed);
                break;
@@ -392,14 +410,14 @@ static void one_packet(dma_addr_t phys)
        case CTL_FLAG_GEN_ICV:
                ctx = crypto_tfm_ctx(crypt->data.tfm);
                dma_pool_free(ctx_pool, crypt->regist_ptr,
-                               crypt->regist_buf->phys_addr);
+                             crypt->regist_buf->phys_addr);
                dma_pool_free(buffer_pool, crypt->regist_buf, crypt->src_buf);
                if (atomic_dec_and_test(&ctx->configuring))
                        complete(&ctx->completion);
                break;
        case CTL_FLAG_GEN_REVAES:
                ctx = crypto_tfm_ctx(crypt->data.tfm);
-               *(u32*)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR);
+               *(u32 *)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR);
                if (atomic_dec_and_test(&ctx->configuring))
                        complete(&ctx->completion);
                break;
@@ -418,8 +436,8 @@ static void crypto_done_action(unsigned long arg)
 {
        int i;
 
-       for(i=0; i<4; i++) {
-               dma_addr_t phys = qmgr_get_entry(RECV_QID);
+       for (i = 0; i < 4; i++) {
+               dma_addr_t phys = qmgr_get_entry(recv_qid);
                if (!phys)
                        return;
                one_packet(phys);
@@ -429,15 +447,52 @@ static void crypto_done_action(unsigned long arg)
 
 static int init_ixp_crypto(struct device *dev)
 {
-       int ret = -ENODEV;
+       struct device_node *np = dev->of_node;
        u32 msg[2] = { 0, 0 };
+       int ret = -ENODEV;
+       u32 npe_id;
 
-       if (! ( ~(*IXP4XX_EXP_CFG2) & (IXP4XX_FEATURE_HASH |
-                               IXP4XX_FEATURE_AES | IXP4XX_FEATURE_DES))) {
-               printk(KERN_ERR "ixp_crypto: No HW crypto available\n");
-               return ret;
+       dev_info(dev, "probing...\n");
+
+       /* Locate the NPE and queue manager to use from device tree */
+       if (IS_ENABLED(CONFIG_OF) && np) {
+               struct of_phandle_args queue_spec;
+               struct of_phandle_args npe_spec;
+
+               ret = of_parse_phandle_with_fixed_args(np, "intel,npe-handle",
+                                                      1, 0, &npe_spec);
+               if (ret) {
+                       dev_err(dev, "no NPE engine specified\n");
+                       return -ENODEV;
+               }
+               npe_id = npe_spec.args[0];
+
+               ret = of_parse_phandle_with_fixed_args(np, "queue-rx", 1, 0,
+                                                      &queue_spec);
+               if (ret) {
+                       dev_err(dev, "no rx queue phandle\n");
+                       return -ENODEV;
+               }
+               recv_qid = queue_spec.args[0];
+
+               ret = of_parse_phandle_with_fixed_args(np, "queue-txready", 1, 0,
+                                                      &queue_spec);
+               if (ret) {
+                       dev_err(dev, "no txready queue phandle\n");
+                       return -ENODEV;
+               }
+               send_qid = queue_spec.args[0];
+       } else {
+               /*
+                * Hardcoded engine when using platform data, this goes away
+                * when we switch to using DT only.
+                */
+               npe_id = 2;
+               send_qid = 29;
+               recv_qid = 30;
        }
-       npe_c = npe_request(NPE_ID);
+
+       npe_c = npe_request(npe_id);
        if (!npe_c)
                return ret;
 
@@ -455,10 +510,9 @@ static int init_ixp_crypto(struct device *dev)
                        goto npe_error;
        }
 
-       switch ((msg[1]>>16) & 0xff) {
+       switch ((msg[1] >> 16) & 0xff) {
        case 3:
-               printk(KERN_WARNING "Firmware of %s lacks AES support\n",
-                               npe_name(npe_c));
+               dev_warn(dev, "Firmware of %s lacks AES support\n", npe_name(npe_c));
                support_aes = 0;
                break;
        case 4:
@@ -466,8 +520,7 @@ static int init_ixp_crypto(struct device *dev)
                support_aes = 1;
                break;
        default:
-               printk(KERN_ERR "Firmware of %s lacks crypto support\n",
-                       npe_name(npe_c));
+               dev_err(dev, "Firmware of %s lacks crypto support\n", npe_name(npe_c));
                ret = -ENODEV;
                goto npe_release;
        }
@@ -475,35 +528,34 @@ static int init_ixp_crypto(struct device *dev)
         * so assure it is large enough
         */
        BUILD_BUG_ON(SHA1_DIGEST_SIZE > sizeof(struct buffer_desc));
-       buffer_pool = dma_pool_create("buffer", dev,
-                       sizeof(struct buffer_desc), 32, 0);
+       buffer_pool = dma_pool_create("buffer", dev, sizeof(struct buffer_desc),
+                                     32, 0);
        ret = -ENOMEM;
-       if (!buffer_pool) {
+       if (!buffer_pool)
                goto err;
-       }
-       ctx_pool = dma_pool_create("context", dev,
-                       NPE_CTX_LEN, 16, 0);
-       if (!ctx_pool) {
+
+       ctx_pool = dma_pool_create("context", dev, NPE_CTX_LEN, 16, 0);
+       if (!ctx_pool)
                goto err;
-       }
-       ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0,
+
+       ret = qmgr_request_queue(send_qid, NPE_QLEN_TOTAL, 0, 0,
                                 "ixp_crypto:out", NULL);
        if (ret)
                goto err;
-       ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0,
+       ret = qmgr_request_queue(recv_qid, NPE_QLEN, 0, 0,
                                 "ixp_crypto:in", NULL);
        if (ret) {
-               qmgr_release_queue(SEND_QID);
+               qmgr_release_queue(send_qid);
                goto err;
        }
-       qmgr_set_irq(RECV_QID, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL);
+       qmgr_set_irq(recv_qid, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL);
        tasklet_init(&crypto_done_tasklet, crypto_done_action, 0);
 
-       qmgr_enable_irq(RECV_QID);
+       qmgr_enable_irq(recv_qid);
        return 0;
 
 npe_error:
-       printk(KERN_ERR "%s not responding\n", npe_name(npe_c));
+       dev_err(dev, "%s not responding\n", npe_name(npe_c));
        ret = -EIO;
 err:
        dma_pool_destroy(ctx_pool);
@@ -515,22 +567,20 @@ npe_release:
 
 static void release_ixp_crypto(struct device *dev)
 {
-       qmgr_disable_irq(RECV_QID);
+       qmgr_disable_irq(recv_qid);
        tasklet_kill(&crypto_done_tasklet);
 
-       qmgr_release_queue(SEND_QID);
-       qmgr_release_queue(RECV_QID);
+       qmgr_release_queue(send_qid);
+       qmgr_release_queue(recv_qid);
 
        dma_pool_destroy(ctx_pool);
        dma_pool_destroy(buffer_pool);
 
        npe_release(npe_c);
 
-       if (crypt_virt) {
-               dma_free_coherent(dev,
-                       NPE_QLEN * sizeof(struct crypt_ctl),
-                       crypt_virt, crypt_phys);
-       }
+       if (crypt_virt)
+               dma_free_coherent(dev, NPE_QLEN * sizeof(struct crypt_ctl),
+                                 crypt_virt, crypt_phys);
 }
 
 static void reset_sa_dir(struct ix_sa_dir *dir)
@@ -543,9 +593,9 @@ static void reset_sa_dir(struct ix_sa_dir *dir)
 static int init_sa_dir(struct ix_sa_dir *dir)
 {
        dir->npe_ctx = dma_pool_alloc(ctx_pool, GFP_KERNEL, &dir->npe_ctx_phys);
-       if (!dir->npe_ctx) {
+       if (!dir->npe_ctx)
                return -ENOMEM;
-       }
+
        reset_sa_dir(dir);
        return 0;
 }
@@ -566,15 +616,31 @@ static int init_tfm(struct crypto_tfm *tfm)
        if (ret)
                return ret;
        ret = init_sa_dir(&ctx->decrypt);
-       if (ret) {
+       if (ret)
                free_sa_dir(&ctx->encrypt);
-       }
+
        return ret;
 }
 
 static int init_tfm_ablk(struct crypto_skcipher *tfm)
 {
-       crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx));
+       struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm);
+       struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm);
+       const char *name = crypto_tfm_alg_name(ctfm);
+
+       ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(ctx->fallback_tfm)) {
+               pr_err("ERROR: Cannot allocate fallback for %s %ld\n",
+                       name, PTR_ERR(ctx->fallback_tfm));
+               return PTR_ERR(ctx->fallback_tfm);
+       }
+
+       pr_info("Fallback for %s is %s\n",
+                crypto_tfm_alg_driver_name(&tfm->base),
+                crypto_tfm_alg_driver_name(crypto_skcipher_tfm(ctx->fallback_tfm))
+                );
+
+       crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx) + crypto_skcipher_reqsize(ctx->fallback_tfm));
        return init_tfm(crypto_skcipher_tfm(tfm));
 }
 
@@ -587,12 +653,17 @@ static int init_tfm_aead(struct crypto_aead *tfm)
 static void exit_tfm(struct crypto_tfm *tfm)
 {
        struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+
        free_sa_dir(&ctx->encrypt);
        free_sa_dir(&ctx->decrypt);
 }
 
 static void exit_tfm_ablk(struct crypto_skcipher *tfm)
 {
+       struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm);
+       struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm);
+
+       crypto_free_skcipher(ctx->fallback_tfm);
        exit_tfm(crypto_skcipher_tfm(tfm));
 }
 
@@ -602,7 +673,8 @@ static void exit_tfm_aead(struct crypto_aead *tfm)
 }
 
 static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
-               int init_len, u32 ctx_addr, const u8 *key, int key_len)
+                             int init_len, u32 ctx_addr, const u8 *key,
+                             int key_len)
 {
        struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
        struct crypt_ctl *crypt;
@@ -629,9 +701,8 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
 
        memcpy(pad, key, key_len);
        memset(pad + key_len, 0, HMAC_PAD_BLOCKLEN - key_len);
-       for (i = 0; i < HMAC_PAD_BLOCKLEN; i++) {
+       for (i = 0; i < HMAC_PAD_BLOCKLEN; i++)
                pad[i] ^= xpad;
-       }
 
        crypt->data.tfm = tfm;
        crypt->regist_ptr = pad;
@@ -652,13 +723,13 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
        buf->phys_addr = pad_phys;
 
        atomic_inc(&ctx->configuring);
-       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
-       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(send_qid));
        return 0;
 }
 
-static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
-               const u8 *key, int key_len, unsigned digest_len)
+static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned int authsize,
+                     const u8 *key, int key_len, unsigned int digest_len)
 {
        u32 itarget, otarget, npe_ctx_addr;
        unsigned char *cinfo;
@@ -673,11 +744,11 @@ static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
        algo = ix_hash(tfm);
 
        /* write cfg word to cryptinfo */
-       cfgword = algo->cfgword | ( authsize << 6); /* (authsize/4) << 8 */
+       cfgword = algo->cfgword | (authsize << 6); /* (authsize/4) << 8 */
 #ifndef __ARMEB__
        cfgword ^= 0xAA000000; /* change the "byte swap" flags */
 #endif
-       *(u32*)cinfo = cpu_to_be32(cfgword);
+       *(u32 *)cinfo = cpu_to_be32(cfgword);
        cinfo += sizeof(cfgword);
 
        /* write ICV to cryptinfo */
@@ -697,11 +768,11 @@ static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
                dir->npe_mode |= NPE_OP_HASH_VERIFY;
 
        ret = register_chain_var(tfm, HMAC_OPAD_VALUE, otarget,
-                       init_len, npe_ctx_addr, key, key_len);
+                                init_len, npe_ctx_addr, key, key_len);
        if (ret)
                return ret;
        return register_chain_var(tfm, HMAC_IPAD_VALUE, itarget,
-                       init_len, npe_ctx_addr, key, key_len);
+                                 init_len, npe_ctx_addr, key, key_len);
 }
 
 static int gen_rev_aes_key(struct crypto_tfm *tfm)
@@ -711,10 +782,10 @@ static int gen_rev_aes_key(struct crypto_tfm *tfm)
        struct ix_sa_dir *dir = &ctx->decrypt;
 
        crypt = get_crypt_desc_emerg();
-       if (!crypt) {
+       if (!crypt)
                return -EAGAIN;
-       }
-       *(u32*)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR);
+
+       *(u32 *)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR);
 
        crypt->data.tfm = tfm;
        crypt->crypt_offs = 0;
@@ -727,13 +798,13 @@ static int gen_rev_aes_key(struct crypto_tfm *tfm)
        crypt->ctl_flags |= CTL_FLAG_GEN_REVAES;
 
        atomic_inc(&ctx->configuring);
-       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
-       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(send_qid));
        return 0;
 }
 
-static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
-               const u8 *key, int key_len)
+static int setup_cipher(struct crypto_tfm *tfm, int encrypt, const u8 *key,
+                       int key_len)
 {
        u8 *cinfo;
        u32 cipher_cfg;
@@ -753,9 +824,15 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
        }
        if (cipher_cfg & MOD_AES) {
                switch (key_len) {
-               case 16: keylen_cfg = MOD_AES128; break;
-               case 24: keylen_cfg = MOD_AES192; break;
-               case 32: keylen_cfg = MOD_AES256; break;
+               case 16:
+                       keylen_cfg = MOD_AES128;
+                       break;
+               case 24:
+                       keylen_cfg = MOD_AES192;
+                       break;
+               case 32:
+                       keylen_cfg = MOD_AES256;
+                       break;
                default:
                        return -EINVAL;
                }
@@ -766,31 +843,31 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
                        return err;
        }
        /* write cfg word to cryptinfo */
-       *(u32*)cinfo = cpu_to_be32(cipher_cfg);
+       *(u32 *)cinfo = cpu_to_be32(cipher_cfg);
        cinfo += sizeof(cipher_cfg);
 
        /* write cipher key to cryptinfo */
        memcpy(cinfo, key, key_len);
        /* NPE wants keylen set to DES3_EDE_KEY_SIZE even for single DES */
        if (key_len < DES3_EDE_KEY_SIZE && !(cipher_cfg & MOD_AES)) {
-               memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE -key_len);
+               memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE - key_len);
                key_len = DES3_EDE_KEY_SIZE;
        }
        dir->npe_ctx_idx = sizeof(cipher_cfg) + key_len;
        dir->npe_mode |= NPE_OP_CRYPT_ENABLE;
-       if ((cipher_cfg & MOD_AES) && !encrypt) {
+       if ((cipher_cfg & MOD_AES) && !encrypt)
                return gen_rev_aes_key(tfm);
-       }
+
        return 0;
 }
 
 static struct buffer_desc *chainup_buffers(struct device *dev,
-               struct scatterlist *sg, unsigned nbytes,
+               struct scatterlist *sg, unsigned int nbytes,
                struct buffer_desc *buf, gfp_t flags,
                enum dma_data_direction dir)
 {
        for (; nbytes > 0; sg = sg_next(sg)) {
-               unsigned len = min(nbytes, sg->length);
+               unsigned int len = min(nbytes, sg->length);
                struct buffer_desc *next_buf;
                dma_addr_t next_buf_phys;
                void *ptr;
@@ -817,7 +894,7 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
 }
 
 static int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key,
-                       unsigned int key_len)
+                      unsigned int key_len)
 {
        struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
        int ret;
@@ -838,7 +915,12 @@ static int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key,
 out:
        if (!atomic_dec_and_test(&ctx->configuring))
                wait_for_completion(&ctx->completion);
-       return ret;
+       if (ret)
+               return ret;
+       crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+       crypto_skcipher_set_flags(ctx->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+
+       return crypto_skcipher_setkey(ctx->fallback_tfm, key, key_len);
 }
 
 static int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
@@ -849,7 +931,7 @@ static int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
 }
 
 static int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key,
-               unsigned int key_len)
+                              unsigned int key_len)
 {
        struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
 
@@ -858,17 +940,36 @@ static int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key,
                return -EINVAL;
 
        memcpy(ctx->nonce, key + (key_len - CTR_RFC3686_NONCE_SIZE),
-                       CTR_RFC3686_NONCE_SIZE);
+              CTR_RFC3686_NONCE_SIZE);
 
        key_len -= CTR_RFC3686_NONCE_SIZE;
        return ablk_setkey(tfm, key, key_len);
 }
 
+static int ixp4xx_cipher_fallback(struct skcipher_request *areq, int encrypt)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+       struct ixp_ctx *op = crypto_skcipher_ctx(tfm);
+       struct ablk_ctx *rctx = skcipher_request_ctx(areq);
+       int err;
+
+       skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+       skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+                                     areq->base.complete, areq->base.data);
+       skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+                                  areq->cryptlen, areq->iv);
+       if (encrypt)
+               err = crypto_skcipher_encrypt(&rctx->fallback_req);
+       else
+               err = crypto_skcipher_decrypt(&rctx->fallback_req);
+       return err;
+}
+
 static int ablk_perform(struct skcipher_request *req, int encrypt)
 {
        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
        struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
-       unsigned ivsize = crypto_skcipher_ivsize(tfm);
+       unsigned int ivsize = crypto_skcipher_ivsize(tfm);
        struct ix_sa_dir *dir;
        struct crypt_ctl *crypt;
        unsigned int nbytes = req->cryptlen;
@@ -876,15 +977,20 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
        struct ablk_ctx *req_ctx = skcipher_request_ctx(req);
        struct buffer_desc src_hook;
        struct device *dev = &pdev->dev;
+       unsigned int offset;
        gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
                                GFP_KERNEL : GFP_ATOMIC;
 
-       if (qmgr_stat_full(SEND_QID))
+       if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1)
+               return ixp4xx_cipher_fallback(req, encrypt);
+
+       if (qmgr_stat_full(send_qid))
                return -EAGAIN;
        if (atomic_read(&ctx->configuring))
                return -EAGAIN;
 
        dir = encrypt ? &ctx->encrypt : &ctx->decrypt;
+       req_ctx->encrypt = encrypt;
 
        crypt = get_crypt_desc();
        if (!crypt)
@@ -900,14 +1006,19 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
 
        BUG_ON(ivsize && !req->iv);
        memcpy(crypt->iv, req->iv, ivsize);
+       if (ivsize > 0 && !encrypt) {
+               offset = req->cryptlen - ivsize;
+               scatterwalk_map_and_copy(req_ctx->iv, req->src, offset, ivsize, 0);
+       }
        if (req->src != req->dst) {
                struct buffer_desc dst_hook;
+
                crypt->mode |= NPE_OP_NOT_IN_PLACE;
                /* This was never tested by Intel
                 * for more than one dst buffer, I think. */
                req_ctx->dst = NULL;
                if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
-                                       flags, DMA_FROM_DEVICE))
+                                    flags, DMA_FROM_DEVICE))
                        goto free_buf_dest;
                src_direction = DMA_TO_DEVICE;
                req_ctx->dst = dst_hook.next;
@@ -916,23 +1027,23 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
                req_ctx->dst = NULL;
        }
        req_ctx->src = NULL;
-       if (!chainup_buffers(dev, req->src, nbytes, &src_hook,
-                               flags, src_direction))
+       if (!chainup_buffers(dev, req->src, nbytes, &src_hook, flags,
+                            src_direction))
                goto free_buf_src;
 
        req_ctx->src = src_hook.next;
        crypt->src_buf = src_hook.phys_next;
        crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK;
-       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
-       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(send_qid));
        return -EINPROGRESS;
 
 free_buf_src:
        free_buf_chain(dev, req_ctx->src, crypt->src_buf);
 free_buf_dest:
-       if (req->src != req->dst) {
+       if (req->src != req->dst)
                free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
-       }
+
        crypt->ctl_flags = CTL_FLAG_UNUSED;
        return -ENOMEM;
 }
@@ -956,7 +1067,7 @@ static int ablk_rfc3686_crypt(struct skcipher_request *req)
        int ret;
 
        /* set up counter block */
-        memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
+       memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
        memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
 
        /* initialize counter portion of counter block */
@@ -970,12 +1081,12 @@ static int ablk_rfc3686_crypt(struct skcipher_request *req)
 }
 
 static int aead_perform(struct aead_request *req, int encrypt,
-               int cryptoffset, int eff_cryptlen, u8 *iv)
+                       int cryptoffset, int eff_cryptlen, u8 *iv)
 {
        struct crypto_aead *tfm = crypto_aead_reqtfm(req);
        struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
-       unsigned ivsize = crypto_aead_ivsize(tfm);
-       unsigned authsize = crypto_aead_authsize(tfm);
+       unsigned int ivsize = crypto_aead_ivsize(tfm);
+       unsigned int authsize = crypto_aead_authsize(tfm);
        struct ix_sa_dir *dir;
        struct crypt_ctl *crypt;
        unsigned int cryptlen;
@@ -987,7 +1098,7 @@ static int aead_perform(struct aead_request *req, int encrypt,
        enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
        unsigned int lastlen;
 
-       if (qmgr_stat_full(SEND_QID))
+       if (qmgr_stat_full(send_qid))
                return -EAGAIN;
        if (atomic_read(&ctx->configuring))
                return -EAGAIN;
@@ -998,7 +1109,7 @@ static int aead_perform(struct aead_request *req, int encrypt,
        } else {
                dir = &ctx->decrypt;
                /* req->cryptlen includes the authsize when decrypting */
-               cryptlen = req->cryptlen -authsize;
+               cryptlen = req->cryptlen - authsize;
                eff_cryptlen -= authsize;
        }
        crypt = get_crypt_desc();
@@ -1058,12 +1169,12 @@ static int aead_perform(struct aead_request *req, int encrypt,
                /* The 12 hmac bytes are scattered,
                 * we need to copy them into a safe buffer */
                req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
-                               &crypt->icv_rev_aes);
+                                                   &crypt->icv_rev_aes);
                if (unlikely(!req_ctx->hmac_virt))
                        goto free_buf_dst;
                if (!encrypt) {
                        scatterwalk_map_and_copy(req_ctx->hmac_virt,
-                               req->src, cryptlen, authsize, 0);
+                                                req->src, cryptlen, authsize, 0);
                }
                req_ctx->encrypt = encrypt;
        } else {
@@ -1071,8 +1182,8 @@ static int aead_perform(struct aead_request *req, int encrypt,
        }
 
        crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD;
-       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
-       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(send_qid));
        return -EINPROGRESS;
 
 free_buf_dst:
@@ -1086,7 +1197,7 @@ free_buf_src:
 static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
 {
        struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
-       unsigned digest_len = crypto_aead_maxauthsize(tfm);
+       unsigned int digest_len = crypto_aead_maxauthsize(tfm);
        int ret;
 
        if (!ctx->enckey_len && !ctx->authkey_len)
@@ -1104,11 +1215,11 @@ static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
        if (ret)
                goto out;
        ret = setup_auth(&tfm->base, 0, authsize, ctx->authkey,
-                       ctx->authkey_len, digest_len);
+                        ctx->authkey_len, digest_len);
        if (ret)
                goto out;
        ret = setup_auth(&tfm->base, 1, authsize,  ctx->authkey,
-                       ctx->authkey_len, digest_len);
+                        ctx->authkey_len, digest_len);
 out:
        if (!atomic_dec_and_test(&ctx->configuring))
                wait_for_completion(&ctx->completion);
@@ -1119,13 +1230,13 @@ static int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
 {
        int max = crypto_aead_maxauthsize(tfm) >> 2;
 
-       if ((authsize>>2) < 1 || (authsize>>2) > max || (authsize & 3))
+       if ((authsize >> 2) < 1 || (authsize >> 2) > max || (authsize & 3))
                return -EINVAL;
        return aead_setup(tfm, authsize);
 }
 
 static int aead_setkey(struct crypto_aead *tfm, const u8 *key,
-                       unsigned int keylen)
+                      unsigned int keylen)
 {
        struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
        struct crypto_authenc_keys keys;
@@ -1364,43 +1475,33 @@ static struct ixp_aead_alg ixp4xx_aeads[] = {
 
 #define IXP_POSTFIX "-ixp4xx"
 
-static const struct platform_device_info ixp_dev_info __initdata = {
-       .name           = DRIVER_NAME,
-       .id             = 0,
-       .dma_mask       = DMA_BIT_MASK(32),
-};
-
-static int __init ixp_module_init(void)
+static int ixp_crypto_probe(struct platform_device *_pdev)
 {
+       struct device *dev = &_pdev->dev;
        int num = ARRAY_SIZE(ixp4xx_algos);
        int i, err;
 
-       pdev = platform_device_register_full(&ixp_dev_info);
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
+       pdev = _pdev;
 
-       err = init_ixp_crypto(&pdev->dev);
-       if (err) {
-               platform_device_unregister(pdev);
+       err = init_ixp_crypto(dev);
+       if (err)
                return err;
-       }
-       for (i=0; i< num; i++) {
+
+       for (i = 0; i < num; i++) {
                struct skcipher_alg *cra = &ixp4xx_algos[i].crypto;
 
                if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
-                       "%s"IXP_POSTFIX, cra->base.cra_name) >=
-                       CRYPTO_MAX_ALG_NAME)
-               {
+                            "%s"IXP_POSTFIX, cra->base.cra_name) >=
+                            CRYPTO_MAX_ALG_NAME)
                        continue;
-               }
-               if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) {
+               if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES))
                        continue;
-               }
 
                /* block ciphers */
                cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
                                      CRYPTO_ALG_ASYNC |
-                                     CRYPTO_ALG_ALLOCATES_MEMORY;
+                                     CRYPTO_ALG_ALLOCATES_MEMORY |
+                                     CRYPTO_ALG_NEED_FALLBACK;
                if (!cra->setkey)
                        cra->setkey = ablk_setkey;
                if (!cra->encrypt)
@@ -1415,7 +1516,7 @@ static int __init ixp_module_init(void)
                cra->base.cra_alignmask = 3;
                cra->base.cra_priority = 300;
                if (crypto_register_skcipher(cra))
-                       printk(KERN_ERR "Failed to register '%s'\n",
+                       dev_err(&pdev->dev, "Failed to register '%s'\n",
                                cra->base.cra_name);
                else
                        ixp4xx_algos[i].registered = 1;
@@ -1448,7 +1549,7 @@ static int __init ixp_module_init(void)
                cra->base.cra_priority = 300;
 
                if (crypto_register_aead(cra))
-                       printk(KERN_ERR "Failed to register '%s'\n",
+                       dev_err(&pdev->dev, "Failed to register '%s'\n",
                                cra->base.cra_driver_name);
                else
                        ixp4xx_aeads[i].registered = 1;
@@ -1456,7 +1557,7 @@ static int __init ixp_module_init(void)
        return 0;
 }
 
-static void __exit ixp_module_exit(void)
+static int ixp_crypto_remove(struct platform_device *pdev)
 {
        int num = ARRAY_SIZE(ixp4xx_algos);
        int i;
@@ -1466,16 +1567,30 @@ static void __exit ixp_module_exit(void)
                        crypto_unregister_aead(&ixp4xx_aeads[i].crypto);
        }
 
-       for (i=0; i< num; i++) {
+       for (i = 0; i < num; i++) {
                if (ixp4xx_algos[i].registered)
                        crypto_unregister_skcipher(&ixp4xx_algos[i].crypto);
        }
        release_ixp_crypto(&pdev->dev);
-       platform_device_unregister(pdev);
+
+       return 0;
 }
+static const struct of_device_id ixp4xx_crypto_of_match[] = {
+       {
+               .compatible = "intel,ixp4xx-crypto",
+       },
+       {},
+};
 
-module_init(ixp_module_init);
-module_exit(ixp_module_exit);
+static struct platform_driver ixp_crypto_driver = {
+       .probe = ixp_crypto_probe,
+       .remove = ixp_crypto_remove,
+       .driver = {
+               .name = "ixp4xx_crypto",
+               .of_match_table = ixp4xx_crypto_of_match,
+       },
+};
+module_platform_driver(ixp_crypto_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>");
index c1007f2..d215a6b 100644 (file)
@@ -66,7 +66,7 @@
 #define CESA_SA_ST_ACT_1                       BIT(1)
 
 /*
- * CESA_SA_FPGA_INT_STATUS looks like a FPGA leftover and is documented only
+ * CESA_SA_FPGA_INT_STATUS looks like an FPGA leftover and is documented only
  * in Errata 4.12. It looks like that it was part of an IRQ-controller in FPGA
  * and someone forgot to remove  it while switching to the core and moving to
  * CESA_SA_INT_STATUS.
index b9c6201..c242d22 100644 (file)
@@ -1,10 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CRYPTO_DEV_OCTEONTX2_CPT) += octeontx2-cpt.o octeontx2-cptvf.o
+obj-$(CONFIG_CRYPTO_DEV_OCTEONTX2_CPT) += rvu_cptpf.o rvu_cptvf.o
 
-octeontx2-cpt-objs := otx2_cptpf_main.o otx2_cptpf_mbox.o \
-                     otx2_cpt_mbox_common.o otx2_cptpf_ucode.o otx2_cptlf.o
-octeontx2-cptvf-objs := otx2_cptvf_main.o otx2_cptvf_mbox.o otx2_cptlf.o \
-                       otx2_cpt_mbox_common.o otx2_cptvf_reqmgr.o \
-                       otx2_cptvf_algs.o
+rvu_cptpf-objs := otx2_cptpf_main.o otx2_cptpf_mbox.o \
+                 otx2_cpt_mbox_common.o otx2_cptpf_ucode.o otx2_cptlf.o \
+                 cn10k_cpt.o
+rvu_cptvf-objs := otx2_cptvf_main.o otx2_cptvf_mbox.o otx2_cptlf.o \
+                 otx2_cpt_mbox_common.o otx2_cptvf_reqmgr.o \
+                 otx2_cptvf_algs.o cn10k_cpt.o
 
 ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c
new file mode 100644 (file)
index 0000000..1499ef7
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2021 Marvell. */
+
+#include <linux/soc/marvell/octeontx2/asm.h>
+#include "otx2_cptpf.h"
+#include "otx2_cptvf.h"
+#include "otx2_cptlf.h"
+#include "cn10k_cpt.h"
+
+static struct cpt_hw_ops otx2_hw_ops = {
+       .send_cmd = otx2_cpt_send_cmd,
+       .cpt_get_compcode = otx2_cpt_get_compcode,
+       .cpt_get_uc_compcode = otx2_cpt_get_uc_compcode,
+};
+
+static struct cpt_hw_ops cn10k_hw_ops = {
+       .send_cmd = cn10k_cpt_send_cmd,
+       .cpt_get_compcode = cn10k_cpt_get_compcode,
+       .cpt_get_uc_compcode = cn10k_cpt_get_uc_compcode,
+};
+
+void cn10k_cpt_send_cmd(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+                       struct otx2_cptlf_info *lf)
+{
+       void __iomem *lmtline = lf->lmtline;
+       u64 val = (lf->slot & 0x7FF);
+       u64 tar_addr = 0;
+
+       /* tar_addr<6:4> = Size of first LMTST - 1 in units of 128b. */
+       tar_addr |= (__force u64)lf->ioreg |
+                   (((OTX2_CPT_INST_SIZE/16) - 1) & 0x7) << 4;
+       /*
+        * Make sure memory areas pointed in CPT_INST_S
+        * are flushed before the instruction is sent to CPT
+        */
+       dma_wmb();
+
+       /* Copy CPT command to LMTLINE */
+       memcpy_toio(lmtline, cptinst, insts_num * OTX2_CPT_INST_SIZE);
+       cn10k_lmt_flush(val, tar_addr);
+}
+
+int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf)
+{
+       struct pci_dev *pdev = cptpf->pdev;
+       resource_size_t size;
+       u64 lmt_base;
+
+       if (!test_bit(CN10K_LMTST, &cptpf->cap_flag)) {
+               cptpf->lfs.ops = &otx2_hw_ops;
+               return 0;
+       }
+
+       cptpf->lfs.ops = &cn10k_hw_ops;
+       lmt_base = readq(cptpf->reg_base + RVU_PF_LMTLINE_ADDR);
+       if (!lmt_base) {
+               dev_err(&pdev->dev, "PF LMTLINE address not configured\n");
+               return -ENOMEM;
+       }
+       size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+       size -= ((1 + cptpf->max_vfs) * MBOX_SIZE);
+       cptpf->lfs.lmt_base = devm_ioremap_wc(&pdev->dev, lmt_base, size);
+       if (!cptpf->lfs.lmt_base) {
+               dev_err(&pdev->dev,
+                       "Mapping of PF LMTLINE address failed\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf)
+{
+       struct pci_dev *pdev = cptvf->pdev;
+       resource_size_t offset, size;
+
+       if (!test_bit(CN10K_LMTST, &cptvf->cap_flag)) {
+               cptvf->lfs.ops = &otx2_hw_ops;
+               return 0;
+       }
+
+       cptvf->lfs.ops = &cn10k_hw_ops;
+       offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+       size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+       /* Map VF LMILINE region */
+       cptvf->lfs.lmt_base = devm_ioremap_wc(&pdev->dev, offset, size);
+       if (!cptvf->lfs.lmt_base) {
+               dev_err(&pdev->dev, "Unable to map BAR4\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.h b/drivers/crypto/marvell/octeontx2/cn10k_cpt.h
new file mode 100644 (file)
index 0000000..c091392
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (C) 2021 Marvell.
+ */
+#ifndef __CN10K_CPT_H
+#define __CN10K_CPT_H
+
+#include "otx2_cpt_common.h"
+#include "otx2_cptpf.h"
+#include "otx2_cptvf.h"
+
+static inline u8 cn10k_cpt_get_compcode(union otx2_cpt_res_s *result)
+{
+       return ((struct cn10k_cpt_res_s *)result)->compcode;
+}
+
+static inline u8 cn10k_cpt_get_uc_compcode(union otx2_cpt_res_s *result)
+{
+       return ((struct cn10k_cpt_res_s *)result)->uc_compcode;
+}
+
+static inline u8 otx2_cpt_get_compcode(union otx2_cpt_res_s *result)
+{
+       return ((struct cn9k_cpt_res_s *)result)->compcode;
+}
+
+static inline u8 otx2_cpt_get_uc_compcode(union otx2_cpt_res_s *result)
+{
+       return ((struct cn9k_cpt_res_s *)result)->uc_compcode;
+}
+
+void cn10k_cpt_send_cmd(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+                       struct otx2_cptlf_info *lf);
+int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf);
+int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf);
+
+#endif /* __CN10K_CPTLF_H */
index ecedd91..c5445b0 100644 (file)
 #define OTX2_CPT_NAME_LENGTH 64
 #define OTX2_CPT_DMA_MINALIGN 128
 
+/* HW capability flags */
+#define CN10K_MBOX  0
+#define CN10K_LMTST 1
+
 #define BAD_OTX2_CPT_ENG_TYPE OTX2_CPT_MAX_ENG_TYPES
 
 enum otx2_cpt_eng_type {
@@ -116,6 +120,25 @@ static inline u64 otx2_cpt_read64(void __iomem *reg_base, u64 blk, u64 slot,
                             OTX2_CPT_RVU_FUNC_ADDR_S(blk, slot, offs));
 }
 
+static inline bool is_dev_otx2(struct pci_dev *pdev)
+{
+       if (pdev->device == OTX2_CPT_PCI_PF_DEVICE_ID ||
+           pdev->device == OTX2_CPT_PCI_VF_DEVICE_ID)
+               return true;
+
+       return false;
+}
+
+static inline void otx2_cpt_set_hw_caps(struct pci_dev *pdev,
+                                       unsigned long *cap_flag)
+{
+       if (!is_dev_otx2(pdev)) {
+               __set_bit(CN10K_MBOX, cap_flag);
+               __set_bit(CN10K_LMTST, cap_flag);
+       }
+}
+
+
 int otx2_cpt_send_ready_msg(struct otx2_mbox *mbox, struct pci_dev *pdev);
 int otx2_cpt_send_mbox_msg(struct otx2_mbox *mbox, struct pci_dev *pdev);
 
index ecafc42..6f94797 100644 (file)
@@ -10,6 +10,8 @@
 /* Device IDs */
 #define OTX2_CPT_PCI_PF_DEVICE_ID 0xA0FD
 #define OTX2_CPT_PCI_VF_DEVICE_ID 0xA0FE
+#define CN10K_CPT_PCI_PF_DEVICE_ID 0xA0F2
+#define CN10K_CPT_PCI_VF_DEVICE_ID 0xA0F3
 
 /* Mailbox interrupts offset */
 #define OTX2_CPT_PF_MBOX_INT   6
@@ -25,6 +27,7 @@
  */
 #define OTX2_CPT_VF_MSIX_VECTORS 1
 #define OTX2_CPT_VF_INTR_MBOX_MASK BIT(0)
+#define CN10K_CPT_VF_MBOX_REGION  (0xC0000)
 
 /* CPT LF MSIX vectors */
 #define OTX2_CPT_LF_MSIX_VECTORS 2
@@ -135,7 +138,7 @@ enum otx2_cpt_comp_e {
        OTX2_CPT_COMP_E_FAULT = 0x02,
        OTX2_CPT_COMP_E_HWERR = 0x04,
        OTX2_CPT_COMP_E_INSTERR = 0x05,
-       OTX2_CPT_COMP_E_LAST_ENTRY = 0x06
+       OTX2_CPT_COMP_E_WARN = 0x06
 };
 
 /*
@@ -266,13 +269,22 @@ union otx2_cpt_inst_s {
 union otx2_cpt_res_s {
        u64 u[2];
 
-       struct {
+       struct cn9k_cpt_res_s {
                u64 compcode:8;
                u64 uc_compcode:8;
                u64 doneint:1;
                u64 reserved_17_63:47;
                u64 reserved_64_127;
        } s;
+
+       struct cn10k_cpt_res_s {
+               u64 compcode:7;
+               u64 doneint:1;
+               u64 uc_compcode:8;
+               u64 rlen:16;
+               u64 spi:32;
+               u64 esn;
+       } cn10k;
 };
 
 /*
index 34aba15..c8350fc 100644 (file)
@@ -379,9 +379,14 @@ int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri,
        for (slot = 0; slot < lfs->lfs_num; slot++) {
                lfs->lf[slot].lfs = lfs;
                lfs->lf[slot].slot = slot;
-               lfs->lf[slot].lmtline = lfs->reg_base +
-                       OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_LMT, slot,
+               if (lfs->lmt_base)
+                       lfs->lf[slot].lmtline = lfs->lmt_base +
+                                               (slot * LMTLINE_SIZE);
+               else
+                       lfs->lf[slot].lmtline = lfs->reg_base +
+                               OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_LMT, slot,
                                                 OTX2_CPT_LMT_LF_LMTLINEX(0));
+
                lfs->lf[slot].ioreg = lfs->reg_base +
                        OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_CPT0, slot,
                                                 OTX2_CPT_LF_NQX(0));
index ab1678f..b691b6c 100644 (file)
@@ -84,12 +84,22 @@ struct otx2_cptlf_info {
        struct otx2_cptlf_wqe *wqe;       /* Tasklet work info */
 };
 
+struct cpt_hw_ops {
+       void (*send_cmd)(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+                        struct otx2_cptlf_info *lf);
+       u8 (*cpt_get_compcode)(union otx2_cpt_res_s *result);
+       u8 (*cpt_get_uc_compcode)(union otx2_cpt_res_s *result);
+};
+
 struct otx2_cptlfs_info {
        /* Registers start address of VF/PF LFs are attached to */
        void __iomem *reg_base;
+#define LMTLINE_SIZE  128
+       void __iomem *lmt_base;
        struct pci_dev *pdev;   /* Device LFs are attached to */
        struct otx2_cptlf_info lf[OTX2_CPT_MAX_LFS_NUM];
        struct otx2_mbox *mbox;
+       struct cpt_hw_ops *ops;
        u8 are_lfs_attached;    /* Whether CPT LFs are attached */
        u8 lfs_num;             /* Number of CPT LFs */
        u8 kcrypto_eng_grp_num; /* Kernel crypto engine group number */
index e19af13..5ebba86 100644 (file)
@@ -47,6 +47,7 @@ struct otx2_cptpf_dev {
        struct workqueue_struct *flr_wq;
        struct cptpf_flr_work   *flr_work;
 
+       unsigned long cap_flag;
        u8 pf_id;               /* RVU PF number */
        u8 max_vfs;             /* Maximum number of VFs supported by CPT */
        u8 enabled_vfs;         /* Number of enabled VFs */
index 58f47e3..146a55a 100644 (file)
@@ -6,10 +6,11 @@
 #include "otx2_cpt_common.h"
 #include "otx2_cptpf_ucode.h"
 #include "otx2_cptpf.h"
+#include "cn10k_cpt.h"
 #include "rvu_reg.h"
 
-#define OTX2_CPT_DRV_NAME    "octeontx2-cpt"
-#define OTX2_CPT_DRV_STRING  "Marvell OcteonTX2 CPT Physical Function Driver"
+#define OTX2_CPT_DRV_NAME    "rvu_cptpf"
+#define OTX2_CPT_DRV_STRING  "Marvell RVU CPT Physical Function Driver"
 
 static void cptpf_enable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf,
                                        int num_vfs)
@@ -62,45 +63,66 @@ static void cptpf_disable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf,
        }
 }
 
-static void cptpf_enable_vf_flr_intrs(struct otx2_cptpf_dev *cptpf)
+static void cptpf_enable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf,
+                                        int num_vfs)
 {
-       /* Clear interrupt if any */
+       /* Clear FLR interrupt if any */
        otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(0),
-                       ~0x0ULL);
-       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
-                       ~0x0ULL);
+                        INTR_MASK(num_vfs));
 
        /* Enable VF FLR interrupts */
        otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
-                        RVU_PF_VFFLR_INT_ENA_W1SX(0), ~0x0ULL);
+                        RVU_PF_VFFLR_INT_ENA_W1SX(0), INTR_MASK(num_vfs));
+       /* Clear ME interrupt if any */
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(0),
+                        INTR_MASK(num_vfs));
+       /* Enable VF ME interrupts */
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                        RVU_PF_VFME_INT_ENA_W1SX(0), INTR_MASK(num_vfs));
+
+       if (num_vfs <= 64)
+               return;
+
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
+                        INTR_MASK(num_vfs - 64));
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                        RVU_PF_VFFLR_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64));
+
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(1),
+                        INTR_MASK(num_vfs - 64));
        otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
-                        RVU_PF_VFFLR_INT_ENA_W1SX(1), ~0x0ULL);
+                        RVU_PF_VFME_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64));
 }
 
-static void cptpf_disable_vf_flr_intrs(struct otx2_cptpf_dev *cptpf,
+static void cptpf_disable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf,
                                       int num_vfs)
 {
        int vector;
 
        /* Disable VF FLR interrupts */
        otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
-                        RVU_PF_VFFLR_INT_ENA_W1CX(0), ~0x0ULL);
+                        RVU_PF_VFFLR_INT_ENA_W1CX(0), INTR_MASK(num_vfs));
+       vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR0);
+       free_irq(vector, cptpf);
+
+       /* Disable VF ME interrupts */
        otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
-                        RVU_PF_VFFLR_INT_ENA_W1CX(1), ~0x0ULL);
+                        RVU_PF_VFME_INT_ENA_W1CX(0), INTR_MASK(num_vfs));
+       vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME0);
+       free_irq(vector, cptpf);
 
-       /* Clear interrupt if any */
-       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(0),
-                        ~0x0ULL);
-       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
-                        ~0x0ULL);
+       if (num_vfs <= 64)
+               return;
 
-       vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR0);
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                        RVU_PF_VFFLR_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64));
+       vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR1);
        free_irq(vector, cptpf);
 
-       if (num_vfs > 64) {
-               vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR1);
-               free_irq(vector, cptpf);
-       }
+       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                        RVU_PF_VFME_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64));
+       vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME1);
+       free_irq(vector, cptpf);
 }
 
 static void cptpf_flr_wq_handler(struct work_struct *work)
@@ -172,11 +194,38 @@ static irqreturn_t cptpf_vf_flr_intr(int __always_unused irq, void *arg)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t cptpf_vf_me_intr(int __always_unused irq, void *arg)
+{
+       struct otx2_cptpf_dev *cptpf = arg;
+       int reg, vf, num_reg = 1;
+       u64 intr;
+
+       if (cptpf->max_vfs > 64)
+               num_reg = 2;
+
+       for (reg = 0; reg < num_reg; reg++) {
+               intr = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                                      RVU_PF_VFME_INTX(reg));
+               if (!intr)
+                       continue;
+               for (vf = 0; vf < 64; vf++) {
+                       if (!(intr & BIT_ULL(vf)))
+                               continue;
+                       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                                        RVU_PF_VFTRPENDX(reg), BIT_ULL(vf));
+                       /* Clear interrupt */
+                       otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+                                        RVU_PF_VFME_INTX(reg), BIT_ULL(vf));
+               }
+       }
+       return IRQ_HANDLED;
+}
+
 static void cptpf_unregister_vfpf_intr(struct otx2_cptpf_dev *cptpf,
                                       int num_vfs)
 {
        cptpf_disable_vfpf_mbox_intr(cptpf, num_vfs);
-       cptpf_disable_vf_flr_intrs(cptpf, num_vfs);
+       cptpf_disable_vf_flr_me_intrs(cptpf, num_vfs);
 }
 
 static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
@@ -202,6 +251,15 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
                        "IRQ registration failed for VFFLR0 irq\n");
                goto free_mbox0_irq;
        }
+       vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0);
+       /* Register VF ME interrupt handler */
+       ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME0", cptpf);
+       if (ret) {
+               dev_err(dev,
+                       "IRQ registration failed for PFVF mbox0 irq\n");
+               goto free_flr0_irq;
+       }
+
        if (num_vfs > 64) {
                vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1);
                ret = request_irq(vector, otx2_cptpf_vfpf_mbox_intr, 0,
@@ -209,7 +267,7 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
                if (ret) {
                        dev_err(dev,
                                "IRQ registration failed for PFVF mbox1 irq\n");
-                       goto free_flr0_irq;
+                       goto free_me0_irq;
                }
                vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1);
                /* Register VF FLR interrupt handler */
@@ -220,15 +278,30 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
                                "IRQ registration failed for VFFLR1 irq\n");
                        goto free_mbox1_irq;
                }
+               vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME1);
+               /* Register VF FLR interrupt handler */
+               ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME1",
+                                 cptpf);
+               if (ret) {
+                       dev_err(dev,
+                               "IRQ registration failed for VFFLR1 irq\n");
+                       goto free_flr1_irq;
+               }
        }
        cptpf_enable_vfpf_mbox_intr(cptpf, num_vfs);
-       cptpf_enable_vf_flr_intrs(cptpf);
+       cptpf_enable_vf_flr_me_intrs(cptpf, num_vfs);
 
        return 0;
 
+free_flr1_irq:
+       vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1);
+       free_irq(vector, cptpf);
 free_mbox1_irq:
        vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1);
        free_irq(vector, cptpf);
+free_me0_irq:
+       vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0);
+       free_irq(vector, cptpf);
 free_flr0_irq:
        vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR0);
        free_irq(vector, cptpf);
@@ -284,7 +357,11 @@ static int cptpf_vfpf_mbox_init(struct otx2_cptpf_dev *cptpf, int num_vfs)
                return -ENOMEM;
 
        /* Map VF-PF mailbox memory */
-       vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_BAR4_ADDR);
+       if (test_bit(CN10K_MBOX, &cptpf->cap_flag))
+               vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_MBOX_ADDR);
+       else
+               vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_BAR4_ADDR);
+
        if (!vfpf_mbox_base) {
                dev_err(dev, "VF-PF mailbox address not configured\n");
                err = -ENOMEM;
@@ -365,6 +442,8 @@ static int cptpf_register_afpf_mbox_intr(struct otx2_cptpf_dev *cptpf)
 
 static int cptpf_afpf_mbox_init(struct otx2_cptpf_dev *cptpf)
 {
+       struct pci_dev *pdev = cptpf->pdev;
+       resource_size_t offset;
        int err;
 
        cptpf->afpf_mbox_wq = alloc_workqueue("cpt_afpf_mailbox",
@@ -373,8 +452,17 @@ static int cptpf_afpf_mbox_init(struct otx2_cptpf_dev *cptpf)
        if (!cptpf->afpf_mbox_wq)
                return -ENOMEM;
 
+       offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+       /* Map AF-PF mailbox memory */
+       cptpf->afpf_mbox_base = devm_ioremap_wc(&pdev->dev, offset, MBOX_SIZE);
+       if (!cptpf->afpf_mbox_base) {
+               dev_err(&pdev->dev, "Unable to map BAR4\n");
+               err = -ENOMEM;
+               goto error;
+       }
+
        err = otx2_mbox_init(&cptpf->afpf_mbox, cptpf->afpf_mbox_base,
-                            cptpf->pdev, cptpf->reg_base, MBOX_DIR_PFAF, 1);
+                            pdev, cptpf->reg_base, MBOX_DIR_PFAF, 1);
        if (err)
                goto error;
 
@@ -570,7 +658,7 @@ static int cptpf_sriov_enable(struct pci_dev *pdev, int num_vfs)
        if (ret)
                goto disable_intr;
 
-       ret = otx2_cpt_create_eng_grps(cptpf->pdev, &cptpf->eng_grps);
+       ret = otx2_cpt_create_eng_grps(cptpf, &cptpf->eng_grps);
        if (ret)
                goto disable_intr;
 
@@ -607,7 +695,6 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
        struct device *dev = &pdev->dev;
-       resource_size_t offset, size;
        struct otx2_cptpf_dev *cptpf;
        int err;
 
@@ -644,15 +731,6 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
        if (err)
                goto clear_drvdata;
 
-       offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
-       size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
-       /* Map AF-PF mailbox memory */
-       cptpf->afpf_mbox_base = devm_ioremap_wc(dev, offset, size);
-       if (!cptpf->afpf_mbox_base) {
-               dev_err(&pdev->dev, "Unable to map BAR4\n");
-               err = -ENODEV;
-               goto clear_drvdata;
-       }
        err = pci_alloc_irq_vectors(pdev, RVU_PF_INT_VEC_CNT,
                                    RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX);
        if (err < 0) {
@@ -660,6 +738,7 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
                        RVU_PF_INT_VEC_CNT);
                goto clear_drvdata;
        }
+       otx2_cpt_set_hw_caps(pdev, &cptpf->cap_flag);
        /* Initialize AF-PF mailbox */
        err = cptpf_afpf_mbox_init(cptpf);
        if (err)
@@ -671,6 +750,10 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
 
        cptpf->max_vfs = pci_sriov_get_totalvfs(pdev);
 
+       err = cn10k_cptpf_lmtst_init(cptpf);
+       if (err)
+               goto unregister_intr;
+
        /* Initialize CPT PF device */
        err = cptpf_device_init(cptpf);
        if (err)
@@ -719,6 +802,7 @@ static void otx2_cptpf_remove(struct pci_dev *pdev)
 /* Supported devices */
 static const struct pci_device_id otx2_cpt_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX2_CPT_PCI_PF_DEVICE_ID) },
+       { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CN10K_CPT_PCI_PF_DEVICE_ID) },
        { 0, }  /* end of table */
 };
 
index a531f4c..dff34b3 100644 (file)
@@ -16,6 +16,8 @@
 #define LOADFVC_MAJOR_OP 0x01
 #define LOADFVC_MINOR_OP 0x08
 
+#define CTX_FLUSH_TIMER_CNT 0xFFFFFF
+
 struct fw_info_t {
        struct list_head ucodes;
 };
@@ -666,7 +668,8 @@ static int reserve_engines(struct device *dev,
 static void ucode_unload(struct device *dev, struct otx2_cpt_ucode *ucode)
 {
        if (ucode->va) {
-               dma_free_coherent(dev, ucode->size, ucode->va, ucode->dma);
+               dma_free_coherent(dev, OTX2_CPT_UCODE_SZ, ucode->va,
+                                 ucode->dma);
                ucode->va = NULL;
                ucode->dma = 0;
                ucode->size = 0;
@@ -685,7 +688,7 @@ static int copy_ucode_to_dma_mem(struct device *dev,
        u32 i;
 
        /*  Allocate DMAable space */
-       ucode->va = dma_alloc_coherent(dev, ucode->size, &ucode->dma,
+       ucode->va = dma_alloc_coherent(dev, OTX2_CPT_UCODE_SZ, &ucode->dma,
                                       GFP_KERNEL);
        if (!ucode->va)
                return -ENOMEM;
@@ -1100,11 +1103,12 @@ int otx2_cpt_get_eng_grp(struct otx2_cpt_eng_grps *eng_grps, int eng_type)
        return eng_grp_num;
 }
 
-int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
+int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf,
                             struct otx2_cpt_eng_grps *eng_grps)
 {
        struct otx2_cpt_uc_info_t *uc_info[OTX2_CPT_MAX_ETYPES_PER_GRP] = {  };
        struct otx2_cpt_engines engs[OTX2_CPT_MAX_ETYPES_PER_GRP] = { {0} };
+       struct pci_dev *pdev = cptpf->pdev;
        struct fw_info_t fw_info;
        int ret;
 
@@ -1180,6 +1184,23 @@ int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
        eng_grps->is_grps_created = true;
 
        cpt_ucode_release_fw(&fw_info);
+
+       if (is_dev_otx2(pdev))
+               return 0;
+       /*
+        * Configure engine group mask to allow context prefetching
+        * for the groups.
+        */
+       otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL,
+                             OTX2_CPT_ALL_ENG_GRPS_MASK << 3 | BIT_ULL(16),
+                             BLKADDR_CPT0);
+       /*
+        * Set interval to periodically flush dirty data for the next
+        * CTX cache entry. Set the interval count to maximum supported
+        * value.
+        */
+       otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTX_FLUSH_TIMER,
+                             CTX_FLUSH_TIMER_CNT, BLKADDR_CPT0);
        return 0;
 
 delete_eng_grp:
@@ -1460,9 +1481,10 @@ int otx2_cpt_discover_eng_capabilities(struct otx2_cptpf_dev *cptpf)
                iq_cmd.cptr.s.grp = otx2_cpt_get_eng_grp(&cptpf->eng_grps,
                                                         etype);
                otx2_cpt_fill_inst(&inst, &iq_cmd, rptr_baddr);
-               otx2_cpt_send_cmd(&inst, 1, &cptpf->lfs.lf[0]);
+               lfs->ops->send_cmd(&inst, 1, &cptpf->lfs.lf[0]);
 
-               while (result->s.compcode == OTX2_CPT_COMPLETION_CODE_INIT)
+               while (lfs->ops->cpt_get_compcode(result) ==
+                                               OTX2_CPT_COMPLETION_CODE_INIT)
                        cpu_relax();
 
                cptpf->eng_caps[etype].u = be64_to_cpup(rptr);
index 6b0d432..fe019ab 100644 (file)
 /* Microcode version string length */
 #define OTX2_CPT_UCODE_VER_STR_SZ   44
 
-/* Maximum number of supported engines/cores on OcteonTX2 platform */
-#define OTX2_CPT_MAX_ENGINES        128
+/* Maximum number of supported engines/cores on OcteonTX2/CN10K platform */
+#define OTX2_CPT_MAX_ENGINES        144
 
 #define OTX2_CPT_ENGS_BITMASK_LEN   BITS_TO_LONGS(OTX2_CPT_MAX_ENGINES)
 
+#define OTX2_CPT_UCODE_SZ           (64 * 1024)
+
 /* Microcode types */
 enum otx2_cpt_ucode_type {
        OTX2_CPT_AE_UC_TYPE = 1,  /* AE-MAIN */
@@ -153,7 +155,7 @@ int otx2_cpt_init_eng_grps(struct pci_dev *pdev,
                           struct otx2_cpt_eng_grps *eng_grps);
 void otx2_cpt_cleanup_eng_grps(struct pci_dev *pdev,
                               struct otx2_cpt_eng_grps *eng_grps);
-int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
+int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf,
                             struct otx2_cpt_eng_grps *eng_grps);
 int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf);
 int otx2_cpt_get_eng_grp(struct otx2_cpt_eng_grps *eng_grps, int eng_type);
index 4f0a169..4207e22 100644 (file)
@@ -19,11 +19,14 @@ struct otx2_cptvf_dev {
        struct otx2_mbox        pfvf_mbox;
        struct work_struct      pfvf_mbox_work;
        struct workqueue_struct *pfvf_mbox_wq;
+       void *bbuf_base;
+       unsigned long cap_flag;
 };
 
 irqreturn_t otx2_cptvf_pfvf_mbox_intr(int irq, void *arg);
 void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work);
 int otx2_cptvf_send_eng_grp_num_msg(struct otx2_cptvf_dev *cptvf, int eng_type);
 int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf);
+int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev);
 
 #endif /* __OTX2_CPTVF_H */
index 47f3787..3411e66 100644 (file)
@@ -5,9 +5,10 @@
 #include "otx2_cptvf.h"
 #include "otx2_cptlf.h"
 #include "otx2_cptvf_algs.h"
+#include "cn10k_cpt.h"
 #include <rvu_reg.h>
 
-#define OTX2_CPTVF_DRV_NAME "octeontx2-cptvf"
+#define OTX2_CPTVF_DRV_NAME "rvu_cptvf"
 
 static void cptvf_enable_pfvf_mbox_intrs(struct otx2_cptvf_dev *cptvf)
 {
@@ -70,6 +71,8 @@ static int cptvf_register_interrupts(struct otx2_cptvf_dev *cptvf)
 
 static int cptvf_pfvf_mbox_init(struct otx2_cptvf_dev *cptvf)
 {
+       struct pci_dev *pdev = cptvf->pdev;
+       resource_size_t offset, size;
        int ret;
 
        cptvf->pfvf_mbox_wq = alloc_workqueue("cpt_pfvf_mailbox",
@@ -78,14 +81,39 @@ static int cptvf_pfvf_mbox_init(struct otx2_cptvf_dev *cptvf)
        if (!cptvf->pfvf_mbox_wq)
                return -ENOMEM;
 
+       if (test_bit(CN10K_MBOX, &cptvf->cap_flag)) {
+               /* For cn10k platform, VF mailbox region is in its BAR2
+                * register space
+                */
+               cptvf->pfvf_mbox_base = cptvf->reg_base +
+                                       CN10K_CPT_VF_MBOX_REGION;
+       } else {
+               offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+               size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+               /* Map PF-VF mailbox memory */
+               cptvf->pfvf_mbox_base = devm_ioremap_wc(&pdev->dev, offset,
+                                                       size);
+               if (!cptvf->pfvf_mbox_base) {
+                       dev_err(&pdev->dev, "Unable to map BAR4\n");
+                       ret = -ENOMEM;
+                       goto free_wqe;
+               }
+       }
+
        ret = otx2_mbox_init(&cptvf->pfvf_mbox, cptvf->pfvf_mbox_base,
-                            cptvf->pdev, cptvf->reg_base, MBOX_DIR_VFPF, 1);
+                            pdev, cptvf->reg_base, MBOX_DIR_VFPF, 1);
        if (ret)
                goto free_wqe;
 
+       ret = otx2_cpt_mbox_bbuf_init(cptvf, pdev);
+       if (ret)
+               goto destroy_mbox;
+
        INIT_WORK(&cptvf->pfvf_mbox_work, otx2_cptvf_pfvf_mbox_handler);
        return 0;
 
+destroy_mbox:
+       otx2_mbox_destroy(&cptvf->pfvf_mbox);
 free_wqe:
        destroy_workqueue(cptvf->pfvf_mbox_wq);
        return ret;
@@ -305,7 +333,6 @@ static int otx2_cptvf_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
        struct device *dev = &pdev->dev;
-       resource_size_t offset, size;
        struct otx2_cptvf_dev *cptvf;
        int ret;
 
@@ -337,15 +364,12 @@ static int otx2_cptvf_probe(struct pci_dev *pdev,
 
        cptvf->reg_base = pcim_iomap_table(pdev)[PCI_PF_REG_BAR_NUM];
 
-       offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
-       size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
-       /* Map PF-VF mailbox memory */
-       cptvf->pfvf_mbox_base = devm_ioremap_wc(dev, offset, size);
-       if (!cptvf->pfvf_mbox_base) {
-               dev_err(&pdev->dev, "Unable to map BAR4\n");
-               ret = -ENODEV;
+       otx2_cpt_set_hw_caps(pdev, &cptvf->cap_flag);
+
+       ret = cn10k_cptvf_lmtst_init(cptvf);
+       if (ret)
                goto clear_drvdata;
-       }
+
        /* Initialize PF<=>VF mailbox */
        ret = cptvf_pfvf_mbox_init(cptvf);
        if (ret)
@@ -392,6 +416,7 @@ static void otx2_cptvf_remove(struct pci_dev *pdev)
 /* Supported devices */
 static const struct pci_device_id otx2_cptvf_id_table[] = {
        {PCI_VDEVICE(CAVIUM, OTX2_CPT_PCI_VF_DEVICE_ID), 0},
+       {PCI_VDEVICE(CAVIUM, CN10K_CPT_PCI_VF_DEVICE_ID), 0},
        { 0, }  /* end of table */
 };
 
@@ -405,6 +430,6 @@ static struct pci_driver otx2_cptvf_pci_driver = {
 module_pci_driver(otx2_cptvf_pci_driver);
 
 MODULE_AUTHOR("Marvell");
-MODULE_DESCRIPTION("Marvell OcteonTX2 CPT Virtual Function Driver");
+MODULE_DESCRIPTION("Marvell RVU CPT Virtual Function Driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(pci, otx2_cptvf_id_table);
index 5d73b71..02cb9e4 100644 (file)
@@ -5,6 +5,48 @@
 #include "otx2_cptvf.h"
 #include <rvu_reg.h>
 
+int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev)
+{
+       struct otx2_mbox_dev *mdev;
+       struct otx2_mbox *otx2_mbox;
+
+       cptvf->bbuf_base = devm_kmalloc(&pdev->dev, MBOX_SIZE, GFP_KERNEL);
+       if (!cptvf->bbuf_base)
+               return -ENOMEM;
+       /*
+        * Overwrite mbox mbase to point to bounce buffer, so that PF/VF
+        * prepare all mbox messages in bounce buffer instead of directly
+        * in hw mbox memory.
+        */
+       otx2_mbox = &cptvf->pfvf_mbox;
+       mdev = &otx2_mbox->dev[0];
+       mdev->mbase = cptvf->bbuf_base;
+
+       return 0;
+}
+
+static void otx2_cpt_sync_mbox_bbuf(struct otx2_mbox *mbox, int devid)
+{
+       u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+       void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
+       struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+       struct mbox_hdr *hdr;
+       u64 msg_size;
+
+       if (mdev->mbase == hw_mbase)
+               return;
+
+       hdr = hw_mbase + mbox->rx_start;
+       msg_size = hdr->msg_size;
+
+       if (msg_size > mbox->rx_size - msgs_offset)
+               msg_size = mbox->rx_size - msgs_offset;
+
+       /* Copy mbox messages from mbox memory to bounce buffer */
+       memcpy(mdev->mbase + mbox->rx_start,
+              hw_mbase + mbox->rx_start, msg_size + msgs_offset);
+}
+
 irqreturn_t otx2_cptvf_pfvf_mbox_intr(int __always_unused irq, void *arg)
 {
        struct otx2_cptvf_dev *cptvf = arg;
@@ -106,6 +148,7 @@ void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work)
 
        cptvf = container_of(work, struct otx2_cptvf_dev, pfvf_mbox_work);
        pfvf_mbox = &cptvf->pfvf_mbox;
+       otx2_cpt_sync_mbox_bbuf(pfvf_mbox, 0);
        mdev = &pfvf_mbox->dev[0];
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + pfvf_mbox->rx_start);
        if (rsp_hdr->num_msgs == 0)
index d5c1c1b..811ded7 100644 (file)
@@ -320,7 +320,7 @@ static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,
                             cpt_req->dlen, false);
 
        /* Send CPT command */
-       otx2_cpt_send_cmd(&cptinst, 1, lf);
+       lf->lfs->ops->send_cmd(&cptinst, 1, lf);
 
        /*
         * We allocate and prepare pending queue entry in critical section
@@ -349,13 +349,14 @@ int otx2_cpt_do_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,
                               &lfs->lf[cpu_num]);
 }
 
-static int cpt_process_ccode(struct pci_dev *pdev,
+static int cpt_process_ccode(struct otx2_cptlfs_info *lfs,
                             union otx2_cpt_res_s *cpt_status,
                             struct otx2_cpt_inst_info *info,
                             u32 *res_code)
 {
-       u8 uc_ccode = cpt_status->s.uc_compcode;
-       u8 ccode = cpt_status->s.compcode;
+       u8 uc_ccode = lfs->ops->cpt_get_uc_compcode(cpt_status);
+       u8 ccode = lfs->ops->cpt_get_compcode(cpt_status);
+       struct pci_dev *pdev = lfs->pdev;
 
        switch (ccode) {
        case OTX2_CPT_COMP_E_FAULT:
@@ -389,6 +390,7 @@ static int cpt_process_ccode(struct pci_dev *pdev,
                return 1;
 
        case OTX2_CPT_COMP_E_GOOD:
+       case OTX2_CPT_COMP_E_WARN:
                /*
                 * Check microcode completion code, it is only valid
                 * when completion code is CPT_COMP_E::GOOD
@@ -426,7 +428,7 @@ static int cpt_process_ccode(struct pci_dev *pdev,
        return 0;
 }
 
-static inline void process_pending_queue(struct pci_dev *pdev,
+static inline void process_pending_queue(struct otx2_cptlfs_info *lfs,
                                         struct otx2_cpt_pending_queue *pqueue)
 {
        struct otx2_cpt_pending_entry *resume_pentry = NULL;
@@ -436,6 +438,7 @@ static inline void process_pending_queue(struct pci_dev *pdev,
        struct otx2_cpt_inst_info *info = NULL;
        struct otx2_cpt_req_info *req = NULL;
        struct crypto_async_request *areq;
+       struct pci_dev *pdev = lfs->pdev;
        u32 res_code, resume_index;
 
        while (1) {
@@ -476,7 +479,7 @@ static inline void process_pending_queue(struct pci_dev *pdev,
                        goto process_pentry;
                }
 
-               if (cpt_process_ccode(pdev, cpt_status, info, &res_code)) {
+               if (cpt_process_ccode(lfs, cpt_status, info, &res_code)) {
                        spin_unlock_bh(&pqueue->lock);
                        return;
                }
@@ -529,7 +532,7 @@ process_pentry:
 
 void otx2_cpt_post_process(struct otx2_cptlf_wqe *wqe)
 {
-       process_pending_queue(wqe->lfs->pdev,
+       process_pending_queue(wqe->lfs,
                              &wqe->lfs->lf[wqe->lf_num].pqueue);
 }
 
index cc8dd30..1491cbf 100644 (file)
@@ -264,8 +264,8 @@ static int nx842_validate_result(struct device *dev,
  * @inlen: Length of input buffer
  * @out: Pointer to output buffer
  * @outlen: Length of output buffer
- * @wrkmem: ptr to buffer for working memory, size determined by
- *          nx842_pseries_driver.workmem_size
+ * @wmem: ptr to buffer for working memory, size determined by
+ *        nx842_pseries_driver.workmem_size
  *
  * Returns:
  *   0         Success, output of length @outlen stored in the buffer at @out
@@ -393,8 +393,8 @@ unlock:
  * @inlen: Length of input buffer
  * @out: Pointer to output buffer
  * @outlen: Length of output buffer
- * @wrkmem: ptr to buffer for working memory, size determined by
- *          nx842_pseries_driver.workmem_size
+ * @wmem: ptr to buffer for working memory, size determined by
+ *        nx842_pseries_driver.workmem_size
  *
  * Returns:
  *   0         Success, output of length @outlen stored in the buffer at @out
@@ -513,7 +513,7 @@ unlock:
 /**
  * nx842_OF_set_defaults -- Set default (disabled) values for devdata
  *
- * @devdata - struct nx842_devdata to update
+ * @devdata: struct nx842_devdata to update
  *
  * Returns:
  *  0 on success
@@ -538,13 +538,15 @@ static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
  * The status field indicates if the device is enabled when the status
  * is 'okay'.  Otherwise the device driver will be disabled.
  *
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to use for dev_info
+ * @prop: struct property point containing the maxsyncop for the update
  *
  * Returns:
  *  0 - Device is available
  *  -ENODEV - Device is not available
  */
-static int nx842_OF_upd_status(struct property *prop)
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+                              struct property *prop)
 {
        const char *status = (const char *)prop->value;
 
@@ -571,8 +573,8 @@ static int nx842_OF_upd_status(struct property *prop)
  *  In this example, the maximum byte length of a scatter list is
  *  0x0ff0 (4,080).
  *
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to update
+ * @prop: struct property point containing the maxsyncop for the update
  *
  * Returns:
  *  0 on success
@@ -619,8 +621,8 @@ static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
  *  0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
  *  elements.
  *
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to update
+ * @prop: struct property point containing the maxsyncop for the update
  *
  * Returns:
  *  0 on success
@@ -689,7 +691,6 @@ out:
 }
 
 /**
- *
  * nx842_OF_upd -- Handle OF properties updates for the device.
  *
  * Set all properties from the OF tree.  Optionally, a new property
@@ -758,7 +759,7 @@ static int nx842_OF_upd(struct property *new_prop)
                goto out;
 
        /* Perform property updates */
-       ret = nx842_OF_upd_status(status);
+       ret = nx842_OF_upd_status(new_devdata, status);
        if (ret)
                goto error_out;
 
@@ -812,8 +813,7 @@ error_out:
  *
  * @np: notifier block
  * @action: notifier action
- * @update: struct pSeries_reconfig_prop_update pointer if action is
- *     PSERIES_UPDATE_PROPERTY
+ * @data: struct of_reconfig_data pointer
  *
  * Returns:
  *     NOTIFY_OK on success
@@ -1069,6 +1069,7 @@ static const struct vio_device_id nx842_vio_driver_ids[] = {
        {"ibm,compression-v1", "ibm,compression"},
        {"", ""},
 };
+MODULE_DEVICE_TABLE(vio, nx842_vio_driver_ids);
 
 static struct vio_driver nx842_vio_driver = {
        .name = KBUILD_MODNAME,
index d6314ea..0e440f7 100644 (file)
@@ -88,7 +88,7 @@ static int cbc_aes_nx_crypt(struct skcipher_request *req,
 
                memcpy(req->iv, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
index e7384d1..3793885 100644 (file)
@@ -391,7 +391,7 @@ static int ccm_nx_decrypt(struct aead_request   *req,
 
                /* update stats */
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
@@ -460,7 +460,7 @@ static int ccm_nx_encrypt(struct aead_request   *req,
 
                /* update stats */
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
index 13f5188..dfa3ad1 100644 (file)
@@ -102,7 +102,7 @@ static int ctr_aes_nx_crypt(struct skcipher_request *req, u8 *iv)
                memcpy(iv, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
 
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
@@ -118,7 +118,7 @@ static int ctr3686_aes_nx_crypt(struct skcipher_request *req)
        struct nx_crypto_ctx *nx_ctx = crypto_skcipher_ctx(tfm);
        u8 iv[16];
 
-       memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_IV_SIZE);
+       memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_NONCE_SIZE);
        memcpy(iv + CTR_RFC3686_NONCE_SIZE, req->iv, CTR_RFC3686_IV_SIZE);
        iv[12] = iv[13] = iv[14] = 0;
        iv[15] = 1;
index 7a729dc..502a565 100644 (file)
@@ -86,7 +86,7 @@ static int ecb_aes_nx_crypt(struct skcipher_request *req,
                        goto out;
 
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
index fc9baca..4a79631 100644 (file)
@@ -382,7 +382,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc,
                NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 
                atomic_inc(&(nx_ctx->stats->aes_ops));
-               atomic64_add(csbcpb->csb.processed_byte_count,
+               atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
                             &(nx_ctx->stats->aes_bytes));
 
                processed += to_process;
index 446f611..655361b 100644 (file)
@@ -660,8 +660,8 @@ static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,
  * @inlen: input buffer size
  * @out: output buffer pointer
  * @outlenp: output buffer size pointer
- * @workmem: working memory buffer pointer, size determined by
- *           nx842_powernv_driver.workmem_size
+ * @wmem: working memory buffer pointer, size determined by
+ *        nx842_powernv_driver.workmem_size
  *
  * Returns: see @nx842_powernv_exec()
  */
index b0ad665..c3bebf0 100644 (file)
 #include "nx_csbcpb.h"
 #include "nx.h"
 
+struct sha256_state_be {
+       __be32 state[SHA256_DIGEST_SIZE / 4];
+       u64 count;
+       u8 buf[SHA256_BLOCK_SIZE];
+};
 
 static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm)
 {
@@ -36,7 +41,7 @@ static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm)
 }
 
 static int nx_sha256_init(struct shash_desc *desc) {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct sha256_state_be *sctx = shash_desc_ctx(desc);
 
        memset(sctx, 0, sizeof *sctx);
 
@@ -56,7 +61,7 @@ static int nx_sha256_init(struct shash_desc *desc) {
 static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
                            unsigned int len)
 {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct sha256_state_be *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *out_sg;
@@ -175,7 +180,7 @@ out:
 
 static int nx_sha256_final(struct shash_desc *desc, u8 *out)
 {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct sha256_state_be *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg, *out_sg;
@@ -245,7 +250,7 @@ out:
 
 static int nx_sha256_export(struct shash_desc *desc, void *out)
 {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct sha256_state_be *sctx = shash_desc_ctx(desc);
 
        memcpy(out, sctx, sizeof(*sctx));
 
@@ -254,7 +259,7 @@ static int nx_sha256_export(struct shash_desc *desc, void *out)
 
 static int nx_sha256_import(struct shash_desc *desc, const void *in)
 {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
+       struct sha256_state_be *sctx = shash_desc_ctx(desc);
 
        memcpy(sctx, in, sizeof(*sctx));
 
@@ -268,8 +273,8 @@ struct shash_alg nx_shash_sha256_alg = {
        .final      = nx_sha256_final,
        .export     = nx_sha256_export,
        .import     = nx_sha256_import,
-       .descsize   = sizeof(struct sha256_state),
-       .statesize  = sizeof(struct sha256_state),
+       .descsize   = sizeof(struct sha256_state_be),
+       .statesize  = sizeof(struct sha256_state_be),
        .base       = {
                .cra_name        = "sha256",
                .cra_driver_name = "sha256-nx",
index c29103a..1ffb40d 100644 (file)
 #include "nx_csbcpb.h"
 #include "nx.h"
 
+struct sha512_state_be {
+       __be64 state[SHA512_DIGEST_SIZE / 8];
+       u64 count[2];
+       u8 buf[SHA512_BLOCK_SIZE];
+};
 
 static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm)
 {
@@ -36,7 +41,7 @@ static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm)
 
 static int nx_sha512_init(struct shash_desc *desc)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct sha512_state_be *sctx = shash_desc_ctx(desc);
 
        memset(sctx, 0, sizeof *sctx);
 
@@ -56,7 +61,7 @@ static int nx_sha512_init(struct shash_desc *desc)
 static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
                            unsigned int len)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct sha512_state_be *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *out_sg;
@@ -178,7 +183,7 @@ out:
 
 static int nx_sha512_final(struct shash_desc *desc, u8 *out)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct sha512_state_be *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
        struct nx_sg *in_sg, *out_sg;
@@ -251,7 +256,7 @@ out:
 
 static int nx_sha512_export(struct shash_desc *desc, void *out)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct sha512_state_be *sctx = shash_desc_ctx(desc);
 
        memcpy(out, sctx, sizeof(*sctx));
 
@@ -260,7 +265,7 @@ static int nx_sha512_export(struct shash_desc *desc, void *out)
 
 static int nx_sha512_import(struct shash_desc *desc, const void *in)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
+       struct sha512_state_be *sctx = shash_desc_ctx(desc);
 
        memcpy(sctx, in, sizeof(*sctx));
 
@@ -274,8 +279,8 @@ struct shash_alg nx_shash_sha512_alg = {
        .final      = nx_sha512_final,
        .export     = nx_sha512_export,
        .import     = nx_sha512_import,
-       .descsize   = sizeof(struct sha512_state),
-       .statesize  = sizeof(struct sha512_state),
+       .descsize   = sizeof(struct sha512_state_be),
+       .statesize  = sizeof(struct sha512_state_be),
        .base       = {
                .cra_name        = "sha512",
                .cra_driver_name = "sha512-nx",
index 493f849..e64f7e3 100644 (file)
@@ -140,8 +140,8 @@ struct cop_status_block {
        u8 crb_seq_number;
        u8 completion_code;
        u8 completion_extension;
-       u32 processed_byte_count;
-       u64 address;
+       __be32 processed_byte_count;
+       __be64 address;
 } __packed;
 
 /* Nest accelerator workbook section 4.4 */
index c9d38bc..bc86313 100644 (file)
@@ -229,9 +229,8 @@ static int omap_des_hw_init(struct omap_des_dev *dd)
         * It may be long delays between requests.
         * Device might go to off mode to save power.
         */
-       err = pm_runtime_get_sync(dd->dev);
+       err = pm_runtime_resume_and_get(dd->dev);
        if (err < 0) {
-               pm_runtime_put_noidle(dd->dev);
                dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
                return err;
        }
@@ -994,9 +993,8 @@ static int omap_des_probe(struct platform_device *pdev)
        pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
 
        pm_runtime_enable(dev);
-       err = pm_runtime_get_sync(dev);
+       err = pm_runtime_resume_and_get(dev);
        if (err < 0) {
-               pm_runtime_put_noidle(dev);
                dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
                goto err_get;
        }
@@ -1124,9 +1122,8 @@ static int omap_des_resume(struct device *dev)
 {
        int err;
 
-       err = pm_runtime_get_sync(dev);
+       err = pm_runtime_resume_and_get(dev);
        if (err < 0) {
-               pm_runtime_put_noidle(dev);
                dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err);
                return err;
        }
index ae0d320..dd53ad9 100644 (file)
@@ -372,7 +372,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
 {
        int err;
 
-       err = pm_runtime_get_sync(dd->dev);
+       err = pm_runtime_resume_and_get(dd->dev);
        if (err < 0) {
                dev_err(dd->dev, "failed to get sync: %d\n", err);
                return err;
@@ -2244,7 +2244,7 @@ static int omap_sham_suspend(struct device *dev)
 
 static int omap_sham_resume(struct device *dev)
 {
-       int err = pm_runtime_get_sync(dev);
+       int err = pm_runtime_resume_and_get(dev);
        if (err < 0) {
                dev_err(dev, "failed to get sync: %d\n", err);
                return err;
index b8f3463..7eb5dae 100644 (file)
@@ -24,7 +24,7 @@ struct icp_qat_fw_loader_hal_handle {
 };
 
 struct icp_qat_fw_loader_chip_info {
-       bool sram_visible;
+       int mmp_sram_size;
        bool nn;
        bool lm2lm3;
        u32 lm_size;
index bd30281..12ca6b8 100644 (file)
@@ -696,7 +696,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
        handle->pci_dev = pci_info->pci_dev;
        switch (handle->pci_dev->device) {
        case ADF_4XXX_PCI_DEVICE_ID:
-               handle->chip_info->sram_visible = false;
+               handle->chip_info->mmp_sram_size = 0;
                handle->chip_info->nn = false;
                handle->chip_info->lm2lm3 = true;
                handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG_2X;
@@ -730,7 +730,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
                break;
        case PCI_DEVICE_ID_INTEL_QAT_C62X:
        case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
-               handle->chip_info->sram_visible = false;
+               handle->chip_info->mmp_sram_size = 0;
                handle->chip_info->nn = true;
                handle->chip_info->lm2lm3 = false;
                handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG;
@@ -763,7 +763,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
                        + LOCAL_TO_XFER_REG_OFFSET);
                break;
        case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
-               handle->chip_info->sram_visible = true;
+               handle->chip_info->mmp_sram_size = 0x40000;
                handle->chip_info->nn = true;
                handle->chip_info->lm2lm3 = false;
                handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG;
@@ -800,7 +800,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
                goto out_err;
        }
 
-       if (handle->chip_info->sram_visible) {
+       if (handle->chip_info->mmp_sram_size > 0) {
                sram_bar =
                        &pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)];
                handle->hal_sram_addr_v = sram_bar->virt_addr;
@@ -1417,7 +1417,11 @@ static int qat_hal_put_rel_wr_xfer(struct icp_qat_fw_loader_handle *handle,
                pr_err("QAT: bad xfrAddr=0x%x\n", xfr_addr);
                return -EINVAL;
        }
-       qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+       status = qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+       if (status) {
+               pr_err("QAT: failed to read register");
+               return status;
+       }
        gpr_addr = qat_hal_get_reg_addr(ICP_GPB_REL, gprnum);
        data16low = 0xffff & data;
        data16hi = 0xffff & (data >> 0x10);
index 1fb5fc8..2026cc6 100644 (file)
@@ -342,7 +342,6 @@ static int qat_uclo_init_umem_seg(struct icp_qat_fw_loader_handle *handle,
        return 0;
 }
 
-#define ICP_DH895XCC_PESRAM_BAR_SIZE 0x80000
 static int qat_uclo_init_ae_memory(struct icp_qat_fw_loader_handle *handle,
                                   struct icp_qat_uof_initmem *init_mem)
 {
@@ -1546,15 +1545,14 @@ int qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle,
        int status = 0;
 
        if (handle->chip_info->fw_auth) {
-               if (!qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc))
+               status = qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc);
+               if (!status)
                        status = qat_uclo_auth_fw(handle, desc);
                qat_uclo_ummap_auth_fw(handle, &desc);
        } else {
-               if (!handle->chip_info->sram_visible) {
-                       dev_dbg(&handle->pci_dev->dev,
-                               "QAT MMP fw not loaded for device 0x%x",
-                               handle->pci_dev->device);
-                       return status;
+               if (handle->chip_info->mmp_sram_size < mem_size) {
+                       pr_err("QAT: MMP size is too large: 0x%x\n", mem_size);
+                       return -EFBIG;
                }
                qat_uclo_wr_sram_by_words(handle, 0, addr_ptr, mem_size);
        }
index 14ade8a..2cf8984 100644 (file)
@@ -6,3 +6,4 @@ qcrypto-objs := core.o \
 
 qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SHA) += sha.o
 qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) += skcipher.o
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_AEAD) += aead.o
diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c
new file mode 100644 (file)
index 0000000..290e244
--- /dev/null
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2021, Linaro Limited. All rights reserved.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <crypto/gcm.h>
+#include <crypto/authenc.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/des.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/scatterwalk.h>
+#include "aead.h"
+
+#define CCM_NONCE_ADATA_SHIFT          6
+#define CCM_NONCE_AUTHSIZE_SHIFT       3
+#define MAX_CCM_ADATA_HEADER_LEN        6
+
+static LIST_HEAD(aead_algs);
+
+static void qce_aead_done(void *data)
+{
+       struct crypto_async_request *async_req = data;
+       struct aead_request *req = aead_request_cast(async_req);
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+       struct qce_result_dump *result_buf = qce->dma.result_buf;
+       enum dma_data_direction dir_src, dir_dst;
+       bool diff_dst;
+       int error;
+       u32 status;
+       unsigned int totallen;
+       unsigned char tag[SHA256_DIGEST_SIZE] = {0};
+       int ret = 0;
+
+       diff_dst = (req->src != req->dst) ? true : false;
+       dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+       dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+       error = qce_dma_terminate_all(&qce->dma);
+       if (error)
+               dev_dbg(qce->dev, "aead dma termination error (%d)\n",
+                       error);
+       if (diff_dst)
+               dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
+
+       dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+
+       if (IS_CCM(rctx->flags)) {
+               if (req->assoclen) {
+                       sg_free_table(&rctx->src_tbl);
+                       if (diff_dst)
+                               sg_free_table(&rctx->dst_tbl);
+               } else {
+                       if (!(IS_DECRYPT(rctx->flags) && !diff_dst))
+                               sg_free_table(&rctx->dst_tbl);
+               }
+       } else {
+               sg_free_table(&rctx->dst_tbl);
+       }
+
+       error = qce_check_status(qce, &status);
+       if (error < 0 && (error != -EBADMSG))
+               dev_err(qce->dev, "aead operation error (%x)\n", status);
+
+       if (IS_ENCRYPT(rctx->flags)) {
+               totallen = req->cryptlen + req->assoclen;
+               if (IS_CCM(rctx->flags))
+                       scatterwalk_map_and_copy(rctx->ccmresult_buf, req->dst,
+                                                totallen, ctx->authsize, 1);
+               else
+                       scatterwalk_map_and_copy(result_buf->auth_iv, req->dst,
+                                                totallen, ctx->authsize, 1);
+
+       } else if (!IS_CCM(rctx->flags)) {
+               totallen = req->cryptlen + req->assoclen - ctx->authsize;
+               scatterwalk_map_and_copy(tag, req->src, totallen, ctx->authsize, 0);
+               ret = memcmp(result_buf->auth_iv, tag, ctx->authsize);
+               if (ret) {
+                       pr_err("Bad message error\n");
+                       error = -EBADMSG;
+               }
+       }
+
+       qce->async_req_done(qce, error);
+}
+
+static struct scatterlist *
+qce_aead_prepare_result_buf(struct sg_table *tbl, struct aead_request *req)
+{
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+
+       sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
+       return qce_sgtable_add(tbl, &rctx->result_sg, QCE_RESULT_BUF_SZ);
+}
+
+static struct scatterlist *
+qce_aead_prepare_ccm_result_buf(struct sg_table *tbl, struct aead_request *req)
+{
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+
+       sg_init_one(&rctx->result_sg, rctx->ccmresult_buf, QCE_BAM_BURST_SIZE);
+       return qce_sgtable_add(tbl, &rctx->result_sg, QCE_BAM_BURST_SIZE);
+}
+
+static struct scatterlist *
+qce_aead_prepare_dst_buf(struct aead_request *req)
+{
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+       struct scatterlist *sg, *msg_sg, __sg[2];
+       gfp_t gfp;
+       unsigned int assoclen = req->assoclen;
+       unsigned int totallen;
+       int ret;
+
+       totallen = rctx->cryptlen + assoclen;
+       rctx->dst_nents = sg_nents_for_len(req->dst, totallen);
+       if (rctx->dst_nents < 0) {
+               dev_err(qce->dev, "Invalid numbers of dst SG.\n");
+               return ERR_PTR(-EINVAL);
+       }
+       if (IS_CCM(rctx->flags))
+               rctx->dst_nents += 2;
+       else
+               rctx->dst_nents += 1;
+
+       gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+                                               GFP_KERNEL : GFP_ATOMIC;
+       ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (IS_CCM(rctx->flags) && assoclen) {
+               /* Get the dst buffer */
+               msg_sg = scatterwalk_ffwd(__sg, req->dst, assoclen);
+
+               sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->adata_sg,
+                                    rctx->assoclen);
+               if (IS_ERR(sg)) {
+                       ret = PTR_ERR(sg);
+                       goto dst_tbl_free;
+               }
+               /* dst buffer */
+               sg = qce_sgtable_add(&rctx->dst_tbl, msg_sg, rctx->cryptlen);
+               if (IS_ERR(sg)) {
+                       ret = PTR_ERR(sg);
+                       goto dst_tbl_free;
+               }
+               totallen = rctx->cryptlen + rctx->assoclen;
+       } else {
+               if (totallen) {
+                       sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, totallen);
+                       if (IS_ERR(sg))
+                               goto dst_tbl_free;
+               }
+       }
+       if (IS_CCM(rctx->flags))
+               sg = qce_aead_prepare_ccm_result_buf(&rctx->dst_tbl, req);
+       else
+               sg = qce_aead_prepare_result_buf(&rctx->dst_tbl, req);
+
+       if (IS_ERR(sg))
+               goto dst_tbl_free;
+
+       sg_mark_end(sg);
+       rctx->dst_sg = rctx->dst_tbl.sgl;
+       rctx->dst_nents = sg_nents_for_len(rctx->dst_sg, totallen) + 1;
+
+       return sg;
+
+dst_tbl_free:
+       sg_free_table(&rctx->dst_tbl);
+       return sg;
+}
+
+static int
+qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req)
+{
+       struct scatterlist *sg, *msg_sg, __sg[2];
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned int assoclen = rctx->assoclen;
+       unsigned int adata_header_len, cryptlen, totallen;
+       gfp_t gfp;
+       bool diff_dst;
+       int ret;
+
+       if (IS_DECRYPT(rctx->flags))
+               cryptlen = rctx->cryptlen + ctx->authsize;
+       else
+               cryptlen = rctx->cryptlen;
+       totallen = cryptlen + req->assoclen;
+
+       /* Get the msg */
+       msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen);
+
+       rctx->adata = kzalloc((ALIGN(assoclen, 16) + MAX_CCM_ADATA_HEADER_LEN) *
+                              sizeof(unsigned char), GFP_ATOMIC);
+       if (!rctx->adata)
+               return -ENOMEM;
+
+       /*
+        * Format associated data (RFC3610 and NIST 800-38C)
+        * Even though specification allows for AAD to be up to 2^64 - 1 bytes,
+        * the assoclen field in aead_request is unsigned int and thus limits
+        * the AAD to be up to 2^32 - 1 bytes. So we handle only two scenarios
+        * while forming the header for AAD.
+        */
+       if (assoclen < 0xff00) {
+               adata_header_len = 2;
+               *(__be16 *)rctx->adata = cpu_to_be16(assoclen);
+       } else {
+               adata_header_len = 6;
+               *(__be16 *)rctx->adata = cpu_to_be16(0xfffe);
+               *(__be32 *)(rctx->adata + 2) = cpu_to_be32(assoclen);
+       }
+
+       /* Copy the associated data */
+       if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, assoclen),
+                             rctx->adata + adata_header_len,
+                             assoclen) != assoclen)
+               return -EINVAL;
+
+       /* Pad associated data to block size */
+       rctx->assoclen = ALIGN(assoclen + adata_header_len, 16);
+
+       diff_dst = (req->src != req->dst) ? true : false;
+
+       if (diff_dst)
+               rctx->src_nents = sg_nents_for_len(req->src, totallen) + 1;
+       else
+               rctx->src_nents = sg_nents_for_len(req->src, totallen) + 2;
+
+       gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC;
+       ret = sg_alloc_table(&rctx->src_tbl, rctx->src_nents, gfp);
+       if (ret)
+               return ret;
+
+       /* Associated Data */
+       sg_init_one(&rctx->adata_sg, rctx->adata, rctx->assoclen);
+       sg = qce_sgtable_add(&rctx->src_tbl, &rctx->adata_sg,
+                            rctx->assoclen);
+       if (IS_ERR(sg)) {
+               ret = PTR_ERR(sg);
+               goto err_free;
+       }
+       /* src msg */
+       sg = qce_sgtable_add(&rctx->src_tbl, msg_sg, cryptlen);
+       if (IS_ERR(sg)) {
+               ret = PTR_ERR(sg);
+               goto err_free;
+       }
+       if (!diff_dst) {
+               /*
+                * For decrypt, when src and dst buffers are same, there is already space
+                * in the buffer for padded 0's which is output in lieu of
+                * the MAC that is input. So skip the below.
+                */
+               if (!IS_DECRYPT(rctx->flags)) {
+                       sg = qce_aead_prepare_ccm_result_buf(&rctx->src_tbl, req);
+                       if (IS_ERR(sg)) {
+                               ret = PTR_ERR(sg);
+                               goto err_free;
+                       }
+               }
+       }
+       sg_mark_end(sg);
+       rctx->src_sg = rctx->src_tbl.sgl;
+       totallen = cryptlen + rctx->assoclen;
+       rctx->src_nents = sg_nents_for_len(rctx->src_sg, totallen);
+
+       if (diff_dst) {
+               sg = qce_aead_prepare_dst_buf(req);
+               if (IS_ERR(sg)) {
+                       ret = PTR_ERR(sg);
+                       goto err_free;
+               }
+       } else {
+               if (IS_ENCRYPT(rctx->flags))
+                       rctx->dst_nents = rctx->src_nents + 1;
+               else
+                       rctx->dst_nents = rctx->src_nents;
+               rctx->dst_sg = rctx->src_sg;
+       }
+
+       return 0;
+err_free:
+       sg_free_table(&rctx->src_tbl);
+       return ret;
+}
+
+static int qce_aead_prepare_buf(struct aead_request *req)
+{
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+       struct scatterlist *sg;
+       bool diff_dst = (req->src != req->dst) ? true : false;
+       unsigned int totallen;
+
+       totallen = rctx->cryptlen + rctx->assoclen;
+
+       sg = qce_aead_prepare_dst_buf(req);
+       if (IS_ERR(sg))
+               return PTR_ERR(sg);
+       if (diff_dst) {
+               rctx->src_nents = sg_nents_for_len(req->src, totallen);
+               if (rctx->src_nents < 0) {
+                       dev_err(qce->dev, "Invalid numbers of src SG.\n");
+                       return -EINVAL;
+               }
+               rctx->src_sg = req->src;
+       } else {
+               rctx->src_nents = rctx->dst_nents - 1;
+               rctx->src_sg = rctx->dst_sg;
+       }
+       return 0;
+}
+
+static int qce_aead_ccm_prepare_buf(struct aead_request *req)
+{
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       struct scatterlist *sg;
+       bool diff_dst = (req->src != req->dst) ? true : false;
+       unsigned int cryptlen;
+
+       if (rctx->assoclen)
+               return qce_aead_ccm_prepare_buf_assoclen(req);
+
+       if (IS_ENCRYPT(rctx->flags))
+               return qce_aead_prepare_buf(req);
+
+       cryptlen = rctx->cryptlen + ctx->authsize;
+       if (diff_dst) {
+               rctx->src_nents = sg_nents_for_len(req->src, cryptlen);
+               rctx->src_sg = req->src;
+               sg = qce_aead_prepare_dst_buf(req);
+               if (IS_ERR(sg))
+                       return PTR_ERR(sg);
+       } else {
+               rctx->src_nents = sg_nents_for_len(req->src, cryptlen);
+               rctx->src_sg = req->src;
+               rctx->dst_nents = rctx->src_nents;
+               rctx->dst_sg = rctx->src_sg;
+       }
+
+       return 0;
+}
+
+static int qce_aead_create_ccm_nonce(struct qce_aead_reqctx *rctx, struct qce_aead_ctx *ctx)
+{
+       unsigned int msglen_size, ivsize;
+       u8 msg_len[4];
+       int i;
+
+       if (!rctx || !rctx->iv)
+               return -EINVAL;
+
+       msglen_size = rctx->iv[0] + 1;
+
+       /* Verify that msg len size is valid */
+       if (msglen_size < 2 || msglen_size > 8)
+               return -EINVAL;
+
+       ivsize = rctx->ivsize;
+
+       /*
+        * Clear the msglen bytes in IV.
+        * Else the h/w engine and nonce will use any stray value pending there.
+        */
+       if (!IS_CCM_RFC4309(rctx->flags)) {
+               for (i = 0; i < msglen_size; i++)
+                       rctx->iv[ivsize - i - 1] = 0;
+       }
+
+       /*
+        * The crypto framework encodes cryptlen as unsigned int. Thus, even though
+        * spec allows for upto 8 bytes to encode msg_len only 4 bytes are needed.
+        */
+       if (msglen_size > 4)
+               msglen_size = 4;
+
+       memcpy(&msg_len[0], &rctx->cryptlen, 4);
+
+       memcpy(&rctx->ccm_nonce[0], rctx->iv, rctx->ivsize);
+       if (rctx->assoclen)
+               rctx->ccm_nonce[0] |= 1 << CCM_NONCE_ADATA_SHIFT;
+       rctx->ccm_nonce[0] |= ((ctx->authsize - 2) / 2) <<
+                               CCM_NONCE_AUTHSIZE_SHIFT;
+       for (i = 0; i < msglen_size; i++)
+               rctx->ccm_nonce[QCE_MAX_NONCE - i - 1] = msg_len[i];
+
+       return 0;
+}
+
+static int
+qce_aead_async_req_handle(struct crypto_async_request *async_req)
+{
+       struct aead_request *req = aead_request_cast(async_req);
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+       enum dma_data_direction dir_src, dir_dst;
+       bool diff_dst;
+       int dst_nents, src_nents, ret;
+
+       if (IS_CCM_RFC4309(rctx->flags)) {
+               memset(rctx->ccm_rfc4309_iv, 0, QCE_MAX_IV_SIZE);
+               rctx->ccm_rfc4309_iv[0] = 3;
+               memcpy(&rctx->ccm_rfc4309_iv[1], ctx->ccm4309_salt, QCE_CCM4309_SALT_SIZE);
+               memcpy(&rctx->ccm_rfc4309_iv[4], req->iv, 8);
+               rctx->iv = rctx->ccm_rfc4309_iv;
+               rctx->ivsize = AES_BLOCK_SIZE;
+       } else {
+               rctx->iv = req->iv;
+               rctx->ivsize = crypto_aead_ivsize(tfm);
+       }
+       if (IS_CCM_RFC4309(rctx->flags))
+               rctx->assoclen = req->assoclen - 8;
+       else
+               rctx->assoclen = req->assoclen;
+
+       diff_dst = (req->src != req->dst) ? true : false;
+       dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+       dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+       if (IS_CCM(rctx->flags)) {
+               ret = qce_aead_create_ccm_nonce(rctx, ctx);
+               if (ret)
+                       return ret;
+       }
+       if (IS_CCM(rctx->flags))
+               ret = qce_aead_ccm_prepare_buf(req);
+       else
+               ret = qce_aead_prepare_buf(req);
+
+       if (ret)
+               return ret;
+       dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+       if (dst_nents < 0) {
+               ret = dst_nents;
+               goto error_free;
+       }
+
+       if (diff_dst) {
+               src_nents = dma_map_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
+               if (src_nents < 0) {
+                       ret = src_nents;
+                       goto error_unmap_dst;
+               }
+       } else {
+               if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+                       src_nents = dst_nents;
+               else
+                       src_nents = dst_nents - 1;
+       }
+
+       ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents, rctx->dst_sg, dst_nents,
+                              qce_aead_done, async_req);
+       if (ret)
+               goto error_unmap_src;
+
+       qce_dma_issue_pending(&qce->dma);
+
+       ret = qce_start(async_req, tmpl->crypto_alg_type);
+       if (ret)
+               goto error_terminate;
+
+       return 0;
+
+error_terminate:
+       qce_dma_terminate_all(&qce->dma);
+error_unmap_src:
+       if (diff_dst)
+               dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+error_unmap_dst:
+       dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+error_free:
+       if (IS_CCM(rctx->flags) && rctx->assoclen) {
+               sg_free_table(&rctx->src_tbl);
+               if (diff_dst)
+                       sg_free_table(&rctx->dst_tbl);
+       } else {
+               sg_free_table(&rctx->dst_tbl);
+       }
+       return ret;
+}
+
+static int qce_aead_crypt(struct aead_request *req, int encrypt)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       struct qce_alg_template *tmpl = to_aead_tmpl(tfm);
+       unsigned int blocksize = crypto_aead_blocksize(tfm);
+
+       rctx->flags  = tmpl->alg_flags;
+       rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
+
+       if (encrypt)
+               rctx->cryptlen = req->cryptlen;
+       else
+               rctx->cryptlen = req->cryptlen - ctx->authsize;
+
+       /* CE does not handle 0 length messages */
+       if (!rctx->cryptlen) {
+               if (!(IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags)))
+                       ctx->need_fallback = true;
+       }
+
+       /* If fallback is needed, schedule and exit */
+       if (ctx->need_fallback) {
+               /* Reset need_fallback in case the same ctx is used for another transaction */
+               ctx->need_fallback = false;
+
+               aead_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+               aead_request_set_callback(&rctx->fallback_req, req->base.flags,
+                                         req->base.complete, req->base.data);
+               aead_request_set_crypt(&rctx->fallback_req, req->src,
+                                      req->dst, req->cryptlen, req->iv);
+               aead_request_set_ad(&rctx->fallback_req, req->assoclen);
+
+               return encrypt ? crypto_aead_encrypt(&rctx->fallback_req) :
+                                crypto_aead_decrypt(&rctx->fallback_req);
+       }
+
+       /*
+        * CBC algorithms require message lengths to be
+        * multiples of block size.
+        */
+       if (IS_CBC(rctx->flags) && !IS_ALIGNED(rctx->cryptlen, blocksize))
+               return -EINVAL;
+
+       /* RFC4309 supported AAD size 16 bytes/20 bytes */
+       if (IS_CCM_RFC4309(rctx->flags))
+               if (crypto_ipsec_check_assoclen(req->assoclen))
+                       return -EINVAL;
+
+       return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
+}
+
+static int qce_aead_encrypt(struct aead_request *req)
+{
+       return qce_aead_crypt(req, 1);
+}
+
+static int qce_aead_decrypt(struct aead_request *req)
+{
+       return qce_aead_crypt(req, 0);
+}
+
+static int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key,
+                              unsigned int keylen)
+{
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+
+       if (IS_CCM_RFC4309(flags)) {
+               if (keylen < QCE_CCM4309_SALT_SIZE)
+                       return -EINVAL;
+               keylen -= QCE_CCM4309_SALT_SIZE;
+               memcpy(ctx->ccm4309_salt, key + keylen, QCE_CCM4309_SALT_SIZE);
+       }
+
+       if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192)
+               return -EINVAL;
+
+       ctx->enc_keylen = keylen;
+       ctx->auth_keylen = keylen;
+
+       memcpy(ctx->enc_key, key, keylen);
+       memcpy(ctx->auth_key, key, keylen);
+
+       if (keylen == AES_KEYSIZE_192)
+               ctx->need_fallback = true;
+
+       return IS_CCM_RFC4309(flags) ?
+               crypto_aead_setkey(ctx->fallback, key, keylen + QCE_CCM4309_SALT_SIZE) :
+               crypto_aead_setkey(ctx->fallback, key, keylen);
+}
+
+static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       struct crypto_authenc_keys authenc_keys;
+       unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+       u32 _key[6];
+       int err;
+
+       err = crypto_authenc_extractkeys(&authenc_keys, key, keylen);
+       if (err)
+               return err;
+
+       if (authenc_keys.enckeylen > QCE_MAX_KEY_SIZE ||
+           authenc_keys.authkeylen > QCE_MAX_KEY_SIZE)
+               return -EINVAL;
+
+       if (IS_DES(flags)) {
+               err = verify_aead_des_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
+               if (err)
+                       return err;
+       } else if (IS_3DES(flags)) {
+               err = verify_aead_des3_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
+               if (err)
+                       return err;
+               /*
+                * The crypto engine does not support any two keys
+                * being the same for triple des algorithms. The
+                * verify_skcipher_des3_key does not check for all the
+                * below conditions. Schedule fallback in this case.
+                */
+               memcpy(_key, authenc_keys.enckey, DES3_EDE_KEY_SIZE);
+               if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) ||
+                   !((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) ||
+                   !((_key[0] ^ _key[4]) | (_key[1] ^ _key[5])))
+                       ctx->need_fallback = true;
+       } else if (IS_AES(flags)) {
+               /* No random key sizes */
+               if (authenc_keys.enckeylen != AES_KEYSIZE_128 &&
+                   authenc_keys.enckeylen != AES_KEYSIZE_192 &&
+                   authenc_keys.enckeylen != AES_KEYSIZE_256)
+                       return -EINVAL;
+               if (authenc_keys.enckeylen == AES_KEYSIZE_192)
+                       ctx->need_fallback = true;
+       }
+
+       ctx->enc_keylen = authenc_keys.enckeylen;
+       ctx->auth_keylen = authenc_keys.authkeylen;
+
+       memcpy(ctx->enc_key, authenc_keys.enckey, authenc_keys.enckeylen);
+
+       memset(ctx->auth_key, 0, sizeof(ctx->auth_key));
+       memcpy(ctx->auth_key, authenc_keys.authkey, authenc_keys.authkeylen);
+
+       return crypto_aead_setkey(ctx->fallback, key, keylen);
+}
+
+static int qce_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+
+       if (IS_CCM(flags)) {
+               if (authsize < 4 || authsize > 16 || authsize % 2)
+                       return -EINVAL;
+               if (IS_CCM_RFC4309(flags) && (authsize < 8 || authsize % 4))
+                       return -EINVAL;
+       }
+       ctx->authsize = authsize;
+
+       return crypto_aead_setauthsize(ctx->fallback, authsize);
+}
+
+static int qce_aead_init(struct crypto_aead *tfm)
+{
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+       ctx->need_fallback = false;
+       ctx->fallback = crypto_alloc_aead(crypto_tfm_alg_name(&tfm->base),
+                                         0, CRYPTO_ALG_NEED_FALLBACK);
+
+       if (IS_ERR(ctx->fallback))
+               return PTR_ERR(ctx->fallback);
+
+       crypto_aead_set_reqsize(tfm, sizeof(struct qce_aead_reqctx) +
+                               crypto_aead_reqsize(ctx->fallback));
+       return 0;
+}
+
+static void qce_aead_exit(struct crypto_aead *tfm)
+{
+       struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+       crypto_free_aead(ctx->fallback);
+}
+
+struct qce_aead_def {
+       unsigned long flags;
+       const char *name;
+       const char *drv_name;
+       unsigned int blocksize;
+       unsigned int chunksize;
+       unsigned int ivsize;
+       unsigned int maxauthsize;
+};
+
+static const struct qce_aead_def aead_def[] = {
+       {
+               .flags          = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
+               .name           = "authenc(hmac(sha1),cbc(des))",
+               .drv_name       = "authenc-hmac-sha1-cbc-des-qce",
+               .blocksize      = DES_BLOCK_SIZE,
+               .ivsize         = DES_BLOCK_SIZE,
+               .maxauthsize    = SHA1_DIGEST_SIZE,
+       },
+       {
+               .flags          = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
+               .name           = "authenc(hmac(sha1),cbc(des3_ede))",
+               .drv_name       = "authenc-hmac-sha1-cbc-3des-qce",
+               .blocksize      = DES3_EDE_BLOCK_SIZE,
+               .ivsize         = DES3_EDE_BLOCK_SIZE,
+               .maxauthsize    = SHA1_DIGEST_SIZE,
+       },
+       {
+               .flags          = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+               .name           = "authenc(hmac(sha256),cbc(des))",
+               .drv_name       = "authenc-hmac-sha256-cbc-des-qce",
+               .blocksize      = DES_BLOCK_SIZE,
+               .ivsize         = DES_BLOCK_SIZE,
+               .maxauthsize    = SHA256_DIGEST_SIZE,
+       },
+       {
+               .flags          = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+               .name           = "authenc(hmac(sha256),cbc(des3_ede))",
+               .drv_name       = "authenc-hmac-sha256-cbc-3des-qce",
+               .blocksize      = DES3_EDE_BLOCK_SIZE,
+               .ivsize         = DES3_EDE_BLOCK_SIZE,
+               .maxauthsize    = SHA256_DIGEST_SIZE,
+       },
+       {
+               .flags          =  QCE_ALG_AES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+               .name           = "authenc(hmac(sha256),cbc(aes))",
+               .drv_name       = "authenc-hmac-sha256-cbc-aes-qce",
+               .blocksize      = AES_BLOCK_SIZE,
+               .ivsize         = AES_BLOCK_SIZE,
+               .maxauthsize    = SHA256_DIGEST_SIZE,
+       },
+       {
+               .flags          =  QCE_ALG_AES | QCE_MODE_CCM,
+               .name           = "ccm(aes)",
+               .drv_name       = "ccm-aes-qce",
+               .blocksize      = 1,
+               .ivsize         = AES_BLOCK_SIZE,
+               .maxauthsize    = AES_BLOCK_SIZE,
+       },
+       {
+               .flags          =  QCE_ALG_AES | QCE_MODE_CCM | QCE_MODE_CCM_RFC4309,
+               .name           = "rfc4309(ccm(aes))",
+               .drv_name       = "rfc4309-ccm-aes-qce",
+               .blocksize      = 1,
+               .ivsize         = 8,
+               .maxauthsize    = AES_BLOCK_SIZE,
+       },
+};
+
+static int qce_aead_register_one(const struct qce_aead_def *def, struct qce_device *qce)
+{
+       struct qce_alg_template *tmpl;
+       struct aead_alg *alg;
+       int ret;
+
+       tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
+       if (!tmpl)
+               return -ENOMEM;
+
+       alg = &tmpl->alg.aead;
+
+       snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
+       snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+                def->drv_name);
+
+       alg->base.cra_blocksize         = def->blocksize;
+       alg->chunksize                  = def->chunksize;
+       alg->ivsize                     = def->ivsize;
+       alg->maxauthsize                = def->maxauthsize;
+       if (IS_CCM(def->flags))
+               alg->setkey             = qce_aead_ccm_setkey;
+       else
+               alg->setkey             = qce_aead_setkey;
+       alg->setauthsize                = qce_aead_setauthsize;
+       alg->encrypt                    = qce_aead_encrypt;
+       alg->decrypt                    = qce_aead_decrypt;
+       alg->init                       = qce_aead_init;
+       alg->exit                       = qce_aead_exit;
+
+       alg->base.cra_priority          = 300;
+       alg->base.cra_flags             = CRYPTO_ALG_ASYNC |
+                                         CRYPTO_ALG_ALLOCATES_MEMORY |
+                                         CRYPTO_ALG_KERN_DRIVER_ONLY |
+                                         CRYPTO_ALG_NEED_FALLBACK;
+       alg->base.cra_ctxsize           = sizeof(struct qce_aead_ctx);
+       alg->base.cra_alignmask         = 0;
+       alg->base.cra_module            = THIS_MODULE;
+
+       INIT_LIST_HEAD(&tmpl->entry);
+       tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AEAD;
+       tmpl->alg_flags = def->flags;
+       tmpl->qce = qce;
+
+       ret = crypto_register_aead(alg);
+       if (ret) {
+               kfree(tmpl);
+               dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name);
+               return ret;
+       }
+
+       list_add_tail(&tmpl->entry, &aead_algs);
+       dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name);
+       return 0;
+}
+
+static void qce_aead_unregister(struct qce_device *qce)
+{
+       struct qce_alg_template *tmpl, *n;
+
+       list_for_each_entry_safe(tmpl, n, &aead_algs, entry) {
+               crypto_unregister_aead(&tmpl->alg.aead);
+               list_del(&tmpl->entry);
+               kfree(tmpl);
+       }
+}
+
+static int qce_aead_register(struct qce_device *qce)
+{
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(aead_def); i++) {
+               ret = qce_aead_register_one(&aead_def[i], qce);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       qce_aead_unregister(qce);
+       return ret;
+}
+
+const struct qce_algo_ops aead_ops = {
+       .type = CRYPTO_ALG_TYPE_AEAD,
+       .register_algs = qce_aead_register,
+       .unregister_algs = qce_aead_unregister,
+       .async_req_handle = qce_aead_async_req_handle,
+};
diff --git a/drivers/crypto/qce/aead.h b/drivers/crypto/qce/aead.h
new file mode 100644 (file)
index 0000000..efb8477
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
+ */
+
+#ifndef _AEAD_H_
+#define _AEAD_H_
+
+#include "common.h"
+#include "core.h"
+
+#define QCE_MAX_KEY_SIZE               64
+#define QCE_CCM4309_SALT_SIZE          3
+
+struct qce_aead_ctx {
+       u8 enc_key[QCE_MAX_KEY_SIZE];
+       u8 auth_key[QCE_MAX_KEY_SIZE];
+       u8 ccm4309_salt[QCE_CCM4309_SALT_SIZE];
+       unsigned int enc_keylen;
+       unsigned int auth_keylen;
+       unsigned int authsize;
+       bool need_fallback;
+       struct crypto_aead *fallback;
+};
+
+struct qce_aead_reqctx {
+       unsigned long flags;
+       u8 *iv;
+       unsigned int ivsize;
+       int src_nents;
+       int dst_nents;
+       struct scatterlist result_sg;
+       struct scatterlist adata_sg;
+       struct sg_table dst_tbl;
+       struct sg_table src_tbl;
+       struct scatterlist *dst_sg;
+       struct scatterlist *src_sg;
+       unsigned int cryptlen;
+       unsigned int assoclen;
+       unsigned char *adata;
+       u8 ccm_nonce[QCE_MAX_NONCE];
+       u8 ccmresult_buf[QCE_BAM_BURST_SIZE];
+       u8 ccm_rfc4309_iv[QCE_MAX_IV_SIZE];
+       struct aead_request fallback_req;
+};
+
+static inline struct qce_alg_template *to_aead_tmpl(struct crypto_aead *tfm)
+{
+       struct aead_alg *alg = crypto_aead_alg(tfm);
+
+       return container_of(alg, struct qce_alg_template, alg.aead);
+}
+
+extern const struct qce_algo_ops aead_ops;
+
+#endif /* _AEAD_H_ */
index dceb957..7c612ba 100644 (file)
@@ -15,6 +15,7 @@
 #include "core.h"
 #include "regs-v5.h"
 #include "sha.h"
+#include "aead.h"
 
 static inline u32 qce_read(struct qce_device *qce, u32 offset)
 {
@@ -88,17 +89,20 @@ static void qce_setup_config(struct qce_device *qce)
        qce_write(qce, REG_CONFIG, config);
 }
 
-static inline void qce_crypto_go(struct qce_device *qce)
+static inline void qce_crypto_go(struct qce_device *qce, bool result_dump)
 {
-       qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
+       if (result_dump)
+               qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
+       else
+               qce_write(qce, REG_GOPROC, BIT(GO_SHIFT));
 }
 
-#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
-static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
+#if defined(CONFIG_CRYPTO_DEV_QCE_SHA) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
+static u32 qce_auth_cfg(unsigned long flags, u32 key_size, u32 auth_size)
 {
        u32 cfg = 0;
 
-       if (IS_AES(flags) && (IS_CCM(flags) || IS_CMAC(flags)))
+       if (IS_CCM(flags) || IS_CMAC(flags))
                cfg |= AUTH_ALG_AES << AUTH_ALG_SHIFT;
        else
                cfg |= AUTH_ALG_SHA << AUTH_ALG_SHIFT;
@@ -116,15 +120,16 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
                cfg |= AUTH_SIZE_SHA256 << AUTH_SIZE_SHIFT;
        else if (IS_CMAC(flags))
                cfg |= AUTH_SIZE_ENUM_16_BYTES << AUTH_SIZE_SHIFT;
+       else if (IS_CCM(flags))
+               cfg |= (auth_size - 1) << AUTH_SIZE_SHIFT;
 
        if (IS_SHA1(flags) || IS_SHA256(flags))
                cfg |= AUTH_MODE_HASH << AUTH_MODE_SHIFT;
-       else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags) ||
-                IS_CBC(flags) || IS_CTR(flags))
+       else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags))
                cfg |= AUTH_MODE_HMAC << AUTH_MODE_SHIFT;
-       else if (IS_AES(flags) && IS_CCM(flags))
+       else if (IS_CCM(flags))
                cfg |= AUTH_MODE_CCM << AUTH_MODE_SHIFT;
-       else if (IS_AES(flags) && IS_CMAC(flags))
+       else if (IS_CMAC(flags))
                cfg |= AUTH_MODE_CMAC << AUTH_MODE_SHIFT;
 
        if (IS_SHA(flags) || IS_SHA_HMAC(flags))
@@ -133,13 +138,11 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
        if (IS_CCM(flags))
                cfg |= QCE_MAX_NONCE_WORDS << AUTH_NONCE_NUM_WORDS_SHIFT;
 
-       if (IS_CBC(flags) || IS_CTR(flags) || IS_CCM(flags) ||
-           IS_CMAC(flags))
-               cfg |= BIT(AUTH_LAST_SHIFT) | BIT(AUTH_FIRST_SHIFT);
-
        return cfg;
 }
+#endif
 
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
 static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
 {
        struct ahash_request *req = ahash_request_cast(async_req);
@@ -168,7 +171,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
                qce_clear_array(qce, REG_AUTH_KEY0, 16);
                qce_clear_array(qce, REG_AUTH_BYTECNT0, 4);
 
-               auth_cfg = qce_auth_cfg(rctx->flags, rctx->authklen);
+               auth_cfg = qce_auth_cfg(rctx->flags, rctx->authklen, digestsize);
        }
 
        if (IS_SHA_HMAC(rctx->flags) || IS_CMAC(rctx->flags)) {
@@ -196,7 +199,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
                qce_write_array(qce, REG_AUTH_BYTECNT0,
                                (u32 *)rctx->byte_count, 2);
 
-       auth_cfg = qce_auth_cfg(rctx->flags, 0);
+       auth_cfg = qce_auth_cfg(rctx->flags, 0, digestsize);
 
        if (rctx->last_blk)
                auth_cfg |= BIT(AUTH_LAST_SHIFT);
@@ -219,13 +222,13 @@ go_proc:
        config = qce_config_reg(qce, 1);
        qce_write(qce, REG_CONFIG, config);
 
-       qce_crypto_go(qce);
+       qce_crypto_go(qce, true);
 
        return 0;
 }
 #endif
 
-#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
+#if defined(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
 static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
 {
        u32 cfg = 0;
@@ -271,7 +274,9 @@ static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
 
        return cfg;
 }
+#endif
 
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
 static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
 {
        u8 swap[QCE_AES_IV_LENGTH];
@@ -380,7 +385,156 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)
        config = qce_config_reg(qce, 1);
        qce_write(qce, REG_CONFIG, config);
 
-       qce_crypto_go(qce);
+       qce_crypto_go(qce, true);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+static const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = {
+       SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
+};
+
+static const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = {
+       SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+       SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
+};
+
+static unsigned int qce_be32_to_cpu_array(u32 *dst, const u8 *src, unsigned int len)
+{
+       u32 *d = dst;
+       const u8 *s = src;
+       unsigned int n;
+
+       n = len / sizeof(u32);
+       for (; n > 0; n--) {
+               *d = be32_to_cpup((const __be32 *)s);
+               s += sizeof(u32);
+               d++;
+       }
+       return DIV_ROUND_UP(len, sizeof(u32));
+}
+
+static int qce_setup_regs_aead(struct crypto_async_request *async_req)
+{
+       struct aead_request *req = aead_request_cast(async_req);
+       struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+       struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+       struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+       struct qce_device *qce = tmpl->qce;
+       u32 enckey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
+       u32 enciv[QCE_MAX_IV_SIZE / sizeof(u32)] = {0};
+       u32 authkey[QCE_SHA_HMAC_KEY_SIZE / sizeof(u32)] = {0};
+       u32 authiv[SHA256_DIGEST_SIZE / sizeof(u32)] = {0};
+       u32 authnonce[QCE_MAX_NONCE / sizeof(u32)] = {0};
+       unsigned int enc_keylen = ctx->enc_keylen;
+       unsigned int auth_keylen = ctx->auth_keylen;
+       unsigned int enc_ivsize = rctx->ivsize;
+       unsigned int auth_ivsize = 0;
+       unsigned int enckey_words, enciv_words;
+       unsigned int authkey_words, authiv_words, authnonce_words;
+       unsigned long flags = rctx->flags;
+       u32 encr_cfg, auth_cfg, config, totallen;
+       u32 iv_last_word;
+
+       qce_setup_config(qce);
+
+       /* Write encryption key */
+       enckey_words = qce_be32_to_cpu_array(enckey, ctx->enc_key, enc_keylen);
+       qce_write_array(qce, REG_ENCR_KEY0, enckey, enckey_words);
+
+       /* Write encryption iv */
+       enciv_words = qce_be32_to_cpu_array(enciv, rctx->iv, enc_ivsize);
+       qce_write_array(qce, REG_CNTR0_IV0, enciv, enciv_words);
+
+       if (IS_CCM(rctx->flags)) {
+               iv_last_word = enciv[enciv_words - 1];
+               qce_write(qce, REG_CNTR3_IV3, iv_last_word + 1);
+               qce_write_array(qce, REG_ENCR_CCM_INT_CNTR0, (u32 *)enciv, enciv_words);
+               qce_write(qce, REG_CNTR_MASK, ~0);
+               qce_write(qce, REG_CNTR_MASK0, ~0);
+               qce_write(qce, REG_CNTR_MASK1, ~0);
+               qce_write(qce, REG_CNTR_MASK2, ~0);
+       }
+
+       /* Clear authentication IV and KEY registers of previous values */
+       qce_clear_array(qce, REG_AUTH_IV0, 16);
+       qce_clear_array(qce, REG_AUTH_KEY0, 16);
+
+       /* Clear byte count */
+       qce_clear_array(qce, REG_AUTH_BYTECNT0, 4);
+
+       /* Write authentication key */
+       authkey_words = qce_be32_to_cpu_array(authkey, ctx->auth_key, auth_keylen);
+       qce_write_array(qce, REG_AUTH_KEY0, (u32 *)authkey, authkey_words);
+
+       /* Write initial authentication IV only for HMAC algorithms */
+       if (IS_SHA_HMAC(rctx->flags)) {
+               /* Write default authentication iv */
+               if (IS_SHA1_HMAC(rctx->flags)) {
+                       auth_ivsize = SHA1_DIGEST_SIZE;
+                       memcpy(authiv, std_iv_sha1, auth_ivsize);
+               } else if (IS_SHA256_HMAC(rctx->flags)) {
+                       auth_ivsize = SHA256_DIGEST_SIZE;
+                       memcpy(authiv, std_iv_sha256, auth_ivsize);
+               }
+               authiv_words = auth_ivsize / sizeof(u32);
+               qce_write_array(qce, REG_AUTH_IV0, (u32 *)authiv, authiv_words);
+       } else if (IS_CCM(rctx->flags)) {
+               /* Write nonce for CCM algorithms */
+               authnonce_words = qce_be32_to_cpu_array(authnonce, rctx->ccm_nonce, QCE_MAX_NONCE);
+               qce_write_array(qce, REG_AUTH_INFO_NONCE0, authnonce, authnonce_words);
+       }
+
+       /* Set up ENCR_SEG_CFG */
+       encr_cfg = qce_encr_cfg(flags, enc_keylen);
+       if (IS_ENCRYPT(flags))
+               encr_cfg |= BIT(ENCODE_SHIFT);
+       qce_write(qce, REG_ENCR_SEG_CFG, encr_cfg);
+
+       /* Set up AUTH_SEG_CFG */
+       auth_cfg = qce_auth_cfg(rctx->flags, auth_keylen, ctx->authsize);
+       auth_cfg |= BIT(AUTH_LAST_SHIFT);
+       auth_cfg |= BIT(AUTH_FIRST_SHIFT);
+       if (IS_ENCRYPT(flags)) {
+               if (IS_CCM(rctx->flags))
+                       auth_cfg |= AUTH_POS_BEFORE << AUTH_POS_SHIFT;
+               else
+                       auth_cfg |= AUTH_POS_AFTER << AUTH_POS_SHIFT;
+       } else {
+               if (IS_CCM(rctx->flags))
+                       auth_cfg |= AUTH_POS_AFTER << AUTH_POS_SHIFT;
+               else
+                       auth_cfg |= AUTH_POS_BEFORE << AUTH_POS_SHIFT;
+       }
+       qce_write(qce, REG_AUTH_SEG_CFG, auth_cfg);
+
+       totallen = rctx->cryptlen + rctx->assoclen;
+
+       /* Set the encryption size and start offset */
+       if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+               qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen + ctx->authsize);
+       else
+               qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen);
+       qce_write(qce, REG_ENCR_SEG_START, rctx->assoclen & 0xffff);
+
+       /* Set the authentication size and start offset */
+       qce_write(qce, REG_AUTH_SEG_SIZE, totallen);
+       qce_write(qce, REG_AUTH_SEG_START, 0);
+
+       /* Write total length */
+       if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+               qce_write(qce, REG_SEG_SIZE, totallen + ctx->authsize);
+       else
+               qce_write(qce, REG_SEG_SIZE, totallen);
+
+       /* get little endianness */
+       config = qce_config_reg(qce, 1);
+       qce_write(qce, REG_CONFIG, config);
+
+       /* Start the process */
+       qce_crypto_go(qce, !IS_CCM(flags));
 
        return 0;
 }
@@ -397,6 +551,10 @@ int qce_start(struct crypto_async_request *async_req, u32 type)
        case CRYPTO_ALG_TYPE_AHASH:
                return qce_setup_regs_ahash(async_req);
 #endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+       case CRYPTO_ALG_TYPE_AEAD:
+               return qce_setup_regs_aead(async_req);
+#endif
        default:
                return -EINVAL;
        }
@@ -419,6 +577,8 @@ int qce_check_status(struct qce_device *qce, u32 *status)
         */
        if (*status & STATUS_ERRORS || !(*status & BIT(OPERATION_DONE_SHIFT)))
                ret = -ENXIO;
+       else if (*status & BIT(MAC_FAILED_SHIFT))
+               ret = -EBADMSG;
 
        return ret;
 }
index 3bc244b..02e63ad 100644 (file)
@@ -11,6 +11,7 @@
 #include <crypto/aes.h>
 #include <crypto/hash.h>
 #include <crypto/internal/skcipher.h>
+#include <crypto/internal/aead.h>
 
 /* xts du size */
 #define QCE_SECTOR_SIZE                        512
 #define QCE_MODE_CCM                   BIT(12)
 #define QCE_MODE_MASK                  GENMASK(12, 8)
 
+#define QCE_MODE_CCM_RFC4309           BIT(13)
+
 /* cipher encryption/decryption operations */
-#define QCE_ENCRYPT                    BIT(13)
-#define QCE_DECRYPT                    BIT(14)
+#define QCE_ENCRYPT                    BIT(30)
+#define QCE_DECRYPT                    BIT(31)
 
 #define IS_DES(flags)                  (flags & QCE_ALG_DES)
 #define IS_3DES(flags)                 (flags & QCE_ALG_3DES)
@@ -73,6 +76,7 @@
 #define IS_CTR(mode)                   (mode & QCE_MODE_CTR)
 #define IS_XTS(mode)                   (mode & QCE_MODE_XTS)
 #define IS_CCM(mode)                   (mode & QCE_MODE_CCM)
+#define IS_CCM_RFC4309(mode)           ((mode) & QCE_MODE_CCM_RFC4309)
 
 #define IS_ENCRYPT(dir)                        (dir & QCE_ENCRYPT)
 #define IS_DECRYPT(dir)                        (dir & QCE_DECRYPT)
@@ -85,6 +89,7 @@ struct qce_alg_template {
        union {
                struct skcipher_alg skcipher;
                struct ahash_alg ahash;
+               struct aead_alg aead;
        } alg;
        struct qce_device *qce;
        const u8 *hash_zero;
index 80b7508..d3780be 100644 (file)
@@ -17,6 +17,7 @@
 #include "core.h"
 #include "cipher.h"
 #include "sha.h"
+#include "aead.h"
 
 #define QCE_MAJOR_VERSION5     0x05
 #define QCE_QUEUE_LENGTH       1
@@ -28,6 +29,9 @@ static const struct qce_algo_ops *qce_ops[] = {
 #ifdef CONFIG_CRYPTO_DEV_QCE_SHA
        &ahash_ops,
 #endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+       &aead_ops,
+#endif
 };
 
 static void qce_unregister_algs(struct qce_device *qce)
index c0a0d8c..8ff1092 100644 (file)
@@ -72,7 +72,7 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
        struct scatterlist *sg;
        bool diff_dst;
        gfp_t gfp;
-       int ret;
+       int dst_nents, src_nents, ret;
 
        rctx->iv = req->iv;
        rctx->ivsize = crypto_skcipher_ivsize(skcipher);
@@ -123,21 +123,26 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
        sg_mark_end(sg);
        rctx->dst_sg = rctx->dst_tbl.sgl;
 
-       ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
-       if (ret < 0)
+       dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+       if (dst_nents < 0) {
+               ret = dst_nents;
                goto error_free;
+       }
 
        if (diff_dst) {
-               ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
-               if (ret < 0)
+               src_nents = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+               if (src_nents < 0) {
+                       ret = src_nents;
                        goto error_unmap_dst;
+               }
                rctx->src_sg = req->src;
        } else {
                rctx->src_sg = rctx->dst_sg;
+               src_nents = dst_nents - 1;
        }
 
-       ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
-                              rctx->dst_sg, rctx->dst_nents,
+       ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents,
+                              rctx->dst_sg, dst_nents,
                               qce_skcipher_done, async_req);
        if (ret)
                goto error_unmap_src;
index 1c6929f..544d704 100644 (file)
@@ -1698,7 +1698,6 @@ static void sa_aead_dma_in_callback(void *data)
        size_t pl, ml;
        int i;
        int err = 0;
-       u16 auth_len;
        u32 *mdptr;
 
        sa_sync_from_device(rxd);
@@ -1711,13 +1710,10 @@ static void sa_aead_dma_in_callback(void *data)
        for (i = 0; i < (authsize / 4); i++)
                mdptr[i + 4] = swab32(mdptr[i + 4]);
 
-       auth_len = req->assoclen + req->cryptlen;
-
        if (rxd->enc) {
                scatterwalk_map_and_copy(&mdptr[4], req->dst, start, authsize,
                                         1);
        } else {
-               auth_len -= authsize;
                start -= authsize;
                scatterwalk_map_and_copy(auth_tag, req->src, start, authsize,
                                         0);
@@ -2300,9 +2296,9 @@ static int sa_dma_init(struct sa_crypto_data *dd)
 
        dd->dma_rx2 = dma_request_chan(dd->dev, "rx2");
        if (IS_ERR(dd->dma_rx2)) {
-               dma_release_channel(dd->dma_rx1);
-               return dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx2),
-                                    "Unable to request rx2 DMA channel\n");
+               ret = dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx2),
+                                   "Unable to request rx2 DMA channel\n");
+               goto err_dma_rx2;
        }
 
        dd->dma_tx = dma_request_chan(dd->dev, "tx");
@@ -2323,28 +2319,31 @@ static int sa_dma_init(struct sa_crypto_data *dd)
        if (ret) {
                dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
                        ret);
-               return ret;
+               goto err_dma_config;
        }
 
        ret = dmaengine_slave_config(dd->dma_rx2, &cfg);
        if (ret) {
                dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
                        ret);
-               return ret;
+               goto err_dma_config;
        }
 
        ret = dmaengine_slave_config(dd->dma_tx, &cfg);
        if (ret) {
                dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
                        ret);
-               return ret;
+               goto err_dma_config;
        }
 
        return 0;
 
+err_dma_config:
+       dma_release_channel(dd->dma_tx);
 err_dma_tx:
-       dma_release_channel(dd->dma_rx1);
        dma_release_channel(dd->dma_rx2);
+err_dma_rx2:
+       dma_release_channel(dd->dma_rx1);
 
        return ret;
 }
@@ -2385,10 +2384,8 @@ MODULE_DEVICE_TABLE(of, of_match);
 
 static int sa_ul_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
-       struct resource *res;
        static void __iomem *saul_base;
        struct sa_crypto_data *dev_data;
        int ret;
@@ -2397,9 +2394,18 @@ static int sa_ul_probe(struct platform_device *pdev)
        if (!dev_data)
                return -ENOMEM;
 
+       dev_data->match_data = of_device_get_match_data(dev);
+       if (!dev_data->match_data)
+               return -ENODEV;
+
+       saul_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(saul_base))
+               return PTR_ERR(saul_base);
+
        sa_k3_dev = dev;
        dev_data->dev = dev;
        dev_data->pdev = pdev;
+       dev_data->base = saul_base;
        platform_set_drvdata(pdev, dev_data);
        dev_set_drvdata(sa_k3_dev, dev_data);
 
@@ -2408,26 +2414,16 @@ static int sa_ul_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev, "%s: failed to get sync: %d\n", __func__,
                        ret);
+               pm_runtime_disable(dev);
                return ret;
        }
 
        sa_init_mem(dev_data);
        ret = sa_dma_init(dev_data);
        if (ret)
-               goto disable_pm_runtime;
-
-       match = of_match_node(of_match, dev->of_node);
-       if (!match) {
-               dev_err(dev, "No compatible match found\n");
-               return -ENODEV;
-       }
-       dev_data->match_data = match->data;
+               goto destroy_dma_pool;
 
        spin_lock_init(&dev_data->scid_lock);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       saul_base = devm_ioremap_resource(dev, res);
-
-       dev_data->base = saul_base;
 
        if (!dev_data->match_data->skip_engine_control) {
                u32 val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN |
@@ -2454,9 +2450,9 @@ release_dma:
        dma_release_channel(dev_data->dma_rx1);
        dma_release_channel(dev_data->dma_tx);
 
+destroy_dma_pool:
        dma_pool_destroy(dev_data->sc_pool);
 
-disable_pm_runtime:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
@@ -2467,6 +2463,8 @@ static int sa_ul_remove(struct platform_device *pdev)
 {
        struct sa_crypto_data *dev_data = platform_get_drvdata(pdev);
 
+       of_platform_depopulate(&pdev->dev);
+
        sa_unregister_algos(&pdev->dev);
 
        dma_release_channel(dev_data->dma_rx2);
index ecb7412..51a6e1a 100644 (file)
@@ -1011,6 +1011,7 @@ static int hash_hw_final(struct ahash_request *req)
                        goto out;
                }
        } else if (req->nbytes == 0 && ctx->keylen > 0) {
+               ret = -EPERM;
                dev_err(device_data->dev, "%s: Empty message with keylength > 0, NOT supported\n",
                        __func__);
                goto out;
index 20373a8..e87d01c 100644 (file)
@@ -103,7 +103,6 @@ config ARM_IMX8M_DDRC_DEVFREQ
        tristate "i.MX8M DDRC DEVFREQ Driver"
        depends on (ARCH_MXC && HAVE_ARM_SMCCC) || \
                (COMPILE_TEST && HAVE_ARM_SMCCC)
-       select DEVFREQ_GOV_SIMPLE_ONDEMAND
        select DEVFREQ_GOV_USERSPACE
        help
          This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
index fe08c46..28f3e0b 100644 (file)
@@ -823,6 +823,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        if (devfreq->profile->timer < 0
                || devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
                mutex_unlock(&devfreq->lock);
+               err = -EINVAL;
                goto err_dev;
        }
 
index b094132..fc09324 100644 (file)
@@ -65,7 +65,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
                dev_pm_opp_put(p_opp);
 
                if (IS_ERR(opp))
-                       return PTR_ERR(opp);
+                       goto no_required_opp;
 
                *freq = dev_pm_opp_get_freq(opp);
                dev_pm_opp_put(opp);
@@ -73,6 +73,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
                return 0;
        }
 
+no_required_opp:
        /*
         * Get the OPP table's index of decided frequency by governor
         * of parent device.
index 0fd6c48..ab9db7a 100644 (file)
@@ -31,8 +31,8 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
        return 0;
 }
 
-static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
+static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
 {
        struct devfreq *devfreq = to_devfreq(dev);
        struct userspace_data *data;
@@ -52,8 +52,8 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
        return err;
 }
 
-static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
-                        char *buf)
+static ssize_t set_freq_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
        struct devfreq *devfreq = to_devfreq(dev);
        struct userspace_data *data;
@@ -70,7 +70,7 @@ static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
        return err;
 }
 
-static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
+static DEVICE_ATTR_RW(set_freq);
 static struct attribute *dev_entries[] = {
        &dev_attr_set_freq.attr,
        NULL,
index 3fc3fd7..f3f6e25 100644 (file)
@@ -45,18 +45,6 @@ static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
        return 0;
 }
 
-static int imx_bus_get_dev_status(struct device *dev,
-               struct devfreq_dev_status *stat)
-{
-       struct imx_bus *priv = dev_get_drvdata(dev);
-
-       stat->busy_time = 0;
-       stat->total_time = 0;
-       stat->current_frequency = clk_get_rate(priv->clk);
-
-       return 0;
-}
-
 static void imx_bus_exit(struct device *dev)
 {
        struct imx_bus *priv = dev_get_drvdata(dev);
@@ -129,9 +117,7 @@ static int imx_bus_probe(struct platform_device *pdev)
                return ret;
        }
 
-       priv->profile.polling_ms = 1000;
        priv->profile.target = imx_bus_target;
-       priv->profile.get_dev_status = imx_bus_get_dev_status;
        priv->profile.exit = imx_bus_exit;
        priv->profile.get_cur_freq = imx_bus_get_cur_freq;
        priv->profile.initial_freq = clk_get_rate(priv->clk);
index ce83f88..10661eb 100644 (file)
@@ -688,6 +688,7 @@ static struct devfreq_dev_profile tegra_devfreq_profile = {
        .polling_ms     = ACTMON_SAMPLING_PERIOD,
        .target         = tegra_devfreq_target,
        .get_dev_status = tegra_devfreq_get_dev_status,
+       .is_cooling_device = true,
 };
 
 static int tegra_governor_get_target(struct devfreq *devfreq,
index 6ab9d9a..39b5b46 100644 (file)
@@ -59,6 +59,7 @@ config DMA_OF
 #devices
 config ALTERA_MSGDMA
        tristate "Altera / Intel mSGDMA Engine"
+       depends on HAS_IOMEM
        select DMA_ENGINE
        help
          Enable support for Altera / Intel mSGDMA controller.
@@ -701,6 +702,7 @@ config XILINX_ZYNQMP_DMA
 
 config XILINX_ZYNQMP_DPDMA
        tristate "Xilinx DPDMA Engine"
+       depends on HAS_IOMEM && OF
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
        help
index 4ec909e..4ae0579 100644 (file)
@@ -332,6 +332,7 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev)
        }
 
        if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) {
+               err = -EINVAL;
                dev_err(dev, "DPDMAI major version mismatch\n"
                             "Found %u.%u, supported version is %u.%u\n",
                                priv->dpdmai_attr.version.major,
@@ -341,6 +342,7 @@ static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev)
        }
 
        if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) {
+               err = -EINVAL;
                dev_err(dev, "DPDMAI minor version mismatch\n"
                             "Found %u.%u, supported version is %u.%u\n",
                                priv->dpdmai_attr.version.major,
@@ -475,6 +477,7 @@ static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv)
                ppriv->store =
                        dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, dev);
                if (!ppriv->store) {
+                       err = -ENOMEM;
                        dev_err(dev, "dpaa2_io_store_create() failed\n");
                        goto err_store;
                }
index 302cba5..d4419bf 100644 (file)
@@ -110,6 +110,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
                pasid = iommu_sva_get_pasid(sva);
                if (pasid == IOMMU_PASID_INVALID) {
                        iommu_sva_unbind_device(sva);
+                       rc = -EINVAL;
                        goto failed;
                }
 
index 776fd44..442d55c 100644 (file)
@@ -168,6 +168,32 @@ static int idxd_setup_interrupts(struct idxd_device *idxd)
        return rc;
 }
 
+static void idxd_cleanup_interrupts(struct idxd_device *idxd)
+{
+       struct pci_dev *pdev = idxd->pdev;
+       struct idxd_irq_entry *irq_entry;
+       int i, msixcnt;
+
+       msixcnt = pci_msix_vec_count(pdev);
+       if (msixcnt <= 0)
+               return;
+
+       irq_entry = &idxd->irq_entries[0];
+       free_irq(irq_entry->vector, irq_entry);
+
+       for (i = 1; i < msixcnt; i++) {
+
+               irq_entry = &idxd->irq_entries[i];
+               if (idxd->hw.cmd_cap & BIT(IDXD_CMD_RELEASE_INT_HANDLE))
+                       idxd_device_release_int_handle(idxd, idxd->int_handles[i],
+                                                      IDXD_IRQ_MSIX);
+               free_irq(irq_entry->vector, irq_entry);
+       }
+
+       idxd_mask_error_interrupts(idxd);
+       pci_free_irq_vectors(pdev);
+}
+
 static int idxd_setup_wqs(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
@@ -242,6 +268,7 @@ static int idxd_setup_engines(struct idxd_device *idxd)
                engine->idxd = idxd;
                device_initialize(&engine->conf_dev);
                engine->conf_dev.parent = &idxd->conf_dev;
+               engine->conf_dev.bus = &dsa_bus_type;
                engine->conf_dev.type = &idxd_engine_device_type;
                rc = dev_set_name(&engine->conf_dev, "engine%d.%d", idxd->id, engine->id);
                if (rc < 0) {
@@ -303,6 +330,19 @@ static int idxd_setup_groups(struct idxd_device *idxd)
        return rc;
 }
 
+static void idxd_cleanup_internals(struct idxd_device *idxd)
+{
+       int i;
+
+       for (i = 0; i < idxd->max_groups; i++)
+               put_device(&idxd->groups[i]->conf_dev);
+       for (i = 0; i < idxd->max_engines; i++)
+               put_device(&idxd->engines[i]->conf_dev);
+       for (i = 0; i < idxd->max_wqs; i++)
+               put_device(&idxd->wqs[i]->conf_dev);
+       destroy_workqueue(idxd->wq);
+}
+
 static int idxd_setup_internals(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
@@ -531,12 +571,12 @@ static int idxd_probe(struct idxd_device *idxd)
                dev_dbg(dev, "Loading RO device config\n");
                rc = idxd_device_load_config(idxd);
                if (rc < 0)
-                       goto err;
+                       goto err_config;
        }
 
        rc = idxd_setup_interrupts(idxd);
        if (rc)
-               goto err;
+               goto err_config;
 
        dev_dbg(dev, "IDXD interrupt setup complete.\n");
 
@@ -549,6 +589,8 @@ static int idxd_probe(struct idxd_device *idxd)
        dev_dbg(dev, "IDXD device %d probed successfully\n", idxd->id);
        return 0;
 
+ err_config:
+       idxd_cleanup_internals(idxd);
  err:
        if (device_pasid_enabled(idxd))
                idxd_disable_system_pasid(idxd);
@@ -556,6 +598,18 @@ static int idxd_probe(struct idxd_device *idxd)
        return rc;
 }
 
+static void idxd_cleanup(struct idxd_device *idxd)
+{
+       struct device *dev = &idxd->pdev->dev;
+
+       perfmon_pmu_remove(idxd);
+       idxd_cleanup_interrupts(idxd);
+       idxd_cleanup_internals(idxd);
+       if (device_pasid_enabled(idxd))
+               idxd_disable_system_pasid(idxd);
+       iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
+}
+
 static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct device *dev = &pdev->dev;
@@ -608,7 +662,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        rc = idxd_register_devices(idxd);
        if (rc) {
                dev_err(dev, "IDXD sysfs setup failed\n");
-               goto err;
+               goto err_dev_register;
        }
 
        idxd->state = IDXD_DEV_CONF_READY;
@@ -618,6 +672,8 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        return 0;
 
+ err_dev_register:
+       idxd_cleanup(idxd);
  err:
        pci_iounmap(pdev, idxd->reg_base);
  err_iomap:
@@ -787,6 +843,7 @@ module_init(idxd_init_module);
 
 static void __exit idxd_exit_module(void)
 {
+       idxd_unregister_driver();
        pci_unregister_driver(&idxd_pci_driver);
        idxd_cdev_remove();
        idxd_unregister_bus_type();
index 0d5c42f..97d9a6f 100644 (file)
@@ -230,7 +230,7 @@ out:
 }
 
 /**
- * ipu_irq_map() - map an IPU interrupt source to an IRQ number
+ * ipu_irq_unmap() - unmap an IPU interrupt source
  * @source:    interrupt source bit position (see ipu_irq_map())
  * @return:    0 or negative error code
  */
index 27c0735..375e7e6 100644 (file)
@@ -131,10 +131,7 @@ static unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
 
 static void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
 {
-       struct dma_chan *chan = vd->tx.chan;
-       struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
-
-       kfree(c->desc);
+       kfree(container_of(vd, struct mtk_uart_apdma_desc, vd));
 }
 
 static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
@@ -207,14 +204,9 @@ static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
 
 static void mtk_uart_apdma_tx_handler(struct mtk_chan *c)
 {
-       struct mtk_uart_apdma_desc *d = c->desc;
-
        mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
        mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
        mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
-
-       list_del(&d->vd.node);
-       vchan_cookie_complete(&d->vd);
 }
 
 static void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
@@ -245,9 +237,17 @@ static void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
 
        c->rx_status = d->avail_len - cnt;
        mtk_uart_apdma_write(c, VFF_RPT, wg);
+}
 
-       list_del(&d->vd.node);
-       vchan_cookie_complete(&d->vd);
+static void mtk_uart_apdma_chan_complete_handler(struct mtk_chan *c)
+{
+       struct mtk_uart_apdma_desc *d = c->desc;
+
+       if (d) {
+               list_del(&d->vd.node);
+               vchan_cookie_complete(&d->vd);
+               c->desc = NULL;
+       }
 }
 
 static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
@@ -261,6 +261,7 @@ static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
                mtk_uart_apdma_rx_handler(c);
        else if (c->dir == DMA_MEM_TO_DEV)
                mtk_uart_apdma_tx_handler(c);
+       mtk_uart_apdma_chan_complete_handler(c);
        spin_unlock_irqrestore(&c->vc.lock, flags);
 
        return IRQ_HANDLED;
@@ -348,7 +349,7 @@ static struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
                return NULL;
 
        /* Now allocate and setup the descriptor */
-       d = kzalloc(sizeof(*d), GFP_ATOMIC);
+       d = kzalloc(sizeof(*d), GFP_NOWAIT);
        if (!d)
                return NULL;
 
@@ -366,7 +367,7 @@ static void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
        unsigned long flags;
 
        spin_lock_irqsave(&c->vc.lock, flags);
-       if (vchan_issue_pending(&c->vc)) {
+       if (vchan_issue_pending(&c->vc) && !c->desc) {
                vd = vchan_next_desc(&c->vc);
                c->desc = to_mtk_uart_apdma_desc(&vd->tx);
 
index fd8d2bc..110de8a 100644 (file)
@@ -2694,13 +2694,15 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
        for (i = 0; i < len / period_len; i++) {
                desc = pl330_get_desc(pch);
                if (!desc) {
+                       unsigned long iflags;
+
                        dev_err(pch->dmac->ddma.dev, "%s:%d Unable to fetch desc\n",
                                __func__, __LINE__);
 
                        if (!first)
                                return NULL;
 
-                       spin_lock_irqsave(&pl330->pool_lock, flags);
+                       spin_lock_irqsave(&pl330->pool_lock, iflags);
 
                        while (!list_empty(&first->node)) {
                                desc = list_entry(first->node.next,
@@ -2710,7 +2712,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
 
                        list_move_tail(&first->node, &pl330->desc_pool);
 
-                       spin_unlock_irqrestore(&pl330->pool_lock, flags);
+                       spin_unlock_irqrestore(&pl330->pool_lock, iflags);
 
                        return NULL;
                }
index 365f94e..3f926a6 100644 (file)
@@ -33,6 +33,7 @@ config QCOM_GPI_DMA
 
 config QCOM_HIDMA_MGMT
        tristate "Qualcomm Technologies HIDMA Management support"
+       depends on HAS_IOMEM
        select DMA_ENGINE
        help
          Enable support for the Qualcomm Technologies HIDMA Management.
index f8ffa02..ba46a0a 100644 (file)
@@ -1,5 +1,6 @@
 config SF_PDMA
        tristate "Sifive PDMA controller driver"
+       depends on HAS_IOMEM
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
        help
index d530c1b..6885b3d 100644 (file)
@@ -1913,7 +1913,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
 
        /* Enable runtime PM and initialize the device. */
        pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
                return ret;
index 265d7c0..e182739 100644 (file)
@@ -3675,6 +3675,9 @@ static int __init d40_probe(struct platform_device *pdev)
 
        kfree(base->lcla_pool.base_unaligned);
 
+       if (base->lcpa_base)
+               iounmap(base->lcpa_base);
+
        if (base->phy_lcpa)
                release_mem_region(base->phy_lcpa,
                                   base->lcpa_size);
index 36ba8b4..18cbd1e 100644 (file)
@@ -1452,7 +1452,7 @@ static int stm32_mdma_alloc_chan_resources(struct dma_chan *c)
                return -ENOMEM;
        }
 
-       ret = pm_runtime_get_sync(dmadev->ddev.dev);
+       ret = pm_runtime_resume_and_get(dmadev->ddev.dev);
        if (ret < 0)
                return ret;
 
@@ -1718,7 +1718,7 @@ static int stm32_mdma_pm_suspend(struct device *dev)
        u32 ccr, id;
        int ret;
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
                return ret;
 
index 70b29bd..6c70980 100644 (file)
 #define XILINX_DPDMA_CH_VDO                            0x020
 #define XILINX_DPDMA_CH_PYLD_SZ                                0x024
 #define XILINX_DPDMA_CH_DESC_ID                                0x028
+#define XILINX_DPDMA_CH_DESC_ID_MASK                   GENMASK(15, 0)
 
 /* DPDMA descriptor fields */
 #define XILINX_DPDMA_DESC_CONTROL_PREEMBLE             0xa5
@@ -866,7 +867,8 @@ static void xilinx_dpdma_chan_queue_transfer(struct xilinx_dpdma_chan *chan)
         * will be used, but it should be enough.
         */
        list_for_each_entry(sw_desc, &desc->descriptors, node)
-               sw_desc->hw.desc_id = desc->vdesc.tx.cookie;
+               sw_desc->hw.desc_id = desc->vdesc.tx.cookie
+                                   & XILINX_DPDMA_CH_DESC_ID_MASK;
 
        sw_desc = list_first_entry(&desc->descriptors,
                                   struct xilinx_dpdma_sw_desc, node);
@@ -1086,7 +1088,8 @@ static void xilinx_dpdma_chan_vsync_irq(struct  xilinx_dpdma_chan *chan)
        if (!chan->running || !pending)
                goto out;
 
-       desc_id = dpdma_read(chan->reg, XILINX_DPDMA_CH_DESC_ID);
+       desc_id = dpdma_read(chan->reg, XILINX_DPDMA_CH_DESC_ID)
+               & XILINX_DPDMA_CH_DESC_ID_MASK;
 
        /* If the retrigger raced with vsync, retry at the next frame. */
        sw_desc = list_first_entry(&pending->descriptors,
@@ -1459,7 +1462,7 @@ static void xilinx_dpdma_enable_irq(struct xilinx_dpdma_device *xdev)
  */
 static void xilinx_dpdma_disable_irq(struct xilinx_dpdma_device *xdev)
 {
-       dpdma_write(xdev->reg, XILINX_DPDMA_IDS, XILINX_DPDMA_INTR_ERR_ALL);
+       dpdma_write(xdev->reg, XILINX_DPDMA_IDS, XILINX_DPDMA_INTR_ALL);
        dpdma_write(xdev->reg, XILINX_DPDMA_EIDS, XILINX_DPDMA_EINTR_ALL);
 }
 
@@ -1596,6 +1599,26 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
        return dma_get_slave_channel(&xdev->chan[chan_id]->vchan.chan);
 }
 
+static void dpdma_hw_init(struct xilinx_dpdma_device *xdev)
+{
+       unsigned int i;
+       void __iomem *reg;
+
+       /* Disable all interrupts */
+       xilinx_dpdma_disable_irq(xdev);
+
+       /* Stop all channels */
+       for (i = 0; i < ARRAY_SIZE(xdev->chan); i++) {
+               reg = xdev->reg + XILINX_DPDMA_CH_BASE
+                               + XILINX_DPDMA_CH_OFFSET * i;
+               dpdma_clr(reg, XILINX_DPDMA_CH_CNTL, XILINX_DPDMA_CH_CNTL_ENABLE);
+       }
+
+       /* Clear the interrupt status registers */
+       dpdma_write(xdev->reg, XILINX_DPDMA_ISR, XILINX_DPDMA_INTR_ALL);
+       dpdma_write(xdev->reg, XILINX_DPDMA_EISR, XILINX_DPDMA_EINTR_ALL);
+}
+
 static int xilinx_dpdma_probe(struct platform_device *pdev)
 {
        struct xilinx_dpdma_device *xdev;
@@ -1622,6 +1645,8 @@ static int xilinx_dpdma_probe(struct platform_device *pdev)
        if (IS_ERR(xdev->reg))
                return PTR_ERR(xdev->reg);
 
+       dpdma_hw_init(xdev);
+
        xdev->irq = platform_get_irq(pdev, 0);
        if (xdev->irq < 0) {
                dev_err(xdev->dev, "failed to get platform irq\n");
index d841956..5fecf5a 100644 (file)
@@ -468,7 +468,7 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan)
        struct zynqmp_dma_desc_sw *desc;
        int i, ret;
 
-       ret = pm_runtime_get_sync(chan->dev);
+       ret = pm_runtime_resume_and_get(chan->dev);
        if (ret < 0)
                return ret;
 
index 5dd905a..27d5692 100644 (file)
@@ -323,6 +323,21 @@ static const char * const smca_umc_mce_desc[] = {
        "AES SRAM ECC error",
 };
 
+static const char * const smca_umc2_mce_desc[] = {
+       "DRAM ECC error",
+       "Data poison error",
+       "SDP parity error",
+       "Reserved",
+       "Address/Command parity error",
+       "Write data parity error",
+       "DCQ SRAM ECC error",
+       "Reserved",
+       "Read data parity error",
+       "Rdb SRAM ECC error",
+       "RdRsp SRAM ECC error",
+       "LM32 MP errors",
+};
+
 static const char * const smca_pb_mce_desc[] = {
        "An ECC error in the Parameter Block RAM array",
 };
@@ -400,6 +415,56 @@ static const char * const smca_pcie_mce_desc[] = {
        "CCIX Non-okay write response with data error",
 };
 
+static const char * const smca_pcie2_mce_desc[] = {
+       "SDP Parity Error logging",
+};
+
+static const char * const smca_xgmipcs_mce_desc[] = {
+       "Data Loss Error",
+       "Training Error",
+       "Flow Control Acknowledge Error",
+       "Rx Fifo Underflow Error",
+       "Rx Fifo Overflow Error",
+       "CRC Error",
+       "BER Exceeded Error",
+       "Tx Vcid Data Error",
+       "Replay Buffer Parity Error",
+       "Data Parity Error",
+       "Replay Fifo Overflow Error",
+       "Replay Fifo Underflow Error",
+       "Elastic Fifo Overflow Error",
+       "Deskew Error",
+       "Flow Control CRC Error",
+       "Data Startup Limit Error",
+       "FC Init Timeout Error",
+       "Recovery Timeout Error",
+       "Ready Serial Timeout Error",
+       "Ready Serial Attempt Error",
+       "Recovery Attempt Error",
+       "Recovery Relock Attempt Error",
+       "Replay Attempt Error",
+       "Sync Header Error",
+       "Tx Replay Timeout Error",
+       "Rx Replay Timeout Error",
+       "LinkSub Tx Timeout Error",
+       "LinkSub Rx Timeout Error",
+       "Rx CMD Pocket Error",
+};
+
+static const char * const smca_xgmiphy_mce_desc[] = {
+       "RAM ECC Error",
+       "ARC instruction buffer parity error",
+       "ARC data buffer parity error",
+       "PHY APB error",
+};
+
+static const char * const smca_waflphy_mce_desc[] = {
+       "RAM ECC Error",
+       "ARC instruction buffer parity error",
+       "ARC data buffer parity error",
+       "PHY APB error",
+};
+
 struct smca_mce_desc {
        const char * const *descs;
        unsigned int num_descs;
@@ -418,6 +483,7 @@ static struct smca_mce_desc smca_mce_descs[] = {
        [SMCA_CS_V2]    = { smca_cs2_mce_desc,  ARRAY_SIZE(smca_cs2_mce_desc)   },
        [SMCA_PIE]      = { smca_pie_mce_desc,  ARRAY_SIZE(smca_pie_mce_desc)   },
        [SMCA_UMC]      = { smca_umc_mce_desc,  ARRAY_SIZE(smca_umc_mce_desc)   },
+       [SMCA_UMC_V2]   = { smca_umc2_mce_desc, ARRAY_SIZE(smca_umc2_mce_desc)  },
        [SMCA_PB]       = { smca_pb_mce_desc,   ARRAY_SIZE(smca_pb_mce_desc)    },
        [SMCA_PSP]      = { smca_psp_mce_desc,  ARRAY_SIZE(smca_psp_mce_desc)   },
        [SMCA_PSP_V2]   = { smca_psp2_mce_desc, ARRAY_SIZE(smca_psp2_mce_desc)  },
@@ -426,6 +492,10 @@ static struct smca_mce_desc smca_mce_descs[] = {
        [SMCA_MP5]      = { smca_mp5_mce_desc,  ARRAY_SIZE(smca_mp5_mce_desc)   },
        [SMCA_NBIO]     = { smca_nbio_mce_desc, ARRAY_SIZE(smca_nbio_mce_desc)  },
        [SMCA_PCIE]     = { smca_pcie_mce_desc, ARRAY_SIZE(smca_pcie_mce_desc)  },
+       [SMCA_PCIE_V2]  = { smca_pcie2_mce_desc,   ARRAY_SIZE(smca_pcie2_mce_desc)      },
+       [SMCA_XGMI_PCS] = { smca_xgmipcs_mce_desc, ARRAY_SIZE(smca_xgmipcs_mce_desc)    },
+       [SMCA_XGMI_PHY] = { smca_xgmiphy_mce_desc, ARRAY_SIZE(smca_xgmiphy_mce_desc)    },
+       [SMCA_WAFL_PHY] = { smca_waflphy_mce_desc, ARRAY_SIZE(smca_waflphy_mce_desc)    },
 };
 
 static bool f12h_mc0_mce(u16 ec, u8 xec)
index ec68ed2..b63d55f 100644 (file)
@@ -58,6 +58,7 @@ static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
                case SELFID_PORT_PARENT:
                case SELFID_PORT_NCONN:
                        (*total_port_count)++;
+                       fallthrough;
                case SELFID_PORT_NONE:
                        break;
                }
index e192648..4c3201e 100644 (file)
@@ -157,7 +157,7 @@ static int __init unmarshal_devices(struct properties_header *properties)
                if (!entry[0].name)
                        goto skip_device;
 
-               ret = device_add_properties(dev, entry); /* makes deep copy */
+               ret = device_create_managed_software_node(dev, entry, NULL);
                if (ret)
                        dev_err(dev, "error %d assigning properties\n", ret);
 
index 5c9625e..10d4457 100644 (file)
 #include <linux/efi.h>
 #include <linux/pci.h>
 
-struct acpi_hid_uid {
-       struct acpi_device_id hid[2];
-       char uid[11]; /* UINT_MAX + null byte */
-};
-
-static int __init match_acpi_dev(struct device *dev, const void *data)
-{
-       struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data;
-       struct acpi_device *adev = to_acpi_device(dev);
-
-       if (acpi_match_device_ids(adev, hid_uid.hid))
-               return 0;
-
-       if (adev->pnp.unique_id)
-               return !strcmp(adev->pnp.unique_id, hid_uid.uid);
-       else
-               return !strcmp("0", hid_uid.uid);
-}
-
 static long __init parse_acpi_path(const struct efi_dev_path *node,
                                   struct device *parent, struct device **child)
 {
-       struct acpi_hid_uid hid_uid = {};
+       char hid[ACPI_ID_LEN], uid[11]; /* UINT_MAX + null byte */
+       struct acpi_device *adev;
        struct device *phys_dev;
 
        if (node->header.length != 12)
                return -EINVAL;
 
-       sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
+       sprintf(hid, "%c%c%c%04X",
                'A' + ((node->acpi.hid >> 10) & 0x1f) - 1,
                'A' + ((node->acpi.hid >>  5) & 0x1f) - 1,
                'A' + ((node->acpi.hid >>  0) & 0x1f) - 1,
                        node->acpi.hid >> 16);
-       sprintf(hid_uid.uid, "%u", node->acpi.uid);
-
-       *child = bus_find_device(&acpi_bus_type, NULL, &hid_uid,
-                                match_acpi_dev);
-       if (!*child)
+       sprintf(uid, "%u", node->acpi.uid);
+
+       for_each_acpi_dev_match(adev, hid, NULL, -1) {
+               if (adev->pnp.unique_id && !strcmp(adev->pnp.unique_id, uid))
+                       break;
+               if (!adev->pnp.unique_id && node->acpi.uid == 0)
+                       break;
+               acpi_dev_put(adev);
+       }
+       if (!adev)
                return -ENODEV;
 
-       phys_dev = acpi_get_first_physical_node(to_acpi_device(*child));
+       phys_dev = acpi_get_first_physical_node(adev);
        if (phys_dev) {
-               get_device(phys_dev);
-               put_device(*child);
-               *child = phys_dev;
-       }
+               *child = get_device(phys_dev);
+               acpi_dev_put(adev);
+       } else
+               *child = &adev->dev;
 
        return 0;
 }
index 3c1c5da..e3da38e 100644 (file)
@@ -335,10 +335,15 @@ int psci_cpu_suspend_enter(u32 state)
 {
        int ret;
 
-       if (!psci_power_state_loses_context(state))
+       if (!psci_power_state_loses_context(state)) {
+               struct arm_cpuidle_irq_context context;
+
+               arm_cpuidle_save_irq_context(&context);
                ret = psci_ops.cpu_suspend(state, 0);
-       else
+               arm_cpuidle_restore_irq_context(&context);
+       } else {
                ret = cpu_suspend(state, psci_suspend_finisher);
+       }
 
        return ret;
 }
index 028f81d..9f937b1 100644 (file)
@@ -15,6 +15,7 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
 static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
 
 bool __ro_after_init smccc_trng_available = false;
+u64 __ro_after_init smccc_has_sve_hint = false;
 
 void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
 {
@@ -22,6 +23,9 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
        smccc_conduit = conduit;
 
        smccc_trng_available = smccc_probe_trng();
+       if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+           smccc_version >= ARM_SMCCC_VERSION_1_3)
+               smccc_has_sve_hint = true;
 }
 
 enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
index 1dd0ec6..3c69b78 100644 (file)
@@ -1383,6 +1383,7 @@ config GPIO_TPS68470
 config GPIO_TQMX86
        tristate "TQ-Systems QTMX86 GPIO"
        depends on MFD_TQMX86 || COMPILE_TEST
+       depends on HAS_IOPORT_MAP
        select GPIOLIB_IRQCHIP
        help
          This driver supports GPIO on the TQMX86 IO controller.
@@ -1450,6 +1451,7 @@ menu "PCI GPIO expanders"
 config GPIO_AMD8111
        tristate "AMD 8111 GPIO driver"
        depends on X86 || COMPILE_TEST
+       depends on HAS_IOPORT_MAP
        help
          The AMD 8111 south bridge contains 32 GPIO pins which can be used.
 
index 157106e..b9fdf05 100644 (file)
@@ -334,7 +334,7 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
        ct->chip.irq_unmask = irq_gc_mask_set_bit;
        ct->chip.irq_set_type = gpio_set_irq_type;
        ct->chip.irq_set_wake = gpio_set_wake_irq;
-       ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+       ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND;
        ct->regs.ack = GPIO_ISR;
        ct->regs.mask = GPIO_IMR;
 
index 1631727..c7b5446 100644 (file)
@@ -1880,6 +1880,7 @@ static void gpio_v2_line_info_changed_to_v1(
                struct gpio_v2_line_info_changed *lic_v2,
                struct gpioline_info_changed *lic_v1)
 {
+       memset(lic_v1, 0, sizeof(*lic_v1));
        gpio_v2_line_info_to_v1(&lic_v2->info, &lic_v1->info);
        lic_v1->timestamp = lic_v2->timestamp_ns;
        lic_v1->event_type = lic_v2->event_type;
index c13985f..2a4cd7d 100644 (file)
@@ -1047,11 +1047,12 @@ int amdgpu_display_gem_fb_init(struct drm_device *dev,
 
        rfb->base.obj[0] = obj;
        drm_helper_mode_fill_fb_struct(dev, &rfb->base, mode_cmd);
-       ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
+
+       ret = amdgpu_display_framebuffer_init(dev, rfb, mode_cmd, obj);
        if (ret)
                goto err;
 
-       ret = amdgpu_display_framebuffer_init(dev, rfb, mode_cmd, obj);
+       ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
        if (ret)
                goto err;
 
@@ -1071,9 +1072,6 @@ int amdgpu_display_gem_fb_verify_and_init(
 
        rfb->base.obj[0] = obj;
        drm_helper_mode_fill_fb_struct(dev, &rfb->base, mode_cmd);
-       ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
-       if (ret)
-               goto err;
        /* Verify that the modifier is supported. */
        if (!drm_any_plane_has_format(dev, mode_cmd->pixel_format,
                                      mode_cmd->modifier[0])) {
@@ -1092,6 +1090,10 @@ int amdgpu_display_gem_fb_verify_and_init(
        if (ret)
                goto err;
 
+       ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
+       if (ret)
+               goto err;
+
        return 0;
 err:
        drm_dbg_kms(dev, "Failed to verify and init gem fb: %d\n", ret);
index baa980a..37ec593 100644 (file)
@@ -214,9 +214,21 @@ static int amdgpu_dma_buf_pin(struct dma_buf_attachment *attach)
 {
        struct drm_gem_object *obj = attach->dmabuf->priv;
        struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+       int r;
 
        /* pin buffer into GTT */
-       return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
+       r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
+       if (r)
+               return r;
+
+       if (bo->tbo.moving) {
+               r = dma_fence_wait(bo->tbo.moving, true);
+               if (r) {
+                       amdgpu_bo_unpin(bo);
+                       return r;
+               }
+       }
+       return 0;
 }
 
 /**
index 05ad75d..cfe4fc6 100644 (file)
@@ -232,7 +232,6 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
 
        pm_runtime_put_sync(dev->dev);
 
-       drm_crtc_vblank_on(c);
 }
 
 #define ATMEL_HLCDC_RGB444_OUTPUT      BIT(0)
@@ -344,7 +343,16 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
 static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
                                          struct drm_atomic_state *state)
 {
+       drm_crtc_vblank_on(c);
+}
+
+static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *c,
+                                         struct drm_atomic_state *state)
+{
        struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->dev->event_lock, flags);
 
        if (c->state->event) {
                c->state->event->pipe = drm_crtc_index(c);
@@ -354,12 +362,7 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
                crtc->event = c->state->event;
                c->state->event = NULL;
        }
-}
-
-static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
-                                         struct drm_atomic_state *state)
-{
-       /* TODO: write common plane control register if available */
+       spin_unlock_irqrestore(&c->dev->event_lock, flags);
 }
 
 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
index 65af56e..f09b6dd 100644 (file)
@@ -593,6 +593,7 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
        dev->mode_config.max_width = dc->desc->max_width;
        dev->mode_config.max_height = dc->desc->max_height;
        dev->mode_config.funcs = &mode_config_funcs;
+       dev->mode_config.async_page_flip = true;
 
        return 0;
 }
index f64e06e..96ea1a2 100644 (file)
@@ -137,6 +137,7 @@ static int kmb_hw_init(struct drm_device *drm, unsigned long flags)
        /* Allocate LCD interrupt resources */
        irq_lcd = platform_get_irq(pdev, 0);
        if (irq_lcd < 0) {
+               ret = irq_lcd;
                drm_err(&kmb->drm, "irq_lcd not found");
                goto setup_fail;
        }
index 3e09df0..cf11feb 100644 (file)
@@ -440,6 +440,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
                        break;
                case TTM_PL_TT:
                        error |= !(domain & NOUVEAU_GEM_DOMAIN_GART);
+                       break;
                default:
                        break;
                }
@@ -546,7 +547,7 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
        struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
        int i, j;
 
-       if (!ttm_dma)
+       if (!ttm_dma || !ttm_dma->dma_address)
                return;
        if (!ttm_dma->pages) {
                NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
@@ -582,7 +583,7 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
        struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
        int i, j;
 
-       if (!ttm_dma)
+       if (!ttm_dma || !ttm_dma->dma_address)
                return;
        if (!ttm_dma->pages) {
                NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
index 61e6d74..eb844cd 100644 (file)
@@ -157,6 +157,7 @@ nouveau_conn_atomic_set_property(struct drm_connector *connector,
                        default:
                                break;
                        }
+                       break;
                case DRM_MODE_SCALE_FULLSCREEN:
                case DRM_MODE_SCALE_CENTER:
                case DRM_MODE_SCALE_ASPECT:
index 3474886..60019d0 100644 (file)
@@ -93,7 +93,22 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj)
        if (ret)
                return -EINVAL;
 
-       return 0;
+       ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
+       if (ret)
+               goto error;
+
+       if (nvbo->bo.moving)
+               ret = dma_fence_wait(nvbo->bo.moving, true);
+
+       ttm_bo_unreserve(&nvbo->bo);
+       if (ret)
+               goto error;
+
+       return ret;
+
+error:
+       nouveau_bo_unpin(nvbo);
+       return ret;
 }
 
 void nouveau_gem_prime_unpin(struct drm_gem_object *obj)
index 8306776..e1d31c6 100644 (file)
@@ -313,6 +313,7 @@ nv50_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
                default:
                        break;
                }
+               break;
        default:
                break;
        }
index 2b031d4..684aff7 100644 (file)
@@ -41,6 +41,7 @@ pwm_info(struct nvkm_therm *therm, int line)
                default:
                        break;
                }
+               break;
        default:
                break;
        }
index f484147..c4b3888 100644 (file)
@@ -383,6 +383,7 @@ MODULE_DEVICE_TABLE(spi, ld9040_ids);
 static struct spi_driver ld9040_driver = {
        .probe = ld9040_probe,
        .remove = ld9040_remove,
+       .id_table = ld9040_ids,
        .driver = {
                .name = "panel-samsung-ld9040",
                .of_match_table = ld9040_of_match,
index 42a8794..4a90807 100644 (file)
@@ -77,9 +77,19 @@ int radeon_gem_prime_pin(struct drm_gem_object *obj)
 
        /* pin buffer into GTT */
        ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
-       if (likely(ret == 0))
-               bo->prime_shared_count++;
-
+       if (unlikely(ret))
+               goto error;
+
+       if (bo->tbo.moving) {
+               ret = dma_fence_wait(bo->tbo.moving, false);
+               if (unlikely(ret)) {
+                       radeon_bo_unpin(bo);
+                       goto error;
+               }
+       }
+
+       bo->prime_shared_count++;
+error:
        radeon_bo_unreserve(bo);
        return ret;
 }
index 1fda574..8106b56 100644 (file)
@@ -159,6 +159,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
        struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
        bool connected = false;
 
+       WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
+
        if (vc4_hdmi->hpd_gpio) {
                if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^
                    vc4_hdmi->hpd_active_low)
@@ -180,10 +182,12 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                        }
                }
 
+               pm_runtime_put(&vc4_hdmi->pdev->dev);
                return connector_status_connected;
        }
 
        cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+       pm_runtime_put(&vc4_hdmi->pdev->dev);
        return connector_status_disconnected;
 }
 
@@ -473,7 +477,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
                   HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
 
        clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
-       clk_disable_unprepare(vc4_hdmi->hsm_clock);
        clk_disable_unprepare(vc4_hdmi->pixel_clock);
 
        ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
@@ -784,13 +787,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
                return;
        }
 
-       ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
-       if (ret) {
-               DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
-               clk_disable_unprepare(vc4_hdmi->pixel_clock);
-               return;
-       }
-
        vc4_hdmi_cec_update_clk_div(vc4_hdmi);
 
        /*
@@ -801,7 +797,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
                               (hsm_rate > VC4_HSM_MID_CLOCK ? 150000000 : 75000000));
        if (ret) {
                DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
-               clk_disable_unprepare(vc4_hdmi->hsm_clock);
                clk_disable_unprepare(vc4_hdmi->pixel_clock);
                return;
        }
@@ -809,7 +804,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
        ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
        if (ret) {
                DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
-               clk_disable_unprepare(vc4_hdmi->hsm_clock);
                clk_disable_unprepare(vc4_hdmi->pixel_clock);
                return;
        }
@@ -1929,6 +1923,29 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int vc4_hdmi_runtime_suspend(struct device *dev)
+{
+       struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(vc4_hdmi->hsm_clock);
+
+       return 0;
+}
+
+static int vc4_hdmi_runtime_resume(struct device *dev)
+{
+       struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+#endif
+
 static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
@@ -2165,11 +2182,18 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {
        {}
 };
 
+static const struct dev_pm_ops vc4_hdmi_pm_ops = {
+       SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
+                          vc4_hdmi_runtime_resume,
+                          NULL)
+};
+
 struct platform_driver vc4_hdmi_driver = {
        .probe = vc4_hdmi_dev_probe,
        .remove = vc4_hdmi_dev_remove,
        .driver = {
                .name = "vc4_hdmi",
                .of_match_table = vc4_hdmi_dt_match,
+               .pm = &vc4_hdmi_pm_ops,
        },
 };
index 94daf82..d76df5c 100644 (file)
@@ -11,3 +11,6 @@ hv_vmbus-y := vmbus_drv.o \
                 channel_mgmt.o ring_buffer.o hv_trace.o
 hv_vmbus-$(CONFIG_HYPERV_TESTING)      += hv_debugfs.o
 hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o
+
+# Code that must be built-in
+obj-$(subst m,y,$(CONFIG_HYPERV)) += hv_common.o
index c2635e9..f3761c7 100644 (file)
@@ -662,12 +662,15 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
        newchannel->onchannel_callback = onchannelcallback;
        newchannel->channel_callback_context = context;
 
-       err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages);
+       if (!newchannel->max_pkt_size)
+               newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE;
+
+       err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages, 0);
        if (err)
                goto error_clean_ring;
 
-       err = hv_ringbuffer_init(&newchannel->inbound,
-                                &page[send_pages], recv_pages);
+       err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages],
+                                recv_pages, newchannel->max_pkt_size);
        if (err)
                goto error_clean_ring;
 
@@ -1186,15 +1189,14 @@ EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
  * vmbus_next_request_id - Returns a new request id. It is also
  * the index at which the guest memory address is stored.
  * Uses a spin lock to avoid race conditions.
- * @rqstor: Pointer to the requestor struct
+ * @channel: Pointer to the VMbus channel struct
  * @rqst_add: Guest memory address to be stored in the array
  */
-u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr)
+u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
 {
+       struct vmbus_requestor *rqstor = &channel->requestor;
        unsigned long flags;
        u64 current_id;
-       const struct vmbus_channel *channel =
-               container_of(rqstor, const struct vmbus_channel, requestor);
 
        /* Check rqstor has been initialized */
        if (!channel->rqstor_size)
@@ -1228,16 +1230,15 @@ EXPORT_SYMBOL_GPL(vmbus_next_request_id);
 /*
  * vmbus_request_addr - Returns the memory address stored at @trans_id
  * in @rqstor. Uses a spin lock to avoid race conditions.
- * @rqstor: Pointer to the requestor struct
+ * @channel: Pointer to the VMbus channel struct
  * @trans_id: Request id sent back from Hyper-V. Becomes the requestor's
  * next request id.
  */
-u64 vmbus_request_addr(struct vmbus_requestor *rqstor, u64 trans_id)
+u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
 {
+       struct vmbus_requestor *rqstor = &channel->requestor;
        unsigned long flags;
        u64 req_addr;
-       const struct vmbus_channel *channel =
-               container_of(rqstor, const struct vmbus_channel, requestor);
 
        /* Check rqstor has been initialized */
        if (!channel->rqstor_size)
index 311cd00..5e479d5 100644 (file)
@@ -232,8 +232,10 @@ int vmbus_connect(void)
         */
 
        for (i = 0; ; i++) {
-               if (i == ARRAY_SIZE(vmbus_versions))
+               if (i == ARRAY_SIZE(vmbus_versions)) {
+                       ret = -EDOM;
                        goto cleanup;
+               }
 
                version = vmbus_versions[i];
                if (version > max_version)
index 58af84e..7f11ea0 100644 (file)
@@ -1010,7 +1010,6 @@ static void hot_add_req(struct work_struct *dummy)
                 * that need to be hot-added while ensuring the alignment
                 * and size requirements of Linux as it relates to hot-add.
                 */
-               region_start = pg_start;
                region_size = (pfn_cnt / HA_CHUNK) * HA_CHUNK;
                if (pfn_cnt % HA_CHUNK)
                        region_size += HA_CHUNK;
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
new file mode 100644 (file)
index 0000000..7f42da9
--- /dev/null
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Architecture neutral utility routines for interacting with
+ * Hyper-V. This file is specifically for code that must be
+ * built-in to the kernel image when CONFIG_HYPERV is set
+ * (vs. being in a module) because it is called from architecture
+ * specific code under arch/.
+ *
+ * Copyright (C) 2021, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <mikelley@microsoft.com>
+ */
+
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/bitfield.h>
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
+
+/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */
+bool hv_query_ext_cap(u64 cap_query)
+{
+       /*
+        * The address of the 'hv_extended_cap' variable will be used as an
+        * output parameter to the hypercall below and so it should be
+        * compatible with 'virt_to_phys'. Which means, it's address should be
+        * directly mapped. Use 'static' to keep it compatible; stack variables
+        * can be virtually mapped, making them incompatible with
+        * 'virt_to_phys'.
+        * Hypercall input/output addresses should also be 8-byte aligned.
+        */
+       static u64 hv_extended_cap __aligned(8);
+       static bool hv_extended_cap_queried;
+       u64 status;
+
+       /*
+        * Querying extended capabilities is an extended hypercall. Check if the
+        * partition supports extended hypercall, first.
+        */
+       if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS))
+               return false;
+
+       /* Extended capabilities do not change at runtime. */
+       if (hv_extended_cap_queried)
+               return hv_extended_cap & cap_query;
+
+       status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL,
+                                &hv_extended_cap);
+
+       /*
+        * The query extended capabilities hypercall should not fail under
+        * any normal circumstances. Avoid repeatedly making the hypercall, on
+        * error.
+        */
+       hv_extended_cap_queried = true;
+       if (!hv_result_success(status)) {
+               pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n",
+                      status);
+               return false;
+       }
+
+       return hv_extended_cap & cap_query;
+}
+EXPORT_SYMBOL_GPL(hv_query_ext_cap);
index 59ce85e..660036d 100644 (file)
@@ -349,6 +349,7 @@ int hv_fcopy_init(struct hv_util_service *srv)
 {
        recv_buffer = srv->recv_buffer;
        fcopy_transaction.recv_channel = srv->channel;
+       fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
 
        /*
         * When this driver loads, the user level daemon that
index b49962d..c698592 100644 (file)
@@ -757,6 +757,7 @@ hv_kvp_init(struct hv_util_service *srv)
 {
        recv_buffer = srv->recv_buffer;
        kvp_transaction.recv_channel = srv->channel;
+       kvp_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 4;
 
        /*
         * When this driver loads, the user level daemon that
index e4aefeb..136576c 100644 (file)
@@ -750,8 +750,8 @@ static int hv_timesync_init(struct hv_util_service *srv)
         */
        hv_ptp_clock = ptp_clock_register(&ptp_hyperv_info, NULL);
        if (IS_ERR_OR_NULL(hv_ptp_clock)) {
-               pr_err("cannot register PTP clock: %ld\n",
-                      PTR_ERR(hv_ptp_clock));
+               pr_err("cannot register PTP clock: %d\n",
+                      PTR_ERR_OR_ZERO(hv_ptp_clock));
                hv_ptp_clock = NULL;
        }
 
index 9416e09..42f3d9d 100644 (file)
@@ -174,7 +174,7 @@ extern int hv_synic_cleanup(unsigned int cpu);
 void hv_ringbuffer_pre_init(struct vmbus_channel *channel);
 
 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
-                      struct page *pages, u32 pagecnt);
+                      struct page *pages, u32 pagecnt, u32 max_pkt_size);
 
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
 
index 374f8af..2aee356 100644 (file)
@@ -181,7 +181,7 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel)
 
 /* Initialize the ring buffer. */
 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
-                      struct page *pages, u32 page_cnt)
+                      struct page *pages, u32 page_cnt, u32 max_pkt_size)
 {
        int i;
        struct page **pages_wraparound;
@@ -223,6 +223,14 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
                sizeof(struct hv_ring_buffer);
        ring_info->priv_read_index = 0;
 
+       /* Initialize buffer that holds copies of incoming packets */
+       if (max_pkt_size) {
+               ring_info->pkt_buffer = kzalloc(max_pkt_size, GFP_KERNEL);
+               if (!ring_info->pkt_buffer)
+                       return -ENOMEM;
+               ring_info->pkt_buffer_size = max_pkt_size;
+       }
+
        spin_lock_init(&ring_info->ring_lock);
 
        return 0;
@@ -235,6 +243,9 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
        vunmap(ring_info->ring_buffer);
        ring_info->ring_buffer = NULL;
        mutex_unlock(&ring_info->ring_buffer_mutex);
+
+       kfree(ring_info->pkt_buffer);
+       ring_info->pkt_buffer_size = 0;
 }
 
 /* Write to the ring buffer. */
@@ -301,10 +312,12 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
         */
 
        if (desc->flags == VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED) {
-               rqst_id = vmbus_next_request_id(&channel->requestor, requestid);
-               if (rqst_id == VMBUS_RQST_ERROR) {
-                       spin_unlock_irqrestore(&outring_info->ring_lock, flags);
-                       return -EAGAIN;
+               if (channel->next_request_id_callback != NULL) {
+                       rqst_id = channel->next_request_id_callback(channel, requestid);
+                       if (rqst_id == VMBUS_RQST_ERROR) {
+                               spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+                               return -EAGAIN;
+                       }
                }
        }
        desc = hv_get_ring_buffer(outring_info) + old_write;
@@ -332,7 +345,8 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
        if (channel->rescind) {
                if (rqst_id != VMBUS_NO_RQSTOR) {
                        /* Reclaim request ID to avoid leak of IDs */
-                       vmbus_request_addr(&channel->requestor, rqst_id);
+                       if (channel->request_addr_callback != NULL)
+                               channel->request_addr_callback(channel, rqst_id);
                }
                return -ENODEV;
        }
@@ -375,7 +389,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
        memcpy(buffer, (const char *)desc + offset, packetlen);
 
        /* Advance ring index to next packet descriptor */
-       __hv_pkt_iter_next(channel, desc);
+       __hv_pkt_iter_next(channel, desc, true);
 
        /* Notify host of update */
        hv_pkt_iter_close(channel);
@@ -402,6 +416,22 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
 }
 
 /*
+ * Get first vmbus packet without copying it out of the ring buffer
+ */
+struct vmpacket_descriptor *hv_pkt_iter_first_raw(struct vmbus_channel *channel)
+{
+       struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+       hv_debug_delay_test(channel, MESSAGE_DELAY);
+
+       if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+               return NULL;
+
+       return (struct vmpacket_descriptor *)(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
+}
+EXPORT_SYMBOL_GPL(hv_pkt_iter_first_raw);
+
+/*
  * Get first vmbus packet from ring buffer after read_index
  *
  * If ring buffer is empty, returns NULL and no other action needed.
@@ -409,17 +439,49 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
 struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
 {
        struct hv_ring_buffer_info *rbi = &channel->inbound;
-       struct vmpacket_descriptor *desc;
+       struct vmpacket_descriptor *desc, *desc_copy;
+       u32 bytes_avail, pkt_len, pkt_offset;
 
-       hv_debug_delay_test(channel, MESSAGE_DELAY);
-       if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+       desc = hv_pkt_iter_first_raw(channel);
+       if (!desc)
                return NULL;
 
-       desc = hv_get_ring_buffer(rbi) + rbi->priv_read_index;
-       if (desc)
-               prefetch((char *)desc + (desc->len8 << 3));
+       bytes_avail = min(rbi->pkt_buffer_size, hv_pkt_iter_avail(rbi));
+
+       /*
+        * Ensure the compiler does not use references to incoming Hyper-V values (which
+        * could change at any moment) when reading local variables later in the code
+        */
+       pkt_len = READ_ONCE(desc->len8) << 3;
+       pkt_offset = READ_ONCE(desc->offset8) << 3;
+
+       /*
+        * If pkt_len is invalid, set it to the smaller of hv_pkt_iter_avail() and
+        * rbi->pkt_buffer_size
+        */
+       if (pkt_len < sizeof(struct vmpacket_descriptor) || pkt_len > bytes_avail)
+               pkt_len = bytes_avail;
+
+       /*
+        * If pkt_offset is invalid, arbitrarily set it to
+        * the size of vmpacket_descriptor
+        */
+       if (pkt_offset < sizeof(struct vmpacket_descriptor) || pkt_offset > pkt_len)
+               pkt_offset = sizeof(struct vmpacket_descriptor);
+
+       /* Copy the Hyper-V packet out of the ring buffer */
+       desc_copy = (struct vmpacket_descriptor *)rbi->pkt_buffer;
+       memcpy(desc_copy, desc, pkt_len);
+
+       /*
+        * Hyper-V could still change len8 and offset8 after the earlier read.
+        * Ensure that desc_copy has legal values for len8 and offset8 that
+        * are consistent with the copy we just made
+        */
+       desc_copy->len8 = pkt_len >> 3;
+       desc_copy->offset8 = pkt_offset >> 3;
 
-       return desc;
+       return desc_copy;
 }
 EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
 
@@ -431,7 +493,8 @@ EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
  */
 struct vmpacket_descriptor *
 __hv_pkt_iter_next(struct vmbus_channel *channel,
-                  const struct vmpacket_descriptor *desc)
+                  const struct vmpacket_descriptor *desc,
+                  bool copy)
 {
        struct hv_ring_buffer_info *rbi = &channel->inbound;
        u32 packetlen = desc->len8 << 3;
@@ -444,7 +507,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
                rbi->priv_read_index -= dsize;
 
        /* more data? */
-       return hv_pkt_iter_first(channel);
+       return copy ? hv_pkt_iter_first(channel) : hv_pkt_iter_first_raw(channel);
 }
 EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
 
index 8762490..e367537 100644 (file)
@@ -1583,6 +1583,17 @@ config SENSORS_SHT3x
          This driver can also be built as a module. If so, the module
          will be called sht3x.
 
+config SENSORS_SHT4x
+       tristate "Sensiron humidity and temperature sensors. SHT4x and compat."
+       depends on I2C
+       select CRC8
+       help
+         If you say yes here you get support for the Sensiron SHT40, SHT41 and
+         SHT45 humidity and temperature sensors.
+
+         This driver can also be built as a module. If so, the module
+         will be called sht4x.
+
 config SENSORS_SHTC1
        tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
        depends on I2C
index 59e78bc..d712c61 100644 (file)
@@ -171,6 +171,7 @@ obj-$(CONFIG_SENSORS_SL28CPLD)      += sl28cpld-hwmon.o
 obj-$(CONFIG_SENSORS_SHT15)    += sht15.o
 obj-$(CONFIG_SENSORS_SHT21)    += sht21.o
 obj-$(CONFIG_SENSORS_SHT3x)    += sht3x.o
+obj-$(CONFIG_SENSORS_SHT4x)    += sht4x.o
 obj-$(CONFIG_SENSORS_SHTC1)    += shtc1.o
 obj-$(CONFIG_SENSORS_SIS5595)  += sis5595.o
 obj-$(CONFIG_SENSORS_SMM665)   += smm665.o
index 3e1d565..74ce521 100644 (file)
@@ -924,10 +924,8 @@ static int pvt_request_regs(struct pvt_hwmon *pvt)
        }
 
        pvt->regs = devm_ioremap_resource(pvt->dev, res);
-       if (IS_ERR(pvt->regs)) {
-               dev_err(pvt->dev, "Couldn't map PVT registers\n");
+       if (IS_ERR(pvt->regs))
                return PTR_ERR(pvt->regs);
-       }
 
        return 0;
 }
index 591929e..fa6aa4f 100644 (file)
@@ -310,6 +310,7 @@ static int ccp_write(struct device *dev, enum hwmon_sensor_types type,
                default:
                        break;
                }
+               break;
        default:
                break;
        }
index fd47ab4..8d3b1da 100644 (file)
@@ -153,8 +153,44 @@ static int hwmon_thermal_get_temp(void *data, int *temp)
        return 0;
 }
 
+static int hwmon_thermal_set_trips(void *data, int low, int high)
+{
+       struct hwmon_thermal_data *tdata = data;
+       struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
+       const struct hwmon_chip_info *chip = hwdev->chip;
+       const struct hwmon_channel_info **info = chip->info;
+       unsigned int i;
+       int err;
+
+       if (!chip->ops->write)
+               return 0;
+
+       for (i = 0; info[i] && info[i]->type != hwmon_temp; i++)
+               continue;
+
+       if (!info[i])
+               return 0;
+
+       if (info[i]->config[tdata->index] & HWMON_T_MIN) {
+               err = chip->ops->write(tdata->dev, hwmon_temp,
+                                      hwmon_temp_min, tdata->index, low);
+               if (err && err != -EOPNOTSUPP)
+                       return err;
+       }
+
+       if (info[i]->config[tdata->index] & HWMON_T_MAX) {
+               err = chip->ops->write(tdata->dev, hwmon_temp,
+                                      hwmon_temp_max, tdata->index, high);
+               if (err && err != -EOPNOTSUPP)
+                       return err;
+       }
+
+       return 0;
+}
+
 static const struct thermal_zone_of_device_ops hwmon_thermal_ops = {
        .get_temp = hwmon_thermal_get_temp,
+       .set_trips = hwmon_thermal_set_trips,
 };
 
 static void hwmon_thermal_remove_sensor(void *data)
index c602583..58d3828 100644 (file)
@@ -196,13 +196,11 @@ static inline u32 ina3221_reg_to_interval_us(u16 config)
        u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK);
        u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config);
        u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config);
-       u32 samples_idx = INA3221_CONFIG_AVG(config);
-       u32 samples = ina3221_avg_samples[samples_idx];
        u32 vbus_ct = ina3221_conv_time[vbus_ct_idx];
        u32 vsh_ct = ina3221_conv_time[vsh_ct_idx];
 
        /* Calculate total conversion time */
-       return channels * (vbus_ct + vsh_ct) * samples;
+       return channels * (vbus_ct + vsh_ct);
 }
 
 static inline int ina3221_wait_for_data(struct ina3221_data *ina)
@@ -288,13 +286,14 @@ static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val)
                        return -ENODATA;
 
                /* Write CONFIG register to trigger a single-shot measurement */
-               if (ina->single_shot)
+               if (ina->single_shot) {
                        regmap_write(ina->regmap, INA3221_CONFIG,
                                     ina->reg_config);
 
-               ret = ina3221_wait_for_data(ina);
-               if (ret)
-                       return ret;
+                       ret = ina3221_wait_for_data(ina);
+                       if (ret)
+                               return ret;
+               }
 
                ret = ina3221_read_value(ina, reg, &regval);
                if (ret)
@@ -344,13 +343,14 @@ static int ina3221_read_curr(struct device *dev, u32 attr,
                        return -ENODATA;
 
                /* Write CONFIG register to trigger a single-shot measurement */
-               if (ina->single_shot)
+               if (ina->single_shot) {
                        regmap_write(ina->regmap, INA3221_CONFIG,
                                     ina->reg_config);
 
-               ret = ina3221_wait_for_data(ina);
-               if (ret)
-                       return ret;
+                       ret = ina3221_wait_for_data(ina);
+                       if (ret)
+                               return ret;
+               }
 
                fallthrough;
        case hwmon_curr_crit:
index 40eab33..d2a60de 100644 (file)
 #include <linux/hwmon.h>
 #include <linux/mutex.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of.h>
 #include <linux/property.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
-#include <linux/acpi.h>
 
 #define DRVNAME                "lm70"
 
@@ -148,29 +148,6 @@ static const struct of_device_id lm70_of_ids[] = {
 MODULE_DEVICE_TABLE(of, lm70_of_ids);
 #endif
 
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id lm70_acpi_ids[] = {
-       {
-               .id = "LM000070",
-               .driver_data = LM70_CHIP_LM70,
-       },
-       {
-               .id = "TMP00121",
-               .driver_data = LM70_CHIP_TMP121,
-       },
-       {
-               .id = "LM000071",
-               .driver_data = LM70_CHIP_LM71,
-       },
-       {
-               .id = "LM000074",
-               .driver_data = LM70_CHIP_LM74,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(acpi, lm70_acpi_ids);
-#endif
-
 static int lm70_probe(struct spi_device *spi)
 {
        struct device *hwmon_dev;
@@ -184,7 +161,7 @@ static int lm70_probe(struct spi_device *spi)
 
 
        /* signaling is SPI_MODE_0 */
-       if (spi->mode & (SPI_CPOL | SPI_CPHA))
+       if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
                return -EINVAL;
 
        /* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
@@ -217,7 +194,6 @@ static struct spi_driver lm70_driver = {
        .driver = {
                .name   = "lm70",
                .of_match_table = of_match_ptr(lm70_of_ids),
-               .acpi_match_table = ACPI_PTR(lm70_acpi_ids),
        },
        .id_table = lm70_ids,
        .probe  = lm70_probe,
index e447feb..afdbb63 100644 (file)
@@ -50,6 +50,7 @@ enum lm75_type {              /* keep sorted in alphabetical order */
        tmp75,
        tmp75b,
        tmp75c,
+       tmp1075,
 };
 
 /**
@@ -293,6 +294,13 @@ static const struct lm75_params device_params[] = {
                .clr_mask = 1 << 5,     /*not one-shot mode*/
                .default_resolution = 12,
                .default_sample_time = MSEC_PER_SEC / 12,
+       },
+       [tmp1075] = { /* not one-shot mode, 27.5 ms sample rate */
+               .clr_mask = 1 << 5 | 1 << 6 | 1 << 7,
+               .default_resolution = 12,
+               .default_sample_time = 28,
+               .num_sample_times = 4,
+               .sample_times = (unsigned int []){ 28, 55, 110, 220 },
        }
 };
 
@@ -662,6 +670,7 @@ static const struct i2c_device_id lm75_ids[] = {
        { "tmp75", tmp75, },
        { "tmp75b", tmp75b, },
        { "tmp75c", tmp75c, },
+       { "tmp1075", tmp1075, },
        { /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, lm75_ids);
@@ -771,6 +780,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
                .compatible = "ti,tmp75c",
                .data = (void *)tmp75c
        },
+       {
+               .compatible = "ti,tmp1075",
+               .data = (void *)tmp1075
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, lm75_of_match);
index ebbfd5f..567b7c5 100644 (file)
@@ -465,6 +465,7 @@ enum lm90_temp11_reg_index {
 
 struct lm90_data {
        struct i2c_client *client;
+       struct device *hwmon_dev;
        u32 channel_config[4];
        struct hwmon_channel_info temp_info;
        const struct hwmon_channel_info *info[3];
@@ -1028,8 +1029,11 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
        int err;
 
        /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index <= 2)
+       if (data->kind == lm99 && index <= 2) {
+               /* prevent integer underflow */
+               val = max(val, -128000l);
                val -= 16000;
+       }
 
        if (data->kind == adt7461 || data->kind == tmp451)
                data->temp11[index] = temp_to_u16_adt7461(data, val);
@@ -1088,8 +1092,11 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
        int err;
 
        /* +16 degrees offset for temp2 for the LM99 */
-       if (data->kind == lm99 && index == 3)
+       if (data->kind == lm99 && index == 3) {
+               /* prevent integer underflow */
+               val = max(val, -128000l);
                val -= 16000;
+       }
 
        if (data->kind == adt7461 || data->kind == tmp451)
                data->temp8[index] = temp_to_u8_adt7461(data, val);
@@ -1136,6 +1143,9 @@ static int lm90_set_temphyst(struct lm90_data *data, long val)
        else
                temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
 
+       /* prevent integer underflow */
+       val = max(val, -128000l);
+
        data->temp_hyst = hyst_to_reg(temp - val);
        err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
                                        data->temp_hyst);
@@ -1703,6 +1713,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
        if (data->kind == max6696)
                config &= ~0x08;
 
+       /*
+        * Interrupt is enabled by default on reset, but it may be disabled
+        * by bootloader, unmask it.
+        */
+       if (client->irq)
+               config &= ~0x80;
+
        config &= 0xBF; /* run */
        lm90_update_confreg(data, config);
 
@@ -1731,22 +1748,41 @@ static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
 
        if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
            (st2 & MAX6696_STATUS2_LOT2))
-               dev_warn(&client->dev,
-                        "temp%d out of range, please check!\n", 1);
+               dev_dbg(&client->dev,
+                       "temp%d out of range, please check!\n", 1);
        if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
            (st2 & MAX6696_STATUS2_ROT2))
-               dev_warn(&client->dev,
-                        "temp%d out of range, please check!\n", 2);
+               dev_dbg(&client->dev,
+                       "temp%d out of range, please check!\n", 2);
        if (st & LM90_STATUS_ROPEN)
-               dev_warn(&client->dev,
-                        "temp%d diode open, please check!\n", 2);
+               dev_dbg(&client->dev,
+                       "temp%d diode open, please check!\n", 2);
        if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
                   MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
-               dev_warn(&client->dev,
-                        "temp%d out of range, please check!\n", 3);
+               dev_dbg(&client->dev,
+                       "temp%d out of range, please check!\n", 3);
        if (st2 & MAX6696_STATUS2_R2OPEN)
-               dev_warn(&client->dev,
-                        "temp%d diode open, please check!\n", 3);
+               dev_dbg(&client->dev,
+                       "temp%d diode open, please check!\n", 3);
+
+       if (st & LM90_STATUS_LLOW)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_min, 0);
+       if (st & LM90_STATUS_RLOW)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_min, 1);
+       if (st2 & MAX6696_STATUS2_R2LOW)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_min, 2);
+       if (st & LM90_STATUS_LHIGH)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_max, 0);
+       if (st & LM90_STATUS_RHIGH)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_max, 1);
+       if (st2 & MAX6696_STATUS2_R2HIGH)
+               hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+                                  hwmon_temp_max, 2);
 
        return true;
 }
@@ -1904,12 +1940,13 @@ static int lm90_probe(struct i2c_client *client)
        if (IS_ERR(hwmon_dev))
                return PTR_ERR(hwmon_dev);
 
+       data->hwmon_dev = hwmon_dev;
+
        if (client->irq) {
                dev_dbg(dev, "IRQ: %d\n", client->irq);
                err = devm_request_threaded_irq(dev, client->irq,
                                                NULL, lm90_irq_thread,
-                                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                                               "lm90", client);
+                                               IRQF_ONESHOT, "lm90", client);
                if (err < 0) {
                        dev_err(dev, "cannot request IRQ %d\n", client->irq);
                        return err;
@@ -1941,15 +1978,40 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
                        lm90_update_confreg(data, data->config | 0x80);
                }
        } else {
-               dev_info(&client->dev, "Everything OK\n");
+               dev_dbg(&client->dev, "Everything OK\n");
        }
 }
 
+static int __maybe_unused lm90_suspend(struct device *dev)
+{
+       struct lm90_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       if (client->irq)
+               disable_irq(client->irq);
+
+       return 0;
+}
+
+static int __maybe_unused lm90_resume(struct device *dev)
+{
+       struct lm90_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       if (client->irq)
+               enable_irq(client->irq);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(lm90_pm_ops, lm90_suspend, lm90_resume);
+
 static struct i2c_driver lm90_driver = {
        .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "lm90",
                .of_match_table = of_match_ptr(lm90_of_match),
+               .pm     = &lm90_pm_ops,
        },
        .probe_new      = lm90_probe,
        .alert          = lm90_alert,
index 062eceb..613338c 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (c) 2016, Intel Corporation.
  */
 
-#include <linux/acpi.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
@@ -133,20 +132,12 @@ static const struct spi_device_id max31722_spi_id[] = {
        {"max31723", 0},
        {}
 };
-
-static const struct acpi_device_id __maybe_unused max31722_acpi_id[] = {
-       {"MAX31722", 0},
-       {"MAX31723", 0},
-       {}
-};
-
 MODULE_DEVICE_TABLE(spi, max31722_spi_id);
 
 static struct spi_driver max31722_driver = {
        .driver = {
                .name = "max31722",
                .pm = &max31722_pm_ops,
-               .acpi_match_table = ACPI_PTR(max31722_acpi_id),
        },
        .probe =            max31722_probe,
        .remove =           max31722_remove,
index 86e6c71..7e9362f 100644 (file)
@@ -27,6 +27,7 @@
 
 /* Fan Config register bits */
 #define MAX31790_FAN_CFG_RPM_MODE      0x80
+#define MAX31790_FAN_CFG_CTRL_MON      0x10
 #define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08
 #define MAX31790_FAN_CFG_TACH_INPUT    0x01
 
@@ -39,6 +40,8 @@
 #define FAN_RPM_MIN                    120
 #define FAN_RPM_MAX                    7864320
 
+#define FAN_COUNT_REG_MAX              0xffe0
+
 #define RPM_FROM_REG(reg, sr)          (((reg) >> 4) ? \
                                         ((60 * (sr) * 8192) / ((reg) >> 4)) : \
                                         FAN_RPM_MAX)
@@ -79,7 +82,7 @@ static struct max31790_data *max31790_update_device(struct device *dev)
                                MAX31790_REG_FAN_FAULT_STATUS1);
                if (rv < 0)
                        goto abort;
-               data->fault_status = rv & 0x3F;
+               data->fault_status |= rv & 0x3F;
 
                rv = i2c_smbus_read_byte_data(client,
                                MAX31790_REG_FAN_FAULT_STATUS2);
@@ -104,7 +107,7 @@ static struct max31790_data *max31790_update_device(struct device *dev)
                                data->tach[NR_CHANNEL + i] = rv;
                        } else {
                                rv = i2c_smbus_read_word_swapped(client,
-                                               MAX31790_REG_PWMOUT(i));
+                                               MAX31790_REG_PWM_DUTY_CYCLE(i));
                                if (rv < 0)
                                        goto abort;
                                data->pwm[i] = rv;
@@ -170,8 +173,11 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
 
        switch (attr) {
        case hwmon_fan_input:
-               sr = get_tach_period(data->fan_dynamics[channel]);
-               rpm = RPM_FROM_REG(data->tach[channel], sr);
+               sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
+               if (data->tach[channel] == FAN_COUNT_REG_MAX)
+                       rpm = 0;
+               else
+                       rpm = RPM_FROM_REG(data->tach[channel], sr);
                *val = rpm;
                return 0;
        case hwmon_fan_target:
@@ -180,7 +186,21 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
                *val = rpm;
                return 0;
        case hwmon_fan_fault:
+               mutex_lock(&data->update_lock);
                *val = !!(data->fault_status & (1 << channel));
+               data->fault_status &= ~(1 << channel);
+               /*
+                * If a fault bit is set, we need to write into one of the fan
+                * configuration registers to clear it. Note that this also
+                * clears the fault for the companion channel if enabled.
+                */
+               if (*val) {
+                       int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL);
+
+                       i2c_smbus_write_byte_data(data->client, reg,
+                                                 data->target_count[channel % NR_CHANNEL] >> 8);
+               }
+               mutex_unlock(&data->update_lock);
                return 0;
        default:
                return -EOPNOTSUPP;
@@ -271,12 +291,12 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel,
                *val = data->pwm[channel] >> 8;
                return 0;
        case hwmon_pwm_enable:
-               if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
+               if (fan_config & MAX31790_FAN_CFG_CTRL_MON)
+                       *val = 0;
+               else if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
                        *val = 2;
-               else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN)
-                       *val = 1;
                else
-                       *val = 0;
+                       *val = 1;
                return 0;
        default:
                return -EOPNOTSUPP;
@@ -299,31 +319,41 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
                        err = -EINVAL;
                        break;
                }
-               data->pwm[channel] = val << 8;
+               data->valid = false;
                err = i2c_smbus_write_word_swapped(client,
                                                   MAX31790_REG_PWMOUT(channel),
-                                                  data->pwm[channel]);
+                                                  val << 8);
                break;
        case hwmon_pwm_enable:
                fan_config = data->fan_config[channel];
                if (val == 0) {
-                       fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN |
-                                       MAX31790_FAN_CFG_RPM_MODE);
+                       fan_config |= MAX31790_FAN_CFG_CTRL_MON;
+                       /*
+                        * Disable RPM mode; otherwise disabling fan speed
+                        * monitoring is not possible.
+                        */
+                       fan_config &= ~MAX31790_FAN_CFG_RPM_MODE;
                } else if (val == 1) {
-                       fan_config = (fan_config |
-                                     MAX31790_FAN_CFG_TACH_INPUT_EN) &
-                                    ~MAX31790_FAN_CFG_RPM_MODE;
+                       fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE);
                } else if (val == 2) {
-                       fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN |
-                                     MAX31790_FAN_CFG_RPM_MODE;
+                       fan_config &= ~MAX31790_FAN_CFG_CTRL_MON;
+                       /*
+                        * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its
+                        * own if MAX31790_FAN_CFG_RPM_MODE is set.
+                        * Do it here as well to reflect the actual register
+                        * value in the cache.
+                        */
+                       fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN);
                } else {
                        err = -EINVAL;
                        break;
                }
-               data->fan_config[channel] = fan_config;
-               err = i2c_smbus_write_byte_data(client,
-                                       MAX31790_REG_FAN_CONFIG(channel),
-                                       fan_config);
+               if (fan_config != data->fan_config[channel]) {
+                       err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel),
+                                                       fan_config);
+                       if (!err)
+                               data->fan_config[channel] = fan_config;
+               }
                break;
        default:
                err = -EOPNOTSUPP;
index 367855d..7821132 100644 (file)
@@ -156,7 +156,7 @@ max6621_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
                default:
                        break;
                }
-
+               break;
        default:
                break;
        }
index 8587189..18fd6f1 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/pm_runtime.h>
 #include <linux/math64.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -17,9 +16,6 @@
 
 #include <linux/platform_data/ntc_thermistor.h>
 
-#include <linux/iio/iio.h>
-#include <linux/iio/machine.h>
-#include <linux/iio/driver.h>
 #include <linux/iio/consumer.h>
 
 #include <linux/hwmon.h>
index 37a5c39..ffb609c 100644 (file)
@@ -19,9 +19,10 @@ config SENSORS_PMBUS
        default y
        help
          If you say yes here you get hardware monitoring support for generic
-         PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
-         MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400,
-         TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020.
+         PMBus devices, including but not limited to ADP4000, BMR310, BMR453,
+         BMR454, BMR456, BMR457, BMR458, BMR480, BMR490, BMR491, BMR492,
+         MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012,
+         TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020.
 
          This driver can also be built as a module. If so, the module will
          be called pmbus.
@@ -85,6 +86,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_DPS920AB
+       tristate "Delta DPS920AB Power Supply"
+       help
+         If you say yes here you get hardware monitoring support for Delta
+         DPS920AB Power Supplies.
+
+         This driver can also be built as a module. If so, the module will
+         be called dps920ab.
+
 config SENSORS_INSPUR_IPSPS
        tristate "INSPUR Power System Power Supply"
        help
@@ -248,6 +258,15 @@ config SENSORS_MAX8688
          This driver can also be built as a module. If so, the module will
          be called max8688.
 
+config SENSORS_MP2888
+       tristate "MPS MP2888"
+       help
+         If you say yes here you get hardware monitoring support for MPS
+         MP2888 Digital, Multi-Phase, Pulse-Width Modulation Controller.
+
+         This driver can also be built as a module. If so, the module will
+         be called mp2888.
+
 config SENSORS_MP2975
        tristate "MPS MP2975"
        help
@@ -257,6 +276,15 @@ config SENSORS_MP2975
          This driver can also be built as a module. If so, the module will
          be called mp2975.
 
+config SENSORS_PIM4328
+       tristate "Flex PIM4328 and compatibles"
+       help
+         If you say yes here you get hardware monitoring support for Flex
+         PIM4328, PIM4820 and PIM4006 Power Interface Modules.
+
+         This driver can also be built as a module. If so, the module will
+         be called pim4328.
+
 config SENSORS_PM6764TR
        tristate "ST PM6764TR"
        help
index f8dcc27..0ed4d59 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
 obj-$(CONFIG_SENSORS_BPA_RS600)        += bpa-rs600.o
 obj-$(CONFIG_SENSORS_FSP_3Y)   += fsp-3y.o
 obj-$(CONFIG_SENSORS_IBM_CFFPS)        += ibm-cffps.o
+obj-$(CONFIG_SENSORS_DPS920AB) += dps920ab.o
 obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
 obj-$(CONFIG_SENSORS_IR35221)  += ir35221.o
 obj-$(CONFIG_SENSORS_IR36021)  += ir36021.o
@@ -28,6 +29,7 @@ obj-$(CONFIG_SENSORS_MAX20751)        += max20751.o
 obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
 obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
+obj-$(CONFIG_SENSORS_MP2888)   += mp2888.o
 obj-$(CONFIG_SENSORS_MP2975)   += mp2975.o
 obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
 obj-$(CONFIG_SENSORS_PXE1610)  += pxe1610.o
@@ -39,3 +41,4 @@ obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
 obj-$(CONFIG_SENSORS_UCD9200)  += ucd9200.o
 obj-$(CONFIG_SENSORS_XDPE122)  += xdpe12284.o
 obj-$(CONFIG_SENSORS_ZL6100)   += zl6100.o
+obj-$(CONFIG_SENSORS_PIM4328)  += pim4328.o
index 980a385..d311e05 100644 (file)
@@ -611,11 +611,13 @@ static int adm1275_probe(struct i2c_client *client)
                tindex = 8;
 
                info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
-                       PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+                       PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+                       PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
-               /* Enable VOUT if not enabled (it is disabled by default) */
-               if (!(config & ADM1278_VOUT_EN)) {
-                       config |= ADM1278_VOUT_EN;
+               /* Enable VOUT & TEMP1 if not enabled (disabled by default) */
+               if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) !=
+                   (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) {
+                       config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN;
                        ret = i2c_smbus_write_byte_data(client,
                                                        ADM1275_PMON_CONFIG,
                                                        config);
@@ -625,10 +627,6 @@ static int adm1275_probe(struct i2c_client *client)
                                return -ENODEV;
                        }
                }
-
-               if (config & ADM1278_TEMP1_EN)
-                       info->func[0] |=
-                               PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
                if (config & ADM1278_VIN_EN)
                        info->func[0] |= PMBUS_HAVE_VIN;
                break;
index f6558ee..2be69fe 100644 (file)
@@ -46,6 +46,32 @@ static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg
        return ret;
 }
 
+/*
+ * The BPA-RS600 violates the PMBus spec. Specifically it treats the
+ * mantissa as unsigned. Deal with this here to allow the PMBus core
+ * to work with correctly encoded data.
+ */
+static int bpa_rs600_read_vin(struct i2c_client *client)
+{
+       int ret, exponent, mantissa;
+
+       ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_READ_VIN);
+       if (ret < 0)
+               return ret;
+
+       if (ret & BIT(10)) {
+               exponent = ret >> 11;
+               mantissa = ret & 0x7ff;
+
+               exponent++;
+               mantissa >>= 1;
+
+               ret = (exponent << 11) | mantissa;
+       }
+
+       return ret;
+}
+
 static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg)
 {
        int ret;
@@ -85,6 +111,9 @@ static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int pha
                /* These commands return data but it is invalid/un-documented */
                ret = -ENXIO;
                break;
+       case PMBUS_READ_VIN:
+               ret = bpa_rs600_read_vin(client);
+               break;
        default:
                if (reg >= PMBUS_VIRT_BASE)
                        ret = -ENXIO;
diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c
new file mode 100644 (file)
index 0000000..d3941f6
--- /dev/null
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Delta DPS920AB PSU
+ *
+ * Copyright (C) 2021 Delta Networks, Inc.
+ * Copyright (C) 2021 Sartura Ltd.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include "pmbus.h"
+
+struct dps920ab_data {
+       char *mfr_model;
+       char *mfr_id;
+};
+
+static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+       /*
+        * This masks commands which are not supported.
+        * PSU advertises that all features are supported,
+        * in reality that unfortunately is not true.
+        * So enable only those that the datasheet confirms.
+        */
+       switch (reg) {
+       case PMBUS_FAN_COMMAND_1:
+       case PMBUS_IOUT_OC_WARN_LIMIT:
+       case PMBUS_STATUS_WORD:
+       case PMBUS_READ_VIN:
+       case PMBUS_READ_IIN:
+       case PMBUS_READ_VOUT:
+       case PMBUS_READ_IOUT:
+       case PMBUS_READ_TEMPERATURE_1:
+       case PMBUS_READ_TEMPERATURE_2:
+       case PMBUS_READ_TEMPERATURE_3:
+       case PMBUS_READ_FAN_SPEED_1:
+       case PMBUS_READ_POUT:
+       case PMBUS_READ_PIN:
+       case PMBUS_MFR_VOUT_MIN:
+       case PMBUS_MFR_VOUT_MAX:
+       case PMBUS_MFR_IOUT_MAX:
+       case PMBUS_MFR_POUT_MAX:
+               return pmbus_read_word_data(client, page, phase, reg);
+       default:
+               return -ENXIO;
+       }
+}
+
+static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg,
+                                   u16 word)
+{
+       /*
+        * This masks commands which are not supported.
+        * PSU only has one R/W register and that is
+        * for the fan.
+        */
+       switch (reg) {
+       case PMBUS_FAN_COMMAND_1:
+               return pmbus_write_word_data(client, page, reg, word);
+       default:
+               return -EACCES;
+       }
+}
+
+static struct pmbus_driver_info dps920ab_info = {
+       .pages = 1,
+
+       .format[PSC_VOLTAGE_IN] = linear,
+       .format[PSC_VOLTAGE_OUT] = linear,
+       .format[PSC_CURRENT_IN] = linear,
+       .format[PSC_CURRENT_OUT] = linear,
+       .format[PSC_POWER] = linear,
+       .format[PSC_FAN] = linear,
+       .format[PSC_TEMPERATURE] = linear,
+
+       .func[0] =
+               PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+               PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
+               PMBUS_HAVE_TEMP  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+               PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
+               PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+               PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+       .read_word_data = dps920ab_read_word_data,
+       .write_word_data = dps920ab_write_word_data,
+};
+
+static int dps920ab_mfr_id_show(struct seq_file *s, void *data)
+{
+       struct dps920ab_data *priv = s->private;
+
+       seq_printf(s, "%s\n", priv->mfr_id);
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id);
+
+static int dps920ab_mfr_model_show(struct seq_file *s, void *data)
+{
+       struct dps920ab_data *priv = s->private;
+
+       seq_printf(s, "%s\n", priv->mfr_model);
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model);
+
+static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client)
+{
+       struct dentry *debugfs_dir;
+       struct dentry *root;
+
+       root = pmbus_get_debugfs_dir(client);
+       if (!root)
+               return;
+
+       debugfs_dir = debugfs_create_dir(client->name, root);
+
+       debugfs_create_file("mfr_id",
+                           0400,
+                           debugfs_dir,
+                           data,
+                           &dps920ab_mfr_id_fops);
+
+       debugfs_create_file("mfr_model",
+                           0400,
+                           debugfs_dir,
+                           data,
+                           &dps920ab_mfr_model_fops);
+}
+
+static int dps920ab_probe(struct i2c_client *client)
+{
+       u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+       struct dps920ab_data *data;
+       int ret;
+
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read Manufacturer ID\n");
+               return ret;
+       }
+
+       buf[ret] = '\0';
+       if (ret != 5 || strncmp(buf, "DELTA", 5)) {
+               buf[ret] = '\0';
+               dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf);
+               return -ENODEV;
+       }
+       data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
+       if (!data->mfr_id)
+               return -ENOMEM;
+
+       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+               return ret;
+       }
+
+       buf[ret] = '\0';
+       if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) {
+               dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf);
+               return -ENODEV;
+       }
+       data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
+       if (!data->mfr_model)
+               return -ENOMEM;
+
+       ret = pmbus_do_probe(client, &dps920ab_info);
+       if (ret)
+               return ret;
+
+       dps920ab_init_debugfs(data, client);
+
+       return 0;
+}
+
+static const struct of_device_id __maybe_unused dps920ab_of_match[] = {
+       { .compatible = "delta,dps920ab", },
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, dps920ab_of_match);
+
+static struct i2c_driver dps920ab_driver = {
+       .driver = {
+                  .name = "dps920ab",
+                  .of_match_table = of_match_ptr(dps920ab_of_match),
+       },
+       .probe_new = dps920ab_probe,
+};
+
+module_i2c_driver(dps920ab_driver);
+
+MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
+MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c
new file mode 100644 (file)
index 0000000..8ecd4ad
--- /dev/null
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers
+ *
+ * Copyright (C) 2020 Nvidia Technologies Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+/* Vendor specific registers. */
+#define MP2888_MFR_SYS_CONFIG  0x44
+#define MP2888_MFR_READ_CS1_2  0x73
+#define MP2888_MFR_READ_CS3_4  0x74
+#define MP2888_MFR_READ_CS5_6  0x75
+#define MP2888_MFR_READ_CS7_8  0x76
+#define MP2888_MFR_READ_CS9_10 0x77
+#define MP2888_MFR_VR_CONFIG1  0xe1
+
+#define MP2888_TOTAL_CURRENT_RESOLUTION        BIT(3)
+#define MP2888_PHASE_CURRENT_RESOLUTION        BIT(4)
+#define MP2888_DRMOS_KCS               GENMASK(2, 0)
+#define MP2888_TEMP_UNIT               10
+#define MP2888_MAX_PHASE               10
+
+struct mp2888_data {
+       struct pmbus_driver_info info;
+       int total_curr_resolution;
+       int phase_curr_resolution;
+       int curr_sense_gain;
+};
+
+#define to_mp2888_data(x)  container_of(x, struct mp2888_data, info)
+
+static int mp2888_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       switch (reg) {
+       case PMBUS_VOUT_MODE:
+               /* Enforce VOUT direct format. */
+               return PB_VOUT_MODE_DIRECT;
+       default:
+               return -ENODATA;
+       }
+}
+
+static int
+mp2888_current_sense_gain_and_resolution_get(struct i2c_client *client, struct mp2888_data *data)
+{
+       int ret;
+
+       /*
+        * Obtain DrMOS current sense gain of power stage from the register
+        * , bits 0-2. The value is selected as below:
+        * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other
+        * values are reserved.
+        */
+       ret = i2c_smbus_read_word_data(client, MP2888_MFR_SYS_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       switch (ret & MP2888_DRMOS_KCS) {
+       case 0:
+               data->curr_sense_gain = 85;
+               break;
+       case 1:
+               data->curr_sense_gain = 97;
+               break;
+       case 2:
+               data->curr_sense_gain = 100;
+               break;
+       case 3:
+               data->curr_sense_gain = 50;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * Obtain resolution selector for total and phase current report and protection.
+        * 0: original resolution; 1: half resolution (in such case phase current value should
+        * be doubled.
+        */
+       data->total_curr_resolution = (ret & MP2888_TOTAL_CURRENT_RESOLUTION) >> 3;
+       data->phase_curr_resolution = (ret & MP2888_PHASE_CURRENT_RESOLUTION) >> 4;
+
+       return 0;
+}
+
+static int
+mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, int phase, u8 reg)
+{
+       int ret;
+
+       ret = pmbus_read_word_data(client, page, phase, reg);
+       if (ret < 0)
+               return ret;
+
+       if (!((phase + 1) % 2))
+               ret >>= 8;
+       ret &= 0xff;
+
+       /*
+        * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs)
+        * where:
+        * - Kcs is the DrMOS current sense gain of power stage, which is obtained from the
+        *   register MP2888_MFR_VR_CONFIG1, bits 13-12 with the following selection of DrMOS
+        *   (data->curr_sense_gain):
+        *   00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A.
+        * - Rcs is the internal phase current sense resistor. This parameter depends on hardware
+        *   assembly. By default it is set to 1kΩ. In case of different assembly, user should
+        *   scale this parameter by dividing it by Rcs.
+        * If phase current resolution bit is set to 1, READ_CSx value should be doubled.
+        * Note, that current phase sensing, providing by the device is not accurate. This is
+        * because sampling of current occurrence of bit weight has a big deviation, especially for
+        * light load.
+        */
+       ret = DIV_ROUND_CLOSEST(ret * 100 - 9800, data->curr_sense_gain);
+       ret = (data->phase_curr_resolution) ? ret * 2 : ret;
+       /* Scale according to total current resolution. */
+       ret = (data->total_curr_resolution) ? ret * 8 : ret * 4;
+       return ret;
+}
+
+static int
+mp2888_read_phases(struct i2c_client *client, struct mp2888_data *data, int page, int phase)
+{
+       int ret;
+
+       switch (phase) {
+       case 0 ... 1:
+               ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS1_2);
+               break;
+       case 2 ... 3:
+               ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS3_4);
+               break;
+       case 4 ... 5:
+               ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS5_6);
+               break;
+       case 6 ... 7:
+               ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS7_8);
+               break;
+       case 8 ... 9:
+               ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS9_10);
+               break;
+       default:
+               return -ENODATA;
+       }
+       return ret;
+}
+
+static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       struct mp2888_data *data = to_mp2888_data(info);
+       int ret;
+
+       switch (reg) {
+       case PMBUS_READ_VIN:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret <= 0)
+                       return ret;
+
+               /*
+                * READ_VIN requires fixup to scale it to linear11 format. Register data format
+                * provides 10 bits for mantissa and 6 bits for exponent. Bits 15:10 are set with
+                * the fixed value 111011b.
+                */
+               ret = (ret & GENMASK(9, 0)) | ((ret & GENMASK(31, 10)) << 1);
+               break;
+       case PMBUS_OT_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+               /*
+                * Chip reports limits in degrees C, but the actual temperature in 10th of
+                * degrees C - scaling is needed to match both.
+                */
+               ret *= MP2888_TEMP_UNIT;
+               break;
+       case PMBUS_READ_IOUT:
+               if (phase != 0xff)
+                       return mp2888_read_phases(client, data, page, phase);
+
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+               /*
+                * READ_IOUT register has unused bits 15:12 with fixed value 1110b. Clear these
+                * bits and scale with total current resolution. Data is provided in direct format.
+                */
+               ret &= GENMASK(11, 0);
+               ret = data->total_curr_resolution ? ret * 2 : ret;
+               break;
+       case PMBUS_IOUT_OC_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+               ret &= GENMASK(9, 0);
+               /*
+                * Chip reports limits with resolution 1A or 2A, if total current resolution bit is
+                * set 1. Actual current is reported with 0.25A or respectively 0.5A resolution.
+                * Scaling is needed to match both.
+                */
+               ret = data->total_curr_resolution ? ret * 8 : ret * 4;
+               break;
+       case PMBUS_READ_POUT:
+       case PMBUS_READ_PIN:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+               ret = data->total_curr_resolution ? ret * 2 : ret;
+               break;
+       case PMBUS_POUT_OP_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+               /*
+                * Chip reports limits with resolution 1W or 2W, if total current resolution bit is
+                * set 1. Actual power is reported with 0.5W or 1W respectively resolution. Scaling
+                * is needed to match both.
+                */
+               ret = data->total_curr_resolution ? ret * 4 : ret * 2;
+               break;
+       /*
+        * The below registers are not implemented by device or implemented not according to the
+        * spec. Skip all of them to avoid exposing non-relevant inputs to sysfs.
+        */
+       case PMBUS_OT_FAULT_LIMIT:
+       case PMBUS_UT_WARN_LIMIT:
+       case PMBUS_UT_FAULT_LIMIT:
+       case PMBUS_VIN_UV_FAULT_LIMIT:
+       case PMBUS_VOUT_UV_WARN_LIMIT:
+       case PMBUS_VOUT_OV_WARN_LIMIT:
+       case PMBUS_VOUT_UV_FAULT_LIMIT:
+       case PMBUS_VOUT_OV_FAULT_LIMIT:
+       case PMBUS_VIN_OV_WARN_LIMIT:
+       case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
+       case PMBUS_IOUT_OC_FAULT_LIMIT:
+       case PMBUS_POUT_MAX:
+       case PMBUS_IOUT_UC_FAULT_LIMIT:
+       case PMBUS_POUT_OP_FAULT_LIMIT:
+       case PMBUS_PIN_OP_WARN_LIMIT:
+       case PMBUS_MFR_VIN_MIN:
+       case PMBUS_MFR_VOUT_MIN:
+       case PMBUS_MFR_VIN_MAX:
+       case PMBUS_MFR_VOUT_MAX:
+       case PMBUS_MFR_IIN_MAX:
+       case PMBUS_MFR_IOUT_MAX:
+       case PMBUS_MFR_PIN_MAX:
+       case PMBUS_MFR_POUT_MAX:
+       case PMBUS_MFR_MAX_TEMP_1:
+               return -ENXIO;
+       default:
+               return -ENODATA;
+       }
+
+       return ret;
+}
+
+static int mp2888_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       struct mp2888_data *data = to_mp2888_data(info);
+
+       switch (reg) {
+       case PMBUS_OT_WARN_LIMIT:
+               word = DIV_ROUND_CLOSEST(word, MP2888_TEMP_UNIT);
+               /* Drop unused bits 15:8. */
+               word = clamp_val(word, 0, GENMASK(7, 0));
+               break;
+       case PMBUS_IOUT_OC_WARN_LIMIT:
+               /* Fix limit according to total curent resolution. */
+               word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 8) :
+                      DIV_ROUND_CLOSEST(word, 4);
+               /* Drop unused bits 15:10. */
+               word = clamp_val(word, 0, GENMASK(9, 0));
+               break;
+       case PMBUS_POUT_OP_WARN_LIMIT:
+               /* Fix limit according to total curent resolution. */
+               word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 4) :
+                      DIV_ROUND_CLOSEST(word, 2);
+               /* Drop unused bits 15:10. */
+               word = clamp_val(word, 0, GENMASK(9, 0));
+               break;
+       default:
+               return -ENODATA;
+       }
+       return pmbus_write_word_data(client, page, reg, word);
+}
+
+static int
+mp2888_identify_multiphase(struct i2c_client *client, struct mp2888_data *data,
+                          struct pmbus_driver_info *info)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+       if (ret < 0)
+               return ret;
+
+       /* Identify multiphase number - could be from 1 to 10. */
+       ret = i2c_smbus_read_word_data(client, MP2888_MFR_VR_CONFIG1);
+       if (ret <= 0)
+               return ret;
+
+       info->phases[0] = ret & GENMASK(3, 0);
+
+       /*
+        * The device provides a total of 10 PWM pins, and can be configured to different phase
+        * count applications for rail.
+        */
+       if (info->phases[0] > MP2888_MAX_PHASE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct pmbus_driver_info mp2888_info = {
+       .pages = 1,
+       .format[PSC_VOLTAGE_IN] = linear,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .format[PSC_CURRENT_IN] = linear,
+       .format[PSC_CURRENT_OUT] = direct,
+       .format[PSC_POWER] = direct,
+       .m[PSC_TEMPERATURE] = 1,
+       .R[PSC_TEMPERATURE] = 1,
+       .m[PSC_VOLTAGE_OUT] = 1,
+       .R[PSC_VOLTAGE_OUT] = 3,
+       .m[PSC_CURRENT_OUT] = 4,
+       .m[PSC_POWER] = 1,
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT |
+                  PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
+                  PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
+                  PMBUS_PHASE_VIRTUAL,
+       .pfunc[0] = PMBUS_HAVE_IOUT,
+       .pfunc[1] = PMBUS_HAVE_IOUT,
+       .pfunc[2] = PMBUS_HAVE_IOUT,
+       .pfunc[3] = PMBUS_HAVE_IOUT,
+       .pfunc[4] = PMBUS_HAVE_IOUT,
+       .pfunc[5] = PMBUS_HAVE_IOUT,
+       .pfunc[6] = PMBUS_HAVE_IOUT,
+       .pfunc[7] = PMBUS_HAVE_IOUT,
+       .pfunc[8] = PMBUS_HAVE_IOUT,
+       .pfunc[9] = PMBUS_HAVE_IOUT,
+       .read_byte_data = mp2888_read_byte_data,
+       .read_word_data = mp2888_read_word_data,
+       .write_word_data = mp2888_write_word_data,
+};
+
+static int mp2888_probe(struct i2c_client *client)
+{
+       struct pmbus_driver_info *info;
+       struct mp2888_data *data;
+       int ret;
+
+       data = devm_kzalloc(&client->dev, sizeof(struct mp2888_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       memcpy(&data->info, &mp2888_info, sizeof(*info));
+       info = &data->info;
+
+       /* Identify multiphase configuration. */
+       ret = mp2888_identify_multiphase(client, data, info);
+       if (ret)
+               return ret;
+
+       /* Obtain current sense gain of power stage and current resolution. */
+       ret = mp2888_current_sense_gain_and_resolution_get(client, data);
+       if (ret)
+               return ret;
+
+       return pmbus_do_probe(client, info);
+}
+
+static const struct i2c_device_id mp2888_id[] = {
+       {"mp2888", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mp2888_id);
+
+static const struct of_device_id __maybe_unused mp2888_of_match[] = {
+       {.compatible = "mps,mp2888"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, mp2888_of_match);
+
+static struct i2c_driver mp2888_driver = {
+       .driver = {
+               .name = "mp2888",
+               .of_match_table = of_match_ptr(mp2888_of_match),
+       },
+       .probe_new = mp2888_probe,
+       .id_table = mp2888_id,
+};
+
+module_i2c_driver(mp2888_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
+MODULE_DESCRIPTION("PMBus driver for MPS MP2888 device");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pim4328.c b/drivers/hwmon/pmbus/pim4328.c
new file mode 100644 (file)
index 0000000..273ff6e
--- /dev/null
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for PIM4006, PIM4328 and PIM4820
+ *
+ * Copyright (c) 2021 Flextronics International Sweden AB
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pmbus.h>
+#include <linux/slab.h>
+#include "pmbus.h"
+
+enum chips { pim4006, pim4328, pim4820 };
+
+struct pim4328_data {
+       enum chips id;
+       struct pmbus_driver_info info;
+};
+
+#define to_pim4328_data(x)  container_of(x, struct pim4328_data, info)
+
+/* PIM4006 and PIM4328 */
+#define PIM4328_MFR_READ_VINA          0xd3
+#define PIM4328_MFR_READ_VINB          0xd4
+
+/* PIM4006 */
+#define PIM4328_MFR_READ_IINA          0xd6
+#define PIM4328_MFR_READ_IINB          0xd7
+#define PIM4328_MFR_FET_CHECKSTATUS    0xd9
+
+/* PIM4328 */
+#define PIM4328_MFR_STATUS_BITS                0xd5
+
+/* PIM4820 */
+#define PIM4328_MFR_READ_STATUS                0xd0
+
+static const struct i2c_device_id pim4328_id[] = {
+       {"bmr455", pim4328},
+       {"pim4006", pim4006},
+       {"pim4106", pim4006},
+       {"pim4206", pim4006},
+       {"pim4306", pim4006},
+       {"pim4328", pim4328},
+       {"pim4406", pim4006},
+       {"pim4820", pim4820},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, pim4328_id);
+
+static int pim4328_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
+{
+       int ret;
+
+       if (page > 0)
+               return -ENXIO;
+
+       if (phase == 0xff)
+               return -ENODATA;
+
+       switch (reg) {
+       case PMBUS_READ_VIN:
+               ret = pmbus_read_word_data(client, page, phase,
+                                          phase == 0 ? PIM4328_MFR_READ_VINA
+                                                     : PIM4328_MFR_READ_VINB);
+               break;
+       case PMBUS_READ_IIN:
+               ret = pmbus_read_word_data(client, page, phase,
+                                          phase == 0 ? PIM4328_MFR_READ_IINA
+                                                     : PIM4328_MFR_READ_IINB);
+               break;
+       default:
+               ret = -ENODATA;
+       }
+
+       return ret;
+}
+
+static int pim4328_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       struct pim4328_data *data = to_pim4328_data(info);
+       int ret, status;
+
+       if (page > 0)
+               return -ENXIO;
+
+       switch (reg) {
+       case PMBUS_STATUS_BYTE:
+               ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
+               if (ret < 0)
+                       return ret;
+               if (data->id == pim4006) {
+                       status = pmbus_read_word_data(client, page, 0xff,
+                                                     PIM4328_MFR_FET_CHECKSTATUS);
+                       if (status < 0)
+                               return status;
+                       if (status & 0x0630) /* Input UV */
+                               ret |= PB_STATUS_VIN_UV;
+               } else if (data->id == pim4328) {
+                       status = pmbus_read_byte_data(client, page,
+                                                     PIM4328_MFR_STATUS_BITS);
+                       if (status < 0)
+                               return status;
+                       if (status & 0x04) /* Input UV */
+                               ret |= PB_STATUS_VIN_UV;
+                       if (status & 0x40) /* Output UV */
+                               ret |= PB_STATUS_NONE_ABOVE;
+               } else if (data->id == pim4820) {
+                       status = pmbus_read_byte_data(client, page,
+                                                     PIM4328_MFR_READ_STATUS);
+                       if (status < 0)
+                               return status;
+                       if (status & 0x05) /* Input OV or OC */
+                               ret |= PB_STATUS_NONE_ABOVE;
+                       if (status & 0x1a) /* Input UV */
+                               ret |= PB_STATUS_VIN_UV;
+                       if (status & 0x40) /* OT */
+                               ret |= PB_STATUS_TEMPERATURE;
+               }
+               break;
+       default:
+               ret = -ENODATA;
+       }
+
+       return ret;
+}
+
+static int pim4328_probe(struct i2c_client *client)
+{
+       int status;
+       u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+       const struct i2c_device_id *mid;
+       struct pim4328_data *data;
+       struct pmbus_driver_info *info;
+       struct pmbus_platform_data *pdata;
+       struct device *dev = &client->dev;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_BLOCK_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(&client->dev, sizeof(struct pim4328_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id);
+       if (status < 0) {
+               dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+               return status;
+       }
+       for (mid = pim4328_id; mid->name[0]; mid++) {
+               if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+                       break;
+       }
+       if (!mid->name[0]) {
+               dev_err(&client->dev, "Unsupported device\n");
+               return -ENODEV;
+       }
+
+       if (strcmp(client->name, mid->name))
+               dev_notice(&client->dev,
+                          "Device mismatch: Configured %s, detected %s\n",
+                          client->name, mid->name);
+
+       data->id = mid->driver_data;
+       info = &data->info;
+       info->pages = 1;
+       info->read_byte_data = pim4328_read_byte_data;
+       info->read_word_data = pim4328_read_word_data;
+
+       pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
+                            GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+       dev->platform_data = pdata;
+       pdata->flags = PMBUS_NO_CAPABILITY | PMBUS_NO_WRITE_PROTECT;
+
+       switch (data->id) {
+       case pim4006:
+               info->phases[0] = 2;
+               info->func[0] = PMBUS_PHASE_VIRTUAL | PMBUS_HAVE_VIN
+                       | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
+               info->pfunc[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
+               info->pfunc[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
+               break;
+       case pim4328:
+               info->phases[0] = 2;
+               info->func[0] = PMBUS_PHASE_VIRTUAL
+                       | PMBUS_HAVE_VCAP | PMBUS_HAVE_VIN
+                       | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
+               info->pfunc[0] = PMBUS_HAVE_VIN;
+               info->pfunc[1] = PMBUS_HAVE_VIN;
+               info->format[PSC_VOLTAGE_IN] = direct;
+               info->format[PSC_TEMPERATURE] = direct;
+               info->format[PSC_CURRENT_OUT] = direct;
+               pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
+               break;
+       case pim4820:
+               info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_TEMP
+                       | PMBUS_HAVE_IIN;
+               info->format[PSC_VOLTAGE_IN] = direct;
+               info->format[PSC_TEMPERATURE] = direct;
+               info->format[PSC_CURRENT_IN] = direct;
+               pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return pmbus_do_probe(client, info);
+}
+
+static struct i2c_driver pim4328_driver = {
+       .driver = {
+                  .name = "pim4328",
+                  },
+       .probe_new = pim4328_probe,
+       .id_table = pim4328_id,
+};
+
+module_i2c_driver(pim4328_driver);
+
+MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
+MODULE_DESCRIPTION("PMBus driver for PIM4006, PIM4328, PIM4820 power interface modules");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
index 618c377..d0d3869 100644 (file)
@@ -173,13 +173,13 @@ static int pmbus_probe(struct i2c_client *client)
                return -ENOMEM;
 
        device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data;
-       if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) {
+       if (device_info->flags) {
                pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
                                     GFP_KERNEL);
                if (!pdata)
                        return -ENOMEM;
 
-               pdata->flags = PMBUS_SKIP_STATUS_CHECK;
+               pdata->flags = device_info->flags;
        }
 
        info->pages = device_info->pages;
@@ -193,22 +193,37 @@ static const struct pmbus_device_info pmbus_info_one = {
        .pages = 1,
        .flags = 0
 };
+
 static const struct pmbus_device_info pmbus_info_zero = {
        .pages = 0,
        .flags = 0
 };
+
 static const struct pmbus_device_info pmbus_info_one_skip = {
        .pages = 1,
        .flags = PMBUS_SKIP_STATUS_CHECK
 };
 
+static const struct pmbus_device_info pmbus_info_one_status = {
+       .pages = 1,
+       .flags = PMBUS_READ_STATUS_AFTER_FAILED_CHECK
+};
+
 /*
  * Use driver_data to set the number of pages supported by the chip.
  */
 static const struct i2c_device_id pmbus_id[] = {
        {"adp4000", (kernel_ulong_t)&pmbus_info_one},
+       {"bmr310", (kernel_ulong_t)&pmbus_info_one_status},
        {"bmr453", (kernel_ulong_t)&pmbus_info_one},
        {"bmr454", (kernel_ulong_t)&pmbus_info_one},
+       {"bmr456", (kernel_ulong_t)&pmbus_info_one},
+       {"bmr457", (kernel_ulong_t)&pmbus_info_one},
+       {"bmr458", (kernel_ulong_t)&pmbus_info_one_status},
+       {"bmr480", (kernel_ulong_t)&pmbus_info_one_status},
+       {"bmr490", (kernel_ulong_t)&pmbus_info_one_status},
+       {"bmr491", (kernel_ulong_t)&pmbus_info_one_status},
+       {"bmr492", (kernel_ulong_t)&pmbus_info_one},
        {"dps460", (kernel_ulong_t)&pmbus_info_one_skip},
        {"dps650ab", (kernel_ulong_t)&pmbus_info_one_skip},
        {"dps800", (kernel_ulong_t)&pmbus_info_one_skip},
index 3968924..e0aa8aa 100644 (file)
@@ -375,7 +375,7 @@ enum pmbus_sensor_classes {
 };
 
 #define PMBUS_PAGES    32      /* Per PMBus specification */
-#define PMBUS_PHASES         /* Maximum number of phases per page */
+#define PMBUS_PHASES   10      /* Maximum number of phases per page */
 
 /* Functionality bit mask */
 #define PMBUS_HAVE_VIN         BIT(0)
index bbd7451..776ee22 100644 (file)
@@ -523,6 +523,8 @@ static bool pmbus_check_register(struct i2c_client *client,
        rv = func(client, page, reg);
        if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
                rv = pmbus_check_status_cml(client);
+       if (rv < 0 && (data->flags & PMBUS_READ_STATUS_AFTER_FAILED_CHECK))
+               data->read_status(client, -1);
        pmbus_clear_fault_page(client, -1);
        return rv >= 0;
 }
@@ -1327,14 +1329,14 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client,
 
                pages = paged ? info->pages : 1;
                for (page = 0; page < pages; page++) {
-                       if (!(info->func[page] & attrs->func))
-                               continue;
-                       ret = pmbus_add_sensor_attrs_one(client, data, info,
-                                                        name, index, page,
-                                                        0xff, attrs, paged);
-                       if (ret)
-                               return ret;
-                       index++;
+                       if (info->func[page] & attrs->func) {
+                               ret = pmbus_add_sensor_attrs_one(client, data, info,
+                                                                name, index, page,
+                                                                0xff, attrs, paged);
+                               if (ret)
+                                       return ret;
+                               index++;
+                       }
                        if (info->phases[page]) {
                                int phase;
 
@@ -2140,6 +2142,111 @@ static int pmbus_find_attributes(struct i2c_client *client,
 }
 
 /*
+ * The pmbus_class_attr_map structure maps one sensor class to
+ * it's corresponding sensor attributes array.
+ */
+struct pmbus_class_attr_map {
+       enum pmbus_sensor_classes class;
+       int nattr;
+       const struct pmbus_sensor_attr *attr;
+};
+
+static const struct pmbus_class_attr_map class_attr_map[] = {
+       {
+               .class = PSC_VOLTAGE_IN,
+               .attr = voltage_attributes,
+               .nattr = ARRAY_SIZE(voltage_attributes),
+       }, {
+               .class = PSC_VOLTAGE_OUT,
+               .attr = voltage_attributes,
+               .nattr = ARRAY_SIZE(voltage_attributes),
+       }, {
+               .class = PSC_CURRENT_IN,
+               .attr = current_attributes,
+               .nattr = ARRAY_SIZE(current_attributes),
+       }, {
+               .class = PSC_CURRENT_OUT,
+               .attr = current_attributes,
+               .nattr = ARRAY_SIZE(current_attributes),
+       }, {
+               .class = PSC_POWER,
+               .attr = power_attributes,
+               .nattr = ARRAY_SIZE(power_attributes),
+       }, {
+               .class = PSC_TEMPERATURE,
+               .attr = temp_attributes,
+               .nattr = ARRAY_SIZE(temp_attributes),
+       }
+};
+
+/*
+ * Read the coefficients for direct mode.
+ */
+static int pmbus_read_coefficients(struct i2c_client *client,
+                                  struct pmbus_driver_info *info,
+                                  const struct pmbus_sensor_attr *attr)
+{
+       int rv;
+       union i2c_smbus_data data;
+       enum pmbus_sensor_classes class = attr->class;
+       s8 R;
+       s16 m, b;
+
+       data.block[0] = 2;
+       data.block[1] = attr->reg;
+       data.block[2] = 0x01;
+
+       rv = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+                           I2C_SMBUS_WRITE, PMBUS_COEFFICIENTS,
+                           I2C_SMBUS_BLOCK_PROC_CALL, &data);
+
+       if (rv < 0)
+               return rv;
+
+       if (data.block[0] != 5)
+               return -EIO;
+
+       m = data.block[1] | (data.block[2] << 8);
+       b = data.block[3] | (data.block[4] << 8);
+       R = data.block[5];
+       info->m[class] = m;
+       info->b[class] = b;
+       info->R[class] = R;
+
+       return rv;
+}
+
+static int pmbus_init_coefficients(struct i2c_client *client,
+                                  struct pmbus_driver_info *info)
+{
+       int i, n, ret = -EINVAL;
+       const struct pmbus_class_attr_map *map;
+       const struct pmbus_sensor_attr *attr;
+
+       for (i = 0; i < ARRAY_SIZE(class_attr_map); i++) {
+               map = &class_attr_map[i];
+               if (info->format[map->class] != direct)
+                       continue;
+               for (n = 0; n < map->nattr; n++) {
+                       attr = &map->attr[n];
+                       if (map->class != attr->class)
+                               continue;
+                       ret = pmbus_read_coefficients(client, info, attr);
+                       if (ret >= 0)
+                               break;
+               }
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "No coefficients found for sensor class %d\n",
+                               map->class);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/*
  * Identify chip parameters.
  * This function is called for all chips.
  */
@@ -2214,11 +2321,14 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
                data->has_status_word = true;
        }
 
-       /* Enable PEC if the controller supports it */
+       /* Enable PEC if the controller and bus supports it */
        if (!(data->flags & PMBUS_NO_CAPABILITY)) {
                ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
-               if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
-                       client->flags |= I2C_CLIENT_PEC;
+               if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) {
+                       if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) {
+                               client->flags |= I2C_CLIENT_PEC;
+                       }
+               }
        }
 
        /*
@@ -2226,9 +2336,11 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
         * faults, and we should not try it. Also, in that case, writes into
         * limit registers need to be disabled.
         */
-       ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
-       if (ret > 0 && (ret & PB_WP_ANY))
-               data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
+       if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) {
+               ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
+               if (ret > 0 && (ret & PB_WP_ANY))
+                       data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
+       }
 
        if (data->info->pages)
                pmbus_clear_faults(client);
@@ -2255,6 +2367,17 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
                        return ret;
                }
        }
+
+       if (data->flags & PMBUS_USE_COEFFICIENTS_CMD) {
+               if (!i2c_check_functionality(client->adapter,
+                                            I2C_FUNC_SMBUS_BLOCK_PROC_CALL))
+                       return -ENODEV;
+
+               ret = pmbus_init_coefficients(client, info);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
index b7d4eac..e9df0c5 100644 (file)
@@ -18,7 +18,7 @@
 #include "pmbus.h"
 
 enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
-            zl9101, zl9117 };
+            zl8802, zl9101, zl9117, zls1003, zls4009 };
 
 struct zl6100_data {
        int id;
@@ -34,6 +34,13 @@ struct zl6100_data {
 
 #define ZL6100_MFR_XTEMP_ENABLE                BIT(7)
 
+#define ZL8802_MFR_USER_GLOBAL_CONFIG  0xe9
+#define ZL8802_MFR_TMON_ENABLE         BIT(12)
+#define ZL8802_MFR_USER_CONFIG         0xd1
+#define ZL8802_MFR_XTEMP_ENABLE_2      BIT(1)
+#define ZL8802_MFR_DDC_CONFIG          0xd3
+#define ZL8802_MFR_PHASES_MASK         0x0007
+
 #define MFR_VMON_OV_FAULT_LIMIT                0xf5
 #define MFR_VMON_UV_FAULT_LIMIT                0xf6
 #define MFR_READ_VMON                  0xf7
@@ -132,7 +139,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page,
        struct zl6100_data *data = to_zl6100_data(info);
        int ret, vreg;
 
-       if (page > 0)
+       if (page >= info->pages)
                return -ENXIO;
 
        if (data->id == zl2005) {
@@ -191,7 +198,7 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
        struct zl6100_data *data = to_zl6100_data(info);
        int ret, status;
 
-       if (page > 0)
+       if (page >= info->pages)
                return -ENXIO;
 
        zl6100_wait(data);
@@ -230,7 +237,7 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
        struct zl6100_data *data = to_zl6100_data(info);
        int ret, vreg;
 
-       if (page > 0)
+       if (page >= info->pages)
                return -ENXIO;
 
        switch (reg) {
@@ -271,7 +278,7 @@ static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
        struct zl6100_data *data = to_zl6100_data(info);
        int ret;
 
-       if (page > 0)
+       if (page >= info->pages)
                return -ENXIO;
 
        zl6100_wait(data);
@@ -287,6 +294,10 @@ static const struct i2c_device_id zl6100_id[] = {
        {"bmr462", zl2008},
        {"bmr463", zl2008},
        {"bmr464", zl2008},
+       {"bmr465", zls4009},
+       {"bmr466", zls1003},
+       {"bmr467", zls4009},
+       {"bmr469", zl8802},
        {"zl2004", zl2004},
        {"zl2005", zl2005},
        {"zl2006", zl2006},
@@ -295,15 +306,18 @@ static const struct i2c_device_id zl6100_id[] = {
        {"zl2106", zl2106},
        {"zl6100", zl6100},
        {"zl6105", zl6105},
+       {"zl8802", zl8802},
        {"zl9101", zl9101},
        {"zl9117", zl9117},
+       {"zls1003", zls1003},
+       {"zls4009", zls4009},
        { }
 };
 MODULE_DEVICE_TABLE(i2c, zl6100_id);
 
 static int zl6100_probe(struct i2c_client *client)
 {
-       int ret;
+       int ret, i;
        struct zl6100_data *data;
        struct pmbus_driver_info *info;
        u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
@@ -367,18 +381,70 @@ static int zl6100_probe(struct i2c_client *client)
          | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
        /*
-        * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
-        * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+        * ZL2004, ZL8802, ZL9101M, ZL9117M and ZLS4009 support monitoring
+        * an extra voltage (VMON for ZL2004, ZL8802 and ZLS4009,
+        * VDRV for ZL9101M and ZL9117M). Report it as vmon.
         */
-       if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+       if (data->id == zl2004 || data->id == zl8802 || data->id == zl9101 ||
+           data->id == zl9117 || data->id == zls4009)
                info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
 
-       ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
-       if (ret < 0)
-               return ret;
+       /*
+        * ZL8802 has two outputs that can be used either independently or in
+        * a current sharing configuration. The driver uses the DDC_CONFIG
+        * register to check if the module is running with independent or
+        * shared outputs. If the module is in shared output mode, only one
+        * output voltage will be reported.
+        */
+       if (data->id == zl8802) {
+               info->pages = 2;
+               info->func[0] |= PMBUS_HAVE_IIN;
+
+               ret = i2c_smbus_read_word_data(client, ZL8802_MFR_DDC_CONFIG);
+               if (ret < 0)
+                       return ret;
+
+               data->access = ktime_get();
+               zl6100_wait(data);
+
+               if (ret & ZL8802_MFR_PHASES_MASK)
+                       info->func[1] |= PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+               else
+                       info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                               | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
 
-       if (ret & ZL6100_MFR_XTEMP_ENABLE)
-               info->func[0] |= PMBUS_HAVE_TEMP2;
+               for (i = 0; i < 2; i++) {
+                       ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+                       if (ret < 0)
+                               return ret;
+
+                       data->access = ktime_get();
+                       zl6100_wait(data);
+
+                       ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_CONFIG);
+                       if (ret < 0)
+                               return ret;
+
+                       if (ret & ZL8802_MFR_XTEMP_ENABLE_2)
+                               info->func[i] |= PMBUS_HAVE_TEMP2;
+
+                       data->access = ktime_get();
+                       zl6100_wait(data);
+               }
+               ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_GLOBAL_CONFIG);
+               if (ret < 0)
+                       return ret;
+
+               if (ret & ZL8802_MFR_TMON_ENABLE)
+                       info->func[0] |= PMBUS_HAVE_TEMP3;
+       } else {
+               ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
+               if (ret < 0)
+                       return ret;
+
+               if (ret & ZL6100_MFR_XTEMP_ENABLE)
+                       info->func[0] |= PMBUS_HAVE_TEMP2;
+       }
 
        data->access = ktime_get();
        zl6100_wait(data);
index 4324a5d..8f1b569 100644 (file)
@@ -64,7 +64,6 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
 
 struct sch5627_data {
        unsigned short addr;
-       struct sch56xx_watchdog_data *watchdog;
        u8 control;
        u8 temp_max[SCH5627_NO_TEMPS];
        u8 temp_crit[SCH5627_NO_TEMPS];
@@ -357,16 +356,6 @@ static const struct hwmon_chip_info sch5627_chip_info = {
        .info = sch5627_info,
 };
 
-static int sch5627_remove(struct platform_device *pdev)
-{
-       struct sch5627_data *data = platform_get_drvdata(pdev);
-
-       if (data->watchdog)
-               sch56xx_watchdog_unregister(data->watchdog);
-
-       return 0;
-}
-
 static int sch5627_probe(struct platform_device *pdev)
 {
        struct sch5627_data *data;
@@ -460,9 +449,9 @@ static int sch5627_probe(struct platform_device *pdev)
                return PTR_ERR(hwmon_dev);
 
        /* Note failing to register the watchdog is not a fatal error */
-       data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
-                       (build_code << 24) | (build_id << 8) | hwmon_rev,
-                       &data->update_lock, 1);
+       sch56xx_watchdog_register(&pdev->dev, data->addr,
+                                 (build_code << 24) | (build_id << 8) | hwmon_rev,
+                                 &data->update_lock, 1);
 
        return 0;
 }
@@ -472,7 +461,6 @@ static struct platform_driver sch5627_driver = {
                .name   = DRVNAME,
        },
        .probe          = sch5627_probe,
-       .remove         = sch5627_remove,
 };
 
 module_platform_driver(sch5627_driver);
index 5683a38..a5cd4de 100644 (file)
@@ -54,7 +54,6 @@ static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = {
 struct sch5636_data {
        unsigned short addr;
        struct device *hwmon_dev;
-       struct sch56xx_watchdog_data *watchdog;
 
        struct mutex update_lock;
        char valid;                     /* !=0 if following fields are valid */
@@ -372,9 +371,6 @@ static int sch5636_remove(struct platform_device *pdev)
        struct sch5636_data *data = platform_get_drvdata(pdev);
        int i;
 
-       if (data->watchdog)
-               sch56xx_watchdog_unregister(data->watchdog);
-
        if (data->hwmon_dev)
                hwmon_device_unregister(data->hwmon_dev);
 
@@ -495,9 +491,8 @@ static int sch5636_probe(struct platform_device *pdev)
        }
 
        /* Note failing to register the watchdog is not a fatal error */
-       data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
-                                       (revision[0] << 8) | revision[1],
-                                       &data->update_lock, 0);
+       sch56xx_watchdog_register(&pdev->dev, data->addr, (revision[0] << 8) | revision[1],
+                                 &data->update_lock, 0);
 
        return 0;
 
index 6c84780..40cdada 100644 (file)
@@ -20,8 +20,8 @@
 #include "sch56xx-common.h"
 
 /* Insmod parameters */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -378,8 +378,8 @@ static const struct watchdog_ops watchdog_ops = {
        .set_timeout    = watchdog_set_timeout,
 };
 
-struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
-       u16 addr, u32 revision, struct mutex *io_lock, int check_enabled)
+void sch56xx_watchdog_register(struct device *parent, u16 addr, u32 revision,
+                              struct mutex *io_lock, int check_enabled)
 {
        struct sch56xx_watchdog_data *data;
        int err, control, output_enable;
@@ -393,23 +393,22 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
        mutex_unlock(io_lock);
 
        if (control < 0)
-               return NULL;
+               return;
        if (output_enable < 0)
-               return NULL;
+               return;
        if (check_enabled && !(output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) {
                pr_warn("Watchdog not enabled by BIOS, not registering\n");
-               return NULL;
+               return;
        }
 
-       data = kzalloc(sizeof(struct sch56xx_watchdog_data), GFP_KERNEL);
+       data = devm_kzalloc(parent, sizeof(struct sch56xx_watchdog_data), GFP_KERNEL);
        if (!data)
-               return NULL;
+               return;
 
        data->addr = addr;
        data->io_lock = io_lock;
 
-       strlcpy(data->wdinfo.identity, "sch56xx watchdog",
-               sizeof(data->wdinfo.identity));
+       strscpy(data->wdinfo.identity, "sch56xx watchdog", sizeof(data->wdinfo.identity));
        data->wdinfo.firmware_version = revision;
        data->wdinfo.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT;
        if (!nowayout)
@@ -421,8 +420,7 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
        data->wddev.timeout = 60;
        data->wddev.min_timeout = 1;
        data->wddev.max_timeout = 255 * 60;
-       if (nowayout)
-               set_bit(WDOG_NO_WAY_OUT, &data->wddev.status);
+       watchdog_set_nowayout(&data->wddev, nowayout);
        if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)
                set_bit(WDOG_ACTIVE, &data->wddev.status);
 
@@ -438,24 +436,14 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
        data->watchdog_output_enable = output_enable;
 
        watchdog_set_drvdata(&data->wddev, data);
-       err = watchdog_register_device(&data->wddev);
+       err = devm_watchdog_register_device(parent, &data->wddev);
        if (err) {
                pr_err("Registering watchdog chardev: %d\n", err);
-               kfree(data);
-               return NULL;
+               devm_kfree(parent, data);
        }
-
-       return data;
 }
 EXPORT_SYMBOL(sch56xx_watchdog_register);
 
-void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
-{
-       watchdog_unregister_device(&data->wddev);
-       kfree(data);
-}
-EXPORT_SYMBOL(sch56xx_watchdog_unregister);
-
 /*
  * platform dev find, add and remove functions
  */
@@ -516,37 +504,18 @@ static int __init sch56xx_device_add(int address, const char *name)
        struct resource res = {
                .start  = address,
                .end    = address + REGION_LENGTH - 1,
+               .name   = name,
                .flags  = IORESOURCE_IO,
        };
        int err;
 
-       sch56xx_pdev = platform_device_alloc(name, address);
-       if (!sch56xx_pdev)
-               return -ENOMEM;
-
-       res.name = sch56xx_pdev->name;
        err = acpi_check_resource_conflict(&res);
        if (err)
-               goto exit_device_put;
-
-       err = platform_device_add_resources(sch56xx_pdev, &res, 1);
-       if (err) {
-               pr_err("Device resource addition failed\n");
-               goto exit_device_put;
-       }
-
-       err = platform_device_add(sch56xx_pdev);
-       if (err) {
-               pr_err("Device addition failed\n");
-               goto exit_device_put;
-       }
-
-       return 0;
+               return err;
 
-exit_device_put:
-       platform_device_put(sch56xx_pdev);
+       sch56xx_pdev = platform_device_register_simple(name, -1, &res, 1);
 
-       return err;
+       return PTR_ERR_OR_ZERO(sch56xx_pdev);
 }
 
 static int __init sch56xx_init(void)
index 75eb736..e907d9d 100644 (file)
@@ -14,6 +14,6 @@ int sch56xx_read_virtual_reg16(u16 addr, u16 reg);
 int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
                               int high_nibble);
 
-struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
-       u16 addr, u32 revision, struct mutex *io_lock, int check_enabled);
+void sch56xx_watchdog_register(struct device *parent, u16 addr, u32 revision,
+                              struct mutex *io_lock, int check_enabled);
 void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data);
diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c
new file mode 100644 (file)
index 0000000..09c2a0b
--- /dev/null
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) Linumiz 2021
+ *
+ * sht4x.c - Linux hwmon driver for SHT4x Temperature and Humidity sensor
+ *
+ * Author: Navin Sankar Velliangiri <navin@linumiz.com>
+ */
+
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+
+/*
+ * Poll intervals (in milliseconds)
+ */
+#define SHT4X_MIN_POLL_INTERVAL        2000
+
+/*
+ * I2C command delays (in microseconds)
+ */
+#define SHT4X_MEAS_DELAY       1000
+#define SHT4X_DELAY_EXTRA      10000
+
+/*
+ * Command Bytes
+ */
+#define SHT4X_CMD_MEASURE_HPM  0b11111101
+#define SHT4X_CMD_RESET                0b10010100
+
+#define SHT4X_CMD_LEN          1
+#define SHT4X_CRC8_LEN         1
+#define SHT4X_WORD_LEN         2
+#define SHT4X_RESPONSE_LENGTH  6
+#define SHT4X_CRC8_POLYNOMIAL  0x31
+#define SHT4X_CRC8_INIT                0xff
+#define SHT4X_MIN_TEMPERATURE  -45000
+#define SHT4X_MAX_TEMPERATURE  125000
+#define SHT4X_MIN_HUMIDITY     0
+#define SHT4X_MAX_HUMIDITY     100000
+
+DECLARE_CRC8_TABLE(sht4x_crc8_table);
+
+/**
+ * struct sht4x_data - All the data required to operate an SHT4X chip
+ * @client: the i2c client associated with the SHT4X
+ * @lock: a mutex that is used to prevent parallel access to the i2c client
+ * @update_interval: the minimum poll interval
+ * @last_updated: the previous time that the SHT4X was polled
+ * @temperature: the latest temperature value received from the SHT4X
+ * @humidity: the latest humidity value received from the SHT4X
+ */
+struct sht4x_data {
+       struct i2c_client       *client;
+       struct mutex            lock;   /* atomic read data updates */
+       bool                    valid;  /* validity of fields below */
+       long                    update_interval;        /* in milli-seconds */
+       long                    last_updated;   /* in jiffies */
+       s32                     temperature;
+       s32                     humidity;
+};
+
+/**
+ * sht4x_read_values() - read and parse the raw data from the SHT4X
+ * @sht4x_data: the struct sht4x_data to use for the lock
+ * Return: 0 if successful, -ERRNO if not
+ */
+static int sht4x_read_values(struct sht4x_data *data)
+{
+       int ret = 0;
+       u16 t_ticks, rh_ticks;
+       unsigned long next_update;
+       struct i2c_client *client = data->client;
+       u8 crc;
+       u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM};
+       u8 raw_data[SHT4X_RESPONSE_LENGTH];
+
+       mutex_lock(&data->lock);
+       next_update = data->last_updated +
+                     msecs_to_jiffies(data->update_interval);
+
+       if (data->valid && time_before_eq(jiffies, next_update))
+               goto unlock;
+
+       ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
+       if (ret < 0)
+               goto unlock;
+
+       usleep_range(SHT4X_MEAS_DELAY, SHT4X_MEAS_DELAY + SHT4X_DELAY_EXTRA);
+
+       ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH);
+       if (ret != SHT4X_RESPONSE_LENGTH) {
+               if (ret >= 0)
+                       ret = -ENODATA;
+               goto unlock;
+       }
+
+       t_ticks = raw_data[0] << 8 | raw_data[1];
+       rh_ticks = raw_data[3] << 8 | raw_data[4];
+
+       crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
+       if (crc != raw_data[2]) {
+               dev_err(&client->dev, "data integrity check failed\n");
+               ret = -EIO;
+               goto unlock;
+       }
+
+       crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
+       if (crc != raw_data[5]) {
+               dev_err(&client->dev, "data integrity check failed\n");
+               ret = -EIO;
+               goto unlock;
+       }
+
+       data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000;
+       data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000;
+       data->last_updated = jiffies;
+       data->valid = true;
+       ret = 0;
+
+unlock:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static ssize_t sht4x_interval_write(struct sht4x_data *data, long val)
+{
+       data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, UINT_MAX);
+
+       return 0;
+}
+
+/* sht4x_interval_read() - read the minimum poll interval in milliseconds */
+static size_t sht4x_interval_read(struct sht4x_data *data, long *val)
+{
+       *val = data->update_interval;
+       return 0;
+}
+
+/* sht4x_temperature1_read() - read the temperature in millidegrees */
+static int sht4x_temperature1_read(struct sht4x_data *data, long *val)
+{
+       int ret;
+
+       ret = sht4x_read_values(data);
+       if (ret < 0)
+               return ret;
+
+       *val = data->temperature;
+
+       return 0;
+}
+
+/* sht4x_humidity1_read() - read a relative humidity in millipercent */
+static int sht4x_humidity1_read(struct sht4x_data *data, long *val)
+{
+       int ret;
+
+       ret = sht4x_read_values(data);
+       if (ret < 0)
+               return ret;
+
+       *val = data->humidity;
+
+       return 0;
+}
+
+static umode_t sht4x_hwmon_visible(const void *data,
+                                  enum hwmon_sensor_types type,
+                                  u32 attr, int channel)
+{
+       switch (type) {
+       case hwmon_temp:
+       case hwmon_humidity:
+               return 0444;
+       case hwmon_chip:
+               return 0644;
+       default:
+               return 0;
+       }
+}
+
+static int sht4x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+                           u32 attr, int channel, long *val)
+{
+       struct sht4x_data *data = dev_get_drvdata(dev);
+
+       switch (type) {
+       case hwmon_temp:
+               return sht4x_temperature1_read(data, val);
+       case hwmon_humidity:
+               return sht4x_humidity1_read(data, val);
+       case hwmon_chip:
+               return sht4x_interval_read(data, val);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+                            u32 attr, int channel, long val)
+{
+       struct sht4x_data *data = dev_get_drvdata(dev);
+
+       switch (type) {
+       case hwmon_chip:
+               return sht4x_interval_write(data, val);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static const struct hwmon_channel_info *sht4x_info[] = {
+       HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
+       HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+       HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
+       NULL,
+};
+
+static const struct hwmon_ops sht4x_hwmon_ops = {
+       .is_visible = sht4x_hwmon_visible,
+       .read = sht4x_hwmon_read,
+       .write = sht4x_hwmon_write,
+};
+
+static const struct hwmon_chip_info sht4x_chip_info = {
+       .ops = &sht4x_hwmon_ops,
+       .info = sht4x_info,
+};
+
+static int sht4x_probe(struct i2c_client *client,
+                      const struct i2c_device_id *sht4x_id)
+{
+       struct device *device = &client->dev;
+       struct device *hwmon_dev;
+       struct sht4x_data *data;
+       u8 cmd[] = {SHT4X_CMD_RESET};
+       int ret;
+
+       /*
+        * we require full i2c support since the sht4x uses multi-byte read and
+        * writes as well as multi-byte commands which are not supported by
+        * the smbus protocol
+        */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -EOPNOTSUPP;
+
+       data = devm_kzalloc(device, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->update_interval = SHT4X_MIN_POLL_INTERVAL;
+       data->client = client;
+
+       mutex_init(&data->lock);
+
+       crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL);
+
+       ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
+       if (ret < 0)
+               return ret;
+       if (ret != SHT4X_CMD_LEN)
+               return -EIO;
+
+       hwmon_dev = devm_hwmon_device_register_with_info(device,
+                                                        client->name,
+                                                        data,
+                                                        &sht4x_chip_info,
+                                                        NULL);
+
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id sht4x_id[] = {
+       { "sht4x", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, sht4x_id);
+
+static struct i2c_driver sht4x_driver = {
+       .driver = {
+               .name = "sht4x",
+       },
+       .probe          = sht4x_probe,
+       .id_table       = sht4x_id,
+};
+
+module_i2c_driver(sht4x_driver);
+
+MODULE_AUTHOR("Navin Sankar Velliangiri <navin@linumiz.com>");
+MODULE_DESCRIPTION("Sensirion SHT4x humidity and temperature sensor driver");
+MODULE_LICENSE("GPL v2");
index 78cfecd..3ded286 100644 (file)
@@ -138,17 +138,23 @@ cp2615_i2c_send(struct usb_interface *usbif, struct cp2615_i2c_transfer *i2c_w)
 static int
 cp2615_i2c_recv(struct usb_interface *usbif, unsigned char tag, void *buf)
 {
-       struct cp2615_iop_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
-       struct cp2615_i2c_transfer_result *i2c_r = (struct cp2615_i2c_transfer_result *)&msg->data;
        struct usb_device *usbdev = interface_to_usbdev(usbif);
-       int res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN),
-                              msg, sizeof(struct cp2615_iop_msg), NULL, 0);
+       struct cp2615_iop_msg *msg;
+       struct cp2615_i2c_transfer_result *i2c_r;
+       int res;
+
+       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
 
+       res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN), msg,
+                          sizeof(struct cp2615_iop_msg), NULL, 0);
        if (res < 0) {
                kfree(msg);
                return res;
        }
 
+       i2c_r = (struct cp2615_i2c_transfer_result *)&msg->data;
        if (msg->msg != htons(iop_I2cTransferResult) || i2c_r->tag != tag) {
                kfree(msg);
                return -EIO;
index f9e1c2c..04a1e38 100644 (file)
@@ -978,6 +978,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
        }
 
 out:
+       /* Unlock the SMBus device for use by BIOS/ACPI */
+       outb_p(SMBHSTSTS_INUSE_STS, SMBHSTSTS(priv));
+
        pm_runtime_mark_last_busy(&priv->pci_dev->dev);
        pm_runtime_put_autosuspend(&priv->pci_dev->dev);
        mutex_unlock(&priv->acpi_lock);
index a39f7d0..66dfa21 100644 (file)
@@ -83,7 +83,7 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                        }
                }
 
-               ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
+               ret = osif_usb_write(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
                if (ret) {
                        dev_err(&adapter->dev, "failure sending STOP\n");
                        return -EREMOTEIO;
@@ -153,7 +153,7 @@ static int osif_probe(struct usb_interface *interface,
         * Set bus frequency. The frequency is:
         * 120,000,000 / ( 16 + 2 * div * 4^prescale).
         * Using dev = 52, prescale = 0 give 100KHz */
-       ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
+       ret = osif_usb_write(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
                            NULL, 0);
        if (ret) {
                dev_err(&interface->dev, "failure sending bit rate");
index 6ef38a8..cb64fe6 100644 (file)
@@ -526,7 +526,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo
                return put_user(funcs, (compat_ulong_t __user *)arg);
        case I2C_RDWR: {
                struct i2c_rdwr_ioctl_data32 rdwr_arg;
-               struct i2c_msg32 *p;
+               struct i2c_msg32 __user *p;
                struct i2c_msg *rdwr_pa;
                int i;
 
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
deleted file mode 100644 (file)
index 19abf11..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# IDE ATA ATAPI Block device driver configuration
-#
-
-# Select HAVE_IDE if IDE is supported
-config HAVE_IDE
-       bool
-
-menuconfig IDE
-       tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)"
-       depends on HAVE_IDE
-       depends on BLOCK
-       select BLK_SCSI_REQUEST
-       help
-         If you say Y here, your kernel will be able to manage ATA/(E)IDE and
-         ATAPI units. The most common cases are IDE hard drives and ATAPI
-         CD-ROM drives.
-
-         This subsystem is currently in maintenance mode with only bug fix
-         changes applied. Users of ATA hardware are encouraged to migrate to
-         the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA
-         (experimental) drivers") which is more actively maintained.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ide-core.
-
-         For further information, please read <file:Documentation/ide/ide.rst>.
-
-         If unsure, say N.
-
-if IDE
-
-comment "Please see Documentation/ide/ide.rst for help/info on IDE drives"
-
-config IDE_XFER_MODE
-       bool
-
-config IDE_TIMINGS
-       bool
-       select IDE_XFER_MODE
-
-config IDE_ATAPI
-       bool
-
-config IDE_LEGACY
-       bool
-
-config BLK_DEV_IDE_SATA
-       bool "Support for SATA (deprecated; conflicts with libata SATA driver)"
-       default n
-       help
-         There are two drivers for Serial ATA controllers.
-
-         The main driver, "libata", uses the SCSI subsystem
-         and supports most modern SATA controllers. In order to use it
-         you may take a look at "Serial ATA (prod) and Parallel ATA
-         (experimental) drivers".
-
-         The IDE driver (which you are currently configuring) supports
-         a few first-generation SATA controllers.
-
-         In order to eliminate conflicts between the two subsystems,
-         this config option enables the IDE driver's SATA support.
-         Normally this is disabled, as it is preferred that libata
-         supports SATA controllers, and this (IDE) driver supports
-         PATA controllers.
-
-         If unsure, say N.
-
-config IDE_GD
-       tristate "generic ATA/ATAPI disk support"
-       default y
-       help
-         Support for ATA/ATAPI disks (including ATAPI floppy drives).
-
-         To compile this driver as a module, choose M here.
-         The module will be called ide-gd_mod.
-
-         If unsure, say Y.
-
-config IDE_GD_ATA
-       bool "ATA disk support"
-       depends on IDE_GD
-       default y
-       help
-         This will include support for ATA hard disks.
-
-         If unsure, say Y.
-
-config IDE_GD_ATAPI
-       bool "ATAPI floppy support"
-       depends on IDE_GD
-       select IDE_ATAPI
-       help
-         This will include support for ATAPI floppy drives
-         (i.e. Iomega ZIP or MKE LS-120).
-
-         For information about jumper settings and the question
-         of when a ZIP drive uses a partition table, see
-         <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
-
-         If unsure, say N.
-
-config BLK_DEV_IDECS
-       tristate "PCMCIA IDE support"
-       depends on PCMCIA
-       help
-         Support for Compact Flash cards, outboard IDE disks, tape drives,
-         and CD-ROM drives connected through a PCMCIA card.
-
-config BLK_DEV_DELKIN
-       tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
-       depends on CARDBUS && PCI
-       help
-         Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
-         Adapters.  This may also work for similar SD and XD adapters.
-
-config BLK_DEV_IDECD
-       tristate "Include IDE/ATAPI CDROM support"
-       depends on BLK_DEV
-       select IDE_ATAPI
-       select CDROM
-       help
-         If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
-         a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
-         SCSI protocol. Most new CD-ROM drives use ATAPI, including the
-         NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
-         double(2X) or better speed drives.
-
-         If you say Y here, the CD-ROM drive will be identified at boot time
-         along with other IDE devices, as "hdb" or "hdc", or something
-         similar (check the boot messages with dmesg). If this is your only
-         CD-ROM drive, you can say N to all other CD-ROM options, but be sure
-         to say Y or M to "ISO 9660 CD-ROM file system support".
-
-         To compile this driver as a module, choose M here: the
-         module will be called ide-cd.
-
-config BLK_DEV_IDECD_VERBOSE_ERRORS
-       bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT
-       depends on BLK_DEV_IDECD
-       default y
-       help
-         Turn this on to have the driver print out the meanings of the
-         ATAPI error codes.  This will use up additional 8kB of kernel-space
-         memory, though.
-
-config BLK_DEV_IDETAPE
-       tristate "Include IDE/ATAPI TAPE support"
-       select IDE_ATAPI
-       help
-         If you have an IDE tape drive using the ATAPI protocol, say Y.
-         ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
-         similar to the SCSI protocol.  If you have an SCSI tape drive
-         however, you can say N here.
-
-         You should also say Y if you have an OnStream DI-30 tape drive; this
-         will not work with the SCSI protocol, until there is support for the
-         SC-30 and SC-50 versions.
-
-         If you say Y here, the tape drive will be identified at boot time
-         along with other IDE devices, as "hdb" or "hdc", or something
-         similar, and will be mapped to a character device such as "ht0"
-         (check the boot messages with dmesg).  Be sure to consult the
-         <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.rst>
-         files for usage information.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ide-tape.
-
-config BLK_DEV_IDEACPI
-       bool "IDE ACPI support"
-       depends on ACPI
-       help
-         Implement ACPI support for generic IDE devices. On modern
-         machines ACPI support is required to properly handle ACPI S3 states.
-
-config IDE_TASK_IOCTL
-       bool "IDE Taskfile Access"
-       help
-         This is a direct raw access to the media.  It is a complex but
-         elegant solution to test and validate the domain of the hardware and
-         perform below the driver data recovery if needed.  This is the most
-         basic form of media-forensics.
-
-         If you are unsure, say N here.
-
-config IDE_PROC_FS
-       bool "legacy /proc/ide/ support"
-       depends on IDE && PROC_FS
-       default y
-       help
-         This option enables support for the various files in
-         /proc/ide.  In Linux 2.6 this has been superseded by
-         files in sysfs but many legacy applications rely on this.
-
-         If unsure say Y.
-
-comment "IDE chipset support/bugfixes"
-
-config IDE_GENERIC
-       tristate "generic/default IDE chipset support"
-       depends on ALPHA || X86 || IA64 || MIPS || ARCH_RPC
-       default ARM && ARCH_RPC
-       help
-         This is the generic IDE driver.  This driver attaches to the
-         fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
-         so on).  Please note that if this driver is built into the
-         kernel or loaded before other ATA (IDE or libata) drivers
-         and the controller is located at legacy ports, this driver
-         may grab those ports and thus can prevent the controller
-         specific driver from attaching.
-
-         Also, currently, IDE generic doesn't allow IRQ sharing
-         meaning that the IRQs it grabs won't be available to other
-         controllers sharing those IRQs which usually makes drivers
-         for those controllers fail.  Generally, it's not a good idea
-         to load IDE generic driver on modern systems.
-
-         If unsure, say N.
-
-config BLK_DEV_PLATFORM
-       tristate "Platform driver for IDE interfaces"
-       help
-         This is the platform IDE driver, used mostly for Memory Mapped
-         IDE devices, like Compact Flashes running in True IDE mode.
-
-         If unsure, say N.
-
-config BLK_DEV_CMD640
-       tristate "CMD640 chipset bugfix/support"
-       depends on X86
-       select IDE_TIMINGS
-       help
-         The CMD-Technologies CMD640 IDE chip is used on many common 486 and
-         Pentium motherboards, usually in combination with a "Neptune" or
-         "SiS" chipset. Unfortunately, it has a number of rather nasty
-         design flaws that can cause severe data corruption under many common
-         conditions. Say Y here to include code which tries to automatically
-         detect and correct the problems under Linux. This option also
-         enables access to the secondary IDE ports in some CMD640 based
-         systems.
-
-         This driver will work automatically in PCI based systems (most new
-         systems have PCI slots). But if your system uses VESA local bus
-         (VLB) instead of PCI, you must also supply a kernel boot parameter
-         to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man
-         bootparam" or see the documentation of your boot loader about how to
-         pass options to the kernel.)
-
-         The CMD640 chip is also used on add-in cards by Acculogic, and on
-         the "CSA-6400E PCI to IDE controller" that some people have. For
-         details, read <file:Documentation/ide/ide.rst>.
-
-config BLK_DEV_CMD640_ENHANCED
-       bool "CMD640 enhanced support"
-       depends on BLK_DEV_CMD640
-       help
-         This option includes support for setting/autotuning PIO modes and
-         prefetch on CMD640 IDE interfaces.  For details, read
-         <file:Documentation/ide/ide.rst>. If you have a CMD640 IDE interface
-         and your BIOS does not already do this for you, then say Y here.
-         Otherwise say N.
-
-config BLK_DEV_IDEPNP
-       tristate "PNP EIDE support"
-       depends on PNP
-       help
-         If you have a PnP (Plug and Play) compatible EIDE card and
-         would like the kernel to automatically detect and activate
-         it, say Y here.
-
-config BLK_DEV_IDEDMA_SFF
-       bool
-
-if PCI
-
-comment "PCI IDE chipsets support"
-
-config BLK_DEV_IDEPCI
-       bool
-
-config IDEPCI_PCIBUS_ORDER
-       bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
-       depends on IDE=y && BLK_DEV_IDEPCI
-       default y
-       help
-         Probe IDE PCI devices in the order in which they appear on the
-         PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
-         instead of the order in which IDE PCI host drivers are loaded.
-
-         Please note that this method of assuring stable naming of
-         IDE devices is unreliable and use other means for achieving
-         it (i.e. udev).
-
-         If in doubt, say N.
-
-# TODO: split it on per host driver config options (or module parameters)
-config BLK_DEV_OFFBOARD
-       bool "Boot off-board chipsets first support (DEPRECATED)"
-       depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
-       help
-         Normally, IDE controllers built into the motherboard (on-board
-         controllers) are assigned to ide0 and ide1 while those on add-in PCI
-         cards (off-board controllers) are relegated to ide2 and ide3.
-         Answering Y here will allow you to reverse the situation, with
-         off-board controllers on ide0/1 and on-board controllers on ide2/3.
-         This can improve the usability of some boot managers such as lilo
-         when booting from a drive on an off-board controller.
-
-         Note that, if you do this, the order of the hd* devices will be
-         rearranged which may require modification of fstab and other files.
-
-         Please also note that this method of assuring stable naming of
-         IDE devices is unreliable and use other means for achieving it
-         (i.e. udev).
-
-         If in doubt, say N.
-
-config BLK_DEV_GENERIC
-       tristate "Generic PCI IDE Chipset Support"
-       select BLK_DEV_IDEPCI
-       help
-         This option provides generic support for various PCI IDE Chipsets
-         which otherwise might not be supported.
-
-config BLK_DEV_OPTI621
-       tristate "OPTi 82C621 chipset enhanced support"
-       select BLK_DEV_IDEPCI
-       help
-         This is a driver for the OPTi 82C621 EIDE controller.
-         Please read the comments at the top of <file:drivers/ide/opti621.c>.
-
-config BLK_DEV_RZ1000
-       tristate "RZ1000 chipset bugfix/support"
-       depends on X86
-       select BLK_DEV_IDEPCI
-       help
-         The PC-Technologies RZ1000 IDE chip is used on many common 486 and
-         Pentium motherboards, usually along with the "Neptune" chipset.
-         Unfortunately, it has a rather nasty design flaw that can cause
-         severe data corruption under many conditions. Say Y here to include
-         code which automatically detects and corrects the problem under
-         Linux. This may slow disk throughput by a few percent, but at least
-         things will operate 100% reliably.
-
-config BLK_DEV_IDEDMA_PCI
-       bool
-       select BLK_DEV_IDEPCI
-       select BLK_DEV_IDEDMA_SFF
-
-config BLK_DEV_AEC62XX
-       tristate "AEC62XX chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
-         IDE controllers. This allows the kernel to change PIO, DMA and UDMA
-         speeds and to configure the chip to optimum performance.
-
-config BLK_DEV_ALI15X3
-       tristate "ALI M15x3 chipset support"
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
-         onboard chipsets.  It also tests for Simplex mode and enables
-         normal dual channel support.
-
-         Please read the comments at the top of
-         <file:drivers/ide/alim15x3.c>.
-
-         If unsure, say N.
-
-config BLK_DEV_AMD74XX
-       tristate "AMD and nVidia IDE support"
-       depends on !ARM
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds explicit support for AMD-7xx and AMD-8111 chips
-         and also for the nVidia nForce chip.  This allows the kernel to
-         change PIO, DMA and UDMA speeds and to configure the chip to
-         optimum performance.
-
-config BLK_DEV_ATIIXP
-       tristate "ATI IXP chipset IDE support"
-       depends on X86
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds explicit support for ATI IXP chipset.
-         This allows the kernel to change PIO, DMA and UDMA speeds
-         and to configure the chip to optimum performance.
-
-         Say Y here if you have an ATI IXP chipset IDE controller.
-
-config BLK_DEV_CMD64X
-       tristate "CMD64{3|6|8|9} chipset support"
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Say Y here if you have an IDE controller which uses any of these
-         chipsets: CMD643, CMD646, or CMD648.
-
-config BLK_DEV_TRIFLEX
-       tristate "Compaq Triflex IDE support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Say Y here if you have a Compaq Triflex IDE controller, such
-         as those commonly found on Compaq Pentium-Pro systems
-
-config BLK_DEV_CY82C693
-       tristate "CY82C693 chipset support"
-       depends on ALPHA
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds detection and support for the CY82C693 chipset
-         used on Digital's PC-Alpha 164SX boards.
-
-config BLK_DEV_CS5520
-       tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
-       depends on X86_32 || COMPILE_TEST
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
-         5510/5520 chipset. This will automatically be detected and
-         configured if found.
-
-         It is safe to say Y to this question.
-
-config BLK_DEV_CS5530
-       tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
-       depends on X86_32 || COMPILE_TEST
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
-         will automatically be detected and configured if found.
-
-         It is safe to say Y to this question.
-
-config BLK_DEV_CS5535
-       tristate "AMD CS5535 chipset support"
-       depends on X86_32
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Include support for UDMA on the NSC/AMD CS5535 companion chipset.
-         This will automatically be detected and configured if found.
-
-         It is safe to say Y to this question.
-
-config BLK_DEV_CS5536
-       tristate "CS5536 chipset support"
-       depends on X86_32
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This option enables support for the AMD CS5536
-         companion chip used with the Geode LX processor family.
-
-         If unsure, say N.
-
-config BLK_DEV_HPT366
-       tristate "HPT36X/37X chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         HPT366 is an Ultra DMA chipset for ATA-66.
-         HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
-         HPT370 is an Ultra DMA chipset for ATA-100.
-         HPT372 is an Ultra DMA chipset for ATA-100.
-         HPT374 is an Ultra DMA chipset for ATA-100.
-
-         This driver adds up to 4 more EIDE devices sharing a single
-         interrupt.
-
-         The HPT366 chipset in its current form is bootable. One solution
-         for this problem are special LILO commands for redirecting the
-         reference to device 0x80. The other solution is to say Y to "Boot
-         off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
-         your mother board has the chipset natively mounted. Regardless one
-         should use the fore mentioned option and call at LILO.
-
-         This driver requires dynamic tuning of the chipset during the
-         ide-probe at boot. It is reported to support DVD II drives, by the
-         manufacturer.
-
-config BLK_DEV_JMICRON
-       tristate "JMicron JMB36x support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Basic support for the JMicron ATA controllers. For full support
-         use the libata drivers.
-
-config BLK_DEV_SC1200
-       tristate "National SCx200 chipset support"
-       depends on X86_32 || COMPILE_TEST
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds support for the on-board IDE controller on the
-         National SCx200 series of embedded x86 "Geode" systems.
-
-config BLK_DEV_PIIX
-       tristate "Intel PIIX/ICH chipsets support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds explicit support for Intel PIIX and ICH chips.
-         This allows the kernel to change PIO, DMA and UDMA speeds and to
-         configure the chip to optimum performance.
-
-config BLK_DEV_IT8172
-       tristate "IT8172 IDE support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds support for the IDE controller on the
-         IT8172 System Controller.
-
-config BLK_DEV_IT8213
-       tristate "IT8213 IDE support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds support for the ITE 8213 IDE controller.
-
-config BLK_DEV_IT821X
-       tristate "IT821X IDE support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds support for the ITE 8211 IDE controller and the
-         IT 8212 IDE RAID controller in both RAID and pass-through mode.
-
-config BLK_DEV_NS87415
-       tristate "NS87415 chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds detection and support for the NS87415 chip
-         (used mainly on SPARC64 and PA-RISC machines).
-
-         Please read the comments at the top of <file:drivers/ide/ns87415.c>.
-
-config BLK_DEV_PDC202XX_OLD
-       tristate "PROMISE PDC202{46|62|65|67} support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         Promise Ultra33 or PDC20246
-         Promise Ultra66 or PDC20262
-         Promise Ultra100 or PDC20265/PDC20267/PDC20268
-
-         This driver adds up to 4 more EIDE devices sharing a single
-         interrupt. This add-on card is a bootable PCI UDMA controller. Since
-         multiple cards can be installed and there are BIOS ROM problems that
-         happen if the BIOS revisions of all installed cards (three-max) do
-         not match, the driver attempts to do dynamic tuning of the chipset
-         at boot-time for max-speed.  Ultra33 BIOS 1.25 or newer is required
-         for more than one card.
-
-         Please read the comments at the top of
-         <file:drivers/ide/pdc202xx_old.c>.
-
-         If unsure, say N.
-
-config BLK_DEV_PDC202XX_NEW
-       tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
-       select BLK_DEV_IDEDMA_PCI
-
-config BLK_DEV_SVWKS
-       tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
-         chipsets.
-
-config BLK_DEV_SIIMAGE
-       tristate "Silicon Image chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds PIO/(U)DMA support for the SI CMD680 and SII
-         3112 (Serial ATA) chips.
-
-config BLK_DEV_SIS5513
-       tristate "SiS5513 chipset support"
-       depends on X86
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver ensures (U)DMA support for SIS5513 chipset family based
-         mainboards.
-
-         The following chipsets are supported:
-         ATA16:  SiS5511, SiS5513
-         ATA33:  SiS5591, SiS5597, SiS5598, SiS5600
-         ATA66:  SiS530, SiS540, SiS620, SiS630, SiS640
-         ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
-         SiS745, SiS750
-
-         Please read the comments at the top of <file:drivers/ide/sis5513.c>.
-
-config BLK_DEV_SL82C105
-       tristate "Winbond SL82c105 support"
-       depends on (PPC || ARM)
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         If you have a Winbond SL82c105 IDE controller, say Y here to enable
-         special configuration for this chip. This is common on various CHRP
-         motherboards, but could be used elsewhere. If in doubt, say Y.
-
-config BLK_DEV_SLC90E66
-       tristate "SLC90E66 chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver ensures (U)DMA support for Victory66 SouthBridges for
-         SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
-         The nice thing about it is that you can mix Ultra/DMA/PIO devices
-         and it will handle timing cycles.  Since this is an improved
-         look-a-like to the PIIX4 it should be a nice addition.
-
-         Please read the comments at the top of
-         <file:drivers/ide/slc90e66.c>.
-
-config BLK_DEV_TRM290
-       tristate "Tekram TRM290 chipset support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds support for bus master DMA transfers
-         using the Tekram TRM290 PCI IDE chip. Volunteers are
-         needed for further tweaking and development.
-         Please read the comments at the top of <file:drivers/ide/trm290.c>.
-
-config BLK_DEV_VIA82CXXX
-       tristate "VIA82CXXX chipset support"
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver adds explicit support for VIA BusMastering IDE chips.
-         This allows the kernel to change PIO, DMA and UDMA speeds and to
-         configure the chip to optimum performance.
-
-config BLK_DEV_TC86C001
-       tristate "Toshiba TC86C001 support"
-       select BLK_DEV_IDEDMA_PCI
-       help
-       This driver adds support for Toshiba TC86C001 GOKU-S chip.
-
-endif
-
-# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
-config BLK_DEV_IDE_PMAC
-       tristate "PowerMac on-board IDE support"
-       depends on PPC_PMAC
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_PCI
-       help
-         This driver provides support for the on-board IDE controller on
-         most of the recent Apple Power Macintoshes and PowerBooks.
-         If unsure, say Y.
-
-config BLK_DEV_IDE_PMAC_ATA100FIRST
-       bool "Probe on-board ATA/100 (Kauai) first"
-       depends on BLK_DEV_IDE_PMAC
-       help
-         This option will cause the ATA/100 controller found in UniNorth2
-         based machines (Windtunnel PowerMac, Aluminium PowerBooks, ...)
-         to be probed before the ATA/66 and ATA/33 controllers. Without
-         these, those machine used to have the hard disk on hdc and the
-         CD-ROM on hda. This option changes this to more natural hda for
-         hard disk and hdc for CD-ROM.
-
-config BLK_DEV_IDE_TX4938
-       tristate "TX4938 internal IDE support"
-       depends on SOC_TX4938
-       select IDE_TIMINGS
-
-config BLK_DEV_IDE_TX4939
-       tristate "TX4939 internal IDE support"
-       depends on SOC_TX4939
-       select BLK_DEV_IDEDMA_SFF
-
-config BLK_DEV_IDE_ICSIDE
-       tristate "ICS IDE interface support"
-       depends on ARM && ARCH_ACORN
-       help
-         On Acorn systems, say Y here if you wish to use the ICS IDE
-         interface card.  This is not required for ICS partition support.
-         If you are unsure, say N to this.
-
-config BLK_DEV_IDEDMA_ICS
-       bool "ICS DMA support"
-       depends on BLK_DEV_IDE_ICSIDE
-       help
-         Say Y here if you want to add DMA (Direct Memory Access) support to
-         the ICS IDE driver.
-
-config BLK_DEV_IDE_RAPIDE
-       tristate "RapIDE interface support"
-       depends on ARM && ARCH_ACORN
-       help
-         Say Y here if you want to support the Yellowstone RapIDE controller
-         manufactured for use with Acorn computers.
-
-config BLK_DEV_GAYLE
-       tristate "Amiga Gayle IDE interface support"
-       depends on AMIGA
-       help
-         This is the IDE driver for the Amiga Gayle IDE interface. It supports
-         both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
-         This includes on-board IDE interfaces on some Amiga models (A600,
-         A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
-         bus (M-Tech E-Matrix 530 expansion card).
-
-         It also provides support for the so-called `IDE doublers' (made
-         by various manufacturers, e.g. Eyetech) that can be connected to
-         the on-board IDE interface of some Amiga models. Using such an IDE
-         doubler, you can connect up to four instead of two IDE devices to
-         the Amiga's on-board IDE interface. The feature is enabled at kernel
-         runtime using the "gayle.doubler" kernel boot parameter.
-
-         Say Y if you have an Amiga with a Gayle IDE interface and want to use
-         IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
-         it.
-
-         Note that you also have to enable Zorro bus support if you want to
-         use Gayle IDE interfaces on the Zorro expansion bus.
-
-config BLK_DEV_BUDDHA
-       tristate "Buddha/Catweasel/X-Surf IDE interface support"
-       depends on ZORRO
-       help
-         This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
-         and X-Surf expansion boards.  It supports up to two interfaces on the
-         Buddha, three on the Catweasel and two on the X-Surf.
-
-         Say Y if you have a Buddha or Catweasel expansion board and want to
-         use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
-         to one of its IDE interfaces.
-
-config BLK_DEV_FALCON_IDE
-       tristate "Falcon IDE interface support"
-       depends on ATARI
-       help
-         This is the IDE driver for the on-board IDE interface on the Atari
-         Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
-         disks, CD-ROM drives, etc.) that are connected to the on-board IDE
-         interface.
-
-config BLK_DEV_MAC_IDE
-       tristate "Macintosh Quadra/Powerbook IDE interface support"
-       depends on MAC
-       help
-         This is the IDE driver for the on-board IDE interface on some m68k
-         Macintosh models, namely Quadra/Centris 630, Performa 588 and
-         Powerbook 150. The IDE interface on the Powerbook 190 is not
-         supported by this driver and requires BLK_DEV_PLATFORM or
-         PATA_PLATFORM.
-
-         Say Y if you have such an Macintosh model and want to use IDE
-         devices (hard disks, CD-ROM drives, etc.) that are connected to the
-         on-board IDE interface.
-
-config BLK_DEV_Q40IDE
-       tristate "Q40/Q60 IDE interface support"
-       depends on Q40
-       help
-         Enable the on-board IDE controller in the Q40/Q60.  This should
-         normally be on; disable it only if you are running a custom hard
-         drive subsystem through an expansion card.
-
-config BLK_DEV_PALMCHIP_BK3710
-       tristate "Palmchip bk3710 IDE controller support"
-       depends on ARCH_DAVINCI
-       select IDE_TIMINGS
-       select BLK_DEV_IDEDMA_SFF
-       help
-         Say Y here if you want to support the onchip IDE controller on the
-         TI DaVinci SoC
-
-# no isa -> no vlb
-if ISA && (ALPHA || X86 || MIPS)
-
-comment "Other IDE chipsets support"
-comment "Note: most of these also require special kernel boot parameters"
-
-config BLK_DEV_4DRIVES
-       tristate "Generic 4 drives/port support"
-       help
-         Certain older chipsets, including the Tekram 690CD, use a single set
-         of I/O ports at 0x1f0 to control up to four drives, instead of the
-         customary two drives per port. Support for this can be enabled at
-         runtime using the "ide-4drives.probe" kernel boot parameter if you
-         say Y here.
-
-config BLK_DEV_ALI14XX
-       tristate "ALI M14xx support"
-       select IDE_TIMINGS
-       select IDE_LEGACY
-       help
-         This driver is enabled at runtime using the "ali14xx.probe" kernel
-         boot parameter.  It enables support for the secondary IDE interface
-         of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
-         I/O speeds to be set as well.
-         See the files <file:Documentation/ide/ide.rst> and
-         <file:drivers/ide/ali14xx.c> for more info.
-
-config BLK_DEV_DTC2278
-       tristate "DTC-2278 support"
-       select IDE_XFER_MODE
-       select IDE_LEGACY
-       help
-         This driver is enabled at runtime using the "dtc2278.probe" kernel
-         boot parameter. It enables support for the secondary IDE interface
-         of the DTC-2278 card, and permits faster I/O speeds to be set as
-         well. See the <file:Documentation/ide/ide.rst> and
-         <file:drivers/ide/dtc2278.c> files for more info.
-
-config BLK_DEV_HT6560B
-       tristate "Holtek HT6560B support"
-       select IDE_TIMINGS
-       select IDE_LEGACY
-       help
-         This driver is enabled at runtime using the "ht6560b.probe" kernel
-         boot parameter. It enables support for the secondary IDE interface
-         of the Holtek card, and permits faster I/O speeds to be set as well.
-         See the <file:Documentation/ide/ide.rst> and
-         <file:drivers/ide/ht6560b.c> files for more info.
-
-config BLK_DEV_QD65XX
-       tristate "QDI QD65xx support"
-       select IDE_TIMINGS
-       select IDE_LEGACY
-       help
-         This driver is enabled at runtime using the "qd65xx.probe" kernel
-         boot parameter.  It permits faster I/O speeds to be set.  See the
-         <file:Documentation/ide/ide.rst> and <file:drivers/ide/qd65xx.c>
-         for more info.
-
-config BLK_DEV_UMC8672
-       tristate "UMC-8672 support"
-       select IDE_XFER_MODE
-       select IDE_LEGACY
-       help
-         This driver is enabled at runtime using the "umc8672.probe" kernel
-         boot parameter. It enables support for the secondary IDE interface
-         of the UMC-8672, and permits faster I/O speeds to be set as well.
-         See the files <file:Documentation/ide/ide.rst> and
-         <file:drivers/ide/umc8672.c> for more info.
-
-endif
-
-config BLK_DEV_IDEDMA
-       def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_ICS
-       select IDE_XFER_MODE
-
-endif # IDE
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
deleted file mode 100644 (file)
index 2605b3c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# link order is important here
-#
-
-ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
-             ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
-             ide-io-std.o ide-eh.o
-
-# core IDE code
-ide-core-$(CONFIG_IDE_XFER_MODE)       += ide-pio-blacklist.o ide-xfer-mode.o
-ide-core-$(CONFIG_IDE_TIMINGS)         += ide-timings.o
-ide-core-$(CONFIG_IDE_ATAPI)           += ide-atapi.o
-ide-core-$(CONFIG_BLK_DEV_IDEPCI)      += setup-pci.o
-ide-core-$(CONFIG_BLK_DEV_IDEDMA)      += ide-dma.o
-ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF)  += ide-dma-sff.o
-ide-core-$(CONFIG_IDE_PROC_FS)         += ide-proc.o
-ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
-ide-core-$(CONFIG_IDE_LEGACY)          += ide-legacy.o
-
-obj-$(CONFIG_IDE)                      += ide-core.o
-
-obj-$(CONFIG_BLK_DEV_ALI14XX)          += ali14xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672)          += umc8672.o
-obj-$(CONFIG_BLK_DEV_DTC2278)          += dtc2278.o
-obj-$(CONFIG_BLK_DEV_HT6560B)          += ht6560b.o
-obj-$(CONFIG_BLK_DEV_QD65XX)           += qd65xx.o
-obj-$(CONFIG_BLK_DEV_4DRIVES)          += ide-4drives.o
-
-obj-$(CONFIG_BLK_DEV_GAYLE)            += gayle.o
-obj-$(CONFIG_BLK_DEV_FALCON_IDE)       += falconide.o
-obj-$(CONFIG_BLK_DEV_MAC_IDE)          += macide.o
-obj-$(CONFIG_BLK_DEV_Q40IDE)           += q40ide.o
-obj-$(CONFIG_BLK_DEV_BUDDHA)           += buddha.o
-
-obj-$(CONFIG_BLK_DEV_AEC62XX)          += aec62xx.o
-obj-$(CONFIG_BLK_DEV_ALI15X3)          += alim15x3.o
-obj-$(CONFIG_BLK_DEV_AMD74XX)          += amd74xx.o
-obj-$(CONFIG_BLK_DEV_ATIIXP)           += atiixp.o
-obj-$(CONFIG_BLK_DEV_CMD64X)           += cmd64x.o
-obj-$(CONFIG_BLK_DEV_CS5520)           += cs5520.o
-obj-$(CONFIG_BLK_DEV_CS5530)           += cs5530.o
-obj-$(CONFIG_BLK_DEV_CS5535)           += cs5535.o
-obj-$(CONFIG_BLK_DEV_CS5536)           += cs5536.o
-obj-$(CONFIG_BLK_DEV_SC1200)           += sc1200.o
-obj-$(CONFIG_BLK_DEV_CY82C693)         += cy82c693.o
-obj-$(CONFIG_BLK_DEV_DELKIN)           += delkin_cb.o
-obj-$(CONFIG_BLK_DEV_HPT366)           += hpt366.o
-obj-$(CONFIG_BLK_DEV_IT8172)           += it8172.o
-obj-$(CONFIG_BLK_DEV_IT8213)           += it8213.o
-obj-$(CONFIG_BLK_DEV_IT821X)           += it821x.o
-obj-$(CONFIG_BLK_DEV_JMICRON)          += jmicron.o
-obj-$(CONFIG_BLK_DEV_NS87415)          += ns87415.o
-obj-$(CONFIG_BLK_DEV_OPTI621)          += opti621.o
-obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)     += pdc202xx_old.o
-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_SIIMAGE)          += siimage.o
-obj-$(CONFIG_BLK_DEV_SIS5513)          += sis5513.o
-obj-$(CONFIG_BLK_DEV_SL82C105)         += sl82c105.o
-obj-$(CONFIG_BLK_DEV_SLC90E66)         += slc90e66.o
-obj-$(CONFIG_BLK_DEV_TC86C001)         += tc86c001.o
-obj-$(CONFIG_BLK_DEV_TRIFLEX)          += triflex.o
-obj-$(CONFIG_BLK_DEV_TRM290)           += trm290.o
-obj-$(CONFIG_BLK_DEV_VIA82CXXX)                += via82cxxx.o
-
-# Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC)          += ide-pci-generic.o
-
-obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)      += ide-scan-pci.o
-
-obj-$(CONFIG_BLK_DEV_CMD640)           += cmd640.o
-
-obj-$(CONFIG_BLK_DEV_IDE_PMAC)         += pmac.o
-
-obj-$(CONFIG_IDE_GENERIC)              += ide-generic.o
-obj-$(CONFIG_BLK_DEV_IDEPNP)           += ide-pnp.o
-
-ide-gd_mod-y += ide-gd.o
-ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
-
-ifeq ($(CONFIG_IDE_GD_ATA), y)
-       ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
-ifeq ($(CONFIG_IDE_PROC_FS), y)
-       ide-gd_mod-y += ide-disk_proc.o
-endif
-endif
-
-ifeq ($(CONFIG_IDE_GD_ATAPI), y)
-       ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
-ifeq ($(CONFIG_IDE_PROC_FS), y)
-       ide-gd_mod-y += ide-floppy_proc.o
-endif
-endif
-
-obj-$(CONFIG_IDE_GD)                   += ide-gd_mod.o
-obj-$(CONFIG_BLK_DEV_IDECD)            += ide-cd_mod.o
-obj-$(CONFIG_BLK_DEV_IDETAPE)          += ide-tape.o
-
-obj-$(CONFIG_BLK_DEV_IDECS)            += ide-cs.o
-
-obj-$(CONFIG_BLK_DEV_PLATFORM)         += ide_platform.o
-
-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)       += icside.o
-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)       += rapide.o
-obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710)  += palm_bk3710.o
-
-obj-$(CONFIG_BLK_DEV_IDE_TX4938)       += tx4938ide.o
-obj-$(CONFIG_BLK_DEV_IDE_TX4939)       += tx4939ide.o
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
deleted file mode 100644 (file)
index 4c959ce..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1999-2002     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007          MontaVista Software, Inc. <source@mvista.com>
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "aec62xx"
-
-struct chipset_bus_clock_list_entry {
-       u8 xfer_speed;
-       u8 chipset_settings;
-       u8 ultra_settings;
-};
-
-static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
-       {       XFER_UDMA_6,    0x31,   0x07    },
-       {       XFER_UDMA_5,    0x31,   0x06    },
-       {       XFER_UDMA_4,    0x31,   0x05    },
-       {       XFER_UDMA_3,    0x31,   0x04    },
-       {       XFER_UDMA_2,    0x31,   0x03    },
-       {       XFER_UDMA_1,    0x31,   0x02    },
-       {       XFER_UDMA_0,    0x31,   0x01    },
-
-       {       XFER_MW_DMA_2,  0x31,   0x00    },
-       {       XFER_MW_DMA_1,  0x31,   0x00    },
-       {       XFER_MW_DMA_0,  0x0a,   0x00    },
-       {       XFER_PIO_4,     0x31,   0x00    },
-       {       XFER_PIO_3,     0x33,   0x00    },
-       {       XFER_PIO_2,     0x08,   0x00    },
-       {       XFER_PIO_1,     0x0a,   0x00    },
-       {       XFER_PIO_0,     0x00,   0x00    },
-       {       0,              0x00,   0x00    }
-};
-
-static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
-       {       XFER_UDMA_6,    0x41,   0x06    },
-       {       XFER_UDMA_5,    0x41,   0x05    },
-       {       XFER_UDMA_4,    0x41,   0x04    },
-       {       XFER_UDMA_3,    0x41,   0x03    },
-       {       XFER_UDMA_2,    0x41,   0x02    },
-       {       XFER_UDMA_1,    0x41,   0x01    },
-       {       XFER_UDMA_0,    0x41,   0x01    },
-
-       {       XFER_MW_DMA_2,  0x41,   0x00    },
-       {       XFER_MW_DMA_1,  0x42,   0x00    },
-       {       XFER_MW_DMA_0,  0x7a,   0x00    },
-       {       XFER_PIO_4,     0x41,   0x00    },
-       {       XFER_PIO_3,     0x43,   0x00    },
-       {       XFER_PIO_2,     0x78,   0x00    },
-       {       XFER_PIO_1,     0x7a,   0x00    },
-       {       XFER_PIO_0,     0x70,   0x00    },
-       {       0,              0x00,   0x00    }
-};
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-       for ( ; chipset_table->xfer_speed ; chipset_table++)
-               if (chipset_table->xfer_speed == speed) {
-                       return chipset_table->chipset_settings;
-               }
-       return chipset_table->chipset_settings;
-}
-
-static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-       for ( ; chipset_table->xfer_speed ; chipset_table++)
-               if (chipset_table->xfer_speed == speed) {
-                       return chipset_table->ultra_settings;
-               }
-       return chipset_table->ultra_settings;
-}
-
-static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       struct ide_host *host   = pci_get_drvdata(dev);
-       struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
-       u16 d_conf              = 0;
-       u8 ultra = 0, ultra_conf = 0;
-       u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
-       const u8 speed = drive->dma_mode;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */
-       pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-       tmp0 = pci_bus_clock_list(speed, bus_clock);
-       d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf);
-       pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-       tmp1 = 0x00;
-       tmp2 = 0x00;
-       pci_read_config_byte(dev, 0x54, &ultra);
-       tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-       ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
-       tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-       pci_write_config_byte(dev, 0x54, tmp2);
-       local_irq_restore(flags);
-}
-
-static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       struct ide_host *host   = pci_get_drvdata(dev);
-       struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
-       u8 unit                 = drive->dn & 1;
-       u8 tmp1 = 0, tmp2 = 0;
-       u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
-       const u8 speed = drive->dma_mode;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /* high 4-bits: Active, low 4-bits: Recovery */
-       pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-       drive_conf = pci_bus_clock_list(speed, bus_clock);
-       pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-       pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
-       tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-       ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
-       tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-       pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
-       local_irq_restore(flags);
-}
-
-static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       hwif->port_ops->set_dma_mode(hwif, drive);
-}
-
-static int init_chipset_aec62xx(struct pci_dev *dev)
-{
-       /* These are necessary to get AEC6280 Macintosh cards to work */
-       if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
-           (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
-               u8 reg49h = 0, reg4ah = 0;
-               /* Clear reset and test bits.  */
-               pci_read_config_byte(dev, 0x49, &reg49h);
-               pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
-               /* Enable chip interrupt output.  */
-               pci_read_config_byte(dev, 0x4a, &reg4ah);
-               pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
-               /* Enable burst mode. */
-               pci_read_config_byte(dev, 0x4a, &reg4ah);
-               pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
-       }
-
-       return 0;
-}
-
-static u8 atp86x_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
-
-       pci_read_config_byte(dev, 0x49, &ata66);
-
-       return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops atp850_port_ops = {
-       .set_pio_mode           = aec_set_pio_mode,
-       .set_dma_mode           = aec6210_set_mode,
-};
-
-static const struct ide_port_ops atp86x_port_ops = {
-       .set_pio_mode           = aec_set_pio_mode,
-       .set_dma_mode           = aec6260_set_mode,
-       .cable_detect           = atp86x_cable_detect,
-};
-
-static const struct ide_port_info aec62xx_chipsets[] = {
-       {       /* 0: AEC6210 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_aec62xx,
-               .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-               .port_ops       = &atp850_port_ops,
-               .host_flags     = IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_NO_DSC |
-                                 IDE_HFLAG_OFF_BOARD,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA2,
-       },
-       {       /* 1: AEC6260 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_aec62xx,
-               .port_ops       = &atp86x_port_ops,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
-                                 IDE_HFLAG_OFF_BOARD,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA4,
-       },
-       {       /* 2: AEC6260R */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_aec62xx,
-               .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-               .port_ops       = &atp86x_port_ops,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_NON_BOOTABLE,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA4,
-       },
-       {       /* 3: AEC6280 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_aec62xx,
-               .port_ops       = &atp86x_port_ops,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_OFF_BOARD,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-       {       /* 4: AEC6280R */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_aec62xx,
-               .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-               .port_ops       = &atp86x_port_ops,
-               .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
-                                 IDE_HFLAG_OFF_BOARD,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       }
-};
-
-/**
- *     aec62xx_init_one        -       called when a AEC is found
- *     @dev: the aec62xx device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- *
- *     NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
- *     chips, pass a local copy of 'struct ide_port_info' down the call chain.
- */
-
-static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       const struct chipset_bus_clock_list_entry *bus_clock;
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-       int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-       int err;
-
-       if (bus_speed <= 33)
-               bus_clock = aec6xxx_33_base;
-       else
-               bus_clock = aec6xxx_34_base;
-
-       err = pci_enable_device(dev);
-       if (err)
-               return err;
-
-       d = aec62xx_chipsets[idx];
-
-       if (idx == 3 || idx == 4) {
-               unsigned long dma_base = pci_resource_start(dev, 4);
-
-               if (inb(dma_base + 2) & 0x10) {
-                       printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected"
-                               "\n", pci_name(dev), (idx == 4) ? "R" : "");
-                       d.udma_mask = ATA_UDMA6;
-               }
-       }
-
-       err = ide_pci_init_one(dev, &d, (void *)bus_clock);
-       if (err)
-               pci_disable_device(dev);
-
-       return err;
-}
-
-static void aec62xx_remove(struct pci_dev *dev)
-{
-       ide_pci_remove(dev);
-       pci_disable_device(dev);
-}
-
-static const struct pci_device_id aec62xx_pci_tbl[] = {
-       { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
-       { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860),   1 },
-       { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R),  2 },
-       { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865),   3 },
-       { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R),  4 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
-
-static struct pci_driver aec62xx_pci_driver = {
-       .name           = "AEC62xx_IDE",
-       .id_table       = aec62xx_pci_tbl,
-       .probe          = aec62xx_init_one,
-       .remove         = aec62xx_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init aec62xx_ide_init(void)
-{
-       return ide_pci_register_driver(&aec62xx_pci_driver);
-}
-
-static void __exit aec62xx_ide_exit(void)
-{
-       pci_unregister_driver(&aec62xx_pci_driver);
-}
-
-module_init(aec62xx_ide_init);
-module_exit(aec62xx_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
deleted file mode 100644 (file)
index 3268931..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function.  The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk.  I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg  (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets.  I've added support for PIO mode 4 for the 1487.  This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.)  -Derek
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "ali14xx"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static const int ports[ALI_NUM_PORTS] __initconst =
-       { 0x074, 0x0f4, 0x034, 0x0e4 };
-
-/* register initialization data */
-typedef struct { u8 reg, data; } RegInitializer;
-
-static const RegInitializer initData[] __initconst = {
-       {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
-       {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
-       {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
-       {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
-       {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
-       {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
-       {0x35, 0x03}, {0x00, 0x00}
-};
-
-/* timing parameter registers for each drive */
-static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
-       {0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-       {0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-       {0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-       {0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
-};
-
-static int basePort;   /* base port address */
-static int regPort;    /* port for register number */
-static int dataPort;   /* port for register data */
-static u8 regOn;       /* output to base port to access registers */
-static u8 regOff;      /* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline u8 inReg(u8 reg)
-{
-       outb_p(reg, regPort);
-       return inb(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg(u8 data, u8 reg)
-{
-       outb_p(reg, regPort);
-       outb_p(data, dataPort);
-}
-
-static DEFINE_SPINLOCK(ali14xx_lock);
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int driveNum;
-       int time1, time2;
-       u8 param1, param2, param3, param4;
-       unsigned long flags;
-       int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-
-       /* calculate timing, according to PIO mode */
-       time1 = ide_pio_cycle_time(drive, pio);
-       time2 = t->active;
-       param3 = param1 = (time2 * bus_speed + 999) / 1000;
-       param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
-       if (pio < 3) {
-               param3 += 8;
-               param4 += 8;
-       }
-       printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-               drive->name, pio, time1, time2, param1, param2, param3, param4);
-
-       /* stuff timing parameters into controller registers */
-       driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
-       spin_lock_irqsave(&ali14xx_lock, flags);
-       outb_p(regOn, basePort);
-       outReg(param1, regTab[driveNum].reg1);
-       outReg(param2, regTab[driveNum].reg2);
-       outReg(param3, regTab[driveNum].reg3);
-       outReg(param4, regTab[driveNum].reg4);
-       outb_p(regOff, basePort);
-       spin_unlock_irqrestore(&ali14xx_lock, flags);
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort(void)
-{
-       int i;
-       u8 t;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       for (i = 0; i < ALI_NUM_PORTS; ++i) {
-               basePort = ports[i];
-               regOff = inb(basePort);
-               for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-                       outb_p(regOn, basePort);
-                       if (inb(basePort) == regOn) {
-                               regPort = basePort + 4;
-                               dataPort = basePort + 8;
-                               t = inReg(0) & 0xf0;
-                               outb_p(regOff, basePort);
-                               local_irq_restore(flags);
-                               if (t != 0x50)
-                                       return 0;
-                               return 1;  /* success */
-                       }
-               }
-               outb_p(regOff, basePort);
-       }
-       local_irq_restore(flags);
-       return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters(void)
-{
-       const RegInitializer *p;
-       u8 t;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       outb_p(regOn, basePort);
-       for (p = initData; p->reg != 0; ++p)
-               outReg(p->data, p->reg);
-       outb_p(0x01, regPort);
-       t = inb(regPort) & 0x01;
-       outb_p(regOff, basePort);
-       local_irq_restore(flags);
-       return t;
-}
-
-static const struct ide_port_ops ali14xx_port_ops = {
-       .set_pio_mode           = ali14xx_set_pio_mode,
-};
-
-static const struct ide_port_info ali14xx_port_info = {
-       .name                   = DRV_NAME,
-       .chipset                = ide_ali14xx,
-       .port_ops               = &ali14xx_port_ops,
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .pio_mask               = ATA_PIO4,
-};
-
-static int __init ali14xx_probe(void)
-{
-       printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
-                         basePort, regOn);
-
-       /* initialize controller registers */
-       if (!initRegisters()) {
-               printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
-               return 1;
-       }
-
-       return ide_legacy_device_add(&ali14xx_port_info, 0);
-}
-
-static bool probe_ali14xx;
-
-module_param_named(probe, probe_ali14xx, bool, 0);
-MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
-
-static int __init ali14xx_init(void)
-{
-       if (probe_ali14xx == 0)
-               goto out;
-
-       /* auto-detect IDE controller port */
-       if (findPort()) {
-               if (ali14xx_probe())
-                       return -ENODEV;
-               return 0;
-       }
-       printk(KERN_ERR "ali14xx: not found.\n");
-out:
-       return -ENODEV;
-}
-
-module_init(ali14xx_init);
-
-MODULE_AUTHOR("see local file");
-MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
deleted file mode 100644 (file)
index 3265970..0000000
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- *  May be copied or modified under the terms of the GNU General Public License
- *  Copyright (C) 2002 Alan Cox
- *  ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
- *  Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
- *  Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- *  9/7/99 --Parts from the above author are included and need to be
- *  converted into standard interface, once I finish the thought.
- *
- *  Recent changes
- *     Don't use LBA48 mode on ALi <= 0xC4
- *     Don't poke 0x79 with a non ALi northbridge
- *     Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
- *     Allow UDMA6 on revisions > 0xC4
- *
- *  Documentation
- *     Chipset documentation available under NDA only
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/dmi.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "alim15x3"
-
-/*
- *     ALi devices are not plug in. Otherwise these static values would
- *     need to go. They ought to go away anyway
- */
-static u8 m5229_revision;
-static u8 chip_is_1543c_e;
-static struct pci_dev *isa_dev;
-
-static void ali_fifo_control(ide_hwif_t *hwif, ide_drive_t *drive, int on)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       int pio_fifo = 0x54 + hwif->channel;
-       u8 fifo;
-       int shift = 4 * (drive->dn & 1);
-
-       pci_read_config_byte(pdev, pio_fifo, &fifo);
-       fifo &= ~(0x0F << shift);
-       fifo |= (on << shift);
-       pci_write_config_byte(pdev, pio_fifo, fifo);
-}
-
-static void ali_program_timings(ide_hwif_t *hwif, ide_drive_t *drive,
-                               struct ide_timing *t, u8 ultra)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       int port = hwif->channel ? 0x5c : 0x58;
-       int udmat = 0x56 + hwif->channel;
-       u8 unit = drive->dn & 1, udma;
-       int shift = 4 * unit;
-
-       /* Set up the UDMA */
-       pci_read_config_byte(dev, udmat, &udma);
-       udma &= ~(0x0F << shift);
-       udma |= ultra << shift;
-       pci_write_config_byte(dev, udmat, udma);
-
-       if (t == NULL)
-               return;
-
-       t->setup = clamp_val(t->setup, 1, 8) & 7;
-       t->act8b = clamp_val(t->act8b, 1, 8) & 7;
-       t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
-       t->active = clamp_val(t->active, 1, 8) & 7;
-       t->recover = clamp_val(t->recover, 1, 16) & 15;
-
-       pci_write_config_byte(dev, port, t->setup);
-       pci_write_config_byte(dev, port + 1, (t->act8b << 4) | t->rec8b);
-       pci_write_config_byte(dev, port + unit + 2,
-                             (t->active << 4) | t->recover);
-}
-
-/**
- *     ali_set_pio_mode        -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Program the controller for the given PIO mode.
- */
-
-static void ali_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-       unsigned long T =  1000000 / bus_speed; /* PCI clock based */
-       struct ide_timing t;
-
-       ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
-       if (pair) {
-               struct ide_timing p;
-
-               ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
-               ide_timing_merge(&p, &t, &t,
-                       IDE_TIMING_SETUP | IDE_TIMING_8BIT);
-               if (pair->dma_mode) {
-                       ide_timing_compute(pair, pair->dma_mode, &p, T, 1);
-                       ide_timing_merge(&p, &t, &t,
-                               IDE_TIMING_SETUP | IDE_TIMING_8BIT);
-               }
-       }
-
-       /* 
-        * PIO mode => ATA FIFO on, ATAPI FIFO off
-        */
-       ali_fifo_control(hwif, drive, (drive->media == ide_disk) ? 0x05 : 0x00);
-
-       ali_program_timings(hwif, drive, &t, 0);
-}
-
-/**
- *     ali_udma_filter         -       compute UDMA mask
- *     @drive: IDE device
- *
- *     Return available UDMA modes.
- *
- *     The actual rules for the ALi are:
- *             No UDMA on revisions <= 0x20
- *             Disk only for revisions < 0xC2
- *             Not WDC drives on M1543C-E (?)
- */
-
-static u8 ali_udma_filter(ide_drive_t *drive)
-{
-       if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
-               if (drive->media != ide_disk)
-                       return 0;
-               if (chip_is_1543c_e &&
-                   strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
-                       return 0;
-       }
-
-       return drive->hwif->ultra_mask;
-}
-
-/**
- *     ali_set_dma_mode        -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Configure the hardware for the desired IDE transfer mode.
- */
-
-static void ali_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       ide_drive_t *pair       = ide_get_pair_dev(drive);
-       int bus_speed           = ide_pci_clk ? ide_pci_clk : 33;
-       unsigned long T         =  1000000 / bus_speed; /* PCI clock based */
-       const u8 speed          = drive->dma_mode;
-       u8 tmpbyte              = 0x00;
-       struct ide_timing t;
-
-       if (speed < XFER_UDMA_0) {
-               ide_timing_compute(drive, drive->dma_mode, &t, T, 1);
-               if (pair) {
-                       struct ide_timing p;
-
-                       ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
-                       ide_timing_merge(&p, &t, &t,
-                               IDE_TIMING_SETUP | IDE_TIMING_8BIT);
-                       if (pair->dma_mode) {
-                               ide_timing_compute(pair, pair->dma_mode,
-                                               &p, T, 1);
-                               ide_timing_merge(&p, &t, &t,
-                                       IDE_TIMING_SETUP | IDE_TIMING_8BIT);
-                       }
-               }
-               ali_program_timings(hwif, drive, &t, 0);
-       } else {
-               ali_program_timings(hwif, drive, NULL,
-                               udma_timing[speed - XFER_UDMA_0]);
-               if (speed >= XFER_UDMA_3) {
-                       pci_read_config_byte(dev, 0x4b, &tmpbyte);
-                       tmpbyte |= 1;
-                       pci_write_config_byte(dev, 0x4b, tmpbyte);
-               }
-       }
-}
-
-/**
- *     ali_dma_check   -       DMA check
- *     @drive: target device
- *     @cmd: command
- *
- *     Returns 1 if the DMA cannot be performed, zero on success.
- */
-
-static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       if (m5229_revision < 0xC2 && drive->media != ide_disk) {
-               if (cmd->tf_flags & IDE_TFLAG_WRITE)
-                       return 1;       /* try PIO instead of DMA */
-       }
-       return 0;
-}
-
-/**
- *     init_chipset_ali15x3    -       Initialise an ALi IDE controller
- *     @dev: PCI device
- *
- *     This function initializes the ALI IDE controller and where 
- *     appropriate also sets up the 1533 southbridge.
- */
-
-static int init_chipset_ali15x3(struct pci_dev *dev)
-{
-       unsigned long flags;
-       u8 tmpbyte;
-       struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
-
-       m5229_revision = dev->revision;
-
-       isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
-       local_irq_save(flags);
-
-       if (m5229_revision < 0xC2) {
-               /*
-                * revision 0x20 (1543-E, 1543-F)
-                * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-                * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-                */
-               pci_read_config_byte(dev, 0x4b, &tmpbyte);
-               /*
-                * clear bit 7
-                */
-               pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-               /*
-                * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-                */
-               if (m5229_revision >= 0x20 && isa_dev) {
-                       pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
-                       chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
-               }
-               goto out;
-       }
-
-       /*
-        * 1543C-B?, 1535, 1535D, 1553
-        * Note 1: not all "motherboard" support this detection
-        * Note 2: if no udma 66 device, the detection may "error".
-        *         but in this case, we will not set the device to
-        *         ultra 66, the detection result is not important
-        */
-
-       /*
-        * enable "Cable Detection", m5229, 0x4b, bit3
-        */
-       pci_read_config_byte(dev, 0x4b, &tmpbyte);
-       pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-       /*
-        * We should only tune the 1533 enable if we are using an ALi
-        * North bridge. We might have no north found on some zany
-        * box without a device at 0:0.0. The ALi bridge will be at
-        * 0:0.0 so if we didn't find one we know what is cooking.
-        */
-       if (north && north->vendor != PCI_VENDOR_ID_AL)
-               goto out;
-
-       if (m5229_revision < 0xC5 && isa_dev)
-       {       
-               /*
-                * set south-bridge's enable bit, m1533, 0x79
-                */
-
-               pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-               if (m5229_revision == 0xC2) {
-                       /*
-                        * 1543C-B0 (m1533, 0x79, bit 2)
-                        */
-                       pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-               } else if (m5229_revision >= 0xC3) {
-                       /*
-                        * 1553/1535 (m1533, 0x79, bit 1)
-                        */
-                       pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-               }
-       }
-
-out:
-       /*
-        * CD_ROM DMA on (m5229, 0x53, bit0)
-        *      Enable this bit even if we want to use PIO.
-        * PIO FIFO off (m5229, 0x53, bit1)
-        *      The hardware will use 0x54h and 0x55h to control PIO FIFO.
-        *      (Not on later devices it seems)
-        *
-        *      0x53 changes meaning on later revs - we must no touch
-        *      bit 1 on them.  Need to check if 0x20 is the right break.
-        */
-       if (m5229_revision >= 0x20) {
-               pci_read_config_byte(dev, 0x53, &tmpbyte);
-
-               if (m5229_revision <= 0x20)
-                       tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-               else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
-                       tmpbyte |= 0x03;
-               else
-                       tmpbyte |= 0x01;
-
-               pci_write_config_byte(dev, 0x53, tmpbyte);
-       }
-       local_irq_restore(flags);
-       pci_dev_put(north);
-       pci_dev_put(isa_dev);
-       return 0;
-}
-
-/*
- *     Cable special cases
- */
-
-static const struct dmi_system_id cable_dmi_table[] = {
-       {
-               .ident = "HP Pavilion N5430",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-                       DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
-               },
-       },
-       {
-               .ident = "Toshiba Satellite S1800-814",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
-               },
-       },
-       { }
-};
-
-static int ali_cable_override(struct pci_dev *pdev)
-{
-       /* Fujitsu P2000 */
-       if (pdev->subsystem_vendor == 0x10CF &&
-           pdev->subsystem_device == 0x10AF)
-               return 1;
-
-       /* Mitac 8317 (Winbook-A) and relatives */
-       if (pdev->subsystem_vendor == 0x1071 &&
-           pdev->subsystem_device == 0x8317)
-               return 1;
-
-       /* Systems by DMI */
-       if (dmi_check_system(cable_dmi_table))
-               return 1;
-
-       return 0;
-}
-
-/**
- *     ali_cable_detect        -       cable detection
- *     @hwif: IDE interface
- *
- *     This checks if the controller and the cable are capable
- *     of UDMA66 transfers. It doesn't check the drives.
- */
-
-static u8 ali_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 cbl = ATA_CBL_PATA40, tmpbyte;
-
-       if (m5229_revision >= 0xC2) {
-               /*
-                * m5229 80-pin cable detection (from Host View)
-                *
-                * 0x4a bit0 is 0 => primary channel has 80-pin
-                * 0x4a bit1 is 0 => secondary channel has 80-pin
-                *
-                * Certain laptops use short but suitable cables
-                * and don't implement the detect logic.
-                */
-               if (ali_cable_override(dev))
-                       cbl = ATA_CBL_PATA40_SHORT;
-               else {
-                       pci_read_config_byte(dev, 0x4a, &tmpbyte);
-                       if ((tmpbyte & (1 << hwif->channel)) == 0)
-                               cbl = ATA_CBL_PATA80;
-               }
-       }
-
-       return cbl;
-}
-
-#ifndef CONFIG_SPARC64
-/**
- *     init_hwif_ali15x3       -       Initialize the ALI IDE x86 stuff
- *     @hwif: interface to configure
- *
- *     Obtain the IRQ tables for an ALi based IDE solution on the PC
- *     class platforms. This part of the code isn't applicable to the
- *     Sparc systems.
- */
-
-static void init_hwif_ali15x3(ide_hwif_t *hwif)
-{
-       u8 ideic, inmir;
-       s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-                                     1, 11, 0, 12, 0, 14, 0, 15 };
-       int irq = -1;
-
-       if (isa_dev) {
-               /*
-                * read IDE interface control
-                */
-               pci_read_config_byte(isa_dev, 0x58, &ideic);
-
-               /* bit0, bit1 */
-               ideic = ideic & 0x03;
-
-               /* get IRQ for IDE Controller */
-               if ((hwif->channel && ideic == 0x03) ||
-                   (!hwif->channel && !ideic)) {
-                       /*
-                        * get SIRQ1 routing table
-                        */
-                       pci_read_config_byte(isa_dev, 0x44, &inmir);
-                       inmir = inmir & 0x0f;
-                       irq = irq_routing_table[inmir];
-               } else if (hwif->channel && !(ideic & 0x01)) {
-                       /*
-                        * get SIRQ2 routing table
-                        */
-                       pci_read_config_byte(isa_dev, 0x75, &inmir);
-                       inmir = inmir & 0x0f;
-                       irq = irq_routing_table[inmir];
-               }
-               if(irq >= 0)
-                       hwif->irq = irq;
-       }
-}
-#else
-#define init_hwif_ali15x3 NULL
-#endif /* CONFIG_SPARC64 */
-
-/**
- *     init_dma_ali15x3        -       set up DMA on ALi15x3
- *     @hwif: IDE interface
- *     @d: IDE port info
- *
- *     Set up the DMA functionality on the ALi 15x3.
- */
-
-static int init_dma_ali15x3(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long base = ide_pci_dma_base(hwif, d);
-
-       if (base == 0)
-               return -1;
-
-       hwif->dma_base = base;
-
-       if (ide_pci_check_simplex(hwif, d) < 0)
-               return -1;
-
-       if (ide_pci_set_master(dev, d->name) < 0)
-               return -1;
-
-       if (!hwif->channel)
-               outb(inb(base + 2) & 0x60, base + 2);
-
-       printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx\n",
-                        hwif->name, base, base + 7);
-
-       if (ide_allocate_dma_engine(hwif))
-               return -1;
-
-       return 0;
-}
-
-static const struct ide_port_ops ali_port_ops = {
-       .set_pio_mode           = ali_set_pio_mode,
-       .set_dma_mode           = ali_set_dma_mode,
-       .udma_filter            = ali_udma_filter,
-       .cable_detect           = ali_cable_detect,
-};
-
-static const struct ide_dma_ops ali_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_check              = ali_dma_check,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info ali15x3_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_ali15x3,
-       .init_hwif      = init_hwif_ali15x3,
-       .init_dma       = init_dma_ali15x3,
-       .port_ops       = &ali_port_ops,
-       .dma_ops        = &sff_dma_ops,
-       .pio_mask       = ATA_PIO5,
-       .swdma_mask     = ATA_SWDMA2,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-/**
- *     alim15x3_init_one       -       set up an ALi15x3 IDE controller
- *     @dev: PCI device to set up
- *
- *     Perform the actual set up for an ALi15x3 that has been found by the
- *     hot plug layer.
- */
-static int alim15x3_init_one(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       struct ide_port_info d = ali15x3_chipset;
-       u8 rev = dev->revision, idx = id->driver_data;
-
-       /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
-       if (rev <= 0xC4)
-               d.host_flags |= IDE_HFLAG_NO_LBA48_DMA;
-
-       if (rev >= 0x20) {
-               if (rev == 0x20)
-                       d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-
-               if (rev < 0xC2)
-                       d.udma_mask = ATA_UDMA2;
-               else if (rev == 0xC2 || rev == 0xC3)
-                       d.udma_mask = ATA_UDMA4;
-               else if (rev == 0xC4)
-                       d.udma_mask = ATA_UDMA5;
-               else
-                       d.udma_mask = ATA_UDMA6;
-
-               d.dma_ops = &ali_dma_ops;
-       } else {
-               d.host_flags |= IDE_HFLAG_NO_DMA;
-
-               d.mwdma_mask = d.swdma_mask = 0;
-       }
-
-       if (idx == 0)
-               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-
-static const struct pci_device_id alim15x3_pci_tbl[] = {
-       { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
-       { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
-
-static struct pci_driver alim15x3_pci_driver = {
-       .name           = "ALI15x3_IDE",
-       .id_table       = alim15x3_pci_tbl,
-       .probe          = alim15x3_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init ali15x3_ide_init(void)
-{
-       return ide_pci_register_driver(&alim15x3_pci_driver);
-}
-
-static void __exit ali15x3_ide_exit(void)
-{
-       pci_unregister_driver(&alim15x3_pci_driver);
-}
-
-module_init(ali15x3_ide_init);
-module_exit(ali15x3_ide_exit);
-
-MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
deleted file mode 100644 (file)
index 7340597..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
- * IDE driver for Linux.
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * Based on the work of:
- *      Andre Hedrick
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "amd74xx"
-
-enum {
-       AMD_IDE_CONFIG          = 0x41,
-       AMD_CABLE_DETECT        = 0x42,
-       AMD_DRIVE_TIMING        = 0x48,
-       AMD_8BIT_TIMING         = 0x4e,
-       AMD_ADDRESS_SETUP       = 0x4c,
-       AMD_UDMA_TIMING         = 0x50,
-};
-
-static unsigned int amd_80w;
-static unsigned int amd_clock;
-
-static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
-static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
-
-static inline u8 amd_offset(struct pci_dev *dev)
-{
-       return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
-}
-
-/*
- * amd_set_speed() writes timing values to the chipset registers
- */
-
-static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
-                         struct ide_timing *timing)
-{
-       u8 t = 0, offset = amd_offset(dev);
-
-       pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
-       t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-       pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
-
-       pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
-               ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
-
-       pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
-               ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
-
-       switch (udma_mask) {
-       case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
-       case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break;
-       case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break;
-       case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break;
-       default: return;
-       }
-
-       if (timing->udma)
-               pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t);
-}
-
-/*
- * amd_set_drive() computes timing values and configures the chipset
- * to a desired transfer mode.  It also can be called by upper layers.
- */
-
-static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       ide_drive_t *peer = ide_get_pair_dev(drive);
-       struct ide_timing t, p;
-       int T, UT;
-       u8 udma_mask = hwif->ultra_mask;
-       const u8 speed = drive->dma_mode;
-
-       T = 1000000000 / amd_clock;
-       UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
-
-       ide_timing_compute(drive, speed, &t, T, UT);
-
-       if (peer) {
-               ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
-               ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-       }
-
-       if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
-       if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
-
-       amd_set_speed(dev, drive->dn, udma_mask, &t);
-}
-
-/*
- * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
- */
-
-static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       amd_set_drive(hwif, drive);
-}
-
-static void amd7409_cable_detect(struct pci_dev *dev)
-{
-       /* no host side cable detection */
-       amd_80w = 0x03;
-}
-
-static void amd7411_cable_detect(struct pci_dev *dev)
-{
-       int i;
-       u32 u = 0;
-       u8 t = 0, offset = amd_offset(dev);
-
-       pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
-       pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
-       amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
-       for (i = 24; i >= 0; i -= 8)
-               if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
-                       printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set "
-                               "cable bits correctly. Enabling workaround.\n",
-                               pci_name(dev));
-                       amd_80w |= (1 << (1 - (i >> 4)));
-               }
-}
-
-/*
- * The initialization callback.  Initialize drive independent registers.
- */
-
-static int init_chipset_amd74xx(struct pci_dev *dev)
-{
-       u8 t = 0, offset = amd_offset(dev);
-
-/*
- * Check 80-wire cable presence.
- */
-
-       if (dev->vendor == PCI_VENDOR_ID_AMD &&
-           dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
-               ; /* no UDMA > 2 */
-       else if (dev->vendor == PCI_VENDOR_ID_AMD &&
-                dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
-               amd7409_cable_detect(dev);
-       else
-               amd7411_cable_detect(dev);
-
-/*
- * Take care of prefetch & postwrite.
- */
-
-       pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
-       /*
-        * Check for broken FIFO support.
-        */
-       if (dev->vendor == PCI_VENDOR_ID_AMD &&
-           dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
-               t &= 0x0f;
-       else
-               t |= 0xf0;
-       pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
-
-       return 0;
-}
-
-static u8 amd_cable_detect(ide_hwif_t *hwif)
-{
-       if ((amd_80w >> hwif->channel) & 1)
-               return ATA_CBL_PATA80;
-       else
-               return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops amd_port_ops = {
-       .set_pio_mode           = amd_set_pio_mode,
-       .set_dma_mode           = amd_set_drive,
-       .cable_detect           = amd_cable_detect,
-};
-
-#define IDE_HFLAGS_AMD \
-       (IDE_HFLAG_PIO_NO_BLACKLIST | \
-        IDE_HFLAG_POST_SET_MODE | \
-        IDE_HFLAG_IO_32BIT | \
-        IDE_HFLAG_UNMASK_IRQS)
-
-#define DECLARE_AMD_DEV(swdma, udma)                           \
-       {                                                               \
-               .name           = DRV_NAME,                             \
-               .init_chipset   = init_chipset_amd74xx,                 \
-               .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
-               .port_ops       = &amd_port_ops,                        \
-               .host_flags     = IDE_HFLAGS_AMD,                       \
-               .pio_mask       = ATA_PIO5,                             \
-               .swdma_mask     = swdma,                                \
-               .mwdma_mask     = ATA_MWDMA2,                           \
-               .udma_mask      = udma,                                 \
-       }
-
-#define DECLARE_NV_DEV(udma)                                   \
-       {                                                               \
-               .name           = DRV_NAME,                             \
-               .init_chipset   = init_chipset_amd74xx,                 \
-               .enablebits     = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
-               .port_ops       = &amd_port_ops,                        \
-               .host_flags     = IDE_HFLAGS_AMD,                       \
-               .pio_mask       = ATA_PIO5,                             \
-               .swdma_mask     = ATA_SWDMA2,                           \
-               .mwdma_mask     = ATA_MWDMA2,                           \
-               .udma_mask      = udma,                                 \
-       }
-
-static const struct ide_port_info amd74xx_chipsets[] = {
-       /* 0: AMD7401 */        DECLARE_AMD_DEV(0x00, ATA_UDMA2),
-       /* 1: AMD7409 */        DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4),
-       /* 2: AMD7411/7441 */   DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
-       /* 3: AMD8111 */        DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6),
-
-       /* 4: NFORCE */         DECLARE_NV_DEV(ATA_UDMA5),
-       /* 5: >= NFORCE2 */     DECLARE_NV_DEV(ATA_UDMA6),
-
-       /* 6: AMD5536 */        DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
-};
-
-static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-
-       d = amd74xx_chipsets[idx];
-
-       /*
-        * Check for bad SWDMA and incorrectly wired Serenade mainboards.
-        */
-       if (idx == 1) {
-               if (dev->revision <= 7)
-                       d.swdma_mask = 0;
-               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
-       } else if (idx == 3) {
-               if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
-                   dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
-                       d.udma_mask = ATA_UDMA5;
-       }
-
-       /*
-        * It seems that on some nVidia controllers using AltStatus
-        * register can be unreliable so default to Status register
-        * if the device is in Compatibility Mode.
-        */
-       if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
-           ide_pci_is_in_compatibility_mode(dev))
-               d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
-
-       printk(KERN_INFO "%s %s: UDMA%s controller\n",
-               d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
-
-       /*
-       * Determine the system bus clock.
-       */
-       amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
-
-       switch (amd_clock) {
-       case 33000: amd_clock = 33333; break;
-       case 37000: amd_clock = 37500; break;
-       case 41000: amd_clock = 41666; break;
-       }
-
-       if (amd_clock < 20000 || amd_clock > 50000) {
-               printk(KERN_WARNING "%s: User given PCI clock speed impossible"
-                                   " (%d), using 33 MHz instead.\n",
-                                   d.name, amd_clock);
-               amd_clock = 33333;
-       }
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id amd74xx_pci_tbl[] = {
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_COBRA_7401),           0 },
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_VIPER_7409),           1 },
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_VIPER_7411),           2 },
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_OPUS_7441),            2 },
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_8111_IDE),             3 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_IDE),        4 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE),       5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE),      5 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA),     5 },
-#endif
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE),       5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE),      5 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA),     5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2),    5 },
-#endif
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE),  5 },
-       { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE),  5 },
-       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_IDE),           6 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
-
-static struct pci_driver amd74xx_pci_driver = {
-       .name           = "AMD_IDE",
-       .id_table       = amd74xx_pci_tbl,
-       .probe          = amd74xx_probe,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init amd74xx_ide_init(void)
-{
-       return ide_pci_register_driver(&amd74xx_pci_driver);
-}
-
-static void __exit amd74xx_ide_exit(void)
-{
-       pci_unregister_driver(&amd74xx_pci_driver);
-}
-
-module_init(amd74xx_ide_init);
-module_exit(amd74xx_ide_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("AMD PCI IDE driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
deleted file mode 100644 (file)
index e08b0aa..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "atiixp"
-
-#define ATIIXP_IDE_PIO_TIMING          0x40
-#define ATIIXP_IDE_MDMA_TIMING         0x44
-#define ATIIXP_IDE_PIO_CONTROL         0x48
-#define ATIIXP_IDE_PIO_MODE            0x4a
-#define ATIIXP_IDE_UDMA_CONTROL                0x54
-#define ATIIXP_IDE_UDMA_MODE           0x56
-
-struct atiixp_ide_timing {
-       u8 command_width;
-       u8 recover_width;
-};
-
-static struct atiixp_ide_timing pio_timing[] = {
-       { 0x05, 0x0d },
-       { 0x04, 0x07 },
-       { 0x03, 0x04 },
-       { 0x02, 0x02 },
-       { 0x02, 0x00 },
-};
-
-static struct atiixp_ide_timing mdma_timing[] = {
-       { 0x07, 0x07 },
-       { 0x02, 0x01 },
-       { 0x02, 0x00 },
-};
-
-static DEFINE_SPINLOCK(atiixp_lock);
-
-/**
- *     atiixp_set_pio_mode     -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Set the interface PIO mode.
- */
-
-static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long flags;
-       int timing_shift = (drive->dn ^ 1) * 8;
-       u32 pio_timing_data;
-       u16 pio_mode_data;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       spin_lock_irqsave(&atiixp_lock, flags);
-
-       pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
-       pio_mode_data &= ~(0x07 << (drive->dn * 4));
-       pio_mode_data |= (pio << (drive->dn * 4));
-       pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
-
-       pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
-       pio_timing_data &= ~(0xff << timing_shift);
-       pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
-                (pio_timing[pio].command_width << (timing_shift + 4));
-       pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
-
-       spin_unlock_irqrestore(&atiixp_lock, flags);
-}
-
-/**
- *     atiixp_set_dma_mode     -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Set a ATIIXP host controller to the desired DMA mode.  This involves
- *     programming the right timing data into the PCI configuration space.
- */
-
-static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long flags;
-       int timing_shift = (drive->dn ^ 1) * 8;
-       u32 tmp32;
-       u16 tmp16;
-       u16 udma_ctl = 0;
-       const u8 speed = drive->dma_mode;
-
-       spin_lock_irqsave(&atiixp_lock, flags);
-
-       pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
-
-       if (speed >= XFER_UDMA_0) {
-               pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
-               tmp16 &= ~(0x07 << (drive->dn * 4));
-               tmp16 |= ((speed & 0x07) << (drive->dn * 4));
-               pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
-
-               udma_ctl |= (1 << drive->dn);
-       } else if (speed >= XFER_MW_DMA_0) {
-               u8 i = speed & 0x03;
-
-               pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
-               tmp32 &= ~(0xff << timing_shift);
-               tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
-                        (mdma_timing[i].command_width << (timing_shift + 4));
-               pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
-
-               udma_ctl &= ~(1 << drive->dn);
-       }
-
-       pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
-
-       spin_unlock_irqrestore(&atiixp_lock, flags);
-}
-
-static u8 atiixp_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       u8 udma_mode = 0, ch = hwif->channel;
-
-       pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
-
-       if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
-               return ATA_CBL_PATA80;
-       else
-               return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops atiixp_port_ops = {
-       .set_pio_mode           = atiixp_set_pio_mode,
-       .set_dma_mode           = atiixp_set_dma_mode,
-       .cable_detect           = atiixp_cable_detect,
-};
-
-static const struct ide_port_info atiixp_pci_info[] = {
-       {       /* 0: IXP200/300/400/700 */
-               .name           = DRV_NAME,
-               .enablebits     = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
-               .port_ops       = &atiixp_port_ops,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-       {       /* 1: IXP600 */
-               .name           = DRV_NAME,
-               .enablebits     = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
-               .port_ops       = &atiixp_port_ops,
-               .host_flags     = IDE_HFLAG_SINGLE,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-};
-
-/**
- *     atiixp_init_one -       called when a ATIIXP is found
- *     @dev: the atiixp device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-
-static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
-}
-
-static const struct pci_device_id atiixp_pci_tbl[] = {
-       { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
-       { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
-       { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
-       { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
-       { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
-       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
-
-static struct pci_driver atiixp_pci_driver = {
-       .name           = "ATIIXP_IDE",
-       .id_table       = atiixp_pci_tbl,
-       .probe          = atiixp_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init atiixp_ide_init(void)
-{
-       return ide_pci_register_driver(&atiixp_pci_driver);
-}
-
-static void __exit atiixp_ide_exit(void)
-{
-       pci_unregister_driver(&atiixp_pci_driver);
-}
-
-module_init(atiixp_ide_init);
-module_exit(atiixp_ide_exit);
-
-MODULE_AUTHOR("HUI YU");
-MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
deleted file mode 100644 (file)
index 46eaf58..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- *  Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- *     Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- *  This driver was written based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at
- *  http://www.jschoenfeld.com
- *
- *  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.
- *
- *  TODO:
- *    - test it :-)
- *    - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
-    /*
-     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
-     */
-
-#define BUDDHA_NUM_HWIFS       2
-#define CATWEASEL_NUM_HWIFS    3
-#define XSURF_NUM_HWIFS         2
-
-#define MAX_NUM_HWIFS          3
-
-    /*
-     *  Bases of the IDE interfaces (relative to the board address)
-     */
-
-#define BUDDHA_BASE1   0x800
-#define BUDDHA_BASE2   0xa00
-#define BUDDHA_BASE3   0xc00
-
-#define XSURF_BASE1     0xb000 /* 2.5" Interface */
-#define XSURF_BASE2     0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
-     XSURF_BASE1, XSURF_BASE2
-};
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define BUDDHA_CONTROL 0x11a
-
-    /*
-     *  Other registers
-     */
-
-#define BUDDHA_IRQ1    0xf00           /* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2    0xf40           /* interrupt */
-#define BUDDHA_IRQ3    0xf80
-
-#define XSURF_IRQ1      0x7e
-#define XSURF_IRQ2      0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
-    XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR  0xfc0           /* master interrupt enable */
-
-
-    /*
-     *  Board information
-     */
-
-typedef enum BuddhaType_Enum {
-    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int buddha_test_irq(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports.irq_addr);
-    if (!(ch & 0x80))
-           return 0;
-    return 1;
-}
-
-static void xsurf_clear_irq(ide_drive_t *drive)
-{
-    /*
-     * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0
-     */
-    z_writeb(0, drive->hwif->io_ports.irq_addr);
-}
-
-static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
-                                     unsigned long ctl, unsigned long irq_port)
-{
-       int i;
-
-       memset(hw, 0, sizeof(*hw));
-
-       hw->io_ports.data_addr = base;
-
-       for (i = 1; i < 8; i++)
-               hw->io_ports_array[i] = base + 2 + i * 4;
-
-       hw->io_ports.ctl_addr = ctl;
-       hw->io_ports.irq_addr = irq_port;
-
-       hw->irq = IRQ_AMIGA_PORTS;
-}
-
-static const struct ide_port_ops buddha_port_ops = {
-       .test_irq               = buddha_test_irq,
-};
-
-static const struct ide_port_ops xsurf_port_ops = {
-       .clear_irq              = xsurf_clear_irq,
-       .test_irq               = buddha_test_irq,
-};
-
-static const struct ide_port_info buddha_port_info = {
-       .port_ops               = &buddha_port_ops,
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_generic,
-};
-
-    /*
-     *  Probe for a Buddha or Catweasel IDE interface
-     */
-
-static int __init buddha_init(void)
-{
-       struct zorro_dev *z = NULL;
-       u_long buddha_board = 0;
-       BuddhaType type;
-       int buddha_num_hwifs, i;
-
-       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-               unsigned long board;
-               struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
-               struct ide_port_info d = buddha_port_info;
-
-               if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
-                       buddha_num_hwifs = BUDDHA_NUM_HWIFS;
-                       type=BOARD_BUDDHA;
-               } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
-                       buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
-                       type=BOARD_CATWEASEL;
-               } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
-                       buddha_num_hwifs = XSURF_NUM_HWIFS;
-                       type=BOARD_XSURF;
-                       d.port_ops = &xsurf_port_ops;
-               } else 
-                       continue;
-               
-               board = z->resource.start;
-
-               if(type != BOARD_XSURF) {
-                       if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
-                               continue;
-               } else {
-                       if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
-                               continue;
-                       if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
-                               goto fail_base2;
-                       if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
-                               release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
-                               release_mem_region(board+XSURF_BASE1, 0x1000);
-                               continue;
-                       }
-               }         
-               buddha_board = (unsigned long)ZTWO_VADDR(board);
-               
-               /* write to BUDDHA_IRQ_MR to enable the board IRQ */
-               /* X-Surf doesn't have this.  IRQs are always on */
-               if (type != BOARD_XSURF)
-                       z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-
-               printk(KERN_INFO "ide: %s IDE controller\n",
-                                buddha_board_name[type]);
-
-               for (i = 0; i < buddha_num_hwifs; i++) {
-                       unsigned long base, ctl, irq_port;
-
-                       if (type != BOARD_XSURF) {
-                               base = buddha_board + buddha_bases[i];
-                               ctl = base + BUDDHA_CONTROL;
-                               irq_port = buddha_board + buddha_irqports[i];
-                       } else {
-                               base = buddha_board + xsurf_bases[i];
-                               /* X-Surf has no CS1* (Control/AltStat) */
-                               ctl = 0;
-                               irq_port = buddha_board + xsurf_irqports[i];
-                       }
-
-                       buddha_setup_ports(&hw[i], base, ctl, irq_port);
-
-                       hws[i] = &hw[i];
-               }
-
-               ide_host_add(&d, hws, i, NULL);
-       }
-
-       return 0;
-}
-
-module_init(buddha_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
deleted file mode 100644 (file)
index f48decb..0000000
+++ /dev/null
@@ -1,848 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Original authors:  abramov@cecmow.enet.dec.com (Igor Abramov)
- *                     mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for the advanced features and bugs
- *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- *  These chips are basically fucked by design, and getting this driver
- *  to work on every motherboard design that uses this screwed chip seems
- *  bloody well impossible.  However, we're still trying.
- *
- *  Version 0.97 worked for everybody.
- *
- *  User feedback is essential.  Many thanks to the beta test team:
- *
- *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- *  liug@mama.indstate.edu, and others.
- *
- *  Version 0.01       Initial version, hacked out of ide.c,
- *                     and #include'd rather than compiled separately.
- *                     This will get cleaned up in a subsequent release.
- *
- *  Version 0.02       Fixes for vlb initialization code, enable prefetch
- *                     for versions 'B' and 'C' of chip by default,
- *                     some code cleanup.
- *
- *  Version 0.03       Added reset of secondary interface,
- *                     and black list for devices which are not compatible
- *                     with prefetch mode. Separate function for setting
- *                     prefetch is added, possibly it will be called some
- *                     day from ioctl processing code.
- *
- *  Version 0.04       Now configs/compiles separate from ide.c
- *
- *  Version 0.05       Major rewrite of interface timing code.
- *                     Added new function cmd640_set_mode to set PIO mode
- *                     from ioctl call. New drives added to black list.
- *
- *  Version 0.06       More code cleanup. Prefetch is enabled only for
- *                     detected hard drives, not included in prefetch
- *                     black list.
- *
- *  Version 0.07       Changed to more conservative drive tuning policy.
- *                     Unknown drives, which report PIO < 4 are set to
- *                     (reported_PIO - 1) if it is supported, or to PIO0.
- *                     List of known drives extended by info provided by
- *                     CMD at their ftp site.
- *
- *  Version 0.08       Added autotune/noautotune support.
- *
- *  Version 0.09       Try to be smarter about 2nd port enabling.
- *  Version 0.10       Be nice and don't reset 2nd port.
- *  Version 0.11       Try to handle more weird situations.
- *
- *  Version 0.12       Lots of bug fixes from Laszlo Peter
- *                     irq unmasking disabled for reliability.
- *                     try to be even smarter about the second port.
- *                     tidy up source code formatting.
- *  Version 0.13       permit irq unmasking again.
- *  Version 0.90       massive code cleanup, some bugs fixed.
- *                     defaults all drives to PIO mode0, prefetch off.
- *                     autotune is OFF by default, with compile time flag.
- *                     prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- *                      (requires hdparm-3.1 or newer)
- *  Version 0.91       first release to linux-kernel list.
- *  Version 0.92       move initial reg dump to separate callable function
- *                     change "readahead" to "prefetch" to avoid confusion
- *  Version 0.95       respect original BIOS timings unless autotuning.
- *                     tons of code cleanup and rearrangement.
- *                     added CONFIG_BLK_DEV_CMD640_ENHANCED option
- *                     prevent use of unmask when prefetch is on
- *  Version 0.96       prevent use of io_32bit when prefetch is off
- *  Version 0.97       fix VLB secondary interface for sjd@slip.net
- *                     other minor tune-ups:  0.96 was very good.
- *  Version 0.98       ignore PCI version when disabled by BIOS
- *  Version 0.99       display setup/active/recovery clocks with PIO mode
- *  Version 1.00       Mmm.. cannot depend on PCMD_ENA in all systems
- *  Version 1.01       slow/fast devsel can be selected with "hdparm -p6/-p7"
- *                      ("fast" is necessary for 32bit I/O in some systems)
- *  Version 1.02       fix bug that resulted in slow "setup times"
- *                      (patch courtesy of Zoltan Hidvegi)
- */
-
-#define CMD640_PREFETCH_MASKS 1
-
-/*#define CMD640_DUMP_REGS */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cmd640"
-
-static bool cmd640_vlb;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID            0x00
-#define DID            0x02
-#define PCMD           0x04
-#define   PCMD_ENA     0x01
-#define PSTTS          0x06
-#define REVID          0x08
-#define PROGIF         0x09
-#define SUBCL          0x0a
-#define BASCL          0x0b
-#define BaseA0         0x10
-#define BaseA1         0x14
-#define BaseA2         0x18
-#define BaseA3         0x1c
-#define INTLINE                0x3c
-#define INPINE         0x3d
-
-#define        CFR             0x50
-#define   CFR_DEVREV           0x03
-#define   CFR_IDE01INTR                0x04
-#define          CFR_DEVID             0x18
-#define          CFR_AT_VESA_078h      0x20
-#define          CFR_DSA1              0x40
-#define          CFR_DSA0              0x80
-
-#define CNTRL          0x51
-#define          CNTRL_DIS_RA0         0x40
-#define   CNTRL_DIS_RA1                0x80
-#define          CNTRL_ENA_2ND         0x08
-
-#define        CMDTIM          0x52
-#define        ARTTIM0         0x53
-#define        DRWTIM0         0x54
-#define ARTTIM1        0x55
-#define DRWTIM1                0x56
-#define ARTTIM23       0x57
-#define   ARTTIM23_DIS_RA2     0x04
-#define   ARTTIM23_DIS_RA3     0x08
-#define   ARTTIM23_IDE23INTR   0x10
-#define DRWTIM23       0x58
-#define BRST           0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-static DEFINE_SPINLOCK(cmd640_lock);
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*__put_cmd640_reg)(u16 reg, u8 val);
-static u8 (*__get_cmd640_reg)(u16 reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1(u16 reg, u8 val)
-{
-       outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-       outb_p(val, (reg & 3) | 0xcfc);
-}
-
-static u8 get_cmd640_reg_pci1(u16 reg)
-{
-       outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-       return inb_p((reg & 3) | 0xcfc);
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2(u16 reg, u8 val)
-{
-       outb_p(0x10, 0xcf8);
-       outb_p(val, cmd640_key + reg);
-       outb_p(0, 0xcf8);
-}
-
-static u8 get_cmd640_reg_pci2(u16 reg)
-{
-       u8 b;
-
-       outb_p(0x10, 0xcf8);
-       b = inb_p(cmd640_key + reg);
-       outb_p(0, 0xcf8);
-       return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb(u16 reg, u8 val)
-{
-       outb_p(reg, cmd640_key);
-       outb_p(val, cmd640_key + 4);
-}
-
-static u8 get_cmd640_reg_vlb(u16 reg)
-{
-       outb_p(reg, cmd640_key);
-       return inb_p(cmd640_key + 4);
-}
-
-static u8 get_cmd640_reg(u16 reg)
-{
-       unsigned long flags;
-       u8 b;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-       b = __get_cmd640_reg(reg);
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-       return b;
-}
-
-static void put_cmd640_reg(u16 reg, u8 val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-       __put_cmd640_reg(reg, val);
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-static int __init match_pci_cmd640_device(void)
-{
-       const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
-       unsigned int i;
-       for (i = 0; i < 4; i++) {
-               if (get_cmd640_reg(i) != ven_dev[i])
-                       return 0;
-       }
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
-       if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
-               printk("ide: cmd640 on PCI disabled by BIOS\n");
-               return 0;
-       }
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
-       return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1(void)
-{
-       __get_cmd640_reg = get_cmd640_reg_pci1;
-       __put_cmd640_reg = put_cmd640_reg_pci1;
-       for (cmd640_key = 0x80000000;
-            cmd640_key <= 0x8000f800;
-            cmd640_key += 0x800) {
-               if (match_pci_cmd640_device())
-                       return 1; /* success */
-       }
-       return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2(void)
-{
-       __get_cmd640_reg = get_cmd640_reg_pci2;
-       __put_cmd640_reg = put_cmd640_reg_pci2;
-       for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
-               if (match_pci_cmd640_device())
-                       return 1; /* success */
-       }
-       return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb(void)
-{
-       u8 b;
-
-       __get_cmd640_reg = get_cmd640_reg_vlb;
-       __put_cmd640_reg = put_cmd640_reg_vlb;
-       cmd640_key = 0x178;
-       b = get_cmd640_reg(CFR);
-       if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
-               cmd640_key = 0x78;
-               b = get_cmd640_reg(CFR);
-               if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
-                       return 0;
-       }
-       return 1; /* success */
-}
-
-/*
- *  Returns 1 if an IDE interface/drive exists at 0x170,
- *  Returns 0 otherwise.
- */
-static int __init secondary_port_responding(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-
-       outb_p(0x0a, 0x176);    /* select drive0 */
-       udelay(100);
-       if ((inb_p(0x176) & 0x1f) != 0x0a) {
-               outb_p(0x1a, 0x176); /* select drive1 */
-               udelay(100);
-               if ((inb_p(0x176) & 0x1f) != 0x1a) {
-                       spin_unlock_irqrestore(&cmd640_lock, flags);
-                       return 0; /* nothing responded */
-               }
-       }
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-       return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers.  May be called from ide.c
- */
-static void cmd640_dump_regs(void)
-{
-       unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
-       /* Dump current state of chip registers */
-       printk("ide: cmd640 internal register dump:");
-       for (; reg <= 0x59; reg++) {
-               if (!(reg & 0x0f))
-                       printk("\n%04x:", reg);
-               printk(" %02x", get_cmd640_reg(reg));
-       }
-       printk("\n");
-}
-#endif
-
-static void __set_prefetch_mode(ide_drive_t *drive, int mode)
-{
-       if (mode) {     /* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-               drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
-               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-#endif
-               drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
-       } else {
-               drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
-               drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
-               drive->io_32bit = 0;
-       }
-}
-
-#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
-{
-       u8 b = get_cmd640_reg(prefetch_regs[index]);
-
-       __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
-}
-#else
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
-{
-       unsigned long flags;
-       int reg = prefetch_regs[index];
-       u8 b;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-       b = __get_cmd640_reg(reg);
-       __set_prefetch_mode(drive, mode);
-       if (mode)
-               b &= ~prefetch_masks[index];    /* enable prefetch */
-       else
-               b |= prefetch_masks[index];     /* disable prefetch */
-       __put_cmd640_reg(reg, b);
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks(unsigned int index)
-{
-       u8 active_count, recovery_count;
-
-       active_count = active_counts[index];
-       if (active_count == 1)
-               ++active_count;
-       recovery_count = recovery_counts[index];
-       if (active_count > 3 && recovery_count == 1)
-               ++recovery_count;
-       if (cmd640_chip_version > 1)
-               recovery_count += 1;  /* cmd640b uses (count + 1)*/
-       printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-static inline u8 pack_nibbles(u8 upper, u8 lower)
-{
-       return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts(ide_drive_t *drive, unsigned int index)
-{
-       unsigned long flags;
-       u8 setup_count    = setup_counts[index];
-       u8 active_count   = active_counts[index];
-       u8 recovery_count = recovery_counts[index];
-
-       /*
-        * Set up address setup count and drive read/write timing registers.
-        * Primary interface has individual count/timing registers for
-        * each drive.  Secondary interface has one common set of registers,
-        * so we merge the timings, using the slowest value for each timing.
-        */
-       if (index > 1) {
-               ide_drive_t *peer = ide_get_pair_dev(drive);
-               unsigned int mate = index ^ 1;
-
-               if (peer) {
-                       if (setup_count < setup_counts[mate])
-                               setup_count = setup_counts[mate];
-                       if (active_count < active_counts[mate])
-                               active_count = active_counts[mate];
-                       if (recovery_count < recovery_counts[mate])
-                               recovery_count = recovery_counts[mate];
-               }
-       }
-
-       /*
-        * Convert setup_count to internal chipset representation
-        */
-       switch (setup_count) {
-       case 4:  setup_count = 0x00; break;
-       case 3:  setup_count = 0x80; break;
-       case 1:
-       case 2:  setup_count = 0x40; break;
-       default: setup_count = 0xc0; /* case 5 */
-       }
-
-       /*
-        * Now that everything is ready, program the new timings
-        */
-       spin_lock_irqsave(&cmd640_lock, flags);
-       /*
-        * Program the address_setup clocks into ARTTIM reg,
-        * and then the active/recovery counts into the DRWTIM reg
-        * (this converts counts of 16 into counts of zero -- okay).
-        */
-       setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
-       __put_cmd640_reg(arttim_regs[index], setup_count);
-       __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
-                           u8 pio_mode, unsigned int cycle_time)
-{
-       struct ide_timing *t;
-       int setup_time, active_time, recovery_time, clock_time;
-       u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-       int bus_speed;
-
-       if (cmd640_vlb)
-               bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
-       else
-               bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-
-       if (pio_mode > 5)
-               pio_mode = 5;
-
-       t = ide_timing_find_mode(XFER_PIO_0 + pio_mode);
-       setup_time  = t->setup;
-       active_time = t->active;
-
-       recovery_time = cycle_time - (setup_time + active_time);
-       clock_time = 1000 / bus_speed;
-       cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
-
-       setup_count = DIV_ROUND_UP(setup_time, clock_time);
-
-       active_count = DIV_ROUND_UP(active_time, clock_time);
-       if (active_count < 2)
-               active_count = 2; /* minimum allowed by cmd640 */
-
-       recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
-       recovery_count2 = cycle_count - (setup_count + active_count);
-       if (recovery_count2 > recovery_count)
-               recovery_count = recovery_count2;
-       if (recovery_count < 2)
-               recovery_count = 2; /* minimum allowed by cmd640 */
-       if (recovery_count > 17) {
-               active_count += recovery_count - 17;
-               recovery_count = 17;
-       }
-       if (active_count > 16)
-               active_count = 16; /* maximum allowed by cmd640 */
-       if (cmd640_chip_version > 1)
-               recovery_count -= 1;  /* cmd640b uses (count + 1)*/
-       if (recovery_count > 16)
-               recovery_count = 16; /* maximum allowed by cmd640 */
-
-       setup_counts[index]    = setup_count;
-       active_counts[index]   = active_count;
-       recovery_counts[index] = recovery_count;
-
-       /*
-        * In a perfect world, we might set the drive pio mode here
-        * (using WIN_SETFEATURE) before continuing.
-        *
-        * But we do not, because:
-        *      1) this is the wrong place to do it (proper is do_special() in ide.c)
-        *      2) in practice this is rarely, if ever, necessary
-        */
-       program_drive_counts(drive, index);
-}
-
-static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned int index = 0, cycle_time;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       u8 b;
-
-       switch (pio) {
-       case 6: /* set fast-devsel off */
-       case 7: /* set fast-devsel on */
-               b = get_cmd640_reg(CNTRL) & ~0x27;
-               if (pio & 1)
-                       b |= 0x27;
-               put_cmd640_reg(CNTRL, b);
-               printk("%s: %sabled cmd640 fast host timing (devsel)\n",
-                       drive->name, (pio & 1) ? "en" : "dis");
-               return;
-       case 8: /* set prefetch off */
-       case 9: /* set prefetch on */
-               set_prefetch_mode(drive, index, pio & 1);
-               printk("%s: %sabled cmd640 prefetch\n",
-                       drive->name, (pio & 1) ? "en" : "dis");
-               return;
-       }
-
-       cycle_time = ide_pio_cycle_time(drive, pio);
-       cmd640_set_mode(drive, index, pio, cycle_time);
-
-       printk("%s: selected cmd640 PIO mode%d (%dns)",
-               drive->name, pio, cycle_time);
-
-       display_clocks(index);
-}
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-static void __init cmd640_init_dev(ide_drive_t *drive)
-{
-       unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-       /*
-        * Reset timing to the slowest speed and turn off prefetch.
-        * This way, the drive identify code has a better chance.
-        */
-       setup_counts[i]    =  4;        /* max possible */
-       active_counts[i]   = 16;        /* max possible */
-       recovery_counts[i] = 16;        /* max possible */
-       program_drive_counts(drive, i);
-       set_prefetch_mode(drive, i, 0);
-       printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared\n", i);
-#else
-       /*
-        * Set the drive unmask flags to match the prefetch setting.
-        */
-       check_prefetch(drive, i);
-       printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n",
-               i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-}
-
-static int cmd640_test_irq(ide_hwif_t *hwif)
-{
-       int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
-       u8  irq_mask            = hwif->channel ? ARTTIM23_IDE23INTR :
-                                                 CFR_IDE01INTR;
-       u8  irq_stat            = get_cmd640_reg(irq_reg);
-
-       return (irq_stat & irq_mask) ? 1 : 0;
-}
-
-static const struct ide_port_ops cmd640_port_ops = {
-       .init_dev               = cmd640_init_dev,
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-       .set_pio_mode           = cmd640_set_pio_mode,
-#endif
-       .test_irq               = cmd640_test_irq,
-};
-
-static int pci_conf1(void)
-{
-       unsigned long flags;
-       u32 tmp;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-       outb(0x01, 0xCFB);
-       tmp = inl(0xCF8);
-       outl(0x80000000, 0xCF8);
-       if (inl(0xCF8) == 0x80000000) {
-               outl(tmp, 0xCF8);
-               spin_unlock_irqrestore(&cmd640_lock, flags);
-               return 1;
-       }
-       outl(tmp, 0xCF8);
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-       return 0;
-}
-
-static int pci_conf2(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cmd640_lock, flags);
-       outb(0x00, 0xCFB);
-       outb(0x00, 0xCF8);
-       outb(0x00, 0xCFA);
-       if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
-               spin_unlock_irqrestore(&cmd640_lock, flags);
-               return 1;
-       }
-       spin_unlock_irqrestore(&cmd640_lock, flags);
-       return 0;
-}
-
-static const struct ide_port_info cmd640_port_info __initconst = {
-       .chipset                = ide_cmd640,
-       .host_flags             = IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_NO_DMA |
-                                 IDE_HFLAG_ABUSE_PREFETCH |
-                                 IDE_HFLAG_ABUSE_FAST_DEVSEL,
-       .port_ops               = &cmd640_port_ops,
-       .pio_mask               = ATA_PIO5,
-};
-
-static int __init cmd640x_init_one(unsigned long base, unsigned long ctl)
-{
-       if (!request_region(base, 8, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               DRV_NAME, base, base + 7);
-               return -EBUSY;
-       }
-
-       if (!request_region(ctl, 1, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               DRV_NAME, ctl);
-               release_region(base, 8);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.
- */
-static int __init cmd640x_init(void)
-{
-       int second_port_cmd640 = 0, rc;
-       const char *bus_type, *port2;
-       u8 b, cfr;
-       struct ide_hw hw[2], *hws[2];
-
-       if (cmd640_vlb && probe_for_cmd640_vlb()) {
-               bus_type = "VLB";
-       } else {
-               cmd640_vlb = 0;
-               /* Find out what kind of PCI probing is supported otherwise
-                  Justin Gibbs will sulk.. */
-               if (pci_conf1() && probe_for_cmd640_pci1())
-                       bus_type = "PCI (type1)";
-               else if (pci_conf2() && probe_for_cmd640_pci2())
-                       bus_type = "PCI (type2)";
-               else
-                       return 0;
-       }
-       /*
-        * Undocumented magic (there is no 0x5b reg in specs)
-        */
-       put_cmd640_reg(0x5b, 0xbd);
-       if (get_cmd640_reg(0x5b) != 0xbd) {
-               printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
-               return 0;
-       }
-       put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
-       cmd640_dump_regs();
-#endif
-
-       /*
-        * Documented magic begins here
-        */
-       cfr = get_cmd640_reg(CFR);
-       cmd640_chip_version = cfr & CFR_DEVREV;
-       if (cmd640_chip_version == 0) {
-               printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
-               return 0;
-       }
-
-       rc = cmd640x_init_one(0x1f0, 0x3f6);
-       if (rc)
-               return rc;
-
-       rc = cmd640x_init_one(0x170, 0x376);
-       if (rc) {
-               release_region(0x3f6, 1);
-               release_region(0x1f0, 8);
-               return rc;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-
-       ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
-       hw[0].irq = 14;
-
-       ide_std_init_ports(&hw[1], 0x170, 0x376);
-       hw[1].irq = 15;
-
-       printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
-                        "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
-
-       /*
-        * Initialize data for primary port
-        */
-       hws[0] = &hw[0];
-
-       /*
-        * Ensure compatibility by always using the slowest timings
-        * for access to the drive's command register block,
-        * and reset the prefetch burstsize to default (512 bytes).
-        *
-        * Maybe we need a way to NOT do these on *some* systems?
-        */
-       put_cmd640_reg(CMDTIM, 0);
-       put_cmd640_reg(BRST, 0x40);
-
-       b = get_cmd640_reg(CNTRL);
-
-       /*
-        * Try to enable the secondary interface, if not already enabled
-        */
-       if (secondary_port_responding()) {
-               if ((b & CNTRL_ENA_2ND)) {
-                       second_port_cmd640 = 1;
-                       port2 = "okay";
-               } else if (cmd640_vlb) {
-                       second_port_cmd640 = 1;
-                       port2 = "alive";
-               } else
-                       port2 = "not cmd640";
-       } else {
-               put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
-               if (secondary_port_responding()) {
-                       second_port_cmd640 = 1;
-                       port2 = "enabled";
-               } else {
-                       put_cmd640_reg(CNTRL, b); /* restore original setting */
-                       port2 = "not responding";
-               }
-       }
-
-       /*
-        * Initialize data for secondary cmd640 port, if enabled
-        */
-       if (second_port_cmd640)
-               hws[1] = &hw[1];
-
-       printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n",
-                        second_port_cmd640 ? "" : "not ", port2);
-
-#ifdef CMD640_DUMP_REGS
-       cmd640_dump_regs();
-#endif
-
-       return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
-                           NULL);
-}
-
-module_param_named(probe_vlb, cmd640_vlb, bool, 0);
-MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
-
-module_init(cmd640x_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
deleted file mode 100644 (file)
index 943bf94..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Due to massive hardware bugs, UltraDMA is only supported
- *           on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998          Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998          David S. Miller (davem@redhat.com)
- *
- * Copyright (C) 1999-2002     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007-2010     Bartlomiej Zolnierkiewicz
- * Copyright (C) 2007,2009     MontaVista Software, Inc. <source@mvista.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cmd64x"
-
-/*
- * CMD64x specific registers definition.
- */
-#define CFR            0x50
-#define   CFR_INTR_CH0         0x04
-
-#define        CMDTIM          0x52
-#define        ARTTIM0         0x53
-#define        DRWTIM0         0x54
-#define ARTTIM1        0x55
-#define DRWTIM1                0x56
-#define ARTTIM23       0x57
-#define   ARTTIM23_DIS_RA2     0x04
-#define   ARTTIM23_DIS_RA3     0x08
-#define   ARTTIM23_INTR_CH1    0x10
-#define DRWTIM2                0x58
-#define BRST           0x59
-#define DRWTIM3                0x5b
-
-#define BMIDECR0       0x70
-#define MRDMODE                0x71
-#define   MRDMODE_INTR_CH0     0x04
-#define   MRDMODE_INTR_CH1     0x08
-#define UDIDETCR0      0x73
-#define DTPR0          0x74
-#define BMIDECR1       0x78
-#define BMIDECSR       0x79
-#define UDIDETCR1      0x7B
-#define DTPR1          0x7C
-
-static void cmd64x_program_timings(ide_drive_t *drive, u8 mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-       const unsigned long T = 1000000 / bus_speed;
-       static const u8 recovery_values[] =
-               {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-       static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-       static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-       static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
-       struct ide_timing t;
-       u8 arttim = 0;
-
-       if (drive->dn >= ARRAY_SIZE(drwtim_regs))
-               return;
-
-       ide_timing_compute(drive, mode, &t, T, 0);
-
-       /*
-        * In case we've got too long recovery phase, try to lengthen
-        * the active phase
-        */
-       if (t.recover > 16) {
-               t.active += t.recover - 16;
-               t.recover = 16;
-       }
-       if (t.active > 16)              /* shouldn't actually happen... */
-               t.active = 16;
-
-       /*
-        * Convert values to internal chipset representation
-        */
-       t.recover = recovery_values[t.recover];
-       t.active &= 0x0f;
-
-       /* Program the active/recovery counts into the DRWTIM register */
-       pci_write_config_byte(dev, drwtim_regs[drive->dn],
-                             (t.active << 4) | t.recover);
-
-       /*
-        * The primary channel has individual address setup timing registers
-        * for each drive and the hardware selects the slowest timing itself.
-        * The secondary channel has one common register and we have to select
-        * the slowest address setup timing ourselves.
-        */
-       if (hwif->channel) {
-               ide_drive_t *pair = ide_get_pair_dev(drive);
-
-               if (pair) {
-                       struct ide_timing tp;
-
-                       ide_timing_compute(pair, pair->pio_mode, &tp, T, 0);
-                       ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP);
-                       if (pair->dma_mode) {
-                               ide_timing_compute(pair, pair->dma_mode,
-                                               &tp, T, 0);
-                               ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP);
-                       }
-               }
-       }
-
-       if (t.setup > 5)                /* shouldn't actually happen... */
-               t.setup = 5;
-
-       /*
-        * Program the address setup clocks into the ARTTIM registers.
-        * Avoid clearing the secondary channel's interrupt bit.
-        */
-       (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
-       if (hwif->channel)
-               arttim &= ~ARTTIM23_INTR_CH1;
-       arttim &= ~0xc0;
-       arttim |= setup_values[t.setup];
-       (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
-}
-
-/*
- * Attempts to set drive's PIO mode.
- * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
- */
-
-static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       /*
-        * Filter out the prefetch control values
-        * to prevent PIO5 from being programmed
-        */
-       if (pio == 8 || pio == 9)
-               return;
-
-       cmd64x_program_timings(drive, XFER_PIO_0 + pio);
-}
-
-static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 unit                 = drive->dn & 0x01;
-       u8 regU = 0, pciU       = hwif->channel ? UDIDETCR1 : UDIDETCR0;
-       const u8 speed          = drive->dma_mode;
-
-       pci_read_config_byte(dev, pciU, &regU);
-       regU &= ~(unit ? 0xCA : 0x35);
-
-       switch(speed) {
-       case XFER_UDMA_5:
-               regU |= unit ? 0x0A : 0x05;
-               break;
-       case XFER_UDMA_4:
-               regU |= unit ? 0x4A : 0x15;
-               break;
-       case XFER_UDMA_3:
-               regU |= unit ? 0x8A : 0x25;
-               break;
-       case XFER_UDMA_2:
-               regU |= unit ? 0x42 : 0x11;
-               break;
-       case XFER_UDMA_1:
-               regU |= unit ? 0x82 : 0x21;
-               break;
-       case XFER_UDMA_0:
-               regU |= unit ? 0xC2 : 0x31;
-               break;
-       case XFER_MW_DMA_2:
-       case XFER_MW_DMA_1:
-       case XFER_MW_DMA_0:
-               cmd64x_program_timings(drive, speed);
-               break;
-       }
-
-       pci_write_config_byte(dev, pciU, regU);
-}
-
-static void cmd648_clear_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long base      = pci_resource_start(dev, 4);
-       u8  irq_mask            = hwif->channel ? MRDMODE_INTR_CH1 :
-                                                 MRDMODE_INTR_CH0;
-       u8  mrdmode             = inb(base + 1);
-
-       /* clear the interrupt bit */
-       outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
-            base + 1);
-}
-
-static void cmd64x_clear_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
-       u8  irq_mask            = hwif->channel ? ARTTIM23_INTR_CH1 :
-                                                 CFR_INTR_CH0;
-       u8  irq_stat            = 0;
-
-       (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
-       /* clear the interrupt bit */
-       (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
-}
-
-static int cmd648_test_irq(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long base      = pci_resource_start(dev, 4);
-       u8 irq_mask             = hwif->channel ? MRDMODE_INTR_CH1 :
-                                                 MRDMODE_INTR_CH0;
-       u8 mrdmode              = inb(base + 1);
-
-       pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n",
-                hwif->name, mrdmode, irq_mask);
-
-       return (mrdmode & irq_mask) ? 1 : 0;
-}
-
-static int cmd64x_test_irq(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
-       u8  irq_mask            = hwif->channel ? ARTTIM23_INTR_CH1 :
-                                                 CFR_INTR_CH0;
-       u8  irq_stat            = 0;
-
-       (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
-
-       pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n",
-                hwif->name, irq_stat, irq_mask);
-
-       return (irq_stat & irq_mask) ? 1 : 0;
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-
-static int cmd646_1_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat = 0, dma_cmd = 0;
-
-       /* get DMA status */
-       dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-       /* read DMA command state */
-       dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-       /* stop DMA */
-       outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-       /* clear the INTR & ERROR bits */
-       outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
-       /* verify good DMA status */
-       return (dma_stat & 7) != 4;
-}
-
-static int init_chipset_cmd64x(struct pci_dev *dev)
-{
-       u8 mrdmode = 0;
-
-       /* Set a good latency timer and cache line size value. */
-       (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-       /* FIXME: pci_set_master() to ensure a good latency timer value */
-
-       /*
-        * Enable interrupts, select MEMORY READ LINE for reads.
-        *
-        * NOTE: although not mentioned in the PCI0646U specs,
-        * bits 0-1 are write only and won't be read back as
-        * set or not -- PCI0646U2 specs clarify this point.
-        */
-       (void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
-       mrdmode &= ~0x30;
-       (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
-
-       return 0;
-}
-
-static u8 cmd64x_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
-       u8 bmidecsr = 0, mask   = hwif->channel ? 0x02 : 0x01;
-
-       switch (dev->device) {
-       case PCI_DEVICE_ID_CMD_648:
-       case PCI_DEVICE_ID_CMD_649:
-               pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
-               return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-       default:
-               return ATA_CBL_PATA40;
-       }
-}
-
-static const struct ide_port_ops cmd64x_port_ops = {
-       .set_pio_mode           = cmd64x_set_pio_mode,
-       .set_dma_mode           = cmd64x_set_dma_mode,
-       .clear_irq              = cmd64x_clear_irq,
-       .test_irq               = cmd64x_test_irq,
-       .cable_detect           = cmd64x_cable_detect,
-};
-
-static const struct ide_port_ops cmd648_port_ops = {
-       .set_pio_mode           = cmd64x_set_pio_mode,
-       .set_dma_mode           = cmd64x_set_dma_mode,
-       .clear_irq              = cmd648_clear_irq,
-       .test_irq               = cmd648_test_irq,
-       .cable_detect           = cmd64x_cable_detect,
-};
-
-static const struct ide_dma_ops cmd646_rev1_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = cmd646_1_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info cmd64x_chipsets[] = {
-       {       /* 0: CMD643 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_cmd64x,
-               .enablebits     = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
-               .port_ops       = &cmd64x_port_ops,
-               .host_flags     = IDE_HFLAG_CLEAR_SIMPLEX |
-                                 IDE_HFLAG_ABUSE_PREFETCH |
-                                 IDE_HFLAG_SERIALIZE,
-               .pio_mask       = ATA_PIO5,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = 0x00, /* no udma */
-       },
-       {       /* 1: CMD646 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_cmd64x,
-               .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
-               .port_ops       = &cmd648_port_ops,
-               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH |
-                                 IDE_HFLAG_SERIALIZE,
-               .pio_mask       = ATA_PIO5,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA2,
-       },
-       {       /* 2: CMD648 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_cmd64x,
-               .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
-               .port_ops       = &cmd648_port_ops,
-               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH,
-               .pio_mask       = ATA_PIO5,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA4,
-       },
-       {       /* 3: CMD649 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_cmd64x,
-               .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
-               .port_ops       = &cmd648_port_ops,
-               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH,
-               .pio_mask       = ATA_PIO5,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       }
-};
-
-static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-
-       d = cmd64x_chipsets[idx];
-
-       if (idx == 1) {
-               /*
-                * UltraDMA only supported on PCI646U and PCI646U2, which
-                * correspond to revisions 0x03, 0x05 and 0x07 respectively.
-                * Actually, although the CMD tech support people won't
-                * tell me the details, the 0x03 revision cannot support
-                * UDMA correctly without hardware modifications, and even
-                * then it only works with Quantum disks due to some
-                * hold time assumptions in the 646U part which are fixed
-                * in the 646U2.
-                *
-                * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-                */
-               if (dev->revision < 5) {
-                       d.udma_mask = 0x00;
-                       /*
-                        * The original PCI0646 didn't have the primary
-                        * channel enable bit, it appeared starting with
-                        * PCI0646U (i.e. revision ID 3).
-                        */
-                       if (dev->revision < 3) {
-                               d.enablebits[0].reg = 0;
-                               d.port_ops = &cmd64x_port_ops;
-                               if (dev->revision == 1)
-                                       d.dma_ops = &cmd646_rev1_dma_ops;
-                       }
-               }
-       }
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id cmd64x_pci_tbl[] = {
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
-
-static struct pci_driver cmd64x_pci_driver = {
-       .name           = "CMD64x_IDE",
-       .id_table       = cmd64x_pci_tbl,
-       .probe          = cmd64x_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init cmd64x_ide_init(void)
-{
-       return ide_pci_register_driver(&cmd64x_pci_driver);
-}
-
-static void __exit cmd64x_ide_exit(void)
-{
-       pci_unregister_driver(&cmd64x_pci_driver);
-}
-
-module_init(cmd64x_ide_init);
-module_exit(cmd64x_ide_exit);
-
-MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
deleted file mode 100644 (file)
index 89a4ff1..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- *     IDE tuning and bus mastering support for the CS5510/CS5520
- *     chipsets
- *
- *     The CS5510/CS5520 are slightly unusual devices. Unlike the 
- *     typical IDE controllers they do bus mastering with the drive in
- *     PIO mode and smarter silicon.
- *
- *     The practical upshot of this is that we must always tune the
- *     drive for the right PIO mode. We must also ignore all the blacklists
- *     and the drive bus mastering DMA information.
- *
- *     *** This driver is strictly experimental ***
- *
- *     (c) Copyright Red Hat Inc 2002
- * 
- * 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, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-
-#define DRV_NAME "cs5520"
-
-struct pio_clocks
-{
-       int address;
-       int assert;
-       int recovery;
-};
-
-static struct pio_clocks cs5520_pio_clocks[]={
-       {3, 6, 11},
-       {2, 5, 6},
-       {1, 4, 3},
-       {1, 3, 2},
-       {1, 2, 1}
-};
-
-static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       int controller = drive->dn > 1 ? 1 : 0;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       /* 8bit CAT/CRT - 8bit command timing for channel */
-       pci_write_config_byte(pdev, 0x62 + controller, 
-               (cs5520_pio_clocks[pio].recovery << 4) |
-               (cs5520_pio_clocks[pio].assert));
-
-       /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */
-
-       /* FIXME: should these use address ? */
-       /* Data read timing */
-       pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1),
-               (cs5520_pio_clocks[pio].recovery << 4) |
-               (cs5520_pio_clocks[pio].assert));
-       /* Write command timing */
-       pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
-               (cs5520_pio_clocks[pio].recovery << 4) |
-               (cs5520_pio_clocks[pio].assert));
-}
-
-static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       printk(KERN_ERR "cs55x0: bad ide timing.\n");
-
-       drive->pio_mode = XFER_PIO_0 + 0;
-       cs5520_set_pio_mode(hwif, drive);
-}
-
-static const struct ide_port_ops cs5520_port_ops = {
-       .set_pio_mode           = cs5520_set_pio_mode,
-       .set_dma_mode           = cs5520_set_dma_mode,
-};
-
-static const struct ide_port_info cyrix_chipset = {
-       .name           = DRV_NAME,
-       .enablebits     = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } },
-       .port_ops       = &cs5520_port_ops,
-       .host_flags     = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520,
-       .pio_mask       = ATA_PIO4,
-};
-
-/*
- *     The 5510/5520 are a bit weird. They don't quite set up the way
- *     the PCI helper layer expects so we must do much of the set up 
- *     work longhand.
- */
-static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       const struct ide_port_info *d = &cyrix_chipset;
-       struct ide_hw hw[2], *hws[] = { NULL, NULL };
-
-       ide_setup_pci_noise(dev, d);
-
-       /* We must not grab the entire device, it has 'ISA' space in its
-        * BARS too and we will freak out other bits of the kernel
-        */
-       if (pci_enable_device_io(dev)) {
-               printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
-               return -ENODEV;
-       }
-       pci_set_master(dev);
-       if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) {
-               printk(KERN_WARNING "%s: No suitable DMA available.\n",
-                       d->name);
-               return -ENODEV;
-       }
-
-       /*
-        *      Now the chipset is configured we can let the core
-        *      do all the device setup for us
-        */
-
-       ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
-       hw[0].irq = 14;
-       hw[1].irq = 15;
-
-       return ide_host_add(d, hws, 2, NULL);
-}
-
-static const struct pci_device_id cs5520_pci_tbl[] = {
-       { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 },
-       { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
-
-static struct pci_driver cs5520_pci_driver = {
-       .name           = "Cyrix_IDE",
-       .id_table       = cs5520_pci_tbl,
-       .probe          = cs5520_init_one,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init cs5520_ide_init(void)
-{
-       return ide_pci_register_driver(&cs5520_pci_driver);
-}
-
-module_init(cs5520_ide_init);
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
deleted file mode 100644 (file)
index 6537159..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2000                  Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2000                  Mark Lord <mlord@pobox.com>
- * Copyright (C) 2007                  Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- *
- * Documentation:
- *     CS5530 documentation available from National Semiconductor.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cs5530"
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] = {
-       {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
-       {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
-};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)   (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/**
- *     cs5530_set_pio_mode     -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Handles setting of PIO mode for the chipset.
- *
- *     The init_hwif_cs5530() routine guarantees that all drives
- *     will have valid default PIO timings set up before we get here.
- */
-
-static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long basereg = CS5530_BASEREG(hwif);
-       unsigned int format = (inl(basereg + 4) >> 31) & 1;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
-}
-
-/**
- *     cs5530_udma_filter      -       UDMA filter
- *     @drive: drive
- *
- *     cs5530_udma_filter() does UDMA mask filtering for the given drive
- *     taking into the consideration capabilities of the mate device.
- *
- *     The CS5530 specifies that two drives sharing a cable cannot mix
- *     UDMA/MDMA.  It has to be one or the other, for the pair, though
- *     different timings can still be chosen for each drive.  We could
- *     set the appropriate timing bits on the fly, but that might be
- *     a bit confusing.  So, for now we statically handle this requirement
- *     by looking at our mate drive to see what it is capable of, before
- *     choosing a mode for our own drive.
- *
- *     Note: This relies on the fact we never fail from UDMA to MWDMA2
- *     but instead drop to PIO.
- */
-
-static u8 cs5530_udma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *mate = ide_get_pair_dev(drive);
-       u16 *mateid;
-       u8 mask = hwif->ultra_mask;
-
-       if (mate == NULL)
-               goto out;
-       mateid = mate->id;
-
-       if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
-               if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
-                   (mateid[ATA_ID_UDMA_MODES] & 7))
-                       goto out;
-               if (mateid[ATA_ID_MWDMA_MODES] & 7)
-                       mask = 0;
-       }
-out:
-       return mask;
-}
-
-static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long basereg;
-       unsigned int reg, timings = 0;
-
-       switch (drive->dma_mode) {
-               case XFER_UDMA_0:       timings = 0x00921250; break;
-               case XFER_UDMA_1:       timings = 0x00911140; break;
-               case XFER_UDMA_2:       timings = 0x00911030; break;
-               case XFER_MW_DMA_0:     timings = 0x00077771; break;
-               case XFER_MW_DMA_1:     timings = 0x00012121; break;
-               case XFER_MW_DMA_2:     timings = 0x00002020; break;
-       }
-       basereg = CS5530_BASEREG(hwif);
-       reg = inl(basereg + 4);                 /* get drive0 config register */
-       timings |= reg & 0x80000000;            /* preserve PIO format bit */
-       if ((drive-> dn & 1) == 0) {            /* are we configuring drive0? */
-               outl(timings, basereg + 4);     /* write drive0 config register */
-       } else {
-               if (timings & 0x00100000)
-                       reg |=  0x00100000;     /* enable UDMA timings for both drives */
-               else
-                       reg &= ~0x00100000;     /* disable UDMA timings for both drives */
-               outl(reg, basereg + 4);         /* write drive0 config register */
-               outl(timings, basereg + 12);    /* write drive1 config register */
-       }
-}
-
-/**
- *     init_chipset_5530       -       set up 5530 bridge
- *     @dev: PCI device
- *
- *     Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-
-static int init_chipset_cs5530(struct pci_dev *dev)
-{
-       struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-
-       if (pci_resource_start(dev, 4) == 0)
-               return -EFAULT;
-
-       dev = NULL;
-       while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
-               switch (dev->device) {
-                       case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
-                               master_0 = pci_dev_get(dev);
-                               break;
-                       case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-                               cs5530_0 = pci_dev_get(dev);
-                               break;
-               }
-       }
-       if (!master_0) {
-               printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
-               goto out;
-       }
-       if (!cs5530_0) {
-               printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
-               goto out;
-       }
-
-       /*
-        * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
-        * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
-        */
-
-       pci_set_master(cs5530_0);
-       pci_try_set_mwi(cs5530_0);
-
-       /*
-        * Set PCI CacheLineSize to 16-bytes:
-        * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
-        */
-
-       pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
-       /*
-        * Disable trapping of UDMA register accesses (Win98 hack):
-        * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
-        */
-
-       pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
-       /*
-        * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
-        * The other settings are what is necessary to get the register
-        * into a sane state for IDE DMA operation.
-        */
-
-       pci_write_config_byte(master_0, 0x40, 0x1e);
-
-       /* 
-        * Set max PCI burst size (16-bytes seems to work best):
-        *         16bytes: set bit-1 at 0x41 (reg value of 0x16)
-        *      all others: clear bit-1 at 0x41, and do:
-        *        128bytes: OR 0x00 at 0x41
-        *        256bytes: OR 0x04 at 0x41
-        *        512bytes: OR 0x08 at 0x41
-        *       1024bytes: OR 0x0c at 0x41
-        */
-
-       pci_write_config_byte(master_0, 0x41, 0x14);
-
-       /*
-        * These settings are necessary to get the chip
-        * into a sane state for IDE DMA operation.
-        */
-
-       pci_write_config_byte(master_0, 0x42, 0x00);
-       pci_write_config_byte(master_0, 0x43, 0xc1);
-
-out:
-       pci_dev_put(master_0);
-       pci_dev_put(cs5530_0);
-       return 0;
-}
-
-/**
- *     init_hwif_cs5530        -       initialise an IDE channel
- *     @hwif: IDE to initialize
- *
- *     This gets invoked by the IDE driver once for each channel. It
- *     performs channel-specific pre-initialization before drive probing.
- */
-
-static void init_hwif_cs5530 (ide_hwif_t *hwif)
-{
-       unsigned long basereg;
-       u32 d0_timings;
-
-       basereg = CS5530_BASEREG(hwif);
-       d0_timings = inl(basereg + 0);
-       if (CS5530_BAD_PIO(d0_timings))
-               outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
-       if (CS5530_BAD_PIO(inl(basereg + 8)))
-               outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
-}
-
-static const struct ide_port_ops cs5530_port_ops = {
-       .set_pio_mode           = cs5530_set_pio_mode,
-       .set_dma_mode           = cs5530_set_dma_mode,
-       .udma_filter            = cs5530_udma_filter,
-};
-
-static const struct ide_port_info cs5530_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_cs5530,
-       .init_hwif      = init_hwif_cs5530,
-       .port_ops       = &cs5530_port_ops,
-       .host_flags     = IDE_HFLAG_SERIALIZE |
-                         IDE_HFLAG_POST_SET_MODE,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA2,
-};
-
-static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &cs5530_chipset, NULL);
-}
-
-static const struct pci_device_id cs5530_pci_tbl[] = {
-       { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
-
-static struct pci_driver cs5530_pci_driver = {
-       .name           = "CS5530 IDE",
-       .id_table       = cs5530_pci_tbl,
-       .probe          = cs5530_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init cs5530_ide_init(void)
-{
-       return ide_pci_register_driver(&cs5530_pci_driver);
-}
-
-static void __exit cs5530_ide_exit(void)
-{
-       pci_unregister_driver(&cs5530_pci_driver);
-}
-
-module_init(cs5530_ide_init);
-module_exit(cs5530_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
deleted file mode 100644 (file)
index 70fdbe3..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
- * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
- *
- * History:
- * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
- * - Reworked tuneproc, set_drive, misc mods to prep for mainline
- * - Work was sponsored by CIS (M) Sdn Bhd.
- * Ported to Kernel 2.6.11 on June 26, 2005 by
- *   Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
- *   Alexander Kiausch <alex.kiausch@t-online.de>
- * Originally developed by AMD for 2.4/2.6
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor/AMD.
- *
- * Documentation:
- *  CS5535 documentation available from AMD
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "cs5535"
-
-#define MSR_ATAC_BASE          0x51300000
-#define ATAC_GLD_MSR_CAP       (MSR_ATAC_BASE+0)
-#define ATAC_GLD_MSR_CONFIG    (MSR_ATAC_BASE+0x01)
-#define ATAC_GLD_MSR_SMI       (MSR_ATAC_BASE+0x02)
-#define ATAC_GLD_MSR_ERROR     (MSR_ATAC_BASE+0x03)
-#define ATAC_GLD_MSR_PM                (MSR_ATAC_BASE+0x04)
-#define ATAC_GLD_MSR_DIAG      (MSR_ATAC_BASE+0x05)
-#define ATAC_IO_BAR            (MSR_ATAC_BASE+0x08)
-#define ATAC_RESET             (MSR_ATAC_BASE+0x10)
-#define ATAC_CH0D0_PIO         (MSR_ATAC_BASE+0x20)
-#define ATAC_CH0D0_DMA         (MSR_ATAC_BASE+0x21)
-#define ATAC_CH0D1_PIO         (MSR_ATAC_BASE+0x22)
-#define ATAC_CH0D1_DMA         (MSR_ATAC_BASE+0x23)
-#define ATAC_PCI_ABRTERR       (MSR_ATAC_BASE+0x24)
-#define ATAC_BM0_CMD_PRIM      0x00
-#define ATAC_BM0_STS_PRIM      0x02
-#define ATAC_BM0_PRD           0x04
-#define CS5535_CABLE_DETECT    0x48
-
-/* Format I PIO settings. We separate out cmd and data for safer timings */
-
-static unsigned int cs5535_pio_cmd_timings[5] =
-{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
-static unsigned int cs5535_pio_dta_timings[5] =
-{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
-
-static unsigned int cs5535_mwdma_timings[3] =
-{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
-
-static unsigned int cs5535_udma_timings[5] =
-{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
-
-/* Macros to check if the register is the reset value -  reset value is an
-   invalid timing and indicates the register has not been set previously */
-
-#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
-#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
-
-/****
- *     cs5535_set_speed         -     Configure the chipset to the new speed
- *     @drive: Drive to set up
- *     @speed: desired speed
- *
- *     cs5535_set_speed() configures the chipset to a new speed.
- */
-static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
-{
-       u32 reg = 0, dummy;
-       u8 unit = drive->dn & 1;
-
-       /* Set the PIO timings */
-       if (speed < XFER_SW_DMA_0) {
-               ide_drive_t *pair = ide_get_pair_dev(drive);
-               u8 cmd, pioa;
-
-               cmd = pioa = speed - XFER_PIO_0;
-
-               if (pair) {
-                       u8 piob = pair->pio_mode - XFER_PIO_0;
-
-                       if (piob < cmd)
-                               cmd = piob;
-               }
-
-               /* Write the speed of the current drive */
-               reg = (cs5535_pio_cmd_timings[cmd] << 16) |
-                       cs5535_pio_dta_timings[pioa];
-               wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
-
-               /* And if nessesary - change the speed of the other drive */
-               rdmsr(unit ?  ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
-
-               if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
-                       cs5535_pio_cmd_timings[cmd]) {
-                       reg &= 0x0000FFFF;
-                       reg |= cs5535_pio_cmd_timings[cmd] << 16;
-                       wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
-               }
-
-               /* Set bit 31 of the DMA register for PIO format 1 timings */
-               rdmsr(unit ?  ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
-               wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
-                                       reg | 0x80000000UL, 0);
-       } else {
-               rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
-
-               reg &= 0x80000000UL;  /* Preserve the PIO format bit */
-
-               if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
-                       reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
-               else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-                       reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
-               else
-                       return;
-
-               wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
-       }
-}
-
-/**
- *     cs5535_set_dma_mode     -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Programs the chipset for DMA mode.
- */
-
-static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       cs5535_set_speed(drive, drive->dma_mode);
-}
-
-/**
- *     cs5535_set_pio_mode     -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     A callback from the upper layers for PIO-only tuning.
- */
-
-static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       cs5535_set_speed(drive, drive->pio_mode);
-}
-
-static u8 cs5535_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 bit;
-
-       /* if a 80 wire cable was detected */
-       pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
-
-       return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops cs5535_port_ops = {
-       .set_pio_mode           = cs5535_set_pio_mode,
-       .set_dma_mode           = cs5535_set_dma_mode,
-       .cable_detect           = cs5535_cable_detect,
-};
-
-static const struct ide_port_info cs5535_chipset = {
-       .name           = DRV_NAME,
-       .port_ops       = &cs5535_port_ops,
-       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA4,
-};
-
-static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &cs5535_chipset, NULL);
-}
-
-static const struct pci_device_id cs5535_pci_tbl[] = {
-       { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
-       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), },
-       { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
-
-static struct pci_driver cs5535_pci_driver = {
-       .name           = "CS5535_IDE",
-       .id_table       = cs5535_pci_tbl,
-       .probe          = cs5535_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init cs5535_ide_init(void)
-{
-       return ide_pci_register_driver(&cs5535_pci_driver);
-}
-
-static void __exit cs5535_ide_exit(void)
-{
-       pci_unregister_driver(&cs5535_pci_driver);
-}
-
-module_init(cs5535_ide_init);
-module_exit(cs5535_ide_exit);
-
-MODULE_AUTHOR("AMD");
-MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c
deleted file mode 100644 (file)
index 8b5ca14..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * CS5536 PATA support
- * (C) 2007 Martin K. Petersen <mkp@mkp.net>
- * (C) 2009 Bartlomiej Zolnierkiewicz
- *
- * Documentation:
- *     Available from AMD web site.
- *
- * The IDE timing registers for the CS5536 live in the Geode Machine
- * Specific Register file and not PCI config space.  Most BIOSes
- * virtualize the PCI registers so the chip looks like a standard IDE
- * controller.  Unfortunately not all implementations get this right.
- * In particular some have problems with unaligned accesses to the
- * virtualized PCI registers.  This driver always does full dword
- * writes to work around the issue.  Also, in case of a bad BIOS this
- * driver can be loaded with the "msr=1" parameter which forces using
- * the Machine Specific Registers to configure the device.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/msr.h>
-
-#define DRV_NAME       "cs5536"
-
-enum {
-       MSR_IDE_CFG             = 0x51300010,
-       PCI_IDE_CFG             = 0x40,
-
-       CFG                     = 0,
-       DTC                     = 2,
-       CAST                    = 3,
-       ETC                     = 4,
-
-       IDE_CFG_CHANEN          = (1 << 1),
-       IDE_CFG_CABLE           = (1 << 17) | (1 << 16),
-
-       IDE_D0_SHIFT            = 24,
-       IDE_D1_SHIFT            = 16,
-       IDE_DRV_MASK            = 0xff,
-
-       IDE_CAST_D0_SHIFT       = 6,
-       IDE_CAST_D1_SHIFT       = 4,
-       IDE_CAST_DRV_MASK       = 0x3,
-
-       IDE_CAST_CMD_SHIFT      = 24,
-       IDE_CAST_CMD_MASK       = 0xff,
-
-       IDE_ETC_UDMA_MASK       = 0xc0,
-};
-
-static int use_msr;
-
-static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
-{
-       if (unlikely(use_msr)) {
-               u32 dummy;
-
-               rdmsr(MSR_IDE_CFG + reg, *val, dummy);
-               return 0;
-       }
-
-       return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
-}
-
-static int cs5536_write(struct pci_dev *pdev, int reg, int val)
-{
-       if (unlikely(use_msr)) {
-               wrmsr(MSR_IDE_CFG + reg, val, 0);
-               return 0;
-       }
-
-       return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
-}
-
-static void cs5536_program_dtc(ide_drive_t *drive, u8 tim)
-{
-       struct pci_dev *pdev = to_pci_dev(drive->hwif->dev);
-       int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
-       u32 dtc;
-
-       cs5536_read(pdev, DTC, &dtc);
-       dtc &= ~(IDE_DRV_MASK << dshift);
-       dtc |= tim << dshift;
-       cs5536_write(pdev, DTC, dtc);
-}
-
-/**
- *     cs5536_cable_detect     -       detect cable type
- *     @hwif: Port to detect on
- *
- *     Perform cable detection for ATA66 capable cable.
- *
- *     Returns a cable type.
- */
-
-static u8 cs5536_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       u32 cfg;
-
-       cs5536_read(pdev, CFG, &cfg);
-
-       if (cfg & IDE_CFG_CABLE)
-               return ATA_CBL_PATA80;
-       else
-               return ATA_CBL_PATA40;
-}
-
-/**
- *     cs5536_set_pio_mode             -       PIO timing setup
- *     @hwif: ATA port
- *     @drive: ATA device
- */
-
-static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u8 drv_timings[5] = {
-               0x98, 0x55, 0x32, 0x21, 0x20,
-       };
-
-       static const u8 addr_timings[5] = {
-               0x2, 0x1, 0x0, 0x0, 0x0,
-       };
-
-       static const u8 cmd_timings[5] = {
-               0x99, 0x92, 0x90, 0x22, 0x20,
-       };
-
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
-       unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-       u32 cast;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       u8 cmd_pio = pio;
-
-       if (pair)
-               cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0);
-
-       timings &= (IDE_DRV_MASK << 8);
-       timings |= drv_timings[pio];
-       ide_set_drivedata(drive, (void *)timings);
-
-       cs5536_program_dtc(drive, drv_timings[pio]);
-
-       cs5536_read(pdev, CAST, &cast);
-
-       cast &= ~(IDE_CAST_DRV_MASK << cshift);
-       cast |= addr_timings[pio] << cshift;
-
-       cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
-       cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT;
-
-       cs5536_write(pdev, CAST, cast);
-}
-
-/**
- *     cs5536_set_dma_mode             -       DMA timing setup
- *     @hwif: ATA port
- *     @drive: ATA device
- */
-
-static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u8 udma_timings[6] = {
-               0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
-       };
-
-       static const u8 mwdma_timings[3] = {
-               0x67, 0x21, 0x20,
-       };
-
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
-       unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-       u32 etc;
-       const u8 mode = drive->dma_mode;
-
-       cs5536_read(pdev, ETC, &etc);
-
-       if (mode >= XFER_UDMA_0) {
-               etc &= ~(IDE_DRV_MASK << dshift);
-               etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
-       } else { /* MWDMA */
-               etc &= ~(IDE_ETC_UDMA_MASK << dshift);
-               timings &= IDE_DRV_MASK;
-               timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8;
-               ide_set_drivedata(drive, (void *)timings);
-       }
-
-       cs5536_write(pdev, ETC, etc);
-}
-
-static void cs5536_dma_start(ide_drive_t *drive)
-{
-       unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-
-       if (drive->current_speed < XFER_UDMA_0 &&
-           (timings >> 8) != (timings & IDE_DRV_MASK))
-               cs5536_program_dtc(drive, timings >> 8);
-
-       ide_dma_start(drive);
-}
-
-static int cs5536_dma_end(ide_drive_t *drive)
-{
-       int ret = ide_dma_end(drive);
-       unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-
-       if (drive->current_speed < XFER_UDMA_0 &&
-           (timings >> 8) != (timings & IDE_DRV_MASK))
-               cs5536_program_dtc(drive, timings & IDE_DRV_MASK);
-
-       return ret;
-}
-
-static const struct ide_port_ops cs5536_port_ops = {
-       .set_pio_mode           = cs5536_set_pio_mode,
-       .set_dma_mode           = cs5536_set_dma_mode,
-       .cable_detect           = cs5536_cable_detect,
-};
-
-static const struct ide_dma_ops cs5536_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = cs5536_dma_start,
-       .dma_end                = cs5536_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info cs5536_info = {
-       .name           = DRV_NAME,
-       .port_ops       = &cs5536_port_ops,
-       .dma_ops        = &cs5536_dma_ops,
-       .host_flags     = IDE_HFLAG_SINGLE,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA5,
-};
-
-/**
- *     cs5536_init_one
- *     @dev: PCI device
- *     @id: Entry in match table
- */
-
-static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       u32 cfg;
-
-       if (use_msr)
-               printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n");
-
-       cs5536_read(dev, CFG, &cfg);
-
-       if ((cfg & IDE_CFG_CHANEN) == 0) {
-               printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
-               return -ENODEV;
-       }
-
-       return ide_pci_init_one(dev, &cs5536_info, NULL);
-}
-
-static const struct pci_device_id cs5536_pci_tbl[] = {
-       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
-       { },
-};
-
-static struct pci_driver cs5536_pci_driver = {
-       .name           = DRV_NAME,
-       .id_table       = cs5536_pci_tbl,
-       .probe          = cs5536_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-module_pci_driver(cs5536_pci_driver);
-
-MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl);
-
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
deleted file mode 100644 (file)
index bc01660..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
- *  Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cy82c693"
-
-/*
- *     NOTE: the value for busmaster timeout is tricky and I got it by
- *     trial and error!  By using a to low value will cause DMA timeouts
- *     and drop IDE performance, and by using a to high value will cause
- *     audio playback to scatter.
- *     If you know a better value or how to calc it, please let me know.
- */
-
-/* twice the value written in cy82c693ub datasheet */
-#define BUSMASTER_TIMEOUT      0x50
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG                0x04
-#define CY82_IDE_ADDRSETUP     0x48
-#define CY82_IDE_MASTER_IOR    0x4C
-#define CY82_IDE_MASTER_IOW    0x4D
-#define CY82_IDE_SLAVE_IOR     0x4E
-#define CY82_IDE_SLAVE_IOW     0x4F
-#define CY82_IDE_MASTER_8BIT   0x50
-#define CY82_IDE_SLAVE_8BIT    0x51
-
-#define CY82_INDEX_PORT                0x22
-#define CY82_DATA_PORT         0x23
-
-#define CY82_INDEX_CHANNEL0    0x30
-#define CY82_INDEX_CHANNEL1    0x31
-#define CY82_INDEX_TIMEOUT     0x32
-
-/*
- * set DMA mode a specific channel for CY82C693
- */
-
-static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       const u8 mode = drive->dma_mode;
-       u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
-
-       index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
-
-       data = (mode & 3) | (single << 2);
-
-       outb(index, CY82_INDEX_PORT);
-       outb(data, CY82_DATA_PORT);
-
-       /*
-        * note: below we set the value for Bus Master IDE TimeOut Register
-        * I'm not absolutely sure what this does, but it solved my problem
-        * with IDE DMA and sound, so I now can play sound and work with
-        * my IDE driver at the same time :-)
-        *
-        * If you know the correct (best) value for this register please
-        * let me know - ASK
-        */
-
-       data = BUSMASTER_TIMEOUT;
-       outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
-       outb(data, CY82_DATA_PORT);
-}
-
-static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-       const unsigned long T = 1000000 / bus_speed;
-       unsigned int addrCtrl;
-       struct ide_timing t;
-       u8 time_16, time_8;
-
-       /* select primary or secondary channel */
-       if (drive->dn > 1) {  /* drive is on the secondary channel */
-               dev = pci_get_slot(dev->bus, dev->devfn+1);
-               if (!dev) {
-                       printk(KERN_ERR "%s: tune_drive: "
-                               "Cannot find secondary interface!\n",
-                               drive->name);
-                       return;
-               }
-       }
-
-       ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
-
-       time_16 = clamp_val(t.recover - 1, 0, 15) |
-                 (clamp_val(t.active - 1, 0, 15) << 4);
-       time_8 = clamp_val(t.act8b - 1, 0, 15) |
-                (clamp_val(t.rec8b - 1, 0, 15) << 4);
-
-       /* now let's write  the clocks registers */
-       if ((drive->dn & 1) == 0) {
-               /*
-                * set master drive
-                * address setup control register
-                * is 32 bit !!!
-                */
-               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-               addrCtrl &= (~0xF);
-               addrCtrl |= clamp_val(t.setup - 1, 0, 15);
-               pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-               /* now let's set the remaining registers */
-               pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16);
-               pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16);
-               pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8);
-       } else {
-               /*
-                * set slave drive
-                * address setup control register
-                * is 32 bit !!!
-                */
-               pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-               addrCtrl &= (~0xF0);
-               addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4);
-               pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-               /* now let's set the remaining registers */
-               pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16);
-               pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
-               pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
-       }
-       if (drive->dn > 1)
-               pci_dev_put(dev);
-}
-
-static void init_iops_cy82c693(ide_hwif_t *hwif)
-{
-       static ide_hwif_t *primary;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       if (PCI_FUNC(dev->devfn) == 1)
-               primary = hwif;
-       else {
-               hwif->mate = primary;
-               hwif->channel = 1;
-       }
-}
-
-static const struct ide_port_ops cy82c693_port_ops = {
-       .set_pio_mode           = cy82c693_set_pio_mode,
-       .set_dma_mode           = cy82c693_set_dma_mode,
-};
-
-static const struct ide_port_info cy82c693_chipset = {
-       .name           = DRV_NAME,
-       .init_iops      = init_iops_cy82c693,
-       .port_ops       = &cy82c693_port_ops,
-       .host_flags     = IDE_HFLAG_SINGLE,
-       .pio_mask       = ATA_PIO4,
-       .swdma_mask     = ATA_SWDMA2,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-static int cy82c693_init_one(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       struct pci_dev *dev2;
-       int ret = -ENODEV;
-
-       /* CY82C693 is more than only a IDE controller.
-          Function 1 is primary IDE channel, function 2 - secondary. */
-       if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
-           PCI_FUNC(dev->devfn) == 1) {
-               dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
-               ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL);
-               if (ret)
-                       pci_dev_put(dev2);
-       }
-       return ret;
-}
-
-static void cy82c693_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
-       ide_pci_remove(dev);
-       pci_dev_put(dev2);
-}
-
-static const struct pci_device_id cy82c693_pci_tbl[] = {
-       { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
-
-static struct pci_driver cy82c693_pci_driver = {
-       .name           = "Cypress_IDE",
-       .id_table       = cy82c693_pci_tbl,
-       .probe          = cy82c693_init_one,
-       .remove         = cy82c693_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init cy82c693_ide_init(void)
-{
-       return ide_pci_register_driver(&cy82c693_pci_driver);
-}
-
-static void __exit cy82c693_ide_exit(void)
-{
-       pci_unregister_driver(&cy82c693_pci_driver);
-}
-
-module_init(cy82c693_ide_init);
-module_exit(cy82c693_ide_exit);
-
-MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
deleted file mode 100644 (file)
index 300daab..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- *  Created 20 Oct 2004 by Mark Lord
- *
- *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
- *
- *  Modeled after the 16-bit PCMCIA driver: ide-cs.c
- *
- *  This is slightly peculiar, in that it is a PCI driver,
- *  but is NOT an IDE PCI driver -- the IDE layer does not directly
- *  support hot insertion/removal of PCI interfaces, so this driver
- *  is unable to use the IDE PCI interfaces.  Instead, it uses the
- *  same interfaces as the ide-cs (PCMCIA) driver uses.
- *  On the plus side, the driver is also smaller/simpler this way.
- *
- *  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.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/io.h>
-
-/*
- * No chip documentation has yet been found,
- * so these configuration values were pulled from
- * a running Win98 system using "debug".
- * This gives around 3MByte/second read performance,
- * which is about 2/3 of what the chip is capable of.
- *
- * There is also a 4KByte mmio region on the card,
- * but its purpose has yet to be reverse-engineered.
- */
-static const u8 setup[] = {
-       0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
-       0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
-};
-
-static const struct ide_port_ops delkin_cb_port_ops = {
-       .quirkproc              = ide_undecoded_slave,
-};
-
-static int delkin_cb_init_chipset(struct pci_dev *dev)
-{
-       unsigned long base = pci_resource_start(dev, 0);
-       int i;
-
-       outb(0x02, base + 0x1e);        /* set nIEN to block interrupts */
-       inb(base + 0x17);               /* read status to clear interrupts */
-
-       for (i = 0; i < sizeof(setup); ++i) {
-               if (setup[i])
-                       outb(setup[i], base + i);
-       }
-
-       return 0;
-}
-
-static const struct ide_port_info delkin_cb_port_info = {
-       .port_ops               = &delkin_cb_port_ops,
-       .host_flags             = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
-                                 IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .init_chipset           = delkin_cb_init_chipset,
-       .chipset                = ide_pci,
-};
-
-static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_host *host;
-       unsigned long base;
-       int rc;
-       struct ide_hw hw, *hws[] = { &hw };
-
-       rc = pci_enable_device(dev);
-       if (rc) {
-               printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
-               return rc;
-       }
-       rc = pci_request_regions(dev, "delkin_cb");
-       if (rc) {
-               printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
-               pci_disable_device(dev);
-               return rc;
-       }
-       base = pci_resource_start(dev, 0);
-
-       delkin_cb_init_chipset(dev);
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
-       hw.irq = dev->irq;
-       hw.dev = &dev->dev;
-
-       rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host);
-       if (rc)
-               goto out_disable;
-
-       pci_set_drvdata(dev, host);
-
-       return 0;
-
-out_disable:
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-       return rc;
-}
-
-static void
-delkin_cb_remove (struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-
-       ide_host_remove(host);
-
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-}
-
-#ifdef CONFIG_PM
-static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
-       return 0;
-}
-
-static int delkin_cb_resume(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       int rc;
-
-       pci_set_power_state(dev, PCI_D0);
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       pci_restore_state(dev);
-       pci_set_master(dev);
-
-       if (host->init_chipset)
-               host->init_chipset(dev);
-
-       return 0;
-}
-#else
-#define delkin_cb_suspend NULL
-#define delkin_cb_resume NULL
-#endif
-
-static struct pci_device_id delkin_cb_pci_tbl[] = {
-       { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
-
-static struct pci_driver delkin_cb_pci_driver = {
-       .name           = "Delkin-ASKA-Workbit Cardbus IDE",
-       .id_table       = delkin_cb_pci_tbl,
-       .probe          = delkin_cb_probe,
-       .remove         = delkin_cb_remove,
-       .suspend        = delkin_cb_suspend,
-       .resume         = delkin_cb_resume,
-};
-
-module_pci_driver(delkin_cb_pci_driver);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
deleted file mode 100644 (file)
index 714e8cd..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "dtc2278"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed.  If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
-       int i;
-
-       for(i = 0; i < 3; ++i) {
-               inb(0x3f6);
-               outb_p(b,0xb0);
-               inb(0x3f6);
-               outb_p(c,0xb4);
-               inb(0x3f6);
-               if(inb(0xb4) == c) {
-                       outb_p(7,0xb0);
-                       inb(0x3f6);
-                       return; /* success */
-               }
-       }
-}
-
-static DEFINE_SPINLOCK(dtc2278_lock);
-
-static void dtc2278_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long flags;
-
-       if (drive->pio_mode >= XFER_PIO_3) {
-               spin_lock_irqsave(&dtc2278_lock, flags);
-               /*
-                * This enables PIO mode4 (3?) on the first interface
-                */
-               sub22(1,0xc3);
-               sub22(0,0xa0);
-               spin_unlock_irqrestore(&dtc2278_lock, flags);
-       } else {
-               /* we don't know how to set it back again.. */
-               /* Actually we do - there is a data sheet available for the
-                  Winbond but does anyone actually care */
-       }
-}
-
-static const struct ide_port_ops dtc2278_port_ops = {
-       .set_pio_mode           = dtc2278_set_pio_mode,
-};
-
-static const struct ide_port_info dtc2278_port_info __initconst = {
-       .name                   = DRV_NAME,
-       .chipset                = ide_dtc2278,
-       .port_ops               = &dtc2278_port_ops,
-       .host_flags             = IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_NO_UNMASK_IRQS |
-                                 IDE_HFLAG_IO_32BIT |
-                                 /* disallow ->io_32bit changes */
-                                 IDE_HFLAG_NO_IO_32BIT |
-                                 IDE_HFLAG_NO_DMA |
-                                 IDE_HFLAG_DTC2278,
-       .pio_mask               = ATA_PIO4,
-};
-
-static int __init dtc2278_probe(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       /*
-        * This enables the second interface
-        */
-       outb_p(4,0xb0);
-       inb(0x3f6);
-       outb_p(0x20,0xb4);
-       inb(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
-       /*
-        * This enables PIO mode4 (3?) on the first interface
-        * and may solve start-up problems for some people.
-        */
-       sub22(1,0xc3);
-       sub22(0,0xa0);
-#endif
-       local_irq_restore(flags);
-
-       return ide_legacy_device_add(&dtc2278_port_info, 0);
-}
-
-static bool probe_dtc2278;
-
-module_param_named(probe, probe_dtc2278, bool, 0);
-MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
-
-static int __init dtc2278_init(void)
-{
-       if (probe_dtc2278 == 0)
-               return -ENODEV;
-
-       if (dtc2278_probe()) {
-               printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
-               return -EBUSY;
-       }
-       return 0;
-}
-
-module_init(dtc2278_init);
-
-MODULE_AUTHOR("See Local File");
-MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
deleted file mode 100644 (file)
index bb86d84..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- *  Atari Falcon IDE Driver
- *
- *     Created 12 Jul 1997 by Geert Uytterhoeven
- *
- *  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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-#include <asm/ide.h>
-
-#define DRV_NAME "falconide"
-
-    /*
-     *  Offsets from base address
-     */
-
-#define ATA_HD_CONTROL 0x39
-
-    /*
-     *  falconide_intr_lock is used to obtain access to the IDE interrupt,
-     *  which is shared between several drivers.
-     */
-
-static int falconide_intr_lock;
-
-static void falconide_release_lock(void)
-{
-       if (falconide_intr_lock == 0) {
-               printk(KERN_ERR "%s: bug\n", __func__);
-               return;
-       }
-       falconide_intr_lock = 0;
-       stdma_release();
-}
-
-static void falconide_get_lock(irq_handler_t handler, void *data)
-{
-       if (falconide_intr_lock == 0) {
-               stdma_lock(handler, data);
-               falconide_intr_lock = 1;
-       }
-}
-
-static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                                void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
-               __ide_mm_insw(data_addr, buf, (len + 1) / 2);
-               return;
-       }
-
-       raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                                 void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
-               __ide_mm_outsw(data_addr, buf, (len + 1) / 2);
-               return;
-       }
-
-       raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-/* Atari has a byte-swapped IDE interface */
-static const struct ide_tp_ops falconide_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_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             = falconide_input_data,
-       .output_data            = falconide_output_data,
-};
-
-static const struct ide_port_info falconide_port_info = {
-       .get_lock               = falconide_get_lock,
-       .release_lock           = falconide_release_lock,
-       .tp_ops                 = &falconide_tp_ops,
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_generic,
-};
-
-static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
-{
-       int i;
-
-       memset(hw, 0, sizeof(*hw));
-
-       hw->io_ports.data_addr = base;
-
-       for (i = 1; i < 8; i++)
-               hw->io_ports_array[i] = base + 1 + i * 4;
-
-       hw->io_ports.ctl_addr = base + ATA_HD_CONTROL;
-
-       hw->irq = IRQ_MFP_IDE;
-}
-
-    /*
-     *  Probe for a Falcon IDE interface
-     */
-
-static int __init falconide_init(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct ide_host *host;
-       struct ide_hw hw, *hws[] = { &hw };
-       unsigned long base;
-       int rc;
-
-       dev_info(&pdev->dev, "Atari Falcon IDE controller\n");
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), DRV_NAME)) {
-               dev_err(&pdev->dev, "resources busy\n");
-               return -EBUSY;
-       }
-
-       base = (unsigned long)res->start;
-
-       falconide_setup_ports(&hw, base);
-
-       host = ide_host_alloc(&falconide_port_info, hws, 1);
-       if (host == NULL) {
-               rc = -ENOMEM;
-               goto err;
-       }
-
-       falconide_get_lock(NULL, NULL);
-       rc = ide_host_register(host, &falconide_port_info, hws);
-       falconide_release_lock();
-
-       if (rc)
-               goto err_free;
-
-       platform_set_drvdata(pdev, host);
-       return 0;
-err_free:
-       ide_host_free(host);
-err:
-       release_mem_region(res->start, resource_size(res));
-       return rc;
-}
-
-static int falconide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = platform_get_drvdata(pdev);
-
-       ide_host_remove(host);
-
-       return 0;
-}
-
-static struct platform_driver ide_falcon_driver = {
-       .remove = falconide_remove,
-       .driver   = {
-               .name   = "atari-falcon-ide",
-       },
-};
-
-module_platform_driver_probe(ide_falcon_driver, falconide_init);
-
-MODULE_AUTHOR("Geert Uytterhoeven");
-MODULE_DESCRIPTION("low-level driver for Atari Falcon IDE");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atari-falcon-ide");
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
deleted file mode 100644 (file)
index 901e6eb..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *  Amiga Gayle IDE Driver
- *
- *     Created 9 Jul 1997 by Geert Uytterhoeven
- *
- *  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.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define GAYLE_CONTROL  0x101a
-
-    /*
-     *  These are at different offsets from the base
-     */
-
-#define GAYLE_IRQ_4000 0xdd3020        /* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200 0xda9000        /* interrupt */
-
-
-    /*
-     *  Offset of the secondary port for IDE doublers
-     *  Note that GAYLE_CONTROL is NOT available then!
-     */
-
-#define GAYLE_NEXT_PORT        0x1000
-
-#define GAYLE_NUM_HWIFS                2
-#define GAYLE_NUM_PROBE_HWIFS  (ide_doubler ? GAYLE_NUM_HWIFS : \
-                                              GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG  (!ide_doubler)
-
-static bool ide_doubler;
-module_param_named(doubler, ide_doubler, bool, 0);
-MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int gayle_test_irq(ide_hwif_t *hwif)
-{
-       unsigned char ch;
-
-       ch = z_readb(hwif->io_ports.irq_addr);
-       if (!(ch & GAYLE_IRQ_IDE))
-               return 0;
-       return 1;
-}
-
-static void gayle_a1200_clear_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       (void)z_readb(hwif->io_ports.status_addr);
-       z_writeb(0x7c, hwif->io_ports.irq_addr);
-}
-
-static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
-                                    unsigned long ctl, unsigned long irq_port)
-{
-       int i;
-
-       memset(hw, 0, sizeof(*hw));
-
-       hw->io_ports.data_addr = base;
-
-       for (i = 1; i < 8; i++)
-               hw->io_ports_array[i] = base + 2 + i * 4;
-
-       hw->io_ports.ctl_addr = ctl;
-       hw->io_ports.irq_addr = irq_port;
-
-       hw->irq = IRQ_AMIGA_PORTS;
-}
-
-static const struct ide_port_ops gayle_a4000_port_ops = {
-       .test_irq               = gayle_test_irq,
-};
-
-static const struct ide_port_ops gayle_a1200_port_ops = {
-       .clear_irq              = gayle_a1200_clear_irq,
-       .test_irq               = gayle_test_irq,
-};
-
-static const struct ide_port_info gayle_port_info = {
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
-                                 IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_generic,
-};
-
-    /*
-     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-     */
-
-static int __init amiga_gayle_ide_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct gayle_ide_platform_data *pdata;
-       unsigned long base, ctrlport, irqport;
-       unsigned int i;
-       int error;
-       struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
-       struct ide_port_info d = gayle_port_info;
-       struct ide_host *host;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       if (!request_mem_region(res->start, resource_size(res), "IDE"))
-               return -EBUSY;
-
-       pdata = dev_get_platdata(&pdev->dev);
-       pr_info("ide: Gayle IDE controller (A%u style%s)\n",
-               pdata->explicit_ack ? 1200 : 4000,
-               ide_doubler ? ", IDE doubler" : "");
-
-       base = (unsigned long)ZTWO_VADDR(pdata->base);
-       ctrlport = 0;
-       irqport = (unsigned long)ZTWO_VADDR(pdata->irqport);
-       if (pdata->explicit_ack)
-               d.port_ops = &gayle_a1200_port_ops;
-       else
-               d.port_ops = &gayle_a4000_port_ops;
-
-       for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) {
-               if (GAYLE_HAS_CONTROL_REG)
-                       ctrlport = base + GAYLE_CONTROL;
-
-               gayle_setup_ports(&hw[i], base, ctrlport, irqport);
-               hws[i] = &hw[i];
-       }
-
-       error = ide_host_add(&d, hws, i, &host);
-       if (error)
-               goto out;
-
-       platform_set_drvdata(pdev, host);
-       return 0;
-
-out:
-       release_mem_region(res->start, resource_size(res));
-       return error;
-}
-
-static int __exit amiga_gayle_ide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       ide_host_remove(host);
-       release_mem_region(res->start, resource_size(res));
-       return 0;
-}
-
-static struct platform_driver amiga_gayle_ide_driver = {
-       .remove = __exit_p(amiga_gayle_ide_remove),
-       .driver   = {
-               .name   = "amiga-gayle-ide",
-       },
-};
-
-module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:amiga-gayle-ide");
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
deleted file mode 100644 (file)
index 50c9a41..0000000
+++ /dev/null
@@ -1,1545 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001         Sun Microsystems, Inc.
- * Portions Copyright (C) 2003         Red Hat Inc
- * Portions Copyright (C) 2007         Bartlomiej Zolnierkiewicz
- * Portions Copyright (C) 2005-2009    MontaVista Software, Inc.
- *
- * Thanks to HighPoint Technologies for their assistance, and hardware.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- *
- * HighPoint has its own drivers (open source except for the RAID part)
- * available from http://www.highpoint-tech.com/USA_new/service_support.htm 
- * This may be useful to anyone wanting to work on this driver, however  do not
- * trust  them too much since the code tends to become less and less meaningful
- * as the time passes... :-/
- *
- * Note that final HPT370 support was done by force extraction of GPL.
- *
- * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma 
- *   xfer to prevent that from happening.
- * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma. 
- * - use new highpoint timings.
- * - detect bus speed using highpoint register.
- * - use pll if we don't have a clock table. added a 66MHz table that's
- *   just 2x the 33MHz table.
- * - removed turnaround. NOTE: we never want to switch between pll and
- *   pci clocks as the chip can glitch in those cases. the highpoint
- *   approved workaround slows everything down too much to be useful. in
- *   addition, we would have to serialize access to each chip.
- *     Adrian Sun <a.sun@sun.com>
- *
- * add drive timings for 66MHz PCI bus,
- * fix ATA Cable signal detection, fix incorrect /proc info
- * add /proc display for per-drive PIO/DMA/UDMA mode and
- * per-channel ATA-33/66 Cable detect.
- *     Duncan Laurie <void@sun.com>
- *
- * fixup /proc output for multiple controllers
- *     Tim Hockin <thockin@sun.com>
- *
- * On hpt366: 
- * Reset the hpt366 on error, reset on dma
- * Fix disabling Fast Interrupt hpt366.
- *     Mike Waychison <crlf@sun.com>
- *
- * Added support for 372N clocking and clock switching. The 372N needs
- * different clocks on read/write. This requires overloading rw_disk and
- * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for
- * keeping me sane. 
- *             Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * - fix the clock turnaround code: it was writing to the wrong ports when
- *   called for the secondary channel, caching the current clock mode per-
- *   channel caused the cached register value to get out of sync with the
- *   actual one, the channels weren't serialized, the turnaround shouldn't
- *   be done on 66 MHz PCI bus
- * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
- *   does not allow for this speed anyway
- * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
- *   their primary channel is kind of virtual, it isn't tied to any pins)
- * - fix/remove bad/unused timing tables and use one set of tables for the whole
- *   HPT37x chip family; save space by introducing the separate transfer mode
- *   table in which the mode lookup is done
- * - use f_CNT value saved by  the HighPoint BIOS as reading it directly gives
- *   the wrong PCI frequency since DPLL has already been calibrated by BIOS;
- *   read it only from the function 0 of HPT374 chips
- * - fix the hotswap code:  it caused RESET- to glitch when tristating the bus,
- *   and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
- * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
- *   they tamper with its fields
- * - pass  to the init_setup handlers a copy of the ide_pci_device_t structure
- *   since they may tamper with its fields
- * - prefix the driver startup messages with the real chip name
- * - claim the extra 240 bytes of I/O space for all chips
- * - optimize the UltraDMA filtering and the drive list lookup code
- * - use pci_get_slot() to get to the function 1 of HPT36x/374
- * - cache offset of the channel's misc. control registers (MCRs) being used
- *   throughout the driver
- * - only touch the relevant MCR when detecting the cable type on HPT374's
- *   function 1
- * - rename all the register related variables consistently
- * - move all the interrupt twiddling code from the speedproc handlers into
- *   init_hwif_hpt366(), also grouping all the DMA related code together there
- * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
- *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
- *   when setting an UltraDMA mode
- * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
- *   the best possible one
- * - clean up DMA timeout handling for HPT370
- * - switch to using the enumeration type to differ between the numerous chip
- *   variants, matching PCI device/revision ID with the chip type early, at the
- *   init_setup stage
- * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
- *   stop duplicating it for each channel by storing the pointer in the pci_dev
- *   structure: first, at the init_setup stage, point it to a static "template"
- *   with only the chip type and its specific base DPLL frequency, the highest
- *   UltraDMA mode, and the chip settings table pointer filled,  then, at the
- *   init_chipset stage, allocate per-chip instance  and fill it with the rest
- *   of the necessary information
- * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
- *   switch  to calculating  PCI clock frequency based on the chip's base DPLL
- *   frequency
- * - switch to using the  DPLL clock and enable UltraATA/133 mode by default on
- *   anything  newer than HPT370/A (except HPT374 that is not capable of this
- *   mode according to the manual)
- * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
- *   also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
- *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
- *   the register setting lists into the table indexed by the clock selected
- * - set the correct hwif->ultra_mask for each individual chip
- * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
- * - stop resetting HPT370's state machine before each DMA transfer as that has
- *   caused more harm than good
- *     Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-#define DRV_NAME "hpt366"
-
-/* various tuning parameters */
-#undef HPT_RESET_STATE_ENGINE
-#undef HPT_DELAY_INTERRUPT
-
-static const char *bad_ata100_5[] = {
-       "IBM-DTLA-307075",
-       "IBM-DTLA-307060",
-       "IBM-DTLA-307045",
-       "IBM-DTLA-307030",
-       "IBM-DTLA-307020",
-       "IBM-DTLA-307015",
-       "IBM-DTLA-305040",
-       "IBM-DTLA-305030",
-       "IBM-DTLA-305020",
-       "IC35L010AVER07-0",
-       "IC35L020AVER07-0",
-       "IC35L030AVER07-0",
-       "IC35L040AVER07-0",
-       "IC35L060AVER07-0",
-       "WDC AC310200R",
-       NULL
-};
-
-static const char *bad_ata66_4[] = {
-       "IBM-DTLA-307075",
-       "IBM-DTLA-307060",
-       "IBM-DTLA-307045",
-       "IBM-DTLA-307030",
-       "IBM-DTLA-307020",
-       "IBM-DTLA-307015",
-       "IBM-DTLA-305040",
-       "IBM-DTLA-305030",
-       "IBM-DTLA-305020",
-       "IC35L010AVER07-0",
-       "IC35L020AVER07-0",
-       "IC35L030AVER07-0",
-       "IC35L040AVER07-0",
-       "IC35L060AVER07-0",
-       "WDC AC310200R",
-       "MAXTOR STM3320620A",
-       NULL
-};
-
-static const char *bad_ata66_3[] = {
-       "WDC AC310200R",
-       NULL
-};
-
-static const char *bad_ata33[] = {
-       "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-       "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-       "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
-       "Maxtor 90510D4",
-       "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-       "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-       "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
-       NULL
-};
-
-static u8 xfer_speeds[] = {
-       XFER_UDMA_6,
-       XFER_UDMA_5,
-       XFER_UDMA_4,
-       XFER_UDMA_3,
-       XFER_UDMA_2,
-       XFER_UDMA_1,
-       XFER_UDMA_0,
-
-       XFER_MW_DMA_2,
-       XFER_MW_DMA_1,
-       XFER_MW_DMA_0,
-
-       XFER_PIO_4,
-       XFER_PIO_3,
-       XFER_PIO_2,
-       XFER_PIO_1,
-       XFER_PIO_0
-};
-
-/* Key for bus clock timings
- * 36x   37x
- * bits  bits
- * 0:3  0:3    data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
- *             cycles = value + 1
- * 4:7  4:8    data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
- *             cycles = value + 1
- * 8:11  9:12  cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
- *             register access.
- * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
- *             register access.
- * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
- * -    21     CLK frequency: 0=ATA clock, 1=dual ATA clock.
- * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
- *             MW DMA xfer.
- * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
- *             task file register access.
- * 28   28     UDMA enable.
- * 29   29     DMA  enable.
- * 30   30     PIO MST enable. If set, the chip is in bus master mode during
- *             PIO xfer.
- * 31   31     FIFO enable.
- */
-
-static u32 forty_base_hpt36x[] = {
-       /* XFER_UDMA_6 */       0x900fd943,
-       /* XFER_UDMA_5 */       0x900fd943,
-       /* XFER_UDMA_4 */       0x900fd943,
-       /* XFER_UDMA_3 */       0x900ad943,
-       /* XFER_UDMA_2 */       0x900bd943,
-       /* XFER_UDMA_1 */       0x9008d943,
-       /* XFER_UDMA_0 */       0x9008d943,
-
-       /* XFER_MW_DMA_2 */     0xa008d943,
-       /* XFER_MW_DMA_1 */     0xa010d955,
-       /* XFER_MW_DMA_0 */     0xa010d9fc,
-
-       /* XFER_PIO_4 */        0xc008d963,
-       /* XFER_PIO_3 */        0xc010d974,
-       /* XFER_PIO_2 */        0xc010d997,
-       /* XFER_PIO_1 */        0xc010d9c7,
-       /* XFER_PIO_0 */        0xc018d9d9
-};
-
-static u32 thirty_three_base_hpt36x[] = {
-       /* XFER_UDMA_6 */       0x90c9a731,
-       /* XFER_UDMA_5 */       0x90c9a731,
-       /* XFER_UDMA_4 */       0x90c9a731,
-       /* XFER_UDMA_3 */       0x90cfa731,
-       /* XFER_UDMA_2 */       0x90caa731,
-       /* XFER_UDMA_1 */       0x90cba731,
-       /* XFER_UDMA_0 */       0x90c8a731,
-
-       /* XFER_MW_DMA_2 */     0xa0c8a731,
-       /* XFER_MW_DMA_1 */     0xa0c8a732,     /* 0xa0c8a733 */
-       /* XFER_MW_DMA_0 */     0xa0c8a797,
-
-       /* XFER_PIO_4 */        0xc0c8a731,
-       /* XFER_PIO_3 */        0xc0c8a742,
-       /* XFER_PIO_2 */        0xc0d0a753,
-       /* XFER_PIO_1 */        0xc0d0a7a3,     /* 0xc0d0a793 */
-       /* XFER_PIO_0 */        0xc0d0a7aa      /* 0xc0d0a7a7 */
-};
-
-static u32 twenty_five_base_hpt36x[] = {
-       /* XFER_UDMA_6 */       0x90c98521,
-       /* XFER_UDMA_5 */       0x90c98521,
-       /* XFER_UDMA_4 */       0x90c98521,
-       /* XFER_UDMA_3 */       0x90cf8521,
-       /* XFER_UDMA_2 */       0x90cf8521,
-       /* XFER_UDMA_1 */       0x90cb8521,
-       /* XFER_UDMA_0 */       0x90cb8521,
-
-       /* XFER_MW_DMA_2 */     0xa0ca8521,
-       /* XFER_MW_DMA_1 */     0xa0ca8532,
-       /* XFER_MW_DMA_0 */     0xa0ca8575,
-
-       /* XFER_PIO_4 */        0xc0ca8521,
-       /* XFER_PIO_3 */        0xc0ca8532,
-       /* XFER_PIO_2 */        0xc0ca8542,
-       /* XFER_PIO_1 */        0xc0d08572,
-       /* XFER_PIO_0 */        0xc0d08585
-};
-
-/*
- * The following are the new timing tables with PIO mode data/taskfile transfer
- * overclocking fixed...
- */
-
-/* This table is taken from the HPT370 data manual rev. 1.02 */
-static u32 thirty_three_base_hpt37x[] = {
-       /* XFER_UDMA_6 */       0x16455031,     /* 0x16655031 ?? */
-       /* XFER_UDMA_5 */       0x16455031,
-       /* XFER_UDMA_4 */       0x16455031,
-       /* XFER_UDMA_3 */       0x166d5031,
-       /* XFER_UDMA_2 */       0x16495031,
-       /* XFER_UDMA_1 */       0x164d5033,
-       /* XFER_UDMA_0 */       0x16515097,
-
-       /* XFER_MW_DMA_2 */     0x26515031,
-       /* XFER_MW_DMA_1 */     0x26515033,
-       /* XFER_MW_DMA_0 */     0x26515097,
-
-       /* XFER_PIO_4 */        0x06515021,
-       /* XFER_PIO_3 */        0x06515022,
-       /* XFER_PIO_2 */        0x06515033,
-       /* XFER_PIO_1 */        0x06915065,
-       /* XFER_PIO_0 */        0x06d1508a
-};
-
-static u32 fifty_base_hpt37x[] = {
-       /* XFER_UDMA_6 */       0x1a861842,
-       /* XFER_UDMA_5 */       0x1a861842,
-       /* XFER_UDMA_4 */       0x1aae1842,
-       /* XFER_UDMA_3 */       0x1a8e1842,
-       /* XFER_UDMA_2 */       0x1a0e1842,
-       /* XFER_UDMA_1 */       0x1a161854,
-       /* XFER_UDMA_0 */       0x1a1a18ea,
-
-       /* XFER_MW_DMA_2 */     0x2a821842,
-       /* XFER_MW_DMA_1 */     0x2a821854,
-       /* XFER_MW_DMA_0 */     0x2a8218ea,
-
-       /* XFER_PIO_4 */        0x0a821842,
-       /* XFER_PIO_3 */        0x0a821843,
-       /* XFER_PIO_2 */        0x0a821855,
-       /* XFER_PIO_1 */        0x0ac218a8,
-       /* XFER_PIO_0 */        0x0b02190c
-};
-
-static u32 sixty_six_base_hpt37x[] = {
-       /* XFER_UDMA_6 */       0x1c86fe62,
-       /* XFER_UDMA_5 */       0x1caefe62,     /* 0x1c8afe62 */
-       /* XFER_UDMA_4 */       0x1c8afe62,
-       /* XFER_UDMA_3 */       0x1c8efe62,
-       /* XFER_UDMA_2 */       0x1c92fe62,
-       /* XFER_UDMA_1 */       0x1c9afe62,
-       /* XFER_UDMA_0 */       0x1c82fe62,
-
-       /* XFER_MW_DMA_2 */     0x2c82fe62,
-       /* XFER_MW_DMA_1 */     0x2c82fe66,
-       /* XFER_MW_DMA_0 */     0x2c82ff2e,
-
-       /* XFER_PIO_4 */        0x0c82fe62,
-       /* XFER_PIO_3 */        0x0c82fe84,
-       /* XFER_PIO_2 */        0x0c82fea6,
-       /* XFER_PIO_1 */        0x0d02ff26,
-       /* XFER_PIO_0 */        0x0d42ff7f
-};
-
-#define HPT371_ALLOW_ATA133_6          1
-#define HPT302_ALLOW_ATA133_6          1
-#define HPT372_ALLOW_ATA133_6          1
-#define HPT370_ALLOW_ATA100_5          0
-#define HPT366_ALLOW_ATA66_4           1
-#define HPT366_ALLOW_ATA66_3           1
-
-/* Supported ATA clock frequencies */
-enum ata_clock {
-       ATA_CLOCK_25MHZ,
-       ATA_CLOCK_33MHZ,
-       ATA_CLOCK_40MHZ,
-       ATA_CLOCK_50MHZ,
-       ATA_CLOCK_66MHZ,
-       NUM_ATA_CLOCKS
-};
-
-struct hpt_timings {
-       u32 pio_mask;
-       u32 dma_mask;
-       u32 ultra_mask;
-       u32 *clock_table[NUM_ATA_CLOCKS];
-};
-
-/*
- *     Hold all the HighPoint chip information in one place.
- */
-
-struct hpt_info {
-       char *chip_name;        /* Chip name */
-       u8 chip_type;           /* Chip type */
-       u8 udma_mask;           /* Allowed UltraDMA modes mask. */
-       u8 dpll_clk;            /* DPLL clock in MHz */
-       u8 pci_clk;             /* PCI  clock in MHz */
-       struct hpt_timings *timings; /* Chipset timing data */
-       u8 clock;               /* ATA clock selected */
-};
-
-/* Supported HighPoint chips */
-enum {
-       HPT36x,
-       HPT370,
-       HPT370A,
-       HPT374,
-       HPT372,
-       HPT372A,
-       HPT302,
-       HPT371,
-       HPT372N,
-       HPT302N,
-       HPT371N
-};
-
-static struct hpt_timings hpt36x_timings = {
-       .pio_mask       = 0xc1f8ffff,
-       .dma_mask       = 0x303800ff,
-       .ultra_mask     = 0x30070000,
-       .clock_table    = {
-               [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
-               [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
-               [ATA_CLOCK_40MHZ] = forty_base_hpt36x,
-               [ATA_CLOCK_50MHZ] = NULL,
-               [ATA_CLOCK_66MHZ] = NULL
-       }
-};
-
-static struct hpt_timings hpt37x_timings = {
-       .pio_mask       = 0xcfc3ffff,
-       .dma_mask       = 0x31c001ff,
-       .ultra_mask     = 0x303c0000,
-       .clock_table    = {
-               [ATA_CLOCK_25MHZ] = NULL,
-               [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
-               [ATA_CLOCK_40MHZ] = NULL,
-               [ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
-               [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
-       }
-};
-
-static const struct hpt_info hpt36x = {
-       .chip_name      = "HPT36x",
-       .chip_type      = HPT36x,
-       .udma_mask      = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
-       .dpll_clk       = 0,    /* no DPLL */
-       .timings        = &hpt36x_timings
-};
-
-static const struct hpt_info hpt370 = {
-       .chip_name      = "HPT370",
-       .chip_type      = HPT370,
-       .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
-       .dpll_clk       = 48,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt370a = {
-       .chip_name      = "HPT370A",
-       .chip_type      = HPT370A,
-       .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
-       .dpll_clk       = 48,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt374 = {
-       .chip_name      = "HPT374",
-       .chip_type      = HPT374,
-       .udma_mask      = ATA_UDMA5,
-       .dpll_clk       = 48,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372 = {
-       .chip_name      = "HPT372",
-       .chip_type      = HPT372,
-       .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 55,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372a = {
-       .chip_name      = "HPT372A",
-       .chip_type      = HPT372A,
-       .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 66,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt302 = {
-       .chip_name      = "HPT302",
-       .chip_type      = HPT302,
-       .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 66,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt371 = {
-       .chip_name      = "HPT371",
-       .chip_type      = HPT371,
-       .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 66,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372n = {
-       .chip_name      = "HPT372N",
-       .chip_type      = HPT372N,
-       .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 77,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt302n = {
-       .chip_name      = "HPT302N",
-       .chip_type      = HPT302N,
-       .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 77,
-       .timings        = &hpt37x_timings
-};
-
-static const struct hpt_info hpt371n = {
-       .chip_name      = "HPT371N",
-       .chip_type      = HPT371N,
-       .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
-       .dpll_clk       = 77,
-       .timings        = &hpt37x_timings
-};
-
-static bool check_in_drive_list(ide_drive_t *drive, const char **list)
-{
-       return match_string(list, -1, (char *)&drive->id[ATA_ID_PROD]) >= 0;
-}
-
-static struct hpt_info *hpt3xx_get_info(struct device *dev)
-{
-       struct ide_host *host   = dev_get_drvdata(dev);
-       struct hpt_info *info   = (struct hpt_info *)host->host_priv;
-
-       return dev == host->dev[1] ? info + 1 : info;
-}
-
-/*
- * The Marvell bridge chips used on the HighPoint SATA cards do not seem
- * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
- */
-
-static u8 hpt3xx_udma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-       u8 mask                 = hwif->ultra_mask;
-
-       switch (info->chip_type) {
-       case HPT36x:
-               if (!HPT366_ALLOW_ATA66_4 ||
-                   check_in_drive_list(drive, bad_ata66_4))
-                       mask = ATA_UDMA3;
-
-               if (!HPT366_ALLOW_ATA66_3 ||
-                   check_in_drive_list(drive, bad_ata66_3))
-                       mask = ATA_UDMA2;
-               break;
-       case HPT370:
-               if (!HPT370_ALLOW_ATA100_5 ||
-                   check_in_drive_list(drive, bad_ata100_5))
-                       mask = ATA_UDMA4;
-               break;
-       case HPT370A:
-               if (!HPT370_ALLOW_ATA100_5 ||
-                   check_in_drive_list(drive, bad_ata100_5))
-                       return ATA_UDMA4;
-               fallthrough;
-       case HPT372 :
-       case HPT372A:
-       case HPT372N:
-       case HPT374 :
-               if (ata_id_is_sata(drive->id))
-                       mask &= ~0x0e;
-               fallthrough;
-       default:
-               return mask;
-       }
-
-       return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
-}
-
-static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-
-       switch (info->chip_type) {
-       case HPT372 :
-       case HPT372A:
-       case HPT372N:
-       case HPT374 :
-               if (ata_id_is_sata(drive->id))
-                       return 0x00;
-               fallthrough;
-       default:
-               return 0x07;
-       }
-}
-
-static u32 get_speed_setting(u8 speed, struct hpt_info *info)
-{
-       int i;
-
-       /*
-        * Lookup the transfer mode table to get the index into
-        * the timing table.
-        *
-        * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
-        */
-       for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
-               if (xfer_speeds[i] == speed)
-                       break;
-
-       return info->timings->clock_table[info->clock][i];
-}
-
-static void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-       struct hpt_timings *t   = info->timings;
-       u8  itr_addr            = 0x40 + (drive->dn * 4);
-       u32 old_itr             = 0;
-       const u8 speed          = drive->dma_mode;
-       u32 new_itr             = get_speed_setting(speed, info);
-       u32 itr_mask            = speed < XFER_MW_DMA_0 ? t->pio_mask :
-                                (speed < XFER_UDMA_0   ? t->dma_mask :
-                                                         t->ultra_mask);
-
-       pci_read_config_dword(dev, itr_addr, &old_itr);
-       new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
-       /*
-        * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
-        * to avoid problems handling I/O errors later
-        */
-       new_itr &= ~0xc0000000;
-
-       pci_write_config_dword(dev, itr_addr, new_itr);
-}
-
-static void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       hpt3xx_set_mode(hwif, drive);
-}
-
-static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-
-       if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
-               return;
-
-       if (info->chip_type >= HPT370) {
-               u8 scr1 = 0;
-
-               pci_read_config_byte(dev, 0x5a, &scr1);
-               if (((scr1 & 0x10) >> 4) != mask) {
-                       if (mask)
-                               scr1 |=  0x10;
-                       else
-                               scr1 &= ~0x10;
-                       pci_write_config_byte(dev, 0x5a, scr1);
-               }
-       } else if (mask)
-               disable_irq(hwif->irq);
-       else
-               enable_irq(hwif->irq);
-}
-
-/*
- * This is specific to the HPT366 UDMA chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-static void hpt366_dma_lost_irq(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
-
-       pci_read_config_byte(dev, 0x50, &mcr1);
-       pci_read_config_byte(dev, 0x52, &mcr3);
-       pci_read_config_byte(dev, 0x5a, &scr1);
-       printk("%s: (%s)  mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
-               drive->name, __func__, mcr1, mcr3, scr1);
-       if (scr1 & 0x10)
-               pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
-       ide_dma_lost_irq(drive);
-}
-
-static void hpt370_clear_engine(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       pci_write_config_byte(dev, hwif->select_data, 0x37);
-       udelay(10);
-}
-
-static void hpt370_irq_timeout(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u16 bfifo               = 0;
-       u8  dma_cmd;
-
-       pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
-       printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
-
-       /* get DMA command mode */
-       dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-       /* stop DMA */
-       outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
-       hpt370_clear_engine(drive);
-}
-
-static void hpt370_dma_start(ide_drive_t *drive)
-{
-#ifdef HPT_RESET_STATE_ENGINE
-       hpt370_clear_engine(drive);
-#endif
-       ide_dma_start(drive);
-}
-
-static int hpt370_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       u8  dma_stat            = inb(hwif->dma_base + ATA_DMA_STATUS);
-
-       if (dma_stat & ATA_DMA_ACTIVE) {
-               /* wait a little */
-               udelay(20);
-               dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-               if (dma_stat & ATA_DMA_ACTIVE)
-                       hpt370_irq_timeout(drive);
-       }
-       return ide_dma_end(drive);
-}
-
-/* returns 1 if DMA IRQ issued, 0 otherwise */
-static int hpt374_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u16 bfifo               = 0;
-       u8  dma_stat;
-
-       pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
-       if (bfifo & 0x1FF) {
-//             printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
-               return 0;
-       }
-
-       dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-       /* return 1 if INTR asserted */
-       if (dma_stat & ATA_DMA_INTR)
-               return 1;
-
-       return 0;
-}
-
-static int hpt374_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 mcr  = 0, mcr_addr   = hwif->select_data;
-       u8 bwsr = 0, mask       = hwif->channel ? 0x02 : 0x01;
-
-       pci_read_config_byte(dev, 0x6a, &bwsr);
-       pci_read_config_byte(dev, mcr_addr, &mcr);
-       if (bwsr & mask)
-               pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
-       return ide_dma_end(drive);
-}
-
-/**
- *     hpt3xxn_set_clock       -       perform clock switching dance
- *     @hwif: hwif to switch
- *     @mode: clocking mode (0x21 for write, 0x23 otherwise)
- *
- *     Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
- */
-
-static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
-{
-       unsigned long base = hwif->extra_base;
-       u8 scr2 = inb(base + 0x6b);
-
-       if ((scr2 & 0x7f) == mode)
-               return;
-
-       /* Tristate the bus */
-       outb(0x80, base + 0x63);
-       outb(0x80, base + 0x67);
-
-       /* Switch clock and reset channels */
-       outb(mode, base + 0x6b);
-       outb(0xc0, base + 0x69);
-
-       /*
-        * Reset the state machines.
-        * NOTE: avoid accidentally enabling the disabled channels.
-        */
-       outb(inb(base + 0x60) | 0x32, base + 0x60);
-       outb(inb(base + 0x64) | 0x32, base + 0x64);
-
-       /* Complete reset */
-       outb(0x00, base + 0x69);
-
-       /* Reconnect channels to bus */
-       outb(0x00, base + 0x63);
-       outb(0x00, base + 0x67);
-}
-
-/**
- *     hpt3xxn_rw_disk         -       prepare for I/O
- *     @drive: drive for command
- *     @rq: block request structure
- *
- *     This is called when a disk I/O is issued to HPT3xxN.
- *     We need it because of the clock switching.
- */
-
-static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
-{
-       hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23);
-}
-
-/**
- *     hpt37x_calibrate_dpll   -       calibrate the DPLL
- *     @dev: PCI device
- *
- *     Perform a calibration cycle on the DPLL.
- *     Returns 1 if this succeeds
- */
-static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
-{
-       u32 dpll = (f_high << 16) | f_low | 0x100;
-       u8  scr2;
-       int i;
-
-       pci_write_config_dword(dev, 0x5c, dpll);
-
-       /* Wait for oscillator ready */
-       for(i = 0; i < 0x5000; ++i) {
-               udelay(50);
-               pci_read_config_byte(dev, 0x5b, &scr2);
-               if (scr2 & 0x80)
-                       break;
-       }
-       /* See if it stays ready (we'll just bail out if it's not yet) */
-       for(i = 0; i < 0x1000; ++i) {
-               pci_read_config_byte(dev, 0x5b, &scr2);
-               /* DPLL destabilized? */
-               if(!(scr2 & 0x80))
-                       return 0;
-       }
-       /* Turn off tuning, we have the DPLL set */
-       pci_read_config_dword (dev, 0x5c, &dpll);
-       pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
-       return 1;
-}
-
-static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
-{
-       struct ide_host *host   = pci_get_drvdata(dev);
-       struct hpt_info *info   = host->host_priv + (&dev->dev == host->dev[1]);
-       u8  chip_type           = info->chip_type;
-       u8  new_mcr, old_mcr    = 0;
-
-       /*
-        * Disable the "fast interrupt" prediction.  Don't hold off
-        * on interrupts. (== 0x01 despite what the docs say)
-        */
-       pci_read_config_byte(dev, mcr_addr + 1, &old_mcr);
-
-       if (chip_type >= HPT374)
-               new_mcr = old_mcr & ~0x07;
-       else if (chip_type >= HPT370) {
-               new_mcr = old_mcr;
-               new_mcr &= ~0x02;
-#ifdef HPT_DELAY_INTERRUPT
-               new_mcr &= ~0x01;
-#else
-               new_mcr |=  0x01;
-#endif
-       } else                                  /* HPT366 and HPT368  */
-               new_mcr = old_mcr & ~0x80;
-
-       if (new_mcr != old_mcr)
-               pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
-}
-
-static int init_chipset_hpt366(struct pci_dev *dev)
-{
-       unsigned long io_base   = pci_resource_start(dev, 4);
-       struct hpt_info *info   = hpt3xx_get_info(&dev->dev);
-       const char *name        = DRV_NAME;
-       u8 pci_clk,  dpll_clk   = 0;    /* PCI and DPLL clock in MHz */
-       u8 chip_type;
-       enum ata_clock  clock;
-
-       chip_type = info->chip_type;
-
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-       pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-       pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-       /*
-        * First, try to estimate the PCI clock frequency...
-        */
-       if (chip_type >= HPT370) {
-               u8  scr1  = 0;
-               u16 f_cnt = 0;
-               u32 temp  = 0;
-
-               /* Interrupt force enable. */
-               pci_read_config_byte(dev, 0x5a, &scr1);
-               if (scr1 & 0x10)
-                       pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
-
-               /*
-                * HighPoint does this for HPT372A.
-                * NOTE: This register is only writeable via I/O space.
-                */
-               if (chip_type == HPT372A)
-                       outb(0x0e, io_base + 0x9c);
-
-               /*
-                * Default to PCI clock. Make sure MA15/16 are set to output
-                * to prevent drives having problems with 40-pin cables.
-                */
-               pci_write_config_byte(dev, 0x5b, 0x23);
-
-               /*
-                * We'll have to read f_CNT value in order to determine
-                * the PCI clock frequency according to the following ratio:
-                *
-                * f_CNT = Fpci * 192 / Fdpll
-                *
-                * First try reading the register in which the HighPoint BIOS
-                * saves f_CNT value before  reprogramming the DPLL from its
-                * default setting (which differs for the various chips).
-                *
-                * NOTE: This register is only accessible via I/O space;
-                * HPT374 BIOS only saves it for the function 0, so we have to
-                * always read it from there -- no need to check the result of
-                * pci_get_slot() for the function 0 as the whole device has
-                * been already "pinned" (via function 1) in init_setup_hpt374()
-                */
-               if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
-                       struct pci_dev  *dev1 = pci_get_slot(dev->bus,
-                                                            dev->devfn - 1);
-                       unsigned long io_base = pci_resource_start(dev1, 4);
-
-                       temp =  inl(io_base + 0x90);
-                       pci_dev_put(dev1);
-               } else
-                       temp =  inl(io_base + 0x90);
-
-               /*
-                * In case the signature check fails, we'll have to
-                * resort to reading the f_CNT register itself in hopes
-                * that nobody has touched the DPLL yet...
-                */
-               if ((temp & 0xFFFFF000) != 0xABCDE000) {
-                       int i;
-
-                       printk(KERN_WARNING "%s %s: no clock data saved by "
-                               "BIOS\n", name, pci_name(dev));
-
-                       /* Calculate the average value of f_CNT. */
-                       for (temp = i = 0; i < 128; i++) {
-                               pci_read_config_word(dev, 0x78, &f_cnt);
-                               temp += f_cnt & 0x1ff;
-                               mdelay(1);
-                       }
-                       f_cnt = temp / 128;
-               } else
-                       f_cnt = temp & 0x1ff;
-
-               dpll_clk = info->dpll_clk;
-               pci_clk  = (f_cnt * dpll_clk) / 192;
-
-               /* Clamp PCI clock to bands. */
-               if (pci_clk < 40)
-                       pci_clk = 33;
-               else if(pci_clk < 45)
-                       pci_clk = 40;
-               else if(pci_clk < 55)
-                       pci_clk = 50;
-               else
-                       pci_clk = 66;
-
-               printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, "
-                       "assuming %d MHz PCI\n", name, pci_name(dev),
-                       dpll_clk, f_cnt, pci_clk);
-       } else {
-               u32 itr1 = 0;
-
-               pci_read_config_dword(dev, 0x40, &itr1);
-
-               /* Detect PCI clock by looking at cmd_high_time. */
-               switch ((itr1 >> 8) & 0x0f) {
-                       case 0x09:
-                               pci_clk = 40;
-                               break;
-                       case 0x05:
-                               pci_clk = 25;
-                               break;
-                       case 0x07:
-                       default:
-                               pci_clk = 33;
-                               break;
-               }
-       }
-
-       /* Let's assume we'll use PCI clock for the ATA clock... */
-       switch (pci_clk) {
-               case 25:
-                       clock = ATA_CLOCK_25MHZ;
-                       break;
-               case 33:
-               default:
-                       clock = ATA_CLOCK_33MHZ;
-                       break;
-               case 40:
-                       clock = ATA_CLOCK_40MHZ;
-                       break;
-               case 50:
-                       clock = ATA_CLOCK_50MHZ;
-                       break;
-               case 66:
-                       clock = ATA_CLOCK_66MHZ;
-                       break;
-       }
-
-       /*
-        * Only try the DPLL if we don't have a table for the PCI clock that
-        * we are running at for HPT370/A, always use it  for anything newer...
-        *
-        * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
-        * We also  don't like using  the DPLL because this causes glitches
-        * on PRST-/SRST- when the state engine gets reset...
-        */
-       if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
-               u16 f_low, delta = pci_clk < 50 ? 2 : 4;
-               int adjust;
-
-                /*
-                 * Select 66 MHz DPLL clock only if UltraATA/133 mode is
-                 * supported/enabled, use 50 MHz DPLL clock otherwise...
-                 */
-               if (info->udma_mask == ATA_UDMA6) {
-                       dpll_clk = 66;
-                       clock = ATA_CLOCK_66MHZ;
-               } else if (dpll_clk) {  /* HPT36x chips don't have DPLL */
-                       dpll_clk = 50;
-                       clock = ATA_CLOCK_50MHZ;
-               }
-
-               if (info->timings->clock_table[clock] == NULL) {
-                       printk(KERN_ERR "%s %s: unknown bus timing!\n",
-                               name, pci_name(dev));
-                       return -EIO;
-               }
-
-               /* Select the DPLL clock. */
-               pci_write_config_byte(dev, 0x5b, 0x21);
-
-               /*
-                * Adjust the DPLL based upon PCI clock, enable it,
-                * and wait for stabilization...
-                */
-               f_low = (pci_clk * 48) / dpll_clk;
-
-               for (adjust = 0; adjust < 8; adjust++) {
-                       if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
-                               break;
-
-                       /*
-                        * See if it'll settle at a fractionally different clock
-                        */
-                       if (adjust & 1)
-                               f_low -= adjust >> 1;
-                       else
-                               f_low += adjust >> 1;
-               }
-               if (adjust == 8) {
-                       printk(KERN_ERR "%s %s: DPLL did not stabilize!\n",
-                               name, pci_name(dev));
-                       return -EIO;
-               }
-
-               printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n",
-                       name, pci_name(dev), dpll_clk);
-       } else {
-               /* Mark the fact that we're not using the DPLL. */
-               dpll_clk = 0;
-
-               printk(KERN_INFO "%s %s: using %d MHz PCI clock\n",
-                       name, pci_name(dev), pci_clk);
-       }
-
-       /* Store the clock frequencies. */
-       info->dpll_clk  = dpll_clk;
-       info->pci_clk   = pci_clk;
-       info->clock     = clock;
-
-       if (chip_type >= HPT370) {
-               u8  mcr1, mcr4;
-
-               /*
-                * Reset the state engines.
-                * NOTE: Avoid accidentally enabling the disabled channels.
-                */
-               pci_read_config_byte (dev, 0x50, &mcr1);
-               pci_read_config_byte (dev, 0x54, &mcr4);
-               pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
-               pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
-               udelay(100);
-       }
-
-       /*
-        * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
-        * the MISC. register to stretch the UltraDMA Tss timing.
-        * NOTE: This register is only writeable via I/O space.
-        */
-       if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
-               outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
-
-       hpt3xx_disable_fast_irq(dev, 0x50);
-       hpt3xx_disable_fast_irq(dev, 0x54);
-
-       return 0;
-}
-
-static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-       u8 chip_type            = info->chip_type;
-       u8 scr1 = 0, ata66      = hwif->channel ? 0x01 : 0x02;
-
-       /*
-        * The HPT37x uses the CBLID pins as outputs for MA15/MA16
-        * address lines to access an external EEPROM.  To read valid
-        * cable detect state the pins must be enabled as inputs.
-        */
-       if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
-               /*
-                * HPT374 PCI function 1
-                * - set bit 15 of reg 0x52 to enable TCBLID as input
-                * - set bit 15 of reg 0x56 to enable FCBLID as input
-                */
-               u8  mcr_addr = hwif->select_data + 2;
-               u16 mcr;
-
-               pci_read_config_word(dev, mcr_addr, &mcr);
-               pci_write_config_word(dev, mcr_addr, mcr | 0x8000);
-               /* Debounce, then read cable ID register */
-               udelay(10);
-               pci_read_config_byte(dev, 0x5a, &scr1);
-               pci_write_config_word(dev, mcr_addr, mcr);
-       } else if (chip_type >= HPT370) {
-               /*
-                * HPT370/372 and 374 pcifn 0
-                * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
-                */
-               u8 scr2 = 0;
-
-               pci_read_config_byte(dev, 0x5b, &scr2);
-               pci_write_config_byte(dev, 0x5b, scr2 & ~1);
-               /* Debounce, then read cable ID register */
-               udelay(10);
-               pci_read_config_byte(dev, 0x5a, &scr1);
-               pci_write_config_byte(dev, 0x5b, scr2);
-       } else
-               pci_read_config_byte(dev, 0x5a, &scr1);
-
-       return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static void init_hwif_hpt366(ide_hwif_t *hwif)
-{
-       struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-       u8  chip_type           = info->chip_type;
-
-       /* Cache the channel's MISC. control registers' offset */
-       hwif->select_data       = hwif->channel ? 0x54 : 0x50;
-
-       /*
-        * HPT3xxN chips have some complications:
-        *
-        * - on 33 MHz PCI we must clock switch
-        * - on 66 MHz PCI we must NOT use the PCI clock
-        */
-       if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
-               /*
-                * Clock is shared between the channels,
-                * so we'll have to serialize them... :-(
-                */
-               hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
-               hwif->rw_disk = &hpt3xxn_rw_disk;
-       }
-}
-
-static int init_dma_hpt366(ide_hwif_t *hwif,
-                                    const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long flags, base = ide_pci_dma_base(hwif, d);
-       u8 dma_old, dma_new, masterdma = 0, slavedma = 0;
-
-       if (base == 0)
-               return -1;
-
-       hwif->dma_base = base;
-
-       if (ide_pci_check_simplex(hwif, d) < 0)
-               return -1;
-
-       if (ide_pci_set_master(dev, d->name) < 0)
-               return -1;
-
-       dma_old = inb(base + 2);
-
-       local_irq_save(flags);
-
-       dma_new = dma_old;
-       pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
-       pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47,  &slavedma);
-
-       if (masterdma & 0x30)   dma_new |= 0x20;
-       if ( slavedma & 0x30)   dma_new |= 0x40;
-       if (dma_new != dma_old)
-               outb(dma_new, base + 2);
-
-       local_irq_restore(flags);
-
-       printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx\n",
-                        hwif->name, base, base + 7);
-
-       hwif->extra_base = base + (hwif->channel ? 8 : 16);
-
-       if (ide_allocate_dma_engine(hwif))
-               return -1;
-
-       return 0;
-}
-
-static void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
-{
-       if (dev2->irq != dev->irq) {
-               /* FIXME: we need a core pci_set_interrupt() */
-               dev2->irq = dev->irq;
-               printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt "
-                       "fixed\n", pci_name(dev2));
-       }
-}
-
-static void hpt371_init(struct pci_dev *dev)
-{
-       u8 mcr1 = 0;
-
-       /*
-        * HPT371 chips physically have only one channel, the secondary one,
-        * but the primary channel registers do exist!  Go figure...
-        * So,  we manually disable the non-existing channel here
-        * (if the BIOS hasn't done this already).
-        */
-       pci_read_config_byte(dev, 0x50, &mcr1);
-       if (mcr1 & 0x04)
-               pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
-}
-
-static int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
-{
-       u8 mcr1 = 0, pin1 = 0, pin2 = 0;
-
-       /*
-        * Now we'll have to force both channels enabled if
-        * at least one of them has been enabled by BIOS...
-        */
-       pci_read_config_byte(dev, 0x50, &mcr1);
-       if (mcr1 & 0x30)
-               pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
-
-       pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin1);
-       pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-
-       if (pin1 != pin2 && dev->irq == dev2->irq) {
-               printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, "
-                       "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2);
-               return 1;
-       }
-
-       return 0;
-}
-
-#define IDE_HFLAGS_HPT3XX \
-       (IDE_HFLAG_NO_ATAPI_DMA | \
-        IDE_HFLAG_OFF_BOARD)
-
-static const struct ide_port_ops hpt3xx_port_ops = {
-       .set_pio_mode           = hpt3xx_set_pio_mode,
-       .set_dma_mode           = hpt3xx_set_mode,
-       .maskproc               = hpt3xx_maskproc,
-       .mdma_filter            = hpt3xx_mdma_filter,
-       .udma_filter            = hpt3xx_udma_filter,
-       .cable_detect           = hpt3xx_cable_detect,
-};
-
-static const struct ide_dma_ops hpt37x_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = hpt374_dma_end,
-       .dma_test_irq           = hpt374_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_dma_ops hpt370_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = hpt370_dma_start,
-       .dma_end                = hpt370_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_clear              = hpt370_irq_timeout,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_dma_ops hpt36x_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = hpt366_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info hpt366_chipsets[] = {
-       {       /* 0: HPT36x */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_hpt366,
-               .init_hwif      = init_hwif_hpt366,
-               .init_dma       = init_dma_hpt366,
-               /*
-                * HPT36x chips have one channel per function and have
-                * both channel enable bits located differently and visible
-                * to both functions -- really stupid design decision... :-(
-                * Bit 4 is for the primary channel, bit 5 for the secondary.
-                */
-               .enablebits     = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
-               .port_ops       = &hpt3xx_port_ops,
-               .dma_ops        = &hpt36x_dma_ops,
-               .host_flags     = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-       },
-       {       /* 1: HPT3xx */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_hpt366,
-               .init_hwif      = init_hwif_hpt366,
-               .init_dma       = init_dma_hpt366,
-               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-               .port_ops       = &hpt3xx_port_ops,
-               .dma_ops        = &hpt37x_dma_ops,
-               .host_flags     = IDE_HFLAGS_HPT3XX,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-       }
-};
-
-/**
- *     hpt366_init_one -       called when an HPT366 is found
- *     @dev: the hpt366 device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       const struct hpt_info *info = NULL;
-       struct hpt_info *dyn_info;
-       struct pci_dev *dev2 = NULL;
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-       u8 rev = dev->revision;
-       int ret;
-
-       if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1))
-               return -ENODEV;
-
-       switch (idx) {
-       case 0:
-               if (rev < 3)
-                       info = &hpt36x;
-               else {
-                       switch (min_t(u8, rev, 6)) {
-                       case 3: info = &hpt370;  break;
-                       case 4: info = &hpt370a; break;
-                       case 5: info = &hpt372;  break;
-                       case 6: info = &hpt372n; break;
-                       }
-                       idx++;
-               }
-               break;
-       case 1:
-               info = (rev > 1) ? &hpt372n : &hpt372a;
-               break;
-       case 2:
-               info = (rev > 1) ? &hpt302n : &hpt302;
-               break;
-       case 3:
-               hpt371_init(dev);
-               info = (rev > 1) ? &hpt371n : &hpt371;
-               break;
-       case 4:
-               info = &hpt374;
-               break;
-       case 5:
-               info = &hpt372n;
-               break;
-       }
-
-       printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name);
-
-       d = hpt366_chipsets[min_t(u8, idx, 1)];
-
-       d.udma_mask = info->udma_mask;
-
-       /* fixup ->dma_ops for HPT370/HPT370A */
-       if (info == &hpt370 || info == &hpt370a)
-               d.dma_ops = &hpt370_dma_ops;
-
-       if (info == &hpt36x || info == &hpt374)
-               dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
-
-       dyn_info = kcalloc(dev2 ? 2 : 1, sizeof(*dyn_info), GFP_KERNEL);
-       if (dyn_info == NULL) {
-               printk(KERN_ERR "%s %s: out of memory!\n",
-                       d.name, pci_name(dev));
-               pci_dev_put(dev2);
-               return -ENOMEM;
-       }
-
-       /*
-        * Copy everything from a static "template" structure
-        * to just allocated per-chip hpt_info structure.
-        */
-       memcpy(dyn_info, info, sizeof(*dyn_info));
-
-       if (dev2) {
-               memcpy(dyn_info + 1, info, sizeof(*dyn_info));
-
-               if (info == &hpt374)
-                       hpt374_init(dev, dev2);
-               else {
-                       if (hpt36x_init(dev, dev2))
-                               d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE;
-               }
-
-               ret = ide_pci_init_two(dev, dev2, &d, dyn_info);
-               if (ret < 0) {
-                       pci_dev_put(dev2);
-                       kfree(dyn_info);
-               }
-               return ret;
-       }
-
-       ret = ide_pci_init_one(dev, &d, dyn_info);
-       if (ret < 0)
-               kfree(dyn_info);
-
-       return ret;
-}
-
-static void hpt366_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct ide_info *info = host->host_priv;
-       struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
-       ide_pci_remove(dev);
-       pci_dev_put(dev2);
-       kfree(info);
-}
-
-static const struct pci_device_id hpt366_pci_tbl[] = {
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366),  0 },
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372),  1 },
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302),  2 },
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371),  3 },
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374),  4 },
-       { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
-
-static struct pci_driver hpt366_pci_driver = {
-       .name           = "HPT366_IDE",
-       .id_table       = hpt366_pci_tbl,
-       .probe          = hpt366_init_one,
-       .remove         = hpt366_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init hpt366_ide_init(void)
-{
-       return ide_pci_register_driver(&hpt366_pci_driver);
-}
-
-static void __exit hpt366_ide_exit(void)
-{
-       pci_unregister_driver(&hpt366_pci_driver);
-}
-
-module_init(hpt366_ide_init);
-module_exit(hpt366_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
deleted file mode 100644 (file)
index 743bc36..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
- *  HT-6560B EIDE-controller support
- *  To activate controller support use kernel parameter "ide0=ht6560b".
- *  Use hdparm utility to enable PIO mode support.
- *
- *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
- *             Jan Evert van Grootheest   <j.e.van.grootheest@caiway.nl>
- *
- */
-
-#define DRV_NAME       "ht6560b"
-#define HT6560B_VERSION "v0.08"
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-/* #define DEBUG */  /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit2 (0x04): "1" enables FIFO function
- *    bit5 (0x20): "1" enables prefetched data read function  (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit1 (0x02): "1" enables prefetched data read function
- *    bit2 (0x04): "0" enables multi-master system           (?)
- *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time        (?)
- */
-#define HT_CONFIG_PORT   0x3e6
-
-static inline u8 HT_CONFIG(ide_drive_t *drive)
-{
-       return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8;
-}
-
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF          0x01
-#define HT_PREFETCH_MODE  0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use Select register to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives.   [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
- * of the value is the Active Time  (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- *     High nibble:  Recovery Cycle Time  (rt)
- *          The valid values range from 2 to 15. The default is 15.
- *
- *     Low nibble:   Active Cycle Time    (at)
- *          The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-static inline u8 HT_TIMING(ide_drive_t *drive)
-{
-       return (unsigned long)ide_get_drivedata(drive) & 0x00ff;
-}
-
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_dev_select(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long flags;
-       static u8 current_select = 0;
-       static u8 current_timing = 0;
-       u8 select, timing;
-       
-       local_irq_save(flags);
-
-       select = HT_CONFIG(drive);
-       timing = HT_TIMING(drive);
-
-       /*
-        * Need to enforce prefetch sometimes because otherwise
-        * it'll hang (hard).
-        */
-       if (drive->media != ide_disk ||
-           (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               select |= HT_PREFETCH_MODE;
-
-       if (select != current_select || timing != current_timing) {
-               current_select = select;
-               current_timing = timing;
-               (void)inb(HT_CONFIG_PORT);
-               (void)inb(HT_CONFIG_PORT);
-               (void)inb(HT_CONFIG_PORT);
-               (void)inb(HT_CONFIG_PORT);
-               outb(select, HT_CONFIG_PORT);
-               /*
-                * Set timing for this drive:
-                */
-               outb(timing, hwif->io_ports.device_addr);
-               (void)inb(hwif->io_ports.status_addr);
-#ifdef DEBUG
-               printk("ht6560b: %s: select=%#x timing=%#x\n",
-                       drive->name, select, timing);
-#endif
-       }
-       local_irq_restore(flags);
-
-       outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr);
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-       u8 orig_value;
-       int i;
-       
-       /* Autodetect ht6560b */
-       if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
-               return 0;
-       
-       for (i=3;i>0;i--) {
-               outb(0x00, HT_CONFIG_PORT);
-               if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
-                       outb(orig_value, HT_CONFIG_PORT);
-                       return 0;
-               }
-       }
-       outb(0x00, HT_CONFIG_PORT);
-       if ((~inb(HT_CONFIG_PORT))& 0x3f) {
-               outb(orig_value, HT_CONFIG_PORT);
-               return 0;
-       }
-       /*
-        * Ht6560b autodetected
-        */
-       outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-       outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */
-       (void)inb(0x1f7);               /* Status register */
-
-       printk("ht6560b " HT6560B_VERSION
-              ": chipset detected and initialized"
-#ifdef DEBUG
-              " with debug enabled"
-#endif
-              "\n"
-               );
-       return 1;
-}
-
-static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
-{
-       int active_time, recovery_time;
-       int active_cycles, recovery_cycles;
-       int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
-
-        if (pio) {
-               unsigned int cycle_time;
-               struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-
-               cycle_time = ide_pio_cycle_time(drive, pio);
-
-               /*
-                *  Just like opti621.c we try to calculate the
-                *  actual cycle time for recovery and activity
-                *  according system bus speed.
-                */
-               active_time = t->active;
-               recovery_time = cycle_time - active_time - t->setup;
-               /*
-                *  Cycle times should be Vesa bus cycles
-                */
-               active_cycles   = (active_time   * bus_speed + 999) / 1000;
-               recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
-               /*
-                *  Upper and lower limits
-                */
-               if (active_cycles   < 2)  active_cycles   = 2;
-               if (recovery_cycles < 2)  recovery_cycles = 2;
-               if (active_cycles   > 15) active_cycles   = 15;
-               if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-               
-#ifdef DEBUG
-               printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-               
-               return (u8)((recovery_cycles << 4) | active_cycles);
-       } else {
-               
-#ifdef DEBUG
-               printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-               
-               return HT_TIMING_DEFAULT;    /* default setting */
-       }
-}
-
-static DEFINE_SPINLOCK(ht6560b_lock);
-
-/*
- *  Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, u8 state)
-{
-       unsigned long flags, config;
-       int t = HT_PREFETCH_MODE << 8;
-
-       spin_lock_irqsave(&ht6560b_lock, flags);
-
-       config = (unsigned long)ide_get_drivedata(drive);
-
-       /*
-        *  Prefetch mode and unmask irq seems to conflict
-        */
-       if (state) {
-               config |= t;   /* enable prefetch mode */
-               drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
-               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-       } else {
-               config &= ~t;  /* disable prefetch mode */
-               drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
-       }
-
-       ide_set_drivedata(drive, (void *)config);
-
-       spin_unlock_irqrestore(&ht6560b_lock, flags);
-
-#ifdef DEBUG
-       printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long flags, config;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       u8 timing;
-       
-       switch (pio) {
-       case 8:         /* set prefetch off */
-       case 9:         /* set prefetch on */
-               ht_set_prefetch(drive, pio & 1);
-               return;
-       }
-
-       timing = ht_pio2timings(drive, pio);
-
-       spin_lock_irqsave(&ht6560b_lock, flags);
-       config = (unsigned long)ide_get_drivedata(drive);
-       config &= 0xff00;
-       config |= timing;
-       ide_set_drivedata(drive, (void *)config);
-       spin_unlock_irqrestore(&ht6560b_lock, flags);
-
-#ifdef DEBUG
-       printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-static void __init ht6560b_init_dev(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       /* Setting default configurations for drives. */
-       unsigned long t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
-
-       if (hwif->channel)
-               t |= (HT_SECONDARY_IF << 8);
-
-       ide_set_drivedata(drive, (void *)t);
-}
-
-static bool probe_ht6560b;
-
-module_param_named(probe, probe_ht6560b, bool, 0);
-MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
-
-static const struct ide_tp_ops ht6560b_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ht6560b_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 ht6560b_port_ops = {
-       .init_dev               = ht6560b_init_dev,
-       .set_pio_mode           = ht6560b_set_pio_mode,
-};
-
-static const struct ide_port_info ht6560b_port_info __initconst = {
-       .name                   = DRV_NAME,
-       .chipset                = ide_ht6560b,
-       .tp_ops                 = &ht6560b_tp_ops,
-       .port_ops               = &ht6560b_port_ops,
-       .host_flags             = IDE_HFLAG_SERIALIZE | /* is this needed? */
-                                 IDE_HFLAG_NO_DMA |
-                                 IDE_HFLAG_ABUSE_PREFETCH,
-       .pio_mask               = ATA_PIO4,
-};
-
-static int __init ht6560b_init(void)
-{
-       if (probe_ht6560b == 0)
-               return -ENODEV;
-
-       if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) {
-               printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (!try_to_init_ht6560b()) {
-               printk(KERN_NOTICE "%s: HBA not found\n", __func__);
-               goto release_region;
-       }
-
-       return ide_legacy_device_add(&ht6560b_port_info, 0);
-
-release_region:
-       release_region(HT_CONFIG_PORT, 1);
-       return -ENODEV;
-}
-
-module_init(ht6560b_init);
-
-MODULE_AUTHOR("See Local File");
-MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
deleted file mode 100644 (file)
index 329c7e4..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 1996-2004 Russell King.
- *
- * Please note that this platform does not support 32-bit IDE IO.
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/scatterlist.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-
-#define DRV_NAME "icside"
-
-#define ICS_IDENT_OFFSET               0x2280
-
-#define ICS_ARCIN_V5_INTRSTAT          0x0000
-#define ICS_ARCIN_V5_INTROFFSET                0x0004
-#define ICS_ARCIN_V5_IDEOFFSET         0x2800
-#define ICS_ARCIN_V5_IDEALTOFFSET      0x2b80
-#define ICS_ARCIN_V5_IDESTEPPING       6
-
-#define ICS_ARCIN_V6_IDEOFFSET_1       0x2000
-#define ICS_ARCIN_V6_INTROFFSET_1      0x2200
-#define ICS_ARCIN_V6_INTRSTAT_1                0x2290
-#define ICS_ARCIN_V6_IDEALTOFFSET_1    0x2380
-#define ICS_ARCIN_V6_IDEOFFSET_2       0x3000
-#define ICS_ARCIN_V6_INTROFFSET_2      0x3200
-#define ICS_ARCIN_V6_INTRSTAT_2                0x3290
-#define ICS_ARCIN_V6_IDEALTOFFSET_2    0x3380
-#define ICS_ARCIN_V6_IDESTEPPING       6
-
-struct cardinfo {
-       unsigned int dataoffset;
-       unsigned int ctrloffset;
-       unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
-       .dataoffset     = ICS_ARCIN_V5_IDEOFFSET,
-       .ctrloffset     = ICS_ARCIN_V5_IDEALTOFFSET,
-       .stepping       = ICS_ARCIN_V5_IDESTEPPING,
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
-       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_1,
-       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_1,
-       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
-       .dataoffset     = ICS_ARCIN_V6_IDEOFFSET_2,
-       .ctrloffset     = ICS_ARCIN_V6_IDEALTOFFSET_2,
-       .stepping       = ICS_ARCIN_V6_IDESTEPPING,
-};
-
-struct icside_state {
-       unsigned int channel;
-       unsigned int enabled;
-       void __iomem *irq_port;
-       void __iomem *ioc_base;
-       unsigned int sel;
-       unsigned int type;
-       struct ide_host *host;
-};
-
-#define ICS_TYPE_A3IN  0
-#define ICS_TYPE_A3USER        1
-#define ICS_TYPE_V6    3
-#define ICS_TYPE_V5    15
-#define ICS_TYPE_NOTYPE        ((unsigned int)-1)
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-       struct icside_state *state = ec->irq_data;
-
-       writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-       struct icside_state *state = ec->irq_data;
-
-       readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-       .irqenable      = icside_irqenable_arcin_v5,
-       .irqdisable     = icside_irqdisable_arcin_v5,
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-       struct icside_state *state = ec->irq_data;
-       void __iomem *base = state->irq_port;
-
-       state->enabled = 1;
-
-       switch (state->channel) {
-       case 0:
-               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
-               readb(base + ICS_ARCIN_V6_INTROFFSET_2);
-               break;
-       case 1:
-               writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
-               readb(base + ICS_ARCIN_V6_INTROFFSET_1);
-               break;
-       }
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-       struct icside_state *state = ec->irq_data;
-
-       state->enabled = 0;
-
-       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose  : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
-       struct icside_state *state = ec->irq_data;
-
-       return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-              readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-       .irqenable      = icside_irqenable_arcin_v6,
-       .irqdisable     = icside_irqdisable_arcin_v6,
-       .irqpending     = icside_irqpending_arcin_v6,
-};
-
-/*
- * Handle routing of interrupts.  This is called before
- * we write the command to the drive.
- */
-static void icside_maskproc(ide_drive_t *drive, int mask)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-       struct icside_state *state = ecard_get_drvdata(ec);
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       state->channel = hwif->channel;
-
-       if (state->enabled && !mask) {
-               switch (hwif->channel) {
-               case 0:
-                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       break;
-               case 1:
-                       writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-                       readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-                       break;
-               }
-       } else {
-               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-               readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
-       }
-
-       local_irq_restore(flags);
-}
-
-static const struct ide_port_ops icside_v6_no_dma_port_ops = {
-       .maskproc               = icside_maskproc,
-};
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time.  NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-
-/*
- * Configure the IOMD to give the appropriate timings for the transfer
- * mode being requested.  We take the advice of the ATA standards, and
- * calculate the cycle time based on the transfer mode, and the EIDE
- * MW DMA specs that the drive provides in the IDENTIFY command.
- *
- * We have the following IOMD DMA modes to choose from:
- *
- *     Type    Active          Recovery        Cycle
- *     A       250 (250)       312 (550)       562 (800)
- *     B       187             250             437
- *     C       125 (125)       125 (375)       250 (500)
- *     D       62              125             187
- *
- * (figures in brackets are actual measured timings)
- *
- * However, we also need to take care of the read/write active and
- * recovery timings:
- *
- *                     Read    Write
- *     Mode    Active  -- Recovery --  Cycle   IOMD type
- *     MW0     215     50      215     480     A
- *     MW1     80      50      50      150     C
- *     MW2     70      25      25      120     C
- */
-static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long cycle_time = 0;
-       int use_dma_info = 0;
-       const u8 xfer_mode = drive->dma_mode;
-
-       switch (xfer_mode) {
-       case XFER_MW_DMA_2:
-               cycle_time = 250;
-               use_dma_info = 1;
-               break;
-
-       case XFER_MW_DMA_1:
-               cycle_time = 250;
-               use_dma_info = 1;
-               break;
-
-       case XFER_MW_DMA_0:
-               cycle_time = 480;
-               break;
-
-       case XFER_SW_DMA_2:
-       case XFER_SW_DMA_1:
-       case XFER_SW_DMA_0:
-               cycle_time = 480;
-               break;
-       }
-
-       /*
-        * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
-        * take care to note the values in the ID...
-        */
-       if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time)
-               cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME];
-
-       ide_set_drivedata(drive, (void *)cycle_time);
-
-       printk(KERN_INFO "%s: %s selected (peak %luMB/s)\n",
-              drive->name, ide_xfer_verbose(xfer_mode),
-              2000 / (cycle_time ? cycle_time : (unsigned long) -1));
-}
-
-static const struct ide_port_ops icside_v6_port_ops = {
-       .set_dma_mode           = icside_set_dma_mode,
-       .maskproc               = icside_maskproc,
-};
-
-static void icside_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static int icside_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-
-       disable_dma(ec->dma);
-
-       return get_dma_residue(ec->dma) != 0;
-}
-
-static void icside_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-
-       /* We can not enable DMA on both channels simultaneously. */
-       BUG_ON(dma_channel_active(ec->dma));
-       enable_dma(ec->dma);
-}
-
-static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-       struct icside_state *state = ecard_get_drvdata(ec);
-       unsigned int dma_mode;
-
-       if (cmd->tf_flags & IDE_TFLAG_WRITE)
-               dma_mode = DMA_MODE_WRITE;
-       else
-               dma_mode = DMA_MODE_READ;
-
-       /*
-        * We can not enable DMA on both channels.
-        */
-       BUG_ON(dma_channel_active(ec->dma));
-
-       /*
-        * Ensure that we have the right interrupt routed.
-        */
-       icside_maskproc(drive, 0);
-
-       /*
-        * Route the DMA signals to the correct interface.
-        */
-       writeb(state->sel | hwif->channel, state->ioc_base);
-
-       /*
-        * Select the correct timing for this drive.
-        */
-       set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive));
-
-       /*
-        * Tell the DMA engine about the SG table and
-        * data direction.
-        */
-       set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents);
-       set_dma_mode(ec->dma, dma_mode);
-
-       return 0;
-}
-
-static int icside_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct expansion_card *ec = ECARD_DEV(hwif->dev);
-       struct icside_state *state = ecard_get_drvdata(ec);
-
-       return readb(state->irq_port +
-                    (hwif->channel ?
-                       ICS_ARCIN_V6_INTRSTAT_2 :
-                       ICS_ARCIN_V6_INTRSTAT_1)) & 1;
-}
-
-static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       hwif->dmatable_cpu      = NULL;
-       hwif->dmatable_dma      = 0;
-
-       return 0;
-}
-
-static const struct ide_dma_ops icside_v6_dma_ops = {
-       .dma_host_set           = icside_dma_host_set,
-       .dma_setup              = icside_dma_setup,
-       .dma_start              = icside_dma_start,
-       .dma_end                = icside_dma_end,
-       .dma_test_irq           = icside_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-};
-#endif
-
-static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       return -EOPNOTSUPP;
-}
-
-static void icside_setup_ports(struct ide_hw *hw, void __iomem *base,
-                              struct cardinfo *info, struct expansion_card *ec)
-{
-       unsigned long port = (unsigned long)base + info->dataoffset;
-
-       hw->io_ports.data_addr   = port;
-       hw->io_ports.error_addr  = port + (1 << info->stepping);
-       hw->io_ports.nsect_addr  = port + (2 << info->stepping);
-       hw->io_ports.lbal_addr   = port + (3 << info->stepping);
-       hw->io_ports.lbam_addr   = port + (4 << info->stepping);
-       hw->io_ports.lbah_addr   = port + (5 << info->stepping);
-       hw->io_ports.device_addr = port + (6 << info->stepping);
-       hw->io_ports.status_addr = port + (7 << info->stepping);
-       hw->io_ports.ctl_addr    = (unsigned long)base + info->ctrloffset;
-
-       hw->irq = ec->irq;
-       hw->dev = &ec->dev;
-}
-
-static const struct ide_port_info icside_v5_port_info = {
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .chipset                = ide_acorn,
-};
-
-static int icside_register_v5(struct icside_state *state,
-                             struct expansion_card *ec)
-{
-       void __iomem *base;
-       struct ide_host *host;
-       struct ide_hw hw, *hws[] = { &hw };
-       int ret;
-
-       base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
-       if (!base)
-               return -ENOMEM;
-
-       state->irq_port = base;
-
-       ec->irqaddr  = base + ICS_ARCIN_V5_INTRSTAT;
-       ec->irqmask  = 1;
-
-       ecard_setirq(ec, &icside_ops_arcin_v5, state);
-
-       /*
-        * Be on the safe side - disable interrupts
-        */
-       icside_irqdisable_arcin_v5(ec, 0);
-
-       icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
-
-       host = ide_host_alloc(&icside_v5_port_info, hws, 1);
-       if (host == NULL)
-               return -ENODEV;
-
-       state->host = host;
-
-       ecard_set_drvdata(ec, state);
-
-       ret = ide_host_register(host, &icside_v5_port_info, hws);
-       if (ret)
-               goto err_free;
-
-       return 0;
-err_free:
-       ide_host_free(host);
-       ecard_set_drvdata(ec, NULL);
-       return ret;
-}
-
-static const struct ide_port_info icside_v6_port_info = {
-       .init_dma               = icside_dma_off_init,
-       .port_ops               = &icside_v6_no_dma_port_ops,
-       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
-       .mwdma_mask             = ATA_MWDMA2,
-       .swdma_mask             = ATA_SWDMA2,
-       .chipset                = ide_acorn,
-};
-
-static int icside_register_v6(struct icside_state *state,
-                             struct expansion_card *ec)
-{
-       void __iomem *ioc_base, *easi_base;
-       struct ide_host *host;
-       unsigned int sel = 0;
-       int ret;
-       struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] };
-       struct ide_port_info d = icside_v6_port_info;
-
-       ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
-       if (!ioc_base) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       easi_base = ioc_base;
-
-       if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
-               easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
-               if (!easi_base) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               /*
-                * Enable access to the EASI region.
-                */
-               sel = 1 << 5;
-       }
-
-       writeb(sel, ioc_base);
-
-       ecard_setirq(ec, &icside_ops_arcin_v6, state);
-
-       state->irq_port   = easi_base;
-       state->ioc_base   = ioc_base;
-       state->sel        = sel;
-
-       /*
-        * Be on the safe side - disable interrupts
-        */
-       icside_irqdisable_arcin_v6(ec, 0);
-
-       icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec);
-       icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec);
-
-       host = ide_host_alloc(&d, hws, 2);
-       if (host == NULL)
-               return -ENODEV;
-
-       state->host = host;
-
-       ecard_set_drvdata(ec, state);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-       if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
-               d.init_dma = icside_dma_init;
-               d.port_ops = &icside_v6_port_ops;
-               d.dma_ops  = &icside_v6_dma_ops;
-       }
-#endif
-
-       ret = ide_host_register(host, &d, hws);
-       if (ret)
-               goto err_free;
-
-       return 0;
-err_free:
-       ide_host_free(host);
-       if (d.dma_ops)
-               free_dma(ec->dma);
-       ecard_set_drvdata(ec, NULL);
-out:
-       return ret;
-}
-
-static int icside_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-       struct icside_state *state;
-       void __iomem *idmem;
-       int ret;
-
-       ret = ecard_request_resources(ec);
-       if (ret)
-               goto out;
-
-       state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
-       if (!state) {
-               ret = -ENOMEM;
-               goto release;
-       }
-
-       state->type     = ICS_TYPE_NOTYPE;
-
-       idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
-       if (idmem) {
-               unsigned int type;
-
-               type = readb(idmem + ICS_IDENT_OFFSET) & 1;
-               type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
-               type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
-               type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
-               ecardm_iounmap(ec, idmem);
-
-               state->type = type;
-       }
-
-       switch (state->type) {
-       case ICS_TYPE_A3IN:
-               dev_warn(&ec->dev, "A3IN unsupported\n");
-               ret = -ENODEV;
-               break;
-
-       case ICS_TYPE_A3USER:
-               dev_warn(&ec->dev, "A3USER unsupported\n");
-               ret = -ENODEV;
-               break;
-
-       case ICS_TYPE_V5:
-               ret = icside_register_v5(state, ec);
-               break;
-
-       case ICS_TYPE_V6:
-               ret = icside_register_v6(state, ec);
-               break;
-
-       default:
-               dev_warn(&ec->dev, "unknown interface type\n");
-               ret = -ENODEV;
-               break;
-       }
-
-       if (ret == 0)
-               goto out;
-
-       kfree(state);
- release:
-       ecard_release_resources(ec);
- out:
-       return ret;
-}
-
-static void icside_remove(struct expansion_card *ec)
-{
-       struct icside_state *state = ecard_get_drvdata(ec);
-
-       switch (state->type) {
-       case ICS_TYPE_V5:
-               /* FIXME: tell IDE to stop using the interface */
-
-               /* Disable interrupts */
-               icside_irqdisable_arcin_v5(ec, 0);
-               break;
-
-       case ICS_TYPE_V6:
-               /* FIXME: tell IDE to stop using the interface */
-               if (ec->dma != NO_DMA)
-                       free_dma(ec->dma);
-
-               /* Disable interrupts */
-               icside_irqdisable_arcin_v6(ec, 0);
-
-               /* Reset the ROM pointer/EASI selection */
-               writeb(0, state->ioc_base);
-               break;
-       }
-
-       ecard_set_drvdata(ec, NULL);
-
-       kfree(state);
-       ecard_release_resources(ec);
-}
-
-static void icside_shutdown(struct expansion_card *ec)
-{
-       struct icside_state *state = ecard_get_drvdata(ec);
-       unsigned long flags;
-
-       /*
-        * Disable interrupts from this card.  We need to do
-        * this before disabling EASI since we may be accessing
-        * this register via that region.
-        */
-       local_irq_save(flags);
-       ec->ops->irqdisable(ec, 0);
-       local_irq_restore(flags);
-
-       /*
-        * Reset the ROM pointer so that we can read the ROM
-        * after a soft reboot.  This also disables access to
-        * the IDE taskfile via the EASI region.
-        */
-       if (state->ioc_base)
-               writeb(0, state->ioc_base);
-}
-
-static const struct ecard_id icside_ids[] = {
-       { MANU_ICS,  PROD_ICS_IDE  },
-       { MANU_ICS2, PROD_ICS2_IDE },
-       { 0xffff, 0xffff }
-};
-
-static struct ecard_driver icside_driver = {
-       .probe          = icside_probe,
-       .remove         = icside_remove,
-       .shutdown       = icside_shutdown,
-       .id_table       = icside_ids,
-       .drv = {
-               .name   = "icside",
-       },
-};
-
-static int __init icside_init(void)
-{
-       return ecard_register_driver(&icside_driver);
-}
-
-static void __exit icside_exit(void)
-{
-       ecard_remove_driver(&icside_driver);
-}
-
-MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ICS IDE driver");
-
-module_init(icside_init);
-module_exit(icside_exit);
diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c
deleted file mode 100644 (file)
index 06c6215..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "ide-4drives"
-
-static bool probe_4drives;
-
-module_param_named(probe, probe_4drives, bool, 0);
-MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
-
-static void ide_4drives_init_dev(ide_drive_t *drive)
-{
-       if (drive->hwif->channel)
-               drive->select ^= 0x20;
-}
-
-static const struct ide_port_ops ide_4drives_port_ops = {
-       .init_dev               = ide_4drives_init_dev,
-};
-
-static const struct ide_port_info ide_4drives_port_info = {
-       .port_ops               = &ide_4drives_port_ops,
-       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA |
-                                 IDE_HFLAG_4DRIVES,
-       .chipset                = ide_4drives,
-};
-
-static int __init ide_4drives_init(void)
-{
-       unsigned long base = 0x1f0, ctl = 0x3f6;
-       struct ide_hw hw, *hws[] = { &hw, &hw };
-
-       if (probe_4drives == 0)
-               return -ENODEV;
-
-       if (!request_region(base, 8, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               DRV_NAME, base, base + 7);
-               return -EBUSY;
-       }
-
-       if (!request_region(ctl, 1, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               DRV_NAME, ctl);
-               release_region(base, 8);
-               return -EBUSY;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = 14;
-
-       return ide_host_add(&ide_4drives_port_info, hws, 2, NULL);
-}
-
-module_init(ide_4drives_init);
-
-MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("generic IDE chipset with 4 drives/port support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
deleted file mode 100644 (file)
index 05e18d6..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Provides ACPI support for IDE drives.
- *
- * Copyright (C) 2005 Intel Corp.
- * Copyright (C) 2005 Randy Dunlap
- * Copyright (C) 2006 SUSE Linux Products GmbH
- * Copyright (C) 2006 Hannes Reinecke
- */
-
-#include <linux/acpi.h>
-#include <linux/ata.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-
-#define REGS_PER_GTF           7
-
-struct GTM_buffer {
-       u32     PIO_speed0;
-       u32     DMA_speed0;
-       u32     PIO_speed1;
-       u32     DMA_speed1;
-       u32     GTM_flags;
-};
-
-struct ide_acpi_drive_link {
-       acpi_handle      obj_handle;
-       u8               idbuff[512];
-};
-
-struct ide_acpi_hwif_link {
-       ide_hwif_t                      *hwif;
-       acpi_handle                      obj_handle;
-       struct GTM_buffer                gtm;
-       struct ide_acpi_drive_link       master;
-       struct ide_acpi_drive_link       slave;
-};
-
-#undef DEBUGGING
-/* note: adds function name and KERN_DEBUG */
-#ifdef DEBUGGING
-#define DEBPRINT(fmt, args...) \
-               printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
-#else
-#define DEBPRINT(fmt, args...) do {} while (0)
-#endif /* DEBUGGING */
-
-static bool ide_noacpi;
-module_param_named(noacpi, ide_noacpi, bool, 0);
-MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
-
-static bool ide_acpigtf;
-module_param_named(acpigtf, ide_acpigtf, bool, 0);
-MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
-
-static bool ide_acpionboot;
-module_param_named(acpionboot, ide_acpionboot, bool, 0);
-MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
-
-static bool ide_noacpi_psx;
-static int no_acpi_psx(const struct dmi_system_id *id)
-{
-       ide_noacpi_psx = true;
-       printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
-       return 0;
-}
-
-static const struct dmi_system_id ide_acpi_dmi_table[] = {
-       /* Bug 9673. */
-       /* We should check if this is because ACPI NVS isn't save/restored. */
-       {
-               .callback = no_acpi_psx,
-               .ident    = "HP nx9005",
-               .matches  = {
-                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
-                       DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
-               },
-       },
-
-       { }     /* terminate list */
-};
-
-int ide_acpi_init(void)
-{
-       dmi_check_system(ide_acpi_dmi_table);
-       return 0;
-}
-
-bool ide_port_acpi(ide_hwif_t *hwif)
-{
-       return ide_noacpi == 0 && hwif->acpidata;
-}
-
-static acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
-{
-       struct acpi_device *adev;
-
-       if (!handle || acpi_bus_get_device(handle, &adev))
-               return NULL;
-
-       adev = acpi_find_child_device(adev, addr, false);
-       return adev ? adev->handle : NULL;
-}
-
-/**
- * ide_get_dev_handle - finds acpi_handle and PCI device.function
- * @dev: device to locate
- * @handle: returned acpi_handle for @dev
- * @pcidevfn: return PCI device.func for @dev
- *
- * Returns the ACPI object handle to the corresponding PCI device.
- *
- * Returns 0 on success, <0 on error.
- */
-static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
-                              u64 *pcidevfn)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       unsigned int bus, devnum, func;
-       u64 addr;
-       acpi_handle dev_handle;
-       acpi_status status;
-       struct acpi_device_info *dinfo = NULL;
-       int ret = -ENODEV;
-
-       bus = pdev->bus->number;
-       devnum = PCI_SLOT(pdev->devfn);
-       func = PCI_FUNC(pdev->devfn);
-       /* ACPI _ADR encoding for PCI bus: */
-       addr = (u64)(devnum << 16 | func);
-
-       DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
-
-       dev_handle = ACPI_HANDLE(dev);
-       if (!dev_handle) {
-               DEBPRINT("no acpi handle for device\n");
-               goto err;
-       }
-
-       status = acpi_get_object_info(dev_handle, &dinfo);
-       if (ACPI_FAILURE(status)) {
-               DEBPRINT("get_object_info for device failed\n");
-               goto err;
-       }
-       if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
-           dinfo->address == addr) {
-               *pcidevfn = addr;
-               *handle = dev_handle;
-       } else {
-               DEBPRINT("get_object_info for device has wrong "
-                       " address: %llu, should be %u\n",
-                       dinfo ? (unsigned long long)dinfo->address : -1ULL,
-                       (unsigned int)addr);
-               goto err;
-       }
-
-       DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
-                devnum, func, (unsigned long long)addr, *handle);
-       ret = 0;
-err:
-       kfree(dinfo);
-       return ret;
-}
-
-/**
- * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
- * @hwif: device to locate
- *
- * Retrieves the object handle for a given hwif.
- *
- * Returns handle on success, 0 on error.
- */
-static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
-{
-       struct device           *dev = hwif->gendev.parent;
-       acpi_handle             dev_handle;
-       u64                     pcidevfn;
-       acpi_handle             chan_handle;
-       int                     err;
-
-       DEBPRINT("ENTER: device %s\n", hwif->name);
-
-       if (!dev) {
-               DEBPRINT("no PCI device for %s\n", hwif->name);
-               return NULL;
-       }
-
-       err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
-       if (err < 0) {
-               DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
-               return NULL;
-       }
-
-       /* get child objects of dev_handle == channel objects,
-        * + _their_ children == drive objects */
-       /* channel is hwif->channel */
-       chan_handle = acpi_get_child(dev_handle, hwif->channel);
-       DEBPRINT("chan adr=%d: handle=0x%p\n",
-                hwif->channel, chan_handle);
-
-       return chan_handle;
-}
-
-/**
- * do_drive_get_GTF - get the drive bootup default taskfile settings
- * @drive: the drive for which the taskfile settings should be retrieved
- * @gtf_length: number of bytes of _GTF data returned at @gtf_address
- * @gtf_address: buffer containing _GTF taskfile arrays
- *
- * The _GTF method has no input parameters.
- * It returns a variable number of register set values (registers
- * hex 1F1..1F7, taskfiles).
- * The <variable number> is not known in advance, so have ACPI-CA
- * allocate the buffer as needed and return it, then free it later.
- *
- * The returned @gtf_length and @gtf_address are only valid if the
- * function return value is 0.
- */
-static int do_drive_get_GTF(ide_drive_t *drive,
-                    unsigned int *gtf_length, unsigned long *gtf_address,
-                    unsigned long *obj_loc)
-{
-       acpi_status                     status;
-       struct acpi_buffer              output;
-       union acpi_object               *out_obj;
-       int                             err = -ENODEV;
-
-       *gtf_length = 0;
-       *gtf_address = 0UL;
-       *obj_loc = 0UL;
-
-       if (!drive->acpidata->obj_handle) {
-               DEBPRINT("No ACPI object found for %s\n", drive->name);
-               goto out;
-       }
-
-       /* Setting up output buffer */
-       output.length = ACPI_ALLOCATE_BUFFER;
-       output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
-
-       /* _GTF has no input parameters */
-       err = -EIO;
-       status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
-                                     NULL, &output);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_DEBUG
-                      "%s: Run _GTF error: status = 0x%x\n",
-                      __func__, status);
-               goto out;
-       }
-
-       if (!output.length || !output.pointer) {
-               DEBPRINT("Run _GTF: "
-                      "length or ptr is NULL (0x%llx, 0x%p)\n",
-                      (unsigned long long)output.length,
-                      output.pointer);
-               goto out;
-       }
-
-       out_obj = output.pointer;
-       if (out_obj->type != ACPI_TYPE_BUFFER) {
-               DEBPRINT("Run _GTF: error: "
-                      "expected object type of ACPI_TYPE_BUFFER, "
-                      "got 0x%x\n", out_obj->type);
-               err = -ENOENT;
-               kfree(output.pointer);
-               goto out;
-       }
-
-       if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
-           out_obj->buffer.length % REGS_PER_GTF) {
-               printk(KERN_ERR
-                      "%s: unexpected GTF length (%d) or addr (0x%p)\n",
-                      __func__, out_obj->buffer.length,
-                      out_obj->buffer.pointer);
-               err = -ENOENT;
-               kfree(output.pointer);
-               goto out;
-       }
-
-       *gtf_length = out_obj->buffer.length;
-       *gtf_address = (unsigned long)out_obj->buffer.pointer;
-       *obj_loc = (unsigned long)out_obj;
-       DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
-                *gtf_length, *gtf_address, *obj_loc);
-       err = 0;
-out:
-       return err;
-}
-
-/**
- * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
- * @drive: the drive to which the taskfile command should be sent
- * @gtf_length: total number of bytes of _GTF taskfiles
- * @gtf_address: location of _GTF taskfile arrays
- *
- * Write {gtf_address, length gtf_length} in groups of
- * REGS_PER_GTF bytes.
- */
-static int do_drive_set_taskfiles(ide_drive_t *drive,
-                                 unsigned int gtf_length,
-                                 unsigned long gtf_address)
-{
-       int                     rc = 0, err;
-       int                     gtf_count = gtf_length / REGS_PER_GTF;
-       int                     ix;
-
-       DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
-                gtf_length, gtf_length, gtf_count, gtf_address);
-
-       /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
-       for (ix = 0; ix < gtf_count; ix++) {
-               u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
-               struct ide_cmd cmd;
-
-               DEBPRINT("(0x1f1-1f7): "
-                        "hex: %02x %02x %02x %02x %02x %02x %02x\n",
-                        gtf[0], gtf[1], gtf[2],
-                        gtf[3], gtf[4], gtf[5], gtf[6]);
-
-               if (!ide_acpigtf) {
-                       DEBPRINT("_GTF execution disabled\n");
-                       continue;
-               }
-
-               /* convert GTF to taskfile */
-               memset(&cmd, 0, sizeof(cmd));
-               memcpy(&cmd.tf.feature, gtf, REGS_PER_GTF);
-               cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-               cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-               err = ide_no_data_taskfile(drive, &cmd);
-               if (err) {
-                       printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
-                                       __func__, err);
-                       rc = err;
-               }
-       }
-
-       return rc;
-}
-
-/**
- * ide_acpi_exec_tfs - get then write drive taskfile settings
- * @drive: the drive for which the taskfile settings should be
- *         written.
- *
- * According to the ACPI spec this should be called after _STM
- * has been evaluated for the interface. Some ACPI vendors interpret
- * that as a hard requirement and modify the taskfile according
- * to the Identify Drive information passed down with _STM.
- * So one should really make sure to call this only after _STM has
- * been executed.
- */
-int ide_acpi_exec_tfs(ide_drive_t *drive)
-{
-       int             ret;
-       unsigned int    gtf_length;
-       unsigned long   gtf_address;
-       unsigned long   obj_loc;
-
-       DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
-
-       ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
-       if (ret < 0) {
-               DEBPRINT("get_GTF error (%d)\n", ret);
-               return ret;
-       }
-
-       DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
-
-       ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
-       kfree((void *)obj_loc);
-       if (ret < 0) {
-               DEBPRINT("set_taskfiles error (%d)\n", ret);
-       }
-
-       DEBPRINT("ret=%d\n", ret);
-
-       return ret;
-}
-
-/**
- * ide_acpi_get_timing - get the channel (controller) timings
- * @hwif: target IDE interface (channel)
- *
- * This function executes the _GTM ACPI method for the target channel.
- *
- */
-void ide_acpi_get_timing(ide_hwif_t *hwif)
-{
-       acpi_status             status;
-       struct acpi_buffer      output;
-       union acpi_object       *out_obj;
-
-       /* Setting up output buffer for _GTM */
-       output.length = ACPI_ALLOCATE_BUFFER;
-       output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
-
-       /* _GTM has no input parameters */
-       status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
-                                     NULL, &output);
-
-       DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
-                status, output.pointer,
-                (unsigned long long)output.length);
-
-       if (ACPI_FAILURE(status)) {
-               DEBPRINT("Run _GTM error: status = 0x%x\n", status);
-               return;
-       }
-
-       if (!output.length || !output.pointer) {
-               DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
-                      (unsigned long long)output.length,
-                      output.pointer);
-               kfree(output.pointer);
-               return;
-       }
-
-       out_obj = output.pointer;
-       if (out_obj->type != ACPI_TYPE_BUFFER) {
-               DEBPRINT("Run _GTM: error: "
-                      "expected object type of ACPI_TYPE_BUFFER, "
-                      "got 0x%x\n", out_obj->type);
-               kfree(output.pointer);
-               return;
-       }
-
-       if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
-           out_obj->buffer.length != sizeof(struct GTM_buffer)) {
-               printk(KERN_ERR
-                       "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
-                       "addr (0x%p)\n",
-                       __func__, out_obj->buffer.length,
-                       sizeof(struct GTM_buffer), out_obj->buffer.pointer);
-               kfree(output.pointer);
-               return;
-       }
-
-       memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
-              sizeof(struct GTM_buffer));
-
-       DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%zx\n",
-                out_obj->buffer.pointer, out_obj->buffer.length,
-                sizeof(struct GTM_buffer));
-
-       DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
-                hwif->acpidata->gtm.PIO_speed0,
-                hwif->acpidata->gtm.DMA_speed0,
-                hwif->acpidata->gtm.PIO_speed1,
-                hwif->acpidata->gtm.DMA_speed1,
-                hwif->acpidata->gtm.GTM_flags);
-
-       kfree(output.pointer);
-}
-
-/**
- * ide_acpi_push_timing - set the channel (controller) timings
- * @hwif: target IDE interface (channel)
- *
- * This function executes the _STM ACPI method for the target channel.
- *
- * _STM requires Identify Drive data, which has to passed as an argument.
- * Unfortunately drive->id is a mangled version which we can't readily
- * use; hence we'll get the information afresh.
- */
-void ide_acpi_push_timing(ide_hwif_t *hwif)
-{
-       acpi_status             status;
-       struct acpi_object_list input;
-       union acpi_object       in_params[3];
-       struct ide_acpi_drive_link      *master = &hwif->acpidata->master;
-       struct ide_acpi_drive_link      *slave = &hwif->acpidata->slave;
-
-       /* Give the GTM buffer + drive Identify data to the channel via the
-        * _STM method: */
-       /* setup input parameters buffer for _STM */
-       input.count = 3;
-       input.pointer = in_params;
-       in_params[0].type = ACPI_TYPE_BUFFER;
-       in_params[0].buffer.length = sizeof(struct GTM_buffer);
-       in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
-       in_params[1].type = ACPI_TYPE_BUFFER;
-       in_params[1].buffer.length = ATA_ID_WORDS * 2;
-       in_params[1].buffer.pointer = (u8 *)&master->idbuff;
-       in_params[2].type = ACPI_TYPE_BUFFER;
-       in_params[2].buffer.length = ATA_ID_WORDS * 2;
-       in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
-       /* Output buffer: _STM has no output */
-
-       status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
-                                     &input, NULL);
-
-       if (ACPI_FAILURE(status)) {
-               DEBPRINT("Run _STM error: status = 0x%x\n", status);
-       }
-       DEBPRINT("_STM status: %d\n", status);
-}
-
-/**
- * ide_acpi_set_state - set the channel power state
- * @hwif: target IDE interface
- * @on: state, on/off
- *
- * This function executes the _PS0/_PS3 ACPI method to set the power state.
- * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
- */
-void ide_acpi_set_state(ide_hwif_t *hwif, int on)
-{
-       ide_drive_t *drive;
-       int i;
-
-       if (ide_noacpi_psx)
-               return;
-
-       DEBPRINT("ENTER:\n");
-
-       /* channel first and then drives for power on and verse versa for power off */
-       if (on)
-               acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               if (drive->acpidata->obj_handle)
-                       acpi_bus_set_power(drive->acpidata->obj_handle,
-                               on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
-       }
-
-       if (!on)
-               acpi_bus_set_power(hwif->acpidata->obj_handle,
-                                  ACPI_STATE_D3_COLD);
-}
-
-/**
- * ide_acpi_init_port - initialize the ACPI link for an IDE interface
- * @hwif: target IDE interface (channel)
- *
- * The ACPI spec is not quite clear when the drive identify buffer
- * should be obtained. Calling IDENTIFY DEVICE during shutdown
- * is not the best of ideas as the drive might already being put to
- * sleep. And obviously we can't call it during resume.
- * So we get the information during startup; but this means that
- * any changes during run-time will be lost after resume.
- */
-void ide_acpi_init_port(ide_hwif_t *hwif)
-{
-       hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
-       if (!hwif->acpidata)
-               return;
-
-       hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
-       if (!hwif->acpidata->obj_handle) {
-               DEBPRINT("no ACPI object for %s found\n", hwif->name);
-               kfree(hwif->acpidata);
-               hwif->acpidata = NULL;
-       }
-}
-
-void ide_acpi_port_init_devices(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i, err;
-
-       if (hwif->acpidata == NULL)
-               return;
-
-       /*
-        * The ACPI spec mandates that we send information
-        * for both drives, regardless whether they are connected
-        * or not.
-        */
-       hwif->devices[0]->acpidata = &hwif->acpidata->master;
-       hwif->devices[1]->acpidata = &hwif->acpidata->slave;
-
-       /* get _ADR info for each device */
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               acpi_handle dev_handle;
-
-               DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
-                        drive->name, hwif->channel, drive->dn & 1);
-
-               /* TBD: could also check ACPI object VALID bits */
-               dev_handle = acpi_get_child(hwif->acpidata->obj_handle,
-                                           drive->dn & 1);
-
-               DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle);
-
-               drive->acpidata->obj_handle = dev_handle;
-       }
-
-       /* send IDENTIFY for each device */
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
-               if (err)
-                       DEBPRINT("identify device %s failed (%d)\n",
-                                drive->name, err);
-       }
-
-       if (ide_noacpi || ide_acpionboot == 0) {
-               DEBPRINT("ACPI methods disabled on boot\n");
-               return;
-       }
-
-       /* ACPI _PS0 before _STM */
-       ide_acpi_set_state(hwif, 1);
-       /*
-        * ACPI requires us to call _STM on startup
-        */
-       ide_acpi_get_timing(hwif);
-       ide_acpi_push_timing(hwif);
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               ide_acpi_exec_tfs(drive);
-       }
-}
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
deleted file mode 100644 (file)
index a1ce9f5..0000000
+++ /dev/null
@@ -1,756 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ATAPI support.
- */
-
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/gfp.h>
-
-#include <scsi/scsi.h>
-
-#define DRV_NAME "ide-atapi"
-#define PFX DRV_NAME ": "
-
-#ifdef DEBUG
-#define debug_log(fmt, args...) \
-       printk(KERN_INFO "ide: " fmt, ## args)
-#else
-#define debug_log(fmt, args...) do {} while (0)
-#endif
-
-#define ATAPI_MIN_CDB_BYTES    12
-
-static inline int dev_is_idecd(ide_drive_t *drive)
-{
-       return drive->media == ide_cdrom || drive->media == ide_optical;
-}
-
-/*
- * Check whether we can support a device,
- * based on the ATAPI IDENTIFY command results.
- */
-int ide_check_atapi_device(ide_drive_t *drive, const char *s)
-{
-       u16 *id = drive->id;
-       u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
-
-       *((u16 *)&gcw) = id[ATA_ID_CONFIG];
-
-       protocol    = (gcw[1] & 0xC0) >> 6;
-       device_type =  gcw[1] & 0x1F;
-       removable   = (gcw[0] & 0x80) >> 7;
-       drq_type    = (gcw[0] & 0x60) >> 5;
-       packet_size =  gcw[0] & 0x03;
-
-#ifdef CONFIG_PPC
-       /* kludge for Apple PowerBook internal zip */
-       if (drive->media == ide_floppy && device_type == 5 &&
-           !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
-           strstr((char *)&id[ATA_ID_PROD], "ZIP"))
-               device_type = 0;
-#endif
-
-       if (protocol != 2)
-               printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
-                       s, drive->name, protocol);
-       else if ((drive->media == ide_floppy && device_type != 0) ||
-                (drive->media == ide_tape && device_type != 1))
-               printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
-                       s, drive->name, device_type);
-       else if (removable == 0)
-               printk(KERN_ERR "%s: %s: the removable flag is not set\n",
-                       s, drive->name);
-       else if (drive->media == ide_floppy && drq_type == 3)
-               printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
-                       "supported\n", s, drive->name, drq_type);
-       else if (packet_size != 0)
-               printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
-                       "bytes\n", s, drive->name, packet_size);
-       else
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_check_atapi_device);
-
-void ide_init_pc(struct ide_atapi_pc *pc)
-{
-       memset(pc, 0, sizeof(*pc));
-}
-EXPORT_SYMBOL_GPL(ide_init_pc);
-
-/*
- * Add a special packet command request to the tail of the request queue,
- * and wait for it to be serviced.
- */
-int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
-                     struct ide_atapi_pc *pc, void *buf, unsigned int bufflen)
-{
-       struct request *rq;
-       int error;
-
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       ide_req(rq)->special = pc;
-
-       if (buf && bufflen) {
-               error = blk_rq_map_kern(drive->queue, rq, buf, bufflen,
-                                       GFP_NOIO);
-               if (error)
-                       goto put_req;
-       }
-
-       memcpy(scsi_req(rq)->cmd, pc->c, 12);
-       if (drive->media == ide_tape)
-               scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
-       blk_execute_rq(disk, rq, 0);
-       error = scsi_req(rq)->result ? -EIO : 0;
-put_req:
-       blk_put_request(rq);
-       return error;
-}
-EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
-
-int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
-{
-       struct ide_atapi_pc pc;
-
-       ide_init_pc(&pc);
-       pc.c[0] = TEST_UNIT_READY;
-
-       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
-
-int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
-{
-       struct ide_atapi_pc pc;
-
-       ide_init_pc(&pc);
-       pc.c[0] = START_STOP;
-       pc.c[4] = start;
-
-       if (drive->media == ide_tape)
-               pc.flags |= PC_FLAG_WAIT_FOR_DSC;
-
-       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_do_start_stop);
-
-int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
-{
-       struct ide_atapi_pc pc;
-
-       if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
-               return 0;
-
-       ide_init_pc(&pc);
-       pc.c[0] = ALLOW_MEDIUM_REMOVAL;
-       pc.c[4] = on;
-
-       return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_set_media_lock);
-
-void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       ide_init_pc(pc);
-       pc->c[0] = REQUEST_SENSE;
-       if (drive->media == ide_floppy) {
-               pc->c[4] = 255;
-               pc->req_xfer = 18;
-       } else {
-               pc->c[4] = 20;
-               pc->req_xfer = 20;
-       }
-}
-EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
-
-void ide_prep_sense(ide_drive_t *drive, struct request *rq)
-{
-       struct request_sense *sense = &drive->sense_data;
-       struct request *sense_rq;
-       struct scsi_request *req;
-       unsigned int cmd_len, sense_len;
-       int err;
-
-       switch (drive->media) {
-       case ide_floppy:
-               cmd_len = 255;
-               sense_len = 18;
-               break;
-       case ide_tape:
-               cmd_len = 20;
-               sense_len = 20;
-               break;
-       default:
-               cmd_len = 18;
-               sense_len = 18;
-       }
-
-       BUG_ON(sense_len > sizeof(*sense));
-
-       if (ata_sense_request(rq) || drive->sense_rq_armed)
-               return;
-
-       sense_rq = drive->sense_rq;
-       if (!sense_rq) {
-               sense_rq = blk_mq_alloc_request(drive->queue, REQ_OP_DRV_IN,
-                                       BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
-               drive->sense_rq = sense_rq;
-       }
-       req = scsi_req(sense_rq);
-
-       memset(sense, 0, sizeof(*sense));
-
-       scsi_req_init(req);
-
-       err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
-                             GFP_NOIO);
-       if (unlikely(err)) {
-               if (printk_ratelimit())
-                       printk(KERN_WARNING PFX "%s: failed to map sense "
-                                           "buffer\n", drive->name);
-               blk_mq_free_request(sense_rq);
-               drive->sense_rq = NULL;
-               return;
-       }
-
-       sense_rq->rq_disk = rq->rq_disk;
-       sense_rq->cmd_flags = REQ_OP_DRV_IN;
-       ide_req(sense_rq)->type = ATA_PRIV_SENSE;
-
-       req->cmd[0] = GPCMD_REQUEST_SENSE;
-       req->cmd[4] = cmd_len;
-       if (drive->media == ide_tape)
-               req->cmd[13] = REQ_IDETAPE_PC1;
-
-       drive->sense_rq_armed = true;
-}
-EXPORT_SYMBOL_GPL(ide_prep_sense);
-
-int ide_queue_sense_rq(ide_drive_t *drive, void *special)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *sense_rq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hwif->lock, flags);
-
-       /* deferred failure from ide_prep_sense() */
-       if (!drive->sense_rq_armed) {
-               printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
-                      drive->name);
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               return -ENOMEM;
-       }
-
-       sense_rq = drive->sense_rq;
-       ide_req(sense_rq)->special = special;
-       drive->sense_rq_armed = false;
-
-       drive->hwif->rq = NULL;
-
-       ide_insert_request_head(drive, sense_rq);
-       spin_unlock_irqrestore(&hwif->lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
-
-/*
- * Called when an error was detected during the last packet command.
- * We queue a request sense packet command at the head of the request
- * queue.
- */
-void ide_retry_pc(ide_drive_t *drive)
-{
-       struct request *failed_rq = drive->hwif->rq;
-       struct request *sense_rq = drive->sense_rq;
-       struct ide_atapi_pc *pc = &drive->request_sense_pc;
-
-       (void)ide_read_error(drive);
-
-       /* init pc from sense_rq */
-       ide_init_pc(pc);
-       memcpy(pc->c, scsi_req(sense_rq)->cmd, 12);
-
-       if (drive->media == ide_tape)
-               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
-
-       /*
-        * Push back the failed request and put request sense on top
-        * of it.  The failed command will be retried after sense data
-        * is acquired.
-        */
-       drive->hwif->rq = NULL;
-       ide_requeue_and_plug(drive, failed_rq);
-       if (ide_queue_sense_rq(drive, pc))
-               ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq));
-}
-EXPORT_SYMBOL_GPL(ide_retry_pc);
-
-int ide_cd_expiry(ide_drive_t *drive)
-{
-       struct request *rq = drive->hwif->rq;
-       unsigned long wait = 0;
-
-       debug_log("%s: scsi_req(rq)->cmd[0]: 0x%x\n", __func__, scsi_req(rq)->cmd[0]);
-
-       /*
-        * Some commands are *slow* and normally take a long time to complete.
-        * Usually we can use the ATAPI "disconnect" to bypass this, but not all
-        * commands/drives support that. Let ide_timer_expiry keep polling us
-        * for these.
-        */
-       switch (scsi_req(rq)->cmd[0]) {
-       case GPCMD_BLANK:
-       case GPCMD_FORMAT_UNIT:
-       case GPCMD_RESERVE_RZONE_TRACK:
-       case GPCMD_CLOSE_TRACK:
-       case GPCMD_FLUSH_CACHE:
-               wait = ATAPI_WAIT_PC;
-               break;
-       default:
-               if (!(rq->rq_flags & RQF_QUIET))
-                       printk(KERN_INFO PFX "cmd 0x%x timed out\n",
-                                        scsi_req(rq)->cmd[0]);
-               wait = 0;
-               break;
-       }
-       return wait;
-}
-EXPORT_SYMBOL_GPL(ide_cd_expiry);
-
-int ide_cd_get_xferlen(struct request *rq)
-{
-       switch (req_op(rq)) {
-       default:
-               return 32768;
-       case REQ_OP_SCSI_IN:
-       case REQ_OP_SCSI_OUT:
-               return blk_rq_bytes(rq);
-       case REQ_OP_DRV_IN:
-       case REQ_OP_DRV_OUT:
-               switch (ide_req(rq)->type) {
-               case ATA_PRIV_PC:
-               case ATA_PRIV_SENSE:
-                       return blk_rq_bytes(rq);
-               default:
-                       return 0;
-               }
-       }
-}
-EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
-
-void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
-{
-       struct ide_taskfile tf;
-
-       drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT |
-                                    IDE_VALID_LBAM | IDE_VALID_LBAH);
-
-       *bcount = (tf.lbah << 8) | tf.lbam;
-       *ireason = tf.nsect & 3;
-}
-EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
-
-/*
- * Check the contents of the interrupt reason register and attempt to recover if
- * there are problems.
- *
- * Returns:
- * - 0 if everything's ok
- * - 1 if the request has to be terminated.
- */
-int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
-                     int ireason, int rw)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw);
-
-       if (ireason == (!rw << 1))
-               return 0;
-       else if (ireason == (rw << 1)) {
-               printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
-                               drive->name, __func__);
-
-               if (dev_is_idecd(drive))
-                       ide_pad_transfer(drive, rw, len);
-       } else if (!rw && ireason == ATAPI_COD) {
-               if (dev_is_idecd(drive)) {
-                       /*
-                        * Some drives (ASUS) seem to tell us that status info
-                        * is available.  Just get it and ignore.
-                        */
-                       (void)hwif->tp_ops->read_status(hwif);
-                       return 0;
-               }
-       } else {
-               if (ireason & ATAPI_COD)
-                       printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name,
-                                       __func__);
-
-               /* drive wants a command packet, or invalid ireason... */
-               printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
-                               drive->name, __func__, ireason);
-       }
-
-       if (dev_is_idecd(drive) && ata_pc_request(rq))
-               rq->rq_flags |= RQF_FAILED;
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(ide_check_ireason);
-
-/*
- * This is the usual interrupt handler which will be called during a packet
- * command.  We will transfer some of the data (as requested by the drive)
- * and will re-point interrupt handler to us.
- */
-static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
-{
-       struct ide_atapi_pc *pc = drive->pc;
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
-       struct request *rq = hwif->rq;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       unsigned int timeout, done;
-       u16 bcount;
-       u8 stat, ireason, dsc = 0;
-       u8 write = !!(pc->flags & PC_FLAG_WRITING);
-
-       debug_log("Enter %s - interrupt handler\n", __func__);
-
-       timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
-                                              : WAIT_TAPE_CMD;
-
-       /* Clear the interrupt */
-       stat = tp_ops->read_status(hwif);
-
-       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               int rc;
-
-               drive->waiting_for_dma = 0;
-               rc = hwif->dma_ops->dma_end(drive);
-               ide_dma_unmap_sg(drive, cmd);
-
-               if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
-                       if (drive->media == ide_floppy)
-                               printk(KERN_ERR PFX "%s: DMA %s error\n",
-                                       drive->name, rq_data_dir(pc->rq)
-                                                    ? "write" : "read");
-                       pc->flags |= PC_FLAG_DMA_ERROR;
-               } else
-                       scsi_req(rq)->resid_len = 0;
-               debug_log("%s: DMA finished\n", drive->name);
-       }
-
-       /* No more interrupts */
-       if ((stat & ATA_DRQ) == 0) {
-               int uptodate;
-               blk_status_t error;
-
-               debug_log("Packet command completed, %d bytes transferred\n",
-                         blk_rq_bytes(rq));
-
-               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
-
-               local_irq_enable_in_hardirq();
-
-               if (drive->media == ide_tape &&
-                   (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE)
-                       stat &= ~ATA_ERR;
-
-               if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
-                       /* Error detected */
-                       debug_log("%s: I/O error\n", drive->name);
-
-                       if (drive->media != ide_tape)
-                               scsi_req(pc->rq)->result++;
-
-                       if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) {
-                               printk(KERN_ERR PFX "%s: I/O error in request "
-                                               "sense command\n", drive->name);
-                               return ide_do_reset(drive);
-                       }
-
-                       debug_log("[cmd %x]: check condition\n", scsi_req(rq)->cmd[0]);
-
-                       /* Retry operation */
-                       ide_retry_pc(drive);
-
-                       /* queued, but not started */
-                       return ide_stopped;
-               }
-               pc->error = 0;
-
-               if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
-                       dsc = 1;
-
-               /*
-                * ->pc_callback() might change rq->data_len for
-                * residual count, cache total length.
-                */
-               done = blk_rq_bytes(rq);
-
-               /* Command finished - Call the callback function */
-               uptodate = drive->pc_callback(drive, dsc);
-
-               if (uptodate == 0)
-                       drive->failed_pc = NULL;
-
-               if (ata_misc_request(rq)) {
-                       scsi_req(rq)->result = 0;
-                       error = BLK_STS_OK;
-               } else {
-
-                       if (blk_rq_is_passthrough(rq) && uptodate <= 0) {
-                               if (scsi_req(rq)->result == 0)
-                                       scsi_req(rq)->result = -EIO;
-                       }
-
-                       error = uptodate ? BLK_STS_OK : BLK_STS_IOERR;
-               }
-
-               ide_complete_rq(drive, error, blk_rq_bytes(rq));
-               return ide_stopped;
-       }
-
-       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
-               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
-               printk(KERN_ERR PFX "%s: The device wants to issue more "
-                               "interrupts in DMA mode\n", drive->name);
-               ide_dma_off(drive);
-               return ide_do_reset(drive);
-       }
-
-       /* Get the number of bytes to transfer on this interrupt. */
-       ide_read_bcount_and_ireason(drive, &bcount, &ireason);
-
-       if (ide_check_ireason(drive, rq, bcount, ireason, write))
-               return ide_do_reset(drive);
-
-       done = min_t(unsigned int, bcount, cmd->nleft);
-       ide_pio_bytes(drive, cmd, write, done);
-
-       /* Update transferred byte count */
-       scsi_req(rq)->resid_len -= done;
-
-       bcount -= done;
-
-       if (bcount)
-               ide_pad_transfer(drive, write, bcount);
-
-       debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n",
-                 scsi_req(rq)->cmd[0], done, bcount, scsi_req(rq)->resid_len);
-
-       /* And set the interrupt handler again */
-       ide_set_handler(drive, ide_pc_intr, timeout);
-       return ide_started;
-}
-
-static void ide_init_packet_cmd(struct ide_cmd *cmd, u8 valid_tf,
-                               u16 bcount, u8 dma)
-{
-       cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO;
-       cmd->valid.out.tf = IDE_VALID_LBAH | IDE_VALID_LBAM |
-                           IDE_VALID_FEATURE | valid_tf;
-       cmd->tf.command = ATA_CMD_PACKET;
-       cmd->tf.feature = dma;          /* Use PIO/DMA */
-       cmd->tf.lbam    = bcount & 0xff;
-       cmd->tf.lbah    = (bcount >> 8) & 0xff;
-}
-
-static u8 ide_read_ireason(ide_drive_t *drive)
-{
-       struct ide_taskfile tf;
-
-       drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT);
-
-       return tf.nsect & 3;
-}
-
-static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
-{
-       int retries = 100;
-
-       while (retries-- && ((ireason & ATAPI_COD) == 0 ||
-               (ireason & ATAPI_IO))) {
-               printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing "
-                               "a packet command, retrying\n", drive->name);
-               udelay(100);
-               ireason = ide_read_ireason(drive);
-               if (retries == 0) {
-                       printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing"
-                                       " a packet command, ignoring\n",
-                                       drive->name);
-                       ireason |= ATAPI_COD;
-                       ireason &= ~ATAPI_IO;
-               }
-       }
-
-       return ireason;
-}
-
-static int ide_delayed_transfer_pc(ide_drive_t *drive)
-{
-       /* Send the actual packet */
-       drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
-
-       /* Timeout for the packet command */
-       return WAIT_FLOPPY_CMD;
-}
-
-static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
-{
-       struct ide_atapi_pc *pc;
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       ide_expiry_t *expiry;
-       unsigned int timeout;
-       int cmd_len;
-       ide_startstop_t startstop;
-       u8 ireason;
-
-       if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
-               printk(KERN_ERR PFX "%s: Strange, packet command initiated yet "
-                               "DRQ isn't asserted\n", drive->name);
-               return startstop;
-       }
-
-       if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
-               if (drive->dma)
-                       drive->waiting_for_dma = 1;
-       }
-
-       if (dev_is_idecd(drive)) {
-               /* ATAPI commands get padded out to 12 bytes minimum */
-               cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]);
-               if (cmd_len < ATAPI_MIN_CDB_BYTES)
-                       cmd_len = ATAPI_MIN_CDB_BYTES;
-
-               timeout = rq->timeout;
-               expiry  = ide_cd_expiry;
-       } else {
-               pc = drive->pc;
-
-               cmd_len = ATAPI_MIN_CDB_BYTES;
-
-               /*
-                * If necessary schedule the packet transfer to occur 'timeout'
-                * milliseconds later in ide_delayed_transfer_pc() after the
-                * device says it's ready for a packet.
-                */
-               if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
-                       timeout = drive->pc_delay;
-                       expiry = &ide_delayed_transfer_pc;
-               } else {
-                       timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
-                                                              : WAIT_TAPE_CMD;
-                       expiry = NULL;
-               }
-
-               ireason = ide_read_ireason(drive);
-               if (drive->media == ide_tape)
-                       ireason = ide_wait_ireason(drive, ireason);
-
-               if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
-                       printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while "
-                               "issuing a packet command\n", drive->name);
-
-                       return ide_do_reset(drive);
-               }
-       }
-
-       hwif->expiry = expiry;
-
-       /* Set the interrupt routine */
-       ide_set_handler(drive,
-                       (dev_is_idecd(drive) ? drive->irq_handler
-                                            : ide_pc_intr),
-                       timeout);
-
-       /* Send the actual packet */
-       if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
-               hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len);
-
-       /* Begin DMA, if necessary */
-       if (dev_is_idecd(drive)) {
-               if (drive->dma)
-                       hwif->dma_ops->dma_start(drive);
-       } else {
-               if (pc->flags & PC_FLAG_DMA_OK) {
-                       pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
-                       hwif->dma_ops->dma_start(drive);
-               }
-       }
-
-       return ide_started;
-}
-
-ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       struct ide_atapi_pc *pc;
-       ide_hwif_t *hwif = drive->hwif;
-       ide_expiry_t *expiry = NULL;
-       struct request *rq = hwif->rq;
-       unsigned int timeout, bytes;
-       u16 bcount;
-       u8 valid_tf;
-       u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT);
-
-       if (dev_is_idecd(drive)) {
-               valid_tf = IDE_VALID_NSECT | IDE_VALID_LBAL;
-               bcount = ide_cd_get_xferlen(rq);
-               expiry = ide_cd_expiry;
-               timeout = ATAPI_WAIT_PC;
-
-               if (drive->dma)
-                       drive->dma = !ide_dma_prepare(drive, cmd);
-       } else {
-               pc = drive->pc;
-
-               valid_tf = IDE_VALID_DEVICE;
-               bytes = blk_rq_bytes(rq);
-               bcount = ((drive->media == ide_tape) ? bytes
-                                                    : min_t(unsigned int,
-                                                            bytes, 63 * 1024));
-
-               /* We haven't transferred any data yet */
-               scsi_req(rq)->resid_len = bcount;
-
-               if (pc->flags & PC_FLAG_DMA_ERROR) {
-                       pc->flags &= ~PC_FLAG_DMA_ERROR;
-                       ide_dma_off(drive);
-               }
-
-               if (pc->flags & PC_FLAG_DMA_OK)
-                       drive->dma = !ide_dma_prepare(drive, cmd);
-
-               if (!drive->dma)
-                       pc->flags &= ~PC_FLAG_DMA_OK;
-
-               timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
-                                                      : WAIT_TAPE_CMD;
-       }
-
-       ide_init_packet_cmd(cmd, valid_tf, bcount, drive->dma);
-
-       (void)do_rw_taskfile(drive, cmd);
-
-       if (drq_int) {
-               if (drive->dma)
-                       drive->waiting_for_dma = 0;
-               hwif->expiry = expiry;
-       }
-
-       ide_execute_command(drive, cmd, ide_transfer_pc, timeout);
-
-       return drq_int ? ide_started : ide_transfer_pc(drive);
-}
-EXPORT_SYMBOL_GPL(ide_issue_pc);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
deleted file mode 100644 (file)
index cffbcc2..0000000
+++ /dev/null
@@ -1,1858 +0,0 @@
-/*
- * ATAPI CD-ROM driver.
- *
- * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005, 2007-2009  Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * See Documentation/cdrom/ide-cd.rst for usage information.
- *
- * Suggestions are welcome. Patches that work are more welcome though. ;-)
- *
- * Documentation:
- *     Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
- *
- * For historical changelog please see:
- *     Documentation/ide/ChangeLog.ide-cd.1994-2004
- */
-
-#define DRV_NAME "ide-cd"
-#define PFX DRV_NAME ": "
-
-#define IDECD_VERSION "5.00"
-
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched/task_stack.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-#include <linux/bcd.h>
-
-/* For SCSI -> ATAPI command conversion */
-#include <scsi/scsi.h>
-
-#include <linux/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include "ide-cd.h"
-
-static DEFINE_MUTEX(ide_cd_mutex);
-static DEFINE_MUTEX(idecd_ref_mutex);
-
-static void ide_cd_release(struct device *);
-
-static struct cdrom_info *ide_cd_get(struct gendisk *disk)
-{
-       struct cdrom_info *cd = NULL;
-
-       mutex_lock(&idecd_ref_mutex);
-       cd = ide_drv_g(disk, cdrom_info);
-       if (cd) {
-               if (ide_device_get(cd->drive))
-                       cd = NULL;
-               else
-                       get_device(&cd->dev);
-
-       }
-       mutex_unlock(&idecd_ref_mutex);
-       return cd;
-}
-
-static void ide_cd_put(struct cdrom_info *cd)
-{
-       ide_drive_t *drive = cd->drive;
-
-       mutex_lock(&idecd_ref_mutex);
-       put_device(&cd->dev);
-       ide_device_put(drive);
-       mutex_unlock(&idecd_ref_mutex);
-}
-
-/*
- * Generic packet command support and error handling routines.
- */
-
-/* Mark that we've seen a media change and invalidate our internal buffers. */
-static void cdrom_saw_media_change(ide_drive_t *drive)
-{
-       drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
-       drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
-}
-
-static int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
-{
-       struct request_sense *sense = &drive->sense_data;
-       int log = 0;
-
-       if (!sense || !rq || (rq->rq_flags & RQF_QUIET))
-               return 0;
-
-       ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
-
-       switch (sense->sense_key) {
-       case NO_SENSE:
-       case RECOVERED_ERROR:
-               break;
-       case NOT_READY:
-               /*
-                * don't care about tray state messages for e.g. capacity
-                * commands or in-progress or becoming ready
-                */
-               if (sense->asc == 0x3a || sense->asc == 0x04)
-                       break;
-               log = 1;
-               break;
-       case ILLEGAL_REQUEST:
-               /*
-                * don't log START_STOP unit with LoEj set, since we cannot
-                * reliably check if drive can auto-close
-                */
-               if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
-                       break;
-               log = 1;
-               break;
-       case UNIT_ATTENTION:
-               /*
-                * Make good and sure we've seen this potential media change.
-                * Some drives (i.e. Creative) fail to present the correct sense
-                * key in the error register.
-                */
-               cdrom_saw_media_change(drive);
-               break;
-       default:
-               log = 1;
-               break;
-       }
-       return log;
-}
-
-static void cdrom_analyze_sense_data(ide_drive_t *drive,
-                                    struct request *failed_command)
-{
-       struct request_sense *sense = &drive->sense_data;
-       struct cdrom_info *info = drive->driver_data;
-       unsigned long sector;
-       unsigned long bio_sectors;
-
-       ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
-                                    sense->error_code, sense->sense_key);
-
-       if (failed_command)
-               ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
-                                            failed_command->cmd[0]);
-
-       if (!cdrom_log_sense(drive, failed_command))
-               return;
-
-       /*
-        * If a read toc is executed for a CD-R or CD-RW medium where the first
-        * toc has not been recorded yet, it will fail with 05/24/00 (which is a
-        * confusing error)
-        */
-       if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
-               if (sense->sense_key == 0x05 && sense->asc == 0x24)
-                       return;
-
-       /* current error */
-       if (sense->error_code == 0x70) {
-               switch (sense->sense_key) {
-               case MEDIUM_ERROR:
-               case VOLUME_OVERFLOW:
-               case ILLEGAL_REQUEST:
-                       if (!sense->valid)
-                               break;
-                       if (failed_command == NULL ||
-                           blk_rq_is_passthrough(failed_command))
-                               break;
-                       sector = (sense->information[0] << 24) |
-                                (sense->information[1] << 16) |
-                                (sense->information[2] <<  8) |
-                                (sense->information[3]);
-
-                       if (queue_logical_block_size(drive->queue) == 2048)
-                               /* device sector size is 2K */
-                               sector <<= 2;
-
-                       bio_sectors = max(bio_sectors(failed_command->bio), 4U);
-                       sector &= ~(bio_sectors - 1);
-
-                       /*
-                        * The SCSI specification allows for the value
-                        * returned by READ CAPACITY to be up to 75 2K
-                        * sectors past the last readable block.
-                        * Therefore, if we hit a medium error within the
-                        * last 75 2K sectors, we decrease the saved size
-                        * value.
-                        */
-                       if (sector < get_capacity(info->disk) &&
-                           drive->probed_capacity - sector < 4 * 75)
-                               set_capacity(info->disk, sector);
-               }
-       }
-
-       ide_cd_log_error(drive->name, failed_command, sense);
-}
-
-static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
-{
-       /*
-        * For ATA_PRIV_SENSE, "ide_req(rq)->special" points to the original
-        * failed request.  Also, the sense data should be read
-        * directly from rq which might be different from the original
-        * sense buffer if it got copied during mapping.
-        */
-       struct request *failed = ide_req(rq)->special;
-       void *sense = bio_data(rq->bio);
-
-       if (failed) {
-               /*
-                * Sense is always read into drive->sense_data, copy back to the
-                * original request.
-                */
-               memcpy(scsi_req(failed)->sense, sense, 18);
-               scsi_req(failed)->sense_len = scsi_req(rq)->sense_len;
-               cdrom_analyze_sense_data(drive, failed);
-
-               if (ide_end_rq(drive, failed, BLK_STS_IOERR, blk_rq_bytes(failed)))
-                       BUG();
-       } else
-               cdrom_analyze_sense_data(drive, NULL);
-}
-
-
-/*
- * Allow the drive 5 seconds to recover; some devices will return NOT_READY
- * while flushing data from cache.
- *
- * returns: 0 failed (write timeout expired)
- *         1 success
- */
-static int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
-{
-
-       struct cdrom_info *info = drive->driver_data;
-
-       if (!scsi_req(rq)->result)
-               info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY;
-
-       scsi_req(rq)->result = 1;
-
-       if (time_after(jiffies, info->write_timeout))
-               return 0;
-       else {
-               /*
-                * take a breather
-                */
-               blk_mq_requeue_request(rq, false);
-               blk_mq_delay_kick_requeue_list(drive->queue, 1);
-               return 1;
-       }
-}
-
-static void ide_cd_free_sense(ide_drive_t *drive)
-{
-       if (!drive->sense_rq)
-               return;
-
-       blk_mq_free_request(drive->sense_rq);
-       drive->sense_rq = NULL;
-       drive->sense_rq_armed = false;
-}
-
-/**
- * Returns:
- * 0: if the request should be continued.
- * 1: if the request will be going through error recovery.
- * 2: if the request should be ended.
- */
-static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       int err, sense_key, do_end_request = 0;
-
-       /* get the IDE error register */
-       err = ide_read_error(drive);
-       sense_key = err >> 4;
-
-       ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, "
-                                 "stat 0x%x",
-                                 rq->cmd[0], rq->cmd_type, err, stat);
-
-       if (ata_sense_request(rq)) {
-               /*
-                * We got an error trying to get sense info from the drive
-                * (probably while trying to recover from a former error).
-                * Just give up.
-                */
-               rq->rq_flags |= RQF_FAILED;
-               return 2;
-       }
-
-       /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */
-       if (blk_rq_is_scsi(rq) && !scsi_req(rq)->result)
-               scsi_req(rq)->result = SAM_STAT_CHECK_CONDITION;
-
-       if (blk_noretry_request(rq))
-               do_end_request = 1;
-
-       switch (sense_key) {
-       case NOT_READY:
-               if (req_op(rq) == REQ_OP_WRITE) {
-                       if (ide_cd_breathe(drive, rq))
-                               return 1;
-               } else {
-                       cdrom_saw_media_change(drive);
-
-                       if (!blk_rq_is_passthrough(rq) &&
-                           !(rq->rq_flags & RQF_QUIET))
-                               printk(KERN_ERR PFX "%s: tray open\n",
-                                       drive->name);
-               }
-               do_end_request = 1;
-               break;
-       case UNIT_ATTENTION:
-               cdrom_saw_media_change(drive);
-
-               if (blk_rq_is_passthrough(rq))
-                       return 0;
-
-               /*
-                * Arrange to retry the request but be sure to give up if we've
-                * retried too many times.
-                */
-               if (++scsi_req(rq)->result > ERROR_MAX)
-                       do_end_request = 1;
-               break;
-       case ILLEGAL_REQUEST:
-               /*
-                * Don't print error message for this condition -- SFF8090i
-                * indicates that 5/24/00 is the correct response to a request
-                * to close the tray if the drive doesn't have that capability.
-                *
-                * cdrom_log_sense() knows this!
-                */
-               if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT)
-                       break;
-               fallthrough;
-       case DATA_PROTECT:
-               /*
-                * No point in retrying after an illegal request or data
-                * protect error.
-                */
-               if (!(rq->rq_flags & RQF_QUIET))
-                       ide_dump_status(drive, "command error", stat);
-               do_end_request = 1;
-               break;
-       case MEDIUM_ERROR:
-               /*
-                * No point in re-trying a zillion times on a bad sector.
-                * If we got here the error is not correctable.
-                */
-               if (!(rq->rq_flags & RQF_QUIET))
-                       ide_dump_status(drive, "media error "
-                                       "(bad sector)", stat);
-               do_end_request = 1;
-               break;
-       case BLANK_CHECK:
-               /* disk appears blank? */
-               if (!(rq->rq_flags & RQF_QUIET))
-                       ide_dump_status(drive, "media error (blank)",
-                                       stat);
-               do_end_request = 1;
-               break;
-       default:
-               if (blk_rq_is_passthrough(rq))
-                       break;
-               if (err & ~ATA_ABORTED) {
-                       /* go to the default handler for other errors */
-                       ide_error(drive, "cdrom_decode_status", stat);
-                       return 1;
-               } else if (++scsi_req(rq)->result > ERROR_MAX)
-                       /* we've racked up too many retries, abort */
-                       do_end_request = 1;
-       }
-
-       if (blk_rq_is_passthrough(rq)) {
-               rq->rq_flags |= RQF_FAILED;
-               do_end_request = 1;
-       }
-
-       /*
-        * End a request through request sense analysis when we have sense data.
-        * We need this in order to perform end of media processing.
-        */
-       if (do_end_request)
-               goto end_request;
-
-       /* if we got a CHECK_CONDITION status, queue a request sense command */
-       if (stat & ATA_ERR)
-               return ide_queue_sense_rq(drive, NULL) ? 2 : 1;
-       return 1;
-
-end_request:
-       if (stat & ATA_ERR) {
-               hwif->rq = NULL;
-               return ide_queue_sense_rq(drive, rq) ? 2 : 1;
-       } else
-               return 2;
-}
-
-static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       struct request *rq = cmd->rq;
-
-       ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
-
-       /*
-        * Some of the trailing request sense fields are optional,
-        * and some drives don't send them.  Sigh.
-        */
-       if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE &&
-           cmd->nleft > 0 && cmd->nleft <= 5)
-               cmd->nleft = 0;
-}
-
-int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
-                   int write, void *buffer, unsigned *bufflen,
-                   struct scsi_sense_hdr *sshdr, int timeout,
-                   req_flags_t rq_flags)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct scsi_sense_hdr local_sshdr;
-       int retries = 10;
-       bool failed;
-
-       ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
-                                 "rq_flags: 0x%x",
-                                 cmd[0], write, timeout, rq_flags);
-
-       if (!sshdr)
-               sshdr = &local_sshdr;
-
-       /* start of retry loop */
-       do {
-               struct request *rq;
-               int error;
-               bool delay = false;
-
-               rq = blk_get_request(drive->queue,
-                       write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
-               memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB);
-               ide_req(rq)->type = ATA_PRIV_PC;
-               rq->rq_flags |= rq_flags;
-               rq->timeout = timeout;
-               if (buffer) {
-                       error = blk_rq_map_kern(drive->queue, rq, buffer,
-                                               *bufflen, GFP_NOIO);
-                       if (error) {
-                               blk_put_request(rq);
-                               return error;
-                       }
-               }
-
-               blk_execute_rq(info->disk, rq, 0);
-               error = scsi_req(rq)->result ? -EIO : 0;
-
-               if (buffer)
-                       *bufflen = scsi_req(rq)->resid_len;
-               scsi_normalize_sense(scsi_req(rq)->sense,
-                                    scsi_req(rq)->sense_len, sshdr);
-
-               /*
-                * FIXME: we should probably abort/retry or something in case of
-                * failure.
-                */
-               failed = (rq->rq_flags & RQF_FAILED) != 0;
-               if (failed) {
-                       /*
-                        * The request failed.  Retry if it was due to a unit
-                        * attention status (usually means media was changed).
-                        */
-                       if (sshdr->sense_key == UNIT_ATTENTION)
-                               cdrom_saw_media_change(drive);
-                       else if (sshdr->sense_key == NOT_READY &&
-                                sshdr->asc == 4 && sshdr->ascq != 4) {
-                               /*
-                                * The drive is in the process of loading
-                                * a disk.  Retry, but wait a little to give
-                                * the drive time to complete the load.
-                                */
-                               delay = true;
-                       } else {
-                               /* otherwise, don't retry */
-                               retries = 0;
-                       }
-                       --retries;
-               }
-               blk_put_request(rq);
-               if (delay)
-                       ssleep(2);
-       } while (failed && retries >= 0);
-
-       /* return an error if the command failed */
-       return failed ? -EIO : 0;
-}
-
-/*
- * returns true if rq has been completed
- */
-static bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
-
-       if (cmd->tf_flags & IDE_TFLAG_WRITE)
-               nr_bytes -= cmd->last_xfer_len;
-
-       if (nr_bytes > 0) {
-               ide_complete_rq(drive, BLK_STS_OK, nr_bytes);
-               return true;
-       }
-
-       return false;
-}
-
-/* standard prep_rq that builds 10 byte cmds */
-static bool ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
-{
-       int hard_sect = queue_logical_block_size(q);
-       long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
-       unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
-       struct scsi_request *req = scsi_req(rq);
-
-       if (rq_data_dir(rq) == READ)
-               req->cmd[0] = GPCMD_READ_10;
-       else
-               req->cmd[0] = GPCMD_WRITE_10;
-
-       /*
-        * fill in lba
-        */
-       req->cmd[2] = (block >> 24) & 0xff;
-       req->cmd[3] = (block >> 16) & 0xff;
-       req->cmd[4] = (block >>  8) & 0xff;
-       req->cmd[5] = block & 0xff;
-
-       /*
-        * and transfer length
-        */
-       req->cmd[7] = (blocks >> 8) & 0xff;
-       req->cmd[8] = blocks & 0xff;
-       req->cmd_len = 10;
-       return true;
-}
-
-/*
- * Most of the SCSI commands are supported directly by ATAPI devices.
- * This transform handles the few exceptions.
- */
-static bool ide_cdrom_prep_pc(struct request *rq)
-{
-       u8 *c = scsi_req(rq)->cmd;
-
-       /* transform 6-byte read/write commands to the 10-byte version */
-       if (c[0] == READ_6 || c[0] == WRITE_6) {
-               c[8] = c[4];
-               c[5] = c[3];
-               c[4] = c[2];
-               c[3] = c[1] & 0x1f;
-               c[2] = 0;
-               c[1] &= 0xe0;
-               c[0] += (READ_10 - READ_6);
-               scsi_req(rq)->cmd_len = 10;
-               return true;
-       }
-
-       /*
-        * it's silly to pretend we understand 6-byte sense commands, just
-        * reject with ILLEGAL_REQUEST and the caller should take the
-        * appropriate action
-        */
-       if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
-               scsi_req(rq)->result = ILLEGAL_REQUEST;
-               return false;
-       }
-
-       return true;
-}
-
-static bool ide_cdrom_prep_rq(ide_drive_t *drive, struct request *rq)
-{
-       if (!blk_rq_is_passthrough(rq)) {
-               scsi_req_init(scsi_req(rq));
-
-               return ide_cdrom_prep_fs(drive->queue, rq);
-       } else if (blk_rq_is_scsi(rq))
-               return ide_cdrom_prep_pc(rq);
-
-       return true;
-}
-
-static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
-       struct request *rq = hwif->rq;
-       ide_expiry_t *expiry = NULL;
-       int dma_error = 0, dma, thislen, uptodate = 0;
-       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0;
-       int sense = ata_sense_request(rq);
-       unsigned int timeout;
-       u16 len;
-       u8 ireason, stat;
-
-       ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write);
-
-       /* check for errors */
-       dma = drive->dma;
-       if (dma) {
-               drive->dma = 0;
-               drive->waiting_for_dma = 0;
-               dma_error = hwif->dma_ops->dma_end(drive);
-               ide_dma_unmap_sg(drive, cmd);
-               if (dma_error) {
-                       printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
-                                       write ? "write" : "read");
-                       ide_dma_off(drive);
-               }
-       }
-
-       /* check status */
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(stat, 0, BAD_R_STAT)) {
-               rc = cdrom_decode_status(drive, stat);
-               if (rc) {
-                       if (rc == 2)
-                               goto out_end;
-                       return ide_stopped;
-               }
-       }
-
-       /* using dma, transfer is complete now */
-       if (dma) {
-               if (dma_error)
-                       return ide_error(drive, "dma error", stat);
-               uptodate = 1;
-               goto out_end;
-       }
-
-       ide_read_bcount_and_ireason(drive, &len, &ireason);
-
-       thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft;
-       if (thislen > len)
-               thislen = len;
-
-       ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
-                                 stat, thislen);
-
-       /* If DRQ is clear, the command has completed. */
-       if ((stat & ATA_DRQ) == 0) {
-               switch (req_op(rq)) {
-               default:
-                       /*
-                        * If we're not done reading/writing, complain.
-                        * Otherwise, complete the command normally.
-                        */
-                       uptodate = 1;
-                       if (cmd->nleft > 0) {
-                               printk(KERN_ERR PFX "%s: %s: data underrun "
-                                       "(%u bytes)\n", drive->name, __func__,
-                                       cmd->nleft);
-                               if (!write)
-                                       rq->rq_flags |= RQF_FAILED;
-                               uptodate = 0;
-                       }
-                       goto out_end;
-               case REQ_OP_DRV_IN:
-               case REQ_OP_DRV_OUT:
-                       ide_cd_request_sense_fixup(drive, cmd);
-
-                       uptodate = cmd->nleft ? 0 : 1;
-
-                       /*
-                        * suck out the remaining bytes from the drive in an
-                        * attempt to complete the data xfer. (see BZ#13399)
-                        */
-                       if (!(stat & ATA_ERR) && !uptodate && thislen) {
-                               ide_pio_bytes(drive, cmd, write, thislen);
-                               uptodate = cmd->nleft ? 0 : 1;
-                       }
-
-                       if (!uptodate)
-                               rq->rq_flags |= RQF_FAILED;
-                       goto out_end;
-               case REQ_OP_SCSI_IN:
-               case REQ_OP_SCSI_OUT:
-                       goto out_end;
-               }
-       }
-
-       rc = ide_check_ireason(drive, rq, len, ireason, write);
-       if (rc)
-               goto out_end;
-
-       cmd->last_xfer_len = 0;
-
-       ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
-                                 "ireason: 0x%x",
-                                 rq->cmd_type, ireason);
-
-       /* transfer data */
-       while (thislen > 0) {
-               int blen = min_t(int, thislen, cmd->nleft);
-
-               if (cmd->nleft == 0)
-                       break;
-
-               ide_pio_bytes(drive, cmd, write, blen);
-               cmd->last_xfer_len += blen;
-
-               thislen -= blen;
-               len -= blen;
-
-               if (sense && write == 0)
-                       scsi_req(rq)->sense_len += blen;
-       }
-
-       /* pad, if necessary */
-       if (len > 0) {
-               if (blk_rq_is_passthrough(rq) || write == 0)
-                       ide_pad_transfer(drive, write, len);
-               else {
-                       printk(KERN_ERR PFX "%s: confused, missing data\n",
-                               drive->name);
-                       blk_dump_rq_flags(rq, "cdrom_newpc_intr");
-               }
-       }
-
-       switch (req_op(rq)) {
-       case REQ_OP_SCSI_IN:
-       case REQ_OP_SCSI_OUT:
-               timeout = rq->timeout;
-               break;
-       case REQ_OP_DRV_IN:
-       case REQ_OP_DRV_OUT:
-               expiry = ide_cd_expiry;
-               fallthrough;
-       default:
-               timeout = ATAPI_WAIT_PC;
-               break;
-       }
-
-       hwif->expiry = expiry;
-       ide_set_handler(drive, cdrom_newpc_intr, timeout);
-       return ide_started;
-
-out_end:
-       if (blk_rq_is_scsi(rq) && rc == 0) {
-               scsi_req(rq)->resid_len = 0;
-               blk_mq_end_request(rq, BLK_STS_OK);
-               hwif->rq = NULL;
-       } else {
-               if (sense && uptodate)
-                       ide_cd_complete_failed_rq(drive, rq);
-
-               if (!blk_rq_is_passthrough(rq)) {
-                       if (cmd->nleft == 0)
-                               uptodate = 1;
-               } else {
-                       if (uptodate <= 0 && scsi_req(rq)->result == 0)
-                               scsi_req(rq)->result = -EIO;
-               }
-
-               if (uptodate == 0 && rq->bio)
-                       if (ide_cd_error_cmd(drive, cmd))
-                               return ide_stopped;
-
-               /* make sure it's fully ended */
-               if (blk_rq_is_passthrough(rq)) {
-                       scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft;
-                       if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
-                               scsi_req(rq)->resid_len += cmd->last_xfer_len;
-               }
-
-               ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, blk_rq_bytes(rq));
-
-               if (sense && rc == 2)
-                       ide_error(drive, "request sense failure", stat);
-       }
-
-       ide_cd_free_sense(drive);
-       return ide_stopped;
-}
-
-static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct request_queue *q = drive->queue;
-       int write = rq_data_dir(rq) == WRITE;
-       unsigned short sectors_per_frame =
-               queue_logical_block_size(q) >> SECTOR_SHIFT;
-
-       ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
-                                 "secs_per_frame: %u",
-                                 rq->cmd[0], rq->cmd_flags, sectors_per_frame);
-
-       if (write) {
-               /* disk has become write protected */
-               if (get_disk_ro(cd->disk))
-                       return ide_stopped;
-       } else {
-               /*
-                * We may be retrying this request after an error.  Fix up any
-                * weirdness which might be present in the request packet.
-                */
-               ide_cdrom_prep_rq(drive, rq);
-       }
-
-       /* fs requests *must* be hardware frame aligned */
-       if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) ||
-           (blk_rq_pos(rq) & (sectors_per_frame - 1)))
-               return ide_stopped;
-
-       /* use DMA, if possible */
-       drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
-       if (write)
-               cd->devinfo.media_written = 1;
-
-       rq->timeout = ATAPI_WAIT_PC;
-
-       return ide_started;
-}
-
-static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
-{
-
-       ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
-                                 rq->cmd[0], rq->cmd_type);
-
-       if (blk_rq_is_scsi(rq))
-               rq->rq_flags |= RQF_QUIET;
-       else
-               rq->rq_flags &= ~RQF_FAILED;
-
-       drive->dma = 0;
-
-       /* sg request */
-       if (rq->bio) {
-               struct request_queue *q = drive->queue;
-               char *buf = bio_data(rq->bio);
-               unsigned int alignment;
-
-               drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
-               /*
-                * check if dma is safe
-                *
-                * NOTE! The "len" and "addr" checks should possibly have
-                * separate masks.
-                */
-               alignment = queue_dma_alignment(q) | q->dma_pad_mask;
-               if ((unsigned long)buf & alignment
-                   || blk_rq_bytes(rq) & q->dma_pad_mask
-                   || object_is_on_stack(buf))
-                       drive->dma = 0;
-       }
-}
-
-static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
-                                       sector_t block)
-{
-       struct ide_cmd cmd;
-       int uptodate = 0;
-       unsigned int nsectors;
-
-       ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
-                                 rq->cmd[0], (unsigned long long)block);
-
-       if (drive->debug_mask & IDE_DBG_RQ)
-               blk_dump_rq_flags(rq, "ide_cd_do_request");
-
-       switch (req_op(rq)) {
-       default:
-               if (cdrom_start_rw(drive, rq) == ide_stopped)
-                       goto out_end;
-               break;
-       case REQ_OP_SCSI_IN:
-       case REQ_OP_SCSI_OUT:
-       handle_pc:
-               if (!rq->timeout)
-                       rq->timeout = ATAPI_WAIT_PC;
-               cdrom_do_block_pc(drive, rq);
-               break;
-       case REQ_OP_DRV_IN:
-       case REQ_OP_DRV_OUT:
-               switch (ide_req(rq)->type) {
-               case ATA_PRIV_MISC:
-                       /* right now this can only be a reset... */
-                       uptodate = 1;
-                       goto out_end;
-               case ATA_PRIV_SENSE:
-               case ATA_PRIV_PC:
-                       goto handle_pc;
-               default:
-                       BUG();
-               }
-       }
-
-       /* prepare sense request for this command */
-       ide_prep_sense(drive, rq);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       if (rq_data_dir(rq))
-               cmd.tf_flags |= IDE_TFLAG_WRITE;
-
-       cmd.rq = rq;
-
-       if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
-               ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
-               ide_map_sg(drive, &cmd);
-       }
-
-       return ide_issue_pc(drive, &cmd);
-out_end:
-       nsectors = blk_rq_sectors(rq);
-
-       if (nsectors == 0)
-               nsectors = 1;
-
-       ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, nsectors << 9);
-
-       return ide_stopped;
-}
-
-/*
- * Ioctl handling.
- *
- * Routines which queue packet commands take as a final argument a pointer to a
- * request_sense struct. If execution of the command results in an error with a
- * CHECK CONDITION status, this structure will be filled with the results of the
- * subsequent request sense command. The pointer can also be NULL, in which case
- * no sense information is returned.
- */
-static void msf_from_bcd(struct atapi_msf *msf)
-{
-       msf->minute = bcd2bin(msf->minute);
-       msf->second = bcd2bin(msf->second);
-       msf->frame  = bcd2bin(msf->frame);
-}
-
-int cdrom_check_status(ide_drive_t *drive, struct scsi_sense_hdr *sshdr)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi;
-       unsigned char cmd[BLK_MAX_CDB];
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (!info)
-               return -EIO;
-
-       cdi = &info->devinfo;
-
-       memset(cmd, 0, BLK_MAX_CDB);
-       cmd[0] = GPCMD_TEST_UNIT_READY;
-
-       /*
-        * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs
-        * instead of supporting the LOAD_UNLOAD opcode.
-        */
-       cmd[7] = cdi->sanyo_slot % 3;
-
-       return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sshdr, 0, RQF_QUIET);
-}
-
-static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
-                              unsigned long *sectors_per_frame)
-{
-       struct {
-               __be32 lba;
-               __be32 blocklen;
-       } capbuf;
-
-       int stat;
-       unsigned char cmd[BLK_MAX_CDB];
-       unsigned len = sizeof(capbuf);
-       u32 blocklen;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       memset(cmd, 0, BLK_MAX_CDB);
-       cmd[0] = GPCMD_READ_CDVD_CAPACITY;
-
-       stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, NULL, 0,
-                              RQF_QUIET);
-       if (stat)
-               return stat;
-
-       /*
-        * Sanity check the given block size, in so far as making
-        * sure the sectors_per_frame we give to the caller won't
-        * end up being bogus.
-        */
-       blocklen = be32_to_cpu(capbuf.blocklen);
-       blocklen = (blocklen >> SECTOR_SHIFT) << SECTOR_SHIFT;
-       switch (blocklen) {
-       case 512:
-       case 1024:
-       case 2048:
-       case 4096:
-               break;
-       default:
-               printk_once(KERN_ERR PFX "%s: weird block size %u; "
-                               "setting default block size to 2048\n",
-                               drive->name, blocklen);
-               blocklen = 2048;
-               break;
-       }
-
-       *capacity = 1 + be32_to_cpu(capbuf.lba);
-       *sectors_per_frame = blocklen >> SECTOR_SHIFT;
-
-       ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu",
-                                    *capacity, *sectors_per_frame);
-
-       return 0;
-}
-
-static int ide_cdrom_read_tocentry(ide_drive_t *drive, int trackno,
-               int msf_flag, int format, char *buf, int buflen)
-{
-       unsigned char cmd[BLK_MAX_CDB];
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       memset(cmd, 0, BLK_MAX_CDB);
-
-       cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-       cmd[6] = trackno;
-       cmd[7] = (buflen >> 8);
-       cmd[8] = (buflen & 0xff);
-       cmd[9] = (format << 6);
-
-       if (msf_flag)
-               cmd[1] = 2;
-
-       return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, NULL, 0, RQF_QUIET);
-}
-
-/* Try to read the entire TOC for the disk into our internal buffer. */
-int ide_cd_read_toc(ide_drive_t *drive)
-{
-       int stat, ntracks, i;
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi = &info->devinfo;
-       struct atapi_toc *toc = info->toc;
-       struct {
-               struct atapi_toc_header hdr;
-               struct atapi_toc_entry  ent;
-       } ms_tmp;
-       long last_written;
-       unsigned long sectors_per_frame = SECTORS_PER_FRAME;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (toc == NULL) {
-               /* try to allocate space */
-               toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
-               if (toc == NULL) {
-                       printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
-                                       drive->name);
-                       return -ENOMEM;
-               }
-               info->toc = toc;
-       }
-
-       /*
-        * Check to see if the existing data is still valid. If it is,
-        * just return.
-        */
-       (void) cdrom_check_status(drive, NULL);
-
-       if (drive->atapi_flags & IDE_AFLAG_TOC_VALID)
-               return 0;
-
-       /* try to get the total cdrom capacity and sector size */
-       stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame);
-       if (stat)
-               toc->capacity = 0x1fffff;
-
-       set_capacity(info->disk, toc->capacity * sectors_per_frame);
-       /* save a private copy of the TOC capacity for error handling */
-       drive->probed_capacity = toc->capacity * sectors_per_frame;
-
-       blk_queue_logical_block_size(drive->queue,
-                                    sectors_per_frame << SECTOR_SHIFT);
-
-       /* first read just the header, so we know how long the TOC is */
-       stat = ide_cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
-                                   sizeof(struct atapi_toc_header));
-       if (stat)
-               return stat;
-
-       if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
-               toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
-               toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
-       }
-
-       ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
-       if (ntracks <= 0)
-               return -EIO;
-       if (ntracks > MAX_TRACKS)
-               ntracks = MAX_TRACKS;
-
-       /* now read the whole schmeer */
-       stat = ide_cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
-                                 (char *)&toc->hdr,
-                                  sizeof(struct atapi_toc_header) +
-                                  (ntracks + 1) *
-                                  sizeof(struct atapi_toc_entry));
-
-       if (stat && toc->hdr.first_track > 1) {
-               /*
-                * Cds with CDI tracks only don't have any TOC entries, despite
-                * of this the returned values are
-                * first_track == last_track = number of CDI tracks + 1,
-                * so that this case is indistinguishable from the same layout
-                * plus an additional audio track. If we get an error for the
-                * regular case, we assume a CDI without additional audio
-                * tracks. In this case the readable TOC is empty (CDI tracks
-                * are not included) and only holds the Leadout entry.
-                *
-                * Heiko Eißfeldt.
-                */
-               ntracks = 0;
-               stat = ide_cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
-                                          (char *)&toc->hdr,
-                                          sizeof(struct atapi_toc_header) +
-                                          (ntracks + 1) *
-                                          sizeof(struct atapi_toc_entry));
-               if (stat)
-                       return stat;
-
-               if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
-                       toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT);
-                       toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT);
-               } else {
-                       toc->hdr.first_track = CDROM_LEADOUT;
-                       toc->hdr.last_track = CDROM_LEADOUT;
-               }
-       }
-
-       if (stat)
-               return stat;
-
-       toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length);
-
-       if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
-               toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
-               toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
-       }
-
-       for (i = 0; i <= ntracks; i++) {
-               if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
-                       if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD)
-                               toc->ent[i].track = bcd2bin(toc->ent[i].track);
-                       msf_from_bcd(&toc->ent[i].addr.msf);
-               }
-               toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute,
-                                                 toc->ent[i].addr.msf.second,
-                                                 toc->ent[i].addr.msf.frame);
-       }
-
-       if (toc->hdr.first_track != CDROM_LEADOUT) {
-               /* read the multisession information */
-               stat = ide_cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
-                                          sizeof(ms_tmp));
-               if (stat)
-                       return stat;
-
-               toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
-       } else {
-               ms_tmp.hdr.last_track = CDROM_LEADOUT;
-               ms_tmp.hdr.first_track = ms_tmp.hdr.last_track;
-               toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
-       }
-
-       if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
-               /* re-read multisession information using MSF format */
-               stat = ide_cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
-                                          sizeof(ms_tmp));
-               if (stat)
-                       return stat;
-
-               msf_from_bcd(&ms_tmp.ent.addr.msf);
-               toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
-                                                  ms_tmp.ent.addr.msf.second,
-                                                  ms_tmp.ent.addr.msf.frame);
-       }
-
-       toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
-
-       /* now try to get the total cdrom capacity */
-       stat = cdrom_get_last_written(cdi, &last_written);
-       if (!stat && (last_written > toc->capacity)) {
-               toc->capacity = last_written;
-               set_capacity(info->disk, toc->capacity * sectors_per_frame);
-               drive->probed_capacity = toc->capacity * sectors_per_frame;
-       }
-
-       /* Remember that we've read this stuff. */
-       drive->atapi_flags |= IDE_AFLAG_TOC_VALID;
-
-       return 0;
-}
-
-int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi = &info->devinfo;
-       struct packet_command cgc;
-       int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
-               size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
-
-       init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
-       do {
-               /* we seem to get stat=0x01,err=0x00 the first time (??) */
-               stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
-               if (!stat)
-                       break;
-       } while (--attempts);
-       return stat;
-}
-
-void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       u16 curspeed, maxspeed;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
-               curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
-               maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
-       } else {
-               curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]);
-               maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
-       }
-
-       ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u",
-                                    curspeed, maxspeed);
-
-       cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176);
-       cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176);
-}
-
-#define IDE_CD_CAPABILITIES \
-       (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
-        CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
-        CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
-        CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
-        CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
-
-static const struct cdrom_device_ops ide_cdrom_dops = {
-       .open                   = ide_cdrom_open_real,
-       .release                = ide_cdrom_release_real,
-       .drive_status           = ide_cdrom_drive_status,
-       .check_events           = ide_cdrom_check_events_real,
-       .tray_move              = ide_cdrom_tray_move,
-       .lock_door              = ide_cdrom_lock_door,
-       .select_speed           = ide_cdrom_select_speed,
-       .get_last_session       = ide_cdrom_get_last_session,
-       .get_mcn                = ide_cdrom_get_mcn,
-       .reset                  = ide_cdrom_reset,
-       .audio_ioctl            = ide_cdrom_audio_ioctl,
-       .capability             = IDE_CD_CAPABILITIES,
-       .generic_packet         = ide_cdrom_packet,
-};
-
-static int ide_cdrom_register(ide_drive_t *drive, int nslots)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *devinfo = &info->devinfo;
-
-       ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots);
-
-       devinfo->ops = &ide_cdrom_dops;
-       devinfo->speed = info->current_speed;
-       devinfo->capacity = nslots;
-       devinfo->handle = drive;
-       strcpy(devinfo->name, drive->name);
-
-       if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT)
-               devinfo->mask |= CDC_SELECT_SPEED;
-
-       return register_cdrom(info->disk, devinfo);
-}
-
-static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct cdrom_device_info *cdi = &cd->devinfo;
-       u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
-       mechtype_t mechtype;
-       int nslots = 1;
-
-       ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx",
-                                    drive->media, drive->atapi_flags);
-
-       cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
-                    CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
-                    CDC_MO_DRIVE | CDC_RAM);
-
-       if (drive->media == ide_optical) {
-               cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
-               printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
-                               drive->name);
-               return nslots;
-       }
-
-       if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) {
-               drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
-               cdi->mask &= ~CDC_PLAY_AUDIO;
-               return nslots;
-       }
-
-       /*
-        * We have to cheat a little here. the packet will eventually be queued
-        * with ide_cdrom_packet(), which extracts the drive from cdi->handle.
-        * Since this device hasn't been registered with the Uniform layer yet,
-        * it can't do this. Same goes for cdi->ops.
-        */
-       cdi->handle = drive;
-       cdi->ops = &ide_cdrom_dops;
-
-       if (ide_cdrom_get_capabilities(drive, buf))
-               return 0;
-
-       if ((buf[8 + 6] & 0x01) == 0)
-               drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-       if (buf[8 + 6] & 0x08)
-               drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
-       if (buf[8 + 3] & 0x01)
-               cdi->mask &= ~CDC_CD_R;
-       if (buf[8 + 3] & 0x02)
-               cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
-       if (buf[8 + 2] & 0x38)
-               cdi->mask &= ~CDC_DVD;
-       if (buf[8 + 3] & 0x20)
-               cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
-       if (buf[8 + 3] & 0x10)
-               cdi->mask &= ~CDC_DVD_R;
-       if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK))
-               cdi->mask &= ~CDC_PLAY_AUDIO;
-
-       mechtype = buf[8 + 6] >> 5;
-       if (mechtype == mechtype_caddy ||
-           mechtype == mechtype_popup ||
-           (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
-               cdi->mask |= CDC_CLOSE_TRAY;
-
-       if (cdi->sanyo_slot > 0) {
-               cdi->mask &= ~CDC_SELECT_DISC;
-               nslots = 3;
-       } else if (mechtype == mechtype_individual_changer ||
-                  mechtype == mechtype_cartridge_changer) {
-               nslots = cdrom_number_of_slots(cdi);
-               if (nslots > 1)
-                       cdi->mask &= ~CDC_SELECT_DISC;
-       }
-
-       ide_cdrom_update_speed(drive, buf);
-
-       printk(KERN_INFO PFX "%s: ATAPI", drive->name);
-
-       /* don't print speed if the drive reported 0 */
-       if (cd->max_speed)
-               printk(KERN_CONT " %dX", cd->max_speed);
-
-       printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
-
-       if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
-               printk(KERN_CONT " DVD%s%s",
-                                (cdi->mask & CDC_DVD_R) ? "" : "-R",
-                                (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM");
-
-       if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
-               printk(KERN_CONT " CD%s%s",
-                                (cdi->mask & CDC_CD_R) ? "" : "-R",
-                                (cdi->mask & CDC_CD_RW) ? "" : "/RW");
-
-       if ((cdi->mask & CDC_SELECT_DISC) == 0)
-               printk(KERN_CONT " changer w/%d slots", nslots);
-       else
-               printk(KERN_CONT " drive");
-
-       printk(KERN_CONT ", %dkB Cache\n",
-                        be16_to_cpup((__be16 *)&buf[8 + 12]));
-
-       return nslots;
-}
-
-struct cd_list_entry {
-       const char      *id_model;
-       const char      *id_firmware;
-       unsigned int    cd_flags;
-};
-
-#ifdef CONFIG_IDE_PROC_FS
-static sector_t ide_cdrom_capacity(ide_drive_t *drive)
-{
-       unsigned long capacity, sectors_per_frame;
-
-       if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame))
-               return 0;
-
-       return capacity * sectors_per_frame;
-}
-
-static int idecd_capacity_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t *drive = m->private;
-
-       seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive));
-       return 0;
-}
-
-static ide_proc_entry_t idecd_proc[] = {
-       { "capacity", S_IFREG|S_IRUGO, idecd_capacity_proc_show },
-       {}
-};
-
-static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
-{
-       return idecd_proc;
-}
-
-static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
-{
-       return NULL;
-}
-#endif
-
-static const struct cd_list_entry ide_cd_quirks_list[] = {
-       /* SCR-3231 doesn't support the SET_CD_SPEED command. */
-       { "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_AFLAG_NO_SPEED_SELECT       },
-       /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
-       { "NEC CD-ROM DRIVE:260",    "1.01", IDE_AFLAG_TOCADDR_AS_BCD |
-                                            IDE_AFLAG_PRE_ATAPI12,          },
-       /* Vertos 300, some versions of this drive like to talk BCD. */
-       { "V003S0DS",                NULL,   IDE_AFLAG_VERTOS_300_SSD,       },
-       /* Vertos 600 ESD. */
-       { "V006E0DS",                NULL,   IDE_AFLAG_VERTOS_600_ESD,       },
-       /*
-        * Sanyo 3 CD changer uses a non-standard command for CD changing
-        * (by default standard ATAPI support for CD changers is used).
-        */
-       { "CD-ROM CDR-C3 G",         NULL,   IDE_AFLAG_SANYO_3CD             },
-       { "CD-ROM CDR-C3G",          NULL,   IDE_AFLAG_SANYO_3CD             },
-       { "CD-ROM CDR_C36",          NULL,   IDE_AFLAG_SANYO_3CD             },
-       /* Stingray 8X CD-ROM. */
-       { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 },
-       /*
-        * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
-        * mode sense page capabilities size, but older drives break.
-        */
-       { "ATAPI CD ROM DRIVE 50X MAX", NULL,   IDE_AFLAG_FULL_CAPS_PAGE     },
-       { "WPI CDS-32X",                NULL,   IDE_AFLAG_FULL_CAPS_PAGE     },
-       /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
-       { "",                        "241N", IDE_AFLAG_LE_SPEED_FIELDS       },
-       /*
-        * Some drives used by Apple don't advertise audio play
-        * but they do support reading TOC & audio datas.
-        */
-       { "MATSHITADVD-ROM SR-8187", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "MATSHITADVD-ROM SR-8186", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "MATSHITADVD-ROM SR-8176", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "MATSHITADVD-ROM SR-8174", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "Optiarc DVD RW AD-5200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "Optiarc DVD RW AD-7200A", NULL,   IDE_AFLAG_PLAY_AUDIO_OK         },
-       { "Optiarc DVD RW AD-7543A", NULL,   IDE_AFLAG_NO_AUTOCLOSE          },
-       { "TEAC CD-ROM CD-224E",     NULL,   IDE_AFLAG_NO_AUTOCLOSE          },
-       { NULL, NULL, 0 }
-};
-
-static unsigned int ide_cd_flags(u16 *id)
-{
-       const struct cd_list_entry *cle = ide_cd_quirks_list;
-
-       while (cle->id_model) {
-               if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
-                   (cle->id_firmware == NULL ||
-                    strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
-                       return cle->cd_flags;
-               cle++;
-       }
-
-       return 0;
-}
-
-static int ide_cdrom_setup(ide_drive_t *drive)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct cdrom_device_info *cdi = &cd->devinfo;
-       struct request_queue *q = drive->queue;
-       u16 *id = drive->id;
-       char *fw_rev = (char *)&id[ATA_ID_FW_REV];
-       int nslots;
-
-       ide_debug_log(IDE_DBG_PROBE, "enter");
-
-       drive->prep_rq = ide_cdrom_prep_rq;
-       blk_queue_dma_alignment(q, 31);
-       blk_queue_update_dma_pad(q, 15);
-
-       drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
-       drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
-
-       if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
-           fw_rev[4] == '1' && fw_rev[6] <= '2')
-               drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
-                                    IDE_AFLAG_TOCADDR_AS_BCD);
-       else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
-                fw_rev[4] == '1' && fw_rev[6] <= '2')
-               drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
-       else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
-               /* 3 => use CD in slot 0 */
-               cdi->sanyo_slot = 3;
-
-       nslots = ide_cdrom_probe_capabilities(drive);
-
-       blk_queue_logical_block_size(q, CD_FRAMESIZE);
-
-       if (ide_cdrom_register(drive, nslots)) {
-               printk(KERN_ERR PFX "%s: %s failed to register device with the"
-                               " cdrom driver.\n", drive->name, __func__);
-               cd->devinfo.handle = NULL;
-               return 1;
-       }
-
-       ide_proc_register_driver(drive, cd->driver);
-       return 0;
-}
-
-static void ide_cd_remove(ide_drive_t *drive)
-{
-       struct cdrom_info *info = drive->driver_data;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       ide_proc_unregister_driver(drive, info->driver);
-       device_del(&info->dev);
-       del_gendisk(info->disk);
-
-       mutex_lock(&idecd_ref_mutex);
-       put_device(&info->dev);
-       mutex_unlock(&idecd_ref_mutex);
-}
-
-static void ide_cd_release(struct device *dev)
-{
-       struct cdrom_info *info = to_ide_drv(dev, cdrom_info);
-       struct cdrom_device_info *devinfo = &info->devinfo;
-       ide_drive_t *drive = info->drive;
-       struct gendisk *g = info->disk;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       kfree(info->toc);
-       if (devinfo->handle == drive)
-               unregister_cdrom(devinfo);
-       drive->driver_data = NULL;
-       drive->prep_rq = NULL;
-       g->private_data = NULL;
-       put_disk(g);
-       kfree(info);
-}
-
-static int ide_cd_probe(ide_drive_t *);
-
-static struct ide_driver ide_cdrom_driver = {
-       .gen_driver = {
-               .owner          = THIS_MODULE,
-               .name           = "ide-cdrom",
-               .bus            = &ide_bus_type,
-       },
-       .probe                  = ide_cd_probe,
-       .remove                 = ide_cd_remove,
-       .version                = IDECD_VERSION,
-       .do_request             = ide_cd_do_request,
-#ifdef CONFIG_IDE_PROC_FS
-       .proc_entries           = ide_cd_proc_entries,
-       .proc_devsets           = ide_cd_proc_devsets,
-#endif
-};
-
-static int idecd_open(struct block_device *bdev, fmode_t mode)
-{
-       struct cdrom_info *info;
-       int rc = -ENXIO;
-
-       if (bdev_check_media_change(bdev)) {
-               info = ide_drv_g(bdev->bd_disk, cdrom_info);
-
-               ide_cd_read_toc(info->drive);
-       }
-
-       mutex_lock(&ide_cd_mutex);
-       info = ide_cd_get(bdev->bd_disk);
-       if (!info)
-               goto out;
-
-       rc = cdrom_open(&info->devinfo, bdev, mode);
-       if (rc < 0)
-               ide_cd_put(info);
-out:
-       mutex_unlock(&ide_cd_mutex);
-       return rc;
-}
-
-static void idecd_release(struct gendisk *disk, fmode_t mode)
-{
-       struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
-
-       mutex_lock(&ide_cd_mutex);
-       cdrom_release(&info->devinfo, mode);
-
-       ide_cd_put(info);
-       mutex_unlock(&ide_cd_mutex);
-}
-
-static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
-       struct packet_command cgc;
-       char buffer[16];
-       int stat;
-       char spindown;
-
-       if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
-               return -EFAULT;
-
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
-       stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
-       if (stat)
-               return stat;
-
-       buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
-       return cdrom_mode_select(cdi, &cgc);
-}
-
-static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
-       struct packet_command cgc;
-       char buffer[16];
-       int stat;
-       char spindown;
-
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
-       stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
-       if (stat)
-               return stat;
-
-       spindown = buffer[11] & 0x0f;
-       if (copy_to_user((void __user *)arg, &spindown, sizeof(char)))
-               return -EFAULT;
-       return 0;
-}
-
-static int idecd_locked_ioctl(struct block_device *bdev, fmode_t mode,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
-       int err;
-
-       switch (cmd) {
-       case CDROMSETSPINDOWN:
-               return idecd_set_spindown(&info->devinfo, arg);
-       case CDROMGETSPINDOWN:
-               return idecd_get_spindown(&info->devinfo, arg);
-       default:
-               break;
-       }
-
-       err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
-       if (err == -EINVAL)
-               err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg);
-
-       return err;
-}
-
-static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
-                            unsigned int cmd, unsigned long arg)
-{
-       int ret;
-
-       mutex_lock(&ide_cd_mutex);
-       ret = idecd_locked_ioctl(bdev, mode, cmd, arg);
-       mutex_unlock(&ide_cd_mutex);
-
-       return ret;
-}
-
-static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
-       void __user *argp = compat_ptr(arg);
-       int err;
-
-       switch (cmd) {
-       case CDROMSETSPINDOWN:
-               return idecd_set_spindown(&info->devinfo, (unsigned long)argp);
-       case CDROMGETSPINDOWN:
-               return idecd_get_spindown(&info->devinfo, (unsigned long)argp);
-       default:
-               break;
-       }
-
-       err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
-       if (err == -EINVAL)
-               err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
-                                 (unsigned long)argp);
-
-       return err;
-}
-
-static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
-                            unsigned int cmd, unsigned long arg)
-{
-       int ret;
-
-       mutex_lock(&ide_cd_mutex);
-       ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg);
-       mutex_unlock(&ide_cd_mutex);
-
-       return ret;
-}
-
-static unsigned int idecd_check_events(struct gendisk *disk,
-                                      unsigned int clearing)
-{
-       struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
-       return cdrom_check_events(&info->devinfo, clearing);
-}
-
-static const struct block_device_operations idecd_ops = {
-       .owner                  = THIS_MODULE,
-       .open                   = idecd_open,
-       .release                = idecd_release,
-       .ioctl                  = idecd_ioctl,
-       .compat_ioctl           = IS_ENABLED(CONFIG_COMPAT) ?
-                                 idecd_compat_ioctl : NULL,
-       .check_events           = idecd_check_events,
-};
-
-/* module options */
-static unsigned long debug_mask;
-module_param(debug_mask, ulong, 0644);
-
-MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
-
-static int ide_cd_probe(ide_drive_t *drive)
-{
-       struct cdrom_info *info;
-       struct gendisk *g;
-
-       ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x",
-                                    drive->driver_req, drive->media);
-
-       if (!strstr("ide-cdrom", drive->driver_req))
-               goto failed;
-
-       if (drive->media != ide_cdrom && drive->media != ide_optical)
-               goto failed;
-
-       drive->debug_mask = debug_mask;
-       drive->irq_handler = cdrom_newpc_intr;
-
-       info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
-       if (info == NULL) {
-               printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
-                               drive->name);
-               goto failed;
-       }
-
-       g = alloc_disk(1 << PARTN_BITS);
-       if (!g)
-               goto out_free_cd;
-
-       ide_init_disk(g, drive);
-
-       info->dev.parent = &drive->gendev;
-       info->dev.release = ide_cd_release;
-       dev_set_name(&info->dev, "%s", dev_name(&drive->gendev));
-
-       if (device_register(&info->dev))
-               goto out_free_disk;
-
-       info->drive = drive;
-       info->driver = &ide_cdrom_driver;
-       info->disk = g;
-
-       g->private_data = &info->driver;
-
-       drive->driver_data = info;
-
-       g->minors = 1;
-       g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
-       if (ide_cdrom_setup(drive)) {
-               put_device(&info->dev);
-               goto failed;
-       }
-
-       ide_cd_read_toc(drive);
-       g->fops = &idecd_ops;
-       g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-       g->events = DISK_EVENT_MEDIA_CHANGE;
-       device_add_disk(&drive->gendev, g, NULL);
-       return 0;
-
-out_free_disk:
-       put_disk(g);
-out_free_cd:
-       kfree(info);
-failed:
-       return -ENODEV;
-}
-
-static void __exit ide_cdrom_exit(void)
-{
-       driver_unregister(&ide_cdrom_driver.gen_driver);
-}
-
-static int __init ide_cdrom_init(void)
-{
-       printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
-       return driver_register(&ide_cdrom_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-cdrom*");
-MODULE_ALIAS("ide-cd");
-module_init(ide_cdrom_init);
-module_exit(ide_cdrom_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
deleted file mode 100644 (file)
index a69dc7f..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  Copyright (C) 1996-98  Erik Andersen
- *  Copyright (C) 1998-2000 Jens Axboe
- */
-#ifndef _IDE_CD_H
-#define _IDE_CD_H
-
-#include <linux/cdrom.h>
-#include <asm/byteorder.h>
-
-#define IDECD_DEBUG_LOG                0
-
-#if IDECD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-#define ATAPI_WAIT_WRITE_BUSY  (10 * HZ)
-
-/************************************************************************/
-
-#define SECTORS_PER_FRAME      (CD_FRAMESIZE >> SECTOR_SHIFT)
-#define SECTOR_BUFFER_SIZE     (CD_FRAMESIZE * 32)
-
-/* Capabilities Page size including 8 bytes of Mode Page Header */
-#define ATAPI_CAPABILITIES_PAGE_SIZE           (8 + 20)
-#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE       4
-
-/* Structure of a MSF cdrom address. */
-struct atapi_msf {
-       u8 reserved;
-       u8 minute;
-       u8 second;
-       u8 frame;
-};
-
-/* Space to hold the disk TOC. */
-#define MAX_TRACKS 99
-struct atapi_toc_header {
-       unsigned short toc_length;
-       u8 first_track;
-       u8 last_track;
-};
-
-struct atapi_toc_entry {
-       u8 reserved1;
-#if defined(__BIG_ENDIAN_BITFIELD)
-       u8 adr     : 4;
-       u8 control : 4;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       u8 control : 4;
-       u8 adr     : 4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       u8 track;
-       u8 reserved2;
-       union {
-               unsigned lba;
-               struct atapi_msf msf;
-       } addr;
-};
-
-struct atapi_toc {
-       int    last_session_lba;
-       int    xa_flag;
-       unsigned long capacity;
-       struct atapi_toc_header hdr;
-       struct atapi_toc_entry  ent[MAX_TRACKS+1];
-         /* One extra for the leadout. */
-};
-
-/* Extra per-device info for cdrom drives. */
-struct cdrom_info {
-       ide_drive_t             *drive;
-       struct ide_driver       *driver;
-       struct gendisk          *disk;
-       struct device           dev;
-
-       /* Buffer for table of contents.  NULL if we haven't allocated
-          a TOC buffer for this device yet. */
-
-       struct atapi_toc *toc;
-
-       u8 max_speed;           /* Max speed of the drive. */
-       u8 current_speed;       /* Current speed of the drive. */
-
-        /* Per-device info needed by cdrom.c generic driver. */
-        struct cdrom_device_info devinfo;
-
-       unsigned long write_timeout;
-};
-
-/* ide-cd_verbose.c */
-void ide_cd_log_error(const char *, struct request *, struct request_sense *);
-
-/* ide-cd.c functions used by ide-cd_ioctl.c */
-int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *,
-                   unsigned *, struct scsi_sense_hdr *, int, req_flags_t);
-int ide_cd_read_toc(ide_drive_t *);
-int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
-void ide_cdrom_update_speed(ide_drive_t *, u8 *);
-int cdrom_check_status(ide_drive_t *, struct scsi_sense_hdr *);
-
-/* ide-cd_ioctl.c */
-int ide_cdrom_open_real(struct cdrom_device_info *, int);
-void ide_cdrom_release_real(struct cdrom_device_info *);
-int ide_cdrom_drive_status(struct cdrom_device_info *, int);
-unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *,
-                                        unsigned int clearing, int slot_nr);
-int ide_cdrom_tray_move(struct cdrom_device_info *, int);
-int ide_cdrom_lock_door(struct cdrom_device_info *, int);
-int ide_cdrom_select_speed(struct cdrom_device_info *, int);
-int ide_cdrom_get_last_session(struct cdrom_device_info *,
-                              struct cdrom_multisession *);
-int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
-int ide_cdrom_reset(struct cdrom_device_info *cdi);
-int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
-int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *);
-
-#endif /* _IDE_CD_H */
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
deleted file mode 100644 (file)
index 011eab9..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * cdrom.c IOCTLs handling for ide-cd driver.
- *
- * Copyright (C) 1994-1996  Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-#include <scsi/scsi.h>
-
-#include "ide-cd.h"
-
-/****************************************************************************
- * Other driver requests (open, close, check media change).
- */
-int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
-{
-       return 0;
-}
-
-/*
- * Close down the device.  Invalidate all cached blocks.
- */
-void ide_cdrom_release_real(struct cdrom_device_info *cdi)
-{
-       ide_drive_t *drive = cdi->handle;
-
-       if (!cdi->use_count)
-               drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
-}
-
-/*
- * add logic to try GET_EVENT command first to check for media and tray
- * status. this should be supported by newer cd-r/w and all DVD etc
- * drives
- */
-int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct media_event_desc med;
-       struct scsi_sense_hdr sshdr;
-       int stat;
-
-       if (slot_nr != CDSL_CURRENT)
-               return -EINVAL;
-
-       stat = cdrom_check_status(drive, &sshdr);
-       if (!stat || sshdr.sense_key == UNIT_ATTENTION)
-               return CDS_DISC_OK;
-
-       if (!cdrom_get_media_event(cdi, &med)) {
-               if (med.media_present)
-                       return CDS_DISC_OK;
-               else if (med.door_open)
-                       return CDS_TRAY_OPEN;
-               else
-                       return CDS_NO_DISC;
-       }
-
-       if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04
-                       && sshdr.ascq == 0x04)
-               return CDS_DISC_OK;
-
-       /*
-        * If not using Mt Fuji extended media tray reports,
-        * just return TRAY_OPEN since ATAPI doesn't provide
-        * any other way to detect this...
-        */
-       if (sshdr.sense_key == NOT_READY) {
-               if (sshdr.asc == 0x3a && sshdr.ascq == 1)
-                       return CDS_NO_DISC;
-               else
-                       return CDS_TRAY_OPEN;
-       }
-       return CDS_DRIVE_NOT_READY;
-}
-
-/*
- * ide-cd always generates media changed event if media is missing, which
- * makes it impossible to use for proper event reporting, so
- * DISK_EVENT_FLAG_UEVENT is cleared in disk->event_flags
- * and the following function is used only to trigger
- * revalidation and never propagated to userland.
- */
-unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi,
-                                        unsigned int clearing, int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       int retval;
-
-       if (slot_nr == CDSL_CURRENT) {
-               (void) cdrom_check_status(drive, NULL);
-               retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0;
-               drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
-               return retval ? DISK_EVENT_MEDIA_CHANGE : 0;
-       } else {
-               return 0;
-       }
-}
-
-/* Eject the disk if EJECTFLAG is 0.
-   If EJECTFLAG is 1, try to reload the disk. */
-static
-int cdrom_eject(ide_drive_t *drive, int ejectflag)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct cdrom_device_info *cdi = &cd->devinfo;
-       char loej = 0x02;
-       unsigned char cmd[BLK_MAX_CDB];
-
-       if ((drive->atapi_flags & IDE_AFLAG_NO_EJECT) && !ejectflag)
-               return -EDRIVE_CANT_DO_THIS;
-
-       /* reload fails on some drives, if the tray is locked */
-       if ((drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) && ejectflag)
-               return 0;
-
-       /* only tell drive to close tray if open, if it can do that */
-       if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
-               loej = 0;
-
-       memset(cmd, 0, BLK_MAX_CDB);
-
-       cmd[0] = GPCMD_START_STOP_UNIT;
-       cmd[4] = loej | (ejectflag != 0);
-
-       return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-}
-
-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
-static
-int ide_cd_lockdoor(ide_drive_t *drive, int lockflag)
-{
-       struct scsi_sense_hdr sshdr;
-       int stat;
-
-       /* If the drive cannot lock the door, just pretend. */
-       if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) {
-               stat = 0;
-       } else {
-               unsigned char cmd[BLK_MAX_CDB];
-
-               memset(cmd, 0, BLK_MAX_CDB);
-
-               cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-               cmd[4] = lockflag ? 1 : 0;
-
-               stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL,
-                                      &sshdr, 0, 0);
-       }
-
-       /* If we got an illegal field error, the drive
-          probably cannot lock the door. */
-       if (stat != 0 &&
-           sshdr.sense_key == ILLEGAL_REQUEST &&
-           (sshdr.asc == 0x24 || sshdr.asc == 0x20)) {
-               printk(KERN_ERR "%s: door locking not supported\n",
-                       drive->name);
-               drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-               stat = 0;
-       }
-
-       /* no medium, that's alright. */
-       if (stat != 0 && sshdr.sense_key == NOT_READY && sshdr.asc == 0x3a)
-               stat = 0;
-
-       if (stat == 0) {
-               if (lockflag)
-                       drive->atapi_flags |= IDE_AFLAG_DOOR_LOCKED;
-               else
-                       drive->atapi_flags &= ~IDE_AFLAG_DOOR_LOCKED;
-       }
-
-       return stat;
-}
-
-int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       ide_drive_t *drive = cdi->handle;
-
-       if (position) {
-               int stat = ide_cd_lockdoor(drive, 0);
-
-               if (stat)
-                       return stat;
-       }
-
-       return cdrom_eject(drive, !position);
-}
-
-int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
-{
-       ide_drive_t *drive = cdi->handle;
-
-       return ide_cd_lockdoor(drive, lock);
-}
-
-/*
- * ATAPI devices are free to select the speed you request or any slower
- * rate. :-(  Requesting too fast a speed will _not_ produce an error.
- */
-int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *cd = drive->driver_data;
-       u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
-       int stat;
-       unsigned char cmd[BLK_MAX_CDB];
-
-       if (speed == 0)
-               speed = 0xffff; /* set to max */
-       else
-               speed *= 177;   /* Nx to kbytes/s */
-
-       memset(cmd, 0, BLK_MAX_CDB);
-
-       cmd[0] = GPCMD_SET_SPEED;
-       /* Read Drive speed in kbytes/second MSB/LSB */
-       cmd[2] = (speed >> 8) & 0xff;
-       cmd[3] = speed & 0xff;
-       if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
-           (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
-               /* Write Drive speed in kbytes/second MSB/LSB */
-               cmd[4] = (speed >> 8) & 0xff;
-               cmd[5] = speed & 0xff;
-       }
-
-       stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-
-       if (!ide_cdrom_get_capabilities(drive, buf)) {
-               ide_cdrom_update_speed(drive, buf);
-               cdi->speed = cd->current_speed;
-       }
-
-       return 0;
-}
-
-int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
-                              struct cdrom_multisession *ms_info)
-{
-       struct atapi_toc *toc;
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *info = drive->driver_data;
-       int ret;
-
-       if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0 || !info->toc) {
-               ret = ide_cd_read_toc(drive);
-               if (ret)
-                       return ret;
-       }
-
-       toc = info->toc;
-       ms_info->addr.lba = toc->last_session_lba;
-       ms_info->xa_flag = toc->xa_flag;
-
-       return 0;
-}
-
-int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
-                     struct cdrom_mcn *mcn_info)
-{
-       ide_drive_t *drive = cdi->handle;
-       int stat, mcnlen;
-       char buf[24];
-       unsigned char cmd[BLK_MAX_CDB];
-       unsigned len = sizeof(buf);
-
-       memset(cmd, 0, BLK_MAX_CDB);
-
-       cmd[0] = GPCMD_READ_SUBCHANNEL;
-       cmd[1] = 2;             /* MSF addressing */
-       cmd[2] = 0x40;  /* request subQ data */
-       cmd[3] = 2;             /* format */
-       cmd[8] = len;
-
-       stat = ide_cd_queue_pc(drive, cmd, 0, buf, &len, NULL, 0, 0);
-       if (stat)
-               return stat;
-
-       mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
-       memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
-       mcn_info->medium_catalog_number[mcnlen] = '\0';
-
-       return 0;
-}
-
-int ide_cdrom_reset(struct cdrom_device_info *cdi)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *cd = drive->driver_data;
-       struct request *rq;
-       int ret;
-
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       rq->rq_flags = RQF_QUIET;
-       blk_execute_rq(cd->disk, rq, 0);
-       ret = scsi_req(rq)->result ? -EIO : 0;
-       blk_put_request(rq);
-       /*
-        * A reset will unlock the door. If it was previously locked,
-        * lock it again.
-        */
-       if (drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED)
-               (void)ide_cd_lockdoor(drive, 1);
-
-       return ret;
-}
-
-static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
-                               struct atapi_toc_entry **ent)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct atapi_toc *toc = info->toc;
-       int ntracks;
-
-       /*
-        * don't serve cached data, if the toc isn't valid
-        */
-       if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0)
-               return -EINVAL;
-
-       /* Check validity of requested track number. */
-       ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
-
-       if (toc->hdr.first_track == CDROM_LEADOUT)
-               ntracks = 0;
-
-       if (track == CDROM_LEADOUT)
-               *ent = &toc->ent[ntracks];
-       else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
-               return -EINVAL;
-       else
-               *ent = &toc->ent[track - toc->hdr.first_track];
-
-       return 0;
-}
-
-static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
-{
-       struct cdrom_ti *ti = arg;
-       struct atapi_toc_entry *first_toc, *last_toc;
-       unsigned long lba_start, lba_end;
-       int stat;
-       unsigned char cmd[BLK_MAX_CDB];
-
-       stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
-       if (stat)
-               return stat;
-
-       stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
-       if (stat)
-               return stat;
-
-       if (ti->cdti_trk1 != CDROM_LEADOUT)
-               ++last_toc;
-       lba_start = first_toc->addr.lba;
-       lba_end   = last_toc->addr.lba;
-
-       if (lba_end <= lba_start)
-               return -EINVAL;
-
-       memset(cmd, 0, BLK_MAX_CDB);
-
-       cmd[0] = GPCMD_PLAY_AUDIO_MSF;
-       lba_to_msf(lba_start,   &cmd[3], &cmd[4], &cmd[5]);
-       lba_to_msf(lba_end - 1, &cmd[6], &cmd[7], &cmd[8]);
-
-       return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-}
-
-static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
-{
-       struct cdrom_info *cd = drive->driver_data;
-       struct cdrom_tochdr *tochdr = arg;
-       struct atapi_toc *toc;
-       int stat;
-
-       /* Make sure our saved TOC is valid. */
-       stat = ide_cd_read_toc(drive);
-       if (stat)
-               return stat;
-
-       toc = cd->toc;
-       tochdr->cdth_trk0 = toc->hdr.first_track;
-       tochdr->cdth_trk1 = toc->hdr.last_track;
-
-       return 0;
-}
-
-static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
-{
-       struct cdrom_tocentry *tocentry = arg;
-       struct atapi_toc_entry *toce;
-       int stat;
-
-       stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
-       if (stat)
-               return stat;
-
-       tocentry->cdte_ctrl = toce->control;
-       tocentry->cdte_adr  = toce->adr;
-       if (tocentry->cdte_format == CDROM_MSF) {
-               lba_to_msf(toce->addr.lba,
-                          &tocentry->cdte_addr.msf.minute,
-                          &tocentry->cdte_addr.msf.second,
-                          &tocentry->cdte_addr.msf.frame);
-       } else
-               tocentry->cdte_addr.lba = toce->addr.lba;
-
-       return 0;
-}
-
-int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
-                         unsigned int cmd, void *arg)
-{
-       ide_drive_t *drive = cdi->handle;
-
-       switch (cmd) {
-       /*
-        * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
-        * atapi doesn't support it
-        */
-       case CDROMPLAYTRKIND:
-               return ide_cd_fake_play_trkind(drive, arg);
-       case CDROMREADTOCHDR:
-               return ide_cd_read_tochdr(drive, arg);
-       case CDROMREADTOCENTRY:
-               return ide_cd_read_tocentry(drive, arg);
-       default:
-               return -EINVAL;
-       }
-}
-
-/* the generic packet interface to cdrom.c */
-int ide_cdrom_packet(struct cdrom_device_info *cdi,
-                           struct packet_command *cgc)
-{
-       ide_drive_t *drive = cdi->handle;
-       req_flags_t flags = 0;
-       unsigned len = cgc->buflen;
-
-       if (cgc->timeout <= 0)
-               cgc->timeout = ATAPI_WAIT_PC;
-
-       /* here we queue the commands from the uniform CD-ROM
-          layer. the packet must be complete, as we do not
-          touch it at all. */
-
-       if (cgc->sshdr)
-               memset(cgc->sshdr, 0, sizeof(*cgc->sshdr));
-
-       if (cgc->quiet)
-               flags |= RQF_QUIET;
-
-       cgc->stat = ide_cd_queue_pc(drive, cgc->cmd,
-                                   cgc->data_direction == CGC_DATA_WRITE,
-                                   cgc->buffer, &len,
-                                   cgc->sshdr, cgc->timeout, flags);
-       if (!cgc->stat)
-               cgc->buflen -= len;
-       return cgc->stat;
-}
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
deleted file mode 100644 (file)
index 5ecd5b2..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Verbose error logging for ATAPI CD/DVD devices.
- *
- * Copyright (C) 1994-1996  Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <scsi/scsi.h>
-#include "ide-cd.h"
-
-#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
-void ide_cd_log_error(const char *name, struct request *failed_command,
-                     struct request_sense *sense)
-{
-       /* Suppress printing unit attention and `in progress of becoming ready'
-          errors when we're not being verbose. */
-       if (sense->sense_key == UNIT_ATTENTION ||
-           (sense->sense_key == NOT_READY && (sense->asc == 4 ||
-                                               sense->asc == 0x3a)))
-               return;
-
-       printk(KERN_ERR "%s: error code: 0x%02x  sense_key: 0x%02x  "
-                       "asc: 0x%02x  ascq: 0x%02x\n",
-                       name, sense->error_code, sense->sense_key,
-                       sense->asc, sense->ascq);
-}
-#else
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const struct {
-       unsigned short packet_command;
-       const char * const text;
-} packet_command_texts[] = {
-       { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
-       { GPCMD_REQUEST_SENSE, "Request Sense" },
-       { GPCMD_FORMAT_UNIT, "Format Unit" },
-       { GPCMD_INQUIRY, "Inquiry" },
-       { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
-       { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
-       { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
-       { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
-       { GPCMD_READ_10, "Read 10" },
-       { GPCMD_WRITE_10, "Write 10" },
-       { GPCMD_SEEK, "Seek" },
-       { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
-       { GPCMD_VERIFY_10, "Verify 10" },
-       { GPCMD_FLUSH_CACHE, "Flush Cache" },
-       { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
-       { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
-       { GPCMD_READ_HEADER, "Read Header" },
-       { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
-       { GPCMD_GET_CONFIGURATION, "Get Configuration" },
-       { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
-       { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
-       { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
-               "Get Event Status Notification" },
-       { GPCMD_PAUSE_RESUME, "Pause/Resume" },
-       { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
-       { GPCMD_READ_DISC_INFO, "Read Disc Info" },
-       { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
-       { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
-       { GPCMD_SEND_OPC, "Send OPC" },
-       { GPCMD_MODE_SELECT_10, "Mode Select 10" },
-       { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
-       { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
-       { GPCMD_CLOSE_TRACK, "Close Track" },
-       { GPCMD_BLANK, "Blank" },
-       { GPCMD_SEND_EVENT, "Send Event" },
-       { GPCMD_SEND_KEY, "Send Key" },
-       { GPCMD_REPORT_KEY, "Report Key" },
-       { GPCMD_LOAD_UNLOAD, "Load/Unload" },
-       { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
-       { GPCMD_READ_12, "Read 12" },
-       { GPCMD_GET_PERFORMANCE, "Get Performance" },
-       { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
-       { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
-       { GPCMD_SET_STREAMING, "Set Streaming" },
-       { GPCMD_READ_CD_MSF, "Read CD MSF" },
-       { GPCMD_SCAN, "Scan" },
-       { GPCMD_SET_SPEED, "Set Speed" },
-       { GPCMD_PLAY_CD, "Play CD" },
-       { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
-       { GPCMD_READ_CD, "Read CD" },
-};
-
-/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const char * const sense_key_texts[16] = {
-       "No sense data",
-       "Recovered error",
-       "Not ready",
-       "Medium error",
-       "Hardware error",
-       "Illegal request",
-       "Unit attention",
-       "Data protect",
-       "Blank check",
-       "(reserved)",
-       "(reserved)",
-       "Aborted command",
-       "(reserved)",
-       "(reserved)",
-       "Miscompare",
-       "(reserved)",
-};
-
-/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const struct {
-       unsigned long asc_ascq;
-       const char * const text;
-} sense_data_texts[] = {
-       { 0x000000, "No additional sense information" },
-       { 0x000011, "Play operation in progress" },
-       { 0x000012, "Play operation paused" },
-       { 0x000013, "Play operation successfully completed" },
-       { 0x000014, "Play operation stopped due to error" },
-       { 0x000015, "No current audio status to return" },
-       { 0x010c0a, "Write error - padding blocks added" },
-       { 0x011700, "Recovered data with no error correction applied" },
-       { 0x011701, "Recovered data with retries" },
-       { 0x011702, "Recovered data with positive head offset" },
-       { 0x011703, "Recovered data with negative head offset" },
-       { 0x011704, "Recovered data with retries and/or CIRC applied" },
-       { 0x011705, "Recovered data using previous sector ID" },
-       { 0x011800, "Recovered data with error correction applied" },
-       { 0x011801, "Recovered data with error correction and retries applied"},
-       { 0x011802, "Recovered data - the data was auto-reallocated" },
-       { 0x011803, "Recovered data with CIRC" },
-       { 0x011804, "Recovered data with L-EC" },
-       { 0x015d00, "Failure prediction threshold exceeded"
-                   " - Predicted logical unit failure" },
-       { 0x015d01, "Failure prediction threshold exceeded"
-                   " - Predicted media failure" },
-       { 0x015dff, "Failure prediction threshold exceeded - False" },
-       { 0x017301, "Power calibration area almost full" },
-       { 0x020400, "Logical unit not ready - cause not reportable" },
-       /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
-       { 0x020401, "Logical unit not ready"
-                   " - in progress [sic] of becoming ready" },
-       { 0x020402, "Logical unit not ready - initializing command required" },
-       { 0x020403, "Logical unit not ready - manual intervention required" },
-       { 0x020404, "Logical unit not ready - format in progress" },
-       { 0x020407, "Logical unit not ready - operation in progress" },
-       { 0x020408, "Logical unit not ready - long write in progress" },
-       { 0x020600, "No reference position found (media may be upside down)" },
-       { 0x023000, "Incompatible medium installed" },
-       { 0x023a00, "Medium not present" },
-       { 0x025300, "Media load or eject failed" },
-       { 0x025700, "Unable to recover table of contents" },
-       { 0x030300, "Peripheral device write fault" },
-       { 0x030301, "No write current" },
-       { 0x030302, "Excessive write errors" },
-       { 0x030c00, "Write error" },
-       { 0x030c01, "Write error - Recovered with auto reallocation" },
-       { 0x030c02, "Write error - auto reallocation failed" },
-       { 0x030c03, "Write error - recommend reassignment" },
-       { 0x030c04, "Compression check miscompare error" },
-       { 0x030c05, "Data expansion occurred during compress" },
-       { 0x030c06, "Block not compressible" },
-       { 0x030c07, "Write error - recovery needed" },
-       { 0x030c08, "Write error - recovery failed" },
-       { 0x030c09, "Write error - loss of streaming" },
-       { 0x031100, "Unrecovered read error" },
-       { 0x031106, "CIRC unrecovered error" },
-       { 0x033101, "Format command failed" },
-       { 0x033200, "No defect spare location available" },
-       { 0x033201, "Defect list update failure" },
-       { 0x035100, "Erase failure" },
-       { 0x037200, "Session fixation error" },
-       { 0x037201, "Session fixation error writin lead-in" },
-       { 0x037202, "Session fixation error writin lead-out" },
-       { 0x037300, "CD control error" },
-       { 0x037302, "Power calibration area is full" },
-       { 0x037303, "Power calibration area error" },
-       { 0x037304, "Program memory area / RMA update failure" },
-       { 0x037305, "Program memory area / RMA is full" },
-       { 0x037306, "Program memory area / RMA is (almost) full" },
-       { 0x040200, "No seek complete" },
-       { 0x040300, "Write fault" },
-       { 0x040900, "Track following error" },
-       { 0x040901, "Tracking servo failure" },
-       { 0x040902, "Focus servo failure" },
-       { 0x040903, "Spindle servo failure" },
-       { 0x041500, "Random positioning error" },
-       { 0x041501, "Mechanical positioning or changer error" },
-       { 0x041502, "Positioning error detected by read of medium" },
-       { 0x043c00, "Mechanical positioning or changer error" },
-       { 0x044000, "Diagnostic failure on component (ASCQ)" },
-       { 0x044400, "Internal CD/DVD logical unit failure" },
-       { 0x04b600, "Media load mechanism failed" },
-       { 0x051a00, "Parameter list length error" },
-       { 0x052000, "Invalid command operation code" },
-       { 0x052100, "Logical block address out of range" },
-       { 0x052102, "Invalid address for write" },
-       { 0x052400, "Invalid field in command packet" },
-       { 0x052600, "Invalid field in parameter list" },
-       { 0x052601, "Parameter not supported" },
-       { 0x052602, "Parameter value invalid" },
-       { 0x052700, "Write protected media" },
-       { 0x052c00, "Command sequence error" },
-       { 0x052c03, "Current program area is not empty" },
-       { 0x052c04, "Current program area is empty" },
-       { 0x053001, "Cannot read medium - unknown format" },
-       { 0x053002, "Cannot read medium - incompatible format" },
-       { 0x053900, "Saving parameters not supported" },
-       { 0x054e00, "Overlapped commands attempted" },
-       { 0x055302, "Medium removal prevented" },
-       { 0x055500, "System resource failure" },
-       { 0x056300, "End of user area encountered on this track" },
-       { 0x056400, "Illegal mode for this track or incompatible medium" },
-       { 0x056f00, "Copy protection key exchange failure"
-                   " - Authentication failure" },
-       { 0x056f01, "Copy protection key exchange failure - Key not present" },
-       { 0x056f02, "Copy protection key exchange failure"
-                    " - Key not established" },
-       { 0x056f03, "Read of scrambled sector without authentication" },
-       { 0x056f04, "Media region code is mismatched to logical unit" },
-       { 0x056f05, "Drive region must be permanent"
-                   " / region reset count error" },
-       { 0x057203, "Session fixation error - incomplete track in session" },
-       { 0x057204, "Empty or partially written reserved track" },
-       { 0x057205, "No more RZONE reservations are allowed" },
-       { 0x05bf00, "Loss of streaming" },
-       { 0x062800, "Not ready to ready transition, medium may have changed" },
-       { 0x062900, "Power on, reset or hardware reset occurred" },
-       { 0x062a00, "Parameters changed" },
-       { 0x062a01, "Mode parameters changed" },
-       { 0x062e00, "Insufficient time for operation" },
-       { 0x063f00, "Logical unit operating conditions have changed" },
-       { 0x063f01, "Microcode has been changed" },
-       { 0x065a00, "Operator request or state change input (unspecified)" },
-       { 0x065a01, "Operator medium removal request" },
-       { 0x0bb900, "Play operation aborted" },
-       /* Here we use 0xff for the key (not a valid key) to signify
-        * that these can have _any_ key value associated with them... */
-       { 0xff0401, "Logical unit is in process of becoming ready" },
-       { 0xff0400, "Logical unit not ready, cause not reportable" },
-       { 0xff0402, "Logical unit not ready, initializing command required" },
-       { 0xff0403, "Logical unit not ready, manual intervention required" },
-       { 0xff0500, "Logical unit does not respond to selection" },
-       { 0xff0800, "Logical unit communication failure" },
-       { 0xff0802, "Logical unit communication parity error" },
-       { 0xff0801, "Logical unit communication time-out" },
-       { 0xff2500, "Logical unit not supported" },
-       { 0xff4c00, "Logical unit failed self-configuration" },
-       { 0xff3e00, "Logical unit has not self-configured yet" },
-};
-
-void ide_cd_log_error(const char *name, struct request *failed_command,
-                     struct request_sense *sense)
-{
-       int i;
-       const char *s = "bad sense key!";
-       char buf[80];
-
-       printk(KERN_ERR "ATAPI device %s:\n", name);
-       if (sense->error_code == 0x70)
-               printk(KERN_CONT "  Error: ");
-       else if (sense->error_code == 0x71)
-               printk("  Deferred Error: ");
-       else if (sense->error_code == 0x7f)
-               printk(KERN_CONT "  Vendor-specific Error: ");
-       else
-               printk(KERN_CONT "  Unknown Error Type: ");
-
-       if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
-               s = sense_key_texts[sense->sense_key];
-
-       printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
-
-       if (sense->asc == 0x40) {
-               sprintf(buf, "Diagnostic failure on component 0x%02x",
-                       sense->ascq);
-               s = buf;
-       } else {
-               int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
-               unsigned long key = (sense->sense_key << 16);
-
-               key |= (sense->asc << 8);
-               if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
-                       key |= sense->ascq;
-               s = NULL;
-
-               while (hi > lo) {
-                       mid = (lo + hi) / 2;
-                       if (sense_data_texts[mid].asc_ascq == key ||
-                           sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
-                               s = sense_data_texts[mid].text;
-                               break;
-                       } else if (sense_data_texts[mid].asc_ascq > key)
-                               hi = mid;
-                       else
-                               lo = mid + 1;
-               }
-       }
-
-       if (s == NULL) {
-               if (sense->asc > 0x80)
-                       s = "(vendor-specific error)";
-               else
-                       s = "(reserved error code)";
-       }
-
-       printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
-                       s, sense->asc, sense->ascq);
-
-       if (failed_command != NULL) {
-               int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts);
-               s = NULL;
-
-               while (hi > lo) {
-                       mid = (lo + hi) / 2;
-                       if (packet_command_texts[mid].packet_command ==
-                           scsi_req(failed_command)->cmd[0]) {
-                               s = packet_command_texts[mid].text;
-                               break;
-                       }
-                       if (packet_command_texts[mid].packet_command >
-                           scsi_req(failed_command)->cmd[0])
-                               hi = mid;
-                       else
-                               lo = mid + 1;
-               }
-
-               printk(KERN_ERR "  The failed \"%s\" packet command "
-                               "was: \n  \"", s);
-               for (i = 0; i < BLK_MAX_CDB; i++)
-                       printk(KERN_CONT "%02x ", scsi_req(failed_command)->cmd[i]);
-               printk(KERN_CONT "\"\n");
-       }
-
-       /* The SKSV bit specifies validity of the sense_key_specific
-        * in the next two commands. It is bit 7 of the first byte.
-        * In the case of NOT_READY, if SKSV is set the drive can
-        * give us nice ETA readings.
-        */
-       if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
-               int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
-
-               printk(KERN_ERR "  Command is %02d%% complete\n",
-                               progress / 0xffff);
-       }
-
-       if (sense->sense_key == ILLEGAL_REQUEST &&
-           (sense->sks[0] & 0x80) != 0) {
-               printk(KERN_ERR "  Error in %s byte %d",
-                               (sense->sks[0] & 0x40) != 0 ?
-                               "command packet" : "command data",
-                               (sense->sks[1] << 8) + sense->sks[2]);
-
-               if ((sense->sks[0] & 0x40) != 0)
-                       printk(KERN_CONT " bit %d", sense->sks[0] & 0x07);
-
-               printk(KERN_CONT "\n");
-       }
-}
-#endif
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
deleted file mode 100644 (file)
index f1e922e..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA IDE/ATA disk cards
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in
-    which case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/major.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-
-#define DRV_NAME "ide-cs"
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/*====================================================================*/
-
-typedef struct ide_info_t {
-       struct pcmcia_device    *p_dev;
-       struct ide_host         *host;
-       int                     ndev;
-} ide_info_t;
-
-static void ide_release(struct pcmcia_device *);
-static int ide_config(struct pcmcia_device *);
-
-static void ide_detach(struct pcmcia_device *p_dev);
-
-static int ide_probe(struct pcmcia_device *link)
-{
-    ide_info_t *info;
-
-    dev_dbg(&link->dev, "ide_attach()\n");
-
-    /* Create new ide device */
-    info = kzalloc(sizeof(*info), GFP_KERNEL);
-    if (!info)
-       return -ENOMEM;
-
-    info->p_dev = link;
-    link->priv = info;
-
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
-           CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
-
-    return ide_config(link);
-} /* ide_attach */
-
-static void ide_detach(struct pcmcia_device *link)
-{
-    ide_info_t *info = link->priv;
-
-    dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
-
-    ide_release(link);
-
-    kfree(info);
-} /* ide_detach */
-
-static const struct ide_port_ops idecs_port_ops = {
-       .quirkproc              = ide_undecoded_slave,
-};
-
-static const struct ide_port_info idecs_port_info = {
-       .port_ops               = &idecs_port_ops,
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_pci,
-};
-
-static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
-                               unsigned long irq, struct pcmcia_device *handle)
-{
-    struct ide_host *host;
-    ide_hwif_t *hwif;
-    int i, rc;
-    struct ide_hw hw, *hws[] = { &hw };
-
-    if (!request_region(io, 8, DRV_NAME)) {
-       printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                       DRV_NAME, io, io + 7);
-       return NULL;
-    }
-
-    if (!request_region(ctl, 1, DRV_NAME)) {
-       printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                       DRV_NAME, ctl);
-       release_region(io, 8);
-       return NULL;
-    }
-
-    memset(&hw, 0, sizeof(hw));
-    ide_std_init_ports(&hw, io, ctl);
-    hw.irq = irq;
-    hw.dev = &handle->dev;
-
-    rc = ide_host_add(&idecs_port_info, hws, 1, &host);
-    if (rc)
-       goto out_release;
-
-    hwif = host->ports[0];
-
-    if (hwif->present)
-       return host;
-
-    /* retry registration in case device is still spinning up */
-    for (i = 0; i < 10; i++) {
-       msleep(100);
-       ide_port_scan(hwif);
-       if (hwif->present)
-           return host;
-    }
-
-    return host;
-
-out_release:
-    release_region(ctl, 1);
-    release_region(io, 8);
-    return NULL;
-}
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
-{
-       int *is_kme = priv_data;
-
-       if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH)
-           != IO_DATA_PATH_WIDTH_8) {
-               pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       }
-       pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-       pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-
-       if (pdev->resource[1]->end) {
-               pdev->resource[0]->end = 8;
-               pdev->resource[1]->end = (*is_kme) ? 2 : 1;
-       } else {
-               if (pdev->resource[0]->end < 16)
-                       return -ENODEV;
-       }
-
-       return pcmcia_request_io(pdev);
-}
-
-static int ide_config(struct pcmcia_device *link)
-{
-    ide_info_t *info = link->priv;
-    int ret = 0, is_kme = 0;
-    unsigned long io_base, ctl_base;
-    struct ide_host *host;
-
-    dev_dbg(&link->dev, "ide_config(0x%p)\n", link);
-
-    is_kme = ((link->manf_id == MANFID_KME) &&
-             ((link->card_id == PRODID_KME_KXLC005_A) ||
-              (link->card_id == PRODID_KME_KXLC005_B)));
-
-    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
-           link->config_flags &= ~CONF_AUTO_CHECK_VCC;
-           if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
-                   goto failed; /* No suitable config found */
-    }
-    io_base = link->resource[0]->start;
-    if (link->resource[1]->end)
-           ctl_base = link->resource[1]->start;
-    else
-           ctl_base = link->resource[0]->start + 0x0e;
-
-    if (!link->irq)
-           goto failed;
-
-    ret = pcmcia_enable_device(link);
-    if (ret)
-           goto failed;
-
-    /* disable drive interrupts during IDE probe */
-    outb(0x02, ctl_base);
-
-    /* special setup for KXLC005 card */
-    if (is_kme)
-       outb(0x81, ctl_base+1);
-
-     host = idecs_register(io_base, ctl_base, link->irq, link);
-     if (host == NULL && resource_size(link->resource[0]) == 0x20) {
-           outb(0x02, ctl_base + 0x10);
-           host = idecs_register(io_base + 0x10, ctl_base + 0x10,
-                                 link->irq, link);
-    }
-
-    if (host == NULL)
-       goto failed;
-
-    info->ndev = 1;
-    info->host = host;
-    dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
-           'a' + host->ports[0]->index * 2,
-           link->vpp / 10, link->vpp % 10);
-
-    return 0;
-
-failed:
-    ide_release(link);
-    return -ENODEV;
-} /* ide_config */
-
-static void ide_release(struct pcmcia_device *link)
-{
-    ide_info_t *info = link->priv;
-    struct ide_host *host = info->host;
-
-    dev_dbg(&link->dev, "ide_release(0x%p)\n", link);
-
-    if (info->ndev) {
-       ide_hwif_t *hwif = host->ports[0];
-       unsigned long data_addr, ctl_addr;
-
-       data_addr = hwif->io_ports.data_addr;
-       ctl_addr = hwif->io_ports.ctl_addr;
-
-       ide_host_remove(host);
-       info->ndev = 0;
-
-       release_region(ctl_addr, 1);
-       release_region(data_addr, 8);
-    }
-
-    pcmcia_disable_device(link);
-} /* ide_release */
-
-
-static const struct pcmcia_device_id ide_ids[] = {
-       PCMCIA_DEVICE_FUNC_ID(4),
-       PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
-       PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
-       PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
-       PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
-       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
-       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
-       PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
-       PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),        /* Kingston */
-       PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620),        /* TI emulated */
-       PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
-       PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
-       PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),        /* Samsung */
-       PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000),        /* Hitachi */
-       PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
-       PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100),        /* Viking CFA */
-       PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200),        /* Lexar, Viking CFA */
-       PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
-       PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
-       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
-       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
-       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
-       PCMCIA_DEVICE_PROD_ID12("CNF   ", "CD-ROM", 0x46d7db81, 0x66536591),
-       PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
-       PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
-       PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
-       PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
-       PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
-       PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
-       PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
-       PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
-       PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
-       PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
-       PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
-       PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
-       PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
-       PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
-       PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
-       PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
-       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
-       PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
-       PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
-       PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
-       PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
-       PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
-       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
-       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
-       PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
-       PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
-       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
-       PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
-       PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
-       PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
-       PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
-       PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
-       PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
-       PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
-       PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
-       PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
-       PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, ide_ids);
-
-static struct pcmcia_driver ide_cs_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "ide-cs",
-       .probe          = ide_probe,
-       .remove         = ide_detach,
-       .id_table       = ide_ids,
-};
-
-static int __init init_ide_cs(void)
-{
-       return pcmcia_register_driver(&ide_cs_driver);
-}
-
-static void __exit exit_ide_cs(void)
-{
-       pcmcia_unregister_driver(&ide_cs_driver);
-}
-
-late_initcall(init_ide_cs);
-module_exit(exit_ide_cs);
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
deleted file mode 100644 (file)
index ca1d4b3..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-
-DEFINE_MUTEX(ide_setting_mtx);
-
-ide_devset_get(io_32bit, io_32bit);
-
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
-       if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
-               return -EPERM;
-
-       if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
-               return -EINVAL;
-
-       drive->io_32bit = arg;
-
-       return 0;
-}
-
-ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
-
-static int set_ksettings(ide_drive_t *drive, int arg)
-{
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
-
-       return 0;
-}
-
-ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
-
-static int set_using_dma(ide_drive_t *drive, int arg)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-       int err = -EPERM;
-
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (ata_id_has_dma(drive->id) == 0)
-               goto out;
-
-       if (drive->hwif->dma_ops == NULL)
-               goto out;
-
-       err = 0;
-
-       if (arg) {
-               if (ide_set_dma(drive))
-                       err = -EIO;
-       } else
-               ide_dma_off(drive);
-
-out:
-       return err;
-#else
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       return -EPERM;
-#endif
-}
-
-/*
- * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
- */
-static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
-{
-       switch (req_pio) {
-       case 202:
-       case 201:
-       case 200:
-       case 102:
-       case 101:
-       case 100:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
-       case 9:
-       case 8:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
-       case 7:
-       case 6:
-               return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
-       default:
-               return 0;
-       }
-}
-
-static int set_pio_mode(ide_drive_t *drive, int arg)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (arg < 0 || arg > 255)
-               return -EINVAL;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return -ENOSYS;
-
-       if (set_pio_mode_abuse(drive->hwif, arg)) {
-               drive->pio_mode = arg + XFER_PIO_0;
-
-               if (arg == 8 || arg == 9) {
-                       unsigned long flags;
-
-                       /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
-                       spin_lock_irqsave(&hwif->lock, flags);
-                       port_ops->set_pio_mode(hwif, drive);
-                       spin_unlock_irqrestore(&hwif->lock, flags);
-               } else
-                       port_ops->set_pio_mode(hwif, drive);
-       } else {
-               int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
-               ide_set_pio(drive, arg);
-
-               if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
-                       if (keep_dma)
-                               ide_dma_on(drive);
-               }
-       }
-
-       return 0;
-}
-
-ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
-
-static int set_unmaskirq(ide_drive_t *drive, int arg)
-{
-       if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
-               return -EPERM;
-
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_UNMASK;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-
-       return 0;
-}
-
-ide_ext_devset_rw_sync(io_32bit, io_32bit);
-ide_ext_devset_rw_sync(keepsettings, ksettings);
-ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
-ide_ext_devset_rw_sync(using_dma, using_dma);
-__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
-
-int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
-                      int arg)
-{
-       struct request_queue *q = drive->queue;
-       struct request *rq;
-       int ret = 0;
-
-       if (!(setting->flags & DS_SYNC))
-               return setting->set(drive, arg);
-
-       rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       scsi_req(rq)->cmd_len = 5;
-       scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC;
-       *(int *)&scsi_req(rq)->cmd[1] = arg;
-       ide_req(rq)->special = setting->set;
-
-       blk_execute_rq(NULL, rq, 0);
-       ret = scsi_req(rq)->result;
-       blk_put_request(rq);
-
-       return ret;
-}
-
-ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
-{
-       int err, (*setfunc)(ide_drive_t *, int) = ide_req(rq)->special;
-
-       err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]);
-       if (err)
-               scsi_req(rq)->result = err;
-       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
-       return ide_stopped;
-}
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
deleted file mode 100644 (file)
index 8413731..0000000
+++ /dev/null
@@ -1,795 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- *  Copyright (C) 1994-1998       Linus Torvalds & authors (see below)
- *  Copyright (C) 1998-2002       Linux ATA Development
- *                                   Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2003            Red Hat
- *  Copyright (C) 2003-2005, 2007  Bartlomiej Zolnierkiewicz
- */
-
-/*
- *  Mostly written by Mark Lord <mlord@pobox.com>
- *                and Gadi Oxman <gadio@netvision.net.il>
- *                and Andre Hedrick <andre@linux-ide.org>
- *
- * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/leds.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <asm/div64.h>
-
-#include "ide-disk.h"
-
-static const u8 ide_rw_cmds[] = {
-       ATA_CMD_READ_MULTI,
-       ATA_CMD_WRITE_MULTI,
-       ATA_CMD_READ_MULTI_EXT,
-       ATA_CMD_WRITE_MULTI_EXT,
-       ATA_CMD_PIO_READ,
-       ATA_CMD_PIO_WRITE,
-       ATA_CMD_PIO_READ_EXT,
-       ATA_CMD_PIO_WRITE_EXT,
-       ATA_CMD_READ,
-       ATA_CMD_WRITE,
-       ATA_CMD_READ_EXT,
-       ATA_CMD_WRITE_EXT,
-};
-
-static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma)
-{
-       u8 index, lba48, write;
-
-       lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
-       write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
-
-       if (dma) {
-               cmd->protocol = ATA_PROT_DMA;
-               index = 8;
-       } else {
-               cmd->protocol = ATA_PROT_PIO;
-               if (drive->mult_count) {
-                       cmd->tf_flags |= IDE_TFLAG_MULTI_PIO;
-                       index = 0;
-               } else
-                       index = 4;
-       }
-
-       cmd->tf.command = ide_rw_cmds[index + lba48 + write];
-}
-
-/*
- * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- */
-static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
-                                       sector_t block)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       u16 nsectors            = (u16)blk_rq_sectors(rq);
-       u8 lba48                = !!(drive->dev_flags & IDE_DFLAG_LBA48);
-       u8 dma                  = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-       struct ide_cmd          cmd;
-       struct ide_taskfile     *tf = &cmd.tf;
-       ide_startstop_t         rc;
-
-       if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
-               if (block + blk_rq_sectors(rq) > 1ULL << 28)
-                       dma = 0;
-               else
-                       lba48 = 0;
-       }
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       if (drive->dev_flags & IDE_DFLAG_LBA) {
-               if (lba48) {
-                       pr_debug("%s: LBA=0x%012llx\n", drive->name,
-                                       (unsigned long long)block);
-
-                       tf->nsect  = nsectors & 0xff;
-                       tf->lbal   = (u8) block;
-                       tf->lbam   = (u8)(block >>  8);
-                       tf->lbah   = (u8)(block >> 16);
-                       tf->device = ATA_LBA;
-
-                       tf = &cmd.hob;
-                       tf->nsect = (nsectors >> 8) & 0xff;
-                       tf->lbal  = (u8)(block >> 24);
-                       if (sizeof(block) != 4) {
-                               tf->lbam = (u8)((u64)block >> 32);
-                               tf->lbah = (u8)((u64)block >> 40);
-                       }
-
-                       cmd.valid.out.hob = IDE_VALID_OUT_HOB;
-                       cmd.valid.in.hob  = IDE_VALID_IN_HOB;
-                       cmd.tf_flags |= IDE_TFLAG_LBA48;
-               } else {
-                       tf->nsect  = nsectors & 0xff;
-                       tf->lbal   = block;
-                       tf->lbam   = block >>= 8;
-                       tf->lbah   = block >>= 8;
-                       tf->device = ((block >> 8) & 0xf) | ATA_LBA;
-               }
-       } else {
-               unsigned int sect, head, cyl, track;
-
-               track = (int)block / drive->sect;
-               sect  = (int)block % drive->sect + 1;
-               head  = track % drive->head;
-               cyl   = track / drive->head;
-
-               pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
-
-               tf->nsect  = nsectors & 0xff;
-               tf->lbal   = sect;
-               tf->lbam   = cyl;
-               tf->lbah   = cyl >> 8;
-               tf->device = head;
-       }
-
-       cmd.tf_flags |= IDE_TFLAG_FS;
-
-       if (rq_data_dir(rq))
-               cmd.tf_flags |= IDE_TFLAG_WRITE;
-
-       ide_tf_set_cmd(drive, &cmd, dma);
-       cmd.rq = rq;
-
-       if (dma == 0) {
-               ide_init_sg_cmd(&cmd, nsectors << 9);
-               ide_map_sg(drive, &cmd);
-       }
-
-       rc = do_rw_taskfile(drive, &cmd);
-
-       if (rc == ide_stopped && dma) {
-               /* fallback to PIO */
-               cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
-               ide_tf_set_cmd(drive, &cmd, 0);
-               ide_init_sg_cmd(&cmd, nsectors << 9);
-               rc = do_rw_taskfile(drive, &cmd);
-       }
-
-       return rc;
-}
-
-/*
- * 268435455  == 137439 MB or 28bit limit
- * 320173056  == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
-
-static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
-                                     sector_t block)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
-       BUG_ON(blk_rq_is_passthrough(rq));
-
-       ledtrig_disk_activity(rq_data_dir(rq) == WRITE);
-
-       pr_debug("%s: %sing: block=%llu, sectors=%u\n",
-                drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
-                (unsigned long long)block, blk_rq_sectors(rq));
-
-       if (hwif->rw_disk)
-               hwif->rw_disk(drive, rq);
-
-       return __ide_do_rw_disk(drive, rq, block);
-}
-
-/*
- * Queries for true maximum capacity of the drive.
- * Returns maximum LBA address (> 0) of the drive, 0 if failed.
- */
-static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-       u64 addr = 0;
-
-       memset(&cmd, 0, sizeof(cmd));
-       if (lba48)
-               tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
-       else
-               tf->command = ATA_CMD_READ_NATIVE_MAX;
-       tf->device  = ATA_LBA;
-
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       if (lba48) {
-               cmd.valid.out.hob = IDE_VALID_OUT_HOB;
-               cmd.valid.in.hob  = IDE_VALID_IN_HOB;
-               cmd.tf_flags = IDE_TFLAG_LBA48;
-       }
-
-       ide_no_data_taskfile(drive, &cmd);
-
-       /* if OK, compute maximum address value */
-       if (!(tf->status & ATA_ERR))
-               addr = ide_get_lba_addr(&cmd, lba48) + 1;
-
-       return addr;
-}
-
-/*
- * Sets maximum virtual LBA address of the drive.
- * Returns new maximum virtual LBA address (> 0) or 0 on failure.
- */
-static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-       u64 addr_set = 0;
-
-       addr_req--;
-
-       memset(&cmd, 0, sizeof(cmd));
-       tf->lbal     = (addr_req >>  0) & 0xff;
-       tf->lbam     = (addr_req >>= 8) & 0xff;
-       tf->lbah     = (addr_req >>= 8) & 0xff;
-       if (lba48) {
-               cmd.hob.lbal = (addr_req >>= 8) & 0xff;
-               cmd.hob.lbam = (addr_req >>= 8) & 0xff;
-               cmd.hob.lbah = (addr_req >>= 8) & 0xff;
-               tf->command  = ATA_CMD_SET_MAX_EXT;
-       } else {
-               tf->device   = (addr_req >>= 8) & 0x0f;
-               tf->command  = ATA_CMD_SET_MAX;
-       }
-       tf->device |= ATA_LBA;
-
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       if (lba48) {
-               cmd.valid.out.hob = IDE_VALID_OUT_HOB;
-               cmd.valid.in.hob  = IDE_VALID_IN_HOB;
-               cmd.tf_flags = IDE_TFLAG_LBA48;
-       }
-
-       ide_no_data_taskfile(drive, &cmd);
-
-       /* if OK, compute maximum address value */
-       if (!(tf->status & ATA_ERR))
-               addr_set = ide_get_lba_addr(&cmd, lba48) + 1;
-
-       return addr_set;
-}
-
-static unsigned long long sectors_to_MB(unsigned long long n)
-{
-       n <<= 9;                /* make it bytes */
-       do_div(n, 1000000);     /* make it MB */
-       return n;
-}
-
-/*
- * Some disks report total number of sectors instead of
- * maximum sector address.  We list them here.
- */
-static const struct drive_list_entry hpa_list[] = {
-       { "ST340823A",  NULL },
-       { "ST320413A",  NULL },
-       { "ST310211A",  NULL },
-       { NULL,         NULL }
-};
-
-static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48)
-{
-       u64 capacity, set_max;
-
-       capacity = drive->capacity64;
-       set_max  = idedisk_read_native_max_address(drive, lba48);
-
-       if (ide_in_drive_list(drive->id, hpa_list)) {
-               /*
-                * Since we are inclusive wrt to firmware revisions do this
-                * extra check and apply the workaround only when needed.
-                */
-               if (set_max == capacity + 1)
-                       set_max--;
-       }
-
-       return set_max;
-}
-
-static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48)
-{
-       set_max = idedisk_set_max_address(drive, set_max, lba48);
-       if (set_max)
-               drive->capacity64 = set_max;
-
-       return set_max;
-}
-
-static void idedisk_check_hpa(ide_drive_t *drive)
-{
-       u64 capacity, set_max;
-       int lba48 = ata_id_lba48_enabled(drive->id);
-
-       capacity = drive->capacity64;
-       set_max  = ide_disk_hpa_get_native_capacity(drive, lba48);
-
-       if (set_max <= capacity)
-               return;
-
-       drive->probed_capacity = set_max;
-
-       printk(KERN_INFO "%s: Host Protected Area detected.\n"
-                        "\tcurrent capacity is %llu sectors (%llu MB)\n"
-                        "\tnative  capacity is %llu sectors (%llu MB)\n",
-                        drive->name,
-                        capacity, sectors_to_MB(capacity),
-                        set_max, sectors_to_MB(set_max));
-
-       if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0)
-               return;
-
-       set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48);
-       if (set_max)
-               printk(KERN_INFO "%s: Host Protected Area disabled.\n",
-                                drive->name);
-}
-
-static int ide_disk_get_capacity(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       int lba;
-
-       if (ata_id_lba48_enabled(id)) {
-               /* drive speaks 48-bit LBA */
-               lba = 1;
-               drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
-       } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
-               /* drive speaks 28-bit LBA */
-               lba = 1;
-               drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
-       } else {
-               /* drive speaks boring old 28-bit CHS */
-               lba = 0;
-               drive->capacity64 = drive->cyl * drive->head * drive->sect;
-       }
-
-       drive->probed_capacity = drive->capacity64;
-
-       if (lba) {
-               drive->dev_flags |= IDE_DFLAG_LBA;
-
-               /*
-               * If this device supports the Host Protected Area feature set,
-               * then we may need to change our opinion about its capacity.
-               */
-               if (ata_id_hpa_enabled(id))
-                       idedisk_check_hpa(drive);
-       }
-
-       /* limit drive capacity to 137GB if LBA48 cannot be used */
-       if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
-           drive->capacity64 > 1ULL << 28) {
-               printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
-                      "%llu sectors (%llu MB)\n",
-                      drive->name, (unsigned long long)drive->capacity64,
-                      sectors_to_MB(drive->capacity64));
-               drive->probed_capacity = drive->capacity64 = 1ULL << 28;
-       }
-
-       if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
-           (drive->dev_flags & IDE_DFLAG_LBA48)) {
-               if (drive->capacity64 > 1ULL << 28) {
-                       printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
-                                        " will be used for accessing sectors "
-                                        "> %u\n", drive->name, 1 << 28);
-               } else
-                       drive->dev_flags &= ~IDE_DFLAG_LBA48;
-       }
-
-       return 0;
-}
-
-static void ide_disk_unlock_native_capacity(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       int lba48 = ata_id_lba48_enabled(id);
-
-       if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 ||
-           ata_id_hpa_enabled(id) == 0)
-               return;
-
-       /*
-        * according to the spec the SET MAX ADDRESS command shall be
-        * immediately preceded by a READ NATIVE MAX ADDRESS command
-        */
-       if (!ide_disk_hpa_get_native_capacity(drive, lba48))
-               return;
-
-       if (ide_disk_hpa_set_capacity(drive, drive->probed_capacity, lba48))
-               drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */
-}
-
-static bool idedisk_prep_rq(ide_drive_t *drive, struct request *rq)
-{
-       struct ide_cmd *cmd;
-
-       if (req_op(rq) != REQ_OP_FLUSH)
-               return true;
-
-       if (ide_req(rq)->special) {
-               cmd = ide_req(rq)->special;
-               memset(cmd, 0, sizeof(*cmd));
-       } else {
-               cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
-       }
-
-       /* FIXME: map struct ide_taskfile on rq->cmd[] */
-       BUG_ON(cmd == NULL);
-
-       if (ata_id_flush_ext_enabled(drive->id) &&
-           (drive->capacity64 >= (1UL << 28)))
-               cmd->tf.command = ATA_CMD_FLUSH_EXT;
-       else
-               cmd->tf.command = ATA_CMD_FLUSH;
-       cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd->tf_flags = IDE_TFLAG_DYN;
-       cmd->protocol = ATA_PROT_NODATA;
-       rq->cmd_flags &= ~REQ_OP_MASK;
-       rq->cmd_flags |= REQ_OP_DRV_OUT;
-       ide_req(rq)->type = ATA_PRIV_TASKFILE;
-       ide_req(rq)->special = cmd;
-       cmd->rq = rq;
-
-       return true;
-}
-
-ide_devset_get(multcount, mult_count);
-
-/*
- * This is tightly woven into the driver->do_special can not touch.
- * DON'T do it again until a total personality rewrite is committed.
- */
-static int set_multcount(ide_drive_t *drive, int arg)
-{
-       struct request *rq;
-
-       if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
-               return -EINVAL;
-
-       if (drive->special_flags & IDE_SFLAG_SET_MULTMODE)
-               return -EBUSY;
-
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_TASKFILE;
-
-       drive->mult_req = arg;
-       drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-       blk_execute_rq(NULL, rq, 0);
-       blk_put_request(rq);
-
-       return (drive->mult_count == arg) ? 0 : -EIO;
-}
-
-ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
-
-static int set_nowerr(ide_drive_t *drive, int arg)
-{
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_NOWERR;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_NOWERR;
-
-       drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-
-       return 0;
-}
-
-static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
-{
-       struct ide_cmd cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.tf.feature = feature;
-       cmd.tf.nsect   = nsect;
-       cmd.tf.command = ATA_CMD_SET_FEATURES;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       return ide_no_data_taskfile(drive, &cmd);
-}
-
-static void update_flush(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       bool wc = false;
-
-       if (drive->dev_flags & IDE_DFLAG_WCACHE) {
-               unsigned long long capacity;
-               int barrier;
-               /*
-                * We must avoid issuing commands a drive does not
-                * understand or we may crash it. We check flush cache
-                * is supported. We also check we have the LBA48 flush
-                * cache if the drive capacity is too large. By this
-                * time we have trimmed the drive capacity if LBA48 is
-                * not available so we don't need to recheck that.
-                */
-               capacity = ide_gd_capacity(drive);
-               barrier = ata_id_flush_enabled(id) &&
-                       (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
-                       ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
-                        capacity <= (1ULL << 28) ||
-                        ata_id_flush_ext_enabled(id));
-
-               printk(KERN_INFO "%s: cache flushes %ssupported\n",
-                      drive->name, barrier ? "" : "not ");
-
-               if (barrier) {
-                       wc = true;
-                       drive->prep_rq = idedisk_prep_rq;
-               }
-       }
-
-       blk_queue_write_cache(drive->queue, wc, false);
-}
-
-ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
-
-static int set_wcache(ide_drive_t *drive, int arg)
-{
-       int err = 1;
-
-       if (arg < 0 || arg > 1)
-               return -EINVAL;
-
-       if (ata_id_flush_enabled(drive->id)) {
-               err = ide_do_setfeature(drive,
-                       arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
-               if (err == 0) {
-                       if (arg)
-                               drive->dev_flags |= IDE_DFLAG_WCACHE;
-                       else
-                               drive->dev_flags &= ~IDE_DFLAG_WCACHE;
-               }
-       }
-
-       update_flush(drive);
-
-       return err;
-}
-
-static int do_idedisk_flushcache(ide_drive_t *drive)
-{
-       struct ide_cmd cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       if (ata_id_flush_ext_enabled(drive->id))
-               cmd.tf.command = ATA_CMD_FLUSH_EXT;
-       else
-               cmd.tf.command = ATA_CMD_FLUSH;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       return ide_no_data_taskfile(drive, &cmd);
-}
-
-ide_devset_get(acoustic, acoustic);
-
-static int set_acoustic(ide_drive_t *drive, int arg)
-{
-       if (arg < 0 || arg > 254)
-               return -EINVAL;
-
-       ide_do_setfeature(drive,
-               arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
-
-       drive->acoustic = arg;
-
-       return 0;
-}
-
-ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
-
-/*
- * drive->addressing:
- *     0: 28-bit
- *     1: 48-bit
- *     2: 48-bit capable doing 28-bit
- */
-static int set_addressing(ide_drive_t *drive, int arg)
-{
-       if (arg < 0 || arg > 2)
-               return -EINVAL;
-
-       if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
-           ata_id_lba48_enabled(drive->id) == 0))
-               return -EIO;
-
-       if (arg == 2)
-               arg = 0;
-
-       if (arg)
-               drive->dev_flags |= IDE_DFLAG_LBA48;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_LBA48;
-
-       return 0;
-}
-
-ide_ext_devset_rw(acoustic, acoustic);
-ide_ext_devset_rw(address, addressing);
-ide_ext_devset_rw(multcount, multcount);
-ide_ext_devset_rw(wcache, wcache);
-
-ide_ext_devset_rw_sync(nowerr, nowerr);
-
-static int ide_disk_check(ide_drive_t *drive, const char *s)
-{
-       return 1;
-}
-
-static void ide_disk_setup(ide_drive_t *drive)
-{
-       struct ide_disk_obj *idkp = drive->driver_data;
-       struct request_queue *q = drive->queue;
-       ide_hwif_t *hwif = drive->hwif;
-       u16 *id = drive->id;
-       char *m = (char *)&id[ATA_ID_PROD];
-       unsigned long long capacity;
-
-       ide_proc_register_driver(drive, idkp->driver);
-
-       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
-               return;
-
-       if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
-               /*
-                * Removable disks (eg. SYQUEST); ignore 'WD' drives
-                */
-               if (m[0] != 'W' || m[1] != 'D')
-                       drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
-       }
-
-       (void)set_addressing(drive, 1);
-
-       if (drive->dev_flags & IDE_DFLAG_LBA48) {
-               int max_s = 2048;
-
-               if (max_s > hwif->rqsize)
-                       max_s = hwif->rqsize;
-
-               blk_queue_max_hw_sectors(q, max_s);
-       }
-
-       printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
-              queue_max_sectors(q) / 2);
-
-       if (ata_id_is_ssd(id)) {
-               blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-               blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
-       }
-
-       /* calculate drive capacity, and select LBA if possible */
-       ide_disk_get_capacity(drive);
-
-       /*
-        * if possible, give fdisk access to more of the drive,
-        * by correcting bios_cyls:
-        */
-       capacity = ide_gd_capacity(drive);
-
-       if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
-               if (ata_id_lba48_enabled(drive->id)) {
-                       /* compatibility */
-                       drive->bios_sect = 63;
-                       drive->bios_head = 255;
-               }
-
-               if (drive->bios_sect && drive->bios_head) {
-                       unsigned int cap0 = capacity; /* truncate to 32 bits */
-                       unsigned int cylsz, cyl;
-
-                       if (cap0 != capacity)
-                               drive->bios_cyl = 65535;
-                       else {
-                               cylsz = drive->bios_sect * drive->bios_head;
-                               cyl = cap0 / cylsz;
-                               if (cyl > 65535)
-                                       cyl = 65535;
-                               if (cyl > drive->bios_cyl)
-                                       drive->bios_cyl = cyl;
-                       }
-               }
-       }
-       printk(KERN_INFO "%s: %llu sectors (%llu MB)",
-                        drive->name, capacity, sectors_to_MB(capacity));
-
-       /* Only print cache size when it was specified */
-       if (id[ATA_ID_BUF_SIZE])
-               printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
-
-       printk(KERN_CONT ", CHS=%d/%d/%d\n",
-                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
-       /* write cache enabled? */
-       if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
-               drive->dev_flags |= IDE_DFLAG_WCACHE;
-
-       set_wcache(drive, 1);
-
-       if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
-           (drive->head == 0 || drive->head > 16))
-               printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n",
-                       drive->name, drive->head);
-}
-
-static void ide_disk_flush(ide_drive_t *drive)
-{
-       if (ata_id_flush_enabled(drive->id) == 0 ||
-           (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
-               return;
-
-       if (do_idedisk_flushcache(drive))
-               printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
-}
-
-static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
-{
-       return 0;
-}
-
-static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
-                                int on)
-{
-       struct ide_cmd cmd;
-       int ret;
-
-       if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
-               return 0;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       ret = ide_no_data_taskfile(drive, &cmd);
-
-       if (ret)
-               drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-
-       return ret;
-}
-
-const struct ide_disk_ops ide_ata_disk_ops = {
-       .check                  = ide_disk_check,
-       .unlock_native_capacity = ide_disk_unlock_native_capacity,
-       .get_capacity           = ide_disk_get_capacity,
-       .setup                  = ide_disk_setup,
-       .flush                  = ide_disk_flush,
-       .init_media             = ide_disk_init_media,
-       .set_doorlock           = ide_disk_set_doorlock,
-       .do_request             = ide_do_rw_disk,
-       .ioctl                  = ide_disk_ioctl,
-       .compat_ioctl           = ide_disk_ioctl,
-};
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
deleted file mode 100644 (file)
index 0e8cc18..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_DISK_H
-#define __IDE_DISK_H
-
-#include "ide-gd.h"
-
-#ifdef CONFIG_IDE_GD_ATA
-/* ide-disk.c */
-extern const struct ide_disk_ops ide_ata_disk_ops;
-ide_decl_devset(address);
-ide_decl_devset(multcount);
-ide_decl_devset(nowerr);
-ide_decl_devset(wcache);
-ide_decl_devset(acoustic);
-
-/* ide-disk_ioctl.c */
-int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int,
-                  unsigned long);
-
-#ifdef CONFIG_IDE_PROC_FS
-/* ide-disk_proc.c */
-extern ide_proc_entry_t ide_disk_proc[];
-extern const struct ide_proc_devset ide_disk_settings[];
-#endif
-#else
-#define ide_disk_proc          NULL
-#define ide_disk_settings      NULL
-#endif
-
-#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
deleted file mode 100644 (file)
index 2c45616..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/mutex.h>
-
-#include "ide-disk.h"
-
-static DEFINE_MUTEX(ide_disk_ioctl_mutex);
-static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
-{ HDIO_GET_ADDRESS,    HDIO_SET_ADDRESS,   &ide_devset_address   },
-{ HDIO_GET_MULTCOUNT,  HDIO_SET_MULTCOUNT, &ide_devset_multcount },
-{ HDIO_GET_NOWERR,     HDIO_SET_NOWERR,    &ide_devset_nowerr    },
-{ HDIO_GET_WCACHE,     HDIO_SET_WCACHE,    &ide_devset_wcache    },
-{ HDIO_GET_ACOUSTIC,   HDIO_SET_ACOUSTIC,  &ide_devset_acoustic  },
-{ 0 }
-};
-
-int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode,
-                  unsigned int cmd, unsigned long arg)
-{
-       int err;
-
-       mutex_lock(&ide_disk_ioctl_mutex);
-       err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
-       if (err != -EOPNOTSUPP)
-               goto out;
-
-       err = generic_ide_ioctl(drive, bdev, cmd, arg);
-out:
-       mutex_unlock(&ide_disk_ioctl_mutex);
-       return err;
-}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
deleted file mode 100644 (file)
index 95d239b..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/seq_file.h>
-
-#include "ide-disk.h"
-
-static int smart_enable(ide_drive_t *drive)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-
-       memset(&cmd, 0, sizeof(cmd));
-       tf->feature = ATA_SMART_ENABLE;
-       tf->lbam    = ATA_SMART_LBAM_PASS;
-       tf->lbah    = ATA_SMART_LBAH_PASS;
-       tf->command = ATA_CMD_SMART;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       return ide_no_data_taskfile(drive, &cmd);
-}
-
-static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-
-       memset(&cmd, 0, sizeof(cmd));
-       tf->feature = sub_cmd;
-       tf->nsect   = 0x01;
-       tf->lbam    = ATA_SMART_LBAM_PASS;
-       tf->lbah    = ATA_SMART_LBAH_PASS;
-       tf->command = ATA_CMD_SMART;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       cmd.protocol = ATA_PROT_PIO;
-
-       return ide_raw_taskfile(drive, &cmd, buf, 1);
-}
-
-static int idedisk_cache_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t     *drive = (ide_drive_t *) m->private;
-
-       if (drive->dev_flags & IDE_DFLAG_ID_READ)
-               seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
-       else
-               seq_printf(m, "(none)\n");
-       return 0;
-}
-
-static int idedisk_capacity_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t*drive = (ide_drive_t *)m->private;
-
-       seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
-       return 0;
-}
-
-static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd)
-{
-       u8 *buf;
-
-       buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       (void)smart_enable(drive);
-
-       if (get_smart_data(drive, buf, sub_cmd) == 0) {
-               __le16 *val = (__le16 *)buf;
-               int i;
-
-               for (i = 0; i < SECTOR_SIZE / 2; i++) {
-                       seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
-                                       (i % 8) == 7 ? '\n' : ' ');
-               }
-       }
-       kfree(buf);
-       return 0;
-}
-
-static int idedisk_sv_proc_show(struct seq_file *m, void *v)
-{
-       return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES);
-}
-
-static int idedisk_st_proc_show(struct seq_file *m, void *v)
-{
-       return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS);
-}
-
-ide_proc_entry_t ide_disk_proc[] = {
-       { "cache",        S_IFREG|S_IRUGO, idedisk_cache_proc_show      },
-       { "capacity",     S_IFREG|S_IRUGO, idedisk_capacity_proc_show   },
-       { "geometry",     S_IFREG|S_IRUGO, ide_geometry_proc_show       },
-       { "smart_values", S_IFREG|S_IRUSR, idedisk_sv_proc_show         },
-       { "smart_thresholds", S_IFREG|S_IRUSR, idedisk_st_proc_show     },
-       {}
-};
-
-ide_devset_rw_field(bios_cyl, bios_cyl);
-ide_devset_rw_field(bios_head, bios_head);
-ide_devset_rw_field(bios_sect, bios_sect);
-ide_devset_rw_field(failures, failures);
-ide_devset_rw_field(lun, lun);
-ide_devset_rw_field(max_failures, max_failures);
-
-const struct ide_proc_devset ide_disk_settings[] = {
-       IDE_PROC_DEVSET(acoustic,       0,   254),
-       IDE_PROC_DEVSET(address,        0,     2),
-       IDE_PROC_DEVSET(bios_cyl,       0, 65535),
-       IDE_PROC_DEVSET(bios_head,      0,   255),
-       IDE_PROC_DEVSET(bios_sect,      0,    63),
-       IDE_PROC_DEVSET(failures,       0, 65535),
-       IDE_PROC_DEVSET(lun,            0,     7),
-       IDE_PROC_DEVSET(max_failures,   0, 65535),
-       IDE_PROC_DEVSET(multcount,      0,    16),
-       IDE_PROC_DEVSET(nowerr,         0,     1),
-       IDE_PROC_DEVSET(wcache,         0,     1),
-       { NULL },
-};
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
deleted file mode 100644 (file)
index b7c2c0b..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-
-/**
- *     config_drive_for_dma    -       attempt to activate IDE DMA
- *     @drive: the drive to place in DMA mode
- *
- *     If the drive supports at least mode 2 DMA or UDMA of any kind
- *     then attempt to place it into DMA mode. Drives that are known to
- *     support DMA but predate the DMA properties or that are known
- *     to have DMA handling bugs are also set up appropriately based
- *     on the good/bad drive lists.
- */
-
-int config_drive_for_dma(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u16 *id = drive->id;
-
-       if (drive->media != ide_disk) {
-               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
-                       return 0;
-       }
-
-       /*
-        * Enable DMA on any drive that has
-        * UltraDMA (mode 0/1/2/3/4/5/6) enabled
-        */
-       if ((id[ATA_ID_FIELD_VALID] & 4) &&
-           ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
-               return 1;
-
-       /*
-        * Enable DMA on any drive that has mode2 DMA
-        * (multi or single) enabled
-        */
-       if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
-           (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
-               return 1;
-
-       /* Consult the list of known "good" drives */
-       if (ide_dma_good_drive(drive))
-               return 1;
-
-       return 0;
-}
-
-u8 ide_dma_sff_read_status(ide_hwif_t *hwif)
-{
-       unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return readb((void __iomem *)addr);
-       else
-               return inb(addr);
-}
-EXPORT_SYMBOL_GPL(ide_dma_sff_read_status);
-
-static void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val)
-{
-       unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(val, (void __iomem *)addr);
-       else
-               outb(val, addr);
-}
-
-/**
- *     ide_dma_host_set        -       Enable/disable DMA on a host
- *     @drive: drive to control
- *
- *     Enable/disable DMA on an IDE controller following generic
- *     bus-mastering IDE controller behaviour.
- */
-
-void ide_dma_host_set(ide_drive_t *drive, int on)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 unit = drive->dn & 1;
-       u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
-       if (on)
-               dma_stat |= (1 << (5 + unit));
-       else
-               dma_stat &= ~(1 << (5 + unit));
-
-       ide_dma_sff_write_status(hwif, dma_stat);
-}
-EXPORT_SYMBOL_GPL(ide_dma_host_set);
-
-/**
- *     ide_build_dmatable      -       build IDE DMA table
- *
- *     ide_build_dmatable() prepares a dma request. We map the command
- *     to get the pci bus addresses of the buffers and then build up
- *     the PRD table that the IDE layer wants to be fed.
- *
- *     Most chipsets correctly interpret a length of 0x0000 as 64KB,
- *     but at least one (e.g. CS5530) misinterprets it as zero (!).
- *     So we break the 64KB entry into two 32KB entries instead.
- *
- *     Returns the number of built PRD entries if all went okay,
- *     returns 0 otherwise.
- *
- *     May also be invoked from trm290.c
- */
-
-int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       __le32 *table = (__le32 *)hwif->dmatable_cpu;
-       unsigned int count = 0;
-       int i;
-       struct scatterlist *sg;
-       u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290);
-
-       for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
-               u32 cur_addr, cur_len, xcount, bcount;
-
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               /*
-                * Fill in the dma table, without crossing any 64kB boundaries.
-                * Most hardware requires 16-bit alignment of all blocks,
-                * but the trm290 requires 32-bit alignment.
-                */
-
-               while (cur_len) {
-                       if (count++ >= PRD_ENTRIES)
-                               goto use_pio_instead;
-
-                       bcount = 0x10000 - (cur_addr & 0xffff);
-                       if (bcount > cur_len)
-                               bcount = cur_len;
-                       *table++ = cpu_to_le32(cur_addr);
-                       xcount = bcount & 0xffff;
-                       if (is_trm290)
-                               xcount = ((xcount >> 2) - 1) << 16;
-                       else if (xcount == 0x0000) {
-                               if (count++ >= PRD_ENTRIES)
-                                       goto use_pio_instead;
-                               *table++ = cpu_to_le32(0x8000);
-                               *table++ = cpu_to_le32(cur_addr + 0x8000);
-                               xcount = 0x8000;
-                       }
-                       *table++ = cpu_to_le32(xcount);
-                       cur_addr += bcount;
-                       cur_len -= bcount;
-               }
-       }
-
-       if (count) {
-               if (!is_trm290)
-                       *--table |= cpu_to_le32(0x80000000);
-               return count;
-       }
-
-use_pio_instead:
-       printk(KERN_ERR "%s: %s\n", drive->name,
-               count ? "DMA table too small" : "empty DMA table?");
-
-       return 0; /* revert to PIO for this request */
-}
-EXPORT_SYMBOL_GPL(ide_build_dmatable);
-
-/**
- *     ide_dma_setup   -       begin a DMA phase
- *     @drive: target device
- *     @cmd: command
- *
- *     Build an IDE DMA PRD (IDE speak for scatter gather table)
- *     and then set up the DMA transfer registers for a device
- *     that follows generic IDE PCI DMA behaviour. Controllers can
- *     override this function if they need to
- *
- *     Returns 0 on success. If a PIO fallback is required then 1
- *     is returned.
- */
-
-int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
-       u8 dma_stat;
-
-       /* fall back to pio! */
-       if (ide_build_dmatable(drive, cmd) == 0) {
-               ide_map_sg(drive, cmd);
-               return 1;
-       }
-
-       /* PRD table */
-       if (mmio)
-               writel(hwif->dmatable_dma,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
-       else
-               outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
-
-       /* specify r/w */
-       if (mmio)
-               writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       else
-               outb(rw, hwif->dma_base + ATA_DMA_CMD);
-
-       /* read DMA status for INTR & ERROR flags */
-       dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
-       /* clear INTR & ERROR flags */
-       ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_setup);
-
-/**
- *     ide_dma_sff_timer_expiry        -       handle a DMA timeout
- *     @drive: Drive that timed out
- *
- *     An IDE DMA transfer timed out. In the event of an error we ask
- *     the driver to resolve the problem, if a DMA transfer is still
- *     in progress we continue to wait (arguably we need to add a
- *     secondary 'I don't care what the drive thinks' timeout here)
- *     Finally if we have an interrupt we let it complete the I/O.
- *     But only one time - we clear expiry and if it's still not
- *     completed after WAIT_CMD, we error and retry in PIO.
- *     This can occur if an interrupt is lost or due to hang or bugs.
- */
-
-int ide_dma_sff_timer_expiry(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
-       printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
-               drive->name, __func__, dma_stat);
-
-       if ((dma_stat & 0x18) == 0x18)  /* BUSY Stupid Early Timer !! */
-               return WAIT_CMD;
-
-       hwif->expiry = NULL;    /* one free ride for now */
-
-       if (dma_stat & ATA_DMA_ERR)     /* ERROR */
-               return -1;
-
-       if (dma_stat & ATA_DMA_ACTIVE)  /* DMAing */
-               return WAIT_CMD;
-
-       if (dma_stat & ATA_DMA_INTR)    /* Got an Interrupt */
-               return WAIT_CMD;
-
-       return 0;       /* Status is unknown -- reset the bus */
-}
-EXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry);
-
-void ide_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_cmd;
-
-       /* Note that this is done *after* the cmd has
-        * been issued to the drive, as per the BM-IDE spec.
-        * The Promise Ultra33 doesn't work correctly when
-        * we do this part before issuing the drive cmd.
-        */
-       if (hwif->host_flags & IDE_HFLAG_MMIO) {
-               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               writeb(dma_cmd | ATA_DMA_START,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       } else {
-               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_dma_start);
-
-/* returns 1 on error, 0 otherwise */
-int ide_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat = 0, dma_cmd = 0;
-
-       /* stop DMA */
-       if (hwif->host_flags & IDE_HFLAG_MMIO) {
-               dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               writeb(dma_cmd & ~ATA_DMA_START,
-                      (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-       } else {
-               dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
-       }
-
-       /* get DMA status */
-       dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
-       /* clear INTR & ERROR bits */
-       ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
-
-#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
-
-       /* verify good DMA status */
-       if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR)
-               return 0x10 | dma_stat;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_end);
-
-/* returns 1 if dma irq issued, 0 otherwise */
-int ide_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
-       return (dma_stat & ATA_DMA_INTR) ? 1 : 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_test_irq);
-
-const struct ide_dma_ops sff_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-EXPORT_SYMBOL_GPL(sff_dma_ops);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
deleted file mode 100644 (file)
index 6f34465..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- *  IDE DMA support (including IDE PCI BM-DMA).
- *
- *  Copyright (C) 1995-1998   Mark Lord
- *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
- */
-
-/*
- *  Special Thanks to Mark for his Six years of work.
- */
-
-/*
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
- * fixing the problem with the BIOS on some Acer motherboards.
- *
- * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
- * "TX" chipset compatibility and for providing patches for the "TX" chipset.
- *
- * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
- * at generic DMA -- his patches were referred to when preparing this code.
- *
- * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
- * for supplying a Promise UDMA board & WD UDMA drive for this work!
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-
-static const struct drive_list_entry drive_whitelist[] = {
-       { "Micropolis 2112A"    ,       NULL            },
-       { "CONNER CTMA 4000"    ,       NULL            },
-       { "CONNER CTT8000-A"    ,       NULL            },
-       { "ST34342A"            ,       NULL            },
-       { NULL                  ,       NULL            }
-};
-
-static const struct drive_list_entry drive_blacklist[] = {
-       { "WDC AC11000H"        ,       NULL            },
-       { "WDC AC22100H"        ,       NULL            },
-       { "WDC AC32500H"        ,       NULL            },
-       { "WDC AC33100H"        ,       NULL            },
-       { "WDC AC31600H"        ,       NULL            },
-       { "WDC AC32100H"        ,       "24.09P07"      },
-       { "WDC AC23200L"        ,       "21.10N21"      },
-       { "Compaq CRD-8241B"    ,       NULL            },
-       { "CRD-8400B"           ,       NULL            },
-       { "CRD-8480B",                  NULL            },
-       { "CRD-8482B",                  NULL            },
-       { "CRD-84"              ,       NULL            },
-       { "SanDisk SDP3B"       ,       NULL            },
-       { "SanDisk SDP3B-64"    ,       NULL            },
-       { "SANYO CD-ROM CRD"    ,       NULL            },
-       { "HITACHI CDR-8"       ,       NULL            },
-       { "HITACHI CDR-8335"    ,       NULL            },
-       { "HITACHI CDR-8435"    ,       NULL            },
-       { "Toshiba CD-ROM XM-6202B"     ,       NULL            },
-       { "TOSHIBA CD-ROM XM-1702BC",   NULL            },
-       { "CD-532E-A"           ,       NULL            },
-       { "E-IDE CD-ROM CR-840",        NULL            },
-       { "CD-ROM Drive/F5A",   NULL            },
-       { "WPI CDD-820",                NULL            },
-       { "SAMSUNG CD-ROM SC-148C",     NULL            },
-       { "SAMSUNG CD-ROM SC",  NULL            },
-       { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     NULL            },
-       { "_NEC DV5800A",               NULL            },
-       { "SAMSUNG CD-ROM SN-124",      "N001" },
-       { "Seagate STT20000A",          NULL  },
-       { "CD-ROM CDR_U200",            "1.09" },
-       { NULL                  ,       NULL            }
-
-};
-
-/**
- *     ide_dma_intr    -       IDE DMA interrupt handler
- *     @drive: the drive the interrupt is for
- *
- *     Handle an interrupt completing a read/write DMA transfer on an
- *     IDE device
- */
-
-ide_startstop_t ide_dma_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
-       u8 stat = 0, dma_stat = 0;
-
-       drive->waiting_for_dma = 0;
-       dma_stat = hwif->dma_ops->dma_end(drive);
-       ide_dma_unmap_sg(drive, cmd);
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
-               if (!dma_stat) {
-                       if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
-                               ide_finish_cmd(drive, cmd, stat);
-                       else
-                               ide_complete_rq(drive, BLK_STS_OK,
-                                               blk_rq_sectors(cmd->rq) << 9);
-                       return ide_stopped;
-               }
-               printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
-                       drive->name, __func__, dma_stat);
-       }
-       return ide_error(drive, "dma_intr", stat);
-}
-
-int ide_dma_good_drive(ide_drive_t *drive)
-{
-       return ide_in_drive_list(drive->id, drive_whitelist);
-}
-
-/**
- *     ide_dma_map_sg  -       map IDE scatter gather for DMA I/O
- *     @drive: the drive to map the DMA table for
- *     @cmd: command
- *
- *     Perform the DMA mapping magic necessary to access the source or
- *     target buffers of a request via DMA.  The lower layers of the
- *     kernel provide the necessary cache management so that we can
- *     operate in a portable fashion.
- */
-
-static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct scatterlist *sg = hwif->sg_table;
-       int i;
-
-       if (cmd->tf_flags & IDE_TFLAG_WRITE)
-               cmd->sg_dma_direction = DMA_TO_DEVICE;
-       else
-               cmd->sg_dma_direction = DMA_FROM_DEVICE;
-
-       i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction);
-       if (i) {
-               cmd->orig_sg_nents = cmd->sg_nents;
-               cmd->sg_nents = i;
-       }
-
-       return i;
-}
-
-/**
- *     ide_dma_unmap_sg        -       clean up DMA mapping
- *     @drive: The drive to unmap
- *
- *     Teardown mappings after DMA has completed. This must be called
- *     after the completion of each use of ide_build_dmatable and before
- *     the next use of ide_build_dmatable. Failure to do so will cause
- *     an oops as only one mapping can be live for each target at a given
- *     time.
- */
-
-void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents,
-                    cmd->sg_dma_direction);
-}
-EXPORT_SYMBOL_GPL(ide_dma_unmap_sg);
-
-/**
- *     ide_dma_off_quietly     -       Generic DMA kill
- *     @drive: drive to control
- *
- *     Turn off the current DMA on this IDE controller.
- */
-
-void ide_dma_off_quietly(ide_drive_t *drive)
-{
-       drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
-
-       drive->hwif->dma_ops->dma_host_set(drive, 0);
-}
-EXPORT_SYMBOL(ide_dma_off_quietly);
-
-/**
- *     ide_dma_off     -       disable DMA on a device
- *     @drive: drive to disable DMA on
- *
- *     Disable IDE DMA for a device on this IDE controller.
- *     Inform the user that DMA has been disabled.
- */
-
-void ide_dma_off(ide_drive_t *drive)
-{
-       printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-       ide_dma_off_quietly(drive);
-}
-EXPORT_SYMBOL(ide_dma_off);
-
-/**
- *     ide_dma_on              -       Enable DMA on a device
- *     @drive: drive to enable DMA on
- *
- *     Enable IDE DMA for a device on this IDE controller.
- */
-
-void ide_dma_on(ide_drive_t *drive)
-{
-       drive->dev_flags |= IDE_DFLAG_USING_DMA;
-
-       drive->hwif->dma_ops->dma_host_set(drive, 1);
-}
-
-int __ide_dma_bad_drive(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-
-       int blacklist = ide_in_drive_list(id, drive_blacklist);
-       if (blacklist) {
-               printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
-                                   drive->name, (char *)&id[ATA_ID_PROD]);
-               return blacklist;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(__ide_dma_bad_drive);
-
-static const u8 xfer_mode_bases[] = {
-       XFER_UDMA_0,
-       XFER_MW_DMA_0,
-       XFER_SW_DMA_0,
-};
-
-static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
-{
-       u16 *id = drive->id;
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       unsigned int mask = 0;
-
-       switch (base) {
-       case XFER_UDMA_0:
-               if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
-                       break;
-               mask = id[ATA_ID_UDMA_MODES];
-               if (port_ops && port_ops->udma_filter)
-                       mask &= port_ops->udma_filter(drive);
-               else
-                       mask &= hwif->ultra_mask;
-
-               /*
-                * avoid false cable warning from eighty_ninty_three()
-                */
-               if (req_mode > XFER_UDMA_2) {
-                       if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
-                               mask &= 0x07;
-               }
-               break;
-       case XFER_MW_DMA_0:
-               mask = id[ATA_ID_MWDMA_MODES];
-
-               /* Also look for the CF specific MWDMA modes... */
-               if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) {
-                       u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1;
-
-                       mask |= ((2 << mode) - 1) << 3;
-               }
-
-               if (port_ops && port_ops->mdma_filter)
-                       mask &= port_ops->mdma_filter(drive);
-               else
-                       mask &= hwif->mwdma_mask;
-               break;
-       case XFER_SW_DMA_0:
-               mask = id[ATA_ID_SWDMA_MODES];
-               if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) {
-                       u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
-
-                       /*
-                        * if the mode is valid convert it to the mask
-                        * (the maximum allowed mode is XFER_SW_DMA_2)
-                        */
-                       if (mode <= 2)
-                               mask = (2 << mode) - 1;
-               }
-               mask &= hwif->swdma_mask;
-               break;
-       default:
-               BUG();
-               break;
-       }
-
-       return mask;
-}
-
-/**
- *     ide_find_dma_mode       -       compute DMA speed
- *     @drive: IDE device
- *     @req_mode: requested mode
- *
- *     Checks the drive/host capabilities and finds the speed to use for
- *     the DMA transfer.  The speed is then limited by the requested mode.
- *
- *     Returns 0 if the drive/host combination is incapable of DMA transfers
- *     or if the requested mode is not a DMA mode.
- */
-
-u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned int mask;
-       int x, i;
-       u8 mode = 0;
-
-       if (drive->media != ide_disk) {
-               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
-                       return 0;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
-               if (req_mode < xfer_mode_bases[i])
-                       continue;
-               mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
-               x = fls(mask) - 1;
-               if (x >= 0) {
-                       mode = xfer_mode_bases[i] + x;
-                       break;
-               }
-       }
-
-       if (hwif->chipset == ide_acorn && mode == 0) {
-               /*
-                * is this correct?
-                */
-               if (ide_dma_good_drive(drive) &&
-                   drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
-                       mode = XFER_MW_DMA_1;
-       }
-
-       mode = min(mode, req_mode);
-
-       printk(KERN_INFO "%s: %s mode selected\n", drive->name,
-                         mode ? ide_xfer_verbose(mode) : "no DMA");
-
-       return mode;
-}
-
-static int ide_tune_dma(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 speed;
-
-       if (ata_id_has_dma(drive->id) == 0 ||
-           (drive->dev_flags & IDE_DFLAG_NODMA))
-               return 0;
-
-       /* consult the list of known "bad" drives */
-       if (__ide_dma_bad_drive(drive))
-               return 0;
-
-       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
-               return config_drive_for_dma(drive);
-
-       speed = ide_max_dma_mode(drive);
-
-       if (!speed)
-               return 0;
-
-       if (ide_set_dma_mode(drive, speed))
-               return 0;
-
-       return 1;
-}
-
-static int ide_dma_check(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if (ide_tune_dma(drive))
-               return 0;
-
-       /* TODO: always do PIO fallback */
-       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
-               return -1;
-
-       ide_set_max_pio(drive);
-
-       return -1;
-}
-
-int ide_set_dma(ide_drive_t *drive)
-{
-       int rc;
-
-       /*
-        * Force DMAing for the beginning of the check.
-        * Some chipsets appear to do interesting
-        * things, if not checked and cleared.
-        *   PARANOIA!!!
-        */
-       ide_dma_off_quietly(drive);
-
-       rc = ide_dma_check(drive);
-       if (rc)
-               return rc;
-
-       ide_dma_on(drive);
-
-       return 0;
-}
-
-void ide_check_dma_crc(ide_drive_t *drive)
-{
-       u8 mode;
-
-       ide_dma_off_quietly(drive);
-       drive->crc_count = 0;
-       mode = drive->current_speed;
-       /*
-        * Don't try non Ultra-DMA modes without iCRC's.  Force the
-        * device to PIO and make the user enable SWDMA/MWDMA modes.
-        */
-       if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
-               mode--;
-       else
-               mode = XFER_PIO_4;
-       ide_set_xfer_rate(drive, mode);
-       if (drive->current_speed >= XFER_SW_DMA_0)
-               ide_dma_on(drive);
-}
-
-void ide_dma_lost_irq(ide_drive_t *drive)
-{
-       printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
-}
-EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
-
-/*
- * un-busy the port etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_dma_ops *dma_ops = hwif->dma_ops;
-       struct ide_cmd *cmd = &hwif->cmd;
-       ide_startstop_t ret = ide_stopped;
-
-       /*
-        * end current dma transaction
-        */
-
-       if (error < 0) {
-               printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
-               drive->waiting_for_dma = 0;
-               (void)dma_ops->dma_end(drive);
-               ide_dma_unmap_sg(drive, cmd);
-               ret = ide_error(drive, "dma timeout error",
-                               hwif->tp_ops->read_status(hwif));
-       } else {
-               printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
-               if (dma_ops->dma_clear)
-                       dma_ops->dma_clear(drive);
-               printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
-               if (dma_ops->dma_test_irq(drive) == 0) {
-                       ide_dump_status(drive, "DMA timeout",
-                                       hwif->tp_ops->read_status(hwif));
-                       drive->waiting_for_dma = 0;
-                       (void)dma_ops->dma_end(drive);
-                       ide_dma_unmap_sg(drive, cmd);
-               }
-       }
-
-       /*
-        * disable dma for now, but remember that we did so because of
-        * a timeout -- we'll reenable after we finish this next request
-        * (or rather the first chunk of it) in pio.
-        */
-       drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
-       drive->retry_pio++;
-       ide_dma_off_quietly(drive);
-
-       /*
-        * make sure request is sane
-        */
-       if (hwif->rq)
-               scsi_req(hwif->rq)->result = 0;
-       return ret;
-}
-
-void ide_release_dma_engine(ide_hwif_t *hwif)
-{
-       if (hwif->dmatable_cpu) {
-               int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
-
-               dma_free_coherent(hwif->dev, prd_size,
-                                 hwif->dmatable_cpu, hwif->dmatable_dma);
-               hwif->dmatable_cpu = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(ide_release_dma_engine);
-
-int ide_allocate_dma_engine(ide_hwif_t *hwif)
-{
-       int prd_size;
-
-       if (hwif->prd_max_nents == 0)
-               hwif->prd_max_nents = PRD_ENTRIES;
-       if (hwif->prd_ent_size == 0)
-               hwif->prd_ent_size = PRD_BYTES;
-
-       prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
-
-       hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
-                                               &hwif->dmatable_dma,
-                                               GFP_ATOMIC);
-       if (hwif->dmatable_cpu == NULL) {
-               printk(KERN_ERR "%s: unable to allocate PRD table\n",
-                       hwif->name);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
-
-int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops;
-
-       if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
-           (dma_ops->dma_check && dma_ops->dma_check(drive, cmd)))
-               goto out;
-       ide_map_sg(drive, cmd);
-       if (ide_dma_map_sg(drive, cmd) == 0)
-               goto out_map;
-       if (dma_ops->dma_setup(drive, cmd))
-               goto out_dma_unmap;
-       drive->waiting_for_dma = 1;
-       return 0;
-out_dma_unmap:
-       ide_dma_unmap_sg(drive, cmd);
-out_map:
-       ide_map_sg(drive, cmd);
-out:
-       return 1;
-}
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
deleted file mode 100644 (file)
index 2f37821..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-
-static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq,
-                                    u8 stat, u8 err)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if ((stat & ATA_BUSY) ||
-           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
-               /* other bits are useless when BUSY */
-               scsi_req(rq)->result |= ERROR_RESET;
-       } else if (stat & ATA_ERR) {
-               /* err has different meaning on cdrom and tape */
-               if (err == ATA_ABORTED) {
-                       if ((drive->dev_flags & IDE_DFLAG_LBA) &&
-                           /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
-                           hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
-                               return ide_stopped;
-               } else if ((err & BAD_CRC) == BAD_CRC) {
-                       /* UDMA crc error, just retry the operation */
-                       drive->crc_count++;
-               } else if (err & (ATA_BBK | ATA_UNC)) {
-                       /* retries won't help these */
-                       scsi_req(rq)->result = ERROR_MAX;
-               } else if (err & ATA_TRK0NF) {
-                       /* help it find track zero */
-                       scsi_req(rq)->result |= ERROR_RECAL;
-               }
-       }
-
-       if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
-           (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
-               int nsect = drive->mult_count ? drive->mult_count : 1;
-
-               ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
-       }
-
-       if (scsi_req(rq)->result >= ERROR_MAX || blk_noretry_request(rq)) {
-               ide_kill_rq(drive, rq);
-               return ide_stopped;
-       }
-
-       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
-               scsi_req(rq)->result |= ERROR_RESET;
-
-       if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) {
-               ++scsi_req(rq)->result;
-               return ide_do_reset(drive);
-       }
-
-       if ((scsi_req(rq)->result & ERROR_RECAL) == ERROR_RECAL)
-               drive->special_flags |= IDE_SFLAG_RECALIBRATE;
-
-       ++scsi_req(rq)->result;
-
-       return ide_stopped;
-}
-
-static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq,
-                                      u8 stat, u8 err)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       if ((stat & ATA_BUSY) ||
-           ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
-               /* other bits are useless when BUSY */
-               scsi_req(rq)->result |= ERROR_RESET;
-       } else {
-               /* add decoding error stuff */
-       }
-
-       if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
-               /* force an abort */
-               hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
-
-       if (scsi_req(rq)->result >= ERROR_MAX) {
-               ide_kill_rq(drive, rq);
-       } else {
-               if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) {
-                       ++scsi_req(rq)->result;
-                       return ide_do_reset(drive);
-               }
-               ++scsi_req(rq)->result;
-       }
-
-       return ide_stopped;
-}
-
-static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq,
-                                  u8 stat, u8 err)
-{
-       if (drive->media == ide_disk)
-               return ide_ata_error(drive, rq, stat, err);
-       return ide_atapi_error(drive, rq, stat, err);
-}
-
-/**
- *     ide_error       -       handle an error on the IDE
- *     @drive: drive the error occurred on
- *     @msg: message to report
- *     @stat: status bits
- *
- *     ide_error() takes action based on the error returned by the drive.
- *     For normal I/O that may well include retries. We deal with
- *     both new-style (taskfile) and old style command handling here.
- *     In the case of taskfile command handling there is work left to
- *     do
- */
-
-ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
-{
-       struct request *rq;
-       u8 err;
-
-       err = ide_dump_status(drive, msg, stat);
-
-       rq = drive->hwif->rq;
-       if (rq == NULL)
-               return ide_stopped;
-
-       /* retry only "normal" I/O: */
-       if (blk_rq_is_passthrough(rq)) {
-               if (ata_taskfile_request(rq)) {
-                       struct ide_cmd *cmd = ide_req(rq)->special;
-
-                       if (cmd)
-                               ide_complete_cmd(drive, cmd, stat, err);
-               } else if (ata_pm_request(rq)) {
-                       scsi_req(rq)->result = 1;
-                       ide_complete_pm_rq(drive, rq);
-                       return ide_stopped;
-               }
-               scsi_req(rq)->result = err;
-               ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq));
-               return ide_stopped;
-       }
-
-       return __ide_error(drive, rq, stat, err);
-}
-EXPORT_SYMBOL_GPL(ide_error);
-
-static inline void ide_complete_drive_reset(ide_drive_t *drive, blk_status_t err)
-{
-       struct request *rq = drive->hwif->rq;
-
-       if (rq && ata_misc_request(rq) &&
-           scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) {
-               if (err <= 0 && scsi_req(rq)->result == 0)
-                       scsi_req(rq)->result = -EIO;
-               ide_complete_rq(drive, err, blk_rq_bytes(rq));
-       }
-}
-
-/* needed below */
-static ide_startstop_t do_reset1(ide_drive_t *, int);
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion
- * every 50ms during an atapi drive reset operation.  If the drive has not yet
- * responded, and we have not yet hit our maximum waiting time, then the timer
- * is restarted for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       u8 stat;
-
-       tp_ops->dev_select(drive);
-       udelay(10);
-       stat = tp_ops->read_status(hwif);
-
-       if (OK_STAT(stat, 0, ATA_BUSY))
-               printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
-       else {
-               if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
-                       /* continue polling */
-                       return ide_started;
-               }
-               /* end of polling */
-               hwif->polling = 0;
-               printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n",
-                       drive->name, stat);
-               /* do it the old fashioned way */
-               return do_reset1(drive, 1);
-       }
-       /* done polling */
-       hwif->polling = 0;
-       ide_complete_drive_reset(drive, BLK_STS_OK);
-       return ide_stopped;
-}
-
-static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
-{
-       static const char *err_master_vals[] =
-               { NULL, "passed", "formatter device error",
-                 "sector buffer error", "ECC circuitry error",
-                 "controlling MPU error" };
-
-       u8 err_master = err & 0x7f;
-
-       printk(KERN_ERR "%s: reset: master: ", hwif->name);
-       if (err_master && err_master < 6)
-               printk(KERN_CONT "%s", err_master_vals[err_master]);
-       else
-               printk(KERN_CONT "error (0x%02x?)", err);
-       if (err & 0x80)
-               printk(KERN_CONT "; slave: failed");
-       printk(KERN_CONT "\n");
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       u8 tmp;
-       blk_status_t err = BLK_STS_OK;
-
-       if (port_ops && port_ops->reset_poll) {
-               err = port_ops->reset_poll(drive);
-               if (err) {
-                       printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
-                               hwif->name, drive->name);
-                       goto out;
-               }
-       }
-
-       tmp = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(tmp, 0, ATA_BUSY)) {
-               if (time_before(jiffies, hwif->poll_timeout)) {
-                       ide_set_handler(drive, &reset_pollfunc, HZ/20);
-                       /* continue polling */
-                       return ide_started;
-               }
-               printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n",
-                       hwif->name, tmp);
-               drive->failures++;
-               err = BLK_STS_IOERR;
-       } else  {
-               tmp = ide_read_error(drive);
-
-               if (tmp == 1) {
-                       printk(KERN_INFO "%s: reset: success\n", hwif->name);
-                       drive->failures = 0;
-               } else {
-                       ide_reset_report_error(hwif, tmp);
-                       drive->failures++;
-                       err = BLK_STS_IOERR;
-               }
-       }
-out:
-       hwif->polling = 0;      /* done polling */
-       ide_complete_drive_reset(drive, err);
-       return ide_stopped;
-}
-
-static void ide_disk_pre_reset(ide_drive_t *drive)
-{
-       int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
-
-       drive->special_flags =
-               legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0;
-
-       drive->mult_count = 0;
-       drive->dev_flags &= ~IDE_DFLAG_PARKED;
-
-       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
-           (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
-               drive->mult_req = 0;
-
-       if (drive->mult_req != drive->mult_count)
-               drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-}
-
-static void pre_reset(ide_drive_t *drive)
-{
-       const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-
-       if (drive->media == ide_disk)
-               ide_disk_pre_reset(drive);
-       else
-               drive->dev_flags |= IDE_DFLAG_POST_RESET;
-
-       if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
-               if (drive->crc_count)
-                       ide_check_dma_crc(drive);
-               else
-                       ide_dma_off(drive);
-       }
-
-       if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
-               if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
-                       drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-                       drive->io_32bit = 0;
-               }
-               return;
-       }
-
-       if (port_ops && port_ops->pre_reset)
-               port_ops->pre_reset(drive);
-
-       if (drive->current_speed != 0xff)
-               drive->desired_speed = drive->current_speed;
-       drive->current_speed = 0xff;
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       const struct ide_port_ops *port_ops;
-       ide_drive_t *tdrive;
-       unsigned long flags, timeout;
-       int i;
-       DEFINE_WAIT(wait);
-
-       spin_lock_irqsave(&hwif->lock, flags);
-
-       /* We must not reset with running handlers */
-       BUG_ON(hwif->handler != NULL);
-
-       /* For an ATAPI device, first try an ATAPI SRST. */
-       if (drive->media != ide_disk && !do_not_try_atapi) {
-               pre_reset(drive);
-               tp_ops->dev_select(drive);
-               udelay(20);
-               tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
-               ndelay(400);
-               hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
-               hwif->polling = 1;
-               __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               return ide_started;
-       }
-
-       /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
-       do {
-               unsigned long now;
-
-               prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
-               timeout = jiffies;
-               ide_port_for_each_present_dev(i, tdrive, hwif) {
-                       if ((tdrive->dev_flags & IDE_DFLAG_PARKED) &&
-                           time_after(tdrive->sleep, timeout))
-                               timeout = tdrive->sleep;
-               }
-
-               now = jiffies;
-               if (time_before_eq(timeout, now))
-                       break;
-
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               timeout = schedule_timeout_uninterruptible(timeout - now);
-               spin_lock_irqsave(&hwif->lock, flags);
-       } while (timeout);
-       finish_wait(&ide_park_wq, &wait);
-
-       /*
-        * First, reset any device state data we were maintaining
-        * for any of the drives on this interface.
-        */
-       ide_port_for_each_dev(i, tdrive, hwif)
-               pre_reset(tdrive);
-
-       if (io_ports->ctl_addr == 0) {
-               spin_unlock_irqrestore(&hwif->lock, flags);
-               ide_complete_drive_reset(drive, BLK_STS_IOERR);
-               return ide_stopped;
-       }
-
-       /*
-        * Note that we also set nIEN while resetting the device,
-        * to mask unwanted interrupts from the interface during the reset.
-        * However, due to the design of PC hardware, this will cause an
-        * immediate interrupt due to the edge transition it produces.
-        * This single interrupt gives us a "fast poll" for drives that
-        * recover from reset very quickly, saving us the first 50ms wait time.
-        */
-       /* set SRST and nIEN */
-       tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS);
-       /* more than enough time */
-       udelay(10);
-       /* clear SRST, leave nIEN (unless device is on the quirk list) */
-       tp_ops->write_devctl(hwif,
-               ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) |
-                ATA_DEVCTL_OBS);
-       /* more than enough time */
-       udelay(10);
-       hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
-       hwif->polling = 1;
-       __ide_set_handler(drive, &reset_pollfunc, HZ/20);
-
-       /*
-        * Some weird controller like resetting themselves to a strange
-        * state when the disks are reset this way. At least, the Winbond
-        * 553 documentation says that
-        */
-       port_ops = hwif->port_ops;
-       if (port_ops && port_ops->resetproc)
-               port_ops->resetproc(drive);
-
-       spin_unlock_irqrestore(&hwif->lock, flags);
-       return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-
-ide_startstop_t ide_do_reset(ide_drive_t *drive)
-{
-       return do_reset1(drive, 0);
-}
-EXPORT_SYMBOL(ide_do_reset);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
deleted file mode 100644 (file)
index f5a2870..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * IDE ATAPI floppy driver.
- *
- * Copyright (C) 1996-1999  Gadi Oxman <gadio@netvision.net.il>
- * Copyright (C) 2000-2002  Paul Bristow <paul@paulbristow.net>
- * Copyright (C) 2005       Bartlomiej Zolnierkiewicz
- *
- * This driver supports the following IDE floppy drives:
- *
- * LS-120/240 SuperDisk
- * Iomega Zip 100/250
- * Iomega PC Card Clik!/PocketZip
- *
- * For a historical changelog see
- * Documentation/ide/ChangeLog.ide-floppy.1996-2002
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-
-#include <scsi/scsi_ioctl.h>
-
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-
-#include "ide-floppy.h"
-
-/*
- * After each failed packet command we issue a request sense command and retry
- * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
- */
-#define IDEFLOPPY_MAX_PC_RETRIES       3
-
-/* format capacities descriptor codes */
-#define CAPACITY_INVALID       0x00
-#define CAPACITY_UNFORMATTED   0x01
-#define CAPACITY_CURRENT       0x02
-#define CAPACITY_NO_CARTRIDGE  0x03
-
-/*
- * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit
- * was apparently being deasserted before the unit was ready to receive data.
- */
-#define IDEFLOPPY_PC_DELAY     (HZ/20) /* default delay for ZIP 100 (50ms) */
-
-static int ide_floppy_callback(ide_drive_t *drive, int dsc)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct ide_atapi_pc *pc = drive->pc;
-       struct request *rq = pc->rq;
-       int uptodate = pc->error ? 0 : 1;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (drive->failed_pc == pc)
-               drive->failed_pc = NULL;
-
-       if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
-           blk_rq_is_scsi(rq))
-               uptodate = 1; /* FIXME */
-       else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
-
-               u8 *buf = bio_data(rq->bio);
-
-               if (!pc->error) {
-                       floppy->sense_key = buf[2] & 0x0F;
-                       floppy->asc = buf[12];
-                       floppy->ascq = buf[13];
-                       floppy->progress_indication = buf[15] & 0x80 ?
-                               (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
-
-                       if (drive->failed_pc)
-                               ide_debug_log(IDE_DBG_PC, "pc = %x",
-                                             drive->failed_pc->c[0]);
-
-                       ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
-                                     "ascq = %x", floppy->sense_key,
-                                     floppy->asc, floppy->ascq);
-               } else
-                       printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
-                              "Aborting request!\n");
-       }
-
-       if (ata_misc_request(rq))
-               scsi_req(rq)->result = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
-
-       return uptodate;
-}
-
-static void ide_floppy_report_error(struct ide_disk_obj *floppy,
-                                   struct ide_atapi_pc *pc)
-{
-       /* suppress error messages resulting from Medium not present */
-       if (floppy->sense_key == 0x02 &&
-           floppy->asc       == 0x3a &&
-           floppy->ascq      == 0x00)
-               return;
-
-       printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, "
-                       "asc = %2x, ascq = %2x\n",
-                       floppy->drive->name, pc->c[0], floppy->sense_key,
-                       floppy->asc, floppy->ascq);
-
-}
-
-static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive,
-                                          struct ide_cmd *cmd,
-                                          struct ide_atapi_pc *pc)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-
-       if (drive->failed_pc == NULL &&
-           pc->c[0] != GPCMD_REQUEST_SENSE)
-               drive->failed_pc = pc;
-
-       /* Set the current packet command */
-       drive->pc = pc;
-
-       if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
-               unsigned int done = blk_rq_bytes(drive->hwif->rq);
-
-               if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
-                       ide_floppy_report_error(floppy, pc);
-
-               /* Giving up */
-               pc->error = IDE_DRV_ERROR_GENERAL;
-
-               drive->failed_pc = NULL;
-               drive->pc_callback(drive, 0);
-               ide_complete_rq(drive, BLK_STS_IOERR, done);
-               return ide_stopped;
-       }
-
-       ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries);
-
-       pc->retries++;
-
-       return ide_issue_pc(drive, cmd);
-}
-
-void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
-{
-       ide_init_pc(pc);
-       pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
-       pc->c[7] = 255;
-       pc->c[8] = 255;
-       pc->req_xfer = 255;
-}
-
-/* A mode sense command is used to "sense" floppy parameters. */
-void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
-{
-       u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
-
-       ide_init_pc(pc);
-       pc->c[0] = GPCMD_MODE_SENSE_10;
-       pc->c[1] = 0;
-       pc->c[2] = page_code;
-
-       switch (page_code) {
-       case IDEFLOPPY_CAPABILITIES_PAGE:
-               length += 12;
-               break;
-       case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
-               length += 32;
-               break;
-       default:
-               printk(KERN_ERR PFX "unsupported page code in %s\n", __func__);
-       }
-       put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
-       pc->req_xfer = length;
-}
-
-static void idefloppy_create_rw_cmd(ide_drive_t *drive,
-                                   struct ide_atapi_pc *pc, struct request *rq,
-                                   unsigned long sector)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       int block = sector / floppy->bs_factor;
-       int blocks = blk_rq_sectors(rq) / floppy->bs_factor;
-       int cmd = rq_data_dir(rq);
-
-       ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks);
-
-       ide_init_pc(pc);
-       pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
-       put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
-       put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
-
-       memcpy(scsi_req(rq)->cmd, pc->c, 12);
-
-       pc->rq = rq;
-       if (cmd == WRITE)
-               pc->flags |= PC_FLAG_WRITING;
-
-       pc->flags |= PC_FLAG_DMA_OK;
-}
-
-static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
-               struct ide_atapi_pc *pc, struct request *rq)
-{
-       ide_init_pc(pc);
-       memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c));
-       pc->rq = rq;
-       if (blk_rq_bytes(rq)) {
-               pc->flags |= PC_FLAG_DMA_OK;
-               if (rq_data_dir(rq) == WRITE)
-                       pc->flags |= PC_FLAG_WRITING;
-       }
-}
-
-static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
-                                            struct request *rq, sector_t block)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct ide_cmd cmd;
-       struct ide_atapi_pc *pc;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]);
-
-       if (drive->debug_mask & IDE_DBG_RQ)
-               blk_dump_rq_flags(rq, (rq->rq_disk
-                                       ? rq->rq_disk->disk_name
-                                       : "dev?"));
-
-       if (scsi_req(rq)->result >= ERROR_MAX) {
-               if (drive->failed_pc) {
-                       ide_floppy_report_error(floppy, drive->failed_pc);
-                       drive->failed_pc = NULL;
-               } else
-                       printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
-
-               if (ata_misc_request(rq)) {
-                       scsi_req(rq)->result = 0;
-                       ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq));
-                       return ide_stopped;
-               } else
-                       goto out_end;
-       }
-
-       switch (req_op(rq)) {
-       default:
-               if (((long)blk_rq_pos(rq) % floppy->bs_factor) ||
-                   (blk_rq_sectors(rq) % floppy->bs_factor)) {
-                       printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
-                               drive->name);
-                       goto out_end;
-               }
-               pc = &floppy->queued_pc;
-               idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
-               break;
-       case REQ_OP_SCSI_IN:
-       case REQ_OP_SCSI_OUT:
-               pc = &floppy->queued_pc;
-               idefloppy_blockpc_cmd(floppy, pc, rq);
-               break;
-       case REQ_OP_DRV_IN:
-       case REQ_OP_DRV_OUT:
-               switch (ide_req(rq)->type) {
-               case ATA_PRIV_MISC:
-               case ATA_PRIV_SENSE:
-                       pc = (struct ide_atapi_pc *)ide_req(rq)->special;
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
-       ide_prep_sense(drive, rq);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       if (rq_data_dir(rq))
-               cmd.tf_flags |= IDE_TFLAG_WRITE;
-
-       cmd.rq = rq;
-
-       if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
-               ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
-               ide_map_sg(drive, &cmd);
-       }
-
-       pc->rq = rq;
-
-       return ide_floppy_issue_pc(drive, &cmd, pc);
-out_end:
-       drive->failed_pc = NULL;
-       if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0)
-               scsi_req(rq)->result = -EIO;
-       ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
-       return ide_stopped;
-}
-
-/*
- * Look at the flexible disk page parameters. We ignore the CHS capacity
- * parameters and use the LBA parameters instead.
- */
-static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive,
-                                            struct ide_atapi_pc *pc)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct gendisk *disk = floppy->disk;
-       u8 *page, buf[40];
-       int capacity, lba_capacity;
-       u16 transfer_rate, sector_size, cyls, rpm;
-       u8 heads, sectors;
-
-       ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
-
-       if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) {
-               printk(KERN_ERR PFX "Can't get flexible disk page params\n");
-               return 1;
-       }
-
-       if (buf[3] & 0x80)
-               drive->dev_flags |= IDE_DFLAG_WP;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_WP;
-
-       set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP));
-
-       page = &buf[8];
-
-       transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]);
-       sector_size   = be16_to_cpup((__be16 *)&buf[8 + 6]);
-       cyls          = be16_to_cpup((__be16 *)&buf[8 + 8]);
-       rpm           = be16_to_cpup((__be16 *)&buf[8 + 28]);
-       heads         = buf[8 + 4];
-       sectors       = buf[8 + 5];
-
-       capacity = cyls * heads * sectors * sector_size;
-
-       if (memcmp(page, &floppy->flexible_disk_page, 32))
-               printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, "
-                               "%d sector size, %d rpm\n",
-                               drive->name, capacity / 1024, cyls, heads,
-                               sectors, transfer_rate / 8, sector_size, rpm);
-
-       memcpy(&floppy->flexible_disk_page, page, 32);
-       drive->bios_cyl = cyls;
-       drive->bios_head = heads;
-       drive->bios_sect = sectors;
-       lba_capacity = floppy->blocks * floppy->block_size;
-
-       if (capacity < lba_capacity) {
-               printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d "
-                       "bytes, but the drive only handles %d\n",
-                       drive->name, lba_capacity, capacity);
-               floppy->blocks = floppy->block_size ?
-                       capacity / floppy->block_size : 0;
-               drive->capacity64 = floppy->blocks * floppy->bs_factor;
-       }
-
-       return 0;
-}
-
-/*
- * Determine if a media is present in the floppy drive, and if so, its LBA
- * capacity.
- */
-static int ide_floppy_get_capacity(ide_drive_t *drive)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct gendisk *disk = floppy->disk;
-       struct ide_atapi_pc pc;
-       u8 *cap_desc;
-       u8 pc_buf[256], header_len, desc_cnt;
-       int i, rc = 1, blocks, length;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       drive->bios_cyl = 0;
-       drive->bios_head = drive->bios_sect = 0;
-       floppy->blocks = 0;
-       floppy->bs_factor = 1;
-       drive->capacity64 = 0;
-
-       ide_floppy_create_read_capacity_cmd(&pc);
-       if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) {
-               printk(KERN_ERR PFX "Can't get floppy parameters\n");
-               return 1;
-       }
-       header_len = pc_buf[3];
-       cap_desc = &pc_buf[4];
-       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
-       for (i = 0; i < desc_cnt; i++) {
-               unsigned int desc_start = 4 + i*8;
-
-               blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
-               length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
-
-               ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
-                                            "%d sector size",
-                                            i, blocks * length / 1024,
-                                            blocks, length);
-
-               if (i)
-                       continue;
-               /*
-                * the code below is valid only for the 1st descriptor, ie i=0
-                */
-
-               switch (pc_buf[desc_start + 4] & 0x03) {
-               /* Clik! drive returns this instead of CAPACITY_CURRENT */
-               case CAPACITY_UNFORMATTED:
-                       if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
-                               /*
-                                * If it is not a clik drive, break out
-                                * (maintains previous driver behaviour)
-                                */
-                               break;
-                       fallthrough;
-               case CAPACITY_CURRENT:
-                       /* Normal Zip/LS-120 disks */
-                       if (memcmp(cap_desc, &floppy->cap_desc, 8))
-                               printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d "
-                                      "sector size\n",
-                                      drive->name, blocks * length / 1024,
-                                      blocks, length);
-                       memcpy(&floppy->cap_desc, cap_desc, 8);
-
-                       if (!length || length % 512) {
-                               printk(KERN_NOTICE PFX "%s: %d bytes block size"
-                                      " not supported\n", drive->name, length);
-                       } else {
-                               floppy->blocks = blocks;
-                               floppy->block_size = length;
-                               floppy->bs_factor = length / 512;
-                               if (floppy->bs_factor != 1)
-                                       printk(KERN_NOTICE PFX "%s: Warning: "
-                                              "non 512 bytes block size not "
-                                              "fully supported\n",
-                                              drive->name);
-                               drive->capacity64 =
-                                       floppy->blocks * floppy->bs_factor;
-                               rc = 0;
-                       }
-                       break;
-               case CAPACITY_NO_CARTRIDGE:
-                       /*
-                        * This is a KERN_ERR so it appears on screen
-                        * for the user to see
-                        */
-                       printk(KERN_ERR PFX "%s: No disk in drive\n",
-                              drive->name);
-                       break;
-               case CAPACITY_INVALID:
-                       printk(KERN_ERR PFX "%s: Invalid capacity for disk "
-                               "in drive\n", drive->name);
-                       break;
-               }
-               ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d",
-                                            pc_buf[desc_start + 4] & 0x03);
-       }
-
-       /* Clik! disk does not support get_flexible_disk_page */
-       if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
-               (void) ide_floppy_get_flexible_disk_page(drive, &pc);
-
-       return rc;
-}
-
-static void ide_floppy_setup(ide_drive_t *drive)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       u16 *id = drive->id;
-
-       drive->pc_callback       = ide_floppy_callback;
-
-       /*
-        * We used to check revisions here. At this point however I'm giving up.
-        * Just assume they are all broken, its easier.
-        *
-        * The actual reason for the workarounds was likely a driver bug after
-        * all rather than a firmware bug, and the workaround below used to hide
-        * it. It should be fixed as of version 1.9, but to be on the safe side
-        * we'll leave the limitation below for the 2.2.x tree.
-        */
-       if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI")) {
-               drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
-               /* This value will be visible in the /proc/ide/hdx/settings */
-               drive->pc_delay = IDEFLOPPY_PC_DELAY;
-               blk_queue_max_hw_sectors(drive->queue, 64);
-       }
-
-       /*
-        * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
-        * nasty clicking noises without it, so please don't remove this.
-        */
-       if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA Clik!")) {
-               blk_queue_max_hw_sectors(drive->queue, 64);
-               drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
-               /* IOMEGA Clik! drives do not support lock/unlock commands */
-               drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-       }
-
-       (void) ide_floppy_get_capacity(drive);
-
-       ide_proc_register_driver(drive, floppy->driver);
-}
-
-static void ide_floppy_flush(ide_drive_t *drive)
-{
-}
-
-static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk)
-{
-       int ret = 0;
-
-       if (ide_do_test_unit_ready(drive, disk))
-               ide_do_start_stop(drive, disk, 1);
-
-       ret = ide_floppy_get_capacity(drive);
-
-       set_capacity(disk, ide_gd_capacity(drive));
-
-       return ret;
-}
-
-const struct ide_disk_ops ide_atapi_disk_ops = {
-       .check          = ide_check_atapi_device,
-       .get_capacity   = ide_floppy_get_capacity,
-       .setup          = ide_floppy_setup,
-       .flush          = ide_floppy_flush,
-       .init_media     = ide_floppy_init_media,
-       .set_doorlock   = ide_set_media_lock,
-       .do_request     = ide_floppy_do_request,
-       .ioctl          = ide_floppy_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = ide_floppy_compat_ioctl,
-#endif
-};
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
deleted file mode 100644 (file)
index 8505a5f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_FLOPPY_H
-#define __IDE_FLOPPY_H
-
-#include "ide-gd.h"
-
-#ifdef CONFIG_IDE_GD_ATAPI
-/*
- * Pages of the SELECT SENSE / MODE SENSE packet commands.
- * See SFF-8070i spec.
- */
-#define        IDEFLOPPY_CAPABILITIES_PAGE     0x1b
-#define IDEFLOPPY_FLEXIBLE_DISK_PAGE   0x05
-
-/* IOCTLs used in low-level formatting. */
-#define        IDEFLOPPY_IOCTL_FORMAT_SUPPORTED        0x4600
-#define        IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY     0x4601
-#define        IDEFLOPPY_IOCTL_FORMAT_START            0x4602
-#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS    0x4603
-
-/* ide-floppy.c */
-extern const struct ide_disk_ops ide_atapi_disk_ops;
-void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
-void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
-
-/* ide-floppy_ioctl.c */
-int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
-                    unsigned int, unsigned long);
-int ide_floppy_compat_ioctl(ide_drive_t *, struct block_device *, fmode_t,
-                           unsigned int, unsigned long);
-
-#ifdef CONFIG_IDE_PROC_FS
-/* ide-floppy_proc.c */
-extern ide_proc_entry_t ide_floppy_proc[];
-extern const struct ide_proc_devset ide_floppy_settings[];
-#endif
-#else
-#define ide_floppy_proc                NULL
-#define ide_floppy_settings    NULL
-#endif
-
-#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
deleted file mode 100644 (file)
index 39a790a..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ide-floppy IOCTLs handling.
- */
-
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/compat.h>
-#include <linux/cdrom.h>
-#include <linux/mutex.h>
-
-#include <asm/unaligned.h>
-
-#include <scsi/scsi_ioctl.h>
-
-#include "ide-floppy.h"
-
-/*
- * Obtain the list of formattable capacities.
- * Very similar to ide_floppy_get_capacity, except that we push the capacity
- * descriptors to userland, instead of our own structures.
- *
- * Userland gives us the following structure:
- *
- * struct idefloppy_format_capacities {
- *     int nformats;
- *     struct {
- *             int nblocks;
- *             int blocksize;
- *     } formats[];
- * };
- *
- * userland initializes nformats to the number of allocated formats[] records.
- * On exit we set nformats to the number of records we've actually initialized.
- */
-
-static DEFINE_MUTEX(ide_floppy_ioctl_mutex);
-static int ide_floppy_get_format_capacities(ide_drive_t *drive,
-                                           struct ide_atapi_pc *pc,
-                                           int __user *arg)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       int i, blocks, length, u_array_size, u_index;
-       int __user *argp;
-       u8 pc_buf[256], header_len, desc_cnt;
-
-       if (get_user(u_array_size, arg))
-               return -EFAULT;
-
-       if (u_array_size <= 0)
-               return -EINVAL;
-
-       ide_floppy_create_read_capacity_cmd(pc);
-
-       if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) {
-               printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
-               return -EIO;
-       }
-
-       header_len = pc_buf[3];
-       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
-       u_index = 0;
-       argp = arg + 1;
-
-       /*
-        * We always skip the first capacity descriptor.  That's the current
-        * capacity.  We are interested in the remaining descriptors, the
-        * formattable capacities.
-        */
-       for (i = 1; i < desc_cnt; i++) {
-               unsigned int desc_start = 4 + i*8;
-
-               if (u_index >= u_array_size)
-                       break;  /* User-supplied buffer too small */
-
-               blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
-               length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
-
-               if (put_user(blocks, argp))
-                       return -EFAULT;
-
-               ++argp;
-
-               if (put_user(length, argp))
-                       return -EFAULT;
-
-               ++argp;
-
-               ++u_index;
-       }
-
-       if (put_user(u_index, arg))
-               return -EFAULT;
-
-       return 0;
-}
-
-static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc,
-                                             u8 *buf, int b, int l,
-                                             int flags)
-{
-       ide_init_pc(pc);
-       pc->c[0] = GPCMD_FORMAT_UNIT;
-       pc->c[1] = 0x17;
-
-       memset(buf, 0, 12);
-       buf[1] = 0xA2;
-       /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
-
-       if (flags & 1)                          /* Verify bit on... */
-               buf[1] ^= 0x20;                 /* ... turn off DCRT bit */
-       buf[3] = 8;
-
-       put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4]));
-       put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8]));
-       pc->req_xfer = 12;
-       pc->flags |= PC_FLAG_WRITING;
-}
-
-static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       u8 buf[20];
-
-       drive->atapi_flags &= ~IDE_AFLAG_SRFP;
-
-       ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE);
-       pc->flags |= PC_FLAG_SUPPRESS_ERROR;
-
-       if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
-               return 1;
-
-       if (buf[8 + 2] & 0x40)
-               drive->atapi_flags |= IDE_AFLAG_SRFP;
-
-       return 0;
-}
-
-static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                 int __user *arg)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       u8 buf[12];
-       int blocks, length, flags, err = 0;
-
-       if (floppy->openers > 1) {
-               /* Don't format if someone is using the disk */
-               drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
-               return -EBUSY;
-       }
-
-       drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
-
-       /*
-        * Send ATAPI_FORMAT_UNIT to the drive.
-        *
-        * Userland gives us the following structure:
-        *
-        * struct idefloppy_format_command {
-        *        int nblocks;
-        *        int blocksize;
-        *        int flags;
-        *        } ;
-        *
-        * flags is a bitmask, currently, the only defined flag is:
-        *
-        *        0x01 - verify media after format.
-        */
-       if (get_user(blocks, arg) ||
-                       get_user(length, arg+1) ||
-                       get_user(flags, arg+2)) {
-               err = -EFAULT;
-               goto out;
-       }
-
-       ide_floppy_get_sfrp_bit(drive, pc);
-       ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags);
-
-       if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
-               err = -EIO;
-
-out:
-       if (err)
-               drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
-       return err;
-}
-
-/*
- * Get ATAPI_FORMAT_UNIT progress indication.
- *
- * Userland gives a pointer to an int.  The int is set to a progress
- * indicator 0-65536, with 65536=100%.
- *
- * If the drive does not support format progress indication, we just check
- * the dsc bit, and return either 0 or 65536.
- */
-
-static int ide_floppy_get_format_progress(ide_drive_t *drive,
-                                         struct ide_atapi_pc *pc,
-                                         int __user *arg)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       u8 sense_buf[18];
-       int progress_indication = 0x10000;
-
-       if (drive->atapi_flags & IDE_AFLAG_SRFP) {
-               ide_create_request_sense_cmd(drive, pc);
-               if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf,
-                                     pc->req_xfer))
-                       return -EIO;
-
-               if (floppy->sense_key == 2 &&
-                   floppy->asc == 4 &&
-                   floppy->ascq == 4)
-                       progress_indication = floppy->progress_indication;
-
-               /* Else assume format_unit has finished, and we're at 0x10000 */
-       } else {
-               ide_hwif_t *hwif = drive->hwif;
-               unsigned long flags;
-               u8 stat;
-
-               local_irq_save(flags);
-               stat = hwif->tp_ops->read_status(hwif);
-               local_irq_restore(flags);
-
-               progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
-       }
-
-       if (put_user(progress_indication, arg))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                              unsigned long arg, unsigned int cmd)
-{
-       struct ide_disk_obj *floppy = drive->driver_data;
-       struct gendisk *disk = floppy->disk;
-       int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
-
-       if (floppy->openers > 1)
-               return -EBUSY;
-
-       ide_set_media_lock(drive, disk, prevent);
-
-       if (cmd == CDROMEJECT)
-               ide_do_start_stop(drive, disk, 2);
-
-       return 0;
-}
-
-static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc,
-                                  fmode_t mode, unsigned int cmd,
-                                  void __user *argp)
-{
-       switch (cmd) {
-       case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
-               return 0;
-       case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
-               return ide_floppy_get_format_capacities(drive, pc, argp);
-       case IDEFLOPPY_IOCTL_FORMAT_START:
-               if (!(mode & FMODE_WRITE))
-                       return -EPERM;
-               return ide_floppy_format_unit(drive, pc, (int __user *)argp);
-       case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
-               return ide_floppy_get_format_progress(drive, pc, argp);
-       default:
-               return -ENOTTY;
-       }
-}
-
-int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
-                    fmode_t mode, unsigned int cmd, unsigned long arg)
-{
-       struct ide_atapi_pc pc;
-       void __user *argp = (void __user *)arg;
-       int err;
-
-       mutex_lock(&ide_floppy_ioctl_mutex);
-       if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
-               err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
-               goto out;
-       }
-
-       err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
-       if (err != -ENOTTY)
-               goto out;
-
-       /*
-        * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
-        * and CDROM_SEND_PACKET (legacy) ioctls
-        */
-       if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-               err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-
-       if (err == -ENOTTY)
-               err = generic_ide_ioctl(drive, bdev, cmd, arg);
-
-out:
-       mutex_unlock(&ide_floppy_ioctl_mutex);
-       return err;
-}
-
-#ifdef CONFIG_COMPAT
-int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
-                           fmode_t mode, unsigned int cmd, unsigned long arg)
-{
-       struct ide_atapi_pc pc;
-       void __user *argp = compat_ptr(arg);
-       int err;
-
-       mutex_lock(&ide_floppy_ioctl_mutex);
-       if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
-               err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
-               goto out;
-       }
-
-       err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
-       if (err != -ENOTTY)
-               goto out;
-
-       /*
-        * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
-        * and CDROM_SEND_PACKET (legacy) ioctls
-        */
-       if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-               err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-
-       if (err == -ENOTTY)
-               err = generic_ide_ioctl(drive, bdev, cmd, arg);
-
-out:
-       mutex_unlock(&ide_floppy_ioctl_mutex);
-       return err;
-}
-#endif
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
deleted file mode 100644 (file)
index 7f697dd..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-
-#include "ide-floppy.h"
-
-static int idefloppy_capacity_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t*drive = (ide_drive_t *)m->private;
-
-       seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
-       return 0;
-}
-
-ide_proc_entry_t ide_floppy_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO, idefloppy_capacity_proc_show   },
-       { "geometry",   S_IFREG|S_IRUGO, ide_geometry_proc_show         },
-       {}
-};
-
-ide_devset_rw_field(bios_cyl, bios_cyl);
-ide_devset_rw_field(bios_head, bios_head);
-ide_devset_rw_field(bios_sect, bios_sect);
-ide_devset_rw_field(ticks, pc_delay);
-
-const struct ide_proc_devset ide_floppy_settings[] = {
-       IDE_PROC_DEVSET(bios_cyl,  0, 1023),
-       IDE_PROC_DEVSET(bios_head, 0,  255),
-       IDE_PROC_DEVSET(bios_sect, 0,   63),
-       IDE_PROC_DEVSET(ticks,     0,  255),
-       { NULL },
-};
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
deleted file mode 100644 (file)
index e2b6c82..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/mutex.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/dmi.h>
-#include <linux/slab.h>
-
-#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
-#define IDE_DISK_MINORS                (1 << PARTN_BITS)
-#else
-#define IDE_DISK_MINORS                0
-#endif
-
-#include "ide-disk.h"
-#include "ide-floppy.h"
-
-#define IDE_GD_VERSION "1.18"
-
-/* module parameters */
-static DEFINE_MUTEX(ide_gd_mutex);
-static unsigned long debug_mask;
-module_param(debug_mask, ulong, 0644);
-
-static DEFINE_MUTEX(ide_disk_ref_mutex);
-
-static void ide_disk_release(struct device *);
-
-static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
-{
-       struct ide_disk_obj *idkp = NULL;
-
-       mutex_lock(&ide_disk_ref_mutex);
-       idkp = ide_drv_g(disk, ide_disk_obj);
-       if (idkp) {
-               if (ide_device_get(idkp->drive))
-                       idkp = NULL;
-               else
-                       get_device(&idkp->dev);
-       }
-       mutex_unlock(&ide_disk_ref_mutex);
-       return idkp;
-}
-
-static void ide_disk_put(struct ide_disk_obj *idkp)
-{
-       ide_drive_t *drive = idkp->drive;
-
-       mutex_lock(&ide_disk_ref_mutex);
-       put_device(&idkp->dev);
-       ide_device_put(drive);
-       mutex_unlock(&ide_disk_ref_mutex);
-}
-
-sector_t ide_gd_capacity(ide_drive_t *drive)
-{
-       return drive->capacity64;
-}
-
-static int ide_gd_probe(ide_drive_t *);
-
-static void ide_gd_remove(ide_drive_t *drive)
-{
-       struct ide_disk_obj *idkp = drive->driver_data;
-       struct gendisk *g = idkp->disk;
-
-       ide_proc_unregister_driver(drive, idkp->driver);
-       device_del(&idkp->dev);
-       del_gendisk(g);
-       drive->disk_ops->flush(drive);
-
-       mutex_lock(&ide_disk_ref_mutex);
-       put_device(&idkp->dev);
-       mutex_unlock(&ide_disk_ref_mutex);
-}
-
-static void ide_disk_release(struct device *dev)
-{
-       struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-       struct gendisk *g = idkp->disk;
-
-       drive->disk_ops = NULL;
-       drive->driver_data = NULL;
-       g->private_data = NULL;
-       put_disk(g);
-       kfree(idkp);
-}
-
-/*
- * On HPA drives the capacity needs to be
- * reinitialized on resume otherwise the disk
- * can not be used and a hard reset is required
- */
-static void ide_gd_resume(ide_drive_t *drive)
-{
-       if (ata_id_hpa_enabled(drive->id))
-               (void)drive->disk_ops->get_capacity(drive);
-}
-
-static const struct dmi_system_id ide_coldreboot_table[] = {
-       {
-               /* Acer TravelMate 66x cuts power during reboot */
-               .ident   = "Acer TravelMate 660",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
-               },
-       },
-
-       { }     /* terminate list */
-};
-
-static void ide_gd_shutdown(ide_drive_t *drive)
-{
-#ifdef CONFIG_ALPHA
-       /* On Alpha, halt(8) doesn't actually turn the machine off,
-          it puts you into the sort of firmware monitor. Typically,
-          it's used to boot another kernel image, so it's not much
-          different from reboot(8). Therefore, we don't need to
-          spin down the disk in this case, especially since Alpha
-          firmware doesn't handle disks in standby mode properly.
-          On the other hand, it's reasonably safe to turn the power
-          off when the shutdown process reaches the firmware prompt,
-          as the firmware initialization takes rather long time -
-          at least 10 seconds, which should be sufficient for
-          the disk to expire its write cache. */
-       if (system_state != SYSTEM_POWER_OFF) {
-#else
-       if (system_state == SYSTEM_RESTART &&
-               !dmi_check_system(ide_coldreboot_table)) {
-#endif
-               drive->disk_ops->flush(drive);
-               return;
-       }
-
-       printk(KERN_INFO "Shutdown: %s\n", drive->name);
-
-       drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
-{
-       return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
-}
-
-static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
-{
-       return (drive->media == ide_disk) ? ide_disk_settings
-                                         : ide_floppy_settings;
-}
-#endif
-
-static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
-                                        struct request *rq, sector_t sector)
-{
-       return drive->disk_ops->do_request(drive, rq, sector);
-}
-
-static struct ide_driver ide_gd_driver = {
-       .gen_driver = {
-               .owner          = THIS_MODULE,
-               .name           = "ide-gd",
-               .bus            = &ide_bus_type,
-       },
-       .probe                  = ide_gd_probe,
-       .remove                 = ide_gd_remove,
-       .resume                 = ide_gd_resume,
-       .shutdown               = ide_gd_shutdown,
-       .version                = IDE_GD_VERSION,
-       .do_request             = ide_gd_do_request,
-#ifdef CONFIG_IDE_PROC_FS
-       .proc_entries           = ide_disk_proc_entries,
-       .proc_devsets           = ide_disk_proc_devsets,
-#endif
-};
-
-static int ide_gd_open(struct block_device *bdev, fmode_t mode)
-{
-       struct gendisk *disk = bdev->bd_disk;
-       struct ide_disk_obj *idkp;
-       ide_drive_t *drive;
-       int ret = 0;
-
-       idkp = ide_disk_get(disk);
-       if (idkp == NULL)
-               return -ENXIO;
-
-       drive = idkp->drive;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       idkp->openers++;
-
-       if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
-               drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
-               /* Just in case */
-
-               ret = drive->disk_ops->init_media(drive, disk);
-
-               /*
-                * Allow O_NDELAY to open a drive without a disk, or with an
-                * unreadable disk, so that we can get the format capacity
-                * of the drive or begin the format - Sam
-                */
-               if (ret && (mode & FMODE_NDELAY) == 0) {
-                       ret = -EIO;
-                       goto out_put_idkp;
-               }
-
-               if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
-                       ret = -EROFS;
-                       goto out_put_idkp;
-               }
-
-               /*
-                * Ignore the return code from door_lock,
-                * since the open() has already succeeded,
-                * and the door_lock is irrelevant at this point.
-                */
-               drive->disk_ops->set_doorlock(drive, disk, 1);
-               if (__invalidate_device(bdev, true))
-                       pr_warn("VFS: busy inodes on changed media %s\n",
-                               bdev->bd_disk->disk_name);
-               drive->disk_ops->get_capacity(drive);
-               set_capacity(disk, ide_gd_capacity(drive));
-               set_bit(GD_NEED_PART_SCAN, &disk->state);
-       } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
-               ret = -EBUSY;
-               goto out_put_idkp;
-       }
-       return 0;
-
-out_put_idkp:
-       idkp->openers--;
-       ide_disk_put(idkp);
-       return ret;
-}
-
-static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
-       int ret;
-
-       mutex_lock(&ide_gd_mutex);
-       ret = ide_gd_open(bdev, mode);
-       mutex_unlock(&ide_gd_mutex);
-
-       return ret;
-}
-
-
-static void ide_gd_release(struct gendisk *disk, fmode_t mode)
-{
-       struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       mutex_lock(&ide_gd_mutex);
-       if (idkp->openers == 1)
-               drive->disk_ops->flush(drive);
-
-       if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
-               drive->disk_ops->set_doorlock(drive, disk, 0);
-               drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
-       }
-
-       idkp->openers--;
-
-       ide_disk_put(idkp);
-       mutex_unlock(&ide_gd_mutex);
-}
-
-static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-       struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-
-       geo->heads = drive->bios_head;
-       geo->sectors = drive->bios_sect;
-       geo->cylinders = (u16)drive->bios_cyl; /* truncate */
-       return 0;
-}
-
-static void ide_gd_unlock_native_capacity(struct gendisk *disk)
-{
-       struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-       const struct ide_disk_ops *disk_ops = drive->disk_ops;
-
-       if (disk_ops->unlock_native_capacity)
-               disk_ops->unlock_native_capacity(drive);
-}
-
-static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
-                            unsigned int cmd, unsigned long arg)
-{
-       struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-
-       return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
-}
-
-#ifdef CONFIG_COMPAT
-static int ide_gd_compat_ioctl(struct block_device *bdev, fmode_t mode,
-                              unsigned int cmd, unsigned long arg)
-{
-       struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
-       ide_drive_t *drive = idkp->drive;
-
-       if (!drive->disk_ops->compat_ioctl)
-               return -ENOIOCTLCMD;
-
-       return drive->disk_ops->compat_ioctl(drive, bdev, mode, cmd, arg);
-}
-#endif
-
-static const struct block_device_operations ide_gd_ops = {
-       .owner                  = THIS_MODULE,
-       .open                   = ide_gd_unlocked_open,
-       .release                = ide_gd_release,
-       .ioctl                  = ide_gd_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl           = ide_gd_compat_ioctl,
-#endif
-       .getgeo                 = ide_gd_getgeo,
-       .unlock_native_capacity = ide_gd_unlock_native_capacity,
-};
-
-static int ide_gd_probe(ide_drive_t *drive)
-{
-       const struct ide_disk_ops *disk_ops = NULL;
-       struct ide_disk_obj *idkp;
-       struct gendisk *g;
-
-       /* strstr("foo", "") is non-NULL */
-       if (!strstr("ide-gd", drive->driver_req))
-               goto failed;
-
-#ifdef CONFIG_IDE_GD_ATA
-       if (drive->media == ide_disk)
-               disk_ops = &ide_ata_disk_ops;
-#endif
-#ifdef CONFIG_IDE_GD_ATAPI
-       if (drive->media == ide_floppy)
-               disk_ops = &ide_atapi_disk_ops;
-#endif
-       if (disk_ops == NULL)
-               goto failed;
-
-       if (disk_ops->check(drive, DRV_NAME) == 0) {
-               printk(KERN_ERR PFX "%s: not supported by this driver\n",
-                       drive->name);
-               goto failed;
-       }
-
-       idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
-       if (!idkp) {
-               printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
-                       drive->name);
-               goto failed;
-       }
-
-       g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
-       if (!g)
-               goto out_free_idkp;
-
-       ide_init_disk(g, drive);
-
-       idkp->dev.parent = &drive->gendev;
-       idkp->dev.release = ide_disk_release;
-       dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev));
-
-       if (device_register(&idkp->dev))
-               goto out_free_disk;
-
-       idkp->drive = drive;
-       idkp->driver = &ide_gd_driver;
-       idkp->disk = g;
-
-       g->private_data = &idkp->driver;
-
-       drive->driver_data = idkp;
-       drive->debug_mask = debug_mask;
-       drive->disk_ops = disk_ops;
-
-       disk_ops->setup(drive);
-
-       set_capacity(g, ide_gd_capacity(drive));
-
-       g->minors = IDE_DISK_MINORS;
-       g->flags |= GENHD_FL_EXT_DEVT;
-       if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
-               g->flags = GENHD_FL_REMOVABLE;
-       g->fops = &ide_gd_ops;
-       g->events = DISK_EVENT_MEDIA_CHANGE;
-       device_add_disk(&drive->gendev, g, NULL);
-       return 0;
-
-out_free_disk:
-       put_disk(g);
-out_free_idkp:
-       kfree(idkp);
-failed:
-       return -ENODEV;
-}
-
-static int __init ide_gd_init(void)
-{
-       printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
-       return driver_register(&ide_gd_driver.gen_driver);
-}
-
-static void __exit ide_gd_exit(void)
-{
-       driver_unregister(&ide_gd_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-disk*");
-MODULE_ALIAS("ide-disk");
-MODULE_ALIAS("ide:*m-floppy*");
-MODULE_ALIAS("ide-floppy");
-module_init(ide_gd_init);
-module_exit(ide_gd_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");
diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h
deleted file mode 100644 (file)
index af3fe18..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_GD_H
-#define __IDE_GD_H
-
-#define DRV_NAME "ide-gd"
-#define PFX DRV_NAME ": "
-
-/* define to see debug info */
-#define IDE_GD_DEBUG_LOG       0
-
-#if IDE_GD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-struct ide_disk_obj {
-       ide_drive_t             *drive;
-       struct ide_driver       *driver;
-       struct gendisk          *disk;
-       struct device           dev;
-       unsigned int            openers;        /* protected by BKL for now */
-
-       /* used for blk_{fs,pc}_request() requests */
-       struct ide_atapi_pc queued_pc;
-
-       /* Last error information */
-       u8 sense_key, asc, ascq;
-
-       int progress_indication;
-
-       /* Device information */
-       /* Current format */
-       int blocks, block_size, bs_factor;
-       /* Last format capacity descriptor */
-       u8 cap_desc[8];
-       /* Copy of the flexible disk page */
-       u8 flexible_disk_page[32];
-};
-
-sector_t ide_gd_capacity(ide_drive_t *);
-
-#endif /* __IDE_GD_H */
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
deleted file mode 100644 (file)
index 80c0d69..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * generic/default IDE host driver
- *
- * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz
- * This code was split off from ide.c.  See it for original copyrights.
- *
- * May be copied or modified under the terms of the GNU General Public License.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-#include <linux/pci_ids.h>
-
-/* FIXME: convert arm to use ide_platform host driver */
-#ifdef CONFIG_ARM
-#include <asm/irq.h>
-#endif
-
-#define DRV_NAME       "ide_generic"
-
-static int probe_mask;
-module_param(probe_mask, int, 0);
-MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
-
-static const struct ide_port_info ide_generic_port_info = {
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .chipset                = ide_generic,
-};
-
-#ifdef CONFIG_ARM
-static const u16 legacy_bases[] = { 0x1f0 };
-static const int legacy_irqs[]  = { IRQ_HARDDISK };
-#elif defined(CONFIG_ALPHA)
-static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 };
-static const int legacy_irqs[]  = { 14, 15, 11, 10 };
-#else
-static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
-static const int legacy_irqs[]  = { 14, 15, 11, 10, 8, 12 };
-#endif
-
-static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
-{
-#ifdef CONFIG_PCI
-       struct pci_dev *p = NULL;
-       u16 val;
-
-       for_each_pci_dev(p) {
-               if (pci_resource_start(p, 0) == 0x1f0)
-                       *primary = 1;
-               if (pci_resource_start(p, 2) == 0x170)
-                       *secondary = 1;
-
-               /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
-               if (p->vendor == PCI_VENDOR_ID_CYRIX &&
-                   (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
-                    p->device == PCI_DEVICE_ID_CYRIX_5520))
-                       *primary = *secondary = 1;
-
-               /* Intel MPIIX - PIO ATA on non PCI side of bridge */
-               if (p->vendor == PCI_VENDOR_ID_INTEL &&
-                   p->device == PCI_DEVICE_ID_INTEL_82371MX) {
-                       pci_read_config_word(p, 0x6C, &val);
-                       if (val & 0x8000) {
-                               /* ATA port enabled */
-                               if (val & 0x4000)
-                                       *secondary = 1;
-                               else
-                                       *primary = 1;
-                       }
-               }
-       }
-#endif
-}
-
-static int __init ide_generic_init(void)
-{
-       struct ide_hw hw, *hws[] = { &hw };
-       unsigned long io_addr;
-       int i, rc = 0, primary = 0, secondary = 0;
-
-       ide_generic_check_pci_legacy_iobases(&primary, &secondary);
-
-       if (!probe_mask) {
-               printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
-                    "module parameter for probing all legacy ISA IDE ports\n");
-
-               if (primary == 0)
-                       probe_mask |= 0x1;
-
-               if (secondary == 0)
-                       probe_mask |= 0x2;
-       } else
-               printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
-                       "upon user request\n");
-
-       for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
-               io_addr = legacy_bases[i];
-
-               if ((probe_mask & (1 << i)) && io_addr) {
-                       if (!request_region(io_addr, 8, DRV_NAME)) {
-                               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
-                                               "not free.\n",
-                                               DRV_NAME, io_addr, io_addr + 7);
-                               rc = -EBUSY;
-                               continue;
-                       }
-
-                       if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
-                               printk(KERN_ERR "%s: I/O resource 0x%lX "
-                                               "not free.\n",
-                                               DRV_NAME, io_addr + 0x206);
-                               release_region(io_addr, 8);
-                               rc = -EBUSY;
-                               continue;
-                       }
-
-                       memset(&hw, 0, sizeof(hw));
-                       ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
-#ifdef CONFIG_IA64
-                       hw.irq = isa_irq_to_vector(legacy_irqs[i]);
-#else
-                       hw.irq = legacy_irqs[i];
-#endif
-                       rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
-                       if (rc) {
-                               release_region(io_addr + 0x206, 1);
-                               release_region(io_addr, 8);
-                       }
-               }
-       }
-
-       return rc;
-}
-
-module_init(ide_generic_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c
deleted file mode 100644 (file)
index 94bdcf1..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-
-#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
-    defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
-#include <asm/ide.h>
-#else
-#include <asm-generic/ide_iops.h>
-#endif
-
-/*
- *     Conventional PIO operations for ATA devices
- */
-
-static u8 ide_inb(unsigned long port)
-{
-       return (u8) inb(port);
-}
-
-static void ide_outb(u8 val, unsigned long port)
-{
-       outb(val, port);
-}
-
-/*
- *     MMIO operations, typically used for SATA controllers
- */
-
-static u8 ide_mm_inb(unsigned long port)
-{
-       return (u8) readb((void __iomem *) port);
-}
-
-static void ide_mm_outb(u8 value, unsigned long port)
-{
-       writeb(value, (void __iomem *) port);
-}
-
-void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
-       else
-               outb(cmd, hwif->io_ports.command_addr);
-}
-EXPORT_SYMBOL_GPL(ide_exec_command);
-
-u8 ide_read_status(ide_hwif_t *hwif)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return readb((void __iomem *)hwif->io_ports.status_addr);
-       else
-               return inb(hwif->io_ports.status_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_status);
-
-u8 ide_read_altstatus(ide_hwif_t *hwif)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return readb((void __iomem *)hwif->io_ports.ctl_addr);
-       else
-               return inb(hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_altstatus);
-
-void ide_write_devctl(ide_hwif_t *hwif, u8 ctl)
-{
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
-       else
-               outb(ctl, hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_write_devctl);
-
-void ide_dev_select(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 select = drive->select | ATA_DEVICE_OBS;
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               writeb(select, (void __iomem *)hwif->io_ports.device_addr);
-       else
-               outb(select, hwif->io_ports.device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_dev_select);
-
-void ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       void (*tf_outb)(u8 addr, unsigned long port);
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       if (mmio)
-               tf_outb = ide_mm_outb;
-       else
-               tf_outb = ide_outb;
-
-       if (valid & IDE_VALID_FEATURE)
-               tf_outb(tf->feature, io_ports->feature_addr);
-       if (valid & IDE_VALID_NSECT)
-               tf_outb(tf->nsect, io_ports->nsect_addr);
-       if (valid & IDE_VALID_LBAL)
-               tf_outb(tf->lbal, io_ports->lbal_addr);
-       if (valid & IDE_VALID_LBAM)
-               tf_outb(tf->lbam, io_ports->lbam_addr);
-       if (valid & IDE_VALID_LBAH)
-               tf_outb(tf->lbah, io_ports->lbah_addr);
-       if (valid & IDE_VALID_DEVICE)
-               tf_outb(tf->device, io_ports->device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_tf_load);
-
-void ide_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       u8 (*tf_inb)(unsigned long port);
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       if (mmio)
-               tf_inb  = ide_mm_inb;
-       else
-               tf_inb  = ide_inb;
-
-       if (valid & IDE_VALID_ERROR)
-               tf->error  = tf_inb(io_ports->feature_addr);
-       if (valid & IDE_VALID_NSECT)
-               tf->nsect  = tf_inb(io_ports->nsect_addr);
-       if (valid & IDE_VALID_LBAL)
-               tf->lbal   = tf_inb(io_ports->lbal_addr);
-       if (valid & IDE_VALID_LBAM)
-               tf->lbam   = tf_inb(io_ports->lbam_addr);
-       if (valid & IDE_VALID_LBAH)
-               tf->lbah   = tf_inb(io_ports->lbah_addr);
-       if (valid & IDE_VALID_DEVICE)
-               tf->device = tf_inb(io_ports->device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_tf_read);
-
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static void ata_vlb_sync(unsigned long port)
-{
-       (void)inb(port);
-       (void)inb(port);
-       (void)inb(port);
-}
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd len is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
-                   unsigned int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long data_addr = io_ports->data_addr;
-       unsigned int words = (len + 1) >> 1;
-       u8 io_32bit = drive->io_32bit;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       if (io_32bit) {
-               unsigned long flags;
-
-               if ((io_32bit & 2) && !mmio) {
-                       local_irq_save(flags);
-                       ata_vlb_sync(io_ports->nsect_addr);
-               }
-
-               words >>= 1;
-               if (mmio)
-                       __ide_mm_insl((void __iomem *)data_addr, buf, words);
-               else
-                       insl(data_addr, buf, words);
-
-               if ((io_32bit & 2) && !mmio)
-                       local_irq_restore(flags);
-
-               if (((len + 1) & 3) < 2)
-                       return;
-
-               buf += len & ~3;
-               words = 1;
-       }
-
-       if (mmio)
-               __ide_mm_insw((void __iomem *)data_addr, buf, words);
-       else
-               insw(data_addr, buf, words);
-}
-EXPORT_SYMBOL_GPL(ide_input_data);
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
-                    unsigned int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long data_addr = io_ports->data_addr;
-       unsigned int words = (len + 1) >> 1;
-       u8 io_32bit = drive->io_32bit;
-       u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
-       if (io_32bit) {
-               unsigned long flags;
-
-               if ((io_32bit & 2) && !mmio) {
-                       local_irq_save(flags);
-                       ata_vlb_sync(io_ports->nsect_addr);
-               }
-
-               words >>= 1;
-               if (mmio)
-                       __ide_mm_outsl((void __iomem *)data_addr, buf, words);
-               else
-                       outsl(data_addr, buf, words);
-
-               if ((io_32bit & 2) && !mmio)
-                       local_irq_restore(flags);
-
-               if (((len + 1) & 3) < 2)
-                       return;
-
-               buf += len & ~3;
-               words = 1;
-       }
-
-       if (mmio)
-               __ide_mm_outsw((void __iomem *)data_addr, buf, words);
-       else
-               outsw(data_addr, buf, words);
-}
-EXPORT_SYMBOL_GPL(ide_output_data);
-
-const struct ide_tp_ops default_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_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,
-};
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
deleted file mode 100644 (file)
index 4867b67..0000000
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- *     IDE I/O functions
- *
- *     Basic PIO and command management functionality.
- *
- * This code was split off from ide.c. See ide.c for history and original
- * copyrights.
- *
- * 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, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/reboot.h>
-#include <linux/cdrom.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/scatterlist.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
-              unsigned int nr_bytes)
-{
-       /*
-        * decide whether to reenable DMA -- 3 is a random magic for now,
-        * if we DMA timeout more than 3 times, just stay in PIO
-        */
-       if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) &&
-           drive->retry_pio <= 3) {
-               drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY;
-               ide_dma_on(drive);
-       }
-
-       if (!blk_update_request(rq, error, nr_bytes)) {
-               if (rq == drive->sense_rq) {
-                       drive->sense_rq = NULL;
-                       drive->sense_rq_active = false;
-               }
-
-               __blk_mq_end_request(rq, error);
-               return 0;
-       }
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(ide_end_rq);
-
-void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
-{
-       const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
-       struct ide_taskfile *tf = &cmd->tf;
-       struct request *rq = cmd->rq;
-       u8 tf_cmd = tf->command;
-
-       tf->error = err;
-       tf->status = stat;
-
-       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
-               u8 data[2];
-
-               tp_ops->input_data(drive, cmd, data, 2);
-
-               cmd->tf.data  = data[0];
-               cmd->hob.data = data[1];
-       }
-
-       ide_tf_readback(drive, cmd);
-
-       if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
-           tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
-               if (tf->lbal != 0xc4) {
-                       printk(KERN_ERR "%s: head unload failed!\n",
-                              drive->name);
-                       ide_tf_dump(drive->name, cmd);
-               } else
-                       drive->dev_flags |= IDE_DFLAG_PARKED;
-       }
-
-       if (rq && ata_taskfile_request(rq)) {
-               struct ide_cmd *orig_cmd = ide_req(rq)->special;
-
-               if (cmd->tf_flags & IDE_TFLAG_DYN)
-                       kfree(orig_cmd);
-               else if (cmd != orig_cmd)
-                       memcpy(orig_cmd, cmd, sizeof(*cmd));
-       }
-}
-
-int ide_complete_rq(ide_drive_t *drive, blk_status_t error, unsigned int nr_bytes)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->rq;
-       int rc;
-
-       /*
-        * if failfast is set on a request, override number of sectors
-        * and complete the whole request right now
-        */
-       if (blk_noretry_request(rq) && error)
-               nr_bytes = blk_rq_sectors(rq) << 9;
-
-       rc = ide_end_rq(drive, rq, error, nr_bytes);
-       if (rc == 0)
-               hwif->rq = NULL;
-
-       return rc;
-}
-EXPORT_SYMBOL(ide_complete_rq);
-
-void ide_kill_rq(ide_drive_t *drive, struct request *rq)
-{
-       u8 drv_req = ata_misc_request(rq) && rq->rq_disk;
-       u8 media = drive->media;
-
-       drive->failed_pc = NULL;
-
-       if ((media == ide_floppy || media == ide_tape) && drv_req) {
-               scsi_req(rq)->result = 0;
-       } else {
-               if (media == ide_tape)
-                       scsi_req(rq)->result = IDE_DRV_ERROR_GENERAL;
-               else if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0)
-                       scsi_req(rq)->result = -EIO;
-       }
-
-       ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
-}
-
-static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
-       tf->nsect   = drive->sect;
-       tf->lbal    = drive->sect;
-       tf->lbam    = drive->cyl;
-       tf->lbah    = drive->cyl >> 8;
-       tf->device  = (drive->head - 1) | drive->select;
-       tf->command = ATA_CMD_INIT_DEV_PARAMS;
-}
-
-static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
-       tf->nsect   = drive->sect;
-       tf->command = ATA_CMD_RESTORE;
-}
-
-static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
-       tf->nsect   = drive->mult_req;
-       tf->command = ATA_CMD_SET_MULTI;
-}
-
-/**
- *     do_special              -       issue some special commands
- *     @drive: drive the command is for
- *
- *     do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
- *     ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
- */
-
-static ide_startstop_t do_special(ide_drive_t *drive)
-{
-       struct ide_cmd cmd;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__,
-               drive->special_flags);
-#endif
-       if (drive->media != ide_disk) {
-               drive->special_flags = 0;
-               drive->mult_req = 0;
-               return ide_stopped;
-       }
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.protocol = ATA_PROT_NODATA;
-
-       if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) {
-               drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY;
-               ide_tf_set_specify_cmd(drive, &cmd.tf);
-       } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) {
-               drive->special_flags &= ~IDE_SFLAG_RECALIBRATE;
-               ide_tf_set_restore_cmd(drive, &cmd.tf);
-       } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) {
-               drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE;
-               ide_tf_set_setmult_cmd(drive, &cmd.tf);
-       } else
-               BUG();
-
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       cmd.tf_flags = IDE_TFLAG_CUSTOM_HANDLER;
-
-       do_rw_taskfile(drive, &cmd);
-
-       return ide_started;
-}
-
-void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct scatterlist *sg = hwif->sg_table, *last_sg = NULL;
-       struct request *rq = cmd->rq;
-
-       cmd->sg_nents = __blk_rq_map_sg(drive->queue, rq, sg, &last_sg);
-       if (blk_rq_bytes(rq) && (blk_rq_bytes(rq) & rq->q->dma_pad_mask))
-               last_sg->length +=
-                       (rq->q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
-}
-EXPORT_SYMBOL_GPL(ide_map_sg);
-
-void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes)
-{
-       cmd->nbytes = cmd->nleft = nr_bytes;
-       cmd->cursg_ofs = 0;
-       cmd->cursg = NULL;
-}
-EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
-
-/**
- *     execute_drive_command   -       issue special drive command
- *     @drive: the drive to issue the command on
- *     @rq: the request structure holding the command
- *
- *     execute_drive_cmd() issues a special drive command,  usually 
- *     initiated by ioctl() from the external hdparm program. The
- *     command can be a drive command, drive task or taskfile 
- *     operation. Weirdly you can call it with NULL to wait for
- *     all commands to finish. Don't do this as that is due to change
- */
-
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
-               struct request *rq)
-{
-       struct ide_cmd *cmd = ide_req(rq)->special;
-
-       if (cmd) {
-               if (cmd->protocol == ATA_PROT_PIO) {
-                       ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9);
-                       ide_map_sg(drive, cmd);
-               }
-
-               return do_rw_taskfile(drive, cmd);
-       }
-
-       /*
-        * NULL is actually a valid way of waiting for
-        * all current requests to be flushed from the queue.
-        */
-#ifdef DEBUG
-       printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
-       scsi_req(rq)->result = 0;
-       ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq));
-
-       return ide_stopped;
-}
-
-static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
-{
-       u8 cmd = scsi_req(rq)->cmd[0];
-
-       switch (cmd) {
-       case REQ_PARK_HEADS:
-       case REQ_UNPARK_HEADS:
-               return ide_do_park_unpark(drive, rq);
-       case REQ_DEVSET_EXEC:
-               return ide_do_devset(drive, rq);
-       case REQ_DRIVE_RESET:
-               return ide_do_reset(drive);
-       default:
-               BUG();
-       }
-}
-
-/**
- *     start_request   -       start of I/O and command issuing for IDE
- *
- *     start_request() initiates handling of a new I/O request. It
- *     accepts commands and I/O (read/write) requests.
- *
- *     FIXME: this function needs a rename
- */
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
-{
-       ide_startstop_t startstop;
-
-#ifdef DEBUG
-       printk("%s: start_request: current=0x%08lx\n",
-               drive->hwif->name, (unsigned long) rq);
-#endif
-
-       /* bail early if we've exceeded max_failures */
-       if (drive->max_failures && (drive->failures > drive->max_failures)) {
-               rq->rq_flags |= RQF_FAILED;
-               goto kill_rq;
-       }
-
-       if (drive->prep_rq && !drive->prep_rq(drive, rq))
-               return ide_stopped;
-
-       if (ata_pm_request(rq))
-               ide_check_pm_state(drive, rq);
-
-       drive->hwif->tp_ops->dev_select(drive);
-       if (ide_wait_stat(&startstop, drive, drive->ready_stat,
-                         ATA_BUSY | ATA_DRQ, WAIT_READY)) {
-               printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
-               return startstop;
-       }
-
-       if (drive->special_flags == 0) {
-               struct ide_driver *drv;
-
-               /*
-                * We reset the drive so we need to issue a SETFEATURES.
-                * Do it _after_ do_special() restored device parameters.
-                */
-               if (drive->current_speed == 0xff)
-                       ide_config_drive_speed(drive, drive->desired_speed);
-
-               if (ata_taskfile_request(rq))
-                       return execute_drive_cmd(drive, rq);
-               else if (ata_pm_request(rq)) {
-                       struct ide_pm_state *pm = ide_req(rq)->special;
-#ifdef DEBUG_PM
-                       printk("%s: start_power_step(step: %d)\n",
-                               drive->name, pm->pm_step);
-#endif
-                       startstop = ide_start_power_step(drive, rq);
-                       if (startstop == ide_stopped &&
-                           pm->pm_step == IDE_PM_COMPLETED)
-                               ide_complete_pm_rq(drive, rq);
-                       return startstop;
-               } else if (!rq->rq_disk && ata_misc_request(rq))
-                       /*
-                        * TODO: Once all ULDs have been modified to
-                        * check for specific op codes rather than
-                        * blindly accepting any special request, the
-                        * check for ->rq_disk above may be replaced
-                        * by a more suitable mechanism or even
-                        * dropped entirely.
-                        */
-                       return ide_special_rq(drive, rq);
-
-               drv = *(struct ide_driver **)rq->rq_disk->private_data;
-
-               return drv->do_request(drive, rq, blk_rq_pos(rq));
-       }
-       return do_special(drive);
-kill_rq:
-       ide_kill_rq(drive, rq);
-       return ide_stopped;
-}
-
-/**
- *     ide_stall_queue         -       pause an IDE device
- *     @drive: drive to stall
- *     @timeout: time to stall for (jiffies)
- *
- *     ide_stall_queue() can be used by a drive to give excess bandwidth back
- *     to the port by sleeping for timeout jiffies.
- */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
-{
-       if (timeout > WAIT_WORSTCASE)
-               timeout = WAIT_WORSTCASE;
-       drive->sleep = timeout + jiffies;
-       drive->dev_flags |= IDE_DFLAG_SLEEPING;
-}
-EXPORT_SYMBOL(ide_stall_queue);
-
-static inline int ide_lock_port(ide_hwif_t *hwif)
-{
-       if (hwif->busy)
-               return 1;
-
-       hwif->busy = 1;
-
-       return 0;
-}
-
-static inline void ide_unlock_port(ide_hwif_t *hwif)
-{
-       hwif->busy = 0;
-}
-
-static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)
-{
-       int rc = 0;
-
-       if (host->host_flags & IDE_HFLAG_SERIALIZE) {
-               rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy);
-               if (rc == 0) {
-                       if (host->get_lock)
-                               host->get_lock(ide_intr, hwif);
-               }
-       }
-       return rc;
-}
-
-static inline void ide_unlock_host(struct ide_host *host)
-{
-       if (host->host_flags & IDE_HFLAG_SERIALIZE) {
-               if (host->release_lock)
-                       host->release_lock();
-               clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy);
-       }
-}
-
-void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
-{
-       struct request_queue *q = drive->queue;
-
-       /* Use 3ms as that was the old plug delay */
-       if (rq) {
-               blk_mq_requeue_request(rq, false);
-               blk_mq_delay_kick_requeue_list(q, 3);
-       } else
-               blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
-}
-
-blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq,
-                         bool local_requeue)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_host *host = hwif->host;
-       ide_startstop_t startstop;
-
-       if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_DONTPREP)) {
-               rq->rq_flags |= RQF_DONTPREP;
-               ide_req(rq)->special = NULL;
-       }
-
-       /* HLD do_request() callback might sleep, make sure it's okay */
-       might_sleep();
-
-       if (ide_lock_host(host, hwif))
-               return BLK_STS_DEV_RESOURCE;
-
-       spin_lock_irq(&hwif->lock);
-
-       if (!ide_lock_port(hwif)) {
-               ide_hwif_t *prev_port;
-
-               WARN_ON_ONCE(hwif->rq);
-repeat:
-               prev_port = hwif->host->cur_port;
-               if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
-                   time_after(drive->sleep, jiffies)) {
-                       ide_unlock_port(hwif);
-                       goto plug_device;
-               }
-
-               if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
-                   hwif != prev_port) {
-                       ide_drive_t *cur_dev =
-                               prev_port ? prev_port->cur_dev : NULL;
-
-                       /*
-                        * set nIEN for previous port, drives in the
-                        * quirk list may not like intr setups/cleanups
-                        */
-                       if (cur_dev &&
-                           (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
-                               prev_port->tp_ops->write_devctl(prev_port,
-                                                               ATA_NIEN |
-                                                               ATA_DEVCTL_OBS);
-
-                       hwif->host->cur_port = hwif;
-               }
-               hwif->cur_dev = drive;
-               drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
-
-               /*
-                * Sanity: don't accept a request that isn't a PM request
-                * if we are currently power managed. This is very important as
-                * blk_stop_queue() doesn't prevent the blk_fetch_request()
-                * above to return us whatever is in the queue. Since we call
-                * ide_do_request() ourselves, we end up taking requests while
-                * the queue is blocked...
-                */
-               if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
-                   ata_pm_request(rq) == 0 &&
-                   (rq->rq_flags & RQF_PM) == 0) {
-                       /* there should be no pending command at this point */
-                       ide_unlock_port(hwif);
-                       goto plug_device;
-               }
-
-               scsi_req(rq)->resid_len = blk_rq_bytes(rq);
-               hwif->rq = rq;
-
-               spin_unlock_irq(&hwif->lock);
-               startstop = start_request(drive, rq);
-               spin_lock_irq(&hwif->lock);
-
-               if (startstop == ide_stopped) {
-                       rq = hwif->rq;
-                       hwif->rq = NULL;
-                       if (rq)
-                               goto repeat;
-                       ide_unlock_port(hwif);
-                       goto out;
-               }
-       } else {
-plug_device:
-               if (local_requeue)
-                       list_add(&rq->queuelist, &drive->rq_list);
-               spin_unlock_irq(&hwif->lock);
-               ide_unlock_host(host);
-               if (!local_requeue)
-                       ide_requeue_and_plug(drive, rq);
-               return BLK_STS_OK;
-       }
-
-out:
-       spin_unlock_irq(&hwif->lock);
-       if (rq == NULL)
-               ide_unlock_host(host);
-       return BLK_STS_OK;
-}
-
-/*
- * Issue a new request to a device.
- */
-blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
-                         const struct blk_mq_queue_data *bd)
-{
-       ide_drive_t *drive = hctx->queue->queuedata;
-       ide_hwif_t *hwif = drive->hwif;
-
-       spin_lock_irq(&hwif->lock);
-       if (drive->sense_rq_active) {
-               spin_unlock_irq(&hwif->lock);
-               return BLK_STS_DEV_RESOURCE;
-       }
-       spin_unlock_irq(&hwif->lock);
-
-       blk_mq_start_request(bd->rq);
-       return ide_issue_rq(drive, bd->rq, false);
-}
-
-static int drive_is_ready(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 stat = 0;
-
-       if (drive->waiting_for_dma)
-               return hwif->dma_ops->dma_test_irq(drive);
-
-       if (hwif->io_ports.ctl_addr &&
-           (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
-               stat = hwif->tp_ops->read_altstatus(hwif);
-       else
-               /* Note: this may clear a pending IRQ!! */
-               stat = hwif->tp_ops->read_status(hwif);
-
-       if (stat & ATA_BUSY)
-               /* drive busy: definitely not interrupting */
-               return 0;
-
-       /* drive ready: *might* be interrupting */
-       return 1;
-}
-
-/**
- *     ide_timer_expiry        -       handle lack of an IDE interrupt
- *     @data: timer callback magic (hwif)
- *
- *     An IDE command has timed out before the expected drive return
- *     occurred. At this point we attempt to clean up the current
- *     mess. If the current handler includes an expiry handler then
- *     we invoke the expiry handler, and providing it is happy the
- *     work is done. If that fails we apply generic recovery rules
- *     invoking the handler and checking the drive DMA status. We
- *     have an excessively incestuous relationship with the DMA
- *     logic that wants cleaning up.
- */
-void ide_timer_expiry (struct timer_list *t)
-{
-       ide_hwif_t      *hwif = from_timer(hwif, t, timer);
-       ide_drive_t     *drive;
-       ide_handler_t   *handler;
-       unsigned long   flags;
-       int             wait = -1;
-       int             plug_device = 0;
-       struct request  *rq_in_flight;
-
-       spin_lock_irqsave(&hwif->lock, flags);
-
-       handler = hwif->handler;
-
-       if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) {
-               /*
-                * Either a marginal timeout occurred
-                * (got the interrupt just as timer expired),
-                * or we were "sleeping" to give other devices a chance.
-                * Either way, we don't really want to complain about anything.
-                */
-       } else {
-               ide_expiry_t *expiry = hwif->expiry;
-               ide_startstop_t startstop = ide_stopped;
-
-               drive = hwif->cur_dev;
-
-               if (expiry) {
-                       wait = expiry(drive);
-                       if (wait > 0) { /* continue */
-                               /* reset timer */
-                               hwif->timer.expires = jiffies + wait;
-                               hwif->req_gen_timer = hwif->req_gen;
-                               add_timer(&hwif->timer);
-                               spin_unlock_irqrestore(&hwif->lock, flags);
-                               return;
-                       }
-               }
-               hwif->handler = NULL;
-               hwif->expiry = NULL;
-               /*
-                * We need to simulate a real interrupt when invoking
-                * the handler() function, which means we need to
-                * globally mask the specific IRQ:
-                */
-               spin_unlock(&hwif->lock);
-               /* disable_irq_nosync ?? */
-               disable_irq(hwif->irq);
-
-               if (hwif->polling) {
-                       startstop = handler(drive);
-               } else if (drive_is_ready(drive)) {
-                       if (drive->waiting_for_dma)
-                               hwif->dma_ops->dma_lost_irq(drive);
-                       if (hwif->port_ops && hwif->port_ops->clear_irq)
-                               hwif->port_ops->clear_irq(drive);
-
-                       printk(KERN_WARNING "%s: lost interrupt\n",
-                               drive->name);
-                       startstop = handler(drive);
-               } else {
-                       if (drive->waiting_for_dma)
-                               startstop = ide_dma_timeout_retry(drive, wait);
-                       else
-                               startstop = ide_error(drive, "irq timeout",
-                                       hwif->tp_ops->read_status(hwif));
-               }
-               /* Disable interrupts again, `handler' might have enabled it */
-               spin_lock_irq(&hwif->lock);
-               enable_irq(hwif->irq);
-               if (startstop == ide_stopped && hwif->polling == 0) {
-                       rq_in_flight = hwif->rq;
-                       hwif->rq = NULL;
-                       ide_unlock_port(hwif);
-                       plug_device = 1;
-               }
-       }
-       spin_unlock_irqrestore(&hwif->lock, flags);
-
-       if (plug_device) {
-               ide_unlock_host(hwif->host);
-               ide_requeue_and_plug(drive, rq_in_flight);
-       }
-}
-
-/**
- *     unexpected_intr         -       handle an unexpected IDE interrupt
- *     @irq: interrupt line
- *     @hwif: port being processed
- *
- *     There's nothing really useful we can do with an unexpected interrupt,
- *     other than reading the status register (to clear it), and logging it.
- *     There should be no way that an irq can happen before we're ready for it,
- *     so we needn't worry much about losing an "important" interrupt here.
- *
- *     On laptops (and "green" PCs), an unexpected interrupt occurs whenever
- *     the drive enters "idle", "standby", or "sleep" mode, so if the status
- *     looks "good", we just ignore the interrupt completely.
- *
- *     This routine assumes __cli() is in effect when called.
- *
- *     If an unexpected interrupt happens on irq15 while we are handling irq14
- *     and if the two interfaces are "serialized" (CMD640), then it looks like
- *     we could screw up by interfering with a new request being set up for 
- *     irq15.
- *
- *     In reality, this is a non-issue.  The new command is not sent unless 
- *     the drive is ready to accept one, in which case we know the drive is
- *     not trying to interrupt us.  And ide_set_handler() is always invoked
- *     before completing the issuance of any new drive command, so we will not
- *     be accidentally invoked as a result of any valid command completion
- *     interrupt.
- */
-
-static void unexpected_intr(int irq, ide_hwif_t *hwif)
-{
-       u8 stat = hwif->tp_ops->read_status(hwif);
-
-       if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
-               /* Try to not flood the console with msgs */
-               static unsigned long last_msgtime, count;
-               ++count;
-
-               if (time_after(jiffies, last_msgtime + HZ)) {
-                       last_msgtime = jiffies;
-                       printk(KERN_ERR "%s: unexpected interrupt, "
-                               "status=0x%02x, count=%ld\n",
-                               hwif->name, stat, count);
-               }
-       }
-}
-
-/**
- *     ide_intr        -       default IDE interrupt handler
- *     @irq: interrupt number
- *     @dev_id: hwif
- *     @regs: unused weirdness from the kernel irq layer
- *
- *     This is the default IRQ handler for the IDE layer. You should
- *     not need to override it. If you do be aware it is subtle in
- *     places
- *
- *     hwif is the interface in the group currently performing
- *     a command. hwif->cur_dev is the drive and hwif->handler is
- *     the IRQ handler to call. As we issue a command the handlers
- *     step through multiple states, reassigning the handler to the
- *     next step in the process. Unlike a smart SCSI controller IDE
- *     expects the main processor to sequence the various transfer
- *     stages. We also manage a poll timer to catch up with most
- *     timeout situations. There are still a few where the handlers
- *     don't ever decide to give up.
- *
- *     The handler eventually returns ide_stopped to indicate the
- *     request completed. At this point we issue the next request
- *     on the port and the process begins again.
- */
-
-irqreturn_t ide_intr (int irq, void *dev_id)
-{
-       ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
-       struct ide_host *host = hwif->host;
-       ide_drive_t *drive;
-       ide_handler_t *handler;
-       unsigned long flags;
-       ide_startstop_t startstop;
-       irqreturn_t irq_ret = IRQ_NONE;
-       int plug_device = 0;
-       struct request *rq_in_flight;
-
-       if (host->host_flags & IDE_HFLAG_SERIALIZE) {
-               if (hwif != host->cur_port)
-                       goto out_early;
-       }
-
-       spin_lock_irqsave(&hwif->lock, flags);
-
-       if (hwif->port_ops && hwif->port_ops->test_irq &&
-           hwif->port_ops->test_irq(hwif) == 0)
-               goto out;
-
-       handler = hwif->handler;
-
-       if (handler == NULL || hwif->polling) {
-               /*
-                * Not expecting an interrupt from this drive.
-                * That means this could be:
-                *      (1) an interrupt from another PCI device
-                *      sharing the same PCI INT# as us.
-                * or   (2) a drive just entered sleep or standby mode,
-                *      and is interrupting to let us know.
-                * or   (3) a spurious interrupt of unknown origin.
-                *
-                * For PCI, we cannot tell the difference,
-                * so in that case we just ignore it and hope it goes away.
-                */
-               if ((host->irq_flags & IRQF_SHARED) == 0) {
-                       /*
-                        * Probably not a shared PCI interrupt,
-                        * so we can safely try to do something about it:
-                        */
-                       unexpected_intr(irq, hwif);
-               } else {
-                       /*
-                        * Whack the status register, just in case
-                        * we have a leftover pending IRQ.
-                        */
-                       (void)hwif->tp_ops->read_status(hwif);
-               }
-               goto out;
-       }
-
-       drive = hwif->cur_dev;
-
-       if (!drive_is_ready(drive))
-               /*
-                * This happens regularly when we share a PCI IRQ with
-                * another device.  Unfortunately, it can also happen
-                * with some buggy drives that trigger the IRQ before
-                * their status register is up to date.  Hopefully we have
-                * enough advance overhead that the latter isn't a problem.
-                */
-               goto out;
-
-       hwif->handler = NULL;
-       hwif->expiry = NULL;
-       hwif->req_gen++;
-       del_timer(&hwif->timer);
-       spin_unlock(&hwif->lock);
-
-       if (hwif->port_ops && hwif->port_ops->clear_irq)
-               hwif->port_ops->clear_irq(drive);
-
-       if (drive->dev_flags & IDE_DFLAG_UNMASK)
-               local_irq_enable_in_hardirq();
-
-       /* service this interrupt, may set handler for next interrupt */
-       startstop = handler(drive);
-
-       spin_lock_irq(&hwif->lock);
-       /*
-        * Note that handler() may have set things up for another
-        * interrupt to occur soon, but it cannot happen until
-        * we exit from this routine, because it will be the
-        * same irq as is currently being serviced here, and Linux
-        * won't allow another of the same (on any CPU) until we return.
-        */
-       if (startstop == ide_stopped && hwif->polling == 0) {
-               BUG_ON(hwif->handler);
-               rq_in_flight = hwif->rq;
-               hwif->rq = NULL;
-               ide_unlock_port(hwif);
-               plug_device = 1;
-       }
-       irq_ret = IRQ_HANDLED;
-out:
-       spin_unlock_irqrestore(&hwif->lock, flags);
-out_early:
-       if (plug_device) {
-               ide_unlock_host(hwif->host);
-               ide_requeue_and_plug(drive, rq_in_flight);
-       }
-
-       return irq_ret;
-}
-EXPORT_SYMBOL_GPL(ide_intr);
-
-void ide_pad_transfer(ide_drive_t *drive, int write, int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 buf[4] = { 0 };
-
-       while (len > 0) {
-               if (write)
-                       hwif->tp_ops->output_data(drive, NULL, buf, min(4, len));
-               else
-                       hwif->tp_ops->input_data(drive, NULL, buf, min(4, len));
-               len -= 4;
-       }
-}
-EXPORT_SYMBOL_GPL(ide_pad_transfer);
-
-void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
-{
-       drive->sense_rq_active = true;
-       list_add_tail(&rq->queuelist, &drive->rq_list);
-       kblockd_schedule_work(&drive->rq_work);
-}
-EXPORT_SYMBOL_GPL(ide_insert_request_head);
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
deleted file mode 100644 (file)
index 43fbc37..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * IDE ioctls handling.
- */
-
-#include <linux/compat.h>
-#include <linux/export.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-
-static int put_user_long(long val, unsigned long arg)
-{
-       if (in_compat_syscall())
-               return put_user(val, (compat_long_t __user *)compat_ptr(arg));
-
-       return put_user(val, (long __user *)arg);
-}
-
-static const struct ide_ioctl_devset ide_ioctl_settings[] = {
-{ HDIO_GET_32BIT,       HDIO_SET_32BIT,        &ide_devset_io_32bit  },
-{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS,        &ide_devset_keepsettings },
-{ HDIO_GET_UNMASKINTR,  HDIO_SET_UNMASKINTR,   &ide_devset_unmaskirq },
-{ HDIO_GET_DMA,                 HDIO_SET_DMA,          &ide_devset_using_dma },
-{ -1,                   HDIO_SET_PIO_MODE,     &ide_devset_pio_mode  },
-{ 0 }
-};
-
-int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
-                     unsigned int cmd, unsigned long arg,
-                     const struct ide_ioctl_devset *s)
-{
-       const struct ide_devset *ds;
-       int err = -EOPNOTSUPP;
-
-       for (; (ds = s->setting); s++) {
-               if (ds->get && s->get_ioctl == cmd)
-                       goto read_val;
-               else if (ds->set && s->set_ioctl == cmd)
-                       goto set_val;
-       }
-
-       return err;
-
-read_val:
-       mutex_lock(&ide_setting_mtx);
-       err = ds->get(drive);
-       mutex_unlock(&ide_setting_mtx);
-       return err >= 0 ? put_user_long(err, arg) : err;
-
-set_val:
-       if (bdev_is_partition(bdev))
-               err = -EINVAL;
-       else {
-               if (!capable(CAP_SYS_ADMIN))
-                       err = -EACCES;
-               else {
-                       mutex_lock(&ide_setting_mtx);
-                       err = ide_devset_execute(drive, ds, arg);
-                       mutex_unlock(&ide_setting_mtx);
-               }
-       }
-       return err;
-}
-EXPORT_SYMBOL_GPL(ide_setting_ioctl);
-
-static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
-                                 void __user *argp)
-{
-       u16 *id = NULL;
-       int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
-       int rc = 0;
-
-       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
-               rc = -ENOMSG;
-               goto out;
-       }
-
-       /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
-       id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
-       if (id == NULL) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       memcpy(id, drive->id, size);
-       ata_id_to_hd_driveid(id);
-
-       if (copy_to_user(argp, id, size))
-               rc = -EFAULT;
-
-       kfree(id);
-out:
-       return rc;
-}
-
-static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
-{
-       return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
-                        << IDE_NICE_DSC_OVERLAP) |
-                       (!!(drive->dev_flags & IDE_DFLAG_NICE1)
-                        << IDE_NICE_1), arg);
-}
-
-static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
-{
-       if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
-               return -EPERM;
-
-       if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
-           (drive->media != ide_tape))
-               return -EPERM;
-
-       if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
-               drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-
-       if ((arg >> IDE_NICE_1) & 1)
-               drive->dev_flags |= IDE_DFLAG_NICE1;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_NICE1;
-
-       return 0;
-}
-
-static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
-{
-       u8 *buf = NULL;
-       int bufsize = 0, err = 0;
-       u8 args[4], xfer_rate = 0;
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-
-       if (NULL == argp) {
-               struct request *rq;
-
-               rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-               ide_req(rq)->type = ATA_PRIV_TASKFILE;
-               blk_execute_rq(NULL, rq, 0);
-               err = scsi_req(rq)->result ? -EIO : 0;
-               blk_put_request(rq);
-
-               return err;
-       }
-
-       if (copy_from_user(args, argp, 4))
-               return -EFAULT;
-
-       memset(&cmd, 0, sizeof(cmd));
-       tf->feature = args[2];
-       if (args[0] == ATA_CMD_SMART) {
-               tf->nsect = args[3];
-               tf->lbal  = args[1];
-               tf->lbam  = ATA_SMART_LBAM_PASS;
-               tf->lbah  = ATA_SMART_LBAH_PASS;
-               cmd.valid.out.tf = IDE_VALID_OUT_TF;
-               cmd.valid.in.tf  = IDE_VALID_NSECT;
-       } else {
-               tf->nsect = args[1];
-               cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
-               cmd.valid.in.tf  = IDE_VALID_NSECT;
-       }
-       tf->command = args[0];
-       cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA;
-
-       if (args[3]) {
-               cmd.tf_flags |= IDE_TFLAG_IO_16BIT;
-               bufsize = SECTOR_SIZE * args[3];
-               buf = kzalloc(bufsize, GFP_KERNEL);
-               if (buf == NULL)
-                       return -ENOMEM;
-       }
-
-       if (tf->command == ATA_CMD_SET_FEATURES &&
-           tf->feature == SETFEATURES_XFER &&
-           tf->nsect >= XFER_SW_DMA_0) {
-               xfer_rate = ide_find_dma_mode(drive, tf->nsect);
-               if (xfer_rate != tf->nsect) {
-                       err = -EINVAL;
-                       goto abort;
-               }
-
-               cmd.tf_flags |= IDE_TFLAG_SET_XFER;
-       }
-
-       err = ide_raw_taskfile(drive, &cmd, buf, args[3]);
-
-       args[0] = tf->status;
-       args[1] = tf->error;
-       args[2] = tf->nsect;
-abort:
-       if (copy_to_user(argp, &args, 4))
-               err = -EFAULT;
-       if (buf) {
-               if (copy_to_user((argp + 4), buf, bufsize))
-                       err = -EFAULT;
-               kfree(buf);
-       }
-       return err;
-}
-
-static int ide_task_ioctl(ide_drive_t *drive, void __user *p)
-{
-       int err = 0;
-       u8 args[7];
-       struct ide_cmd cmd;
-
-       if (copy_from_user(args, p, 7))
-               return -EFAULT;
-
-       memset(&cmd, 0, sizeof(cmd));
-       memcpy(&cmd.tf.feature, &args[1], 6);
-       cmd.tf.command = args[0];
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-
-       err = ide_no_data_taskfile(drive, &cmd);
-
-       args[0] = cmd.tf.command;
-       memcpy(&args[1], &cmd.tf.feature, 6);
-
-       if (copy_to_user(p, args, 7))
-               err = -EFAULT;
-
-       return err;
-}
-
-static int generic_drive_reset(ide_drive_t *drive)
-{
-       struct request *rq;
-       int ret = 0;
-
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       scsi_req(rq)->cmd_len = 1;
-       scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
-       blk_execute_rq(NULL, rq, 1);
-       ret = scsi_req(rq)->result;
-       blk_put_request(rq);
-       return ret;
-}
-
-int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
-                     unsigned int cmd, unsigned long arg)
-{
-       int err;
-       void __user *argp = (void __user *)arg;
-
-       if (in_compat_syscall())
-               argp = compat_ptr(arg);
-
-       err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
-       if (err != -EOPNOTSUPP)
-               return err;
-
-       switch (cmd) {
-       case HDIO_OBSOLETE_IDENTITY:
-       case HDIO_GET_IDENTITY:
-               if (bdev_is_partition(bdev))
-                       return -EINVAL;
-               return ide_get_identity_ioctl(drive, cmd, argp);
-       case HDIO_GET_NICE:
-               return ide_get_nice_ioctl(drive, arg);
-       case HDIO_SET_NICE:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               return ide_set_nice_ioctl(drive, arg);
-#ifdef CONFIG_IDE_TASK_IOCTL
-       case HDIO_DRIVE_TASKFILE:
-               if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-                       return -EACCES;
-               /* missing compat handler for HDIO_DRIVE_TASKFILE */
-               if (in_compat_syscall())
-                       return -ENOTTY;
-               if (drive->media == ide_disk)
-                       return ide_taskfile_ioctl(drive, arg);
-               return -ENOMSG;
-#endif
-       case HDIO_DRIVE_CMD:
-               if (!capable(CAP_SYS_RAWIO))
-                       return -EACCES;
-               return ide_cmd_ioctl(drive, argp);
-       case HDIO_DRIVE_TASK:
-               if (!capable(CAP_SYS_RAWIO))
-                       return -EACCES;
-               return ide_task_ioctl(drive, argp);
-       case HDIO_DRIVE_RESET:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               return generic_drive_reset(drive);
-       case HDIO_GET_BUSSTATE:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               if (put_user_long(BUSSTATE_ON, arg))
-                       return -EFAULT;
-               return 0;
-       case HDIO_SET_BUSSTATE:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               return -EOPNOTSUPP;
-       default:
-               return -EINVAL;
-       }
-}
-EXPORT_SYMBOL(generic_ide_ioctl);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
deleted file mode 100644 (file)
index f2be127..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 2000-2002    Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2003         Red Hat
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-#include <linux/nmi.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-void SELECT_MASK(ide_drive_t *drive, int mask)
-{
-       const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-
-       if (port_ops && port_ops->maskproc)
-               port_ops->maskproc(drive, mask);
-}
-
-u8 ide_read_error(ide_drive_t *drive)
-{
-       struct ide_taskfile tf;
-
-       drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_ERROR);
-
-       return tf.error;
-}
-EXPORT_SYMBOL_GPL(ide_read_error);
-
-void ide_fix_driveid(u16 *id)
-{
-#ifndef __LITTLE_ENDIAN
-# ifdef __BIG_ENDIAN
-       int i;
-
-       for (i = 0; i < 256; i++)
-               id[i] = __le16_to_cpu(id[i]);
-# else
-#  error "Please fix <asm/byteorder.h>"
-# endif
-#endif
-}
-
-/*
- * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
- * removing leading/trailing blanks and compressing internal blanks.
- * It is primarily used to tidy up the model name/number fields as
- * returned by the ATA_CMD_ID_ATA[PI] commands.
- */
-
-void ide_fixstring(u8 *s, const int bytecount, const int byteswap)
-{
-       u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-       if (byteswap) {
-               /* convert from big-endian to host byte order */
-               for (p = s ; p != end ; p += 2)
-                       be16_to_cpus((u16 *) p);
-       }
-
-       /* strip leading blanks */
-       p = s;
-       while (s != end && *s == ' ')
-               ++s;
-       /* compress internal blanks and strip trailing blanks */
-       while (s != end && *s) {
-               if (*s++ != ' ' || (s != end && *s && *s != ' '))
-                       *p++ = *(s-1);
-       }
-       /* wipe out trailing garbage */
-       while (p != end)
-               *p++ = '\0';
-}
-EXPORT_SYMBOL(ide_fixstring);
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return error -- caller may then invoke ide_error().
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
- */
-int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
-                   unsigned long timeout, u8 *rstat)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       unsigned long flags;
-       bool irqs_threaded = force_irqthreads;
-       int i;
-       u8 stat;
-
-       udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
-       stat = tp_ops->read_status(hwif);
-
-       if (stat & ATA_BUSY) {
-               if (!irqs_threaded) {
-                       local_save_flags(flags);
-                       local_irq_enable_in_hardirq();
-               }
-               timeout += jiffies;
-               while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
-                       if (time_after(jiffies, timeout)) {
-                               /*
-                                * One last read after the timeout in case
-                                * heavy interrupt load made us not make any
-                                * progress during the timeout..
-                                */
-                               stat = tp_ops->read_status(hwif);
-                               if ((stat & ATA_BUSY) == 0)
-                                       break;
-
-                               if (!irqs_threaded)
-                                       local_irq_restore(flags);
-                               *rstat = stat;
-                               return -EBUSY;
-                       }
-               }
-               if (!irqs_threaded)
-                       local_irq_restore(flags);
-       }
-       /*
-        * Allow status to settle, then read it again.
-        * A few rare drives vastly violate the 400ns spec here,
-        * so we'll wait up to 10usec for a "good" status
-        * rather than expensively fail things immediately.
-        * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-        */
-       for (i = 0; i < 10; i++) {
-               udelay(1);
-               stat = tp_ops->read_status(hwif);
-
-               if (OK_STAT(stat, good, bad)) {
-                       *rstat = stat;
-                       return 0;
-               }
-       }
-       *rstat = stat;
-       return -EFAULT;
-}
-
-/*
- * In case of error returns error value after doing "*startstop = ide_error()".
- * The caller should return the updated value of "startstop" in this case,
- * "startstop" is unchanged when the function returns 0.
- */
-int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good,
-                 u8 bad, unsigned long timeout)
-{
-       int err;
-       u8 stat;
-
-       /* bail early if we've exceeded max_failures */
-       if (drive->max_failures && (drive->failures > drive->max_failures)) {
-               *startstop = ide_stopped;
-               return 1;
-       }
-
-       err = __ide_wait_stat(drive, good, bad, timeout, &stat);
-
-       if (err) {
-               char *s = (err == -EBUSY) ? "status timeout" : "status error";
-               *startstop = ide_error(drive, s, stat);
-       }
-
-       return err;
-}
-EXPORT_SYMBOL(ide_wait_stat);
-
-/**
- *     ide_in_drive_list       -       look for drive in black/white list
- *     @id: drive identifier
- *     @table: list to inspect
- *
- *     Look for a drive in the blacklist and the whitelist tables
- *     Returns 1 if the drive is found in the table.
- */
-
-int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
-{
-       for ( ; table->id_model; table++)
-               if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) &&
-                   (!table->id_firmware ||
-                    strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware)))
-                       return 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_in_drive_list);
-
-/*
- * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
- * Some optical devices with the buggy firmwares have the same problem.
- */
-static const struct drive_list_entry ivb_list[] = {
-       { "QUANTUM FIREBALLlct10 05"    , "A03.0900"    },
-       { "QUANTUM FIREBALLlct20 30"    , "APL.0900"    },
-       { "TSSTcorp CDDVDW SH-S202J"    , "SB00"        },
-       { "TSSTcorp CDDVDW SH-S202J"    , "SB01"        },
-       { "TSSTcorp CDDVDW SH-S202N"    , "SB00"        },
-       { "TSSTcorp CDDVDW SH-S202N"    , "SB01"        },
-       { "TSSTcorp CDDVDW SH-S202H"    , "SB00"        },
-       { "TSSTcorp CDDVDW SH-S202H"    , "SB01"        },
-       { "SAMSUNG SP0822N"             , "WA100-10"    },
-       { NULL                          , NULL          }
-};
-
-/*
- *  All hosts that use the 80c ribbon must use!
- *  The name is derived from upper byte of word 93 and the 80c ribbon.
- */
-u8 eighty_ninty_three(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u16 *id = drive->id;
-       int ivb = ide_in_drive_list(id, ivb_list);
-
-       if (hwif->cbl == ATA_CBL_SATA || hwif->cbl == ATA_CBL_PATA40_SHORT)
-               return 1;
-
-       if (ivb)
-               printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
-                                 drive->name);
-
-       if (ata_id_is_sata(id) && !ivb)
-               return 1;
-
-       if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
-               goto no_80w;
-
-       /*
-        * FIXME:
-        * - change master/slave IDENTIFY order
-        * - force bit13 (80c cable present) check also for !ivb devices
-        *   (unless the slave device is pre-ATA3)
-        */
-       if (id[ATA_ID_HW_CONFIG] & 0x4000)
-               return 1;
-
-       if (ivb) {
-               const char *model = (char *)&id[ATA_ID_PROD];
-
-               if (strstr(model, "TSSTcorp CDDVDW SH-S202")) {
-                       /*
-                        * These ATAPI devices always report 80c cable
-                        * so we have to depend on the host in this case.
-                        */
-                       if (hwif->cbl == ATA_CBL_PATA80)
-                               return 1;
-               } else {
-                       /* Depend on the device side cable detection. */
-                       if (id[ATA_ID_HW_CONFIG] & 0x2000)
-                               return 1;
-               }
-       }
-no_80w:
-       if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED)
-               return 0;
-
-       printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
-                           "limiting max speed to UDMA33\n",
-                           drive->name,
-                           hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
-
-       drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED;
-
-       return 0;
-}
-
-static const char *nien_quirk_list[] = {
-       "QUANTUM FIREBALLlct08 08",
-       "QUANTUM FIREBALLP KA6.4",
-       "QUANTUM FIREBALLP KA9.1",
-       "QUANTUM FIREBALLP KX13.6",
-       "QUANTUM FIREBALLP KX20.5",
-       "QUANTUM FIREBALLP KX27.3",
-       "QUANTUM FIREBALLP LM20.4",
-       "QUANTUM FIREBALLP LM20.5",
-       "FUJITSU MHZ2160BH G2",
-       NULL
-};
-
-void ide_check_nien_quirk_list(ide_drive_t *drive)
-{
-       const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-       for (list = nien_quirk_list; *list != NULL; list++)
-               if (strstr(m, *list) != NULL) {
-                       drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
-                       return;
-               }
-}
-
-int ide_driveid_update(ide_drive_t *drive)
-{
-       u16 *id;
-       int rc;
-
-       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
-       if (id == NULL)
-               return 0;
-
-       SELECT_MASK(drive, 1);
-       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1);
-       SELECT_MASK(drive, 0);
-
-       if (rc)
-               goto out_err;
-
-       drive->id[ATA_ID_UDMA_MODES]  = id[ATA_ID_UDMA_MODES];
-       drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
-       drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
-       drive->id[ATA_ID_CFA_MODES]   = id[ATA_ID_CFA_MODES];
-       /* anything more ? */
-
-       kfree(id);
-
-       return 1;
-out_err:
-       if (rc == 2)
-               printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
-       kfree(id);
-       return 0;
-}
-
-int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       struct ide_taskfile tf;
-       u16 *id = drive->id, i;
-       int error = 0;
-       u8 stat;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-       if (hwif->dma_ops)      /* check if host supports DMA */
-               hwif->dma_ops->dma_host_set(drive, 0);
-#endif
-
-       /* Skip setting PIO flow-control modes on pre-EIDE drives */
-       if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0)
-               goto skip;
-
-       /*
-        * Don't use ide_wait_cmd here - it will
-        * attempt to set_geometry and recalibrate,
-        * but for some reason these don't work at
-        * this point (lost interrupt).
-        */
-
-       udelay(1);
-       tp_ops->dev_select(drive);
-       SELECT_MASK(drive, 1);
-       udelay(1);
-       tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
-
-       memset(&tf, 0, sizeof(tf));
-       tf.feature = SETFEATURES_XFER;
-       tf.nsect   = speed;
-
-       tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT);
-
-       tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
-
-       if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK)
-               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
-       error = __ide_wait_stat(drive, drive->ready_stat,
-                               ATA_BUSY | ATA_DRQ | ATA_ERR,
-                               WAIT_CMD, &stat);
-
-       SELECT_MASK(drive, 0);
-
-       if (error) {
-               (void) ide_dump_status(drive, "set_drive_speed_status", stat);
-               return error;
-       }
-
-       if (speed >= XFER_SW_DMA_0) {
-               id[ATA_ID_UDMA_MODES]  &= ~0xFF00;
-               id[ATA_ID_MWDMA_MODES] &= ~0x0700;
-               id[ATA_ID_SWDMA_MODES] &= ~0x0700;
-               if (ata_id_is_cfa(id))
-                       id[ATA_ID_CFA_MODES] &= ~0x0E00;
-       } else  if (ata_id_is_cfa(id))
-               id[ATA_ID_CFA_MODES] &= ~0x01C0;
-
- skip:
-#ifdef CONFIG_BLK_DEV_IDEDMA
-       if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA))
-               hwif->dma_ops->dma_host_set(drive, 1);
-       else if (hwif->dma_ops) /* check if host supports DMA */
-               ide_dma_off_quietly(drive);
-#endif
-
-       if (speed >= XFER_UDMA_0) {
-               i = 1 << (speed - XFER_UDMA_0);
-               id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
-       } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) {
-               i = speed - XFER_MW_DMA_2;
-               id[ATA_ID_CFA_MODES] |= i << 9;
-       } else if (speed >= XFER_MW_DMA_0) {
-               i = 1 << (speed - XFER_MW_DMA_0);
-               id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
-       } else if (speed >= XFER_SW_DMA_0) {
-               i = 1 << (speed - XFER_SW_DMA_0);
-               id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
-       } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) {
-               i = speed - XFER_PIO_4;
-               id[ATA_ID_CFA_MODES] |= i << 6;
-       }
-
-       if (!drive->init_speed)
-               drive->init_speed = speed;
-       drive->current_speed = speed;
-       return error;
-}
-
-/*
- * This should get invoked any time we exit the driver to
- * wait for an interrupt response from a drive.  handler() points
- * at the appropriate code to handle the next interrupt, and a
- * timer is started to prevent us from waiting forever in case
- * something goes wrong (see the ide_timer_expiry() handler later on).
- *
- * See also ide_execute_command
- */
-void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
-                      unsigned int timeout)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       BUG_ON(hwif->handler);
-       hwif->handler           = handler;
-       hwif->timer.expires     = jiffies + timeout;
-       hwif->req_gen_timer     = hwif->req_gen;
-       add_timer(&hwif->timer);
-}
-
-void ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
-                    unsigned int timeout)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hwif->lock, flags);
-       __ide_set_handler(drive, handler, timeout);
-       spin_unlock_irqrestore(&hwif->lock, flags);
-}
-EXPORT_SYMBOL(ide_set_handler);
-
-/**
- *     ide_execute_command     -       execute an IDE command
- *     @drive: IDE drive to issue the command against
- *     @cmd: command
- *     @handler: handler for next phase
- *     @timeout: timeout for command
- *
- *     Helper function to issue an IDE command. This handles the
- *     atomicity requirements, command timing and ensures that the
- *     handler and IRQ setup do not race. All IDE command kick off
- *     should go via this function or do equivalent locking.
- */
-
-void ide_execute_command(ide_drive_t *drive, struct ide_cmd *cmd,
-                        ide_handler_t *handler, unsigned timeout)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hwif->lock, flags);
-       if ((cmd->protocol != ATAPI_PROT_DMA &&
-            cmd->protocol != ATAPI_PROT_PIO) ||
-           (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT))
-               __ide_set_handler(drive, handler, timeout);
-       hwif->tp_ops->exec_command(hwif, cmd->tf.command);
-       /*
-        * Drive takes 400nS to respond, we must avoid the IRQ being
-        * serviced before that.
-        *
-        * FIXME: we could skip this delay with care on non shared devices
-        */
-       ndelay(400);
-       spin_unlock_irqrestore(&hwif->lock, flags);
-}
-
-/*
- * ide_wait_not_busy() waits for the currently selected device on the hwif
- * to report a non-busy status, see comments in ide_probe_port().
- */
-int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
-{
-       u8 stat = 0;
-
-       while (timeout--) {
-               /*
-                * Turn this into a schedule() sleep once I'm sure
-                * about locking issues (2.5 work ?).
-                */
-               mdelay(1);
-               stat = hwif->tp_ops->read_status(hwif);
-               if ((stat & ATA_BUSY) == 0)
-                       return 0;
-               /*
-                * Assume a value of 0xff means nothing is connected to
-                * the interface and it doesn't implement the pull-down
-                * resistor on D7.
-                */
-               if (stat == 0xff)
-                       return -ENODEV;
-               touch_nmi_watchdog();
-       }
-       return -EBUSY;
-}
diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c
deleted file mode 100644 (file)
index be65b41..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-
-static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw,
-                               u8 port_no, const struct ide_port_info *d,
-                               unsigned long config)
-{
-       unsigned long base, ctl;
-       int irq;
-
-       if (port_no == 0) {
-               base = 0x1f0;
-               ctl  = 0x3f6;
-               irq  = 14;
-       } else {
-               base = 0x170;
-               ctl  = 0x376;
-               irq  = 15;
-       }
-
-       if (!request_region(base, 8, d->name)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               d->name, base, base + 7);
-               return;
-       }
-
-       if (!request_region(ctl, 1, d->name)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               d->name, ctl);
-               release_region(base, 8);
-               return;
-       }
-
-       ide_std_init_ports(hw, base, ctl);
-       hw->irq = irq;
-       hw->config = config;
-
-       hws[port_no] = hw;
-}
-
-int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
-{
-       struct ide_hw hw[2], *hws[] = { NULL, NULL };
-
-       memset(&hw, 0, sizeof(hw));
-
-       if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
-               ide_legacy_init_one(hws, &hw[0], 0, d, config);
-       ide_legacy_init_one(hws, &hw[1], 1, d, config);
-
-       if (hws[0] == NULL && hws[1] == NULL &&
-           (d->host_flags & IDE_HFLAG_SINGLE))
-               return -ENOENT;
-
-       return ide_host_add(d, hws, 2, NULL);
-}
-EXPORT_SYMBOL_GPL(ide_legacy_device_add);
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
deleted file mode 100644 (file)
index 7b9f655..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48)
-{
-       struct ide_taskfile *tf = &cmd->tf;
-       u32 high, low;
-
-       low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
-       if (lba48) {
-               tf = &cmd->hob;
-               high = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
-       } else
-               high = tf->device & 0xf;
-
-       return ((u64)high << 24) | low;
-}
-EXPORT_SYMBOL_GPL(ide_get_lba_addr);
-
-static void ide_dump_sector(ide_drive_t *drive)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-       u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
-
-       memset(&cmd, 0, sizeof(cmd));
-       if (lba48) {
-               cmd.valid.in.tf  = IDE_VALID_LBA;
-               cmd.valid.in.hob = IDE_VALID_LBA;
-               cmd.tf_flags = IDE_TFLAG_LBA48;
-       } else
-               cmd.valid.in.tf  = IDE_VALID_LBA | IDE_VALID_DEVICE;
-
-       ide_tf_readback(drive, &cmd);
-
-       if (lba48 || (tf->device & ATA_LBA))
-               printk(KERN_CONT ", LBAsect=%llu",
-                       (unsigned long long)ide_get_lba_addr(&cmd, lba48));
-       else
-               printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
-                       tf->device & 0xf, tf->lbal);
-}
-
-static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
-{
-       printk(KERN_CONT "{ ");
-       if (err & ATA_ABORTED)
-               printk(KERN_CONT "DriveStatusError ");
-       if (err & ATA_ICRC)
-               printk(KERN_CONT "%s",
-                       (err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
-       if (err & ATA_UNC)
-               printk(KERN_CONT "UncorrectableError ");
-       if (err & ATA_IDNF)
-               printk(KERN_CONT "SectorIdNotFound ");
-       if (err & ATA_TRK0NF)
-               printk(KERN_CONT "TrackZeroNotFound ");
-       if (err & ATA_AMNF)
-               printk(KERN_CONT "AddrMarkNotFound ");
-       printk(KERN_CONT "}");
-       if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
-           (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
-               struct request *rq = drive->hwif->rq;
-
-               ide_dump_sector(drive);
-
-               if (rq)
-                       printk(KERN_CONT ", sector=%llu",
-                              (unsigned long long)blk_rq_pos(rq));
-       }
-       printk(KERN_CONT "\n");
-}
-
-static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
-{
-       printk(KERN_CONT "{ ");
-       if (err & ATAPI_ILI)
-               printk(KERN_CONT "IllegalLengthIndication ");
-       if (err & ATAPI_EOM)
-               printk(KERN_CONT "EndOfMedia ");
-       if (err & ATA_ABORTED)
-               printk(KERN_CONT "AbortedCommand ");
-       if (err & ATA_MCR)
-               printk(KERN_CONT "MediaChangeRequested ");
-       if (err & ATAPI_LFS)
-               printk(KERN_CONT "LastFailedSense=0x%02x ",
-                       (err & ATAPI_LFS) >> 4);
-       printk(KERN_CONT "}\n");
-}
-
-/**
- *     ide_dump_status         -       translate ATA/ATAPI error
- *     @drive: drive that status applies to
- *     @msg: text message to print
- *     @stat: status byte to decode
- *
- *     Error reporting, in human readable form (luxurious, but a memory hog).
- *     Combines the drive name, message and status byte to provide a
- *     user understandable explanation of the device error.
- */
-
-u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
-{
-       u8 err = 0;
-
-       printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat);
-       if (stat & ATA_BUSY)
-               printk(KERN_CONT "Busy ");
-       else {
-               if (stat & ATA_DRDY)
-                       printk(KERN_CONT "DriveReady ");
-               if (stat & ATA_DF)
-                       printk(KERN_CONT "DeviceFault ");
-               if (stat & ATA_DSC)
-                       printk(KERN_CONT "SeekComplete ");
-               if (stat & ATA_DRQ)
-                       printk(KERN_CONT "DataRequest ");
-               if (stat & ATA_CORR)
-                       printk(KERN_CONT "CorrectedError ");
-               if (stat & ATA_SENSE)
-                       printk(KERN_CONT "Sense ");
-               if (stat & ATA_ERR)
-                       printk(KERN_CONT "Error ");
-       }
-       printk(KERN_CONT "}\n");
-       if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
-               err = ide_read_error(drive);
-               printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err);
-               if (drive->media == ide_disk)
-                       ide_dump_ata_error(drive, err);
-               else
-                       ide_dump_atapi_error(drive, err);
-       }
-
-       printk(KERN_ERR "%s: possibly failed opcode: 0x%02x\n",
-               drive->name, drive->hwif->cmd.tf.command);
-
-       return err;
-}
-EXPORT_SYMBOL(ide_dump_status);
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
deleted file mode 100644 (file)
index a80a0f2..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-#include <linux/jiffies.h>
-#include <linux/blkdev.h>
-
-DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
-
-static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct request_queue *q = drive->queue;
-       struct request *rq;
-       int rc;
-
-       timeout += jiffies;
-       spin_lock_irq(&hwif->lock);
-       if (drive->dev_flags & IDE_DFLAG_PARKED) {
-               int reset_timer = time_before(timeout, drive->sleep);
-               int start_queue = 0;
-
-               drive->sleep = timeout;
-               wake_up_all(&ide_park_wq);
-               if (reset_timer && del_timer(&hwif->timer))
-                       start_queue = 1;
-               spin_unlock_irq(&hwif->lock);
-
-               if (start_queue)
-                       blk_mq_run_hw_queues(q, true);
-               return;
-       }
-       spin_unlock_irq(&hwif->lock);
-
-       rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
-       scsi_req(rq)->cmd[0] = REQ_PARK_HEADS;
-       scsi_req(rq)->cmd_len = 1;
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       ide_req(rq)->special = &timeout;
-       blk_execute_rq(NULL, rq, 1);
-       rc = scsi_req(rq)->result ? -EIO : 0;
-       blk_put_request(rq);
-       if (rc)
-               goto out;
-
-       /*
-        * Make sure that *some* command is sent to the drive after the
-        * timeout has expired, so power management will be reenabled.
-        */
-       rq = blk_get_request(q, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT);
-       if (IS_ERR(rq))
-               goto out;
-
-       scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
-       scsi_req(rq)->cmd_len = 1;
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       spin_lock_irq(&hwif->lock);
-       ide_insert_request_head(drive, rq);
-       spin_unlock_irq(&hwif->lock);
-
-out:
-       return;
-}
-
-ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
-{
-       struct ide_cmd cmd;
-       struct ide_taskfile *tf = &cmd.tf;
-
-       memset(&cmd, 0, sizeof(cmd));
-       if (scsi_req(rq)->cmd[0] == REQ_PARK_HEADS) {
-               drive->sleep = *(unsigned long *)ide_req(rq)->special;
-               drive->dev_flags |= IDE_DFLAG_SLEEPING;
-               tf->command = ATA_CMD_IDLEIMMEDIATE;
-               tf->feature = 0x44;
-               tf->lbal = 0x4c;
-               tf->lbam = 0x4e;
-               tf->lbah = 0x55;
-               cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-               cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       } else          /* cmd == REQ_UNPARK_HEADS */
-               tf->command = ATA_CMD_CHK_POWER;
-
-       cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
-       cmd.protocol = ATA_PROT_NODATA;
-
-       cmd.rq = rq;
-
-       return do_rw_taskfile(drive, &cmd);
-}
-
-ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
-                     char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long now;
-       unsigned int msecs;
-
-       if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
-               return -EOPNOTSUPP;
-
-       spin_lock_irq(&hwif->lock);
-       now = jiffies;
-       if (drive->dev_flags & IDE_DFLAG_PARKED &&
-           time_after(drive->sleep, now))
-               msecs = jiffies_to_msecs(drive->sleep - now);
-       else
-               msecs = 0;
-       spin_unlock_irq(&hwif->lock);
-
-       return snprintf(buf, 20, "%u\n", msecs);
-}
-
-ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
-                      const char *buf, size_t len)
-{
-#define MAX_PARK_TIMEOUT 30000
-       ide_drive_t *drive = to_ide_device(dev);
-       long int input;
-       int rc;
-
-       rc = kstrtol(buf, 10, &input);
-       if (rc)
-               return rc;
-       if (input < -2)
-               return -EINVAL;
-       if (input > MAX_PARK_TIMEOUT) {
-               input = MAX_PARK_TIMEOUT;
-               rc = -EOVERFLOW;
-       }
-
-       mutex_lock(&ide_setting_mtx);
-       if (input >= 0) {
-               if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
-                       rc = -EOPNOTSUPP;
-               else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
-                       issue_park_cmd(drive, msecs_to_jiffies(input));
-       } else {
-               if (drive->media == ide_disk)
-                       switch (input) {
-                       case -1:
-                               drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
-                               break;
-                       case -2:
-                               drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
-                               break;
-                       }
-               else
-                       rc = -EOPNOTSUPP;
-       }
-       mutex_unlock(&ide_setting_mtx);
-
-       return rc ? rc : len;
-}
diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c
deleted file mode 100644 (file)
index 673420d..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- *  Copyright (C) 2001-2002    Andre Hedrick <andre@linux-ide.org>
- *  Portions (C) Copyright 2002  Red Hat Inc
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "ide_pci_generic"
-
-static bool ide_generic_all;           /* Set to claim all devices */
-
-module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
-MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
-
-static void netcell_quirkproc(ide_drive_t *drive)
-{
-       /* mark words 85-87 as valid */
-       drive->id[ATA_ID_CSF_DEFAULT] |= 0x4000;
-}
-
-static const struct ide_port_ops netcell_port_ops = {
-       .quirkproc              = netcell_quirkproc,
-};
-
-#define DECLARE_GENERIC_PCI_DEV(extra_flags) \
-       { \
-               .name           = DRV_NAME, \
-               .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
-                                 extra_flags, \
-               .swdma_mask     = ATA_SWDMA2, \
-               .mwdma_mask     = ATA_MWDMA2, \
-               .udma_mask      = ATA_UDMA6, \
-       }
-
-static const struct ide_port_info generic_chipsets[] = {
-       /*  0: Unknown */
-       DECLARE_GENERIC_PCI_DEV(0),
-
-       {       /* 1: NS87410 */
-               .name           = DRV_NAME,
-               .enablebits     = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} },
-               .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
-               .swdma_mask     = ATA_SWDMA2,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA6,
-       },
-
-       /*  2: SAMURAI / HT6565 / HINT_IDE */
-       DECLARE_GENERIC_PCI_DEV(0),
-       /*  3: UM8673F / UM8886A / UM8886BF */
-       DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA),
-       /*  4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */
-       DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA),
-
-       {       /* 5: VIA8237SATA */
-               .name           = DRV_NAME,
-               .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-                                 IDE_HFLAG_OFF_BOARD,
-               .swdma_mask     = ATA_SWDMA2,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA6,
-       },
-
-       {       /* 6: Revolution */
-               .name           = DRV_NAME,
-               .port_ops       = &netcell_port_ops,
-               .host_flags     = IDE_HFLAG_CLEAR_SIMPLEX |
-                                 IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-                                 IDE_HFLAG_OFF_BOARD,
-               .swdma_mask     = ATA_SWDMA2,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA6,
-       }
-};
-
-/**
- *     generic_init_one        -       called when a PIIX is found
- *     @dev: the generic device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-
-static int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       const struct ide_port_info *d = &generic_chipsets[id->driver_data];
-       int ret = -ENODEV;
-
-       /* Don't use the generic entry unless instructed to do so */
-       if (id->driver_data == 0 && ide_generic_all == 0)
-                       goto out;
-
-       switch (dev->vendor) {
-       case PCI_VENDOR_ID_UMC:
-               if (dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
-                               !(PCI_FUNC(dev->devfn) & 1))
-                       goto out; /* UM8886A/BF pair */
-               break;
-       case PCI_VENDOR_ID_OPTI:
-               if (dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
-                               !(PCI_FUNC(dev->devfn) & 1))
-                       goto out;
-               break;
-       case PCI_VENDOR_ID_JMICRON:
-               if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 &&
-                               PCI_FUNC(dev->devfn) != 1)
-                       goto out;
-               break;
-       case PCI_VENDOR_ID_NS:
-               if (dev->device == PCI_DEVICE_ID_NS_87410 &&
-                               (dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-                       goto out;
-               break;
-       }
-
-       if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
-               u16 command;
-               pci_read_config_word(dev, PCI_COMMAND, &command);
-               if (!(command & PCI_COMMAND_IO)) {
-                       printk(KERN_INFO "%s %s: skipping disabled "
-                               "controller\n", d->name, pci_name(dev));
-                       goto out;
-               }
-       }
-       ret = ide_pci_init_one(dev, d, NULL);
-out:
-       return ret;
-}
-
-static const struct pci_device_id generic_pci_tbl[] = {
-       { PCI_VDEVICE(NS,       PCI_DEVICE_ID_NS_87410),                 1 },
-       { PCI_VDEVICE(PCTECH,   PCI_DEVICE_ID_PCTECH_SAMURAI_IDE),       2 },
-       { PCI_VDEVICE(HOLTEK,   PCI_DEVICE_ID_HOLTEK_6565),              2 },
-       { PCI_VDEVICE(UMC,      PCI_DEVICE_ID_UMC_UM8673F),              3 },
-       { PCI_VDEVICE(UMC,      PCI_DEVICE_ID_UMC_UM8886A),              3 },
-       { PCI_VDEVICE(UMC,      PCI_DEVICE_ID_UMC_UM8886BF),             3 },
-       { PCI_VDEVICE(HINT,     PCI_DEVICE_ID_HINT_VXPROII_IDE),         2 },
-       { PCI_VDEVICE(VIA,      PCI_DEVICE_ID_VIA_82C561),               4 },
-       { PCI_VDEVICE(OPTI,     PCI_DEVICE_ID_OPTI_82C558),              4 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VDEVICE(VIA,      PCI_DEVICE_ID_VIA_8237_SATA),            5 },
-#endif
-       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_1),        4 },
-       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),        4 },
-       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),        4 },
-       { PCI_VDEVICE(TOSHIBA,  PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),        4 },
-       { PCI_VDEVICE(NETCELL,  PCI_DEVICE_ID_REVOLUTION),               6 },
-       /*
-        * Must come last.  If you add entries adjust
-        * this table and generic_chipsets[] appropriately.
-        */
-       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
-
-static struct pci_driver generic_pci_driver = {
-       .name           = "PCI_IDE",
-       .id_table       = generic_pci_tbl,
-       .probe          = generic_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init generic_ide_init(void)
-{
-       return ide_pci_register_driver(&generic_pci_driver);
-}
-
-static void __exit generic_ide_exit(void)
-{
-       pci_unregister_driver(&generic_pci_driver);
-}
-
-module_init(generic_ide_init);
-module_exit(generic_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c
deleted file mode 100644 (file)
index 1fd2479..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * PIO blacklist.  Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640.  Here we keep info on some known drives.
- *
- * Changes to the ide_pio_blacklist[] should be made with EXTREME CAUTION
- * to avoid breaking the fragile cmd640.c support.
- */
-
-#include <linux/string.h>
-#include <linux/ide.h>
-
-static struct ide_pio_info {
-       const char      *name;
-       int             pio;
-} ide_pio_blacklist [] = {
-       { "Conner Peripherals 540MB - CFS540A", 3 },
-
-       { "WDC AC2700",  3 },
-       { "WDC AC2540",  3 },
-       { "WDC AC2420",  3 },
-       { "WDC AC2340",  3 },
-       { "WDC AC2250",  0 },
-       { "WDC AC2200",  0 },
-       { "WDC AC21200", 4 },
-       { "WDC AC2120",  0 },
-       { "WDC AC2850",  3 },
-       { "WDC AC1270",  3 },
-       { "WDC AC1170",  1 },
-       { "WDC AC1210",  1 },
-       { "WDC AC280",   0 },
-       { "WDC AC31000", 3 },
-       { "WDC AC31200", 3 },
-
-       { "Maxtor 7131 AT", 1 },
-       { "Maxtor 7171 AT", 1 },
-       { "Maxtor 7213 AT", 1 },
-       { "Maxtor 7245 AT", 1 },
-       { "Maxtor 7345 AT", 1 },
-       { "Maxtor 7546 AT", 3 },
-       { "Maxtor 7540 AV", 3 },
-
-       { "SAMSUNG SHD-3121A", 1 },
-       { "SAMSUNG SHD-3122A", 1 },
-       { "SAMSUNG SHD-3172A", 1 },
-
-       { "ST5660A",  3 },
-       { "ST3660A",  3 },
-       { "ST3630A",  3 },
-       { "ST3655A",  3 },
-       { "ST3391A",  3 },
-       { "ST3390A",  1 },
-       { "ST3600A",  1 },
-       { "ST3290A",  0 },
-       { "ST3144A",  0 },
-       { "ST3491A",  1 }, /* reports 3, should be 1 or 2 (depending on drive)
-                             according to Seagate's FIND-ATA program */
-
-       { "QUANTUM ELS127A", 0 },
-       { "QUANTUM ELS170A", 0 },
-       { "QUANTUM LPS240A", 0 },
-       { "QUANTUM LPS210A", 3 },
-       { "QUANTUM LPS270A", 3 },
-       { "QUANTUM LPS365A", 3 },
-       { "QUANTUM LPS540A", 3 },
-       { "QUANTUM LIGHTNING 540A", 3 },
-       { "QUANTUM LIGHTNING 730A", 3 },
-
-       { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-       { "QUANTUM FIREBALL_640", 3 },
-       { "QUANTUM FIREBALL_1080", 3 },
-       { "QUANTUM FIREBALL_1280", 3 },
-       { NULL, 0 }
-};
-
-/**
- *     ide_scan_pio_blacklist  -       check for a blacklisted drive
- *     @model: Drive model string
- *
- *     This routine searches the ide_pio_blacklist for an entry
- *     matching the start/whole of the supplied model name.
- *
- *     Returns -1 if no match found.
- *     Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-
-int ide_scan_pio_blacklist(char *model)
-{
-       struct ide_pio_info *p;
-
-       for (p = ide_pio_blacklist; p->name != NULL; p++) {
-               if (strncmp(p->name, model, strlen(p->name)) == 0)
-                       return p->pio;
-       }
-       return -1;
-}
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
deleted file mode 100644 (file)
index d680b3e..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-
-int generic_ide_suspend(struct device *dev, pm_message_t mesg)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq;
-       struct ide_pm_state rqpm;
-       int ret;
-
-       if (ide_port_acpi(hwif)) {
-               /* call ACPI _GTM only once */
-               if ((drive->dn & 1) == 0 || pair == NULL)
-                       ide_acpi_get_timing(hwif);
-       }
-
-       memset(&rqpm, 0, sizeof(rqpm));
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_PM_SUSPEND;
-       ide_req(rq)->special = &rqpm;
-       rqpm.pm_step = IDE_PM_START_SUSPEND;
-       if (mesg.event == PM_EVENT_PRETHAW)
-               mesg.event = PM_EVENT_FREEZE;
-       rqpm.pm_state = mesg.event;
-
-       blk_execute_rq(NULL, rq, 0);
-       ret = scsi_req(rq)->result ? -EIO : 0;
-       blk_put_request(rq);
-
-       if (ret == 0 && ide_port_acpi(hwif)) {
-               /* call ACPI _PS3 only after both devices are suspended */
-               if ((drive->dn & 1) || pair == NULL)
-                       ide_acpi_set_state(hwif, 0);
-       }
-
-       return ret;
-}
-
-static int ide_pm_execute_rq(struct request *rq)
-{
-       struct request_queue *q = rq->q;
-
-       if (unlikely(blk_queue_dying(q))) {
-               rq->rq_flags |= RQF_QUIET;
-               scsi_req(rq)->result = -ENXIO;
-               blk_mq_end_request(rq, BLK_STS_OK);
-               return -ENXIO;
-       }
-       blk_execute_rq(NULL, rq, true);
-
-       return scsi_req(rq)->result ? -EIO : 0;
-}
-
-int generic_ide_resume(struct device *dev)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq;
-       struct ide_pm_state rqpm;
-       int err;
-
-       blk_mq_start_stopped_hw_queues(drive->queue, true);
-
-       if (ide_port_acpi(hwif)) {
-               /* call ACPI _PS0 / _STM only once */
-               if ((drive->dn & 1) == 0 || pair == NULL) {
-                       ide_acpi_set_state(hwif, 1);
-                       ide_acpi_push_timing(hwif);
-               }
-
-               ide_acpi_exec_tfs(drive);
-       }
-
-       memset(&rqpm, 0, sizeof(rqpm));
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, BLK_MQ_REQ_PM);
-       ide_req(rq)->type = ATA_PRIV_PM_RESUME;
-       ide_req(rq)->special = &rqpm;
-       rqpm.pm_step = IDE_PM_START_RESUME;
-       rqpm.pm_state = PM_EVENT_ON;
-
-       err = ide_pm_execute_rq(rq);
-       blk_put_request(rq);
-
-       if (err == 0 && dev->driver) {
-               struct ide_driver *drv = to_ide_driver(dev->driver);
-
-               if (drv->resume)
-                       drv->resume(drive);
-       }
-
-       return err;
-}
-
-void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
-{
-       struct ide_pm_state *pm = ide_req(rq)->special;
-
-#ifdef DEBUG_PM
-       printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
-               drive->name, pm->pm_step);
-#endif
-       if (drive->media != ide_disk)
-               return;
-
-       switch (pm->pm_step) {
-       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
-               if (pm->pm_state == PM_EVENT_FREEZE)
-                       pm->pm_step = IDE_PM_COMPLETED;
-               else
-                       pm->pm_step = IDE_PM_STANDBY;
-               break;
-       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               pm->pm_step = IDE_PM_COMPLETED;
-               break;
-       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
-               pm->pm_step = IDE_PM_IDLE;
-               break;
-       case IDE_PM_IDLE:               /* Resume step 2 (idle)*/
-               pm->pm_step = IDE_PM_RESTORE_DMA;
-               break;
-       }
-}
-
-ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
-{
-       struct ide_pm_state *pm = ide_req(rq)->special;
-       struct ide_cmd cmd = { };
-
-       switch (pm->pm_step) {
-       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
-               if (drive->media != ide_disk)
-                       break;
-               /* Not supported? Switch to next step now. */
-               if (ata_id_flush_enabled(drive->id) == 0 ||
-                   (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
-                       ide_complete_power_step(drive, rq);
-                       return ide_stopped;
-               }
-               if (ata_id_flush_ext_enabled(drive->id))
-                       cmd.tf.command = ATA_CMD_FLUSH_EXT;
-               else
-                       cmd.tf.command = ATA_CMD_FLUSH;
-               goto out_do_tf;
-       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               cmd.tf.command = ATA_CMD_STANDBYNOW1;
-               goto out_do_tf;
-       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
-               ide_set_max_pio(drive);
-               /*
-                * skip IDE_PM_IDLE for ATAPI devices
-                */
-               if (drive->media != ide_disk)
-                       pm->pm_step = IDE_PM_RESTORE_DMA;
-               else
-                       ide_complete_power_step(drive, rq);
-               return ide_stopped;
-       case IDE_PM_IDLE:               /* Resume step 2 (idle) */
-               cmd.tf.command = ATA_CMD_IDLEIMMEDIATE;
-               goto out_do_tf;
-       case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
-               /*
-                * Right now, all we do is call ide_set_dma(drive),
-                * we could be smarter and check for current xfer_speed
-                * in struct drive etc...
-                */
-               if (drive->hwif->dma_ops == NULL)
-                       break;
-               /*
-                * TODO: respect IDE_DFLAG_USING_DMA
-                */
-               ide_set_dma(drive);
-               break;
-       }
-
-       pm->pm_step = IDE_PM_COMPLETED;
-
-       return ide_stopped;
-
-out_do_tf:
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       cmd.protocol = ATA_PROT_NODATA;
-
-       return do_rw_taskfile(drive, &cmd);
-}
-
-/**
- *     ide_complete_pm_rq - end the current Power Management request
- *     @drive: target drive
- *     @rq: request
- *
- *     This function cleans up the current PM request and stops the queue
- *     if necessary.
- */
-void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
-{
-       struct request_queue *q = drive->queue;
-       struct ide_pm_state *pm = ide_req(rq)->special;
-
-       ide_complete_power_step(drive, rq);
-       if (pm->pm_step != IDE_PM_COMPLETED)
-               return;
-
-#ifdef DEBUG_PM
-       printk("%s: completing PM request, %s\n", drive->name,
-              (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) ? "suspend" : "resume");
-#endif
-       if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND)
-               blk_mq_stop_hw_queues(q);
-       else
-               drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
-
-       drive->hwif->rq = NULL;
-
-       blk_mq_end_request(rq, BLK_STS_OK);
-}
-
-void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
-{
-       struct ide_pm_state *pm = ide_req(rq)->special;
-
-       if (blk_rq_is_private(rq) &&
-           ide_req(rq)->type == ATA_PRIV_PM_SUSPEND &&
-           pm->pm_step == IDE_PM_START_SUSPEND)
-               /* Mark drive blocked when starting the suspend sequence. */
-               drive->dev_flags |= IDE_DFLAG_BLOCKED;
-       else if (blk_rq_is_private(rq) &&
-                ide_req(rq)->type == ATA_PRIV_PM_RESUME &&
-                pm->pm_step == IDE_PM_START_RESUME) {
-               /*
-                * The first thing we do on wakeup is to wait for BSY bit to
-                * go away (with a looong timeout) as a drive on this hwif may
-                * just be POSTing itself.
-                * We do that before even selecting as the "other" device on
-                * the bus may be broken enough to walk on our toes at this
-                * point.
-                */
-               ide_hwif_t *hwif = drive->hwif;
-               const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-               struct request_queue *q = drive->queue;
-               int rc;
-#ifdef DEBUG_PM
-               printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
-#endif
-               rc = ide_wait_not_busy(hwif, 35000);
-               if (rc)
-                       printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
-               tp_ops->dev_select(drive);
-               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-               rc = ide_wait_not_busy(hwif, 100000);
-               if (rc)
-                       printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
-
-               blk_mq_start_hw_queues(q);
-       }
-}
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
deleted file mode 100644 (file)
index fc541f1..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * This file provides autodetection for ISA PnP IDE interfaces.
- * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
- *
- * Copyright (C) 2000 Andrey Panin <pazke@donpac.ru>
- */
-
-#include <linux/init.h>
-#include <linux/pnp.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#define DRV_NAME "ide-pnp"
-
-/* Add your devices here :)) */
-static const struct pnp_device_id idepnp_devices[] = {
-       /* Generic ESDI/IDE/ATA compatible hard disk controller */
-       {.id = "PNP0600", .driver_data = 0},
-       {.id = ""}
-};
-
-static const struct ide_port_info ide_pnp_port_info = {
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .chipset                = ide_generic,
-};
-
-static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-       struct ide_host *host;
-       unsigned long base, ctl;
-       int rc;
-       struct ide_hw hw, *hws[] = { &hw };
-
-       printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n");
-
-       if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
-               return -1;
-
-       base = pnp_port_start(dev, 0);
-       ctl = pnp_port_start(dev, 1);
-
-       if (!request_region(base, 8, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               DRV_NAME, base, base + 7);
-               return -EBUSY;
-       }
-
-       if (!request_region(ctl, 1, DRV_NAME)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               DRV_NAME, ctl);
-               release_region(base, 8);
-               return -EBUSY;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-       ide_std_init_ports(&hw, base, ctl);
-       hw.irq = pnp_irq(dev, 0);
-
-       rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host);
-       if (rc)
-               goto out;
-
-       pnp_set_drvdata(dev, host);
-
-       return 0;
-out:
-       release_region(ctl, 1);
-       release_region(base, 8);
-
-       return rc;
-}
-
-static void idepnp_remove(struct pnp_dev *dev)
-{
-       struct ide_host *host = pnp_get_drvdata(dev);
-
-       ide_host_remove(host);
-
-       release_region(pnp_port_start(dev, 1), 1);
-       release_region(pnp_port_start(dev, 0), 8);
-}
-
-static struct pnp_driver idepnp_driver = {
-       .name           = "ide",
-       .id_table       = idepnp_devices,
-       .probe          = idepnp_probe,
-       .remove         = idepnp_remove,
-};
-
-module_pnp_driver(idepnp_driver);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
deleted file mode 100644 (file)
index aefd74c..0000000
+++ /dev/null
@@ -1,1623 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1994-1998   Linus Torvalds & authors (see below)
- *  Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
- */
-
-/*
- *  Mostly written by Mark Lord <mlord@pobox.com>
- *                and Gadi Oxman <gadio@netvision.net.il>
- *                and Andre Hedrick <andre@linux-ide.org>
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- * This is the IDE probe module, as evolved from hd.c and ide.c.
- *
- * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- *      by Andrea Arcangeli
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/spinlock.h>
-#include <linux/kmod.h>
-#include <linux/pci.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/**
- *     generic_id              -       add a generic drive id
- *     @drive: drive to make an ID block for
- *     
- *     Add a fake id field to the drive we are passed. This allows
- *     use to skip a ton of NULL checks (which people always miss) 
- *     and make drive properties unconditional outside of this file
- */
-static void generic_id(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-
-       id[ATA_ID_CUR_CYLS]     = id[ATA_ID_CYLS]       = drive->cyl;
-       id[ATA_ID_CUR_HEADS]    = id[ATA_ID_HEADS]      = drive->head;
-       id[ATA_ID_CUR_SECTORS]  = id[ATA_ID_SECTORS]    = drive->sect;
-}
-
-static void ide_disk_init_chs(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-
-       /* Extract geometry if we did not already have one for the drive */
-       if (!drive->cyl || !drive->head || !drive->sect) {
-               drive->cyl  = drive->bios_cyl  = id[ATA_ID_CYLS];
-               drive->head = drive->bios_head = id[ATA_ID_HEADS];
-               drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];
-       }
-
-       /* Handle logical geometry translation by the drive */
-       if (ata_id_current_chs_valid(id)) {
-               drive->cyl  = id[ATA_ID_CUR_CYLS];
-               drive->head = id[ATA_ID_CUR_HEADS];
-               drive->sect = id[ATA_ID_CUR_SECTORS];
-       }
-
-       /* Use physical geometry if what we have still makes no sense */
-       if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {
-               drive->cyl  = id[ATA_ID_CYLS];
-               drive->head = id[ATA_ID_HEADS];
-               drive->sect = id[ATA_ID_SECTORS];
-       }
-}
-
-static void ide_disk_init_mult_count(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;
-
-       if (max_multsect) {
-               if ((max_multsect / 2) > 1)
-                       id[ATA_ID_MULTSECT] = max_multsect | 0x100;
-               else
-                       id[ATA_ID_MULTSECT] &= ~0x1ff;
-
-               drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
-
-               if (drive->mult_req)
-                       drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-       }
-}
-
-static void ide_classify_ata_dev(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       char *m = (char *)&id[ATA_ID_PROD];
-       int is_cfa = ata_id_is_cfa(id);
-
-       /* CF devices are *not* removable in Linux definition of the term */
-       if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
-               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-
-       drive->media = ide_disk;
-
-       if (!ata_id_has_unload(drive->id))
-               drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
-
-       printk(KERN_INFO "%s: %s, %s DISK drive\n", drive->name, m,
-               is_cfa ? "CFA" : "ATA");
-}
-
-static void ide_classify_atapi_dev(ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       char *m = (char *)&id[ATA_ID_PROD];
-       u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
-
-       printk(KERN_INFO "%s: %s, ATAPI ", drive->name, m);
-       switch (type) {
-       case ide_floppy:
-               if (!strstr(m, "CD-ROM")) {
-                       if (!strstr(m, "oppy") &&
-                           !strstr(m, "poyp") &&
-                           !strstr(m, "ZIP"))
-                               printk(KERN_CONT "cdrom or floppy?, assuming ");
-                       if (drive->media != ide_cdrom) {
-                               printk(KERN_CONT "FLOPPY");
-                               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-                               break;
-                       }
-               }
-               /* Early cdrom models used zero */
-               type = ide_cdrom;
-               fallthrough;
-       case ide_cdrom:
-               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-#ifdef CONFIG_PPC
-               /* kludge for Apple PowerBook internal zip */
-               if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
-                       printk(KERN_CONT "FLOPPY");
-                       type = ide_floppy;
-                       break;
-               }
-#endif
-               printk(KERN_CONT "CD/DVD-ROM");
-               break;
-       case ide_tape:
-               printk(KERN_CONT "TAPE");
-               break;
-       case ide_optical:
-               printk(KERN_CONT "OPTICAL");
-               drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-               break;
-       default:
-               printk(KERN_CONT "UNKNOWN (type %d)", type);
-               break;
-       }
-
-       printk(KERN_CONT " drive\n");
-       drive->media = type;
-       /* an ATAPI device ignores DRDY */
-       drive->ready_stat = 0;
-       if (ata_id_cdb_intr(id))
-               drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
-       drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
-       /* we don't do head unloading on ATAPI devices */
-       drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
-}
-
-/**
- *     do_identify     -       identify a drive
- *     @drive: drive to identify 
- *     @cmd: command used
- *     @id: buffer for IDENTIFY data
- *
- *     Called when we have issued a drive identify command to
- *     read and parse the results. This function is run with
- *     interrupts disabled. 
- */
-
-static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       char *m = (char *)&id[ATA_ID_PROD];
-       unsigned long flags;
-       int bswap = 1;
-
-       /* local CPU only; some systems need this */
-       local_irq_save(flags);
-       /* read 512 bytes of id info */
-       hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
-       local_irq_restore(flags);
-
-       drive->dev_flags |= IDE_DFLAG_ID_READ;
-#ifdef DEBUG
-       printk(KERN_INFO "%s: dumping identify data\n", drive->name);
-       ide_dump_identify((u8 *)id);
-#endif
-       ide_fix_driveid(id);
-
-       /*
-        *  ATA_CMD_ID_ATA returns little-endian info,
-        *  ATA_CMD_ID_ATAPI *usually* returns little-endian info.
-        */
-       if (cmd == ATA_CMD_ID_ATAPI) {
-               if ((m[0] == 'N' && m[1] == 'E') ||  /* NEC */
-                   (m[0] == 'F' && m[1] == 'X') ||  /* Mitsumi */
-                   (m[0] == 'P' && m[1] == 'i'))    /* Pioneer */
-                       /* Vertos drives may still be weird */
-                       bswap ^= 1;
-       }
-
-       ide_fixstring(m, ATA_ID_PROD_LEN, bswap);
-       ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap);
-       ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap);
-
-       /* we depend on this a lot! */
-       m[ATA_ID_PROD_LEN - 1] = '\0';
-
-       if (strstr(m, "E X A B Y T E N E S T"))
-               drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-       else
-               drive->dev_flags |= IDE_DFLAG_PRESENT;
-}
-
-/**
- *     ide_dev_read_id -       send ATA/ATAPI IDENTIFY command
- *     @drive: drive to identify
- *     @cmd: command to use
- *     @id: buffer for IDENTIFY data
- *     @irq_ctx: flag set when called from the IRQ context
- *
- *     Sends an ATA(PI) IDENTIFY request to a drive and waits for a response.
- *
- *     Returns:        0  device was identified
- *                     1  device timed-out (no response to identify request)
- *                     2  device aborted the command (refused to identify itself)
- */
-
-int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       int use_altstatus = 0, rc;
-       unsigned long timeout;
-       u8 s = 0, a = 0;
-
-       /*
-        * Disable device IRQ.  Otherwise we'll get spurious interrupts
-        * during the identify phase that the IRQ handler isn't expecting.
-        */
-       if (io_ports->ctl_addr)
-               tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
-
-       /* take a deep breath */
-       if (irq_ctx)
-               mdelay(50);
-       else
-               msleep(50);
-
-       if (io_ports->ctl_addr &&
-           (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
-               a = tp_ops->read_altstatus(hwif);
-               s = tp_ops->read_status(hwif);
-               if ((a ^ s) & ~ATA_SENSE)
-                       /* ancient Seagate drives, broken interfaces */
-                       printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
-                                        "instead of ALTSTATUS(0x%02x)\n",
-                                        drive->name, s, a);
-               else
-                       /* use non-intrusive polling */
-                       use_altstatus = 1;
-       }
-
-       /* set features register for atapi
-        * identify command to be sure of reply
-        */
-       if (cmd == ATA_CMD_ID_ATAPI) {
-               struct ide_taskfile tf;
-
-               memset(&tf, 0, sizeof(tf));
-               /* disable DMA & overlap */
-               tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE);
-       }
-
-       /* ask drive for ID */
-       tp_ops->exec_command(hwif, cmd);
-
-       timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-
-       /* wait for IRQ and ATA_DRQ */
-       if (irq_ctx) {
-               rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s);
-               if (rc)
-                       return 1;
-       } else {
-               rc = ide_busy_sleep(drive, timeout, use_altstatus);
-               if (rc)
-                       return 1;
-
-               msleep(50);
-               s = tp_ops->read_status(hwif);
-       }
-
-       if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
-               /* drive returned ID */
-               do_identify(drive, cmd, id);
-               /* drive responded with ID */
-               rc = 0;
-               /* clear drive IRQ */
-               (void)tp_ops->read_status(hwif);
-       } else {
-               /* drive refused ID */
-               rc = 2;
-       }
-       return rc;
-}
-
-int ide_busy_sleep(ide_drive_t *drive, unsigned long timeout, int altstatus)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 stat;
-
-       timeout += jiffies;
-
-       do {
-               msleep(50);     /* give drive a breather */
-               stat = altstatus ? hwif->tp_ops->read_altstatus(hwif)
-                                : hwif->tp_ops->read_status(hwif);
-               if ((stat & ATA_BUSY) == 0)
-                       return 0;
-       } while (time_before(jiffies, timeout));
-
-       printk(KERN_ERR "%s: timeout in %s\n", drive->name, __func__);
-
-       return 1;       /* drive timed-out */
-}
-
-static u8 ide_read_device(ide_drive_t *drive)
-{
-       struct ide_taskfile tf;
-
-       drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_DEVICE);
-
-       return tf.device;
-}
-
-/**
- *     do_probe                -       probe an IDE device
- *     @drive: drive to probe
- *     @cmd: command to use
- *
- *     do_probe() has the difficult job of finding a drive if it exists,
- *     without getting hung up if it doesn't exist, without trampling on
- *     ethernet cards, and without leaving any IRQs dangling to haunt us later.
- *
- *     If a drive is "known" to exist (from CMOS or kernel parameters),
- *     but does not respond right away, the probe will "hang in there"
- *     for the maximum wait time (about 30 seconds), otherwise it will
- *     exit much more quickly.
- *
- * Returns:    0  device was identified
- *             1  device timed-out (no response to identify request)
- *             2  device aborted the command (refused to identify itself)
- *             3  bad status from device (possible for ATAPI drives)
- *             4  probe was not attempted because failure was obvious
- */
-
-static int do_probe (ide_drive_t *drive, u8 cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       u16 *id = drive->id;
-       int rc;
-       u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
-
-       /* avoid waiting for inappropriate probes */
-       if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA)
-               return 4;
-
-#ifdef DEBUG
-       printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
-               drive->name, present, drive->media,
-               (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI");
-#endif
-
-       /* needed for some systems
-        * (e.g. crw9624 as drive0 with disk as slave)
-        */
-       msleep(50);
-       tp_ops->dev_select(drive);
-       msleep(50);
-
-       if (ide_read_device(drive) != drive->select && present == 0) {
-               if (drive->dn & 1) {
-                       /* exit with drive0 selected */
-                       tp_ops->dev_select(hwif->devices[0]);
-                       /* allow ATA_BUSY to assert & clear */
-                       msleep(50);
-               }
-               /* no i/f present: mmm.. this should be a 4 -ml */
-               return 3;
-       }
-
-       stat = tp_ops->read_status(hwif);
-
-       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
-           present || cmd == ATA_CMD_ID_ATAPI) {
-               rc = ide_dev_read_id(drive, cmd, id, 0);
-               if (rc)
-                       /* failed: try again */
-                       rc = ide_dev_read_id(drive, cmd, id, 0);
-
-               stat = tp_ops->read_status(hwif);
-
-               if (stat == (ATA_BUSY | ATA_DRDY))
-                       return 4;
-
-               if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) {
-                       printk(KERN_ERR "%s: no response (status = 0x%02x), "
-                                       "resetting drive\n", drive->name, stat);
-                       msleep(50);
-                       tp_ops->dev_select(drive);
-                       msleep(50);
-                       tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
-                       (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0);
-                       rc = ide_dev_read_id(drive, cmd, id, 0);
-               }
-
-               /* ensure drive IRQ is clear */
-               stat = tp_ops->read_status(hwif);
-
-               if (rc == 1)
-                       printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
-                                       drive->name, stat);
-       } else {
-               /* not present or maybe ATAPI */
-               rc = 3;
-       }
-       if (drive->dn & 1) {
-               /* exit with drive0 selected */
-               tp_ops->dev_select(hwif->devices[0]);
-               msleep(50);
-               /* ensure drive irq is clear */
-               (void)tp_ops->read_status(hwif);
-       }
-       return rc;
-}
-
-/**
- *     probe_for_drives        -       upper level drive probe
- *     @drive: drive to probe for
- *
- *     probe_for_drive() tests for existence of a given drive using do_probe()
- *     and presents things to the user as needed.
- *
- *     Returns:        0  no device was found
- *                     1  device was found
- *                        (note: IDE_DFLAG_PRESENT might still be not set)
- */
-
-static u8 probe_for_drive(ide_drive_t *drive)
-{
-       char *m;
-       int rc;
-       u8 cmd;
-
-       drive->dev_flags &= ~IDE_DFLAG_ID_READ;
-
-       m = (char *)&drive->id[ATA_ID_PROD];
-       strcpy(m, "UNKNOWN");
-
-       /* skip probing? */
-       if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
-               /* if !(success||timed-out) */
-               cmd = ATA_CMD_ID_ATA;
-               rc = do_probe(drive, cmd);
-               if (rc >= 2) {
-                       /* look for ATAPI device */
-                       cmd = ATA_CMD_ID_ATAPI;
-                       rc = do_probe(drive, cmd);
-               }
-
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       return 0;
-
-               /* identification failed? */
-               if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
-                       if (drive->media == ide_disk) {
-                               printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
-                                       drive->name, drive->cyl,
-                                       drive->head, drive->sect);
-                       } else if (drive->media == ide_cdrom) {
-                               printk(KERN_INFO "%s: ATAPI cdrom (?)\n", drive->name);
-                       } else {
-                               /* nuke it */
-                               printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
-                               drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-                       }
-               } else {
-                       if (cmd == ATA_CMD_ID_ATAPI)
-                               ide_classify_atapi_dev(drive);
-                       else
-                               ide_classify_ata_dev(drive);
-               }
-       }
-
-       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               return 0;
-
-       /* The drive wasn't being helpful. Add generic info only */
-       if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
-               generic_id(drive);
-               return 1;
-       }
-
-       if (drive->media == ide_disk) {
-               ide_disk_init_chs(drive);
-               ide_disk_init_mult_count(drive);
-       }
-
-       return 1;
-}
-
-static void hwif_release_dev(struct device *dev)
-{
-       ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
-
-       complete(&hwif->gendev_rel_comp);
-}
-
-static int ide_register_port(ide_hwif_t *hwif)
-{
-       int ret;
-
-       /* register with global device tree */
-       dev_set_name(&hwif->gendev, "%s", hwif->name);
-       dev_set_drvdata(&hwif->gendev, hwif);
-       if (hwif->gendev.parent == NULL)
-               hwif->gendev.parent = hwif->dev;
-       hwif->gendev.release = hwif_release_dev;
-
-       ret = device_register(&hwif->gendev);
-       if (ret < 0) {
-               printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       hwif->portdev = device_create(ide_port_class, &hwif->gendev,
-                                     MKDEV(0, 0), hwif, "%s", hwif->name);
-       if (IS_ERR(hwif->portdev)) {
-               ret = PTR_ERR(hwif->portdev);
-               device_unregister(&hwif->gendev);
-       }
-out:
-       return ret;
-}
-
-/**
- *     ide_port_wait_ready     -       wait for port to become ready
- *     @hwif: IDE port
- *
- *     This is needed on some PPCs and a bunch of BIOS-less embedded
- *     platforms.  Typical cases are:
- *
- *     - The firmware hard reset the disk before booting the kernel,
- *       the drive is still doing it's poweron-reset sequence, that
- *       can take up to 30 seconds.
- *
- *     - The firmware does nothing (or no firmware), the device is
- *       still in POST state (same as above actually).
- *
- *     - Some CD/DVD/Writer combo drives tend to drive the bus during
- *       their reset sequence even when they are non-selected slave
- *       devices, thus preventing discovery of the main HD.
- *
- *     Doing this wait-for-non-busy should not harm any existing
- *     configuration and fix some issues like the above.
- *
- *     BenH.
- *
- *     Returns 0 on success, error code (< 0) otherwise.
- */
-
-static int ide_port_wait_ready(ide_hwif_t *hwif)
-{
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       ide_drive_t *drive;
-       int i, rc;
-
-       printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name);
-
-       /* Let HW settle down a bit from whatever init state we
-        * come from */
-       mdelay(2);
-
-       /* Wait for BSY bit to go away, spec timeout is 30 seconds,
-        * I know of at least one disk who takes 31 seconds, I use 35
-        * here to be safe
-        */
-       rc = ide_wait_not_busy(hwif, 35000);
-       if (rc)
-               return rc;
-
-       /* Now make sure both master & slave are ready */
-       ide_port_for_each_dev(i, drive, hwif) {
-               /* Ignore disks that we will not probe for later. */
-               if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
-                   (drive->dev_flags & IDE_DFLAG_PRESENT)) {
-                       tp_ops->dev_select(drive);
-                       tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-                       mdelay(2);
-                       rc = ide_wait_not_busy(hwif, 35000);
-                       if (rc)
-                               goto out;
-               } else
-                       printk(KERN_DEBUG "%s: ide_wait_not_busy() skipped\n",
-                                         drive->name);
-       }
-out:
-       /* Exit function with master reselected (let's be sane) */
-       if (i)
-               tp_ops->dev_select(hwif->devices[0]);
-
-       return rc;
-}
-
-/**
- *     ide_undecoded_slave     -       look for bad CF adapters
- *     @dev1: slave device
- *
- *     Analyse the drives on the interface and attempt to decide if we
- *     have the same drive viewed twice. This occurs with crap CF adapters
- *     and PCMCIA sometimes.
- */
-
-void ide_undecoded_slave(ide_drive_t *dev1)
-{
-       ide_drive_t *dev0 = dev1->hwif->devices[0];
-
-       if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0)
-               return;
-
-       /* If the models don't match they are not the same product */
-       if (strcmp((char *)&dev0->id[ATA_ID_PROD],
-                  (char *)&dev1->id[ATA_ID_PROD]))
-               return;
-
-       /* Serial numbers do not match */
-       if (strncmp((char *)&dev0->id[ATA_ID_SERNO],
-                   (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN))
-               return;
-
-       /* No serial number, thankfully very rare for CF */
-       if (*(char *)&dev0->id[ATA_ID_SERNO] == 0)
-               return;
-
-       /* Appears to be an IDE flash adapter with decode bugs */
-       printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
-
-       dev1->dev_flags &= ~IDE_DFLAG_PRESENT;
-}
-
-EXPORT_SYMBOL_GPL(ide_undecoded_slave);
-
-static int ide_probe_port(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       unsigned int irqd;
-       int i, rc = -ENODEV;
-
-       BUG_ON(hwif->present);
-
-       if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) &&
-           (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE))
-               return -EACCES;
-
-       /*
-        * We must always disable IRQ, as probe_for_drive will assert IRQ, but
-        * we'll install our IRQ driver much later...
-        */
-       irqd = hwif->irq;
-       if (irqd)
-               disable_irq(hwif->irq);
-
-       if (ide_port_wait_ready(hwif) == -EBUSY)
-               printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
-
-       /*
-        * Second drive should only exist if first drive was found,
-        * but a lot of cdrom drives are configured as single slaves.
-        */
-       ide_port_for_each_dev(i, drive, hwif) {
-               (void) probe_for_drive(drive);
-               if (drive->dev_flags & IDE_DFLAG_PRESENT)
-                       rc = 0;
-       }
-
-       /*
-        * Use cached IRQ number. It might be (and is...) changed by probe
-        * code above
-        */
-       if (irqd)
-               enable_irq(irqd);
-
-       return rc;
-}
-
-static void ide_port_tune_devices(ide_hwif_t *hwif)
-{
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       ide_drive_t *drive;
-       int i;
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               ide_check_nien_quirk_list(drive);
-
-               if (port_ops && port_ops->quirkproc)
-                       port_ops->quirkproc(drive);
-       }
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               ide_set_max_pio(drive);
-
-               drive->dev_flags |= IDE_DFLAG_NICE1;
-
-               if (hwif->dma_ops)
-                       ide_set_dma(drive);
-       }
-}
-
-static void ide_initialize_rq(struct request *rq)
-{
-       struct ide_request *req = blk_mq_rq_to_pdu(rq);
-
-       req->special = NULL;
-       scsi_req_init(&req->sreq);
-       req->sreq.sense = req->sense;
-}
-
-static const struct blk_mq_ops ide_mq_ops = {
-       .queue_rq               = ide_queue_rq,
-       .initialize_rq_fn       = ide_initialize_rq,
-};
-
-/*
- * init request queue
- */
-static int ide_init_queue(ide_drive_t *drive)
-{
-       struct request_queue *q;
-       ide_hwif_t *hwif = drive->hwif;
-       int max_sectors = 256;
-       int max_sg_entries = PRD_ENTRIES;
-       struct blk_mq_tag_set *set;
-
-       /*
-        *      Our default set up assumes the normal IDE case,
-        *      that is 64K segmenting, standard PRD setup
-        *      and LBA28. Some drivers then impose their own
-        *      limits and LBA48 we could raise it but as yet
-        *      do not.
-        */
-
-       set = &drive->tag_set;
-       set->ops = &ide_mq_ops;
-       set->nr_hw_queues = 1;
-       set->queue_depth = 32;
-       set->reserved_tags = 1;
-       set->cmd_size = sizeof(struct ide_request);
-       set->numa_node = hwif_to_node(hwif);
-       set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
-       if (blk_mq_alloc_tag_set(set))
-               return 1;
-
-       q = blk_mq_init_queue(set);
-       if (IS_ERR(q)) {
-               blk_mq_free_tag_set(set);
-               return 1;
-       }
-
-       blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
-
-       q->queuedata = drive;
-       blk_queue_segment_boundary(q, 0xffff);
-
-       if (hwif->rqsize < max_sectors)
-               max_sectors = hwif->rqsize;
-       blk_queue_max_hw_sectors(q, max_sectors);
-
-#ifdef CONFIG_PCI
-       /* When we have an IOMMU, we may have a problem where pci_map_sg()
-        * creates segments that don't completely match our boundary
-        * requirements and thus need to be broken up again. Because it
-        * doesn't align properly either, we may actually have to break up
-        * to more segments than what was we got in the first place, a max
-        * worst case is twice as many.
-        * This will be fixed once we teach pci_map_sg() about our boundary
-        * requirements, hopefully soon. *FIXME*
-        */
-       max_sg_entries >>= 1;
-#endif /* CONFIG_PCI */
-
-       blk_queue_max_segments(q, max_sg_entries);
-
-       /* assign drive queue */
-       drive->queue = q;
-
-       return 0;
-}
-
-static DEFINE_MUTEX(ide_cfg_mtx);
-
-/*
- * For any present drive:
- * - allocate the block device queue
- */
-static int ide_port_setup_devices(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i, j = 0;
-
-       mutex_lock(&ide_cfg_mtx);
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               if (ide_init_queue(drive)) {
-                       printk(KERN_ERR "ide: failed to init %s\n",
-                                       drive->name);
-                       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-                       continue;
-               }
-
-               j++;
-       }
-       mutex_unlock(&ide_cfg_mtx);
-
-       return j;
-}
-
-static void ide_host_enable_irqs(struct ide_host *host)
-{
-       ide_hwif_t *hwif;
-       int i;
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif == NULL)
-                       continue;
-
-               /* clear any pending IRQs */
-               hwif->tp_ops->read_status(hwif);
-
-               /* unmask IRQs */
-               if (hwif->io_ports.ctl_addr)
-                       hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-       }
-}
-
-/*
- * This routine sets up the IRQ for an IDE interface.
- */
-static int init_irq (ide_hwif_t *hwif)
-{
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       struct ide_host *host = hwif->host;
-       irq_handler_t irq_handler = host->irq_handler;
-       int sa = host->irq_flags;
-
-       if (irq_handler == NULL)
-               irq_handler = ide_intr;
-
-       if (!host->get_lock)
-               if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
-                       goto out_up;
-
-#if !defined(__mc68000__)
-       printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
-               io_ports->data_addr, io_ports->status_addr,
-               io_ports->ctl_addr, hwif->irq);
-#else
-       printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name,
-               io_ports->data_addr, hwif->irq);
-#endif /* __mc68000__ */
-       if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE)
-               printk(KERN_CONT " (serialized)");
-       printk(KERN_CONT "\n");
-
-       return 0;
-out_up:
-       return 1;
-}
-
-static void ata_probe(dev_t dev)
-{
-       request_module("ide-disk");
-       request_module("ide-cd");
-       request_module("ide-tape");
-       request_module("ide-floppy");
-}
-
-void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned int unit = drive->dn & 1;
-
-       disk->major = hwif->major;
-       disk->first_minor = unit << PARTN_BITS;
-       sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
-       disk->queue = drive->queue;
-}
-
-EXPORT_SYMBOL_GPL(ide_init_disk);
-
-static void drive_release_dev (struct device *dev)
-{
-       ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-
-       ide_proc_unregister_device(drive);
-
-       if (drive->sense_rq)
-               blk_mq_free_request(drive->sense_rq);
-
-       blk_cleanup_queue(drive->queue);
-       drive->queue = NULL;
-       blk_mq_free_tag_set(&drive->tag_set);
-
-       drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-
-       complete(&drive->gendev_rel_comp);
-}
-
-static int hwif_init(ide_hwif_t *hwif)
-{
-       if (!hwif->irq) {
-               printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
-               return 0;
-       }
-
-       if (__register_blkdev(hwif->major, hwif->name, ata_probe))
-               return 0;
-
-       if (!hwif->sg_max_nents)
-               hwif->sg_max_nents = PRD_ENTRIES;
-
-       hwif->sg_table = kmalloc_array(hwif->sg_max_nents,
-                                      sizeof(struct scatterlist),
-                                      GFP_KERNEL);
-       if (!hwif->sg_table) {
-               printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
-               goto out;
-       }
-
-       sg_init_table(hwif->sg_table, hwif->sg_max_nents);
-       
-       if (init_irq(hwif)) {
-               printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
-                       hwif->name, hwif->irq);
-               goto out;
-       }
-
-       return 1;
-
-out:
-       unregister_blkdev(hwif->major, hwif->name);
-       return 0;
-}
-
-static void hwif_register_devices(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       unsigned int i;
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               struct device *dev = &drive->gendev;
-               int ret;
-
-               dev_set_name(dev, "%u.%u", hwif->index, i);
-               dev_set_drvdata(dev, drive);
-               dev->parent = &hwif->gendev;
-               dev->bus = &ide_bus_type;
-               dev->release = drive_release_dev;
-
-               ret = device_register(dev);
-               if (ret < 0)
-                       printk(KERN_WARNING "IDE: %s: device_register error: "
-                                           "%d\n", __func__, ret);
-       }
-}
-
-static void ide_port_init_devices(ide_hwif_t *hwif)
-{
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       ide_drive_t *drive;
-       int i;
-
-       ide_port_for_each_dev(i, drive, hwif) {
-               drive->dn = i + hwif->channel * 2;
-
-               if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
-                       drive->io_32bit = 1;
-               if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
-                       drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
-               if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
-                       drive->dev_flags |= IDE_DFLAG_UNMASK;
-               if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
-                       drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
-
-               drive->pio_mode = XFER_PIO_0;
-
-               if (port_ops && port_ops->init_dev)
-                       port_ops->init_dev(drive);
-       }
-}
-
-static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
-                         const struct ide_port_info *d)
-{
-       hwif->channel = port;
-
-       hwif->chipset = d->chipset ? d->chipset : ide_pci;
-
-       if (d->init_iops)
-               d->init_iops(hwif);
-
-       /* ->host_flags may be set by ->init_iops (or even earlier...) */
-       hwif->host_flags |= d->host_flags;
-       hwif->pio_mask = d->pio_mask;
-
-       if (d->tp_ops)
-               hwif->tp_ops = d->tp_ops;
-
-       /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
-       if ((hwif->host_flags & IDE_HFLAG_DTC2278) == 0 || hwif->channel == 0)
-               hwif->port_ops = d->port_ops;
-
-       hwif->swdma_mask = d->swdma_mask;
-       hwif->mwdma_mask = d->mwdma_mask;
-       hwif->ultra_mask = d->udma_mask;
-
-       if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
-               int rc;
-
-               hwif->dma_ops = d->dma_ops;
-
-               if (d->init_dma)
-                       rc = d->init_dma(hwif, d);
-               else
-                       rc = ide_hwif_setup_dma(hwif, d);
-
-               if (rc < 0) {
-                       printk(KERN_INFO "%s: DMA disabled\n", hwif->name);
-
-                       hwif->dma_ops = NULL;
-                       hwif->dma_base = 0;
-                       hwif->swdma_mask = 0;
-                       hwif->mwdma_mask = 0;
-                       hwif->ultra_mask = 0;
-               }
-       }
-
-       if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
-           ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base))
-               hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
-
-       if (d->max_sectors)
-               hwif->rqsize = d->max_sectors;
-       else {
-               if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
-                   (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
-                       hwif->rqsize = 256;
-               else
-                       hwif->rqsize = 65536;
-       }
-
-       /* call chipset specific routine for each enabled port */
-       if (d->init_hwif)
-               d->init_hwif(hwif);
-}
-
-static void ide_port_cable_detect(ide_hwif_t *hwif)
-{
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) {
-               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-                       hwif->cbl = port_ops->cable_detect(hwif);
-       }
-}
-
-/*
- * Deferred request list insertion handler
- */
-static void drive_rq_insert_work(struct work_struct *work)
-{
-       ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
-       ide_hwif_t *hwif = drive->hwif;
-       struct request *rq;
-       blk_status_t ret;
-       LIST_HEAD(list);
-
-       blk_mq_quiesce_queue(drive->queue);
-
-       ret = BLK_STS_OK;
-       spin_lock_irq(&hwif->lock);
-       while (!list_empty(&drive->rq_list)) {
-               rq = list_first_entry(&drive->rq_list, struct request, queuelist);
-               list_del_init(&rq->queuelist);
-
-               spin_unlock_irq(&hwif->lock);
-               ret = ide_issue_rq(drive, rq, true);
-               spin_lock_irq(&hwif->lock);
-       }
-       spin_unlock_irq(&hwif->lock);
-
-       blk_mq_unquiesce_queue(drive->queue);
-
-       if (ret != BLK_STS_OK)
-               kblockd_schedule_work(&drive->rq_work);
-}
-
-static const u8 ide_hwif_to_major[] =
-       { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
-         IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
-
-static void ide_port_init_devices_data(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i;
-
-       ide_port_for_each_dev(i, drive, hwif) {
-               u8 j = (hwif->index * MAX_DRIVES) + i;
-               u16 *saved_id = drive->id;
-
-               memset(drive, 0, sizeof(*drive));
-               memset(saved_id, 0, SECTOR_SIZE);
-               drive->id = saved_id;
-
-               drive->media                    = ide_disk;
-               drive->select                   = (i << 4) | ATA_DEVICE_OBS;
-               drive->hwif                     = hwif;
-               drive->ready_stat               = ATA_DRDY;
-               drive->bad_wstat                = BAD_W_STAT;
-               drive->special_flags            = IDE_SFLAG_RECALIBRATE |
-                                                 IDE_SFLAG_SET_GEOMETRY;
-               drive->name[0]                  = 'h';
-               drive->name[1]                  = 'd';
-               drive->name[2]                  = 'a' + j;
-               drive->max_failures             = IDE_DEFAULT_MAX_FAILURES;
-
-               INIT_LIST_HEAD(&drive->list);
-               init_completion(&drive->gendev_rel_comp);
-
-               INIT_WORK(&drive->rq_work, drive_rq_insert_work);
-               INIT_LIST_HEAD(&drive->rq_list);
-       }
-}
-
-static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
-{
-       /* fill in any non-zero initial values */
-       hwif->index     = index;
-       hwif->major     = ide_hwif_to_major[index];
-
-       hwif->name[0]   = 'i';
-       hwif->name[1]   = 'd';
-       hwif->name[2]   = 'e';
-       hwif->name[3]   = '0' + index;
-
-       spin_lock_init(&hwif->lock);
-
-       timer_setup(&hwif->timer, ide_timer_expiry, 0);
-
-       init_completion(&hwif->gendev_rel_comp);
-
-       hwif->tp_ops = &default_tp_ops;
-
-       ide_port_init_devices_data(hwif);
-}
-
-static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw)
-{
-       memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
-       hwif->irq = hw->irq;
-       hwif->dev = hw->dev;
-       hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
-       hwif->config_data = hw->config;
-}
-
-static unsigned int ide_indexes;
-
-/**
- *     ide_find_port_slot      -       find free port slot
- *     @d: IDE port info
- *
- *     Return the new port slot index or -ENOENT if we are out of free slots.
- */
-
-static int ide_find_port_slot(const struct ide_port_info *d)
-{
-       int idx = -ENOENT;
-       u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
-       u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;
-
-       /*
-        * Claim an unassigned slot.
-        *
-        * Give preference to claiming other slots before claiming ide0/ide1,
-        * just in case there's another interface yet-to-be-scanned
-        * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults).
-        *
-        * Unless there is a bootable card that does not use the standard
-        * ports 0x1f0/0x170 (the ide0/ide1 defaults).
-        */
-       mutex_lock(&ide_cfg_mtx);
-       if (bootable) {
-               if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
-                       idx = ffz(ide_indexes | i);
-       } else {
-               if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
-                       idx = ffz(ide_indexes | 3);
-               else if ((ide_indexes & 3) != 3)
-                       idx = ffz(ide_indexes);
-       }
-       if (idx >= 0)
-               ide_indexes |= (1 << idx);
-       mutex_unlock(&ide_cfg_mtx);
-
-       return idx;
-}
-
-static void ide_free_port_slot(int idx)
-{
-       mutex_lock(&ide_cfg_mtx);
-       ide_indexes &= ~(1 << idx);
-       mutex_unlock(&ide_cfg_mtx);
-}
-
-static void ide_port_free_devices(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i;
-
-       ide_port_for_each_dev(i, drive, hwif) {
-               kfree(drive->id);
-               kfree(drive);
-       }
-}
-
-static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
-{
-       ide_drive_t *drive;
-       int i;
-
-       for (i = 0; i < MAX_DRIVES; i++) {
-               drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node);
-               if (drive == NULL)
-                       goto out_nomem;
-
-               /*
-                * In order to keep things simple we have an id
-                * block for all drives at all times. If the device
-                * is pre ATA or refuses ATA/ATAPI identify we
-                * will add faked data to this.
-                *
-                * Also note that 0 everywhere means "can't do X"
-                */
-               drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
-               if (drive->id == NULL)
-                       goto out_free_drive;
-
-               hwif->devices[i] = drive;
-       }
-       return 0;
-
-out_free_drive:
-       kfree(drive);
-out_nomem:
-       ide_port_free_devices(hwif);
-       return -ENOMEM;
-}
-
-struct ide_host *ide_host_alloc(const struct ide_port_info *d,
-                               struct ide_hw **hws, unsigned int n_ports)
-{
-       struct ide_host *host;
-       struct device *dev = hws[0] ? hws[0]->dev : NULL;
-       int node = dev ? dev_to_node(dev) : -1;
-       int i;
-
-       host = kzalloc_node(sizeof(*host), GFP_KERNEL, node);
-       if (host == NULL)
-               return NULL;
-
-       for (i = 0; i < n_ports; i++) {
-               ide_hwif_t *hwif;
-               int idx;
-
-               if (hws[i] == NULL)
-                       continue;
-
-               hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node);
-               if (hwif == NULL)
-                       continue;
-
-               if (ide_port_alloc_devices(hwif, node) < 0) {
-                       kfree(hwif);
-                       continue;
-               }
-
-               idx = ide_find_port_slot(d);
-               if (idx < 0) {
-                       printk(KERN_ERR "%s: no free slot for interface\n",
-                                       d ? d->name : "ide");
-                       ide_port_free_devices(hwif);
-                       kfree(hwif);
-                       continue;
-               }
-
-               ide_init_port_data(hwif, idx);
-
-               hwif->host = host;
-
-               host->ports[i] = hwif;
-               host->n_ports++;
-       }
-
-       if (host->n_ports == 0) {
-               kfree(host);
-               return NULL;
-       }
-
-       host->dev[0] = dev;
-
-       if (d) {
-               host->init_chipset = d->init_chipset;
-               host->get_lock     = d->get_lock;
-               host->release_lock = d->release_lock;
-               host->host_flags = d->host_flags;
-               host->irq_flags = d->irq_flags;
-       }
-
-       return host;
-}
-EXPORT_SYMBOL_GPL(ide_host_alloc);
-
-static void ide_port_free(ide_hwif_t *hwif)
-{
-       ide_port_free_devices(hwif);
-       ide_free_port_slot(hwif->index);
-       kfree(hwif);
-}
-
-static void ide_disable_port(ide_hwif_t *hwif)
-{
-       struct ide_host *host = hwif->host;
-       int i;
-
-       printk(KERN_INFO "%s: disabling port\n", hwif->name);
-
-       for (i = 0; i < MAX_HOST_PORTS; i++) {
-               if (host->ports[i] == hwif) {
-                       host->ports[i] = NULL;
-                       host->n_ports--;
-               }
-       }
-
-       ide_port_free(hwif);
-}
-
-int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
-                     struct ide_hw **hws)
-{
-       ide_hwif_t *hwif, *mate = NULL;
-       int i, j = 0;
-
-       pr_warn("legacy IDE will be removed in 2021, please switch to libata\n"
-               "Report any missing HW support to linux-ide@vger.kernel.org\n");
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif == NULL) {
-                       mate = NULL;
-                       continue;
-               }
-
-               ide_init_port_hw(hwif, hws[i]);
-               ide_port_apply_params(hwif);
-
-               if ((i & 1) && mate) {
-                       hwif->mate = mate;
-                       mate->mate = hwif;
-               }
-
-               mate = (i & 1) ? NULL : hwif;
-
-               ide_init_port(hwif, i & 1, d);
-               ide_port_cable_detect(hwif);
-
-               hwif->port_flags |= IDE_PFLAG_PROBING;
-
-               ide_port_init_devices(hwif);
-       }
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif == NULL)
-                       continue;
-
-               if (ide_probe_port(hwif) == 0)
-                       hwif->present = 1;
-
-               hwif->port_flags &= ~IDE_PFLAG_PROBING;
-
-               if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 ||
-                   hwif->mate == NULL || hwif->mate->present == 0) {
-                       if (ide_register_port(hwif)) {
-                               ide_disable_port(hwif);
-                               continue;
-                       }
-               }
-
-               if (hwif->present)
-                       ide_port_tune_devices(hwif);
-       }
-
-       ide_host_enable_irqs(host);
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif == NULL)
-                       continue;
-
-               if (hwif_init(hwif) == 0) {
-                       printk(KERN_INFO "%s: failed to initialize IDE "
-                                        "interface\n", hwif->name);
-                       device_unregister(hwif->portdev);
-                       device_unregister(&hwif->gendev);
-                       ide_disable_port(hwif);
-                       continue;
-               }
-
-               if (hwif->present)
-                       if (ide_port_setup_devices(hwif) == 0) {
-                               hwif->present = 0;
-                               continue;
-                       }
-
-               j++;
-
-               ide_acpi_init_port(hwif);
-
-               if (hwif->present)
-                       ide_acpi_port_init_devices(hwif);
-       }
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif == NULL)
-                       continue;
-
-               ide_sysfs_register_port(hwif);
-               ide_proc_register_port(hwif);
-
-               if (hwif->present) {
-                       ide_proc_port_register_devices(hwif);
-                       hwif_register_devices(hwif);
-               }
-       }
-
-       return j ? 0 : -1;
-}
-EXPORT_SYMBOL_GPL(ide_host_register);
-
-int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws,
-                unsigned int n_ports, struct ide_host **hostp)
-{
-       struct ide_host *host;
-       int rc;
-
-       host = ide_host_alloc(d, hws, n_ports);
-       if (host == NULL)
-               return -ENOMEM;
-
-       rc = ide_host_register(host, d, hws);
-       if (rc) {
-               ide_host_free(host);
-               return rc;
-       }
-
-       if (hostp)
-               *hostp = host;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_host_add);
-
-static void __ide_port_unregister_devices(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i;
-
-       ide_port_for_each_present_dev(i, drive, hwif) {
-               device_unregister(&drive->gendev);
-               wait_for_completion(&drive->gendev_rel_comp);
-       }
-}
-
-void ide_port_unregister_devices(ide_hwif_t *hwif)
-{
-       mutex_lock(&ide_cfg_mtx);
-       __ide_port_unregister_devices(hwif);
-       hwif->present = 0;
-       ide_port_init_devices_data(hwif);
-       mutex_unlock(&ide_cfg_mtx);
-}
-EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
-
-/**
- *     ide_unregister          -       free an IDE interface
- *     @hwif: IDE interface
- *
- *     Perform the final unregister of an IDE interface.
- *
- *     Locking:
- *     The caller must not hold the IDE locks.
- *
- *     It is up to the caller to be sure there is no pending I/O here,
- *     and that the interface will not be reopened (present/vanishing
- *     locking isn't yet done BTW).
- */
-
-static void ide_unregister(ide_hwif_t *hwif)
-{
-       mutex_lock(&ide_cfg_mtx);
-
-       if (hwif->present) {
-               __ide_port_unregister_devices(hwif);
-               hwif->present = 0;
-       }
-
-       ide_proc_unregister_port(hwif);
-
-       if (!hwif->host->get_lock)
-               free_irq(hwif->irq, hwif);
-
-       device_unregister(hwif->portdev);
-       device_unregister(&hwif->gendev);
-       wait_for_completion(&hwif->gendev_rel_comp);
-
-       /*
-        * Remove us from the kernel's knowledge
-        */
-       kfree(hwif->sg_table);
-       unregister_blkdev(hwif->major, hwif->name);
-
-       ide_release_dma_engine(hwif);
-
-       mutex_unlock(&ide_cfg_mtx);
-}
-
-void ide_host_free(struct ide_host *host)
-{
-       ide_hwif_t *hwif;
-       int i;
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif)
-                       ide_port_free(hwif);
-       }
-
-       kfree(host);
-}
-EXPORT_SYMBOL_GPL(ide_host_free);
-
-void ide_host_remove(struct ide_host *host)
-{
-       ide_hwif_t *hwif;
-       int i;
-
-       ide_host_for_each_port(i, hwif, host) {
-               if (hwif)
-                       ide_unregister(hwif);
-       }
-
-       ide_host_free(host);
-}
-EXPORT_SYMBOL_GPL(ide_host_remove);
-
-void ide_port_scan(ide_hwif_t *hwif)
-{
-       int rc;
-
-       ide_port_apply_params(hwif);
-       ide_port_cable_detect(hwif);
-
-       hwif->port_flags |= IDE_PFLAG_PROBING;
-
-       ide_port_init_devices(hwif);
-
-       rc = ide_probe_port(hwif);
-
-       hwif->port_flags &= ~IDE_PFLAG_PROBING;
-
-       if (rc < 0)
-               return;
-
-       hwif->present = 1;
-
-       ide_port_tune_devices(hwif);
-       ide_port_setup_devices(hwif);
-       ide_acpi_port_init_devices(hwif);
-       hwif_register_devices(hwif);
-       ide_proc_port_register_devices(hwif);
-}
-EXPORT_SYMBOL_GPL(ide_port_scan);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
deleted file mode 100644 (file)
index 15c17f3..0000000
+++ /dev/null
@@ -1,633 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1997-1998    Mark Lord
- *  Copyright (C) 2003         Red Hat
- *
- *  Some code was moved here from ide.c, see it for original copyrights.
- */
-
-/*
- * This is the /proc/ide/ filesystem implementation.
- *
- * Drive/Driver settings can be retrieved by reading the drive's
- * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
- * To write a new value "val" into a specific setting "name", use:
- *   echo "name:val" >/proc/ide/ide0/hda/settings
- */
-
-#include <linux/module.h>
-
-#include <linux/uaccess.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/ctype.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-static struct proc_dir_entry *proc_ide_root;
-
-static int ide_imodel_proc_show(struct seq_file *m, void *v)
-{
-       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
-       const char      *name;
-
-       switch (hwif->chipset) {
-       case ide_generic:       name = "generic";       break;
-       case ide_pci:           name = "pci";           break;
-       case ide_cmd640:        name = "cmd640";        break;
-       case ide_dtc2278:       name = "dtc2278";       break;
-       case ide_ali14xx:       name = "ali14xx";       break;
-       case ide_qd65xx:        name = "qd65xx";        break;
-       case ide_umc8672:       name = "umc8672";       break;
-       case ide_ht6560b:       name = "ht6560b";       break;
-       case ide_4drives:       name = "4drives";       break;
-       case ide_pmac:          name = "mac-io";        break;
-       case ide_au1xxx:        name = "au1xxx";        break;
-       case ide_palm3710:      name = "palm3710";      break;
-       case ide_acorn:         name = "acorn";         break;
-       default:                name = "(unknown)";     break;
-       }
-       seq_printf(m, "%s\n", name);
-       return 0;
-}
-
-static int ide_mate_proc_show(struct seq_file *m, void *v)
-{
-       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
-
-       if (hwif && hwif->mate)
-               seq_printf(m, "%s\n", hwif->mate->name);
-       else
-               seq_printf(m, "(none)\n");
-       return 0;
-}
-
-static int ide_channel_proc_show(struct seq_file *m, void *v)
-{
-       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
-
-       seq_printf(m, "%c\n", hwif->channel ? '1' : '0');
-       return 0;
-}
-
-static int ide_identify_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t *drive = (ide_drive_t *)m->private;
-       u8 *buf;
-
-       if (!drive) {
-               seq_putc(m, '\n');
-               return 0;
-       }
-
-       buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       if (taskfile_lib_get_identify(drive, buf) == 0) {
-               __le16 *val = (__le16 *)buf;
-               int i;
-
-               for (i = 0; i < SECTOR_SIZE / 2; i++) {
-                       seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
-                                       (i % 8) == 7 ? '\n' : ' ');
-               }
-       } else
-               seq_putc(m, buf[0]);
-       kfree(buf);
-       return 0;
-}
-
-/**
- *     ide_find_setting        -       find a specific setting
- *     @st: setting table pointer
- *     @name: setting name
- *
- *     Scan's the setting table for a matching entry and returns
- *     this or NULL if no entry is found. The caller must hold the
- *     setting semaphore
- */
-
-static
-const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
-                                              char *name)
-{
-       while (st->name) {
-               if (strcmp(st->name, name) == 0)
-                       break;
-               st++;
-       }
-       return st->name ? st : NULL;
-}
-
-/**
- *     ide_read_setting        -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *
- *     Read a drive setting and return the value. The caller
- *     must hold the ide_setting_mtx when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- */
-
-static int ide_read_setting(ide_drive_t *drive,
-                           const struct ide_proc_devset *setting)
-{
-       const struct ide_devset *ds = setting->setting;
-       int val = -EINVAL;
-
-       if (ds->get)
-               val = ds->get(drive);
-
-       return val;
-}
-
-/**
- *     ide_write_setting       -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *     @val: value
- *
- *     Write a drive setting if it is possible. The caller
- *     must hold the ide_setting_mtx when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- *
- *     FIXME:  This should be changed to enqueue a special request
- *     to the driver to change settings, and then wait on a sema for completion.
- *     The current scheme of polling is kludgy, though safe enough.
- */
-
-static int ide_write_setting(ide_drive_t *drive,
-                            const struct ide_proc_devset *setting, int val)
-{
-       const struct ide_devset *ds = setting->setting;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-       if (!ds->set)
-               return -EPERM;
-       if ((ds->flags & DS_SYNC)
-           && (val < setting->min || val > setting->max))
-               return -EINVAL;
-       return ide_devset_execute(drive, ds, val);
-}
-
-ide_devset_get(xfer_rate, current_speed);
-
-static int set_xfer_rate (ide_drive_t *drive, int arg)
-{
-       struct ide_cmd cmd;
-
-       if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
-               return -EINVAL;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.tf.command = ATA_CMD_SET_FEATURES;
-       cmd.tf.feature = SETFEATURES_XFER;
-       cmd.tf.nsect   = (u8)arg;
-       cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
-       cmd.valid.in.tf  = IDE_VALID_NSECT;
-       cmd.tf_flags   = IDE_TFLAG_SET_XFER;
-
-       return ide_no_data_taskfile(drive, &cmd);
-}
-
-ide_devset_rw(current_speed, xfer_rate);
-ide_devset_rw_field(init_speed, init_speed);
-ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
-ide_devset_ro_field(number, dn);
-
-static const struct ide_proc_devset ide_generic_settings[] = {
-       IDE_PROC_DEVSET(current_speed, 0, 70),
-       IDE_PROC_DEVSET(init_speed, 0, 70),
-       IDE_PROC_DEVSET(io_32bit,  0, 1 + (SUPPORT_VLB_SYNC << 1)),
-       IDE_PROC_DEVSET(keepsettings, 0, 1),
-       IDE_PROC_DEVSET(nice1, 0, 1),
-       IDE_PROC_DEVSET(number, 0, 3),
-       IDE_PROC_DEVSET(pio_mode, 0, 255),
-       IDE_PROC_DEVSET(unmaskirq, 0, 1),
-       IDE_PROC_DEVSET(using_dma, 0, 1),
-       { NULL },
-};
-
-static void proc_ide_settings_warn(void)
-{
-       printk_once(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
-                           "obsolete, and will be removed soon!\n");
-}
-
-static int ide_settings_proc_show(struct seq_file *m, void *v)
-{
-       const struct ide_proc_devset *setting, *g, *d;
-       const struct ide_devset *ds;
-       ide_drive_t     *drive = (ide_drive_t *) m->private;
-       int             rc, mul_factor, div_factor;
-
-       proc_ide_settings_warn();
-
-       mutex_lock(&ide_setting_mtx);
-       g = ide_generic_settings;
-       d = drive->settings;
-       seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
-       seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
-       while (g->name || (d && d->name)) {
-               /* read settings in the alphabetical order */
-               if (g->name && d && d->name) {
-                       if (strcmp(d->name, g->name) < 0)
-                               setting = d++;
-                       else
-                               setting = g++;
-               } else if (d && d->name) {
-                       setting = d++;
-               } else
-                       setting = g++;
-               mul_factor = setting->mulf ? setting->mulf(drive) : 1;
-               div_factor = setting->divf ? setting->divf(drive) : 1;
-               seq_printf(m, "%-24s", setting->name);
-               rc = ide_read_setting(drive, setting);
-               if (rc >= 0)
-                       seq_printf(m, "%-16d", rc * mul_factor / div_factor);
-               else
-                       seq_printf(m, "%-16s", "write-only");
-               seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
-               ds = setting->setting;
-               if (ds->get)
-                       seq_printf(m, "r");
-               if (ds->set)
-                       seq_printf(m, "w");
-               seq_printf(m, "\n");
-       }
-       mutex_unlock(&ide_setting_mtx);
-       return 0;
-}
-
-static int ide_settings_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ide_settings_proc_show, PDE_DATA(inode));
-}
-
-#define MAX_LEN        30
-
-static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer,
-                                      size_t count, loff_t *pos)
-{
-       ide_drive_t     *drive = PDE_DATA(file_inode(file));
-       char            name[MAX_LEN + 1];
-       int             for_real = 0, mul_factor, div_factor;
-       unsigned long   n;
-
-       const struct ide_proc_devset *setting;
-       char *buf, *s;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-
-       proc_ide_settings_warn();
-
-       if (count >= PAGE_SIZE)
-               return -EINVAL;
-
-       s = buf = (char *)__get_free_page(GFP_USER);
-       if (!buf)
-               return -ENOMEM;
-
-       if (copy_from_user(buf, buffer, count)) {
-               free_page((unsigned long)buf);
-               return -EFAULT;
-       }
-
-       buf[count] = '\0';
-
-       /*
-        * Skip over leading whitespace
-        */
-       while (count && isspace(*s)) {
-               --count;
-               ++s;
-       }
-       /*
-        * Do one full pass to verify all parameters,
-        * then do another to actually write the new settings.
-        */
-       do {
-               char *p = s;
-               n = count;
-               while (n > 0) {
-                       unsigned val;
-                       char *q = p;
-
-                       while (n > 0 && *p != ':') {
-                               --n;
-                               p++;
-                       }
-                       if (*p != ':')
-                               goto parse_error;
-                       if (p - q > MAX_LEN)
-                               goto parse_error;
-                       memcpy(name, q, p - q);
-                       name[p - q] = 0;
-
-                       if (n > 0) {
-                               --n;
-                               p++;
-                       } else
-                               goto parse_error;
-
-                       val = simple_strtoul(p, &q, 10);
-                       n -= q - p;
-                       p = q;
-                       if (n > 0 && !isspace(*p))
-                               goto parse_error;
-                       while (n > 0 && isspace(*p)) {
-                               --n;
-                               ++p;
-                       }
-
-                       mutex_lock(&ide_setting_mtx);
-                       /* generic settings first, then driver specific ones */
-                       setting = ide_find_setting(ide_generic_settings, name);
-                       if (!setting) {
-                               if (drive->settings)
-                                       setting = ide_find_setting(drive->settings, name);
-                               if (!setting) {
-                                       mutex_unlock(&ide_setting_mtx);
-                                       goto parse_error;
-                               }
-                       }
-                       if (for_real) {
-                               mul_factor = setting->mulf ? setting->mulf(drive) : 1;
-                               div_factor = setting->divf ? setting->divf(drive) : 1;
-                               ide_write_setting(drive, setting, val * div_factor / mul_factor);
-                       }
-                       mutex_unlock(&ide_setting_mtx);
-               }
-       } while (!for_real++);
-       free_page((unsigned long)buf);
-       return count;
-parse_error:
-       free_page((unsigned long)buf);
-       printk("%s(): parse error\n", __func__);
-       return -EINVAL;
-}
-
-static const struct proc_ops ide_settings_proc_ops = {
-       .proc_open      = ide_settings_proc_open,
-       .proc_read      = seq_read,
-       .proc_lseek     = seq_lseek,
-       .proc_release   = single_release,
-       .proc_write     = ide_settings_proc_write,
-};
-
-int ide_capacity_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%llu\n", (long long)0x7fffffff);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_capacity_proc_show);
-
-int ide_geometry_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t     *drive = (ide_drive_t *) m->private;
-
-       seq_printf(m, "physical     %d/%d/%d\n",
-                       drive->cyl, drive->head, drive->sect);
-       seq_printf(m, "logical      %d/%d/%d\n",
-                       drive->bios_cyl, drive->bios_head, drive->bios_sect);
-       return 0;
-}
-EXPORT_SYMBOL(ide_geometry_proc_show);
-
-static int ide_dmodel_proc_show(struct seq_file *seq, void *v)
-{
-       ide_drive_t     *drive = (ide_drive_t *) seq->private;
-       char            *m = (char *)&drive->id[ATA_ID_PROD];
-
-       seq_printf(seq, "%.40s\n", m[0] ? m : "(none)");
-       return 0;
-}
-
-static int ide_driver_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t             *drive = (ide_drive_t *)m->private;
-       struct device           *dev = &drive->gendev;
-       struct ide_driver       *ide_drv;
-
-       if (dev->driver) {
-               ide_drv = to_ide_driver(dev->driver);
-               seq_printf(m, "%s version %s\n",
-                               dev->driver->name, ide_drv->version);
-       } else
-               seq_printf(m, "ide-default version 0.9.newide\n");
-       return 0;
-}
-
-static int ide_media_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t     *drive = (ide_drive_t *) m->private;
-       const char      *media;
-
-       switch (drive->media) {
-       case ide_disk:          media = "disk\n";       break;
-       case ide_cdrom:         media = "cdrom\n";      break;
-       case ide_tape:          media = "tape\n";       break;
-       case ide_floppy:        media = "floppy\n";     break;
-       case ide_optical:       media = "optical\n";    break;
-       default:                media = "UNKNOWN\n";    break;
-       }
-       seq_puts(m, media);
-       return 0;
-}
-
-static int ide_media_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ide_media_proc_show, PDE_DATA(inode));
-}
-
-static const struct file_operations ide_media_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ide_media_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static ide_proc_entry_t generic_drive_entries[] = {
-       { "driver",     S_IFREG|S_IRUGO,         ide_driver_proc_show   },
-       { "identify",   S_IFREG|S_IRUSR,         ide_identify_proc_show },
-       { "media",      S_IFREG|S_IRUGO,         ide_media_proc_show    },
-       { "model",      S_IFREG|S_IRUGO,         ide_dmodel_proc_show   },
-       {}
-};
-
-static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
-{
-       struct proc_dir_entry *ent;
-
-       if (!dir || !p)
-               return;
-       while (p->name != NULL) {
-               ent = proc_create_single_data(p->name, p->mode, dir, p->show, data);
-               if (!ent) return;
-               p++;
-       }
-}
-
-static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
-{
-       if (!dir || !p)
-               return;
-       while (p->name != NULL) {
-               remove_proc_entry(p->name, dir);
-               p++;
-       }
-}
-
-void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver)
-{
-       mutex_lock(&ide_setting_mtx);
-       drive->settings = driver->proc_devsets(drive);
-       mutex_unlock(&ide_setting_mtx);
-
-       ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive);
-}
-
-EXPORT_SYMBOL(ide_proc_register_driver);
-
-/**
- *     ide_proc_unregister_driver      -       remove driver specific data
- *     @drive: drive
- *     @driver: driver
- *
- *     Clean up the driver specific /proc files and IDE settings
- *     for a given drive.
- *
- *     Takes ide_setting_mtx.
- */
-
-void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver)
-{
-       ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
-
-       mutex_lock(&ide_setting_mtx);
-       /*
-        * ide_setting_mtx protects both the settings list and the use
-        * of settings (we cannot take a setting out that is being used).
-        */
-       drive->settings = NULL;
-       mutex_unlock(&ide_setting_mtx);
-}
-EXPORT_SYMBOL(ide_proc_unregister_driver);
-
-void ide_proc_port_register_devices(ide_hwif_t *hwif)
-{
-       struct proc_dir_entry *ent;
-       struct proc_dir_entry *parent = hwif->proc;
-       ide_drive_t *drive;
-       char name[64];
-       int i;
-
-       ide_port_for_each_dev(i, drive, hwif) {
-               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
-                       continue;
-
-               drive->proc = proc_mkdir(drive->name, parent);
-               if (drive->proc) {
-                       ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
-                       proc_create_data("settings", S_IFREG|S_IRUSR|S_IWUSR,
-                                       drive->proc, &ide_settings_proc_ops,
-                                       drive);
-               }
-               sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name);
-               ent = proc_symlink(drive->name, proc_ide_root, name);
-               if (!ent) return;
-       }
-}
-
-void ide_proc_unregister_device(ide_drive_t *drive)
-{
-       if (drive->proc) {
-               remove_proc_entry("settings", drive->proc);
-               ide_remove_proc_entries(drive->proc, generic_drive_entries);
-               remove_proc_entry(drive->name, proc_ide_root);
-               remove_proc_entry(drive->name, drive->hwif->proc);
-               drive->proc = NULL;
-       }
-}
-
-static ide_proc_entry_t hwif_entries[] = {
-       { "channel",    S_IFREG|S_IRUGO,        ide_channel_proc_show   },
-       { "mate",       S_IFREG|S_IRUGO,        ide_mate_proc_show      },
-       { "model",      S_IFREG|S_IRUGO,        ide_imodel_proc_show    },
-       {}
-};
-
-void ide_proc_register_port(ide_hwif_t *hwif)
-{
-       if (!hwif->proc) {
-               hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
-
-               if (!hwif->proc)
-                       return;
-
-               ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
-       }
-}
-
-void ide_proc_unregister_port(ide_hwif_t *hwif)
-{
-       if (hwif->proc) {
-               ide_remove_proc_entries(hwif->proc, hwif_entries);
-               remove_proc_entry(hwif->name, proc_ide_root);
-               hwif->proc = NULL;
-       }
-}
-
-static int proc_print_driver(struct device_driver *drv, void *data)
-{
-       struct ide_driver *ide_drv = to_ide_driver(drv);
-       struct seq_file *s = data;
-
-       seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
-
-       return 0;
-}
-
-static int ide_drivers_show(struct seq_file *s, void *p)
-{
-       int err;
-
-       err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
-       if (err < 0)
-               printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
-                       __func__, err);
-       return 0;
-}
-
-DEFINE_PROC_SHOW_ATTRIBUTE(ide_drivers);
-
-void proc_ide_create(void)
-{
-       proc_ide_root = proc_mkdir("ide", NULL);
-
-       if (!proc_ide_root)
-               return;
-
-       proc_create("drivers", 0, proc_ide_root, &ide_drivers_proc_ops);
-}
-
-void proc_ide_destroy(void)
-{
-       remove_proc_entry("drivers", proc_ide_root);
-       remove_proc_entry("ide", NULL);
-}
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
deleted file mode 100644 (file)
index b0411a1..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * support for probing IDE PCI devices in the PCI bus order
- *
- * Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- * Copyright (c) 1995-1998  Mark Lord
- *
- * May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-
-/*
- *     Module interfaces
- */
-
-static int pre_init = 1;               /* Before first ordered IDE scan */
-static LIST_HEAD(ide_pci_drivers);
-
-/*
- *     __ide_pci_register_driver       -       attach IDE driver
- *     @driver: pci driver
- *     @module: owner module of the driver
- *
- *     Registers a driver with the IDE layer. The IDE layer arranges that
- *     boot time setup is done in the expected device order and then
- *     hands the controllers off to the core PCI code to do the rest of
- *     the work.
- *
- *     Returns are the same as for pci_register_driver
- */
-
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
-                             const char *mod_name)
-{
-       if (!pre_init)
-               return __pci_register_driver(driver, module, mod_name);
-       driver->driver.owner = module;
-       list_add_tail(&driver->node, &ide_pci_drivers);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-
-/**
- *     ide_scan_pcidev         -       find an IDE driver for a device
- *     @dev: PCI device to check
- *
- *     Look for an IDE driver to handle the device we are considering.
- *     This is only used during boot up to get the ordering correct. After
- *     boot up the pci layer takes over the job.
- */
-
-static int __init ide_scan_pcidev(struct pci_dev *dev)
-{
-       struct list_head *l;
-       struct pci_driver *d;
-       int ret;
-
-       list_for_each(l, &ide_pci_drivers) {
-               d = list_entry(l, struct pci_driver, node);
-               if (d->id_table) {
-                       const struct pci_device_id *id =
-                               pci_match_id(d->id_table, dev);
-
-                       if (id != NULL) {
-                               pci_assign_irq(dev);
-                               ret = d->probe(dev, id);
-                               if (ret >= 0) {
-                                       dev->driver = d;
-                                       pci_dev_get(dev);
-                                       return 1;
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
- *     ide_scan_pcibus         -       perform the initial IDE driver scan
- *
- *     Perform the initial bus rather than driver ordered scan of the
- *     PCI drivers. After this all IDE pci handling becomes standard
- *     module ordering not traditionally ordered.
- */
-
-static int __init ide_scan_pcibus(void)
-{
-       struct pci_dev *dev = NULL;
-       struct pci_driver *d, *tmp;
-
-       pre_init = 0;
-       for_each_pci_dev(dev)
-               ide_scan_pcidev(dev);
-
-       /*
-        *      Hand the drivers over to the PCI layer now we
-        *      are post init.
-        */
-
-       list_for_each_entry_safe(d, tmp, &ide_pci_drivers, node) {
-               list_del(&d->node);
-               if (__pci_register_driver(d, d->driver.owner,
-                                         d->driver.mod_name))
-                       printk(KERN_ERR "%s: failed to register %s driver\n",
-                                       __func__, d->driver.mod_name);
-       }
-
-       return 0;
-}
-device_initcall(ide_scan_pcibus);
diff --git a/drivers/ide/ide-sysfs.c b/drivers/ide/ide-sysfs.c
deleted file mode 100644 (file)
index c08a8a0..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-
-char *ide_media_string(ide_drive_t *drive)
-{
-       switch (drive->media) {
-       case ide_disk:
-               return "disk";
-       case ide_cdrom:
-               return "cdrom";
-       case ide_tape:
-               return "tape";
-       case ide_floppy:
-               return "floppy";
-       case ide_optical:
-               return "optical";
-       default:
-               return "UNKNOWN";
-       }
-}
-
-static ssize_t media_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", ide_media_string(drive));
-}
-static DEVICE_ATTR_RO(media);
-
-static ssize_t drivename_show(struct device *dev, struct device_attribute *attr,
-                             char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", drive->name);
-}
-static DEVICE_ATTR_RO(drivename);
-
-static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
-                            char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "ide:m-%s\n", ide_media_string(drive));
-}
-static DEVICE_ATTR_RO(modalias);
-
-static ssize_t model_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
-}
-static DEVICE_ATTR_RO(model);
-
-static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
-                            char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
-}
-static DEVICE_ATTR_RO(firmware);
-
-static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
-}
-static DEVICE_ATTR(serial, 0400, serial_show, NULL);
-
-static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store);
-
-static struct attribute *ide_attrs[] = {
-       &dev_attr_media.attr,
-       &dev_attr_drivename.attr,
-       &dev_attr_modalias.attr,
-       &dev_attr_model.attr,
-       &dev_attr_firmware.attr,
-       &dev_attr_serial.attr,
-       &dev_attr_unload_heads.attr,
-       NULL,
-};
-
-static const struct attribute_group ide_attr_group = {
-       .attrs = ide_attrs,
-};
-
-const struct attribute_group *ide_dev_groups[] = {
-       &ide_attr_group,
-       NULL,
-};
-
-static ssize_t store_delete_devices(struct device *portdev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t n)
-{
-       ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
-       if (strncmp(buf, "1", n))
-               return -EINVAL;
-
-       ide_port_unregister_devices(hwif);
-
-       return n;
-};
-
-static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
-
-static ssize_t store_scan(struct device *portdev,
-                         struct device_attribute *attr,
-                         const char *buf, size_t n)
-{
-       ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
-       if (strncmp(buf, "1", n))
-               return -EINVAL;
-
-       ide_port_unregister_devices(hwif);
-       ide_port_scan(hwif);
-
-       return n;
-};
-
-static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
-
-static struct device_attribute *ide_port_attrs[] = {
-       &dev_attr_delete_devices,
-       &dev_attr_scan,
-       NULL
-};
-
-int ide_sysfs_register_port(ide_hwif_t *hwif)
-{
-       int i, rc;
-
-       for (i = 0; ide_port_attrs[i]; i++) {
-               rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
-               if (rc)
-                       break;
-       }
-
-       return rc;
-}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
deleted file mode 100644 (file)
index fa05e7e..0000000
+++ /dev/null
@@ -1,2083 +0,0 @@
-/*
- * IDE ATAPI streaming tape driver.
- *
- * Copyright (C) 1995-1999  Gadi Oxman <gadio@netvision.net.il>
- * Copyright (C) 2003-2005  Bartlomiej Zolnierkiewicz
- *
- * This driver was constructed as a student project in the software laboratory
- * of the faculty of electrical engineering in the Technion - Israel's
- * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
- *
- * It is hereby placed under the terms of the GNU general public license.
- * (See linux/COPYING).
- *
- * For a historical changelog see
- * Documentation/ide/ChangeLog.ide-tape.1995-2002
- */
-
-#define DRV_NAME "ide-tape"
-
-#define IDETAPE_VERSION "1.20"
-
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <scsi/scsi.h>
-
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-#include <linux/mtio.h>
-
-/* define to see debug info */
-#undef IDETAPE_DEBUG_LOG
-
-#ifdef IDETAPE_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-/**************************** Tunable parameters *****************************/
-/*
- * After each failed packet command we issue a request sense command and retry
- * the packet command IDETAPE_MAX_PC_RETRIES times.
- *
- * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
- */
-#define IDETAPE_MAX_PC_RETRIES         3
-
-/*
- * The following parameter is used to select the point in the internal tape fifo
- * in which we will start to refill the buffer. Decreasing the following
- * parameter will improve the system's latency and interactive response, while
- * using a high value might improve system throughput.
- */
-#define IDETAPE_FIFO_THRESHOLD         2
-
-/*
- * DSC polling parameters.
- *
- * Polling for DSC (a single bit in the status register) is a very important
- * function in ide-tape. There are two cases in which we poll for DSC:
- *
- * 1. Before a read/write packet command, to ensure that we can transfer data
- * from/to the tape's data buffers, without causing an actual media access.
- * In case the tape is not ready yet, we take out our request from the device
- * request queue, so that ide.c could service requests from the other device
- * on the same interface in the meantime.
- *
- * 2. After the successful initialization of a "media access packet command",
- * which is a command that can take a long time to complete (the interval can
- * range from several seconds to even an hour). Again, we postpone our request
- * in the middle to free the bus for the other device. The polling frequency
- * here should be lower than the read/write frequency since those media access
- * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
- * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
- * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
- *
- * We also set a timeout for the timer, in case something goes wrong. The
- * timeout should be longer then the maximum execution time of a tape operation.
- */
-
-/* DSC timings. */
-#define IDETAPE_DSC_RW_MIN             5*HZ/100        /* 50 msec */
-#define IDETAPE_DSC_RW_MAX             40*HZ/100       /* 400 msec */
-#define IDETAPE_DSC_RW_TIMEOUT         2*60*HZ         /* 2 minutes */
-#define IDETAPE_DSC_MA_FAST            2*HZ            /* 2 seconds */
-#define IDETAPE_DSC_MA_THRESHOLD       5*60*HZ         /* 5 minutes */
-#define IDETAPE_DSC_MA_SLOW            30*HZ           /* 30 seconds */
-#define IDETAPE_DSC_MA_TIMEOUT         2*60*60*HZ      /* 2 hours */
-
-/*************************** End of tunable parameters ***********************/
-
-/* tape directions */
-enum {
-       IDETAPE_DIR_NONE  = (1 << 0),
-       IDETAPE_DIR_READ  = (1 << 1),
-       IDETAPE_DIR_WRITE = (1 << 2),
-};
-
-/* Tape door status */
-#define DOOR_UNLOCKED                  0
-#define DOOR_LOCKED                    1
-#define DOOR_EXPLICITLY_LOCKED         2
-
-/* Some defines for the SPACE command */
-#define IDETAPE_SPACE_OVER_FILEMARK    1
-#define IDETAPE_SPACE_TO_EOD           3
-
-/* Some defines for the LOAD UNLOAD command */
-#define IDETAPE_LU_LOAD_MASK           1
-#define IDETAPE_LU_RETENSION_MASK      2
-#define IDETAPE_LU_EOT_MASK            4
-
-/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
-#define IDETAPE_BLOCK_DESCRIPTOR       0
-#define IDETAPE_CAPABILITIES_PAGE      0x2a
-
-/*
- * Most of our global data which we need to save even as we leave the driver due
- * to an interrupt or a timer event is stored in the struct defined below.
- */
-typedef struct ide_tape_obj {
-       ide_drive_t             *drive;
-       struct ide_driver       *driver;
-       struct gendisk          *disk;
-       struct device           dev;
-
-       /* used by REQ_IDETAPE_{READ,WRITE} requests */
-       struct ide_atapi_pc queued_pc;
-
-       /*
-        * DSC polling variables.
-        *
-        * While polling for DSC we use postponed_rq to postpone the current
-        * request so that ide.c will be able to service pending requests on the
-        * other device. Note that at most we will have only one DSC (usually
-        * data transfer) request in the device request queue.
-        */
-       bool postponed_rq;
-
-       /* The time in which we started polling for DSC */
-       unsigned long dsc_polling_start;
-       /* Timer used to poll for dsc */
-       struct timer_list dsc_timer;
-       /* Read/Write dsc polling frequency */
-       unsigned long best_dsc_rw_freq;
-       unsigned long dsc_poll_freq;
-       unsigned long dsc_timeout;
-
-       /* Read position information */
-       u8 partition;
-       /* Current block */
-       unsigned int first_frame;
-
-       /* Last error information */
-       u8 sense_key, asc, ascq;
-
-       /* Character device operation */
-       unsigned int minor;
-       /* device name */
-       char name[4];
-       /* Current character device data transfer direction */
-       u8 chrdev_dir;
-
-       /* tape block size, usually 512 or 1024 bytes */
-       unsigned short blk_size;
-       int user_bs_factor;
-
-       /* Copy of the tape's Capabilities and Mechanical Page */
-       u8 caps[20];
-
-       /*
-        * Active data transfer request parameters.
-        *
-        * At most, there is only one ide-tape originated data transfer request
-        * in the device request queue. This allows ide.c to easily service
-        * requests from the other device when we postpone our active request.
-        */
-
-       /* Data buffer size chosen based on the tape's recommendation */
-       int buffer_size;
-       /* Staging buffer of buffer_size bytes */
-       void *buf;
-       /* The read/write cursor */
-       void *cur;
-       /* The number of valid bytes in buf */
-       size_t valid;
-
-       /* Measures average tape speed */
-       unsigned long avg_time;
-       int avg_size;
-       int avg_speed;
-
-       /* the door is currently locked */
-       int door_locked;
-       /* the tape hardware is write protected */
-       char drv_write_prot;
-       /* the tape is write protected (hardware or opened as read-only) */
-       char write_prot;
-} idetape_tape_t;
-
-static DEFINE_MUTEX(ide_tape_mutex);
-static DEFINE_MUTEX(idetape_ref_mutex);
-
-static DEFINE_MUTEX(idetape_chrdev_mutex);
-
-static struct class *idetape_sysfs_class;
-
-static void ide_tape_release(struct device *);
-
-static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
-
-static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev,
-                                        unsigned int i)
-{
-       struct ide_tape_obj *tape = NULL;
-
-       mutex_lock(&idetape_ref_mutex);
-
-       if (cdev)
-               tape = idetape_devs[i];
-       else
-               tape = ide_drv_g(disk, ide_tape_obj);
-
-       if (tape) {
-               if (ide_device_get(tape->drive))
-                       tape = NULL;
-               else
-                       get_device(&tape->dev);
-       }
-
-       mutex_unlock(&idetape_ref_mutex);
-       return tape;
-}
-
-static void ide_tape_put(struct ide_tape_obj *tape)
-{
-       ide_drive_t *drive = tape->drive;
-
-       mutex_lock(&idetape_ref_mutex);
-       put_device(&tape->dev);
-       ide_device_put(drive);
-       mutex_unlock(&idetape_ref_mutex);
-}
-
-/*
- * called on each failed packet command retry to analyze the request sense. We
- * currently do not utilize this information.
- */
-static void idetape_analyze_error(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = drive->failed_pc;
-       struct request *rq = drive->hwif->rq;
-       u8 *sense = bio_data(rq->bio);
-
-       tape->sense_key = sense[2] & 0xF;
-       tape->asc       = sense[12];
-       tape->ascq      = sense[13];
-
-       ide_debug_log(IDE_DBG_FUNC,
-                     "cmd: 0x%x, sense key = %x, asc = %x, ascq = %x",
-                     rq->cmd[0], tape->sense_key, tape->asc, tape->ascq);
-
-       /* correct remaining bytes to transfer */
-       if (pc->flags & PC_FLAG_DMA_ERROR)
-               scsi_req(rq)->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]);
-
-       /*
-        * If error was the result of a zero-length read or write command,
-        * with sense key=5, asc=0x22, ascq=0, let it slide.  Some drives
-        * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.
-        */
-       if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6)
-           /* length == 0 */
-           && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) {
-               if (tape->sense_key == 5) {
-                       /* don't report an error, everything's ok */
-                       pc->error = 0;
-                       /* don't retry read/write */
-                       pc->flags |= PC_FLAG_ABORT;
-               }
-       }
-       if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
-               pc->error = IDE_DRV_ERROR_FILEMARK;
-               pc->flags |= PC_FLAG_ABORT;
-       }
-       if (pc->c[0] == WRITE_6) {
-               if ((sense[2] & 0x40) || (tape->sense_key == 0xd
-                    && tape->asc == 0x0 && tape->ascq == 0x2)) {
-                       pc->error = IDE_DRV_ERROR_EOD;
-                       pc->flags |= PC_FLAG_ABORT;
-               }
-       }
-       if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
-               if (tape->sense_key == 8) {
-                       pc->error = IDE_DRV_ERROR_EOD;
-                       pc->flags |= PC_FLAG_ABORT;
-               }
-               if (!(pc->flags & PC_FLAG_ABORT) &&
-                   (blk_rq_bytes(rq) - scsi_req(rq)->resid_len))
-                       pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
-       }
-}
-
-static void ide_tape_handle_dsc(ide_drive_t *);
-
-static int ide_tape_callback(ide_drive_t *drive, int dsc)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = drive->pc;
-       struct request *rq = drive->hwif->rq;
-       int uptodate = pc->error ? 0 : 1;
-       int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc: %d, err: %d", rq->cmd[0],
-                     dsc, err);
-
-       if (dsc)
-               ide_tape_handle_dsc(drive);
-
-       if (drive->failed_pc == pc)
-               drive->failed_pc = NULL;
-
-       if (pc->c[0] == REQUEST_SENSE) {
-               if (uptodate)
-                       idetape_analyze_error(drive);
-               else
-                       printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
-                                       "itself - Aborting request!\n");
-       } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
-               unsigned int blocks =
-                       (blk_rq_bytes(rq) - scsi_req(rq)->resid_len) / tape->blk_size;
-
-               tape->avg_size += blocks * tape->blk_size;
-
-               if (time_after_eq(jiffies, tape->avg_time + HZ)) {
-                       tape->avg_speed = tape->avg_size * HZ /
-                               (jiffies - tape->avg_time) / 1024;
-                       tape->avg_size = 0;
-                       tape->avg_time = jiffies;
-               }
-
-               tape->first_frame += blocks;
-
-               if (pc->error) {
-                       uptodate = 0;
-                       err = pc->error;
-               }
-       }
-       scsi_req(rq)->result = err;
-
-       return uptodate;
-}
-
-/*
- * Postpone the current request so that ide.c will be able to service requests
- * from another device on the same port while we are polling for DSC.
- */
-static void ide_tape_stall_queue(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc_poll_freq: %lu",
-                     drive->hwif->rq->cmd[0], tape->dsc_poll_freq);
-
-       tape->postponed_rq = true;
-
-       ide_stall_queue(drive, tape->dsc_poll_freq);
-}
-
-static void ide_tape_handle_dsc(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       /* Media access command */
-       tape->dsc_polling_start = jiffies;
-       tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
-       tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-       /* Allow ide.c to handle other requests */
-       ide_tape_stall_queue(drive);
-}
-
-/*
- * Packet Command Interface
- *
- * The current Packet Command is available in drive->pc, and will not change
- * until we finish handling it. Each packet command is associated with a
- * callback function that will be called when the command is finished.
- *
- * The handling will be done in three stages:
- *
- * 1. ide_tape_issue_pc will send the packet command to the drive, and will set
- * the interrupt handler to ide_pc_intr.
- *
- * 2. On each interrupt, ide_pc_intr will be called. This step will be
- * repeated until the device signals us that no more interrupts will be issued.
- *
- * 3. ATAPI Tape media access commands have immediate status with a delayed
- * process. In case of a successful initiation of a media access packet command,
- * the DSC bit will be set when the actual execution of the command is finished.
- * Since the tape drive will not issue an interrupt, we have to poll for this
- * event. In this case, we define the request as "low priority request" by
- * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
- * exit the driver.
- *
- * ide.c will then give higher priority to requests which originate from the
- * other device, until will change rq_status to RQ_ACTIVE.
- *
- * 4. When the packet command is finished, it will be checked for errors.
- *
- * 5. In case an error was found, we queue a request sense packet command in
- * front of the request queue and retry the operation up to
- * IDETAPE_MAX_PC_RETRIES times.
- *
- * 6. In case no error was found, or we decided to give up and not to retry
- * again, the callback function will be called and then we will handle the next
- * request.
- */
-
-static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
-                                        struct ide_cmd *cmd,
-                                        struct ide_atapi_pc *pc)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct request *rq = drive->hwif->rq;
-
-       if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
-               drive->failed_pc = pc;
-
-       /* Set the current packet command */
-       drive->pc = pc;
-
-       if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
-               (pc->flags & PC_FLAG_ABORT)) {
-
-               /*
-                * We will "abort" retrying a packet command in case legitimate
-                * error code was received (crossing a filemark, or end of the
-                * media, for example).
-                */
-               if (!(pc->flags & PC_FLAG_ABORT)) {
-                       if (!(pc->c[0] == TEST_UNIT_READY &&
-                             tape->sense_key == 2 && tape->asc == 4 &&
-                            (tape->ascq == 1 || tape->ascq == 8))) {
-                               printk(KERN_ERR "ide-tape: %s: I/O error, "
-                                               "pc = %2x, key = %2x, "
-                                               "asc = %2x, ascq = %2x\n",
-                                               tape->name, pc->c[0],
-                                               tape->sense_key, tape->asc,
-                                               tape->ascq);
-                       }
-                       /* Giving up */
-                       pc->error = IDE_DRV_ERROR_GENERAL;
-               }
-
-               drive->failed_pc = NULL;
-               drive->pc_callback(drive, 0);
-               ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
-               return ide_stopped;
-       }
-       ide_debug_log(IDE_DBG_SENSE, "retry #%d, cmd: 0x%02x", pc->retries,
-                     pc->c[0]);
-
-       pc->retries++;
-
-       return ide_issue_pc(drive, cmd);
-}
-
-/* A mode sense command is used to "sense" tape parameters. */
-static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
-{
-       ide_init_pc(pc);
-       pc->c[0] = MODE_SENSE;
-       if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-               /* DBD = 1 - Don't return block descriptors */
-               pc->c[1] = 8;
-       pc->c[2] = page_code;
-       /*
-        * Changed pc->c[3] to 0 (255 will at best return unused info).
-        *
-        * For SCSI this byte is defined as subpage instead of high byte
-        * of length and some IDE drives seem to interpret it this way
-        * and return an error when 255 is used.
-        */
-       pc->c[3] = 0;
-       /* We will just discard data in that case */
-       pc->c[4] = 255;
-       if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
-               pc->req_xfer = 12;
-       else if (page_code == IDETAPE_CAPABILITIES_PAGE)
-               pc->req_xfer = 24;
-       else
-               pc->req_xfer = 50;
-}
-
-static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = drive->pc;
-       u8 stat;
-
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if (stat & ATA_DSC) {
-               if (stat & ATA_ERR) {
-                       /* Error detected */
-                       if (pc->c[0] != TEST_UNIT_READY)
-                               printk(KERN_ERR "ide-tape: %s: I/O error, ",
-                                               tape->name);
-                       /* Retry operation */
-                       ide_retry_pc(drive);
-                       return ide_stopped;
-               }
-               pc->error = 0;
-       } else {
-               pc->error = IDE_DRV_ERROR_GENERAL;
-               drive->failed_pc = NULL;
-       }
-       drive->pc_callback(drive, 0);
-       return ide_stopped;
-}
-
-static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
-                                  struct ide_atapi_pc *pc, struct request *rq,
-                                  u8 opcode)
-{
-       unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9);
-
-       ide_init_pc(pc);
-       put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
-       pc->c[1] = 1;
-
-       if (blk_rq_bytes(rq) == tape->buffer_size)
-               pc->flags |= PC_FLAG_DMA_OK;
-
-       if (opcode == READ_6)
-               pc->c[0] = READ_6;
-       else if (opcode == WRITE_6) {
-               pc->c[0] = WRITE_6;
-               pc->flags |= PC_FLAG_WRITING;
-       }
-
-       memcpy(scsi_req(rq)->cmd, pc->c, 12);
-}
-
-static ide_startstop_t idetape_do_request(ide_drive_t *drive,
-                                         struct request *rq, sector_t block)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc *pc = NULL;
-       struct ide_cmd cmd;
-       struct scsi_request *req = scsi_req(rq);
-       u8 stat;
-
-       ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u",
-                     req->cmd[0], (unsigned long long)blk_rq_pos(rq),
-                     blk_rq_sectors(rq));
-
-       BUG_ON(!blk_rq_is_private(rq));
-       BUG_ON(ide_req(rq)->type != ATA_PRIV_MISC &&
-              ide_req(rq)->type != ATA_PRIV_SENSE);
-
-       /* Retry a failed packet command */
-       if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
-               pc = drive->failed_pc;
-               goto out;
-       }
-
-       /*
-        * If the tape is still busy, postpone our request and service
-        * the other device meanwhile.
-        */
-       stat = hwif->tp_ops->read_status(hwif);
-
-       if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
-           (req->cmd[13] & REQ_IDETAPE_PC2) == 0)
-               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
-
-       if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
-               drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
-               drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
-       }
-
-       if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
-           !(stat & ATA_DSC)) {
-               if (!tape->postponed_rq) {
-                       tape->dsc_polling_start = jiffies;
-                       tape->dsc_poll_freq = tape->best_dsc_rw_freq;
-                       tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
-               } else if (time_after(jiffies, tape->dsc_timeout)) {
-                       printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
-                               tape->name);
-                       if (req->cmd[13] & REQ_IDETAPE_PC2) {
-                               idetape_media_access_finished(drive);
-                               return ide_stopped;
-                       } else {
-                               return ide_do_reset(drive);
-                       }
-               } else if (time_after(jiffies,
-                                       tape->dsc_polling_start +
-                                       IDETAPE_DSC_MA_THRESHOLD))
-                       tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
-               ide_tape_stall_queue(drive);
-               return ide_stopped;
-       } else {
-               drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
-               tape->postponed_rq = false;
-       }
-
-       if (req->cmd[13] & REQ_IDETAPE_READ) {
-               pc = &tape->queued_pc;
-               ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
-               goto out;
-       }
-       if (req->cmd[13] & REQ_IDETAPE_WRITE) {
-               pc = &tape->queued_pc;
-               ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
-               goto out;
-       }
-       if (req->cmd[13] & REQ_IDETAPE_PC1) {
-               pc = (struct ide_atapi_pc *)ide_req(rq)->special;
-               req->cmd[13] &= ~(REQ_IDETAPE_PC1);
-               req->cmd[13] |= REQ_IDETAPE_PC2;
-               goto out;
-       }
-       if (req->cmd[13] & REQ_IDETAPE_PC2) {
-               idetape_media_access_finished(drive);
-               return ide_stopped;
-       }
-       BUG();
-
-out:
-       /* prepare sense request for this command */
-       ide_prep_sense(drive, rq);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       if (rq_data_dir(rq))
-               cmd.tf_flags |= IDE_TFLAG_WRITE;
-
-       cmd.rq = rq;
-
-       ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
-       ide_map_sg(drive, &cmd);
-
-       return ide_tape_issue_pc(drive, &cmd, pc);
-}
-
-/*
- * Write a filemark if write_filemark=1. Flush the device buffers without
- * writing a filemark otherwise.
- */
-static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
-               struct ide_atapi_pc *pc, int write_filemark)
-{
-       ide_init_pc(pc);
-       pc->c[0] = WRITE_FILEMARKS;
-       pc->c[4] = write_filemark;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct gendisk *disk = tape->disk;
-       int load_attempted = 0;
-
-       /* Wait for the tape to become ready */
-       set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags);
-       timeout += jiffies;
-       while (time_before(jiffies, timeout)) {
-               if (ide_do_test_unit_ready(drive, disk) == 0)
-                       return 0;
-               if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
-                   || (tape->asc == 0x3A)) {
-                       /* no media */
-                       if (load_attempted)
-                               return -ENOMEDIUM;
-                       ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
-                       load_attempted = 1;
-               /* not about to be ready */
-               } else if (!(tape->sense_key == 2 && tape->asc == 4 &&
-                            (tape->ascq == 1 || tape->ascq == 8)))
-                       return -EIO;
-               msleep(100);
-       }
-       return -EIO;
-}
-
-static int idetape_flush_tape_buffers(ide_drive_t *drive)
-{
-       struct ide_tape_obj *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-       int rc;
-
-       idetape_create_write_filemark_cmd(drive, &pc, 0);
-       rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0);
-       if (rc)
-               return rc;
-       idetape_wait_ready(drive, 60 * 5 * HZ);
-       return 0;
-}
-
-static int ide_tape_read_position(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-       u8 buf[20];
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       /* prep cmd */
-       ide_init_pc(&pc);
-       pc.c[0] = READ_POSITION;
-       pc.req_xfer = 20;
-
-       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer))
-               return -1;
-
-       if (!pc.error) {
-               ide_debug_log(IDE_DBG_FUNC, "BOP - %s",
-                               (buf[0] & 0x80) ? "Yes" : "No");
-               ide_debug_log(IDE_DBG_FUNC, "EOP - %s",
-                               (buf[0] & 0x40) ? "Yes" : "No");
-
-               if (buf[0] & 0x4) {
-                       printk(KERN_INFO "ide-tape: Block location is unknown"
-                                        "to the tape\n");
-                       clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
-                                 &drive->atapi_flags);
-                       return -1;
-               } else {
-                       ide_debug_log(IDE_DBG_FUNC, "Block Location: %u",
-                                     be32_to_cpup((__be32 *)&buf[4]));
-
-                       tape->partition = buf[1];
-                       tape->first_frame = be32_to_cpup((__be32 *)&buf[4]);
-                       set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
-                               &drive->atapi_flags);
-               }
-       }
-
-       return tape->first_frame;
-}
-
-static void idetape_create_locate_cmd(ide_drive_t *drive,
-               struct ide_atapi_pc *pc,
-               unsigned int block, u8 partition, int skip)
-{
-       ide_init_pc(pc);
-       pc->c[0] = POSITION_TO_ELEMENT;
-       pc->c[1] = 2;
-       put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
-       pc->c[8] = partition;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       if (tape->chrdev_dir != IDETAPE_DIR_READ)
-               return;
-
-       clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags);
-       tape->valid = 0;
-       if (tape->buf != NULL) {
-               kfree(tape->buf);
-               tape->buf = NULL;
-       }
-
-       tape->chrdev_dir = IDETAPE_DIR_NONE;
-}
-
-/*
- * Position the tape to the requested block using the LOCATE packet command.
- * A READ POSITION command is then issued to check where we are positioned. Like
- * all higher level operations, we queue the commands at the tail of the request
- * queue and wait for their completion.
- */
-static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
-               u8 partition, int skip)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct gendisk *disk = tape->disk;
-       int ret;
-       struct ide_atapi_pc pc;
-
-       if (tape->chrdev_dir == IDETAPE_DIR_READ)
-               __ide_tape_discard_merge_buffer(drive);
-       idetape_wait_ready(drive, 60 * 5 * HZ);
-       idetape_create_locate_cmd(drive, &pc, block, partition, skip);
-       ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-       if (ret)
-               return ret;
-
-       ret = ide_tape_read_position(drive);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
-                                         int restore_position)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       int seek, position;
-
-       __ide_tape_discard_merge_buffer(drive);
-       if (restore_position) {
-               position = ide_tape_read_position(drive);
-               seek = position > 0 ? position : 0;
-               if (idetape_position_tape(drive, seek, 0, 0)) {
-                       printk(KERN_INFO "ide-tape: %s: position_tape failed in"
-                                        " %s\n", tape->name, __func__);
-                       return;
-               }
-       }
-}
-
-/*
- * Generate a read/write request for the block device interface and wait for it
- * to be serviced.
- */
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct request *rq;
-       int ret;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, size: %d", cmd, size);
-
-       BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
-       BUG_ON(size < 0 || size % tape->blk_size);
-
-       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_MISC;
-       scsi_req(rq)->cmd[13] = cmd;
-       rq->rq_disk = tape->disk;
-       rq->__sector = tape->first_frame;
-
-       if (size) {
-               ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size,
-                                     GFP_NOIO);
-               if (ret)
-                       goto out_put;
-       }
-
-       blk_execute_rq(tape->disk, rq, 0);
-
-       /* calculate the number of transferred bytes and update buffer state */
-       size -= scsi_req(rq)->resid_len;
-       tape->cur = tape->buf;
-       if (cmd == REQ_IDETAPE_READ)
-               tape->valid = size;
-       else
-               tape->valid = 0;
-
-       ret = size;
-       if (scsi_req(rq)->result == IDE_DRV_ERROR_GENERAL)
-               ret = -EIO;
-out_put:
-       blk_put_request(rq);
-       return ret;
-}
-
-static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
-{
-       ide_init_pc(pc);
-       pc->c[0] = INQUIRY;
-       pc->c[4] = 254;
-       pc->req_xfer = 254;
-}
-
-static void idetape_create_rewind_cmd(ide_drive_t *drive,
-               struct ide_atapi_pc *pc)
-{
-       ide_init_pc(pc);
-       pc->c[0] = REZERO_UNIT;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
-{
-       ide_init_pc(pc);
-       pc->c[0] = ERASE;
-       pc->c[1] = 1;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
-{
-       ide_init_pc(pc);
-       pc->c[0] = SPACE;
-       put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
-       pc->c[1] = cmd;
-       pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void ide_tape_flush_merge_buffer(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
-               printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer"
-                               " but we are not writing.\n");
-               return;
-       }
-       if (tape->buf) {
-               size_t aligned = roundup(tape->valid, tape->blk_size);
-
-               memset(tape->cur, 0, aligned - tape->valid);
-               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned);
-               kfree(tape->buf);
-               tape->buf = NULL;
-       }
-       tape->chrdev_dir = IDETAPE_DIR_NONE;
-}
-
-static int idetape_init_rw(ide_drive_t *drive, int dir)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       int rc;
-
-       BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE);
-
-       if (tape->chrdev_dir == dir)
-               return 0;
-
-       if (tape->chrdev_dir == IDETAPE_DIR_READ)
-               ide_tape_discard_merge_buffer(drive, 1);
-       else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
-               ide_tape_flush_merge_buffer(drive);
-               idetape_flush_tape_buffers(drive);
-       }
-
-       if (tape->buf || tape->valid) {
-               printk(KERN_ERR "ide-tape: valid should be 0 now\n");
-               tape->valid = 0;
-       }
-
-       tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
-       if (!tape->buf)
-               return -ENOMEM;
-       tape->chrdev_dir = dir;
-       tape->cur = tape->buf;
-
-       /*
-        * Issue a 0 rw command to ensure that DSC handshake is
-        * switched from completion mode to buffer available mode.  No
-        * point in issuing this if DSC overlap isn't supported, some
-        * drives (Seagate STT3401A) will return an error.
-        */
-       if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
-               int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ
-                                                 : REQ_IDETAPE_WRITE;
-
-               rc = idetape_queue_rw_tail(drive, cmd, 0);
-               if (rc < 0) {
-                       kfree(tape->buf);
-                       tape->buf = NULL;
-                       tape->chrdev_dir = IDETAPE_DIR_NONE;
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       memset(tape->buf, 0, tape->buffer_size);
-
-       while (bcount) {
-               unsigned int count = min(tape->buffer_size, bcount);
-
-               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count);
-               bcount -= count;
-       }
-}
-
-/*
- * Rewinds the tape to the Beginning Of the current Partition (BOP). We
- * currently support only one partition.
- */
-static int idetape_rewind_tape(ide_drive_t *drive)
-{
-       struct ide_tape_obj *tape = drive->driver_data;
-       struct gendisk *disk = tape->disk;
-       struct ide_atapi_pc pc;
-       int ret;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       idetape_create_rewind_cmd(drive, &pc);
-       ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-       if (ret)
-               return ret;
-
-       ret = ide_tape_read_position(drive);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-/* mtio.h compatible commands should be issued to the chrdev interface. */
-static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
-                               unsigned long arg)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       void __user *argp = (void __user *)arg;
-
-       struct idetape_config {
-               int dsc_rw_frequency;
-               int dsc_media_access_frequency;
-               int nr_stages;
-       } config;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%04x", cmd);
-
-       switch (cmd) {
-       case 0x0340:
-               if (copy_from_user(&config, argp, sizeof(config)))
-                       return -EFAULT;
-               tape->best_dsc_rw_freq = config.dsc_rw_frequency;
-               break;
-       case 0x0350:
-               memset(&config, 0, sizeof(config));
-               config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
-               config.nr_stages = 1;
-               if (copy_to_user(argp, &config, sizeof(config)))
-                       return -EFAULT;
-               break;
-       default:
-               return -EIO;
-       }
-       return 0;
-}
-
-static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
-                                       int mt_count)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct gendisk *disk = tape->disk;
-       struct ide_atapi_pc pc;
-       int retval, count = 0;
-       int sprev = !!(tape->caps[4] & 0x20);
-
-
-       ide_debug_log(IDE_DBG_FUNC, "mt_op: %d, mt_count: %d", mt_op, mt_count);
-
-       if (mt_count == 0)
-               return 0;
-       if (MTBSF == mt_op || MTBSFM == mt_op) {
-               if (!sprev)
-                       return -EIO;
-               mt_count = -mt_count;
-       }
-
-       if (tape->chrdev_dir == IDETAPE_DIR_READ) {
-               tape->valid = 0;
-               if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK),
-                                      &drive->atapi_flags))
-                       ++count;
-               ide_tape_discard_merge_buffer(drive, 0);
-       }
-
-       switch (mt_op) {
-       case MTFSF:
-       case MTBSF:
-               idetape_create_space_cmd(&pc, mt_count - count,
-                                        IDETAPE_SPACE_OVER_FILEMARK);
-               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-       case MTFSFM:
-       case MTBSFM:
-               if (!sprev)
-                       return -EIO;
-               retval = idetape_space_over_filemarks(drive, MTFSF,
-                                                     mt_count - count);
-               if (retval)
-                       return retval;
-               count = (MTBSFM == mt_op ? 1 : -1);
-               return idetape_space_over_filemarks(drive, MTFSF, count);
-       default:
-               printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
-                               mt_op);
-               return -EIO;
-       }
-}
-
-/*
- * Our character device read / write functions.
- *
- * The tape is optimized to maximize throughput when it is transferring an
- * integral number of the "continuous transfer limit", which is a parameter of
- * the specific tape (26kB on my particular tape, 32kB for Onstream).
- *
- * As of version 1.3 of the driver, the character device provides an abstract
- * continuous view of the media - any mix of block sizes (even 1 byte) on the
- * same backup/restore procedure is supported. The driver will internally
- * convert the requests to the recommended transfer unit, so that an unmatch
- * between the user's block size to the recommended size will only result in a
- * (slightly) increased driver overhead, but will no longer hit performance.
- * This is not applicable to Onstream.
- */
-static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       struct ide_tape_obj *tape = file->private_data;
-       ide_drive_t *drive = tape->drive;
-       size_t done = 0;
-       ssize_t ret = 0;
-       int rc;
-
-       ide_debug_log(IDE_DBG_FUNC, "count %zd", count);
-
-       if (tape->chrdev_dir != IDETAPE_DIR_READ) {
-               if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags))
-                       if (count > tape->blk_size &&
-                           (count % tape->blk_size) == 0)
-                               tape->user_bs_factor = count / tape->blk_size;
-       }
-
-       rc = idetape_init_rw(drive, IDETAPE_DIR_READ);
-       if (rc < 0)
-               return rc;
-
-       while (done < count) {
-               size_t todo;
-
-               /* refill if staging buffer is empty */
-               if (!tape->valid) {
-                       /* If we are at a filemark, nothing more to read */
-                       if (test_bit(ilog2(IDE_AFLAG_FILEMARK),
-                                    &drive->atapi_flags))
-                               break;
-                       /* read */
-                       if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
-                                                 tape->buffer_size) <= 0)
-                               break;
-               }
-
-               /* copy out */
-               todo = min_t(size_t, count - done, tape->valid);
-               if (copy_to_user(buf + done, tape->cur, todo))
-                       ret = -EFAULT;
-
-               tape->cur += todo;
-               tape->valid -= todo;
-               done += todo;
-       }
-
-       if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
-               idetape_space_over_filemarks(drive, MTFSF, 1);
-               return 0;
-       }
-
-       return ret ? ret : done;
-}
-
-static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
-                                    size_t count, loff_t *ppos)
-{
-       struct ide_tape_obj *tape = file->private_data;
-       ide_drive_t *drive = tape->drive;
-       size_t done = 0;
-       ssize_t ret = 0;
-       int rc;
-
-       /* The drive is write protected. */
-       if (tape->write_prot)
-               return -EACCES;
-
-       ide_debug_log(IDE_DBG_FUNC, "count %zd", count);
-
-       /* Initialize write operation */
-       rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE);
-       if (rc < 0)
-               return rc;
-
-       while (done < count) {
-               size_t todo;
-
-               /* flush if staging buffer is full */
-               if (tape->valid == tape->buffer_size &&
-                   idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
-                                         tape->buffer_size) <= 0)
-                       return rc;
-
-               /* copy in */
-               todo = min_t(size_t, count - done,
-                            tape->buffer_size - tape->valid);
-               if (copy_from_user(tape->cur, buf + done, todo))
-                       ret = -EFAULT;
-
-               tape->cur += todo;
-               tape->valid += todo;
-               done += todo;
-       }
-
-       return ret ? ret : done;
-}
-
-static int idetape_write_filemark(ide_drive_t *drive)
-{
-       struct ide_tape_obj *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-
-       /* Write a filemark */
-       idetape_create_write_filemark_cmd(drive, &pc, 1);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) {
-               printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-/*
- * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is
- * requested.
- *
- * Note: MTBSF and MTBSFM are not supported when the tape doesn't support
- * spacing over filemarks in the reverse direction. In this case, MTFSFM is also
- * usually not supported.
- *
- * The following commands are currently not supported:
- *
- * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS,
- * MT_ST_WRITE_THRESHOLD.
- */
-static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct gendisk *disk = tape->disk;
-       struct ide_atapi_pc pc;
-       int i, retval;
-
-       ide_debug_log(IDE_DBG_FUNC, "MTIOCTOP ioctl: mt_op: %d, mt_count: %d",
-                     mt_op, mt_count);
-
-       switch (mt_op) {
-       case MTFSF:
-       case MTFSFM:
-       case MTBSF:
-       case MTBSFM:
-               if (!mt_count)
-                       return 0;
-               return idetape_space_over_filemarks(drive, mt_op, mt_count);
-       default:
-               break;
-       }
-
-       switch (mt_op) {
-       case MTWEOF:
-               if (tape->write_prot)
-                       return -EACCES;
-               ide_tape_discard_merge_buffer(drive, 1);
-               for (i = 0; i < mt_count; i++) {
-                       retval = idetape_write_filemark(drive);
-                       if (retval)
-                               return retval;
-               }
-               return 0;
-       case MTREW:
-               ide_tape_discard_merge_buffer(drive, 0);
-               if (idetape_rewind_tape(drive))
-                       return -EIO;
-               return 0;
-       case MTLOAD:
-               ide_tape_discard_merge_buffer(drive, 0);
-               return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
-       case MTUNLOAD:
-       case MTOFFL:
-               /*
-                * If door is locked, attempt to unlock before
-                * attempting to eject.
-                */
-               if (tape->door_locked) {
-                       if (!ide_set_media_lock(drive, disk, 0))
-                               tape->door_locked = DOOR_UNLOCKED;
-               }
-               ide_tape_discard_merge_buffer(drive, 0);
-               retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
-               if (!retval)
-                       clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
-                                 &drive->atapi_flags);
-               return retval;
-       case MTNOP:
-               ide_tape_discard_merge_buffer(drive, 0);
-               return idetape_flush_tape_buffers(drive);
-       case MTRETEN:
-               ide_tape_discard_merge_buffer(drive, 0);
-               return ide_do_start_stop(drive, disk,
-                       IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-       case MTEOM:
-               idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
-               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-       case MTERASE:
-               (void)idetape_rewind_tape(drive);
-               idetape_create_erase_cmd(&pc);
-               return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-       case MTSETBLK:
-               if (mt_count) {
-                       if (mt_count < tape->blk_size ||
-                           mt_count % tape->blk_size)
-                               return -EIO;
-                       tape->user_bs_factor = mt_count / tape->blk_size;
-                       clear_bit(ilog2(IDE_AFLAG_DETECT_BS),
-                                 &drive->atapi_flags);
-               } else
-                       set_bit(ilog2(IDE_AFLAG_DETECT_BS),
-                               &drive->atapi_flags);
-               return 0;
-       case MTSEEK:
-               ide_tape_discard_merge_buffer(drive, 0);
-               return idetape_position_tape(drive,
-                       mt_count * tape->user_bs_factor, tape->partition, 0);
-       case MTSETPART:
-               ide_tape_discard_merge_buffer(drive, 0);
-               return idetape_position_tape(drive, 0, mt_count, 0);
-       case MTFSR:
-       case MTBSR:
-       case MTLOCK:
-               retval = ide_set_media_lock(drive, disk, 1);
-               if (retval)
-                       return retval;
-               tape->door_locked = DOOR_EXPLICITLY_LOCKED;
-               return 0;
-       case MTUNLOCK:
-               retval = ide_set_media_lock(drive, disk, 0);
-               if (retval)
-                       return retval;
-               tape->door_locked = DOOR_UNLOCKED;
-               return 0;
-       default:
-               printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
-                               mt_op);
-               return -EIO;
-       }
-}
-
-/*
- * Our character device ioctls. General mtio.h magnetic io commands are
- * supported here, and not in the corresponding block interface. Our own
- * ide-tape ioctls are supported on both interfaces.
- */
-static long do_idetape_chrdev_ioctl(struct file *file,
-                               unsigned int cmd, unsigned long arg)
-{
-       struct ide_tape_obj *tape = file->private_data;
-       ide_drive_t *drive = tape->drive;
-       struct mtop mtop;
-       struct mtget mtget;
-       struct mtpos mtpos;
-       int block_offset = 0, position = tape->first_frame;
-       void __user *argp = (void __user *)arg;
-
-       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x", cmd);
-
-       if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
-               ide_tape_flush_merge_buffer(drive);
-               idetape_flush_tape_buffers(drive);
-       }
-       if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-               block_offset = tape->valid /
-                       (tape->blk_size * tape->user_bs_factor);
-               position = ide_tape_read_position(drive);
-               if (position < 0)
-                       return -EIO;
-       }
-       switch (cmd) {
-       case MTIOCTOP:
-               if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
-                       return -EFAULT;
-               return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
-       case MTIOCGET:
-               memset(&mtget, 0, sizeof(struct mtget));
-               mtget.mt_type = MT_ISSCSI2;
-               mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-               mtget.mt_dsreg =
-                       ((tape->blk_size * tape->user_bs_factor)
-                        << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
-
-               if (tape->drv_write_prot)
-                       mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
-
-               return put_user_mtget(argp, &mtget);
-       case MTIOCPOS:
-               mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
-               return put_user_mtpos(argp, &mtpos);
-       default:
-               if (tape->chrdev_dir == IDETAPE_DIR_READ)
-                       ide_tape_discard_merge_buffer(drive, 1);
-               return idetape_blkdev_ioctl(drive, cmd, arg);
-       }
-}
-
-static long idetape_chrdev_ioctl(struct file *file,
-                               unsigned int cmd, unsigned long arg)
-{
-       long ret;
-       mutex_lock(&ide_tape_mutex);
-       ret = do_idetape_chrdev_ioctl(file, cmd, arg);
-       mutex_unlock(&ide_tape_mutex);
-       return ret;
-}
-
-static long idetape_chrdev_compat_ioctl(struct file *file,
-                               unsigned int cmd, unsigned long arg)
-{
-       long ret;
-
-       if (cmd == MTIOCPOS32)
-               cmd = MTIOCPOS;
-       else if (cmd == MTIOCGET32)
-               cmd = MTIOCGET;
-
-       mutex_lock(&ide_tape_mutex);
-       ret = do_idetape_chrdev_ioctl(file, cmd, arg);
-       mutex_unlock(&ide_tape_mutex);
-       return ret;
-}
-
-/*
- * Do a mode sense page 0 with block descriptor and if it succeeds set the tape
- * block size with the reported value.
- */
-static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-       u8 buf[12];
-
-       idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
-               printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
-               if (tape->blk_size == 0) {
-                       printk(KERN_WARNING "ide-tape: Cannot deal with zero "
-                                           "block size, assuming 32k\n");
-                       tape->blk_size = 32768;
-               }
-               return;
-       }
-       tape->blk_size = (buf[4 + 5] << 16) +
-                               (buf[4 + 6] << 8)  +
-                                buf[4 + 7];
-       tape->drv_write_prot = (buf[2] & 0x80) >> 7;
-
-       ide_debug_log(IDE_DBG_FUNC, "blk_size: %d, write_prot: %d",
-                     tape->blk_size, tape->drv_write_prot);
-}
-
-static int idetape_chrdev_open(struct inode *inode, struct file *filp)
-{
-       unsigned int minor = iminor(inode), i = minor & ~0xc0;
-       ide_drive_t *drive;
-       idetape_tape_t *tape;
-       int retval;
-
-       if (i >= MAX_HWIFS * MAX_DRIVES)
-               return -ENXIO;
-
-       mutex_lock(&idetape_chrdev_mutex);
-
-       tape = ide_tape_get(NULL, true, i);
-       if (!tape) {
-               mutex_unlock(&idetape_chrdev_mutex);
-               return -ENXIO;
-       }
-
-       drive = tape->drive;
-       filp->private_data = tape;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       /*
-        * We really want to do nonseekable_open(inode, filp); here, but some
-        * versions of tar incorrectly call lseek on tapes and bail out if that
-        * fails.  So we disallow pread() and pwrite(), but permit lseeks.
-        */
-       filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-
-
-       if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
-               retval = -EBUSY;
-               goto out_put_tape;
-       }
-
-       retval = idetape_wait_ready(drive, 60 * HZ);
-       if (retval) {
-               clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
-               printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
-               goto out_put_tape;
-       }
-
-       ide_tape_read_position(drive);
-       if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags))
-               (void)idetape_rewind_tape(drive);
-
-       /* Read block size and write protect status from drive. */
-       ide_tape_get_bsize_from_bdesc(drive);
-
-       /* Set write protect flag if device is opened as read-only. */
-       if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
-               tape->write_prot = 1;
-       else
-               tape->write_prot = tape->drv_write_prot;
-
-       /* Make sure drive isn't write protected if user wants to write. */
-       if (tape->write_prot) {
-               if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
-                   (filp->f_flags & O_ACCMODE) == O_RDWR) {
-                       clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
-                       retval = -EROFS;
-                       goto out_put_tape;
-               }
-       }
-
-       /* Lock the tape drive door so user can't eject. */
-       if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
-               if (!ide_set_media_lock(drive, tape->disk, 1)) {
-                       if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
-                               tape->door_locked = DOOR_LOCKED;
-               }
-       }
-       mutex_unlock(&idetape_chrdev_mutex);
-
-       return 0;
-
-out_put_tape:
-       ide_tape_put(tape);
-
-       mutex_unlock(&idetape_chrdev_mutex);
-
-       return retval;
-}
-
-static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       ide_tape_flush_merge_buffer(drive);
-       tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
-       if (tape->buf != NULL) {
-               idetape_pad_zeros(drive, tape->blk_size *
-                               (tape->user_bs_factor - 1));
-               kfree(tape->buf);
-               tape->buf = NULL;
-       }
-       idetape_write_filemark(drive);
-       idetape_flush_tape_buffers(drive);
-       idetape_flush_tape_buffers(drive);
-}
-
-static int idetape_chrdev_release(struct inode *inode, struct file *filp)
-{
-       struct ide_tape_obj *tape = filp->private_data;
-       ide_drive_t *drive = tape->drive;
-       unsigned int minor = iminor(inode);
-
-       mutex_lock(&idetape_chrdev_mutex);
-
-       tape = drive->driver_data;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
-               idetape_write_release(drive, minor);
-       if (tape->chrdev_dir == IDETAPE_DIR_READ) {
-               if (minor < 128)
-                       ide_tape_discard_merge_buffer(drive, 1);
-       }
-
-       if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
-                                   &drive->atapi_flags))
-               (void) idetape_rewind_tape(drive);
-
-       if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
-               if (tape->door_locked == DOOR_LOCKED) {
-                       if (!ide_set_media_lock(drive, tape->disk, 0))
-                               tape->door_locked = DOOR_UNLOCKED;
-               }
-       }
-       clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
-       ide_tape_put(tape);
-
-       mutex_unlock(&idetape_chrdev_mutex);
-
-       return 0;
-}
-
-static void idetape_get_inquiry_results(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-       u8 pc_buf[256];
-       char fw_rev[4], vendor_id[8], product_id[16];
-
-       idetape_create_inquiry_cmd(&pc);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) {
-               printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
-                               tape->name);
-               return;
-       }
-       memcpy(vendor_id, &pc_buf[8], 8);
-       memcpy(product_id, &pc_buf[16], 16);
-       memcpy(fw_rev, &pc_buf[32], 4);
-
-       ide_fixstring(vendor_id, 8, 0);
-       ide_fixstring(product_id, 16, 0);
-       ide_fixstring(fw_rev, 4, 0);
-
-       printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
-                       drive->name, tape->name, vendor_id, product_id, fw_rev);
-}
-
-/*
- * Ask the tape about its various parameters. In particular, we will adjust our
- * data transfer buffer        size to the recommended value as returned by the tape.
- */
-static void idetape_get_mode_sense_results(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       struct ide_atapi_pc pc;
-       u8 buf[24], *caps;
-       u8 speed, max_speed;
-
-       idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
-       if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
-               printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
-                               " some default values\n");
-               tape->blk_size = 512;
-               put_unaligned(52,   (u16 *)&tape->caps[12]);
-               put_unaligned(540,  (u16 *)&tape->caps[14]);
-               put_unaligned(6*52, (u16 *)&tape->caps[16]);
-               return;
-       }
-       caps = buf + 4 + buf[3];
-
-       /* convert to host order and save for later use */
-       speed = be16_to_cpup((__be16 *)&caps[14]);
-       max_speed = be16_to_cpup((__be16 *)&caps[8]);
-
-       *(u16 *)&caps[8] = max_speed;
-       *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]);
-       *(u16 *)&caps[14] = speed;
-       *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]);
-
-       if (!speed) {
-               printk(KERN_INFO "ide-tape: %s: invalid tape speed "
-                               "(assuming 650KB/sec)\n", drive->name);
-               *(u16 *)&caps[14] = 650;
-       }
-       if (!max_speed) {
-               printk(KERN_INFO "ide-tape: %s: invalid max_speed "
-                               "(assuming 650KB/sec)\n", drive->name);
-               *(u16 *)&caps[8] = 650;
-       }
-
-       memcpy(&tape->caps, caps, 20);
-
-       /* device lacks locking support according to capabilities page */
-       if ((caps[6] & 1) == 0)
-               drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-
-       if (caps[7] & 0x02)
-               tape->blk_size = 512;
-       else if (caps[7] & 0x04)
-               tape->blk_size = 1024;
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-#define ide_tape_devset_get(name, field) \
-static int get_##name(ide_drive_t *drive) \
-{ \
-       idetape_tape_t *tape = drive->driver_data; \
-       return tape->field; \
-}
-
-#define ide_tape_devset_set(name, field) \
-static int set_##name(ide_drive_t *drive, int arg) \
-{ \
-       idetape_tape_t *tape = drive->driver_data; \
-       tape->field = arg; \
-       return 0; \
-}
-
-#define ide_tape_devset_rw_field(_name, _field) \
-ide_tape_devset_get(_name, _field) \
-ide_tape_devset_set(_name, _field) \
-IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
-
-#define ide_tape_devset_r_field(_name, _field) \
-ide_tape_devset_get(_name, _field) \
-IDE_DEVSET(_name, 0, get_##_name, NULL)
-
-static int mulf_tdsc(ide_drive_t *drive)       { return 1000; }
-static int divf_tdsc(ide_drive_t *drive)       { return   HZ; }
-static int divf_buffer(ide_drive_t *drive)     { return    2; }
-static int divf_buffer_size(ide_drive_t *drive)        { return 1024; }
-
-ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
-
-ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
-
-ide_tape_devset_r_field(avg_speed, avg_speed);
-ide_tape_devset_r_field(speed, caps[14]);
-ide_tape_devset_r_field(buffer, caps[16]);
-ide_tape_devset_r_field(buffer_size, buffer_size);
-
-static const struct ide_proc_devset idetape_settings[] = {
-       __IDE_PROC_DEVSET(avg_speed,    0, 0xffff, NULL, NULL),
-       __IDE_PROC_DEVSET(buffer,       0, 0xffff, NULL, divf_buffer),
-       __IDE_PROC_DEVSET(buffer_size,  0, 0xffff, NULL, divf_buffer_size),
-       __IDE_PROC_DEVSET(dsc_overlap,  0,      1, NULL, NULL),
-       __IDE_PROC_DEVSET(speed,        0, 0xffff, NULL, NULL),
-       __IDE_PROC_DEVSET(tdsc,         IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
-                                       mulf_tdsc, divf_tdsc),
-       { NULL },
-};
-#endif
-
-/*
- * The function below is called to:
- *
- * 1. Initialize our various state variables.
- * 2. Ask the tape for its capabilities.
- * 3. Allocate a buffer which will be used for data transfer. The buffer size
- * is chosen based on the recommendation which we received in step 2.
- *
- * Note that at this point ide.c already assigned us an irq, so that we can
- * queue requests here and wait for their completion.
- */
-static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
-{
-       unsigned long t;
-       int speed;
-       u16 *ctl = (u16 *)&tape->caps[12];
-
-       ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor);
-
-       drive->pc_callback = ide_tape_callback;
-
-       drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
-
-       if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
-               printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
-                                tape->name);
-               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-       }
-
-       /* Seagate Travan drives do not support DSC overlap. */
-       if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
-               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-
-       tape->minor = minor;
-       tape->name[0] = 'h';
-       tape->name[1] = 't';
-       tape->name[2] = '0' + minor;
-       tape->chrdev_dir = IDETAPE_DIR_NONE;
-
-       idetape_get_inquiry_results(drive);
-       idetape_get_mode_sense_results(drive);
-       ide_tape_get_bsize_from_bdesc(drive);
-       tape->user_bs_factor = 1;
-       tape->buffer_size = *ctl * tape->blk_size;
-       while (tape->buffer_size > 0xffff) {
-               printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
-               *ctl /= 2;
-               tape->buffer_size = *ctl * tape->blk_size;
-       }
-
-       /* select the "best" DSC read/write polling freq */
-       speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
-
-       t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000);
-
-       /*
-        * Ensure that the number we got makes sense; limit it within
-        * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
-        */
-       tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
-                                        IDETAPE_DSC_RW_MAX);
-       printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
-               "%ums tDSC%s\n",
-               drive->name, tape->name, *(u16 *)&tape->caps[14],
-               (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
-               tape->buffer_size / 1024,
-               jiffies_to_msecs(tape->best_dsc_rw_freq),
-               (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
-
-       ide_proc_register_driver(drive, tape->driver);
-}
-
-static void ide_tape_remove(ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-
-       ide_proc_unregister_driver(drive, tape->driver);
-       device_del(&tape->dev);
-
-       mutex_lock(&idetape_ref_mutex);
-       put_device(&tape->dev);
-       mutex_unlock(&idetape_ref_mutex);
-}
-
-static void ide_tape_release(struct device *dev)
-{
-       struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj);
-       ide_drive_t *drive = tape->drive;
-       struct gendisk *g = tape->disk;
-
-       BUG_ON(tape->valid);
-
-       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-       drive->driver_data = NULL;
-       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
-       device_destroy(idetape_sysfs_class,
-                       MKDEV(IDETAPE_MAJOR, tape->minor + 128));
-       idetape_devs[tape->minor] = NULL;
-       g->private_data = NULL;
-       put_disk(g);
-       kfree(tape);
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static int idetape_name_proc_show(struct seq_file *m, void *v)
-{
-       ide_drive_t     *drive = (ide_drive_t *) m->private;
-       idetape_tape_t  *tape = drive->driver_data;
-
-       seq_printf(m, "%s\n", tape->name);
-       return 0;
-}
-
-static ide_proc_entry_t idetape_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO,        ide_capacity_proc_show  },
-       { "name",       S_IFREG|S_IRUGO,        idetape_name_proc_show  },
-       {}
-};
-
-static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive)
-{
-       return idetape_proc;
-}
-
-static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive)
-{
-       return idetape_settings;
-}
-#endif
-
-static int ide_tape_probe(ide_drive_t *);
-
-static struct ide_driver idetape_driver = {
-       .gen_driver = {
-               .owner          = THIS_MODULE,
-               .name           = "ide-tape",
-               .bus            = &ide_bus_type,
-       },
-       .probe                  = ide_tape_probe,
-       .remove                 = ide_tape_remove,
-       .version                = IDETAPE_VERSION,
-       .do_request             = idetape_do_request,
-#ifdef CONFIG_IDE_PROC_FS
-       .proc_entries           = ide_tape_proc_entries,
-       .proc_devsets           = ide_tape_proc_devsets,
-#endif
-};
-
-/* Our character device supporting functions, passed to register_chrdev. */
-static const struct file_operations idetape_fops = {
-       .owner          = THIS_MODULE,
-       .read           = idetape_chrdev_read,
-       .write          = idetape_chrdev_write,
-       .unlocked_ioctl = idetape_chrdev_ioctl,
-       .compat_ioctl   = IS_ENABLED(CONFIG_COMPAT) ?
-                         idetape_chrdev_compat_ioctl : NULL,
-       .open           = idetape_chrdev_open,
-       .release        = idetape_chrdev_release,
-       .llseek         = noop_llseek,
-};
-
-static int idetape_open(struct block_device *bdev, fmode_t mode)
-{
-       struct ide_tape_obj *tape;
-
-       mutex_lock(&ide_tape_mutex);
-       tape = ide_tape_get(bdev->bd_disk, false, 0);
-       mutex_unlock(&ide_tape_mutex);
-
-       if (!tape)
-               return -ENXIO;
-
-       return 0;
-}
-
-static void idetape_release(struct gendisk *disk, fmode_t mode)
-{
-       struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
-
-       mutex_lock(&ide_tape_mutex);
-       ide_tape_put(tape);
-       mutex_unlock(&ide_tape_mutex);
-}
-
-static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
-       ide_drive_t *drive = tape->drive;
-       int err;
-
-       mutex_lock(&ide_tape_mutex);
-       err = generic_ide_ioctl(drive, bdev, cmd, arg);
-       if (err == -EINVAL)
-               err = idetape_blkdev_ioctl(drive, cmd, arg);
-       mutex_unlock(&ide_tape_mutex);
-
-       return err;
-}
-
-static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode,
-                               unsigned int cmd, unsigned long arg)
-{
-        if (cmd == 0x0340 || cmd == 0x350)
-               arg = (unsigned long)compat_ptr(arg);
-
-       return idetape_ioctl(bdev, mode, cmd, arg);
-}
-
-static const struct block_device_operations idetape_block_ops = {
-       .owner          = THIS_MODULE,
-       .open           = idetape_open,
-       .release        = idetape_release,
-       .ioctl          = idetape_ioctl,
-       .compat_ioctl   = IS_ENABLED(CONFIG_COMPAT) ?
-                               idetape_compat_ioctl : NULL,
-};
-
-static int ide_tape_probe(ide_drive_t *drive)
-{
-       idetape_tape_t *tape;
-       struct gendisk *g;
-       int minor;
-
-       ide_debug_log(IDE_DBG_FUNC, "enter");
-
-       if (!strstr(DRV_NAME, drive->driver_req))
-               goto failed;
-
-       if (drive->media != ide_tape)
-               goto failed;
-
-       if ((drive->dev_flags & IDE_DFLAG_ID_READ) &&
-           ide_check_atapi_device(drive, DRV_NAME) == 0) {
-               printk(KERN_ERR "ide-tape: %s: not supported by this version of"
-                               " the driver\n", drive->name);
-               goto failed;
-       }
-       tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
-       if (tape == NULL) {
-               printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
-                               drive->name);
-               goto failed;
-       }
-
-       g = alloc_disk(1 << PARTN_BITS);
-       if (!g)
-               goto out_free_tape;
-
-       ide_init_disk(g, drive);
-
-       tape->dev.parent = &drive->gendev;
-       tape->dev.release = ide_tape_release;
-       dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev));
-
-       if (device_register(&tape->dev))
-               goto out_free_disk;
-
-       tape->drive = drive;
-       tape->driver = &idetape_driver;
-       tape->disk = g;
-
-       g->private_data = &tape->driver;
-
-       drive->driver_data = tape;
-
-       mutex_lock(&idetape_ref_mutex);
-       for (minor = 0; idetape_devs[minor]; minor++)
-               ;
-       idetape_devs[minor] = tape;
-       mutex_unlock(&idetape_ref_mutex);
-
-       idetape_setup(drive, tape, minor);
-
-       device_create(idetape_sysfs_class, &drive->gendev,
-                     MKDEV(IDETAPE_MAJOR, minor), NULL, "%s", tape->name);
-       device_create(idetape_sysfs_class, &drive->gendev,
-                     MKDEV(IDETAPE_MAJOR, minor + 128), NULL,
-                     "n%s", tape->name);
-
-       g->fops = &idetape_block_ops;
-
-       return 0;
-
-out_free_disk:
-       put_disk(g);
-out_free_tape:
-       kfree(tape);
-failed:
-       return -ENODEV;
-}
-
-static void __exit idetape_exit(void)
-{
-       driver_unregister(&idetape_driver.gen_driver);
-       class_destroy(idetape_sysfs_class);
-       unregister_chrdev(IDETAPE_MAJOR, "ht");
-}
-
-static int __init idetape_init(void)
-{
-       int error = 1;
-       idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
-       if (IS_ERR(idetape_sysfs_class)) {
-               idetape_sysfs_class = NULL;
-               printk(KERN_ERR "Unable to create sysfs class for ide tapes\n");
-               error = -EBUSY;
-               goto out;
-       }
-
-       if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
-               printk(KERN_ERR "ide-tape: Failed to register chrdev"
-                               " interface\n");
-               error = -EBUSY;
-               goto out_free_class;
-       }
-
-       error = driver_register(&idetape_driver.gen_driver);
-       if (error)
-               goto out_free_chrdev;
-
-       return 0;
-
-out_free_chrdev:
-       unregister_chrdev(IDETAPE_MAJOR, "ht");
-out_free_class:
-       class_destroy(idetape_sysfs_class);
-out:
-       return error;
-}
-
-MODULE_ALIAS("ide:*m-tape*");
-module_init(idetape_init);
-module_exit(idetape_exit);
-MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
-MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
deleted file mode 100644 (file)
index 6665fc4..0000000
+++ /dev/null
@@ -1,668 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 2000-2002       Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000-2002       Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2001-2002       Klaus Smolin
- *                                     IBM Storage Technology Division
- *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
- *
- *  The big the bad and the ugly.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/nmi.h>
-#include <linux/scatterlist.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-
-void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-
-       /* Be sure we're looking at the low order bytes */
-       tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
-       tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf);
-
-       if (cmd->tf_flags & IDE_TFLAG_LBA48) {
-               tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS);
-
-               tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob);
-       }
-}
-
-void ide_tf_dump(const char *s, struct ide_cmd *cmd)
-{
-#ifdef DEBUG
-       printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
-               "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
-              s, cmd->tf.feature, cmd->tf.nsect,
-              cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah,
-              cmd->tf.device, cmd->tf.command);
-       printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x\n",
-              s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah);
-#endif
-}
-
-int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf)
-{
-       struct ide_cmd cmd;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.tf.nsect = 0x01;
-       if (drive->media == ide_disk)
-               cmd.tf.command = ATA_CMD_ID_ATA;
-       else
-               cmd.tf.command = ATA_CMD_ID_ATAPI;
-       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
-       cmd.protocol = ATA_PROT_PIO;
-
-       return ide_raw_taskfile(drive, &cmd, buf, 1);
-}
-
-static ide_startstop_t task_no_data_intr(ide_drive_t *);
-static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *);
-static ide_startstop_t task_pio_intr(ide_drive_t *);
-
-ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
-       struct ide_taskfile *tf = &cmd->tf;
-       ide_handler_t *handler = NULL;
-       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-       const struct ide_dma_ops *dma_ops = hwif->dma_ops;
-
-       if (orig_cmd->protocol == ATA_PROT_PIO &&
-           (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) &&
-           drive->mult_count == 0) {
-               pr_err("%s: multimode not set!\n", drive->name);
-               return ide_stopped;
-       }
-
-       if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
-               orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS;
-
-       memcpy(cmd, orig_cmd, sizeof(*cmd));
-
-       if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
-               ide_tf_dump(drive->name, cmd);
-               tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
-               if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
-                       u8 data[2] = { cmd->tf.data, cmd->hob.data };
-
-                       tp_ops->output_data(drive, cmd, data, 2);
-               }
-
-               if (cmd->valid.out.tf & IDE_VALID_DEVICE) {
-                       u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ?
-                                 0xE0 : 0xEF;
-
-                       if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED))
-                               cmd->tf.device &= HIHI;
-                       cmd->tf.device |= drive->select;
-               }
-
-               tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob);
-               tp_ops->tf_load(drive, &cmd->tf,  cmd->valid.out.tf);
-       }
-
-       switch (cmd->protocol) {
-       case ATA_PROT_PIO:
-               if (cmd->tf_flags & IDE_TFLAG_WRITE) {
-                       tp_ops->exec_command(hwif, tf->command);
-                       ndelay(400);    /* FIXME */
-                       return pre_task_out_intr(drive, cmd);
-               }
-               handler = task_pio_intr;
-               fallthrough;
-       case ATA_PROT_NODATA:
-               if (handler == NULL)
-                       handler = task_no_data_intr;
-               ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
-               return ide_started;
-       case ATA_PROT_DMA:
-               if (ide_dma_prepare(drive, cmd))
-                       return ide_stopped;
-               hwif->expiry = dma_ops->dma_timer_expiry;
-               ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
-               dma_ops->dma_start(drive);
-               fallthrough;
-       default:
-               return ide_started;
-       }
-}
-EXPORT_SYMBOL_GPL(do_rw_taskfile);
-
-static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &hwif->cmd;
-       struct ide_taskfile *tf = &cmd->tf;
-       int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
-       int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
-       u8 stat;
-
-       local_irq_enable_in_hardirq();
-
-       while (1) {
-               stat = hwif->tp_ops->read_status(hwif);
-               if ((stat & ATA_BUSY) == 0 || retries-- == 0)
-                       break;
-               udelay(10);
-       };
-
-       if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
-               if (custom && tf->command == ATA_CMD_SET_MULTI) {
-                       drive->mult_req = drive->mult_count = 0;
-                       drive->special_flags |= IDE_SFLAG_RECALIBRATE;
-                       (void)ide_dump_status(drive, __func__, stat);
-                       return ide_stopped;
-               } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
-                       if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
-                               ide_set_handler(drive, &task_no_data_intr,
-                                               WAIT_WORSTCASE);
-                               return ide_started;
-                       }
-               }
-               return ide_error(drive, "task_no_data_intr", stat);
-       }
-
-       if (custom && tf->command == ATA_CMD_SET_MULTI)
-               drive->mult_count = drive->mult_req;
-
-       if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
-           tf->command == ATA_CMD_CHK_POWER) {
-               struct request *rq = hwif->rq;
-
-               if (ata_pm_request(rq))
-                       ide_complete_pm_rq(drive, rq);
-               else
-                       ide_finish_cmd(drive, cmd, stat);
-       }
-
-       return ide_stopped;
-}
-
-static u8 wait_drive_not_busy(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       int retries;
-       u8 stat;
-
-       /*
-        * Last sector was transferred, wait until device is ready.  This can
-        * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
-        */
-       for (retries = 0; retries < 1000; retries++) {
-               stat = hwif->tp_ops->read_status(hwif);
-
-               if (stat & ATA_BUSY)
-                       udelay(10);
-               else
-                       break;
-       }
-
-       if (stat & ATA_BUSY)
-               pr_err("%s: drive still BUSY!\n", drive->name);
-
-       return stat;
-}
-
-void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
-                  unsigned int write, unsigned int len)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct scatterlist *sg = hwif->sg_table;
-       struct scatterlist *cursg = cmd->cursg;
-       struct page *page;
-       unsigned int offset;
-       u8 *buf;
-
-       if (cursg == NULL)
-               cursg = cmd->cursg = sg;
-
-       while (len) {
-               unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
-
-               page = sg_page(cursg);
-               offset = cursg->offset + cmd->cursg_ofs;
-
-               /* get the current page and offset */
-               page = nth_page(page, (offset >> PAGE_SHIFT));
-               offset %= PAGE_SIZE;
-
-               nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset));
-
-               buf = kmap_atomic(page) + offset;
-
-               cmd->nleft -= nr_bytes;
-               cmd->cursg_ofs += nr_bytes;
-
-               if (cmd->cursg_ofs == cursg->length) {
-                       cursg = cmd->cursg = sg_next(cmd->cursg);
-                       cmd->cursg_ofs = 0;
-               }
-
-               /* do the actual data transfer */
-               if (write)
-                       hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
-               else
-                       hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
-
-               kunmap_atomic(buf);
-
-               len -= nr_bytes;
-       }
-}
-EXPORT_SYMBOL_GPL(ide_pio_bytes);
-
-static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
-                             unsigned int write)
-{
-       unsigned int nr_bytes;
-
-       u8 saved_io_32bit = drive->io_32bit;
-
-       if (cmd->tf_flags & IDE_TFLAG_FS)
-               scsi_req(cmd->rq)->result = 0;
-
-       if (cmd->tf_flags & IDE_TFLAG_IO_16BIT)
-               drive->io_32bit = 0;
-
-       touch_softlockup_watchdog();
-
-       if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
-               nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
-       else
-               nr_bytes = SECTOR_SIZE;
-
-       ide_pio_bytes(drive, cmd, write, nr_bytes);
-
-       drive->io_32bit = saved_io_32bit;
-}
-
-static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       if (cmd->tf_flags & IDE_TFLAG_FS) {
-               int nr_bytes = cmd->nbytes - cmd->nleft;
-
-               if (cmd->protocol == ATA_PROT_PIO &&
-                   ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) {
-                       if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
-                               nr_bytes -= drive->mult_count << 9;
-                       else
-                               nr_bytes -= SECTOR_SIZE;
-               }
-
-               if (nr_bytes > 0)
-                       ide_complete_rq(drive, BLK_STS_OK, nr_bytes);
-       }
-}
-
-void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
-{
-       struct request *rq = drive->hwif->rq;
-       u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;
-       u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);
-
-       ide_complete_cmd(drive, cmd, stat, err);
-       scsi_req(rq)->result = err;
-
-       if (err == 0 && set_xfer) {
-               ide_set_xfer_rate(drive, nsect);
-               ide_driveid_update(drive);
-       }
-
-       ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq));
-}
-
-/*
- * Handler for command with PIO data phase.
- */
-static ide_startstop_t task_pio_intr(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct ide_cmd *cmd = &drive->hwif->cmd;
-       u8 stat = hwif->tp_ops->read_status(hwif);
-       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
-       if (write == 0) {
-               /* Error? */
-               if (stat & ATA_ERR)
-                       goto out_err;
-
-               /* Didn't want any data? Odd. */
-               if ((stat & ATA_DRQ) == 0) {
-                       /* Command all done? */
-                       if (OK_STAT(stat, ATA_DRDY, ATA_BUSY))
-                               goto out_end;
-
-                       /* Assume it was a spurious irq */
-                       goto out_wait;
-               }
-       } else {
-               if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
-                       goto out_err;
-
-               /* Deal with unexpected ATA data phase. */
-               if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0))
-                       goto out_err;
-       }
-
-       if (write && cmd->nleft == 0)
-               goto out_end;
-
-       /* Still data left to transfer. */
-       ide_pio_datablock(drive, cmd, write);
-
-       /* Are we done? Check status and finish transfer. */
-       if (write == 0 && cmd->nleft == 0) {
-               stat = wait_drive_not_busy(drive);
-               if (!OK_STAT(stat, 0, BAD_STAT))
-                       goto out_err;
-
-               goto out_end;
-       }
-out_wait:
-       /* Still data left to transfer. */
-       ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
-       return ide_started;
-out_end:
-       if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
-               ide_finish_cmd(drive, cmd, stat);
-       else
-               ide_complete_rq(drive, BLK_STS_OK, blk_rq_sectors(cmd->rq) << 9);
-       return ide_stopped;
-out_err:
-       ide_error_cmd(drive, cmd);
-       return ide_error(drive, __func__, stat);
-}
-
-static ide_startstop_t pre_task_out_intr(ide_drive_t *drive,
-                                        struct ide_cmd *cmd)
-{
-       ide_startstop_t startstop;
-
-       if (ide_wait_stat(&startstop, drive, ATA_DRQ,
-                         drive->bad_wstat, WAIT_DRQ)) {
-               pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name,
-                       (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "",
-                       (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
-               return startstop;
-       }
-
-       if (!force_irqthreads && (drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
-               local_irq_disable();
-
-       ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
-
-       ide_pio_datablock(drive, cmd, 1);
-
-       return ide_started;
-}
-
-int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
-                    u16 nsect)
-{
-       struct request *rq;
-       int error;
-
-       rq = blk_get_request(drive->queue,
-               (cmd->tf_flags & IDE_TFLAG_WRITE) ?
-                       REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
-       ide_req(rq)->type = ATA_PRIV_TASKFILE;
-
-       /*
-        * (ks) We transfer currently only whole sectors.
-        * This is suffient for now.  But, it would be great,
-        * if we would find a solution to transfer any size.
-        * To support special commands like READ LONG.
-        */
-       if (nsect) {
-               error = blk_rq_map_kern(drive->queue, rq, buf,
-                                       nsect * SECTOR_SIZE, GFP_NOIO);
-               if (error)
-                       goto put_req;
-       }
-
-       ide_req(rq)->special = cmd;
-       cmd->rq = rq;
-
-       blk_execute_rq(NULL, rq, 0);
-       error = scsi_req(rq)->result ? -EIO : 0;
-put_req:
-       blk_put_request(rq);
-       return error;
-}
-EXPORT_SYMBOL(ide_raw_taskfile);
-
-int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       cmd->protocol = ATA_PROT_NODATA;
-
-       return ide_raw_taskfile(drive, cmd, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
-
-#ifdef CONFIG_IDE_TASK_IOCTL
-int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
-{
-       ide_task_request_t      *req_task;
-       struct ide_cmd          cmd;
-       u8 *outbuf              = NULL;
-       u8 *inbuf               = NULL;
-       u8 *data_buf            = NULL;
-       int err                 = 0;
-       int tasksize            = sizeof(struct ide_task_request_s);
-       unsigned int taskin     = 0;
-       unsigned int taskout    = 0;
-       u16 nsect               = 0;
-       char __user *buf = (char __user *)arg;
-
-       req_task = memdup_user(buf, tasksize);
-       if (IS_ERR(req_task))
-               return PTR_ERR(req_task);
-
-       taskout = req_task->out_size;
-       taskin  = req_task->in_size;
-
-       if (taskin > 65536 || taskout > 65536) {
-               err = -EINVAL;
-               goto abort;
-       }
-
-       if (taskout) {
-               int outtotal = tasksize;
-               outbuf = kzalloc(taskout, GFP_KERNEL);
-               if (outbuf == NULL) {
-                       err = -ENOMEM;
-                       goto abort;
-               }
-               if (copy_from_user(outbuf, buf + outtotal, taskout)) {
-                       err = -EFAULT;
-                       goto abort;
-               }
-       }
-
-       if (taskin) {
-               int intotal = tasksize + taskout;
-               inbuf = kzalloc(taskin, GFP_KERNEL);
-               if (inbuf == NULL) {
-                       err = -ENOMEM;
-                       goto abort;
-               }
-               if (copy_from_user(inbuf, buf + intotal, taskin)) {
-                       err = -EFAULT;
-                       goto abort;
-               }
-       }
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
-       memcpy(&cmd.tf,  req_task->io_ports,  HDIO_DRIVE_TASK_HDR_SIZE);
-
-       cmd.valid.out.tf = IDE_VALID_DEVICE;
-       cmd.valid.in.tf  = IDE_VALID_DEVICE | IDE_VALID_IN_TF;
-       cmd.tf_flags = IDE_TFLAG_IO_16BIT;
-
-       if (drive->dev_flags & IDE_DFLAG_LBA48) {
-               cmd.tf_flags |= IDE_TFLAG_LBA48;
-               cmd.valid.in.hob = IDE_VALID_IN_HOB;
-       }
-
-       if (req_task->out_flags.all) {
-               cmd.ftf_flags |= IDE_FTFLAG_FLAGGED;
-
-               if (req_task->out_flags.b.data)
-                       cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA;
-
-               if (req_task->out_flags.b.nsector_hob)
-                       cmd.valid.out.hob |= IDE_VALID_NSECT;
-               if (req_task->out_flags.b.sector_hob)
-                       cmd.valid.out.hob |= IDE_VALID_LBAL;
-               if (req_task->out_flags.b.lcyl_hob)
-                       cmd.valid.out.hob |= IDE_VALID_LBAM;
-               if (req_task->out_flags.b.hcyl_hob)
-                       cmd.valid.out.hob |= IDE_VALID_LBAH;
-
-               if (req_task->out_flags.b.error_feature)
-                       cmd.valid.out.tf  |= IDE_VALID_FEATURE;
-               if (req_task->out_flags.b.nsector)
-                       cmd.valid.out.tf  |= IDE_VALID_NSECT;
-               if (req_task->out_flags.b.sector)
-                       cmd.valid.out.tf  |= IDE_VALID_LBAL;
-               if (req_task->out_flags.b.lcyl)
-                       cmd.valid.out.tf  |= IDE_VALID_LBAM;
-               if (req_task->out_flags.b.hcyl)
-                       cmd.valid.out.tf  |= IDE_VALID_LBAH;
-       } else {
-               cmd.valid.out.tf |= IDE_VALID_OUT_TF;
-               if (cmd.tf_flags & IDE_TFLAG_LBA48)
-                       cmd.valid.out.hob |= IDE_VALID_OUT_HOB;
-       }
-
-       if (req_task->in_flags.b.data)
-               cmd.ftf_flags |= IDE_FTFLAG_IN_DATA;
-
-       if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) {
-               /* fixup data phase if needed */
-               if (req_task->data_phase == TASKFILE_IN_DMAQ ||
-                   req_task->data_phase == TASKFILE_IN_DMA)
-                       cmd.tf_flags |= IDE_TFLAG_WRITE;
-       }
-
-       cmd.protocol = ATA_PROT_DMA;
-
-       switch (req_task->data_phase) {
-       case TASKFILE_MULTI_OUT:
-               if (!drive->mult_count) {
-                       /* (hs): give up if multcount is not set */
-                       pr_err("%s: %s Multimode Write multcount is not set\n",
-                               drive->name, __func__);
-                       err = -EPERM;
-                       goto abort;
-               }
-               cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-               fallthrough;
-       case TASKFILE_OUT:
-               cmd.protocol = ATA_PROT_PIO;
-               fallthrough;
-       case TASKFILE_OUT_DMAQ:
-       case TASKFILE_OUT_DMA:
-               cmd.tf_flags |= IDE_TFLAG_WRITE;
-               nsect = taskout / SECTOR_SIZE;
-               data_buf = outbuf;
-               break;
-       case TASKFILE_MULTI_IN:
-               if (!drive->mult_count) {
-                       /* (hs): give up if multcount is not set */
-                       pr_err("%s: %s Multimode Read multcount is not set\n",
-                               drive->name, __func__);
-                       err = -EPERM;
-                       goto abort;
-               }
-               cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-               fallthrough;
-       case TASKFILE_IN:
-               cmd.protocol = ATA_PROT_PIO;
-               fallthrough;
-       case TASKFILE_IN_DMAQ:
-       case TASKFILE_IN_DMA:
-               nsect = taskin / SECTOR_SIZE;
-               data_buf = inbuf;
-               break;
-       case TASKFILE_NO_DATA:
-               cmd.protocol = ATA_PROT_NODATA;
-               break;
-       default:
-               err = -EFAULT;
-               goto abort;
-       }
-
-       if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
-               nsect = 0;
-       else if (!nsect) {
-               nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect;
-
-               if (!nsect) {
-                       pr_err("%s: in/out command without data\n",
-                                       drive->name);
-                       err = -EFAULT;
-                       goto abort;
-               }
-       }
-
-       err = ide_raw_taskfile(drive, &cmd, data_buf, nsect);
-
-       memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2);
-       memcpy(req_task->io_ports,  &cmd.tf,  HDIO_DRIVE_TASK_HDR_SIZE);
-
-       if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) &&
-           req_task->in_flags.all == 0) {
-               req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-               if (drive->dev_flags & IDE_DFLAG_LBA48)
-                       req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
-       }
-
-       if (copy_to_user(buf, req_task, tasksize)) {
-               err = -EFAULT;
-               goto abort;
-       }
-       if (taskout) {
-               int outtotal = tasksize;
-               if (copy_to_user(buf + outtotal, outbuf, taskout)) {
-                       err = -EFAULT;
-                       goto abort;
-               }
-       }
-       if (taskin) {
-               int intotal = tasksize + taskout;
-               if (copy_to_user(buf + intotal, inbuf, taskin)) {
-                       err = -EFAULT;
-                       goto abort;
-               }
-       }
-abort:
-       kfree(req_task);
-       kfree(outbuf);
-       kfree(inbuf);
-
-       return err;
-}
-#endif
diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c
deleted file mode 100644 (file)
index cfe78df..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *  Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-/*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
- * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension and UDMA6, which
- * is currently supported only by Maxtor drives.
- */
-
-static struct ide_timing ide_timing[] = {
-
-       { XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
-       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
-       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
-       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
-
-       { XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
-       { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
-       { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
-
-       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
-       { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 100,   0 },
-       { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
-       { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
-       { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
-
-       { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
-       { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
-       { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
-
-       { XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
-       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
-       { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
-       { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
-
-       { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
-       { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
-       { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
-
-       { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 },
-
-       { 0xff }
-};
-
-struct ide_timing *ide_timing_find_mode(u8 speed)
-{
-       struct ide_timing *t;
-
-       for (t = ide_timing; t->mode != speed; t++)
-               if (t->mode == 0xff)
-                       return NULL;
-       return t;
-}
-EXPORT_SYMBOL_GPL(ide_timing_find_mode);
-
-u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
-{
-       u16 *id = drive->id;
-       struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-       u16 cycle = 0;
-
-       if (id[ATA_ID_FIELD_VALID] & 2) {
-               if (ata_id_has_iordy(drive->id))
-                       cycle = id[ATA_ID_EIDE_PIO_IORDY];
-               else
-                       cycle = id[ATA_ID_EIDE_PIO];
-
-               /* conservative "downgrade" for all pre-ATA2 drives */
-               if (pio < 3 && cycle < t->cycle)
-                       cycle = 0; /* use standard timing */
-
-               /* Use the standard timing for the CF specific modes too */
-               if (pio > 4 && ata_id_is_cfa(id))
-                       cycle = 0;
-       }
-
-       return cycle ? cycle : t->cycle;
-}
-EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
-
-#define ENOUGH(v, unit)                (((v) - 1) / (unit) + 1)
-#define EZ(v, unit)            ((v) ? ENOUGH((v) * 1000, unit) : 0)
-
-static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q,
-                               int T, int UT)
-{
-       q->setup   = EZ(t->setup,   T);
-       q->act8b   = EZ(t->act8b,   T);
-       q->rec8b   = EZ(t->rec8b,   T);
-       q->cyc8b   = EZ(t->cyc8b,   T);
-       q->active  = EZ(t->active,  T);
-       q->recover = EZ(t->recover, T);
-       q->cycle   = EZ(t->cycle,   T);
-       q->udma    = EZ(t->udma,    UT);
-}
-
-void ide_timing_merge(struct ide_timing *a, struct ide_timing *b,
-                     struct ide_timing *m, unsigned int what)
-{
-       if (what & IDE_TIMING_SETUP)
-               m->setup   = max(a->setup,   b->setup);
-       if (what & IDE_TIMING_ACT8B)
-               m->act8b   = max(a->act8b,   b->act8b);
-       if (what & IDE_TIMING_REC8B)
-               m->rec8b   = max(a->rec8b,   b->rec8b);
-       if (what & IDE_TIMING_CYC8B)
-               m->cyc8b   = max(a->cyc8b,   b->cyc8b);
-       if (what & IDE_TIMING_ACTIVE)
-               m->active  = max(a->active,  b->active);
-       if (what & IDE_TIMING_RECOVER)
-               m->recover = max(a->recover, b->recover);
-       if (what & IDE_TIMING_CYCLE)
-               m->cycle   = max(a->cycle,   b->cycle);
-       if (what & IDE_TIMING_UDMA)
-               m->udma    = max(a->udma,    b->udma);
-}
-EXPORT_SYMBOL_GPL(ide_timing_merge);
-
-int ide_timing_compute(ide_drive_t *drive, u8 speed,
-                      struct ide_timing *t, int T, int UT)
-{
-       u16 *id = drive->id;
-       struct ide_timing *s, p;
-
-       /*
-        * Find the mode.
-        */
-       s = ide_timing_find_mode(speed);
-       if (s == NULL)
-               return -EINVAL;
-
-       /*
-        * Copy the timing from the table.
-        */
-       *t = *s;
-
-       /*
-        * If the drive is an EIDE drive, it can tell us it needs extended
-        * PIO/MWDMA cycle timing.
-        */
-       if (id[ATA_ID_FIELD_VALID] & 2) {       /* EIDE drive */
-               memset(&p, 0, sizeof(p));
-
-               if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
-                       if (speed <= XFER_PIO_2)
-                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
-                       else if ((speed <= XFER_PIO_4) ||
-                                (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
-                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
-               } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-                       p.cycle = id[ATA_ID_EIDE_DMA_MIN];
-
-               ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
-       }
-
-       /*
-        * Convert the timing to bus clock counts.
-        */
-       ide_timing_quantize(t, t, T, UT);
-
-       /*
-        * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
-        * S.M.A.R.T and some other commands. We have to ensure that the
-        * DMA cycle timing is slower/equal than the current PIO timing.
-        */
-       if (speed >= XFER_SW_DMA_0) {
-               ide_timing_compute(drive, drive->pio_mode, &p, T, UT);
-               ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
-       }
-
-       /*
-        * Lengthen active & recovery time so that cycle time is correct.
-        */
-       if (t->act8b + t->rec8b < t->cyc8b) {
-               t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
-               t->rec8b = t->cyc8b - t->act8b;
-       }
-
-       if (t->active + t->recover < t->cycle) {
-               t->active += (t->cycle - (t->active + t->recover)) / 2;
-               t->recover = t->cycle - t->active;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_timing_compute);
diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c
deleted file mode 100644 (file)
index 0b9709b..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-static const char *udma_str[] =
-        { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
-          "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
-static const char *mwdma_str[] =
-       { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" };
-static const char *swdma_str[] =
-       { "SWDMA0", "SWDMA1", "SWDMA2" };
-static const char *pio_str[] =
-       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" };
-
-/**
- *     ide_xfer_verbose        -       return IDE mode names
- *     @mode: transfer mode
- *
- *     Returns a constant string giving the name of the mode
- *     requested.
- */
-
-const char *ide_xfer_verbose(u8 mode)
-{
-       const char *s;
-       u8 i = mode & 0xf;
-
-       if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
-               s = udma_str[i];
-       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4)
-               s = mwdma_str[i];
-       else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
-               s = swdma_str[i];
-       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6)
-               s = pio_str[i & 0x7];
-       else if (mode == XFER_PIO_SLOW)
-               s = "PIO SLOW";
-       else
-               s = "XFER ERROR";
-
-       return s;
-}
-EXPORT_SYMBOL(ide_xfer_verbose);
-
-/**
- *     ide_get_best_pio_mode   -       get PIO mode from drive
- *     @drive: drive to consider
- *     @mode_wanted: preferred mode
- *     @max_mode: highest allowed mode
- *
- *     This routine returns the recommended PIO settings for a given drive,
- *     based on the drive->id information and the ide_pio_blacklist[].
- *
- *     Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
- *     This is used by most chipset support modules when "auto-tuning".
- */
-
-static u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
-{
-       u16 *id = drive->id;
-       int pio_mode = -1, overridden = 0;
-
-       if (mode_wanted != 255)
-               return min_t(u8, mode_wanted, max_mode);
-
-       if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
-               pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
-
-       if (pio_mode != -1) {
-               printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
-       } else {
-               pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
-               if (pio_mode > 2) {     /* 2 is maximum allowed tPIO value */
-                       pio_mode = 2;
-                       overridden = 1;
-               }
-
-               if (id[ATA_ID_FIELD_VALID] & 2) {             /* ATA2? */
-                       if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7))
-                               pio_mode = 4 + min_t(int, 2,
-                                                    id[ATA_ID_CFA_MODES] & 7);
-                       else if (ata_id_has_iordy(id)) {
-                               if (id[ATA_ID_PIO_MODES] & 7) {
-                                       overridden = 0;
-                                       if (id[ATA_ID_PIO_MODES] & 4)
-                                               pio_mode = 5;
-                                       else if (id[ATA_ID_PIO_MODES] & 2)
-                                               pio_mode = 4;
-                                       else
-                                               pio_mode = 3;
-                               }
-                       }
-               }
-
-               if (overridden)
-                       printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
-                                        drive->name);
-       }
-
-       if (pio_mode > max_mode)
-               pio_mode = max_mode;
-
-       return pio_mode;
-}
-
-int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio)
-{
-       /*
-        * IORDY may lead to controller lock up on certain controllers
-        * if the port is not occupied.
-        */
-       if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING))
-               return 0;
-       return ata_id_pio_need_iordy(drive->id, pio);
-}
-EXPORT_SYMBOL_GPL(ide_pio_need_iordy);
-
-int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
-               return 0;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL)
-               return -1;
-
-       /*
-        * TODO: temporary hack for some legacy host drivers that didn't
-        * set transfer mode on the device in ->set_pio_mode method...
-        */
-       if (port_ops->set_dma_mode == NULL) {
-               drive->pio_mode = mode;
-               port_ops->set_pio_mode(hwif, drive);
-               return 0;
-       }
-
-       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
-               if (ide_config_drive_speed(drive, mode))
-                       return -1;
-               drive->pio_mode = mode;
-               port_ops->set_pio_mode(hwif, drive);
-               return 0;
-       } else {
-               drive->pio_mode = mode;
-               port_ops->set_pio_mode(hwif, drive);
-               return ide_config_drive_speed(drive, mode);
-       }
-}
-
-int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
-               return 0;
-
-       if (port_ops == NULL || port_ops->set_dma_mode == NULL)
-               return -1;
-
-       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
-               if (ide_config_drive_speed(drive, mode))
-                       return -1;
-               drive->dma_mode = mode;
-               port_ops->set_dma_mode(hwif, drive);
-               return 0;
-       } else {
-               drive->dma_mode = mode;
-               port_ops->set_dma_mode(hwif, drive);
-               return ide_config_drive_speed(drive, mode);
-       }
-}
-EXPORT_SYMBOL_GPL(ide_set_dma_mode);
-
-/* req_pio == "255" for auto-tune */
-void ide_set_pio(ide_drive_t *drive, u8 req_pio)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-       u8 host_pio, pio;
-
-       if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return;
-
-       BUG_ON(hwif->pio_mask == 0x00);
-
-       host_pio = fls(hwif->pio_mask) - 1;
-
-       pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
-
-       /*
-        * TODO:
-        * - report device max PIO mode
-        * - check req_pio != 255 against device max PIO mode
-        */
-       printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
-                         drive->name, host_pio, req_pio,
-                         req_pio == 255 ? "(auto-tune)" : "", pio);
-
-       (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
-}
-EXPORT_SYMBOL_GPL(ide_set_pio);
-
-/**
- *     ide_rate_filter         -       filter transfer mode
- *     @drive: IDE device
- *     @speed: desired speed
- *
- *     Given the available transfer modes this function returns
- *     the best available speed at or below the speed requested.
- *
- *     TODO: check device PIO capabilities
- */
-
-static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 mode = ide_find_dma_mode(drive, speed);
-
-       if (mode == 0) {
-               if (hwif->pio_mask)
-                       mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
-               else
-                       mode = XFER_PIO_4;
-       }
-
-/*     printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
-
-       return min(speed, mode);
-}
-
-/**
- *     ide_set_xfer_rate       -       set transfer rate
- *     @drive: drive to set
- *     @rate: speed to attempt to set
- *
- *     General helper for setting the speed of an IDE device. This
- *     function knows about user enforced limits from the configuration
- *     which ->set_pio_mode/->set_dma_mode does not.
- */
-
-int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       const struct ide_port_ops *port_ops = hwif->port_ops;
-
-       if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
-           (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
-               return -1;
-
-       rate = ide_rate_filter(drive, rate);
-
-       BUG_ON(rate < XFER_PIO_0);
-
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6)
-               return ide_set_pio_mode(drive, rate);
-
-       return ide_set_dma_mode(drive, rate);
-}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
deleted file mode 100644 (file)
index 9a9c64f..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1994-1998        Linus Torvalds & authors (see below)
- *  Copyright (C) 2003-2005, 2007   Bartlomiej Zolnierkiewicz
- */
-
-/*
- *  Mostly written by Mark Lord  <mlord@pobox.com>
- *                and Gadi Oxman <gadio@netvision.net.il>
- *                and Andre Hedrick <andre@linux-ide.org>
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
- *   (usually 14 & 15).
- * There can be up to two drives per interface, as per the ATA-2 spec.
- *
- * ...
- *
- *  From hd.c:
- *  |
- *  | It traverses the request-list, using interrupts to jump between functions.
- *  | As nearly all functions can be called within interrupts, we may not sleep.
- *  | Special care is recommended.  Have Fun!
- *  |
- *  | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *  |
- *  | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  | in the early extended-partition checks and added DM partitions.
- *  |
- *  | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- *  |
- *  | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- *  October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- *     Mark Lord       (mlord@pobox.com)               (IDE Perf.Pkg)
- *     Delman Lee      (delman@ieee.org)               ("Mr. atdisk2")
- *     Scott Snyder    (snyder@fnald0.fnal.gov)        (ATAPI IDE cd-rom)
- *
- *  This was a rewrite of just about everything from hd.c, though some original
- *  code is still sprinkled about.  Think of it as a major evolution, with
- *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-
-struct class *ide_port_class;
-
-/**
- * ide_device_get      -       get an additional reference to a ide_drive_t
- * @drive:     device to get a reference to
- *
- * Gets a reference to the ide_drive_t and increments the use count of the
- * underlying LLDD module.
- */
-int ide_device_get(ide_drive_t *drive)
-{
-       struct device *host_dev;
-       struct module *module;
-
-       if (!get_device(&drive->gendev))
-               return -ENXIO;
-
-       host_dev = drive->hwif->host->dev[0];
-       module = host_dev ? host_dev->driver->owner : NULL;
-
-       if (module && !try_module_get(module)) {
-               put_device(&drive->gendev);
-               return -ENXIO;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_device_get);
-
-/**
- * ide_device_put      -       release a reference to a ide_drive_t
- * @drive:     device to release a reference on
- *
- * Release a reference to the ide_drive_t and decrements the use count of
- * the underlying LLDD module.
- */
-void ide_device_put(ide_drive_t *drive)
-{
-#ifdef CONFIG_MODULE_UNLOAD
-       struct device *host_dev = drive->hwif->host->dev[0];
-       struct module *module = host_dev ? host_dev->driver->owner : NULL;
-
-       module_put(module);
-#endif
-       put_device(&drive->gendev);
-}
-EXPORT_SYMBOL_GPL(ide_device_put);
-
-static int ide_bus_match(struct device *dev, struct device_driver *drv)
-{
-       return 1;
-}
-
-static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-
-       add_uevent_var(env, "MEDIA=%s", ide_media_string(drive));
-       add_uevent_var(env, "DRIVENAME=%s", drive->name);
-       add_uevent_var(env, "MODALIAS=ide:m-%s", ide_media_string(drive));
-       return 0;
-}
-
-static int generic_ide_probe(struct device *dev)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       struct ide_driver *drv = to_ide_driver(dev->driver);
-
-       return drv->probe ? drv->probe(drive) : -ENODEV;
-}
-
-static int generic_ide_remove(struct device *dev)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       struct ide_driver *drv = to_ide_driver(dev->driver);
-
-       if (drv->remove)
-               drv->remove(drive);
-
-       return 0;
-}
-
-static void generic_ide_shutdown(struct device *dev)
-{
-       ide_drive_t *drive = to_ide_device(dev);
-       struct ide_driver *drv = to_ide_driver(dev->driver);
-
-       if (dev->driver && drv->shutdown)
-               drv->shutdown(drive);
-}
-
-struct bus_type ide_bus_type = {
-       .name           = "ide",
-       .match          = ide_bus_match,
-       .uevent         = ide_uevent,
-       .probe          = generic_ide_probe,
-       .remove         = generic_ide_remove,
-       .shutdown       = generic_ide_shutdown,
-       .dev_groups     = ide_dev_groups,
-       .suspend        = generic_ide_suspend,
-       .resume         = generic_ide_resume,
-};
-
-EXPORT_SYMBOL_GPL(ide_bus_type);
-
-int ide_vlb_clk;
-EXPORT_SYMBOL_GPL(ide_vlb_clk);
-
-module_param_named(vlb_clock, ide_vlb_clk, int, 0);
-MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)");
-
-int ide_pci_clk;
-EXPORT_SYMBOL_GPL(ide_pci_clk);
-
-module_param_named(pci_clock, ide_pci_clk, int, 0);
-MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
-
-static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp)
-{
-       unsigned int a, b, i, j = 1;
-       unsigned int *dev_param_mask = (unsigned int *)kp->arg;
-
-       /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */
-       if (sscanf(s, "%u.%u:%u", &a, &b, &j) != 3 &&
-           sscanf(s, "%u.%u", &a, &b) != 2)
-               return -EINVAL;
-
-       i = a * MAX_DRIVES + b;
-
-       if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
-               return -EINVAL;
-
-       if (j)
-               *dev_param_mask |= (1 << i);
-       else
-               *dev_param_mask &= ~(1 << i);
-
-       return 0;
-}
-
-static const struct kernel_param_ops param_ops_ide_dev_mask = {
-       .set = ide_set_dev_param_mask
-};
-
-#define param_check_ide_dev_mask(name, p) param_check_uint(name, p)
-
-static unsigned int ide_nodma;
-
-module_param_named(nodma, ide_nodma, ide_dev_mask, 0);
-MODULE_PARM_DESC(nodma, "disallow DMA for a device");
-
-static unsigned int ide_noflush;
-
-module_param_named(noflush, ide_noflush, ide_dev_mask, 0);
-MODULE_PARM_DESC(noflush, "disable flush requests for a device");
-
-static unsigned int ide_nohpa;
-
-module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0);
-MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
-
-static unsigned int ide_noprobe;
-
-module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0);
-MODULE_PARM_DESC(noprobe, "skip probing for a device");
-
-static unsigned int ide_nowerr;
-
-module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0);
-MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
-
-static unsigned int ide_cdroms;
-
-module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0);
-MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
-
-struct chs_geom {
-       unsigned int    cyl;
-       u8              head;
-       u8              sect;
-};
-
-static unsigned int ide_disks;
-static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES];
-
-static int ide_set_disk_chs(const char *str, const struct kernel_param *kp)
-{
-       unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1;
-
-       /* controller . device (0 or 1) : Cylinders , Heads , Sectors */
-       /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */
-       if (sscanf(str, "%u.%u:%u,%u,%u", &a, &b, &c, &h, &s) != 5 &&
-           sscanf(str, "%u.%u:%u", &a, &b, &j) != 3)
-               return -EINVAL;
-
-       i = a * MAX_DRIVES + b;
-
-       if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
-               return -EINVAL;
-
-       if (c > INT_MAX || h > 255 || s > 255)
-               return -EINVAL;
-
-       if (j)
-               ide_disks |= (1 << i);
-       else
-               ide_disks &= ~(1 << i);
-
-       ide_disks_chs[i].cyl  = c;
-       ide_disks_chs[i].head = h;
-       ide_disks_chs[i].sect = s;
-
-       return 0;
-}
-
-module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
-MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
-
-static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
-{
-       int i = drive->hwif->index * MAX_DRIVES + unit;
-
-       if (ide_nodma & (1 << i)) {
-               printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
-               drive->dev_flags |= IDE_DFLAG_NODMA;
-       }
-       if (ide_noflush & (1 << i)) {
-               printk(KERN_INFO "ide: disabling flush requests for %s\n",
-                                drive->name);
-               drive->dev_flags |= IDE_DFLAG_NOFLUSH;
-       }
-       if (ide_nohpa & (1 << i)) {
-               printk(KERN_INFO "ide: disabling Host Protected Area for %s\n",
-                                drive->name);
-               drive->dev_flags |= IDE_DFLAG_NOHPA;
-       }
-       if (ide_noprobe & (1 << i)) {
-               printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
-               drive->dev_flags |= IDE_DFLAG_NOPROBE;
-       }
-       if (ide_nowerr & (1 << i)) {
-               printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n",
-                                drive->name);
-               drive->bad_wstat = BAD_R_STAT;
-       }
-       if (ide_cdroms & (1 << i)) {
-               printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
-               drive->dev_flags |= IDE_DFLAG_PRESENT;
-               drive->media = ide_cdrom;
-               /* an ATAPI device ignores DRDY */
-               drive->ready_stat = 0;
-       }
-       if (ide_disks & (1 << i)) {
-               drive->cyl  = drive->bios_cyl  = ide_disks_chs[i].cyl;
-               drive->head = drive->bios_head = ide_disks_chs[i].head;
-               drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
-
-               printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
-                                drive->name,
-                                drive->cyl, drive->head, drive->sect);
-
-               drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT;
-               drive->media = ide_disk;
-               drive->ready_stat = ATA_DRDY;
-       }
-}
-
-static unsigned int ide_ignore_cable;
-
-static int ide_set_ignore_cable(const char *s, const struct kernel_param *kp)
-{
-       int i, j = 1;
-
-       /* controller (ignore) */
-       /* controller : 1 (ignore) | 0 (use) */
-       if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
-               return -EINVAL;
-
-       if (i >= MAX_HWIFS || j < 0 || j > 1)
-               return -EINVAL;
-
-       if (j)
-               ide_ignore_cable |= (1 << i);
-       else
-               ide_ignore_cable &= ~(1 << i);
-
-       return 0;
-}
-
-module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0);
-MODULE_PARM_DESC(ignore_cable, "ignore cable detection");
-
-void ide_port_apply_params(ide_hwif_t *hwif)
-{
-       ide_drive_t *drive;
-       int i;
-
-       if (ide_ignore_cable & (1 << hwif->index)) {
-               printk(KERN_INFO "ide: ignoring cable detection for %s\n",
-                                hwif->name);
-               hwif->cbl = ATA_CBL_PATA40_SHORT;
-       }
-
-       ide_port_for_each_dev(i, drive, hwif)
-               ide_dev_apply_params(drive, i);
-}
-
-/*
- * This is gets invoked once during initialization, to set *everything* up
- */
-static int __init ide_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "Uniform Multi-Platform E-IDE driver\n");
-
-       ret = bus_register(&ide_bus_type);
-       if (ret < 0) {
-               printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
-               return ret;
-       }
-
-       ide_port_class = class_create(THIS_MODULE, "ide_port");
-       if (IS_ERR(ide_port_class)) {
-               ret = PTR_ERR(ide_port_class);
-               goto out_port_class;
-       }
-
-       ide_acpi_init();
-
-       proc_ide_create();
-
-       return 0;
-
-out_port_class:
-       bus_unregister(&ide_bus_type);
-
-       return ret;
-}
-
-static void __exit ide_exit(void)
-{
-       proc_ide_destroy();
-
-       class_destroy(ide_port_class);
-
-       bus_unregister(&ide_bus_type);
-}
-
-module_init(ide_init);
-module_exit(ide_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
deleted file mode 100644 (file)
index 91639fd..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Platform IDE driver
- *
- * Copyright (C) 2007 MontaVista Software
- *
- * Maintainer: Kumar Gala <galak@kernel.crashing.org>
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/ata_platform.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-static void plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base,
-                                void __iomem *ctrl,
-                                struct pata_platform_info *pdata, int irq)
-{
-       unsigned long port = (unsigned long)base;
-       int i;
-
-       hw->io_ports.data_addr = port;
-
-       port += (1 << pdata->ioport_shift);
-       for (i = 1; i <= 7;
-            i++, port += (1 << pdata->ioport_shift))
-               hw->io_ports_array[i] = port;
-
-       hw->io_ports.ctl_addr = (unsigned long)ctrl;
-
-       hw->irq = irq;
-}
-
-static const struct ide_port_info platform_ide_port_info = {
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .chipset                = ide_generic,
-};
-
-static int plat_ide_probe(struct platform_device *pdev)
-{
-       struct resource *res_base, *res_alt, *res_irq;
-       void __iomem *base, *alt_base;
-       struct pata_platform_info *pdata;
-       struct ide_host *host;
-       int ret = 0, mmio = 0;
-       struct ide_hw hw, *hws[] = { &hw };
-       struct ide_port_info d = platform_ide_port_info;
-
-       pdata = dev_get_platdata(&pdev->dev);
-
-       /* get a pointer to the register memory */
-       res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
-
-       if (!res_base || !res_alt) {
-               res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!res_base || !res_alt) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               mmio = 1;
-       }
-
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res_irq) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (mmio) {
-               base = devm_ioremap(&pdev->dev,
-                       res_base->start, resource_size(res_base));
-               alt_base = devm_ioremap(&pdev->dev,
-                       res_alt->start, resource_size(res_alt));
-       } else {
-               base = devm_ioport_map(&pdev->dev,
-                       res_base->start, resource_size(res_base));
-               alt_base = devm_ioport_map(&pdev->dev,
-                       res_alt->start, resource_size(res_alt));
-       }
-
-       memset(&hw, 0, sizeof(hw));
-       plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
-       hw.dev = &pdev->dev;
-
-       d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
-       if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
-               d.irq_flags |= IRQF_SHARED;
-
-       if (mmio)
-               d.host_flags |= IDE_HFLAG_MMIO;
-
-       ret = ide_host_add(&d, hws, 1, &host);
-       if (ret)
-               goto out;
-
-       platform_set_drvdata(pdev, host);
-
-       return 0;
-
-out:
-       return ret;
-}
-
-static int plat_ide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = dev_get_drvdata(&pdev->dev);
-
-       ide_host_remove(host);
-
-       return 0;
-}
-
-static struct platform_driver platform_ide_driver = {
-       .driver = {
-               .name = "pata_platform",
-       },
-       .probe = plat_ide_probe,
-       .remove = plat_ide_remove,
-};
-
-module_platform_driver(platform_ide_driver);
-
-MODULE_DESCRIPTION("Platform IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pata_platform");
diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c
deleted file mode 100644 (file)
index b6f674a..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *      IT8172 IDE controller support
- *
- * Copyright (C) 2000 MontaVista Software Inc.
- * Copyright (C) 2008 Shane McDonald
- *
- *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "IT8172"
-
-static void it8172_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u16 drive_enables;
-       u32 drive_timing;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       /*
-        * The highest value of DIOR/DIOW pulse width and recovery time
-        * that can be set in the IT8172 is 8 PCI clock cycles.  As a result,
-        * it cannot be configured for PIO mode 0.  This table sets these
-        * parameters to the maximum supported by the IT8172.
-        */
-       static const u8 timings[] = { 0x3f, 0x3c, 0x1b, 0x12, 0x0a };
-
-       pci_read_config_word(dev, 0x40, &drive_enables);
-       pci_read_config_dword(dev, 0x44, &drive_timing);
-
-       /*
-        * Enable port 0x44. The IT8172 spec is confused; it calls
-        * this register the "Slave IDE Timing Register", but in fact,
-        * it controls timing for both master and slave drives.
-        */
-       drive_enables |= 0x4000;
-
-       drive_enables &= drive->dn ? 0xc006 : 0xc060;
-       if (drive->media == ide_disk)
-               /* enable prefetch */
-               drive_enables |= 0x0004 << (drive->dn * 4);
-       if (ide_pio_need_iordy(drive, pio))
-               /* enable IORDY sample-point */
-               drive_enables |= 0x0002 << (drive->dn * 4);
-
-       drive_timing &= drive->dn ? 0x00003f00 : 0x000fc000;
-       drive_timing |= timings[pio] << (drive->dn * 6 + 8);
-
-       pci_write_config_word(dev, 0x40, drive_enables);
-       pci_write_config_dword(dev, 0x44, drive_timing);
-}
-
-static void it8172_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int a_speed             = 3 << (drive->dn * 4);
-       int u_flag              = 1 << drive->dn;
-       int u_speed             = 0;
-       u8 reg48, reg4a;
-       const u8 speed          = drive->dma_mode;
-
-       pci_read_config_byte(dev, 0x48, &reg48);
-       pci_read_config_byte(dev, 0x4a, &reg4a);
-
-       if (speed >= XFER_UDMA_0) {
-               u8 udma = speed - XFER_UDMA_0;
-               u_speed = udma << (drive->dn * 4);
-
-               pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-               reg4a &= ~a_speed;
-               pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-       } else {
-               const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
-               pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-               pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-
-               drive->pio_mode =
-                       mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
-
-               it8172_set_pio_mode(hwif, drive);
-       }
-}
-
-
-static const struct ide_port_ops it8172_port_ops = {
-       .set_pio_mode   = it8172_set_pio_mode,
-       .set_dma_mode   = it8172_set_dma_mode,
-};
-
-static const struct ide_port_info it8172_port_info = {
-       .name           = DRV_NAME,
-       .port_ops       = &it8172_port_ops,
-       .enablebits     = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} },
-       .host_flags     = IDE_HFLAG_SINGLE,
-       .pio_mask       = ATA_PIO4 & ~ATA_PIO0,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA2,
-};
-
-static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return -ENODEV; /* IT8172 is more than an IDE controller */
-       return ide_pci_init_one(dev, &it8172_port_info, NULL);
-}
-
-static struct pci_device_id it8172_pci_tbl[] = {
-       { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8172), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
-
-static struct pci_driver it8172_pci_driver = {
-       .name           = "IT8172_IDE",
-       .id_table       = it8172_pci_tbl,
-       .probe          = it8172_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init it8172_ide_init(void)
-{
-       return ide_pci_register_driver(&it8172_pci_driver);
-}
-
-static void __exit it8172_ide_exit(void)
-{
-       pci_unregister_driver(&it8172_pci_driver);
-}
-
-module_init(it8172_ide_init);
-module_exit(it8172_ide_exit);
-
-MODULE_AUTHOR("Steve Longerbeam");
-MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c
deleted file mode 100644 (file)
index d0bf443..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ITE 8213 IDE driver
- *
- * Copyright (C) 2006 Jack Lee
- * Copyright (C) 2006 Alan Cox
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "it8213"
-
-/**
- *     it8213_set_pio_mode     -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Set the interface PIO mode.
- */
-
-static void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int is_slave            = drive->dn & 1;
-       int master_port         = 0x40;
-       int slave_port          = 0x44;
-       unsigned long flags;
-       u16 master_data;
-       u8 slave_data;
-       static DEFINE_SPINLOCK(tune_lock);
-       int control = 0;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       static const u8 timings[][2] = {
-                                       { 0, 0 },
-                                       { 0, 0 },
-                                       { 1, 0 },
-                                       { 2, 1 },
-                                       { 2, 3 }, };
-
-       spin_lock_irqsave(&tune_lock, flags);
-       pci_read_config_word(dev, master_port, &master_data);
-
-       if (pio > 1)
-               control |= 1;   /* Programmable timing on */
-       if (drive->media != ide_disk)
-               control |= 4;   /* ATAPI */
-       if (ide_pio_need_iordy(drive, pio))
-               control |= 2;   /* IORDY */
-       if (is_slave) {
-               master_data |=  0x4000;
-               master_data &= ~0x0070;
-               if (pio > 1)
-                       master_data = master_data | (control << 4);
-               pci_read_config_byte(dev, slave_port, &slave_data);
-               slave_data = slave_data & 0xf0;
-               slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
-       } else {
-               master_data &= ~0x3307;
-               if (pio > 1)
-                       master_data = master_data | control;
-               master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
-       }
-       pci_write_config_word(dev, master_port, master_data);
-       if (is_slave)
-               pci_write_config_byte(dev, slave_port, slave_data);
-       spin_unlock_irqrestore(&tune_lock, flags);
-}
-
-/**
- *     it8213_set_dma_mode     -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Tune the ITE chipset for the DMA mode.
- */
-
-static void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 maslave              = 0x40;
-       int a_speed             = 3 << (drive->dn * 4);
-       int u_flag              = 1 << drive->dn;
-       int v_flag              = 0x01 << drive->dn;
-       int w_flag              = 0x10 << drive->dn;
-       int u_speed             = 0;
-       u16                     reg4042, reg4a;
-       u8                      reg48, reg54, reg55;
-       const u8 speed          = drive->dma_mode;
-
-       pci_read_config_word(dev, maslave, &reg4042);
-       pci_read_config_byte(dev, 0x48, &reg48);
-       pci_read_config_word(dev, 0x4a, &reg4a);
-       pci_read_config_byte(dev, 0x54, &reg54);
-       pci_read_config_byte(dev, 0x55, &reg55);
-
-       if (speed >= XFER_UDMA_0) {
-               u8 udma = speed - XFER_UDMA_0;
-
-               u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-
-               if (!(reg48 & u_flag))
-                       pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-               if (speed >= XFER_UDMA_5)
-                       pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
-               else
-                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
-               if ((reg4a & a_speed) != u_speed)
-                       pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
-               if (speed > XFER_UDMA_2) {
-                       if (!(reg54 & v_flag))
-                               pci_write_config_byte(dev, 0x54, reg54 | v_flag);
-               } else
-                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
-       } else {
-               const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
-               if (reg48 & u_flag)
-                       pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-               if (reg4a & a_speed)
-                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-               if (reg54 & v_flag)
-                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
-               if (reg55 & w_flag)
-                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
-               if (speed >= XFER_MW_DMA_0)
-                       drive->pio_mode =
-                               mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
-               else
-                       drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
-               it8213_set_pio_mode(hwif, drive);
-       }
-}
-
-static u8 it8213_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 reg42h = 0;
-
-       pci_read_config_byte(dev, 0x42, &reg42h);
-
-       return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops it8213_port_ops = {
-       .set_pio_mode           = it8213_set_pio_mode,
-       .set_dma_mode           = it8213_set_dma_mode,
-       .cable_detect           = it8213_cable_detect,
-};
-
-static const struct ide_port_info it8213_chipset = {
-       .name           = DRV_NAME,
-       .enablebits     = { {0x41, 0x80, 0x80} },
-       .port_ops       = &it8213_port_ops,
-       .host_flags     = IDE_HFLAG_SINGLE,
-       .pio_mask       = ATA_PIO4,
-       .swdma_mask     = ATA_SWDMA2_ONLY,
-       .mwdma_mask     = ATA_MWDMA12_ONLY,
-       .udma_mask      = ATA_UDMA6,
-};
-
-/**
- *     it8213_init_one -       pci layer discovery entry
- *     @dev: PCI device
- *     @id: ident table entry
- *
- *     Called by the PCI code when it finds an ITE8213 controller. As
- *     this device follows the standard interfaces we can use the
- *     standard helper functions to do almost all the work for us.
- */
-
-static int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &it8213_chipset, NULL);
-}
-
-static const struct pci_device_id it8213_pci_tbl[] = {
-       { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 },
-       { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
-
-static struct pci_driver it8213_pci_driver = {
-       .name           = "ITE8213_IDE",
-       .id_table       = it8213_pci_tbl,
-       .probe          = it8213_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init it8213_ide_init(void)
-{
-       return ide_pci_register_driver(&it8213_pci_driver);
-}
-
-static void __exit it8213_ide_exit(void)
-{
-       pci_unregister_driver(&it8213_pci_driver);
-}
-
-module_init(it8213_ide_init);
-module_exit(it8213_ide_exit);
-
-MODULE_AUTHOR("Jack Lee, Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
deleted file mode 100644 (file)
index 36a64c8..0000000
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright (C) 2004          Red Hat
- * Copyright (C) 2007          Bartlomiej Zolnierkiewicz
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *  Based in part on the ITE vendor provided SCSI driver.
- *
- *  Documentation:
- *     Datasheet is freely available, some other documents under NDA.
- *
- *  The ITE8212 isn't exactly a standard IDE controller. It has two
- *  modes. In pass through mode then it is an IDE controller. In its smart
- *  mode its actually quite a capable hardware raid controller disguised
- *  as an IDE controller. Smart mode only understands DMA read/write and
- *  identify, none of the fancier commands apply. The IT8211 is identical
- *  in other respects but lacks the raid mode.
- *
- *  Errata:
- *  o  Rev 0x10 also requires master/slave hold the same DMA timings and
- *     cannot do ATAPI MWDMA.
- *  o  The identify data for raid volumes lacks CHS info (technically ok)
- *     but also fails to set the LBA28 and other bits. We fix these in
- *     the IDE probe quirk code.
- *  o  If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
- *     raid then the controller firmware dies
- *  o  Smart mode without RAID doesn't clear all the necessary identify
- *     bits to reduce the command set to the one used
- *
- *  This has a few impacts on the driver
- *  - In pass through mode we do all the work you would expect
- *  - In smart mode the clocking set up is done by the controller generally
- *    but we must watch the other limits and filter.
- *  - There are a few extra vendor commands that actually talk to the
- *    controller but only work PIO with no IRQ.
- *
- *  Vendor areas of the identify block in smart mode are used for the
- *  timing and policy set up. Each HDD in raid mode also has a serial
- *  block on the disk. The hardware extra commands are get/set chip status,
- *  rebuild, get rebuild status.
- *
- *  In Linux the driver supports pass through mode as if the device was
- *  just another IDE controller. If the smart mode is running then
- *  volumes are managed by the controller firmware and each IDE "disk"
- *  is a raid volume. Even more cute - the controller can do automated
- *  hotplug and rebuild.
- *
- *  The pass through controller itself is a little demented. It has a
- *  flaw that it has a single set of PIO/MWDMA timings per channel so
- *  non UDMA devices restrict each others performance. It also has a
- *  single clock source per channel so mixed UDMA100/133 performance
- *  isn't perfect and we have to pick a clock. Thankfully none of this
- *  matters in smart mode. ATAPI DMA is not currently supported.
- *
- *  It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
- *
- *  TODO
- *     -       ATAPI UDMA is ok but not MWDMA it seems
- *     -       RAID configuration ioctls
- *     -       Move to libata once it grows up
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "it821x"
-
-#define QUIRK_VORTEX86 1
-
-struct it821x_dev
-{
-       unsigned int smart:1,           /* Are we in smart raid mode */
-               timing10:1;             /* Rev 0x10 */
-       u8      clock_mode;             /* 0, ATA_50 or ATA_66 */
-       u8      want[2][2];             /* Mode/Pri log for master slave */
-       /* We need these for switching the clock when DMA goes on/off
-          The high byte is the 66Mhz timing */
-       u16     pio[2];                 /* Cached PIO values */
-       u16     mwdma[2];               /* Cached MWDMA values */
-       u16     udma[2];                /* Cached UDMA values (per drive) */
-       u16     quirks;
-};
-
-#define ATA_66         0
-#define ATA_50         1
-#define ATA_ANY                2
-
-#define UDMA_OFF       0
-#define MWDMA_OFF      0
-
-/*
- *     We allow users to force the card into non raid mode without
- *     flashing the alternative BIOS. This is also necessary right now
- *     for embedded platforms that cannot run a PC BIOS but are using this
- *     device.
- */
-
-static int it8212_noraid;
-
-/**
- *     it821x_program  -       program the PIO/MWDMA registers
- *     @drive: drive to tune
- *     @timing: timing info
- *
- *     Program the PIO/MWDMA timing for this channel according to the
- *     current clock.
- */
-
-static void it821x_program(ide_drive_t *drive, u16 timing)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int channel = hwif->channel;
-       u8 conf;
-
-       /* Program PIO/MWDMA timing bits */
-       if(itdev->clock_mode == ATA_66)
-               conf = timing >> 8;
-       else
-               conf = timing & 0xFF;
-
-       pci_write_config_byte(dev, 0x54 + 4 * channel, conf);
-}
-
-/**
- *     it821x_program_udma     -       program the UDMA registers
- *     @drive: drive to tune
- *     @timing: timing info
- *
- *     Program the UDMA timing for this drive according to the
- *     current clock.
- */
-
-static void it821x_program_udma(ide_drive_t *drive, u16 timing)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int channel = hwif->channel;
-       u8 unit = drive->dn & 1, conf;
-
-       /* Program UDMA timing bits */
-       if(itdev->clock_mode == ATA_66)
-               conf = timing >> 8;
-       else
-               conf = timing & 0xFF;
-
-       if (itdev->timing10 == 0)
-               pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf);
-       else {
-               pci_write_config_byte(dev, 0x56 + 4 * channel, conf);
-               pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf);
-       }
-}
-
-/**
- *     it821x_clock_strategy
- *     @drive: drive to set up
- *
- *     Select between the 50 and 66Mhz base clocks to get the best
- *     results for this interface.
- */
-
-static void it821x_clock_strategy(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       int clock, altclock, sel = 0;
-       u8 unit = drive->dn & 1, v;
-
-       if(itdev->want[0][0] > itdev->want[1][0]) {
-               clock = itdev->want[0][1];
-               altclock = itdev->want[1][1];
-       } else {
-               clock = itdev->want[1][1];
-               altclock = itdev->want[0][1];
-       }
-
-       /*
-        * if both clocks can be used for the mode with the higher priority
-        * use the clock needed by the mode with the lower priority
-        */
-       if (clock == ATA_ANY)
-               clock = altclock;
-
-       /* Nobody cares - keep the same clock */
-       if(clock == ATA_ANY)
-               return;
-       /* No change */
-       if(clock == itdev->clock_mode)
-               return;
-
-       /* Load this into the controller ? */
-       if(clock == ATA_66)
-               itdev->clock_mode = ATA_66;
-       else {
-               itdev->clock_mode = ATA_50;
-               sel = 1;
-       }
-
-       pci_read_config_byte(dev, 0x50, &v);
-       v &= ~(1 << (1 + hwif->channel));
-       v |= sel << (1 + hwif->channel);
-       pci_write_config_byte(dev, 0x50, v);
-
-       /*
-        *      Reprogram the UDMA/PIO of the pair drive for the switch
-        *      MWDMA will be dealt with by the dma switcher
-        */
-       if(pair && itdev->udma[1-unit] != UDMA_OFF) {
-               it821x_program_udma(pair, itdev->udma[1-unit]);
-               it821x_program(pair, itdev->pio[1-unit]);
-       }
-       /*
-        *      Reprogram the UDMA/PIO of our drive for the switch.
-        *      MWDMA will be dealt with by the dma switcher
-        */
-       if(itdev->udma[unit] != UDMA_OFF) {
-               it821x_program_udma(drive, itdev->udma[unit]);
-               it821x_program(drive, itdev->pio[unit]);
-       }
-}
-
-/**
- *     it821x_set_pio_mode     -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Tune the host to the desired PIO mode taking into the consideration
- *     the maximum PIO mode supported by the other device on the cable.
- */
-
-static void it821x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       u8 unit = drive->dn & 1, set_pio = pio;
-
-       /* Spec says 89 ref driver uses 88 */
-       static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
-       static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
-
-       /*
-        * Compute the best PIO mode we can for a given device. We must
-        * pick a speed that does not cause problems with the other device
-        * on the cable.
-        */
-       if (pair) {
-               u8 pair_pio = pair->pio_mode - XFER_PIO_0;
-               /* trim PIO to the slowest of the master/slave */
-               if (pair_pio < set_pio)
-                       set_pio = pair_pio;
-       }
-
-       /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
-       itdev->want[unit][1] = pio_want[set_pio];
-       itdev->want[unit][0] = 1;       /* PIO is lowest priority */
-       itdev->pio[unit] = pio_timings[set_pio];
-       it821x_clock_strategy(drive);
-       it821x_program(drive, itdev->pio[unit]);
-}
-
-/**
- *     it821x_tune_mwdma       -       tune a channel for MWDMA
- *     @drive: drive to set up
- *     @mode_wanted: the target operating mode
- *
- *     Load the timing settings for this device mode into the
- *     controller when doing MWDMA in pass through mode. The caller
- *     must manage the whole lack of per device MWDMA/PIO timings and
- *     the shared MWDMA/PIO timing register.
- */
-
-static void it821x_tune_mwdma(ide_drive_t *drive, u8 mode_wanted)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
-       u8 unit = drive->dn & 1, channel = hwif->channel, conf;
-
-       static u16 dma[]        = { 0x8866, 0x3222, 0x3121 };
-       static u8 mwdma_want[]  = { ATA_ANY, ATA_66, ATA_ANY };
-
-       itdev->want[unit][1] = mwdma_want[mode_wanted];
-       itdev->want[unit][0] = 2;       /* MWDMA is low priority */
-       itdev->mwdma[unit] = dma[mode_wanted];
-       itdev->udma[unit] = UDMA_OFF;
-
-       /* UDMA bits off - Revision 0x10 do them in pairs */
-       pci_read_config_byte(dev, 0x50, &conf);
-       if (itdev->timing10)
-               conf |= channel ? 0x60: 0x18;
-       else
-               conf |= 1 << (3 + 2 * channel + unit);
-       pci_write_config_byte(dev, 0x50, conf);
-
-       it821x_clock_strategy(drive);
-       /* FIXME: do we need to program this ? */
-       /* it821x_program(drive, itdev->mwdma[unit]); */
-}
-
-/**
- *     it821x_tune_udma        -       tune a channel for UDMA
- *     @drive: drive to set up
- *     @mode_wanted: the target operating mode
- *
- *     Load the timing settings for this device mode into the
- *     controller when doing UDMA modes in pass through.
- */
-
-static void it821x_tune_udma(ide_drive_t *drive, u8 mode_wanted)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       u8 unit = drive->dn & 1, channel = hwif->channel, conf;
-
-       static u16 udma[]       = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
-       static u8 udma_want[]   = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
-
-       itdev->want[unit][1] = udma_want[mode_wanted];
-       itdev->want[unit][0] = 3;       /* UDMA is high priority */
-       itdev->mwdma[unit] = MWDMA_OFF;
-       itdev->udma[unit] = udma[mode_wanted];
-       if(mode_wanted >= 5)
-               itdev->udma[unit] |= 0x8080;    /* UDMA 5/6 select on */
-
-       /* UDMA on. Again revision 0x10 must do the pair */
-       pci_read_config_byte(dev, 0x50, &conf);
-       if (itdev->timing10)
-               conf &= channel ? 0x9F: 0xE7;
-       else
-               conf &= ~ (1 << (3 + 2 * channel + unit));
-       pci_write_config_byte(dev, 0x50, conf);
-
-       it821x_clock_strategy(drive);
-       it821x_program_udma(drive, itdev->udma[unit]);
-
-}
-
-/**
- *     it821x_dma_read -       DMA hook
- *     @drive: drive for DMA
- *
- *     The IT821x has a single timing register for MWDMA and for PIO
- *     operations. As we flip back and forth we have to reload the
- *     clock. In addition the rev 0x10 device only works if the same
- *     timing value is loaded into the master and slave UDMA clock
- *     so we must also reload that.
- *
- *     FIXME: we could figure out in advance if we need to do reloads
- */
-
-static void it821x_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       u8 unit = drive->dn & 1;
-
-       if(itdev->mwdma[unit] != MWDMA_OFF)
-               it821x_program(drive, itdev->mwdma[unit]);
-       else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
-               it821x_program_udma(drive, itdev->udma[unit]);
-       ide_dma_start(drive);
-}
-
-/**
- *     it821x_dma_write        -       DMA hook
- *     @drive: drive for DMA stop
- *
- *     The IT821x has a single timing register for MWDMA and for PIO
- *     operations. As we flip back and forth we have to reload the
- *     clock.
- */
-
-static int it821x_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       int ret = ide_dma_end(drive);
-       u8 unit = drive->dn & 1;
-
-       if(itdev->mwdma[unit] != MWDMA_OFF)
-               it821x_program(drive, itdev->pio[unit]);
-       return ret;
-}
-
-/**
- *     it821x_set_dma_mode     -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Tune the ITE chipset for the desired DMA mode.
- */
-
-static void it821x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       const u8 speed = drive->dma_mode;
-
-       /*
-        * MWDMA tuning is really hard because our MWDMA and PIO
-        * timings are kept in the same place.  We can switch in the
-        * host dma on/off callbacks.
-        */
-       if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
-               it821x_tune_udma(drive, speed - XFER_UDMA_0);
-       else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-               it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
-}
-
-/**
- *     it821x_cable_detect     -       cable detection
- *     @hwif: interface to check
- *
- *     Check for the presence of an ATA66 capable cable on the
- *     interface. Problematic as it seems some cards don't have
- *     the needed logic onboard.
- */
-
-static u8 it821x_cable_detect(ide_hwif_t *hwif)
-{
-       /* The reference driver also only does disk side */
-       return ATA_CBL_PATA80;
-}
-
-/**
- *     it821x_quirkproc        -       post init callback
- *     @drive: drive
- *
- *     This callback is run after the drive has been probed but
- *     before anything gets attached. It allows drivers to do any
- *     final tuning that is needed, or fixups to work around bugs.
- */
-
-static void it821x_quirkproc(ide_drive_t *drive)
-{
-       struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
-       u16 *id = drive->id;
-
-       if (!itdev->smart) {
-               /*
-                *      If we are in pass through mode then not much
-                *      needs to be done, but we do bother to clear the
-                *      IRQ mask as we may well be in PIO (eg rev 0x10)
-                *      for now and we know unmasking is safe on this chipset.
-                */
-               drive->dev_flags |= IDE_DFLAG_UNMASK;
-       } else {
-       /*
-        *      Perform fixups on smart mode. We need to "lose" some
-        *      capabilities the firmware lacks but does not filter, and
-        *      also patch up some capability bits that it forgets to set
-        *      in RAID mode.
-        */
-
-               /* Check for RAID v native */
-               if (strstr((char *)&id[ATA_ID_PROD],
-                          "Integrated Technology Express")) {
-                       /* In raid mode the ident block is slightly buggy
-                          We need to set the bits so that the IDE layer knows
-                          LBA28. LBA48 and DMA ar valid */
-                       id[ATA_ID_CAPABILITY]    |= (3 << 8); /* LBA28, DMA */
-                       id[ATA_ID_COMMAND_SET_2] |= 0x0400;   /* LBA48 valid */
-                       id[ATA_ID_CFS_ENABLE_2]  |= 0x0400;   /* LBA48 on */
-                       /* Reporting logic */
-                       printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
-                               drive->name, id[147] ? "Bootable " : "",
-                               id[ATA_ID_CSFO]);
-                       if (id[ATA_ID_CSFO] != 1)
-                               printk(KERN_CONT "(%dK stripe)", id[146]);
-                       printk(KERN_CONT ".\n");
-               } else {
-                       /* Non RAID volume. Fixups to stop the core code
-                          doing unsupported things */
-                       id[ATA_ID_FIELD_VALID]   &= 3;
-                       id[ATA_ID_QUEUE_DEPTH]    = 0;
-                       id[ATA_ID_COMMAND_SET_1]  = 0;
-                       id[ATA_ID_COMMAND_SET_2] &= 0xC400;
-                       id[ATA_ID_CFSSE]         &= 0xC000;
-                       id[ATA_ID_CFS_ENABLE_1]   = 0;
-                       id[ATA_ID_CFS_ENABLE_2]  &= 0xC400;
-                       id[ATA_ID_CSF_DEFAULT]   &= 0xC000;
-                       id[127]                   = 0;
-                       id[ATA_ID_DLF]            = 0;
-                       id[ATA_ID_CSFO]           = 0;
-                       id[ATA_ID_CFA_POWER]      = 0;
-                       printk(KERN_INFO "%s: Performing identify fixups.\n",
-                               drive->name);
-               }
-
-               /*
-                * Set MWDMA0 mode as enabled/support - just to tell
-                * IDE core that DMA is supported (it821x hardware
-                * takes care of DMA mode programming).
-                */
-               if (ata_id_has_dma(id)) {
-                       id[ATA_ID_MWDMA_MODES] |= 0x0101;
-                       drive->current_speed = XFER_MW_DMA_0;
-               }
-       }
-
-}
-
-static const struct ide_dma_ops it821x_pass_through_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = it821x_dma_start,
-       .dma_end                = it821x_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-/**
- *     init_hwif_it821x        -       set up hwif structs
- *     @hwif: interface to set up
- *
- *     We do the basic set up of the interface structure. The IT8212
- *     requires several custom handlers so we override the default
- *     ide DMA handlers appropriately
- */
-
-static void init_hwif_it821x(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct it821x_dev *itdevs = host->host_priv;
-       struct it821x_dev *idev = itdevs + hwif->channel;
-       u8 conf;
-
-       ide_set_hwifdata(hwif, idev);
-
-       pci_read_config_byte(dev, 0x50, &conf);
-       if (conf & 1) {
-               idev->smart = 1;
-               hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-               /* Long I/O's although allowed in LBA48 space cause the
-                  onboard firmware to enter the twighlight zone */
-               hwif->rqsize = 256;
-       }
-
-       /* Pull the current clocks from 0x50 also */
-       if (conf & (1 << (1 + hwif->channel)))
-               idev->clock_mode = ATA_50;
-       else
-               idev->clock_mode = ATA_66;
-
-       idev->want[0][1] = ATA_ANY;
-       idev->want[1][1] = ATA_ANY;
-
-       /*
-        *      Not in the docs but according to the reference driver
-        *      this is necessary.
-        */
-
-       if (dev->revision == 0x10) {
-               idev->timing10 = 1;
-               hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-               if (idev->smart == 0)
-                       printk(KERN_WARNING DRV_NAME " %s: revision 0x10, "
-                               "workarounds activated\n", pci_name(dev));
-       }
-
-       if (idev->smart == 0) {
-               /* MWDMA/PIO clock switching for pass through mode */
-               hwif->dma_ops = &it821x_pass_through_dma_ops;
-       } else
-               hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
-
-       if (hwif->dma_base == 0)
-               return;
-
-       hwif->ultra_mask = ATA_UDMA6;
-       hwif->mwdma_mask = ATA_MWDMA2;
-
-       /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
-       if (idev->quirks & QUIRK_VORTEX86) {
-               if (dev->revision == 0x11)
-                       hwif->ultra_mask = 0;
-       }
-}
-
-static void it8212_disable_raid(struct pci_dev *dev)
-{
-       /* Reset local CPU, and set BIOS not ready */
-       pci_write_config_byte(dev, 0x5E, 0x01);
-
-       /* Set to bypass mode, and reset PCI bus */
-       pci_write_config_byte(dev, 0x50, 0x00);
-       pci_write_config_word(dev, PCI_COMMAND,
-                             PCI_COMMAND_PARITY | PCI_COMMAND_IO |
-                             PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-       pci_write_config_word(dev, 0x40, 0xA0F3);
-
-       pci_write_config_dword(dev,0x4C, 0x02040204);
-       pci_write_config_byte(dev, 0x42, 0x36);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-}
-
-static int init_chipset_it821x(struct pci_dev *dev)
-{
-       u8 conf;
-       static char *mode[2] = { "pass through", "smart" };
-
-       /* Force the card into bypass mode if so requested */
-       if (it8212_noraid) {
-               printk(KERN_INFO DRV_NAME " %s: forcing bypass mode\n",
-                       pci_name(dev));
-               it8212_disable_raid(dev);
-       }
-       pci_read_config_byte(dev, 0x50, &conf);
-       printk(KERN_INFO DRV_NAME " %s: controller in %s mode\n",
-               pci_name(dev), mode[conf & 1]);
-       return 0;
-}
-
-static const struct ide_port_ops it821x_port_ops = {
-       /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */
-       .set_pio_mode           = it821x_set_pio_mode,
-       .set_dma_mode           = it821x_set_dma_mode,
-       .quirkproc              = it821x_quirkproc,
-       .cable_detect           = it821x_cable_detect,
-};
-
-static const struct ide_port_info it821x_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_it821x,
-       .init_hwif      = init_hwif_it821x,
-       .port_ops       = &it821x_port_ops,
-       .pio_mask       = ATA_PIO4,
-};
-
-/**
- *     it821x_init_one -       pci layer discovery entry
- *     @dev: PCI device
- *     @id: ident table entry
- *
- *     Called by the PCI code when it finds an ITE821x controller.
- *     We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct it821x_dev *itdevs;
-       int rc;
-
-       itdevs = kcalloc(2, sizeof(*itdevs), GFP_KERNEL);
-       if (itdevs == NULL) {
-               printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev));
-               return -ENOMEM;
-       }
-
-       itdevs->quirks = id->driver_data;
-
-       rc = ide_pci_init_one(dev, &it821x_chipset, itdevs);
-       if (rc)
-               kfree(itdevs);
-
-       return rc;
-}
-
-static void it821x_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct it821x_dev *itdevs = host->host_priv;
-
-       ide_pci_remove(dev);
-       kfree(itdevs);
-}
-
-static const struct pci_device_id it821x_pci_tbl[] = {
-       { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
-       { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
-       { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
-       { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
-
-static struct pci_driver it821x_pci_driver = {
-       .name           = "ITE821x IDE",
-       .id_table       = it821x_pci_tbl,
-       .probe          = it821x_init_one,
-       .remove         = it821x_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init it821x_ide_init(void)
-{
-       return ide_pci_register_driver(&it821x_pci_driver);
-}
-
-static void __exit it821x_ide_exit(void)
-{
-       pci_unregister_driver(&it821x_pci_driver);
-}
-
-module_init(it821x_ide_init);
-module_exit(it821x_ide_exit);
-
-module_param_named(noraid, it8212_noraid, int, S_IRUGO);
-MODULE_PARM_DESC(noraid, "Force card into bypass mode");
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c
deleted file mode 100644 (file)
index ae6480d..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-
-/*
- * Copyright (C) 2006          Red Hat
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "jmicron"
-
-typedef enum {
-       PORT_PATA0 = 0,
-       PORT_PATA1 = 1,
-       PORT_SATA = 2,
-} port_type;
-
-/**
- *     jmicron_cable_detect    -       cable detection
- *     @hwif: IDE port
- *
- *     Returns the cable type.
- */
-
-static u8 jmicron_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-
-       u32 control;
-       u32 control5;
-
-       int port = hwif->channel;
-       port_type port_map[2];
-
-       pci_read_config_dword(pdev, 0x40, &control);
-
-       /* There are two basic mappings. One has the two SATA ports merged
-          as master/slave and the secondary as PATA, the other has only the
-          SATA port mapped */
-       if (control & (1 << 23)) {
-               port_map[0] = PORT_SATA;
-               port_map[1] = PORT_PATA0;
-       } else {
-               port_map[0] = PORT_SATA;
-               port_map[1] = PORT_SATA;
-       }
-
-       /* The 365/366 may have this bit set to map the second PATA port
-          as the internal primary channel */
-       pci_read_config_dword(pdev, 0x80, &control5);
-       if (control5 & (1<<24))
-               port_map[0] = PORT_PATA1;
-
-       /* The two ports may then be logically swapped by the firmware */
-       if (control & (1 << 22))
-               port = port ^ 1;
-
-       /*
-        *      Now we know which physical port we are talking about we can
-        *      actually do our cable checking etc. Thankfully we don't need
-        *      to do the plumbing for other cases.
-        */
-       switch (port_map[port]) {
-       case PORT_PATA0:
-               if (control & (1 << 3)) /* 40/80 pin primary */
-                       return ATA_CBL_PATA40;
-               return ATA_CBL_PATA80;
-       case PORT_PATA1:
-               if (control5 & (1 << 19))       /* 40/80 pin secondary */
-                       return ATA_CBL_PATA40;
-               return ATA_CBL_PATA80;
-       case PORT_SATA:
-               break;
-       }
-       /* Avoid bogus "control reaches end of non-void function" */
-       return ATA_CBL_PATA80;
-}
-
-static void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-/**
- *     jmicron_set_dma_mode    -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     As the JMicron snoops for timings we don't need to do anything here.
- */
-
-static void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-static const struct ide_port_ops jmicron_port_ops = {
-       .set_pio_mode           = jmicron_set_pio_mode,
-       .set_dma_mode           = jmicron_set_dma_mode,
-       .cable_detect           = jmicron_cable_detect,
-};
-
-static const struct ide_port_info jmicron_chipset = {
-       .name           = DRV_NAME,
-       .enablebits     = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
-       .port_ops       = &jmicron_port_ops,
-       .pio_mask       = ATA_PIO5,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA6,
-};
-
-/**
- *     jmicron_init_one        -       pci layer discovery entry
- *     @dev: PCI device
- *     @id: ident table entry
- *
- *     Called by the PCI code when it finds a Jmicron controller.
- *     We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &jmicron_chipset, NULL);
-}
-
-/* All JMB PATA controllers have and will continue to have the same
- * interface.  Matching vendor and device class is enough for all
- * current and future controllers if the controller is programmed
- * properly.
- *
- * If libata is configured, jmicron PCI quirk programs the controller
- * into the correct mode.  If libata isn't configured, match known
- * device IDs too to maintain backward compatibility.
- */
-static struct pci_device_id jmicron_pci_tbl[] = {
-#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
-       { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
-       { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
-       { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
-       { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
-       { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
-#endif
-       { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-         PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
-       { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
-
-static struct pci_driver jmicron_pci_driver = {
-       .name           = "JMicron IDE",
-       .id_table       = jmicron_pci_tbl,
-       .probe          = jmicron_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init jmicron_ide_init(void)
-{
-       return ide_pci_register_driver(&jmicron_pci_driver);
-}
-
-static void __exit jmicron_ide_exit(void)
-{
-       pci_unregister_driver(&jmicron_pci_driver);
-}
-
-module_init(jmicron_ide_init);
-module_exit(jmicron_ide_exit);
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
deleted file mode 100644 (file)
index 8d2bf73..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- *  Macintosh IDE Driver
- *
- *     Copyright (C) 1998 by Michael Schmitz
- *
- *  This driver was written based on information obtained from the MacOS IDE
- *  driver binary by Mikael Forselius
- *
- *  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.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/macintosh.h>
-
-#define DRV_NAME "mac_ide"
-
-#define IDE_BASE 0x50F1A000    /* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_CONTROL    0x38    /* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR                0x101   /* (0x101) IDE interrupt flags on Quadra:
-                                *
-                                * Bit 0+1: some interrupt flags
-                                * Bit 2+3: some interrupt enable
-                                * Bit 4:   ??
-                                * Bit 5:   IDE interrupt flag (any hwif)
-                                * Bit 6:   maybe IDE interrupt enable (any hwif) ??
-                                * Bit 7:   Any interrupt condition
-                                */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-int macide_test_irq(ide_hwif_t *hwif)
-{
-       if (*ide_ifr & 0x20)
-               return 1;
-       return 0;
-}
-
-static void macide_clear_irq(ide_drive_t *drive)
-{
-       *ide_ifr &= ~0x20;
-}
-
-static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base,
-                                     int irq)
-{
-       int i;
-
-       memset(hw, 0, sizeof(*hw));
-
-       for (i = 0; i < 8; i++)
-               hw->io_ports_array[i] = base + i * 4;
-
-       hw->io_ports.ctl_addr = base + IDE_CONTROL;
-
-       hw->irq = irq;
-}
-
-static const struct ide_port_ops macide_port_ops = {
-       .clear_irq              = macide_clear_irq,
-       .test_irq               = macide_test_irq,
-};
-
-static const struct ide_port_info macide_port_info = {
-       .port_ops               = &macide_port_ops,
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_generic,
-};
-
-static const char *mac_ide_name[] =
-       { "Quadra", "Powerbook", "Powerbook Baboon" };
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-static int mac_ide_probe(struct platform_device *pdev)
-{
-       struct resource *mem, *irq;
-       struct ide_hw hw, *hws[] = { &hw };
-       struct ide_port_info d = macide_port_info;
-       struct ide_host *host;
-       int rc;
-
-       if (!MACH_IS_MAC)
-               return -ENODEV;
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem)
-               return -ENODEV;
-
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq)
-               return -ENODEV;
-
-       if (!devm_request_mem_region(&pdev->dev, mem->start,
-                                    resource_size(mem), DRV_NAME)) {
-               dev_err(&pdev->dev, "resources busy\n");
-               return -EBUSY;
-       }
-
-       printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
-                        mac_ide_name[macintosh_config->ide_type - 1]);
-
-       macide_setup_ports(&hw, mem->start, irq->start);
-
-       rc = ide_host_add(&d, hws, 1, &host);
-       if (rc)
-               return rc;
-
-       platform_set_drvdata(pdev, host);
-       return 0;
-}
-
-static int mac_ide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = platform_get_drvdata(pdev);
-
-       ide_host_remove(host);
-       return 0;
-}
-
-static struct platform_driver mac_ide_driver = {
-       .driver = {
-               .name = DRV_NAME,
-       },
-       .probe  = mac_ide_probe,
-       .remove = mac_ide_remove,
-};
-
-module_platform_driver(mac_ide_driver);
-
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
deleted file mode 100644 (file)
index 11a672a..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1997-1998     Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998          Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2004          Grant Grundler <grundler at parisc-linux.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "ns87415"
-
-#ifdef CONFIG_SUPERIO
-/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
- * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
- * which use the integrated NS87514 cell for CD-ROM support.
- * i.e we have to support for CD-ROM installs.
- * See drivers/parisc/superio.c for more gory details.
- */
-#include <asm/superio.h>
-
-#define SUPERIO_IDE_MAX_RETRIES 25
-
-/* Because of a defect in Super I/O, all reads of the PCI DMA status 
- * registers, IDE status register and the IDE select register need to be 
- * retried
- */
-static u8 superio_ide_inb (unsigned long port)
-{
-       u8 tmp;
-       int retries = SUPERIO_IDE_MAX_RETRIES;
-
-       /* printk(" [ reading port 0x%x with retry ] ", port); */
-
-       do {
-               tmp = inb(port);
-               if (tmp == 0)
-                       udelay(50);
-       } while (tmp == 0 && retries-- > 0);
-
-       return tmp;
-}
-
-static u8 superio_read_status(ide_hwif_t *hwif)
-{
-       return superio_ide_inb(hwif->io_ports.status_addr);
-}
-
-static u8 superio_dma_sff_read_status(ide_hwif_t *hwif)
-{
-       return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS);
-}
-
-static void superio_tf_read(ide_drive_t *drive, struct ide_taskfile *tf,
-                           u8 valid)
-{
-       struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-
-       if (valid & IDE_VALID_ERROR)
-               tf->error  = inb(io_ports->feature_addr);
-       if (valid & IDE_VALID_NSECT)
-               tf->nsect  = inb(io_ports->nsect_addr);
-       if (valid & IDE_VALID_LBAL)
-               tf->lbal   = inb(io_ports->lbal_addr);
-       if (valid & IDE_VALID_LBAM)
-               tf->lbam   = inb(io_ports->lbam_addr);
-       if (valid & IDE_VALID_LBAH)
-               tf->lbah   = inb(io_ports->lbah_addr);
-       if (valid & IDE_VALID_DEVICE)
-               tf->device = superio_ide_inb(io_ports->device_addr);
-}
-
-static void ns87415_dev_select(ide_drive_t *drive);
-
-static const struct ide_tp_ops superio_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = superio_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ns87415_dev_select,
-       .tf_load                = ide_tf_load,
-       .tf_read                = superio_tf_read,
-
-       .input_data             = ide_input_data,
-       .output_data            = ide_output_data,
-};
-
-static void superio_init_iops(struct hwif_s *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       u32 dma_stat;
-       u8 port = hwif->channel, tmp;
-
-       dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa);
-
-       /* Clear error/interrupt, enable dma */
-       tmp = superio_ide_inb(dma_stat);
-       outb(tmp | 0x66, dma_stat);
-}
-#else
-#define superio_dma_sff_read_status ide_dma_sff_read_status
-#endif
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to IDE_DFLAG_PRESENT)
- * the IRQ associated with the port,
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       new = *old;
-
-       /* Adjust IRQ enable bit */
-       bit = 1 << (8 + hwif->channel);
-
-       if (drive->dev_flags & IDE_DFLAG_PRESENT)
-               new &= ~bit;
-       else
-               new |= bit;
-
-       /* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-       bit   = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1));
-       other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1));
-       new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
-       if (new != *old) {
-               unsigned char stat;
-
-               /*
-                * Don't change DMA engine settings while Write Buffers
-                * are busy.
-                */
-               (void) pci_read_config_byte(dev, 0x43, &stat);
-               while (stat & 0x03) {
-                       udelay(1);
-                       (void) pci_read_config_byte(dev, 0x43, &stat);
-               }
-
-               *old = new;
-               (void) pci_write_config_dword(dev, 0x40, new);
-
-               /*
-                * And let things settle...
-                */
-               udelay(10);
-       }
-
-       local_irq_restore(flags);
-}
-
-static void ns87415_dev_select(ide_drive_t *drive)
-{
-       ns87415_prepare_drive(drive,
-                             !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
-
-       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-static void ns87415_dma_start(ide_drive_t *drive)
-{
-       ns87415_prepare_drive(drive, 1);
-       ide_dma_start(drive);
-}
-
-static int ns87415_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat = 0, dma_cmd = 0;
-
-       dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-       /* get DMA command mode */
-       dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-       /* stop DMA */
-       outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-       /* from ERRATA: clear the INTR & ERROR bits */
-       dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-       outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD);
-
-       ns87415_prepare_drive(drive, 0);
-
-       /* verify good DMA status */
-       return (dma_stat & 7) != 4;
-}
-
-static void init_hwif_ns87415 (ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned int ctrl, using_inta;
-       u8 progif;
-#ifdef __sparc_v9__
-       int timeout;
-       u8 stat;
-#endif
-
-       /*
-        * We cannot probe for IRQ: both ports share common IRQ on INTA.
-        * Also, leave IRQ masked during drive probing, to prevent infinite
-        * interrupts from a potentially floating INTA..
-        *
-        * IRQs get unmasked in dev_select() when drive is first used.
-        */
-       (void) pci_read_config_dword(dev, 0x40, &ctrl);
-       (void) pci_read_config_byte(dev, 0x09, &progif);
-       /* is irq in "native" mode? */
-       using_inta = progif & (1 << (hwif->channel << 1));
-       if (!using_inta)
-               using_inta = ctrl & (1 << (4 + hwif->channel));
-       if (hwif->mate) {
-               hwif->select_data = hwif->mate->select_data;
-       } else {
-               hwif->select_data = (unsigned long)
-                                       &ns87415_control[ns87415_count++];
-               ctrl |= (1 << 8) | (1 << 9);    /* mask both IRQs */
-               if (using_inta)
-                       ctrl &= ~(1 << 6);      /* unmask INTA */
-               *((unsigned int *)hwif->select_data) = ctrl;
-               (void) pci_write_config_dword(dev, 0x40, ctrl);
-
-               /*
-                * Set prefetch size to 512 bytes for both ports,
-                * but don't turn on/off prefetching here.
-                */
-               pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
-               /*
-                * XXX: Reset the device, if we don't it will not respond to
-                *      dev_select() properly during first ide_probe_port().
-                */
-               timeout = 10000;
-               outb(12, hwif->io_ports.ctl_addr);
-               udelay(10);
-               outb(8, hwif->io_ports.ctl_addr);
-               do {
-                       udelay(50);
-                       stat = hwif->tp_ops->read_status(hwif);
-                       if (stat == 0xff)
-                               break;
-               } while ((stat & ATA_BUSY) && --timeout);
-#endif
-       }
-
-       if (!using_inta)
-               hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
-
-       if (!hwif->dma_base)
-               return;
-
-       outb(0x60, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-static const struct ide_tp_ops ns87415_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ns87415_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_dma_ops ns87415_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ns87415_dma_start,
-       .dma_end                = ns87415_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = superio_dma_sff_read_status,
-};
-
-static const struct ide_port_info ns87415_chipset = {
-       .name           = DRV_NAME,
-       .init_hwif      = init_hwif_ns87415,
-       .tp_ops         = &ns87415_tp_ops,
-       .dma_ops        = &ns87415_dma_ops,
-       .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-                         IDE_HFLAG_NO_ATAPI_DMA,
-};
-
-static int ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d = ns87415_chipset;
-
-#ifdef CONFIG_SUPERIO
-       if (PCI_SLOT(dev->devfn) == 0xE) {
-               /* Built-in - assume it's under superio. */
-               d.init_iops = superio_init_iops;
-               d.tp_ops = &superio_tp_ops;
-       }
-#endif
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id ns87415_pci_tbl[] = {
-       { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
-
-static struct pci_driver ns87415_pci_driver = {
-       .name           = "NS87415_IDE",
-       .id_table       = ns87415_pci_tbl,
-       .probe          = ns87415_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init ns87415_ide_init(void)
-{
-       return ide_pci_register_driver(&ns87415_pci_driver);
-}
-
-static void __exit ns87415_ide_exit(void)
-{
-       pci_unregister_driver(&ns87415_pci_driver);
-}
-
-module_init(ns87415_ide_init);
-module_exit(ns87415_ide_exit);
-
-MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
deleted file mode 100644 (file)
index c374f82..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "opti621"
-
-#define READ_REG 0     /* index of Read cycle timing register */
-#define WRITE_REG 1    /* index of Write cycle timing register */
-#define CNTRL_REG 3    /* index of Control register */
-#define STRAP_REG 5    /* index of Strap register */
-#define MISC_REG 6     /* index of Miscellaneous register */
-
-static int reg_base;
-
-static DEFINE_SPINLOCK(opti621_lock);
-
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-static void write_reg(u8 value, int reg)
-{
-       inw(reg_base + 1);
-       inw(reg_base + 1);
-       outb(3, reg_base + 2);
-       outb(value, reg_base + reg);
-       outb(0x83, reg_base + 2);
-}
-
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-static u8 read_reg(int reg)
-{
-       u8 ret = 0;
-
-       inw(reg_base + 1);
-       inw(reg_base + 1);
-       outb(3, reg_base + 2);
-       ret = inb(reg_base + reg);
-       outb(0x83, reg_base + 2);
-
-       return ret;
-}
-
-static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       ide_drive_t *pair = ide_get_pair_dev(drive);
-       unsigned long flags;
-       unsigned long mode = drive->pio_mode, pair_mode;
-       const u8 pio = mode - XFER_PIO_0;
-       u8 tim, misc, addr_pio = pio, clk;
-
-       /* DRDY is default 2 (by OPTi Databook) */
-       static const u8 addr_timings[2][5] = {
-               { 0x20, 0x10, 0x00, 0x00, 0x00 },       /* 33 MHz */
-               { 0x10, 0x10, 0x00, 0x00, 0x00 },       /* 25 MHz */
-       };
-       static const u8 data_rec_timings[2][5] = {
-               { 0x5b, 0x45, 0x32, 0x21, 0x20 },       /* 33 MHz */
-               { 0x48, 0x34, 0x21, 0x10, 0x10 }        /* 25 MHz */
-       };
-
-       ide_set_drivedata(drive, (void *)mode);
-
-       if (pair) {
-               pair_mode = (unsigned long)ide_get_drivedata(pair);
-               if (pair_mode && pair_mode < mode)
-                       addr_pio = pair_mode - XFER_PIO_0;
-       }
-
-       spin_lock_irqsave(&opti621_lock, flags);
-
-       reg_base = hwif->io_ports.data_addr;
-
-       /* allow Register-B */
-       outb(0xc0, reg_base + CNTRL_REG);
-       /* hmm, setupvic.exe does this ;-) */
-       outb(0xff, reg_base + 5);
-       /* if reads 0xff, adapter not exist? */
-       (void)inb(reg_base + CNTRL_REG);
-       /* if reads 0xc0, no interface exist? */
-       read_reg(CNTRL_REG);
-
-       /* check CLK speed */
-       clk = read_reg(STRAP_REG) & 1;
-
-       printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33);
-
-       tim  = data_rec_timings[clk][pio];
-       misc = addr_timings[clk][addr_pio];
-
-       /* select Index-0/1 for Register-A/B */
-       write_reg(drive->dn & 1, MISC_REG);
-       /* set read cycle timings */
-       write_reg(tim, READ_REG);
-       /* set write cycle timings */
-       write_reg(tim, WRITE_REG);
-
-       /* use Register-A for drive 0 */
-       /* use Register-B for drive 1 */
-       write_reg(0x85, CNTRL_REG);
-
-       /* set address setup, DRDY timings,   */
-       /*  and read prefetch for both drives */
-       write_reg(misc, MISC_REG);
-
-       spin_unlock_irqrestore(&opti621_lock, flags);
-}
-
-static const struct ide_port_ops opti621_port_ops = {
-       .set_pio_mode           = opti621_set_pio_mode,
-};
-
-static const struct ide_port_info opti621_chipset = {
-       .name           = DRV_NAME,
-       .enablebits     = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
-       .port_ops       = &opti621_port_ops,
-       .host_flags     = IDE_HFLAG_NO_DMA,
-       .pio_mask       = ATA_PIO4,
-};
-
-static int opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &opti621_chipset, NULL);
-}
-
-static const struct pci_device_id opti621_pci_tbl[] = {
-       { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
-       { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
-
-static struct pci_driver opti621_pci_driver = {
-       .name           = "Opti621_IDE",
-       .id_table       = opti621_pci_tbl,
-       .probe          = opti621_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init opti621_ide_init(void)
-{
-       return ide_pci_register_driver(&opti621_pci_driver);
-}
-
-static void __exit opti621_ide_exit(void)
-{
-       pci_unregister_driver(&opti621_pci_driver);
-}
-
-module_init(opti621_ide_init);
-module_exit(opti621_ide_exit);
-
-MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
deleted file mode 100644 (file)
index d1fe4c1..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Palmchip bk3710 IDE controller
- *
- * Copyright (C) 2006 Texas Instruments.
- * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * ----------------------------------------------------------------------------
- *
- * ----------------------------------------------------------------------------
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-/* Offset of the primary interface registers */
-#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
-
-/* Primary Control Offset */
-#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
-
-#define BK3710_BMICP           0x00
-#define BK3710_BMISP           0x02
-#define BK3710_BMIDTP          0x04
-#define BK3710_IDETIMP         0x40
-#define BK3710_IDESTATUS       0x47
-#define BK3710_UDMACTL         0x48
-#define BK3710_MISCCTL         0x50
-#define BK3710_REGSTB          0x54
-#define BK3710_REGRCVR         0x58
-#define BK3710_DATSTB          0x5C
-#define BK3710_DATRCVR         0x60
-#define BK3710_DMASTB          0x64
-#define BK3710_DMARCVR         0x68
-#define BK3710_UDMASTB         0x6C
-#define BK3710_UDMATRP         0x70
-#define BK3710_UDMAENV         0x74
-#define BK3710_IORDYTMP                0x78
-
-static unsigned ideclk_period; /* in nanoseconds */
-
-struct palm_bk3710_udmatiming {
-       unsigned int rptime;    /* tRP -- Ready to pause time (nsec) */
-       unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */
-                               /* tENV is always a minimum of 20 nsec */
-};
-
-static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
-       { 160, 240 / 2 },       /* UDMA Mode 0 */
-       { 125, 160 / 2 },       /* UDMA Mode 1 */
-       { 100, 120 / 2 },       /* UDMA Mode 2 */
-       { 100,  90 / 2 },       /* UDMA Mode 3 */
-       { 100,  60 / 2 },       /* UDMA Mode 4 */
-       {  85,  40 / 2 },       /* UDMA Mode 5 */
-};
-
-static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
-                                   unsigned int mode)
-{
-       u8 tenv, trp, t0;
-       u32 val32;
-       u16 val16;
-
-       /* DMA Data Setup */
-       t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
-                         ideclk_period) - 1;
-       tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
-       trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
-                          ideclk_period) - 1;
-
-       /* udmastb Ultra DMA Access Strobe Width */
-       val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
-       val32 |= (t0 << (dev ? 8 : 0));
-       writel(val32, base + BK3710_UDMASTB);
-
-       /* udmatrp Ultra DMA Ready to Pause Time */
-       val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
-       val32 |= (trp << (dev ? 8 : 0));
-       writel(val32, base + BK3710_UDMATRP);
-
-       /* udmaenv Ultra DMA envelop Time */
-       val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
-       val32 |= (tenv << (dev ? 8 : 0));
-       writel(val32, base + BK3710_UDMAENV);
-
-       /* Enable UDMA for Device */
-       val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
-       writew(val16, base + BK3710_UDMACTL);
-}
-
-static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
-                                  unsigned short min_cycle,
-                                  unsigned int mode)
-{
-       u8 td, tkw, t0;
-       u32 val32;
-       u16 val16;
-       struct ide_timing *t;
-       int cycletime;
-
-       t = ide_timing_find_mode(mode);
-       cycletime = max_t(int, t->cycle, min_cycle);
-
-       /* DMA Data Setup */
-       t0 = DIV_ROUND_UP(cycletime, ideclk_period);
-       td = DIV_ROUND_UP(t->active, ideclk_period);
-       tkw = t0 - td - 1;
-       td -= 1;
-
-       val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
-       val32 |= (td << (dev ? 8 : 0));
-       writel(val32, base + BK3710_DMASTB);
-
-       val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
-       val32 |= (tkw << (dev ? 8 : 0));
-       writel(val32, base + BK3710_DMARCVR);
-
-       /* Disable UDMA for Device */
-       val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
-       writew(val16, base + BK3710_UDMACTL);
-}
-
-static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
-                                  unsigned int dev, unsigned int cycletime,
-                                  unsigned int mode)
-{
-       u8 t2, t2i, t0;
-       u32 val32;
-       struct ide_timing *t;
-
-       t = ide_timing_find_mode(XFER_PIO_0 + mode);
-
-       /* PIO Data Setup */
-       t0 = DIV_ROUND_UP(cycletime, ideclk_period);
-       t2 = DIV_ROUND_UP(t->active, ideclk_period);
-
-       t2i = t0 - t2 - 1;
-       t2 -= 1;
-
-       val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
-       val32 |= (t2 << (dev ? 8 : 0));
-       writel(val32, base + BK3710_DATSTB);
-
-       val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
-       val32 |= (t2i << (dev ? 8 : 0));
-       writel(val32, base + BK3710_DATRCVR);
-
-       if (mate) {
-               u8 mode2 = mate->pio_mode - XFER_PIO_0;
-
-               if (mode2 < mode)
-                       mode = mode2;
-       }
-
-       /* TASKFILE Setup */
-       t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
-       t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
-
-       t2i = t0 - t2 - 1;
-       t2 -= 1;
-
-       val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
-       val32 |= (t2 << (dev ? 8 : 0));
-       writel(val32, base + BK3710_REGSTB);
-
-       val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
-       val32 |= (t2i << (dev ? 8 : 0));
-       writel(val32, base + BK3710_REGRCVR);
-}
-
-static void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int is_slave = drive->dn & 1;
-       void __iomem *base = (void __iomem *)hwif->dma_base;
-       const u8 xferspeed = drive->dma_mode;
-
-       if (xferspeed >= XFER_UDMA_0) {
-               palm_bk3710_setudmamode(base, is_slave,
-                                       xferspeed - XFER_UDMA_0);
-       } else {
-               palm_bk3710_setdmamode(base, is_slave,
-                                      drive->id[ATA_ID_EIDE_DMA_MIN],
-                                      xferspeed);
-       }
-}
-
-static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned int cycle_time;
-       int is_slave = drive->dn & 1;
-       ide_drive_t *mate;
-       void __iomem *base = (void __iomem *)hwif->dma_base;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       /*
-        * Obtain the drive PIO data for tuning the Palm Chip registers
-        */
-       cycle_time = ide_pio_cycle_time(drive, pio);
-       mate = ide_get_pair_dev(drive);
-       palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
-}
-
-static void palm_bk3710_chipinit(void __iomem *base)
-{
-       /*
-        * REVISIT:  the ATA reset signal needs to be managed through a
-        * GPIO, which means it should come from platform_data.  Until
-        * we get and use such information, we have to trust that things
-        * have been reset before we get here.
-        */
-
-       /*
-        * Program the IDETIMP Register Value based on the following assumptions
-        *
-        * (ATA_IDETIMP_IDEEN           , ENABLE ) |
-        * (ATA_IDETIMP_PREPOST1        , DISABLE) |
-        * (ATA_IDETIMP_PREPOST0        , DISABLE) |
-        *
-        * DM6446 silicon rev 2.1 and earlier have no observed net benefit
-        * from enabling prefetch/postwrite.
-        */
-       writew(BIT(15), base + BK3710_IDETIMP);
-
-       /*
-        * UDMACTL Ultra-ATA DMA Control
-        * (ATA_UDMACTL_UDMAP1  , 0 ) |
-        * (ATA_UDMACTL_UDMAP0  , 0 )
-        *
-        */
-       writew(0, base + BK3710_UDMACTL);
-
-       /*
-        * MISCCTL Miscellaneous Conrol Register
-        * (ATA_MISCCTL_HWNHLD1P        , 1 cycle)
-        * (ATA_MISCCTL_HWNHLD0P        , 1 cycle)
-        * (ATA_MISCCTL_TIMORIDE        , 1)
-        */
-       writel(0x001, base + BK3710_MISCCTL);
-
-       /*
-        * IORDYTMP IORDY Timer for Primary Register
-        * (ATA_IORDYTMP_IORDYTMP     , 0xffff  )
-        */
-       writel(0xFFFF, base + BK3710_IORDYTMP);
-
-       /*
-        * Configure BMISP Register
-        * (ATA_BMISP_DMAEN1    , DISABLE )     |
-        * (ATA_BMISP_DMAEN0    , DISABLE )     |
-        * (ATA_BMISP_IORDYINT  , CLEAR)        |
-        * (ATA_BMISP_INTRSTAT  , CLEAR)        |
-        * (ATA_BMISP_DMAERROR  , CLEAR)
-        */
-       writew(0, base + BK3710_BMISP);
-
-       palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
-       palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
-}
-
-static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif)
-{
-       return ATA_CBL_PATA80;
-}
-
-static int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
-
-       if (ide_allocate_dma_engine(hwif))
-               return -1;
-
-       hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET;
-
-       return 0;
-}
-
-static const struct ide_port_ops palm_bk3710_ports_ops = {
-       .set_pio_mode           = palm_bk3710_set_pio_mode,
-       .set_dma_mode           = palm_bk3710_set_dma_mode,
-       .cable_detect           = palm_bk3710_cable_detect,
-};
-
-static struct ide_port_info palm_bk3710_port_info __initdata = {
-       .init_dma               = palm_bk3710_init_dma,
-       .port_ops               = &palm_bk3710_ports_ops,
-       .dma_ops                = &sff_dma_ops,
-       .host_flags             = IDE_HFLAG_MMIO,
-       .pio_mask               = ATA_PIO4,
-       .mwdma_mask             = ATA_MWDMA2,
-       .chipset                = ide_palm3710,
-};
-
-static int __init palm_bk3710_probe(struct platform_device *pdev)
-{
-       struct clk *clk;
-       struct resource *mem, *irq;
-       void __iomem *base;
-       unsigned long rate, mem_size;
-       int i, rc;
-       struct ide_hw hw, *hws[] = { &hw };
-
-       clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(clk))
-               return -ENODEV;
-
-       clk_enable(clk);
-       rate = clk_get_rate(clk);
-       if (!rate)
-               return -EINVAL;
-
-       /* NOTE:  round *down* to meet minimum timings; we count in clocks */
-       ideclk_period = 1000000000UL / rate;
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (mem == NULL) {
-               printk(KERN_ERR "failed to get memory region resource\n");
-               return -ENODEV;
-       }
-
-       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (irq == NULL) {
-               printk(KERN_ERR "failed to get IRQ resource\n");
-               return -ENODEV;
-       }
-
-       mem_size = resource_size(mem);
-       if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) {
-               printk(KERN_ERR "failed to request memory region\n");
-               return -EBUSY;
-       }
-
-       base = ioremap(mem->start, mem_size);
-       if (!base) {
-               printk(KERN_ERR "failed to map IO memory\n");
-               release_mem_region(mem->start, mem_size);
-               return -ENOMEM;
-       }
-
-       /* Configure the Palm Chip controller */
-       palm_bk3710_chipinit(base);
-
-       memset(&hw, 0, sizeof(hw));
-       for (i = 0; i < IDE_NR_PORTS - 2; i++)
-               hw.io_ports_array[i] = (unsigned long)
-                               (base + IDE_PALM_ATA_PRI_REG_OFFSET + i);
-       hw.io_ports.ctl_addr = (unsigned long)
-                       (base + IDE_PALM_ATA_PRI_CTL_OFFSET);
-       hw.irq = irq->start;
-       hw.dev = &pdev->dev;
-
-       palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
-                                                            ATA_UDMA5;
-
-       /* Register the IDE interface with Linux */
-       rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL);
-       if (rc)
-               goto out;
-
-       return 0;
-out:
-       printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
-       return rc;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:palm_bk3710");
-
-static struct platform_driver platform_bk_driver = {
-       .driver = {
-               .name = "palm_bk3710",
-       },
-};
-
-static int __init palm_bk3710_init(void)
-{
-       return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe);
-}
-
-module_init(palm_bk3710_init);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
deleted file mode 100644 (file)
index 4fcafb9..0000000
+++ /dev/null
@@ -1,557 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Promise TX2/TX4/TX2000/133 IDE driver
- *
- *  Split from:
- *  linux/drivers/ide/pdc202xx.c       Version 0.35    Mar. 30, 2002
- *  Copyright (C) 1998-2002            Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2005-2007            MontaVista Software, Inc.
- *  Portions Copyright (C) 1999 Promise Technology, Inc.
- *  Author: Frank Tiernan (frankt@promise.com)
- *  Released under terms of General Public License
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/ktime.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/prom.h>
-#endif
-
-#define DRV_NAME "pdc202xx_new"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args)
-#else
-#define DBG(fmt, args...)
-#endif
-
-static u8 max_dma_rate(struct pci_dev *pdev)
-{
-       u8 mode;
-
-       switch(pdev->device) {
-               case PCI_DEVICE_ID_PROMISE_20277:
-               case PCI_DEVICE_ID_PROMISE_20276:
-               case PCI_DEVICE_ID_PROMISE_20275:
-               case PCI_DEVICE_ID_PROMISE_20271:
-               case PCI_DEVICE_ID_PROMISE_20269:
-                       mode = 4;
-                       break;
-               case PCI_DEVICE_ID_PROMISE_20270:
-               case PCI_DEVICE_ID_PROMISE_20268:
-                       mode = 3;
-                       break;
-               default:
-                       return 0;
-       }
-
-       return mode;
-}
-
-/**
- * get_indexed_reg - Get indexed register
- * @hwif: for the port address
- * @index: index of the indexed register
- */
-static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
-{
-       u8 value;
-
-       outb(index, hwif->dma_base + 1);
-       value = inb(hwif->dma_base + 3);
-
-       DBG("index[%02X] value[%02X]\n", index, value);
-       return value;
-}
-
-/**
- * set_indexed_reg - Set indexed register
- * @hwif: for the port address
- * @index: index of the indexed register
- */
-static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
-{
-       outb(index, hwif->dma_base + 1);
-       outb(value, hwif->dma_base + 3);
-       DBG("index[%02X] value[%02X]\n", index, value);
-}
-
-/*
- * ATA Timing Tables based on 133 MHz PLL output clock.
- *
- * If the PLL outputs 100 MHz clock, the ASIC hardware will set
- * the timing registers automatically when "set features" command is
- * issued to the device. However, if the PLL output clock is 133 MHz,
- * the following tables must be used.
- */
-static struct pio_timing {
-       u8 reg0c, reg0d, reg13;
-} pio_timings [] = {
-       { 0xfb, 0x2b, 0xac },   /* PIO mode 0, IORDY off, Prefetch off */
-       { 0x46, 0x29, 0xa4 },   /* PIO mode 1, IORDY off, Prefetch off */
-       { 0x23, 0x26, 0x64 },   /* PIO mode 2, IORDY off, Prefetch off */
-       { 0x27, 0x0d, 0x35 },   /* PIO mode 3, IORDY on,  Prefetch off */
-       { 0x23, 0x09, 0x25 },   /* PIO mode 4, IORDY on,  Prefetch off */
-};
-
-static struct mwdma_timing {
-       u8 reg0e, reg0f;
-} mwdma_timings [] = {
-       { 0xdf, 0x5f },         /* MWDMA mode 0 */
-       { 0x6b, 0x27 },         /* MWDMA mode 1 */
-       { 0x69, 0x25 },         /* MWDMA mode 2 */
-};
-
-static struct udma_timing {
-       u8 reg10, reg11, reg12;
-} udma_timings [] = {
-       { 0x4a, 0x0f, 0xd5 },   /* UDMA mode 0 */
-       { 0x3a, 0x0a, 0xd0 },   /* UDMA mode 1 */
-       { 0x2a, 0x07, 0xcd },   /* UDMA mode 2 */
-       { 0x1a, 0x05, 0xcd },   /* UDMA mode 3 */
-       { 0x1a, 0x03, 0xcd },   /* UDMA mode 4 */
-       { 0x1a, 0x02, 0xcb },   /* UDMA mode 5 */
-       { 0x1a, 0x01, 0xcb },   /* UDMA mode 6 */
-};
-
-static void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
-       const u8 speed          = drive->dma_mode;
-
-       /*
-        * IDE core issues SETFEATURES_XFER to the drive first (thanks to
-        * IDE_HFLAG_POST_SET_MODE in ->host_flags).  PDC202xx hardware will
-        * automatically set the timing registers based on 100 MHz PLL output.
-        *
-        * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
-        * chips, we must override the default register settings...
-        */
-       if (max_dma_rate(dev) == 4) {
-               u8 mode = speed & 0x07;
-
-               if (speed >= XFER_UDMA_0) {
-                       set_indexed_reg(hwif, 0x10 + adj,
-                                       udma_timings[mode].reg10);
-                       set_indexed_reg(hwif, 0x11 + adj,
-                                       udma_timings[mode].reg11);
-                       set_indexed_reg(hwif, 0x12 + adj,
-                                       udma_timings[mode].reg12);
-               } else {
-                       set_indexed_reg(hwif, 0x0e + adj,
-                                       mwdma_timings[mode].reg0e);
-                       set_indexed_reg(hwif, 0x0f + adj,
-                                       mwdma_timings[mode].reg0f);
-               }
-       } else if (speed == XFER_UDMA_2) {
-               /* Set tHOLD bit to 0 if using UDMA mode 2 */
-               u8 tmp = get_indexed_reg(hwif, 0x10 + adj);
-
-               set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
-       }
-}
-
-static void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       if (max_dma_rate(dev) == 4) {
-               set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
-               set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
-               set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
-       }
-}
-
-static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
-{
-       if (get_indexed_reg(hwif, 0x0b) & 0x04)
-               return ATA_CBL_PATA40;
-       else
-               return ATA_CBL_PATA80;
-}
-
-static void pdcnew_reset(ide_drive_t *drive)
-{
-       /*
-        * Deleted this because it is redundant from the caller.
-        */
-       printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n",
-               drive->hwif->channel ? "Secondary" : "Primary");
-}
-
-/**
- * read_counter - Read the byte count registers
- * @dma_base: for the port address
- */
-static long read_counter(u32 dma_base)
-{
-       u32  pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
-       u8   cnt0, cnt1, cnt2, cnt3;
-       long count = 0, last;
-       int  retry = 3;
-
-       do {
-               last = count;
-
-               /* Read the current count */
-               outb(0x20, pri_dma_base + 0x01);
-               cnt0 = inb(pri_dma_base + 0x03);
-               outb(0x21, pri_dma_base + 0x01);
-               cnt1 = inb(pri_dma_base + 0x03);
-               outb(0x20, sec_dma_base + 0x01);
-               cnt2 = inb(sec_dma_base + 0x03);
-               outb(0x21, sec_dma_base + 0x01);
-               cnt3 = inb(sec_dma_base + 0x03);
-
-               count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0;
-
-               /*
-                * The 30-bit decrementing counter is read in 4 pieces.
-                * Incorrect value may be read when the most significant bytes
-                * are changing...
-                */
-       } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count));
-
-       DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n",
-                 cnt0, cnt1, cnt2, cnt3);
-
-       return count;
-}
-
-/**
- * detect_pll_input_clock - Detect the PLL input clock in Hz.
- * @dma_base: for the port address
- * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
- */
-static long detect_pll_input_clock(unsigned long dma_base)
-{
-       ktime_t start_time, end_time;
-       long start_count, end_count;
-       long pll_input, usec_elapsed;
-       u8 scr1;
-
-       start_count = read_counter(dma_base);
-       start_time = ktime_get();
-
-       /* Start the test mode */
-       outb(0x01, dma_base + 0x01);
-       scr1 = inb(dma_base + 0x03);
-       DBG("scr1[%02X]\n", scr1);
-       outb(scr1 | 0x40, dma_base + 0x03);
-
-       /* Let the counter run for 10 ms. */
-       mdelay(10);
-
-       end_count = read_counter(dma_base);
-       end_time = ktime_get();
-
-       /* Stop the test mode */
-       outb(0x01, dma_base + 0x01);
-       scr1 = inb(dma_base + 0x03);
-       DBG("scr1[%02X]\n", scr1);
-       outb(scr1 & ~0x40, dma_base + 0x03);
-
-       /*
-        * Calculate the input clock in Hz
-        * (the clock counter is 30 bit wide and counts down)
-        */
-       usec_elapsed = ktime_us_delta(end_time, start_time);
-       pll_input = ((start_count - end_count) & 0x3fffffff) / 10 *
-               (10000000 / usec_elapsed);
-
-       DBG("start[%ld] end[%ld]\n", start_count, end_count);
-
-       return pll_input;
-}
-
-#ifdef CONFIG_PPC_PMAC
-static void apple_kiwi_init(struct pci_dev *pdev)
-{
-       struct device_node *np = pci_device_to_OF_node(pdev);
-       u8 conf;
-
-       if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
-               return;
-
-       if (pdev->revision >= 0x03) {
-               /* Setup chip magic config stuff (from darwin) */
-               pci_read_config_byte (pdev, 0x40, &conf);
-               pci_write_config_byte(pdev, 0x40, (conf | 0x01));
-       }
-}
-#endif /* CONFIG_PPC_PMAC */
-
-static int init_chipset_pdcnew(struct pci_dev *dev)
-{
-       const char *name = DRV_NAME;
-       unsigned long dma_base = pci_resource_start(dev, 4);
-       unsigned long sec_dma_base = dma_base + 0x08;
-       long pll_input, pll_output, ratio;
-       int f, r;
-       u8 pll_ctl0, pll_ctl1;
-
-       if (dma_base == 0)
-               return -EFAULT;
-
-#ifdef CONFIG_PPC_PMAC
-       apple_kiwi_init(dev);
-#endif
-
-       /* Calculate the required PLL output frequency */
-       switch(max_dma_rate(dev)) {
-               case 4: /* it's 133 MHz for Ultra133 chips */
-                       pll_output = 133333333;
-                       break;
-               case 3: /* and  100 MHz for Ultra100 chips */
-               default:
-                       pll_output = 100000000;
-                       break;
-       }
-
-       /*
-        * Detect PLL input clock.
-        * On some systems, where PCI bus is running at non-standard clock rate
-        * (e.g. 25 or 40 MHz), we have to adjust the cycle time.
-        * PDC20268 and newer chips employ PLL circuit to help correct timing
-        * registers setting.
-        */
-       pll_input = detect_pll_input_clock(dma_base);
-       printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n",
-               name, pci_name(dev), pll_input / 1000);
-
-       /* Sanity check */
-       if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) {
-               printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!"
-                       "\n", name, pci_name(dev), pll_input);
-               goto out;
-       }
-
-#ifdef DEBUG
-       DBG("pll_output is %ld Hz\n", pll_output);
-
-       /* Show the current clock value of PLL control register
-        * (maybe already configured by the BIOS)
-        */
-       outb(0x02, sec_dma_base + 0x01);
-       pll_ctl0 = inb(sec_dma_base + 0x03);
-       outb(0x03, sec_dma_base + 0x01);
-       pll_ctl1 = inb(sec_dma_base + 0x03);
-
-       DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-#endif
-
-       /*
-        * Calculate the ratio of F, R and NO
-        * POUT = (F + 2) / (( R + 2) * NO)
-        */
-       ratio = pll_output / (pll_input / 1000);
-       if (ratio < 8600L) { /* 8.6x */
-               /* Using NO = 0x01, R = 0x0d */
-               r = 0x0d;
-       } else if (ratio < 12900L) { /* 12.9x */
-               /* Using NO = 0x01, R = 0x08 */
-               r = 0x08;
-       } else if (ratio < 16100L) { /* 16.1x */
-               /* Using NO = 0x01, R = 0x06 */
-               r = 0x06;
-       } else if (ratio < 64000L) { /* 64x */
-               r = 0x00;
-       } else {
-               /* Invalid ratio */
-               printk(KERN_ERR "%s %s: Bad ratio %ld, giving up!\n",
-                       name, pci_name(dev), ratio);
-               goto out;
-       }
-
-       f = (ratio * (r + 2)) / 1000 - 2;
-
-       DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio);
-
-       if (unlikely(f < 0 || f > 127)) {
-               /* Invalid F */
-               printk(KERN_ERR "%s %s: F[%d] invalid!\n",
-                       name, pci_name(dev), f);
-               goto out;
-       }
-
-       pll_ctl0 = (u8) f;
-       pll_ctl1 = (u8) r;
-
-       DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-
-       outb(0x02,     sec_dma_base + 0x01);
-       outb(pll_ctl0, sec_dma_base + 0x03);
-       outb(0x03,     sec_dma_base + 0x01);
-       outb(pll_ctl1, sec_dma_base + 0x03);
-
-       /* Wait the PLL circuit to be stable */
-       mdelay(30);
-
-#ifdef DEBUG
-       /*
-        *  Show the current clock value of PLL control register
-        */
-       outb(0x02, sec_dma_base + 0x01);
-       pll_ctl0 = inb(sec_dma_base + 0x03);
-       outb(0x03, sec_dma_base + 0x01);
-       pll_ctl1 = inb(sec_dma_base + 0x03);
-
-       DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-#endif
-
- out:
-       return 0;
-}
-
-static struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev)
-{
-       struct pci_dev *dev2;
-
-       dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1,
-                                               PCI_FUNC(dev->devfn)));
-
-       if (dev2 &&
-           dev2->vendor == dev->vendor &&
-           dev2->device == dev->device) {
-
-               if (dev2->irq != dev->irq) {
-                       dev2->irq = dev->irq;
-                       printk(KERN_INFO DRV_NAME " %s: PCI config space "
-                               "interrupt fixed\n", pci_name(dev));
-               }
-
-               return dev2;
-       }
-
-       return NULL;
-}
-
-static const struct ide_port_ops pdcnew_port_ops = {
-       .set_pio_mode           = pdcnew_set_pio_mode,
-       .set_dma_mode           = pdcnew_set_dma_mode,
-       .resetproc              = pdcnew_reset,
-       .cable_detect           = pdcnew_cable_detect,
-};
-
-#define DECLARE_PDCNEW_DEV(udma) \
-       { \
-               .name           = DRV_NAME, \
-               .init_chipset   = init_chipset_pdcnew, \
-               .port_ops       = &pdcnew_port_ops, \
-               .host_flags     = IDE_HFLAG_POST_SET_MODE | \
-                                 IDE_HFLAG_ERROR_STOPS_FIFO | \
-                                 IDE_HFLAG_OFF_BOARD, \
-               .pio_mask       = ATA_PIO4, \
-               .mwdma_mask     = ATA_MWDMA2, \
-               .udma_mask      = udma, \
-       }
-
-static const struct ide_port_info pdcnew_chipsets[] = {
-       /* 0: PDC202{68,70} */          DECLARE_PDCNEW_DEV(ATA_UDMA5),
-       /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6),
-};
-
-/**
- *     pdc202new_init_one      -       called when a pdc202xx is found
- *     @dev: the pdc202new device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-static int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data];
-       struct pci_dev *bridge = dev->bus->self;
-
-       if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge &&
-           bridge->vendor == PCI_VENDOR_ID_DEC &&
-           bridge->device == PCI_DEVICE_ID_DEC_21150) {
-               struct pci_dev *dev2;
-
-               if (PCI_SLOT(dev->devfn) & 2)
-                       return -ENODEV;
-
-               dev2 = pdc20270_get_dev2(dev);
-
-               if (dev2) {
-                       int ret = ide_pci_init_two(dev, dev2, d, NULL);
-                       if (ret < 0)
-                               pci_dev_put(dev2);
-                       return ret;
-               }
-       }
-
-       if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge &&
-           bridge->vendor == PCI_VENDOR_ID_INTEL &&
-           (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
-            bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
-               printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller,"
-                       " skipping\n", pci_name(dev));
-               return -ENODEV;
-       }
-
-       return ide_pci_init_one(dev, d, NULL);
-}
-
-static void pdc202new_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
-       ide_pci_remove(dev);
-       pci_dev_put(dev2);
-}
-
-static const struct pci_device_id pdc202new_pci_tbl[] = {
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
-
-static struct pci_driver pdc202new_pci_driver = {
-       .name           = "Promise_IDE",
-       .id_table       = pdc202new_pci_tbl,
-       .probe          = pdc202new_init_one,
-       .remove         = pdc202new_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init pdc202new_ide_init(void)
-{
-       return ide_pci_register_driver(&pdc202new_pci_driver);
-}
-
-static void __exit pdc202new_ide_exit(void)
-{
-       pci_unregister_driver(&pdc202new_pci_driver);
-}
-
-module_init(pdc202new_ide_init);
-module_exit(pdc202new_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
-MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
deleted file mode 100644 (file)
index 5248ac0..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1998-2002            Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2006-2007, 2009      MontaVista Software, Inc.
- *  Copyright (C) 2007-2010            Bartlomiej Zolnierkiewicz
- *
- *  Portions Copyright (C) 1999 Promise Technology, Inc.
- *  Author: Frank Tiernan (frankt@promise.com)
- *  Released under terms of General Public License
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "pdc202xx_old"
-
-static void pdc202xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 drive_pci            = 0x60 + (drive->dn << 2);
-       const u8 speed          = drive->dma_mode;
-
-       u8                      AP = 0, BP = 0, CP = 0;
-       u8                      TA = 0, TB = 0, TC = 0;
-
-       pci_read_config_byte(dev, drive_pci,     &AP);
-       pci_read_config_byte(dev, drive_pci + 1, &BP);
-       pci_read_config_byte(dev, drive_pci + 2, &CP);
-
-       switch(speed) {
-               case XFER_UDMA_5:
-               case XFER_UDMA_4:       TB = 0x20; TC = 0x01; break;
-               case XFER_UDMA_2:       TB = 0x20; TC = 0x01; break;
-               case XFER_UDMA_3:
-               case XFER_UDMA_1:       TB = 0x40; TC = 0x02; break;
-               case XFER_UDMA_0:
-               case XFER_MW_DMA_2:     TB = 0x60; TC = 0x03; break;
-               case XFER_MW_DMA_1:     TB = 0x60; TC = 0x04; break;
-               case XFER_MW_DMA_0:     TB = 0xE0; TC = 0x0F; break;
-               case XFER_PIO_4:        TA = 0x01; TB = 0x04; break;
-               case XFER_PIO_3:        TA = 0x02; TB = 0x06; break;
-               case XFER_PIO_2:        TA = 0x03; TB = 0x08; break;
-               case XFER_PIO_1:        TA = 0x05; TB = 0x0C; break;
-               case XFER_PIO_0:
-               default:                TA = 0x09; TB = 0x13; break;
-       }
-
-       if (speed < XFER_SW_DMA_0) {
-               /*
-                * preserve SYNC_INT / ERDDY_EN bits while clearing
-                * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
-                */
-               AP &= ~0x3f;
-               if (ide_pio_need_iordy(drive, speed - XFER_PIO_0))
-                       AP |= 0x20;     /* set IORDY_EN bit */
-               if (drive->media == ide_disk)
-                       AP |= 0x10;     /* set Prefetch_EN bit */
-               /* clear PB[4:0] bits of register B */
-               BP &= ~0x1f;
-               pci_write_config_byte(dev, drive_pci,     AP | TA);
-               pci_write_config_byte(dev, drive_pci + 1, BP | TB);
-       } else {
-               /* clear MB[2:0] bits of register B */
-               BP &= ~0xe0;
-               /* clear MC[3:0] bits of register C */
-               CP &= ~0x0f;
-               pci_write_config_byte(dev, drive_pci + 1, BP | TB);
-               pci_write_config_byte(dev, drive_pci + 2, CP | TC);
-       }
-}
-
-static void pdc202xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       pdc202xx_set_mode(hwif, drive);
-}
-
-static int pdc202xx_test_irq(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long high_16   = pci_resource_start(dev, 4);
-       u8 sc1d                 = inb(high_16 + 0x1d);
-
-       if (hwif->channel) {
-               /*
-                * bit 7: error, bit 6: interrupting,
-                * bit 5: FIFO full, bit 4: FIFO empty
-                */
-               return (sc1d & 0x40) ? 1 : 0;
-       } else  {
-               /*
-                * bit 3: error, bit 2: interrupting,
-                * bit 1: FIFO full, bit 0: FIFO empty
-                */
-               return (sc1d & 0x04) ? 1 : 0;
-       }
-}
-
-static u8 pdc2026x_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
-
-       pci_read_config_word(dev, 0x50, &CIS);
-
-       return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-/*
- * Set the control register to use the 66MHz system
- * clock for UDMA 3/4/5 mode operation when necessary.
- *
- * FIXME: this register is shared by both channels, some locking is needed
- *
- * It may also be possible to leave the 66MHz clock on
- * and readjust the timing parameters.
- */
-static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
-{
-       unsigned long clock_reg = hwif->extra_base + 0x01;
-       u8 clock = inb(clock_reg);
-
-       outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
-}
-
-static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
-{
-       unsigned long clock_reg = hwif->extra_base + 0x01;
-       u8 clock = inb(clock_reg);
-
-       outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
-}
-
-static void pdc2026x_init_hwif(ide_hwif_t *hwif)
-{
-       pdc_old_disable_66MHz_clock(hwif);
-}
-
-static void pdc202xx_dma_start(ide_drive_t *drive)
-{
-       if (drive->current_speed > XFER_UDMA_2)
-               pdc_old_enable_66MHz_clock(drive->hwif);
-       if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
-               ide_hwif_t *hwif        = drive->hwif;
-               struct request *rq      = hwif->rq;
-               unsigned long high_16   = hwif->extra_base - 16;
-               unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
-               u32 word_count  = 0;
-               u8 clock = inb(high_16 + 0x11);
-
-               outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
-               word_count = (blk_rq_sectors(rq) << 8);
-               word_count = (rq_data_dir(rq) == READ) ?
-                                       word_count | 0x05000000 :
-                                       word_count | 0x06000000;
-               outl(word_count, atapi_reg);
-       }
-       ide_dma_start(drive);
-}
-
-static int pdc202xx_dma_end(ide_drive_t *drive)
-{
-       if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
-               ide_hwif_t *hwif        = drive->hwif;
-               unsigned long high_16   = hwif->extra_base - 16;
-               unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
-               u8 clock                = 0;
-
-               outl(0, atapi_reg); /* zero out extra */
-               clock = inb(high_16 + 0x11);
-               outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
-       }
-       if (drive->current_speed > XFER_UDMA_2)
-               pdc_old_disable_66MHz_clock(drive->hwif);
-       return ide_dma_end(drive);
-}
-
-static int init_chipset_pdc202xx(struct pci_dev *dev)
-{
-       unsigned long dmabase = pci_resource_start(dev, 4);
-       u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
-
-       if (dmabase == 0)
-               goto out;
-
-       udma_speed_flag = inb(dmabase | 0x1f);
-       primary_mode    = inb(dmabase | 0x1a);
-       secondary_mode  = inb(dmabase | 0x1b);
-       printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
-               "Primary %s Mode " \
-               "Secondary %s Mode.\n", pci_name(dev),
-               (udma_speed_flag & 1) ? "EN" : "DIS",
-               (primary_mode & 1) ? "MASTER" : "PCI",
-               (secondary_mode & 1) ? "MASTER" : "PCI" );
-
-       if (!(udma_speed_flag & 1)) {
-               printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
-                       pci_name(dev), udma_speed_flag,
-                       (udma_speed_flag|1));
-               outb(udma_speed_flag | 1, dmabase | 0x1f);
-               printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
-       }
-out:
-       return 0;
-}
-
-static void pdc202ata4_fixup_irq(struct pci_dev *dev, const char *name)
-{
-       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-               u8 irq = 0, irq2 = 0;
-               pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-               /* 0xbc */
-               pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
-               if (irq != irq2) {
-                       pci_write_config_byte(dev,
-                               (PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
-                       printk(KERN_INFO "%s %s: PCI config space interrupt "
-                               "mirror fixed\n", name, pci_name(dev));
-               }
-       }
-}
-
-#define IDE_HFLAGS_PDC202XX \
-       (IDE_HFLAG_ERROR_STOPS_FIFO | \
-        IDE_HFLAG_OFF_BOARD)
-
-static const struct ide_port_ops pdc20246_port_ops = {
-       .set_pio_mode           = pdc202xx_set_pio_mode,
-       .set_dma_mode           = pdc202xx_set_mode,
-       .test_irq               = pdc202xx_test_irq,
-};
-
-static const struct ide_port_ops pdc2026x_port_ops = {
-       .set_pio_mode           = pdc202xx_set_pio_mode,
-       .set_dma_mode           = pdc202xx_set_mode,
-       .test_irq               = pdc202xx_test_irq,
-       .cable_detect           = pdc2026x_cable_detect,
-};
-
-static const struct ide_dma_ops pdc2026x_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = pdc202xx_dma_start,
-       .dma_end                = pdc202xx_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-#define DECLARE_PDC2026X_DEV(udma, sectors) \
-       { \
-               .name           = DRV_NAME, \
-               .init_chipset   = init_chipset_pdc202xx, \
-               .init_hwif      = pdc2026x_init_hwif, \
-               .port_ops       = &pdc2026x_port_ops, \
-               .dma_ops        = &pdc2026x_dma_ops, \
-               .host_flags     = IDE_HFLAGS_PDC202XX, \
-               .pio_mask       = ATA_PIO4, \
-               .mwdma_mask     = ATA_MWDMA2, \
-               .udma_mask      = udma, \
-               .max_sectors    = sectors, \
-       }
-
-static const struct ide_port_info pdc202xx_chipsets[] = {
-       {       /* 0: PDC20246 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_pdc202xx,
-               .port_ops       = &pdc20246_port_ops,
-               .dma_ops        = &sff_dma_ops,
-               .host_flags     = IDE_HFLAGS_PDC202XX,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA2,
-       },
-
-       /* 1: PDC2026{2,3} */
-       DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
-       /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */
-       DECLARE_PDC2026X_DEV(ATA_UDMA5, 256),
-};
-
-/**
- *     pdc202xx_init_one       -       called when a PDC202xx is found
- *     @dev: the pdc202xx device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-static int pdc202xx_init_one(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       const struct ide_port_info *d;
-       u8 idx = id->driver_data;
-
-       d = &pdc202xx_chipsets[idx];
-
-       if (idx < 2)
-               pdc202ata4_fixup_irq(dev, d->name);
-
-       if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) {
-               struct pci_dev *bridge = dev->bus->self;
-
-               if (bridge &&
-                   bridge->vendor == PCI_VENDOR_ID_INTEL &&
-                   (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
-                    bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
-                       printk(KERN_INFO DRV_NAME " %s: skipping Promise "
-                               "PDC20265 attached to I2O RAID controller\n",
-                               pci_name(dev));
-                       return -ENODEV;
-               }
-       }
-
-       return ide_pci_init_one(dev, d, NULL);
-}
-
-static const struct pci_device_id pdc202xx_pci_tbl[] = {
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
-       { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
-
-static struct pci_driver pdc202xx_pci_driver = {
-       .name           = "Promise_Old_IDE",
-       .id_table       = pdc202xx_pci_tbl,
-       .probe          = pdc202xx_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init pdc202xx_ide_init(void)
-{
-       return ide_pci_register_driver(&pdc202xx_pci_driver);
-}
-
-static void __exit pdc202xx_ide_exit(void)
-{
-       pci_unregister_driver(&pdc202xx_pci_driver);
-}
-
-module_init(pdc202xx_ide_init);
-module_exit(pdc202xx_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
deleted file mode 100644 (file)
index a671cea..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2003 Red Hat
- *  Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *
- * Documentation:
- *
- *     Publicly available from Intel web site. Errata documentation
- * is also publicly available. As an aide to anyone hacking on this
- * driver the list of errata that are relevant is below.going back to
- * PIIX4. Older device documentation is now a bit tricky to find.
- *
- * Errata of note:
- *
- * Unfixable
- *     PIIX4    errata #9      - Only on ultra obscure hw
- *     ICH3     errata #13     - Not observed to affect real hw
- *                               by Intel
- *
- * Things we must deal with
- *     PIIX4   errata #10      - BM IDE hang with non UDMA
- *                               (must stop/start dma to recover)
- *     440MX   errata #15      - As PIIX4 errata #10
- *     PIIX4   errata #15      - Must not read control registers
- *                               during a PIO transfer
- *     440MX   errata #13      - As PIIX4 errata #15
- *     ICH2    errata #21      - DMA mode 0 doesn't work right
- *     ICH0/1  errata #55      - As ICH2 errata #21
- *     ICH2    spec c #9       - Extra operations needed to handle
- *                               drive hotswap [NOT YET SUPPORTED]
- *     ICH2    spec c #20      - IDE PRD must not cross a 64K boundary
- *                               and must be dword aligned
- *     ICH2    spec c #24      - UDMA mode 4,5 t85/86 should be 6ns not 3.3
- *
- * Should have been BIOS fixed:
- *     450NX:  errata #19      - DMA hangs on old 450NX
- *     450NX:  errata #20      - DMA hangs on old 450NX
- *     450NX:  errata #25      - Corruption with DMA on old 450NX
- *     ICH3    errata #15      - IDE deadlock under high load
- *                               (BIOS must set dev 31 fn 0 bit 23)
- *     ICH3    errata #18      - Don't use native mode
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "piix"
-
-static int no_piix_dma;
-
-/**
- *     piix_set_pio_mode       -       set host controller for PIO mode
- *     @port: port
- *     @drive: drive
- *
- *     Set the interface PIO mode based upon the settings done by AMI BIOS.
- */
-
-static void piix_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int is_slave            = drive->dn & 1;
-       int master_port         = hwif->channel ? 0x42 : 0x40;
-       int slave_port          = 0x44;
-       unsigned long flags;
-       u16 master_data;
-       u8 slave_data;
-       static DEFINE_SPINLOCK(tune_lock);
-       int control = 0;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-                                    /* ISP  RTC */
-       static const u8 timings[][2]= {
-                                       { 0, 0 },
-                                       { 0, 0 },
-                                       { 1, 0 },
-                                       { 2, 1 },
-                                       { 2, 3 }, };
-
-       /*
-        * Master vs slave is synchronized above us but the slave register is
-        * shared by the two hwifs so the corner case of two slave timeouts in
-        * parallel must be locked.
-        */
-       spin_lock_irqsave(&tune_lock, flags);
-       pci_read_config_word(dev, master_port, &master_data);
-
-       if (pio > 1)
-               control |= 1;   /* Programmable timing on */
-       if (drive->media == ide_disk)
-               control |= 4;   /* Prefetch, post write */
-       if (ide_pio_need_iordy(drive, pio))
-               control |= 2;   /* IORDY */
-       if (is_slave) {
-               master_data |=  0x4000;
-               master_data &= ~0x0070;
-               if (pio > 1) {
-                       /* Set PPE, IE and TIME */
-                       master_data |= control << 4;
-               }
-               pci_read_config_byte(dev, slave_port, &slave_data);
-               slave_data &= hwif->channel ? 0x0f : 0xf0;
-               slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
-                              (hwif->channel ? 4 : 0);
-       } else {
-               master_data &= ~0x3307;
-               if (pio > 1) {
-                       /* enable PPE, IE and TIME */
-                       master_data |= control;
-               }
-               master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
-       }
-       pci_write_config_word(dev, master_port, master_data);
-       if (is_slave)
-               pci_write_config_byte(dev, slave_port, slave_data);
-       spin_unlock_irqrestore(&tune_lock, flags);
-}
-
-/**
- *     piix_set_dma_mode       -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Set a PIIX host controller to the desired DMA mode.  This involves
- *     programming the right timing data into the PCI configuration space.
- */
-
-static void piix_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 maslave              = hwif->channel ? 0x42 : 0x40;
-       int a_speed             = 3 << (drive->dn * 4);
-       int u_flag              = 1 << drive->dn;
-       int v_flag              = 0x01 << drive->dn;
-       int w_flag              = 0x10 << drive->dn;
-       int u_speed             = 0;
-       int                     sitre;
-       u16                     reg4042, reg4a;
-       u8                      reg48, reg54, reg55;
-       const u8 speed          = drive->dma_mode;
-
-       pci_read_config_word(dev, maslave, &reg4042);
-       sitre = (reg4042 & 0x4000) ? 1 : 0;
-       pci_read_config_byte(dev, 0x48, &reg48);
-       pci_read_config_word(dev, 0x4a, &reg4a);
-       pci_read_config_byte(dev, 0x54, &reg54);
-       pci_read_config_byte(dev, 0x55, &reg55);
-
-       if (speed >= XFER_UDMA_0) {
-               u8 udma = speed - XFER_UDMA_0;
-
-               u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-
-               if (!(reg48 & u_flag))
-                       pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-               if (speed == XFER_UDMA_5) {
-                       pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
-               } else {
-                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-               }
-               if ((reg4a & a_speed) != u_speed)
-                       pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
-               if (speed > XFER_UDMA_2) {
-                       if (!(reg54 & v_flag))
-                               pci_write_config_byte(dev, 0x54, reg54 | v_flag);
-               } else
-                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
-       } else {
-               const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
-               if (reg48 & u_flag)
-                       pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-               if (reg4a & a_speed)
-                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-               if (reg54 & v_flag)
-                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
-               if (reg55 & w_flag)
-                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
-               if (speed >= XFER_MW_DMA_0)
-                       drive->pio_mode =
-                               mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
-               else
-                       drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
-               piix_set_pio_mode(hwif, drive);
-       }
-}
-
-/**
- *     init_chipset_ich        -       set up the ICH chipset
- *     @dev: PCI device to set up
- *
- *     Initialize the PCI device as required.  For the ICH this turns
- *     out to be nice and simple.
- */
-
-static int init_chipset_ich(struct pci_dev *dev)
-{
-       u32 extra = 0;
-
-       pci_read_config_dword(dev, 0x54, &extra);
-       pci_write_config_dword(dev, 0x54, extra | 0x400);
-
-       return 0;
-}
-
-/**
- *     ich_clear_irq   -       clear BMDMA status
- *     @drive: IDE drive
- *
- *     ICHx contollers set DMA INTR no matter DMA or PIO.
- *     BMDMA status might need to be cleared even for
- *     PIO interrupts to prevent spurious/lost IRQ.
- */
-static void ich_clear_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat;
-
-       /*
-        * ide_dma_end() needs BMDMA status for error checking.
-        * So, skip clearing BMDMA status here and leave it
-        * to ide_dma_end() if this is DMA interrupt.
-        */
-       if (drive->waiting_for_dma || hwif->dma_base == 0)
-               return;
-
-       /* clear the INTR & ERROR bits */
-       dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-       /* Should we force the bit as well ? */
-       outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-struct ich_laptop {
-       u16 device;
-       u16 subvendor;
-       u16 subdevice;
-};
-
-/*
- *     List of laptops that use short cables rather than 80 wire
- */
-
-static const struct ich_laptop ich_laptop[] = {
-       /* devid, subvendor, subdev */
-       { 0x27DF, 0x1025, 0x0102 },     /* ICH7 on Acer 5602aWLMi */
-       { 0x27DF, 0x0005, 0x0280 },     /* ICH7 on Acer 5602WLMi */
-       { 0x27DF, 0x1025, 0x0110 },     /* ICH7 on Acer 3682WLMi */
-       { 0x27DF, 0x1043, 0x1267 },     /* ICH7 on Asus W5F */
-       { 0x27DF, 0x103C, 0x30A1 },     /* ICH7 on HP Compaq nc2400 */
-       { 0x27DF, 0x1071, 0xD221 },     /* ICH7 on Hercules EC-900 */
-       { 0x24CA, 0x1025, 0x0061 },     /* ICH4 on Acer Aspire 2023WLMi */
-       { 0x24CA, 0x1025, 0x003d },     /* ICH4 on ACER TM290 */
-       { 0x266F, 0x1025, 0x0066 },     /* ICH6 on ACER Aspire 1694WLMi */
-       { 0x2653, 0x1043, 0x82D8 },     /* ICH6M on Asus Eee 701 */
-       { 0x27df, 0x104d, 0x900e },     /* ICH7 on Sony TZ-90 */
-       /* end marker */
-       { 0, }
-};
-
-static u8 piix_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       const struct ich_laptop *lap = &ich_laptop[0];
-       u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
-
-       /* check for specials */
-       while (lap->device) {
-               if (lap->device == pdev->device &&
-                   lap->subvendor == pdev->subsystem_vendor &&
-                   lap->subdevice == pdev->subsystem_device) {
-                       return ATA_CBL_PATA40_SHORT;
-               }
-               lap++;
-       }
-
-       pci_read_config_byte(pdev, 0x54, &reg54h);
-
-       return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-/**
- *     init_hwif_piix          -       fill in the hwif for the PIIX
- *     @hwif: IDE interface
- *
- *     Set up the ide_hwif_t for the PIIX interface according to the
- *     capabilities of the hardware.
- */
-
-static void init_hwif_piix(ide_hwif_t *hwif)
-{
-       if (!hwif->dma_base)
-               return;
-
-       if (no_piix_dma)
-               hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
-}
-
-static const struct ide_port_ops piix_port_ops = {
-       .set_pio_mode           = piix_set_pio_mode,
-       .set_dma_mode           = piix_set_dma_mode,
-       .cable_detect           = piix_cable_detect,
-};
-
-static const struct ide_port_ops ich_port_ops = {
-       .set_pio_mode           = piix_set_pio_mode,
-       .set_dma_mode           = piix_set_dma_mode,
-       .clear_irq              = ich_clear_irq,
-       .cable_detect           = piix_cable_detect,
-};
-
-#define DECLARE_PIIX_DEV(udma) \
-       {                                               \
-               .name           = DRV_NAME,             \
-               .init_hwif      = init_hwif_piix,       \
-               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
-               .port_ops       = &piix_port_ops,       \
-               .pio_mask       = ATA_PIO4,             \
-               .swdma_mask     = ATA_SWDMA2_ONLY,      \
-               .mwdma_mask     = ATA_MWDMA12_ONLY,     \
-               .udma_mask      = udma,                 \
-       }
-
-#define DECLARE_ICH_DEV(mwdma, udma) \
-       { \
-               .name           = DRV_NAME, \
-               .init_chipset   = init_chipset_ich, \
-               .init_hwif      = init_hwif_piix, \
-               .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
-               .port_ops       = &ich_port_ops, \
-               .pio_mask       = ATA_PIO4, \
-               .swdma_mask     = ATA_SWDMA2_ONLY, \
-               .mwdma_mask     = mwdma, \
-               .udma_mask      = udma, \
-       }
-
-static const struct ide_port_info piix_pci_info[] = {
-       /* 0: MPIIX */
-       {       /*
-                * MPIIX actually has only a single IDE channel mapped to
-                * the primary or secondary ports depending on the value
-                * of the bit 14 of the IDETIM register at offset 0x6c
-                */
-               .name           = DRV_NAME,
-               .enablebits     = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
-               .host_flags     = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA,
-               .pio_mask       = ATA_PIO4,
-               /* This is a painful system best to let it self tune for now */
-       },
-       /* 1: PIIXa/PIIXb/PIIX3 */
-       DECLARE_PIIX_DEV(0x00), /* no udma */
-       /* 2: PIIX4 */
-       DECLARE_PIIX_DEV(ATA_UDMA2),
-       /* 3: ICH0 */
-       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2),
-       /* 4: ICH */
-       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4),
-       /* 5: PIIX4 */
-       DECLARE_PIIX_DEV(ATA_UDMA4),
-       /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
-       DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5),
-       /* 7: ICH7/7-R, no MWDMA1 */
-       DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5),
-};
-
-/**
- *     piix_init_one   -       called when a PIIX is found
- *     @dev: the piix device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-static int piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL);
-}
-
-/**
- *     piix_check_450nx        -       Check for problem 450NX setup
- *     
- *     Check for the present of 450NX errata #19 and errata #25. If
- *     they are found, disable use of DMA IDE
- */
-
-static void piix_check_450nx(void)
-{
-       struct pci_dev *pdev = NULL;
-       u16 cfg;
-       while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
-       {
-               /* Look for 450NX PXB. Check for problem configurations
-                  A PCI quirk checks bit 6 already */
-               pci_read_config_word(pdev, 0x41, &cfg);
-               /* Only on the original revision: IDE DMA can hang */
-               if (pdev->revision == 0x00)
-                       no_piix_dma = 1;
-               /* On all revisions below 5 PXB bus lock must be disabled for IDE */
-               else if (cfg & (1<<14) && pdev->revision < 5)
-                       no_piix_dma = 2;
-       }
-       if(no_piix_dma)
-               printk(KERN_WARNING DRV_NAME ": 450NX errata present, disabling IDE DMA.\n");
-       if(no_piix_dma == 2)
-               printk(KERN_WARNING DRV_NAME ": A BIOS update may resolve this.\n");
-}              
-
-static const struct pci_device_id piix_pci_tbl[] = {
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0),  1 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1),  1 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX),    0 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1),  1 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB),    2 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1),  3 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1),  2 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1),  4 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1),  5 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX),    2 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9),  6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8),  6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11),  6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1),  6 },
-#endif
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2),      6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19),    6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21),    7 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1),  6 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18),    7 },
-       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6),     6 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
-
-static struct pci_driver piix_pci_driver = {
-       .name           = "PIIX_IDE",
-       .id_table       = piix_pci_tbl,
-       .probe          = piix_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init piix_ide_init(void)
-{
-       piix_check_450nx();
-       return ide_pci_register_driver(&piix_pci_driver);
-}
-
-static void __exit piix_ide_exit(void)
-{
-       pci_unregister_driver(&piix_pci_driver);
-}
-
-module_init(piix_ide_init);
-module_exit(piix_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
-MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
deleted file mode 100644 (file)
index ea0b064..0000000
+++ /dev/null
@@ -1,1703 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Support for IDE interfaces on PowerMacs.
- *
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- *  Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
- *  Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *
- * TODO: - Use pre-calculated (kauai) timing tables all the time and
- * get rid of the "rounded" tables used previously, so we have the
- * same table format for all controllers and can then just have one
- * big table
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#include <asm/mediabay.h>
-
-#define DRV_NAME "ide-pmac"
-
-#undef IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT       50
-
-typedef struct pmac_ide_hwif {
-       unsigned long                   regbase;
-       int                             irq;
-       int                             kind;
-       int                             aapl_bus_id;
-       unsigned                        broken_dma : 1;
-       unsigned                        broken_dma_warn : 1;
-       struct device_node*             node;
-       struct macio_dev                *mdev;
-       u32                             timings[4];
-       volatile u32 __iomem *          *kauai_fcr;
-       ide_hwif_t                      *hwif;
-
-       /* Those fields are duplicating what is in hwif. We currently
-        * can't use the hwif ones because of some assumptions that are
-        * beeing done by the generic code about the kind of dma controller
-        * and format of the dma table. This will have to be fixed though.
-        */
-       volatile struct dbdma_regs __iomem *    dma_regs;
-       struct dbdma_cmd*               dma_table_cpu;
-} pmac_ide_hwif_t;
-
-enum {
-       controller_ohare,       /* OHare based */
-       controller_heathrow,    /* Heathrow/Paddington */
-       controller_kl_ata3,     /* KeyLargo ATA-3 */
-       controller_kl_ata4,     /* KeyLargo ATA-4 */
-       controller_un_ata6,     /* UniNorth2 ATA-6 */
-       controller_k2_ata6,     /* K2 ATA-6 */
-       controller_sh_ata6,     /* Shasta ATA-6 */
-};
-
-static const char* model_name[] = {
-       "OHare ATA",            /* OHare based */
-       "Heathrow ATA",         /* Heathrow/Paddington */
-       "KeyLargo ATA-3",       /* KeyLargo ATA-3 (MDMA only) */
-       "KeyLargo ATA-4",       /* KeyLargo ATA-4 (UDMA/66) */
-       "UniNorth ATA-6",       /* UniNorth2 ATA-6 (UDMA/100) */
-       "K2 ATA-6",             /* K2 ATA-6 (UDMA/100) */
-       "Shasta ATA-6",         /* Shasta ATA-6 (UDMA/133) */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG      0x200
-#define IDE_INTERRUPT          0x300
-
-/* Kauai (U2) ATA has different register setup */
-#define IDE_KAUAI_PIO_CONFIG   0x200
-#define IDE_KAUAI_ULTRA_CONFIG 0x210
-#define IDE_KAUAI_POLL_CONFIG  0x220
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)                (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t)     (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS          30      /* 33Mhz cell */
-#define IDE_SYSCLK_66_NS       15      /* 66Mhz cell */
-
-/* 133Mhz cell, found in shasta.
- * See comments about 100 Mhz Uninorth 2...
- * Note that PIO_MASK and MDMA_MASK seem to overlap
- */
-#define TR_133_PIOREG_PIO_MASK         0xff000fff
-#define TR_133_PIOREG_MDMA_MASK                0x00fff800
-#define TR_133_UDMAREG_UDMA_MASK       0x0003ffff
-#define TR_133_UDMAREG_UDMA_EN         0x00000001
-
-/* 100Mhz cell, found in Uninorth 2. I don't have much infos about
- * this one yet, it appears as a pci device (106b/0033) on uninorth
- * internal PCI bus and it's clock is controlled like gem or fw. It
- * appears to be an evolution of keylargo ATA4 with a timing register
- * extended to 2 32bits registers and a similar DBDMA channel. Other
- * registers seem to exist but I can't tell much about them.
- * 
- * So far, I'm using pre-calculated tables for this extracted from
- * the values used by the MacOS X driver.
- * 
- * The "PIO" register controls PIO and MDMA timings, the "ULTRA"
- * register controls the UDMA timings. At least, it seems bit 0
- * of this one enables UDMA vs. MDMA, and bits 4..7 are the
- * cycle time in units of 10ns. Bits 8..15 are used by I don't
- * know their meaning yet
- */
-#define TR_100_PIOREG_PIO_MASK         0xff000fff
-#define TR_100_PIOREG_MDMA_MASK                0x00fff000
-#define TR_100_UDMAREG_UDMA_MASK       0x0000ffff
-#define TR_100_UDMAREG_UDMA_EN         0x00000001
-
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- * 
- * 3 Values can be programmed:
- *  - Write data setup, which appears to match the cycle time. They
- *    also call it DIOW setup.
- *  - Ready to pause time (from spec)
- *  - Address setup. That one is weird. I don't see where exactly
- *    it fits in UDMA cycles, I got it's name from an obscure piece
- *    of commented out code in Darwin. They leave it to 0, we do as
- *    well, despite a comment that would lead to think it has a
- *    min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads.
- */
-#define TR_66_UDMA_MASK                        0xfff00000
-#define TR_66_UDMA_EN                  0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK      0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT     29
-#define TR_66_UDMA_RDY2PAUS_MASK       0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT      25
-#define TR_66_UDMA_WRDATASETUP_MASK    0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT   21
-#define TR_66_MDMA_MASK                        0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK       0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT      15
-#define TR_66_MDMA_ACCESS_MASK         0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT                10
-#define TR_66_PIO_MASK                 0x000003ff
-#define TR_66_PIO_RECOVERY_MASK                0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT       5
-#define TR_66_PIO_ACCESS_MASK          0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT         0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- * 
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK                        0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK       0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT      16
-#define TR_33_MDMA_ACCESS_MASK         0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT                11
-#define TR_33_MDMA_HALFTICK            0x00200000
-#define TR_33_PIO_MASK                 0x000007ff
-#define TR_33_PIO_E                    0x00000400
-#define TR_33_PIO_RECOVERY_MASK                0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT       5
-#define TR_33_PIO_ACCESS_MASK          0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT         0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA                   0x80000000
-#define IDE_INTR_DEVICE                        0x40000000
-
-/*
- * FCR Register on Kauai. Not sure what bit 0x4 is  ...
- */
-#define KAUAI_FCR_UATA_MAGIC           0x00000004
-#define KAUAI_FCR_UATA_RESET_N         0x00000002
-#define KAUAI_FCR_UATA_ENABLE          0x00000001
-
-/* Rounded Multiword DMA timings
- * 
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
-       int     accessTime;
-       int     recoveryTime;
-       int     cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  75,  75, 150 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 150, 150, 300 },
-    { 120, 120, 240 },
-    {  90, 120, 210 },
-    {  90,  90, 180 },
-    {  90,  60, 150 },
-    {  90,  30, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  90,  75, 165 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-/* KeyLargo ATA-4 Ultra DMA timings (rounded) */
-struct {
-       int     addrSetup; /* ??? */
-       int     rdy2pause;
-       int     wrDataSetup;
-} kl66_udma_timings[] =
-{
-    {   0, 180,  120 },        /* Mode 0 */
-    {   0, 150,  90 }, /*      1 */
-    {   0, 120,  60 }, /*      2 */
-    {   0, 90,   45 }, /*      3 */
-    {   0, 90,   30 }  /*      4 */
-};
-
-/* UniNorth 2 ATA/100 timings */
-struct kauai_timing {
-       int     cycle_time;
-       u32     timing_reg;
-};
-
-static struct kauai_timing     kauai_pio_timings[] =
-{
-       { 930   , 0x08000fff },
-       { 600   , 0x08000a92 },
-       { 383   , 0x0800060f },
-       { 360   , 0x08000492 },
-       { 330   , 0x0800048f },
-       { 300   , 0x080003cf },
-       { 270   , 0x080003cc },
-       { 240   , 0x0800038b },
-       { 239   , 0x0800030c },
-       { 180   , 0x05000249 },
-       { 120   , 0x04000148 },
-       { 0     , 0 },
-};
-
-static struct kauai_timing     kauai_mdma_timings[] =
-{
-       { 1260  , 0x00fff000 },
-       { 480   , 0x00618000 },
-       { 360   , 0x00492000 },
-       { 270   , 0x0038e000 },
-       { 240   , 0x0030c000 },
-       { 210   , 0x002cb000 },
-       { 180   , 0x00249000 },
-       { 150   , 0x00209000 },
-       { 120   , 0x00148000 },
-       { 0     , 0 },
-};
-
-static struct kauai_timing     kauai_udma_timings[] =
-{
-       { 120   , 0x000070c0 },
-       { 90    , 0x00005d80 },
-       { 60    , 0x00004a60 },
-       { 45    , 0x00003a50 },
-       { 30    , 0x00002a30 },
-       { 20    , 0x00002921 },
-       { 0     , 0 },
-};
-
-static struct kauai_timing     shasta_pio_timings[] =
-{
-       { 930   , 0x08000fff },
-       { 600   , 0x0A000c97 },
-       { 383   , 0x07000712 },
-       { 360   , 0x040003cd },
-       { 330   , 0x040003cd },
-       { 300   , 0x040003cd },
-       { 270   , 0x040003cd },
-       { 240   , 0x040003cd },
-       { 239   , 0x040003cd },
-       { 180   , 0x0400028b },
-       { 120   , 0x0400010a },
-       { 0     , 0 },
-};
-
-static struct kauai_timing     shasta_mdma_timings[] =
-{
-       { 1260  , 0x00fff000 },
-       { 480   , 0x00820800 },
-       { 360   , 0x00820800 },
-       { 270   , 0x00820800 },
-       { 240   , 0x00820800 },
-       { 210   , 0x00820800 },
-       { 180   , 0x00820800 },
-       { 150   , 0x0028b000 },
-       { 120   , 0x001ca000 },
-       { 0     , 0 },
-};
-
-static struct kauai_timing     shasta_udma133_timings[] =
-{
-       { 120   , 0x00035901, },
-       { 90    , 0x000348b1, },
-       { 60    , 0x00033881, },
-       { 45    , 0x00033861, },
-       { 30    , 0x00033841, },
-       { 20    , 0x00033031, },
-       { 15    , 0x00033021, },
-       { 0     , 0 },
-};
-
-
-static inline u32
-kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
-{
-       int i;
-       
-       for (i=0; table[i].cycle_time; i++)
-               if (cycle_time > table[i+1].cycle_time)
-                       return table[i].timing_reg;
-       BUG();
-       return 0;
-}
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS              256
-
-/* 
- * Wait 1s for disk to answer on IDE bus after a hard reset
- * of the device (via GPIO/FCR).
- * 
- * Some devices seem to "pollute" the bus even after dropping
- * the BSY bit (typically some combo drives slave on the UDMA
- * bus) after a hard reset. Since we hard reset all drives on
- * KeyLargo ATA66, we have to keep that delay around. I may end
- * up not hard resetting anymore on these and keep the delay only
- * for older interfaces instead (we have to reset when coming
- * from MacOS...) --BenH. 
- */
-#define IDE_WAKEUP_DELAY       (1*HZ)
-
-static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
-
-#define PMAC_IDE_REG(x) \
-       ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
-
-/*
- * Apply the timings of the proper unit (master/slave) to the shared
- * timing register when selecting that unit. This version is for
- * ASICs with a single timing register
- */
-static void pmac_ide_apply_timings(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
-       if (drive->dn & 1)
-               writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG));
-       else
-               writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG));
-       (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
-}
-
-/*
- * Apply the timings of the proper unit (master/slave) to the shared
- * timing register when selecting that unit. This version is for
- * ASICs with a dual timing register (Kauai)
- */
-static void pmac_ide_kauai_apply_timings(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
-       if (drive->dn & 1) {
-               writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
-               writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
-       } else {
-               writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
-               writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
-       }
-       (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
-}
-
-/*
- * Force an update of controller timing values for a given drive
- */
-static void
-pmac_ide_do_update_timings(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
-       if (pmif->kind == controller_sh_ata6 ||
-           pmif->kind == controller_un_ata6 ||
-           pmif->kind == controller_k2_ata6)
-               pmac_ide_kauai_apply_timings(drive);
-       else
-               pmac_ide_apply_timings(drive);
-}
-
-static void pmac_dev_select(ide_drive_t *drive)
-{
-       pmac_ide_apply_timings(drive);
-
-       writeb(drive->select | ATA_DEVICE_OBS,
-              (void __iomem *)drive->hwif->io_ports.device_addr);
-}
-
-static void pmac_kauai_dev_select(ide_drive_t *drive)
-{
-       pmac_ide_kauai_apply_timings(drive);
-
-       writeb(drive->select | ATA_DEVICE_OBS,
-              (void __iomem *)drive->hwif->io_ports.device_addr);
-}
-
-static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
-       writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
-       (void)readl((void __iomem *)(hwif->io_ports.data_addr
-                                    + IDE_TIMING_CONFIG));
-}
-
-static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
-{
-       writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
-       (void)readl((void __iomem *)(hwif->io_ports.data_addr
-                                    + IDE_TIMING_CONFIG));
-}
-
-/*
- * Old tuning functions (called on hdparm -p), sets up drive PIO timings
- */
-static void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio);
-       u32 *timings, t;
-       unsigned accessTicks, recTicks;
-       unsigned accessTime, recTime;
-       unsigned int cycle_time;
-
-       /* which drive is it ? */
-       timings = &pmif->timings[drive->dn & 1];
-       t = *timings;
-
-       cycle_time = ide_pio_cycle_time(drive, pio);
-
-       switch (pmif->kind) {
-       case controller_sh_ata6: {
-               /* 133Mhz cell */
-               u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
-               t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
-               break;
-               }
-       case controller_un_ata6:
-       case controller_k2_ata6: {
-               /* 100Mhz cell */
-               u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
-               t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
-               break;
-               }
-       case controller_kl_ata4:
-               /* 66Mhz cell */
-               recTime = cycle_time - tim->active - tim->setup;
-               recTime = max(recTime, 150U);
-               accessTime = tim->active;
-               accessTime = max(accessTime, 150U);
-               accessTicks = SYSCLK_TICKS_66(accessTime);
-               accessTicks = min(accessTicks, 0x1fU);
-               recTicks = SYSCLK_TICKS_66(recTime);
-               recTicks = min(recTicks, 0x1fU);
-               t = (t & ~TR_66_PIO_MASK) |
-                       (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-                       (recTicks << TR_66_PIO_RECOVERY_SHIFT);
-               break;
-       default: {
-               /* 33Mhz cell */
-               int ebit = 0;
-               recTime = cycle_time - tim->active - tim->setup;
-               recTime = max(recTime, 150U);
-               accessTime = tim->active;
-               accessTime = max(accessTime, 150U);
-               accessTicks = SYSCLK_TICKS(accessTime);
-               accessTicks = min(accessTicks, 0x1fU);
-               accessTicks = max(accessTicks, 4U);
-               recTicks = SYSCLK_TICKS(recTime);
-               recTicks = min(recTicks, 0x1fU);
-               recTicks = max(recTicks, 5U) - 4;
-               if (recTicks > 9) {
-                       recTicks--; /* guess, but it's only for PIO0, so... */
-                       ebit = 1;
-               }
-               t = (t & ~TR_33_PIO_MASK) |
-                               (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
-                               (recTicks << TR_33_PIO_RECOVERY_SHIFT);
-               if (ebit)
-                       t |= TR_33_PIO_E;
-               break;
-               }
-       }
-
-#ifdef IDE_PMAC_DEBUG
-       printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n",
-               drive->name, pio,  *timings);
-#endif 
-
-       *timings = t;
-       pmac_ide_do_update_timings(drive);
-}
-
-/*
- * Calculate KeyLargo ATA/66 UDMA timings
- */
-static int
-set_timings_udma_ata4(u32 *timings, u8 speed)
-{
-       unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
-       if (speed > XFER_UDMA_4)
-               return 1;
-
-       rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause);
-       wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup);
-       addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup);
-
-       *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-                       (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
-                       (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
-                       (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
-                       TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
-       printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
-               speed & 0xf,  *timings);
-#endif 
-
-       return 0;
-}
-
-/*
- * Calculate Kauai ATA/100 UDMA timings
- */
-static int
-set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
-{
-       struct ide_timing *t = ide_timing_find_mode(speed);
-       u32 tr;
-
-       if (speed > XFER_UDMA_5 || t == NULL)
-               return 1;
-       tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
-       *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
-       *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
-
-       return 0;
-}
-
-/*
- * Calculate Shasta ATA/133 UDMA timings
- */
-static int
-set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
-{
-       struct ide_timing *t = ide_timing_find_mode(speed);
-       u32 tr;
-
-       if (speed > XFER_UDMA_6 || t == NULL)
-               return 1;
-       tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
-       *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
-       *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
-
-       return 0;
-}
-
-/*
- * Calculate MDMA timings for all cells
- */
-static void
-set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
-                       u8 speed)
-{
-       u16 *id = drive->id;
-       int cycleTime, accessTime = 0, recTime = 0;
-       unsigned accessTicks, recTicks;
-       struct mdma_timings_t* tm = NULL;
-       int i;
-
-       /* Get default cycle time for mode */
-       switch(speed & 0xf) {
-               case 0: cycleTime = 480; break;
-               case 1: cycleTime = 150; break;
-               case 2: cycleTime = 120; break;
-               default:
-                       BUG();
-                       break;
-       }
-
-       /* Check if drive provides explicit DMA cycle time */
-       if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME])
-               cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime);
-
-       /* OHare limits according to some old Apple sources */  
-       if ((intf_type == controller_ohare) && (cycleTime < 150))
-               cycleTime = 150;
-       /* Get the proper timing array for this controller */
-       switch(intf_type) {
-               case controller_sh_ata6:
-               case controller_un_ata6:
-               case controller_k2_ata6:
-                       break;
-               case controller_kl_ata4:
-                       tm = mdma_timings_66;
-                       break;
-               case controller_kl_ata3:
-                       tm = mdma_timings_33k;
-                       break;
-               default:
-                       tm = mdma_timings_33;
-                       break;
-       }
-       if (tm != NULL) {
-               /* Lookup matching access & recovery times */
-               i = -1;
-               for (;;) {
-                       if (tm[i+1].cycleTime < cycleTime)
-                               break;
-                       i++;
-               }
-               cycleTime = tm[i].cycleTime;
-               accessTime = tm[i].accessTime;
-               recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
-               printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
-                       drive->name, cycleTime, accessTime, recTime);
-#endif
-       }
-       switch(intf_type) {
-       case controller_sh_ata6: {
-               /* 133Mhz cell */
-               u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
-               *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
-               *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
-               }
-               break;
-       case controller_un_ata6:
-       case controller_k2_ata6: {
-               /* 100Mhz cell */
-               u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
-               *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
-               *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
-               }
-               break;
-       case controller_kl_ata4:
-               /* 66Mhz cell */
-               accessTicks = SYSCLK_TICKS_66(accessTime);
-               accessTicks = min(accessTicks, 0x1fU);
-               accessTicks = max(accessTicks, 0x1U);
-               recTicks = SYSCLK_TICKS_66(recTime);
-               recTicks = min(recTicks, 0x1fU);
-               recTicks = max(recTicks, 0x3U);
-               /* Clear out mdma bits and disable udma */
-               *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
-                       (accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
-                       (recTicks << TR_66_MDMA_RECOVERY_SHIFT);
-               break;
-       case controller_kl_ata3:
-               /* 33Mhz cell on KeyLargo */
-               accessTicks = SYSCLK_TICKS(accessTime);
-               accessTicks = max(accessTicks, 1U);
-               accessTicks = min(accessTicks, 0x1fU);
-               accessTime = accessTicks * IDE_SYSCLK_NS;
-               recTicks = SYSCLK_TICKS(recTime);
-               recTicks = max(recTicks, 1U);
-               recTicks = min(recTicks, 0x1fU);
-               *timings = ((*timings) & ~TR_33_MDMA_MASK) |
-                               (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-                               (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-               break;
-       default: {
-               /* 33Mhz cell on others */
-               int halfTick = 0;
-               int origAccessTime = accessTime;
-               int origRecTime = recTime;
-               
-               accessTicks = SYSCLK_TICKS(accessTime);
-               accessTicks = max(accessTicks, 1U);
-               accessTicks = min(accessTicks, 0x1fU);
-               accessTime = accessTicks * IDE_SYSCLK_NS;
-               recTicks = SYSCLK_TICKS(recTime);
-               recTicks = max(recTicks, 2U) - 1;
-               recTicks = min(recTicks, 0x1fU);
-               recTime = (recTicks + 1) * IDE_SYSCLK_NS;
-               if ((accessTicks > 1) &&
-                   ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-                   ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-                       halfTick = 1;
-                       accessTicks--;
-               }
-               *timings = ((*timings) & ~TR_33_MDMA_MASK) |
-                               (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-                               (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-               if (halfTick)
-                       *timings |= TR_33_MDMA_HALFTICK;
-               }
-       }
-#ifdef IDE_PMAC_DEBUG
-       printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
-               drive->name, speed & 0xf,  *timings);
-#endif 
-}
-
-static void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       int ret = 0;
-       u32 *timings, *timings2, tl[2];
-       u8 unit = drive->dn & 1;
-       const u8 speed = drive->dma_mode;
-
-       timings = &pmif->timings[unit];
-       timings2 = &pmif->timings[unit+2];
-
-       /* Copy timings to local image */
-       tl[0] = *timings;
-       tl[1] = *timings2;
-
-       if (speed >= XFER_UDMA_0) {
-               if (pmif->kind == controller_kl_ata4)
-                       ret = set_timings_udma_ata4(&tl[0], speed);
-               else if (pmif->kind == controller_un_ata6
-                        || pmif->kind == controller_k2_ata6)
-                       ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
-               else if (pmif->kind == controller_sh_ata6)
-                       ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
-               else
-                       ret = -1;
-       } else
-               set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
-
-       if (ret)
-               return;
-
-       /* Apply timings to controller */
-       *timings = tl[0];
-       *timings2 = tl[1];
-
-       pmac_ide_do_update_timings(drive);      
-}
-
-/*
- * Blast some well known "safe" values to the timing registers at init or
- * wakeup from sleep time, before we do real calculation
- */
-static void
-sanitize_timings(pmac_ide_hwif_t *pmif)
-{
-       unsigned int value, value2 = 0;
-       
-       switch(pmif->kind) {
-               case controller_sh_ata6:
-                       value = 0x0a820c97;
-                       value2 = 0x00033031;
-                       break;
-               case controller_un_ata6:
-               case controller_k2_ata6:
-                       value = 0x08618a92;
-                       value2 = 0x00002921;
-                       break;
-               case controller_kl_ata4:
-                       value = 0x0008438c;
-                       break;
-               case controller_kl_ata3:
-                       value = 0x00084526;
-                       break;
-               case controller_heathrow:
-               case controller_ohare:
-               default:
-                       value = 0x00074526;
-                       break;
-       }
-       pmif->timings[0] = pmif->timings[1] = value;
-       pmif->timings[2] = pmif->timings[3] = value2;
-}
-
-static int on_media_bay(pmac_ide_hwif_t *pmif)
-{
-       return pmif->mdev && pmif->mdev->media_bay != NULL;
-}
-
-/* Suspend call back, should be called after the child devices
- * have actually been suspended
- */
-static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
-{
-       /* We clear the timings */
-       pmif->timings[0] = 0;
-       pmif->timings[1] = 0;
-       
-       disable_irq(pmif->irq);
-
-       /* The media bay will handle itself just fine */
-       if (on_media_bay(pmif))
-               return 0;
-       
-       /* Kauai has bus control FCRs directly here */
-       if (pmif->kauai_fcr) {
-               u32 fcr = readl(pmif->kauai_fcr);
-               fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
-               writel(fcr, pmif->kauai_fcr);
-       }
-
-       /* Disable the bus on older machines and the cell on kauai */
-       ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id,
-                           0);
-
-       return 0;
-}
-
-/* Resume call back, should be called before the child devices
- * are resumed
- */
-static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif)
-{
-       /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */
-       if (!on_media_bay(pmif)) {
-               ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
-               ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
-               msleep(10);
-               ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
-
-               /* Kauai has it different */
-               if (pmif->kauai_fcr) {
-                       u32 fcr = readl(pmif->kauai_fcr);
-                       fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE;
-                       writel(fcr, pmif->kauai_fcr);
-               }
-
-               msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
-       }
-
-       /* Sanitize drive timings */
-       sanitize_timings(pmif);
-
-       enable_irq(pmif->irq);
-
-       return 0;
-}
-
-static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       struct device_node *np = pmif->node;
-       const char *cable = of_get_property(np, "cable-type", NULL);
-       struct device_node *root = of_find_node_by_path("/");
-       const char *model = of_get_property(root, "model", NULL);
-
-       of_node_put(root);
-       /* Get cable type from device-tree. */
-       if (cable && !strncmp(cable, "80-", 3)) {
-               /* Some drives fail to detect 80c cable in PowerBook */
-               /* These machine use proprietary short IDE cable anyway */
-               if (!strncmp(model, "PowerBook", 9))
-                       return ATA_CBL_PATA40_SHORT;
-               else
-                       return ATA_CBL_PATA80;
-       }
-
-       /*
-        * G5's seem to have incorrect cable type in device-tree.
-        * Let's assume they have a 80 conductor cable, this seem
-        * to be always the case unless the user mucked around.
-        */
-       if (of_device_is_compatible(np, "K2-UATA") ||
-           of_device_is_compatible(np, "shasta-ata"))
-               return ATA_CBL_PATA80;
-
-       return ATA_CBL_PATA40;
-}
-
-static void pmac_ide_init_dev(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
-       if (on_media_bay(pmif)) {
-               if (check_media_bay(pmif->mdev->media_bay) == MB_CD) {
-                       drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
-                       return;
-               }
-               drive->dev_flags |= IDE_DFLAG_NOPROBE;
-       }
-}
-
-static const struct ide_tp_ops pmac_tp_ops = {
-       .exec_command           = pmac_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = pmac_write_devctl,
-
-       .dev_select             = pmac_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_tp_ops pmac_ata6_tp_ops = {
-       .exec_command           = pmac_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = pmac_write_devctl,
-
-       .dev_select             = pmac_kauai_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 pmac_ide_ata4_port_ops = {
-       .init_dev               = pmac_ide_init_dev,
-       .set_pio_mode           = pmac_ide_set_pio_mode,
-       .set_dma_mode           = pmac_ide_set_dma_mode,
-       .cable_detect           = pmac_ide_cable_detect,
-};
-
-static const struct ide_port_ops pmac_ide_port_ops = {
-       .init_dev               = pmac_ide_init_dev,
-       .set_pio_mode           = pmac_ide_set_pio_mode,
-       .set_dma_mode           = pmac_ide_set_dma_mode,
-};
-
-static const struct ide_dma_ops pmac_dma_ops;
-
-static const struct ide_port_info pmac_port_info = {
-       .name                   = DRV_NAME,
-       .init_dma               = pmac_ide_init_dma,
-       .chipset                = ide_pmac,
-       .tp_ops                 = &pmac_tp_ops,
-       .port_ops               = &pmac_ide_port_ops,
-       .dma_ops                = &pmac_dma_ops,
-       .host_flags             = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
-                                 IDE_HFLAG_POST_SET_MODE |
-                                 IDE_HFLAG_MMIO |
-                                 IDE_HFLAG_UNMASK_IRQS,
-       .pio_mask               = ATA_PIO4,
-       .mwdma_mask             = ATA_MWDMA2,
-};
-
-/*
- * Setup, register & probe an IDE channel driven by this driver, this is
- * called by one of the 2 probe functions (macio or PCI).
- */
-static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw)
-{
-       struct device_node *np = pmif->node;
-       const int *bidp;
-       struct ide_host *host;
-       struct ide_hw *hws[] = { hw };
-       struct ide_port_info d = pmac_port_info;
-       int rc;
-
-       pmif->broken_dma = pmif->broken_dma_warn = 0;
-       if (of_device_is_compatible(np, "shasta-ata")) {
-               pmif->kind = controller_sh_ata6;
-               d.tp_ops = &pmac_ata6_tp_ops;
-               d.port_ops = &pmac_ide_ata4_port_ops;
-               d.udma_mask = ATA_UDMA6;
-       } else if (of_device_is_compatible(np, "kauai-ata")) {
-               pmif->kind = controller_un_ata6;
-               d.tp_ops = &pmac_ata6_tp_ops;
-               d.port_ops = &pmac_ide_ata4_port_ops;
-               d.udma_mask = ATA_UDMA5;
-       } else if (of_device_is_compatible(np, "K2-UATA")) {
-               pmif->kind = controller_k2_ata6;
-               d.tp_ops = &pmac_ata6_tp_ops;
-               d.port_ops = &pmac_ide_ata4_port_ops;
-               d.udma_mask = ATA_UDMA5;
-       } else if (of_device_is_compatible(np, "keylargo-ata")) {
-               if (of_node_name_eq(np, "ata-4")) {
-                       pmif->kind = controller_kl_ata4;
-                       d.port_ops = &pmac_ide_ata4_port_ops;
-                       d.udma_mask = ATA_UDMA4;
-               } else
-                       pmif->kind = controller_kl_ata3;
-       } else if (of_device_is_compatible(np, "heathrow-ata")) {
-               pmif->kind = controller_heathrow;
-       } else {
-               pmif->kind = controller_ohare;
-               pmif->broken_dma = 1;
-       }
-
-       bidp = of_get_property(np, "AAPL,bus-id", NULL);
-       pmif->aapl_bus_id =  bidp ? *bidp : 0;
-
-       /* On Kauai-type controllers, we make sure the FCR is correct */
-       if (pmif->kauai_fcr)
-               writel(KAUAI_FCR_UATA_MAGIC |
-                      KAUAI_FCR_UATA_RESET_N |
-                      KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
-       
-       /* Make sure we have sane timings */
-       sanitize_timings(pmif);
-
-       /* If we are on a media bay, wait for it to settle and lock it */
-       if (pmif->mdev)
-               lock_media_bay(pmif->mdev->media_bay);
-
-       host = ide_host_alloc(&d, hws, 1);
-       if (host == NULL) {
-               rc = -ENOMEM;
-               goto bail;
-       }
-       pmif->hwif = host->ports[0];
-
-       if (on_media_bay(pmif)) {
-               /* Fixup bus ID for media bay */
-               if (!bidp)
-                       pmif->aapl_bus_id = 1;
-       } else if (pmif->kind == controller_ohare) {
-               /* The code below is having trouble on some ohare machines
-                * (timing related ?). Until I can put my hand on one of these
-                * units, I keep the old way
-                */
-               ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-       } else {
-               /* This is necessary to enable IDE when net-booting */
-               ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
-               ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
-               msleep(10);
-               ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
-               msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
-       }
-
-       printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), "
-              "bus ID %d%s, irq %d\n", model_name[pmif->kind],
-              pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
-              on_media_bay(pmif) ? " (mediabay)" : "", hw->irq);
-
-       rc = ide_host_register(host, &d, hws);
-       if (rc)
-               pmif->hwif = NULL;
-
-       if (pmif->mdev)
-               unlock_media_bay(pmif->mdev->media_bay);
-
- bail:
-       if (rc && host)
-               ide_host_free(host);
-       return rc;
-}
-
-static void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
-{
-       int i;
-
-       for (i = 0; i < 8; ++i)
-               hw->io_ports_array[i] = base + i * 0x10;
-
-       hw->io_ports.ctl_addr = base + 0x160;
-}
-
-/*
- * Attach to a macio probed interface
- */
-static int pmac_ide_macio_attach(struct macio_dev *mdev,
-                                const struct of_device_id *match)
-{
-       void __iomem *base;
-       unsigned long regbase;
-       pmac_ide_hwif_t *pmif;
-       int irq, rc;
-       struct ide_hw hw;
-
-       pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
-       if (pmif == NULL)
-               return -ENOMEM;
-
-       if (macio_resource_count(mdev) == 0) {
-               printk(KERN_WARNING "ide-pmac: no address for %pOF\n",
-                                   mdev->ofdev.dev.of_node);
-               rc = -ENXIO;
-               goto out_free_pmif;
-       }
-
-       /* Request memory resource for IO ports */
-       if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
-               printk(KERN_ERR "ide-pmac: can't request MMIO resource for "
-                               "%pOF!\n", mdev->ofdev.dev.of_node);
-               rc = -EBUSY;
-               goto out_free_pmif;
-       }
-                       
-       /* XXX This is bogus. Should be fixed in the registry by checking
-        * the kind of host interrupt controller, a bit like gatwick
-        * fixes in irq.c. That works well enough for the single case
-        * where that happens though...
-        */
-       if (macio_irq_count(mdev) == 0) {
-               printk(KERN_WARNING "ide-pmac: no intrs for device %pOF, using "
-                                   "13\n", mdev->ofdev.dev.of_node);
-               irq = irq_create_mapping(NULL, 13);
-       } else
-               irq = macio_irq(mdev, 0);
-
-       base = ioremap(macio_resource_start(mdev, 0), 0x400);
-       regbase = (unsigned long) base;
-
-       pmif->mdev = mdev;
-       pmif->node = mdev->ofdev.dev.of_node;
-       pmif->regbase = regbase;
-       pmif->irq = irq;
-       pmif->kauai_fcr = NULL;
-
-       if (macio_resource_count(mdev) >= 2) {
-               if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
-                       printk(KERN_WARNING "ide-pmac: can't request DMA "
-                                           "resource for %pOF!\n",
-                                           mdev->ofdev.dev.of_node);
-               else
-                       pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
-       } else
-               pmif->dma_regs = NULL;
-
-       dev_set_drvdata(&mdev->ofdev.dev, pmif);
-
-       memset(&hw, 0, sizeof(hw));
-       pmac_ide_init_ports(&hw, pmif->regbase);
-       hw.irq = irq;
-       hw.dev = &mdev->bus->pdev->dev;
-       hw.parent = &mdev->ofdev.dev;
-
-       rc = pmac_ide_setup_device(pmif, &hw);
-       if (rc != 0) {
-               /* The inteface is released to the common IDE layer */
-               dev_set_drvdata(&mdev->ofdev.dev, NULL);
-               iounmap(base);
-               if (pmif->dma_regs) {
-                       iounmap(pmif->dma_regs);
-                       macio_release_resource(mdev, 1);
-               }
-               macio_release_resource(mdev, 0);
-               kfree(pmif);
-       }
-
-       return rc;
-
-out_free_pmif:
-       kfree(pmif);
-       return rc;
-}
-
-static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
-       int rc = 0;
-
-       if (mesg.event != mdev->ofdev.dev.power.power_state.event
-                       && (mesg.event & PM_EVENT_SLEEP)) {
-               rc = pmac_ide_do_suspend(pmif);
-               if (rc == 0)
-                       mdev->ofdev.dev.power.power_state = mesg;
-       }
-
-       return rc;
-}
-
-static int
-pmac_ide_macio_resume(struct macio_dev *mdev)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
-       int rc = 0;
-
-       if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
-               rc = pmac_ide_do_resume(pmif);
-               if (rc == 0)
-                       mdev->ofdev.dev.power.power_state = PMSG_ON;
-       }
-
-       return rc;
-}
-
-/*
- * Attach to a PCI probed interface
- */
-static int pmac_ide_pci_attach(struct pci_dev *pdev,
-                              const struct pci_device_id *id)
-{
-       struct device_node *np;
-       pmac_ide_hwif_t *pmif;
-       void __iomem *base;
-       unsigned long rbase, rlen;
-       int rc;
-       struct ide_hw hw;
-
-       np = pci_device_to_OF_node(pdev);
-       if (np == NULL) {
-               printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n");
-               return -ENODEV;
-       }
-
-       pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
-       if (pmif == NULL)
-               return -ENOMEM;
-
-       if (pci_enable_device(pdev)) {
-               printk(KERN_WARNING "ide-pmac: Can't enable PCI device for "
-                                   "%pOF\n", np);
-               rc = -ENXIO;
-               goto out_free_pmif;
-       }
-       pci_set_master(pdev);
-                       
-       if (pci_request_regions(pdev, "Kauai ATA")) {
-               printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for "
-                               "%pOF\n", np);
-               rc = -ENXIO;
-               goto out_free_pmif;
-       }
-
-       pmif->mdev = NULL;
-       pmif->node = np;
-
-       rbase = pci_resource_start(pdev, 0);
-       rlen = pci_resource_len(pdev, 0);
-
-       base = ioremap(rbase, rlen);
-       pmif->regbase = (unsigned long) base + 0x2000;
-       pmif->dma_regs = base + 0x1000;
-       pmif->kauai_fcr = base;
-       pmif->irq = pdev->irq;
-
-       pci_set_drvdata(pdev, pmif);
-
-       memset(&hw, 0, sizeof(hw));
-       pmac_ide_init_ports(&hw, pmif->regbase);
-       hw.irq = pdev->irq;
-       hw.dev = &pdev->dev;
-
-       rc = pmac_ide_setup_device(pmif, &hw);
-       if (rc != 0) {
-               /* The inteface is released to the common IDE layer */
-               iounmap(base);
-               pci_release_regions(pdev);
-               kfree(pmif);
-       }
-
-       return rc;
-
-out_free_pmif:
-       kfree(pmif);
-       return rc;
-}
-
-static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
-{
-       pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
-       int rc = 0;
-
-       if (mesg.event != pdev->dev.power.power_state.event
-                       && (mesg.event & PM_EVENT_SLEEP)) {
-               rc = pmac_ide_do_suspend(pmif);
-               if (rc == 0)
-                       pdev->dev.power.power_state = mesg;
-       }
-
-       return rc;
-}
-
-static int
-pmac_ide_pci_resume(struct pci_dev *pdev)
-{
-       pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
-       int rc = 0;
-
-       if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
-               rc = pmac_ide_do_resume(pmif);
-               if (rc == 0)
-                       pdev->dev.power.power_state = PMSG_ON;
-       }
-
-       return rc;
-}
-
-#ifdef CONFIG_PMAC_MEDIABAY
-static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
-
-       switch(mb_state) {
-       case MB_CD:
-               if (!pmif->hwif->present)
-                       ide_port_scan(pmif->hwif);
-               break;
-       default:
-               if (pmif->hwif->present)
-                       ide_port_unregister_devices(pmif->hwif);
-       }
-}
-#endif /* CONFIG_PMAC_MEDIABAY */
-
-
-static struct of_device_id pmac_ide_macio_match[] = 
-{
-       {
-       .name           = "IDE",
-       },
-       {
-       .name           = "ATA",
-       },
-       {
-       .type           = "ide",
-       },
-       {
-       .type           = "ata",
-       },
-       {},
-};
-
-static struct macio_driver pmac_ide_macio_driver = 
-{
-       .driver = {
-               .name           = "ide-pmac",
-               .owner          = THIS_MODULE,
-               .of_match_table = pmac_ide_macio_match,
-       },
-       .probe          = pmac_ide_macio_attach,
-       .suspend        = pmac_ide_macio_suspend,
-       .resume         = pmac_ide_macio_resume,
-#ifdef CONFIG_PMAC_MEDIABAY
-       .mediabay_event = pmac_ide_macio_mb_event,
-#endif
-};
-
-static const struct pci_device_id pmac_ide_pci_match[] = {
-       { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA),    0 },
-       { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100),  0 },
-       { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100),    0 },
-       { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA),       0 },
-       { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA),    0 },
-       {},
-};
-
-static struct pci_driver pmac_ide_pci_driver = {
-       .name           = "ide-pmac",
-       .id_table       = pmac_ide_pci_match,
-       .probe          = pmac_ide_pci_attach,
-       .suspend        = pmac_ide_pci_suspend,
-       .resume         = pmac_ide_pci_resume,
-};
-MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
-
-int __init pmac_ide_probe(void)
-{
-       int error;
-
-       if (!machine_is(powermac))
-               return -ENODEV;
-
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
-       error = pci_register_driver(&pmac_ide_pci_driver);
-       if (error)
-               goto out;
-       error = macio_register_driver(&pmac_ide_macio_driver);
-       if (error) {
-               pci_unregister_driver(&pmac_ide_pci_driver);
-               goto out;
-       }
-#else
-       error = macio_register_driver(&pmac_ide_macio_driver);
-       if (error)
-               goto out;
-       error = pci_register_driver(&pmac_ide_pci_driver);
-       if (error) {
-               macio_unregister_driver(&pmac_ide_macio_driver);
-               goto out;
-       }
-#endif
-out:
-       return error;
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       struct dbdma_cmd *table;
-       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
-       struct scatterlist *sg;
-       int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-       int i = cmd->sg_nents, count = 0;
-
-       /* DMA table is already aligned */
-       table = (struct dbdma_cmd *) pmif->dma_table_cpu;
-
-       /* Make sure DMA controller is stopped (necessary ?) */
-       writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
-       while (readl(&dma->status) & RUN)
-               udelay(1);
-
-       /* Build DBDMA commands list */
-       sg = hwif->sg_table;
-       while (i && sg_dma_len(sg)) {
-               u32 cur_addr;
-               u32 cur_len;
-
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) {
-                       if (pmif->broken_dma_warn == 0) {
-                               printk(KERN_WARNING "%s: DMA on non aligned address, "
-                                      "switching to PIO on Ohare chipset\n", drive->name);
-                               pmif->broken_dma_warn = 1;
-                       }
-                       return 0;
-               }
-               while (cur_len) {
-                       unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-                       if (count++ >= MAX_DCMDS) {
-                               printk(KERN_WARNING "%s: DMA table too small\n",
-                                      drive->name);
-                               return 0;
-                       }
-                       table->command = cpu_to_le16(wr? OUTPUT_MORE: INPUT_MORE);
-                       table->req_count = cpu_to_le16(tc);
-                       table->phy_addr = cpu_to_le32(cur_addr);
-                       table->cmd_dep = 0;
-                       table->xfer_status = 0;
-                       table->res_count = 0;
-                       cur_addr += tc;
-                       cur_len -= tc;
-                       ++table;
-               }
-               sg = sg_next(sg);
-               i--;
-       }
-
-       /* convert the last command to an input/output last command */
-       if (count) {
-               table[-1].command = cpu_to_le16(wr? OUTPUT_LAST: INPUT_LAST);
-               /* add the stop command to the end of the list */
-               memset(table, 0, sizeof(struct dbdma_cmd));
-               table->command = cpu_to_le16(DBDMA_STOP);
-               mb();
-               writel(hwif->dmatable_dma, &dma->cmdptr);
-               return 1;
-       }
-
-       printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
-       return 0; /* revert to PIO for this request */
-}
-
-/*
- * Prepare a DMA transfer. We build the DMA table, adjust the timings for
- * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
- */
-static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
-       u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
-       if (pmac_ide_build_dmatable(drive, cmd) == 0)
-               return 1;
-
-       /* Apple adds 60ns to wrDataSetup on reads */
-       if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
-               writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL),
-                       PMAC_IDE_REG(IDE_TIMING_CONFIG));
-               (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
-       }
-
-       return 0;
-}
-
-/*
- * Kick the DMA controller into life after the DMA command has been issued
- * to the drive.
- */
-static void
-pmac_ide_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma;
-
-       dma = pmif->dma_regs;
-
-       writel((RUN << 16) | RUN, &dma->control);
-       /* Make sure it gets to the controller right now */
-       (void)readl(&dma->control);
-}
-
-/*
- * After a DMA transfer, make sure the controller is stopped
- */
-static int
-pmac_ide_dma_end (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
-       u32 dstat;
-
-       dstat = readl(&dma->status);
-       writel(((RUN|WAKE|DEAD) << 16), &dma->control);
-
-       /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
-        * in theory, but with ATAPI decices doing buffer underruns, that would
-        * cause us to disable DMA, which isn't what we want
-        */
-       return (dstat & (RUN|DEAD)) != RUN;
-}
-
-/*
- * Check out that the interrupt we got was for us. We can't always know this
- * for sure with those Apple interfaces (well, we could on the recent ones but
- * that's not implemented yet), on the other hand, we don't have shared interrupts
- * so it's not really a problem
- */
-static int
-pmac_ide_dma_test_irq (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
-       unsigned long status, timeout;
-
-       /* We have to things to deal with here:
-        * 
-        * - The dbdma won't stop if the command was started
-        * but completed with an error without transferring all
-        * datas. This happens when bad blocks are met during
-        * a multi-block transfer.
-        * 
-        * - The dbdma fifo hasn't yet finished flushing to
-        * to system memory when the disk interrupt occurs.
-        * 
-        */
-
-       /* If ACTIVE is cleared, the STOP command have passed and
-        * transfer is complete.
-        */
-       status = readl(&dma->status);
-       if (!(status & ACTIVE))
-               return 1;
-
-       /* If dbdma didn't execute the STOP command yet, the
-        * active bit is still set. We consider that we aren't
-        * sharing interrupts (which is hopefully the case with
-        * those controllers) and so we just try to flush the
-        * channel for pending data in the fifo
-        */
-       udelay(1);
-       writel((FLUSH << 16) | FLUSH, &dma->control);
-       timeout = 0;
-       for (;;) {
-               udelay(1);
-               status = readl(&dma->status);
-               if ((status & FLUSH) == 0)
-                       break;
-               if (++timeout > 100) {
-                       printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n",
-                              hwif->index);
-                       break;
-               }
-       }       
-       return 1;
-}
-
-static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void
-pmac_ide_dma_lost_irq (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
-       unsigned long status = readl(&dma->status);
-
-       printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
-}
-
-static const struct ide_dma_ops pmac_dma_ops = {
-       .dma_host_set           = pmac_ide_dma_host_set,
-       .dma_setup              = pmac_ide_dma_setup,
-       .dma_start              = pmac_ide_dma_start,
-       .dma_end                = pmac_ide_dma_end,
-       .dma_test_irq           = pmac_ide_dma_test_irq,
-       .dma_lost_irq           = pmac_ide_dma_lost_irq,
-};
-
-/*
- * Allocate the data structures needed for using DMA with an interface
- * and fill the proper list of functions pointers
- */
-static int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       /* We won't need pci_dev if we switch to generic consistent
-        * DMA routines ...
-        */
-       if (dev == NULL || pmif->dma_regs == 0)
-               return -ENODEV;
-       /*
-        * Allocate space for the DBDMA commands.
-        * The +2 is +1 for the stop command and +1 to allow for
-        * aligning the start address to a multiple of 16 bytes.
-        */
-       pmif->dma_table_cpu = dma_alloc_coherent(&dev->dev,
-               (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-               &hwif->dmatable_dma, GFP_KERNEL);
-       if (pmif->dma_table_cpu == NULL) {
-               printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-                      hwif->name);
-               return -ENOMEM;
-       }
-
-       hwif->sg_max_nents = MAX_DCMDS;
-
-       return 0;
-}
-
-module_init(pmac_ide_probe);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
deleted file mode 100644 (file)
index ecd0a69..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- *  Q40 I/O port IDE Driver
- *
- *     (c) Richard Zidlicky
- *
- *  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.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#include <asm/ide.h>
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define Q40IDE_NUM_HWIFS       2
-
-#define PCIDE_BASE1    0x1f0
-#define PCIDE_BASE2    0x170
-#define PCIDE_BASE3    0x1e8
-#define PCIDE_BASE4    0x168
-#define PCIDE_BASE5    0x1e0
-#define PCIDE_BASE6    0x160
-
-static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
-    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
-    PCIDE_BASE6 */
-};
-
-static int q40ide_default_irq(unsigned long base)
-{
-           switch (base) {
-                   case 0x1f0: return 14;
-                   case 0x170: return 15;
-                   case 0x1e8: return 11;
-                   default:
-                       return 0;
-          }
-}
-
-
-/*
- * Addresses are pretranslated for Q40 ISA access.
- */
-static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
-{
-       memset(hw, 0, sizeof(*hw));
-       /* BIG FAT WARNING: 
-          assumption: only DATA port is ever used in 16 bit mode */
-       hw->io_ports.data_addr = Q40_ISA_IO_W(base);
-       hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
-       hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
-       hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
-       hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
-       hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
-       hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
-       hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
-       hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
-
-       hw->irq = irq;
-}
-
-static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                             void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
-               __ide_mm_insw(data_addr, buf, (len + 1) / 2);
-               return;
-       }
-
-       raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                              void *buf, unsigned int len)
-{
-       unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
-       if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
-               __ide_mm_outsw(data_addr, buf, (len + 1) / 2);
-               return;
-       }
-
-       raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-/* Q40 has a byte-swapped IDE interface */
-static const struct ide_tp_ops q40ide_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_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             = q40ide_input_data,
-       .output_data            = q40ide_output_data,
-};
-
-static const struct ide_port_info q40ide_port_info = {
-       .tp_ops                 = &q40ide_tp_ops,
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-       .irq_flags              = IRQF_SHARED,
-       .chipset                = ide_generic,
-};
-
-/* 
- * the static array is needed to have the name reported in /proc/ioports,
- * hwif->name unfortunately isn't available yet
- */
-static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
-       "ide0", "ide1"
-};
-
-/*
- *  Probe for Q40 IDE interfaces
- */
-
-static int __init q40ide_init(void)
-{
-    int i;
-    struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
-
-    if (!MACH_IS_Q40)
-      return -ENODEV;
-
-    printk(KERN_INFO "ide: Q40 IDE controller\n");
-
-    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
-       const char *name = q40_ide_names[i];
-
-       if (!request_region(pcide_bases[i], 8, name)) {
-               printk("could not reserve ports %lx-%lx for %s\n",
-                      pcide_bases[i],pcide_bases[i]+8,name);
-               continue;
-       }
-       if (!request_region(pcide_bases[i]+0x206, 1, name)) {
-               printk("could not reserve port %lx for %s\n",
-                      pcide_bases[i]+0x206,name);
-               release_region(pcide_bases[i], 8);
-               continue;
-       }
-       q40_ide_setup_ports(&hw[i], pcide_bases[i],
-                       q40ide_default_irq(pcide_bases[i]));
-
-       hws[i] = &hw[i];
-    }
-
-    return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
-}
-
-module_init(q40ide_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
deleted file mode 100644 (file)
index ab79b62..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
- */
-
-/*
- *  Version 0.03       Cleaned auto-tune, added probe
- *  Version 0.04       Added second channel tuning
- *  Version 0.05       Enhanced tuning ; added qd6500 support
- *  Version 0.06       Added dos driver's list
- *  Version 0.07       Second channel bug fix 
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * To activate controller support, use "ide0=qd65xx"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@ens-lyon.org>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#define DRV_NAME "qd65xx"
-
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- *     -- qd6500 is a single IDE interface
- *     -- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- *        qd6580: 1
- * upper nibble:
- *        qd6500: 1100
- *        qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- *                                                   channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- *         0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- *     (maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-/*
- * qd65xx_select:
- *
- * This routine is invoked to prepare for access to a given drive.
- */
-
-static void qd65xx_dev_select(ide_drive_t *drive)
-{
-       u8 index = ((   (QD_TIMREG(drive)) & 0x80 ) >> 7) |
-                       (QD_TIMREG(drive) & 0x02);
-
-       if (timings[index] != QD_TIMING(drive))
-               outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-
-       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- *     lower nibble represents active time,   in count of VLB clocks
- *     upper nibble represents recovery time, in count of VLB clocks
- */
-
-static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
-       int clk = ide_vlb_clk ? ide_vlb_clk : 50;
-       u8 act_cyc, rec_cyc;
-
-       if (clk <= 33) {
-               act_cyc =  9 - IDE_IN(active_time   * clk / 1000 + 1, 2,  9);
-               rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
-       } else {
-               act_cyc =  8 - IDE_IN(active_time   * clk / 1000 + 1, 1,  8);
-               rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
-       }
-
-       return (rec_cyc << 4) | 0x08 | act_cyc;
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static u8 qd6580_compute_timing (int active_time, int recovery_time)
-{
-       int clk = ide_vlb_clk ? ide_vlb_clk : 50;
-       u8 act_cyc, rec_cyc;
-
-       act_cyc = 17 - IDE_IN(active_time   * clk / 1000 + 1, 2, 17);
-       rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
-
-       return (rec_cyc << 4) | act_cyc;
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
-               int *active_time, int *recovery_time)
-{
-       struct qd65xx_timing_s *p;
-       char *m = (char *)&drive->id[ATA_ID_PROD];
-       char model[ATA_ID_PROD_LEN];
-
-       if (*m == 0)
-               return 0;
-
-       strncpy(model, m, ATA_ID_PROD_LEN);
-       ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
-
-       for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-               if (!strncmp(p->model, model+p->offset, 4)) {
-                       printk(KERN_DEBUG "%s: listed !\n", drive->name);
-                       *active_time = p->active;
-                       *recovery_time = p->recovery;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing
- */
-
-static void qd_set_timing (ide_drive_t *drive, u8 timing)
-{
-       unsigned long data = (unsigned long)ide_get_drivedata(drive);
-
-       data &= 0xff00;
-       data |= timing;
-       ide_set_drivedata(drive, (void *)data);
-
-       printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
-}
-
-static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       u16 *id = drive->id;
-       int active_time   = 175;
-       int recovery_time = 415; /* worst case values from the dos driver */
-
-       /* FIXME: use drive->pio_mode value */
-       if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
-           (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
-           id[ATA_ID_EIDE_PIO] >= 240) {
-               printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-                       id[ATA_ID_OLD_PIO_MODES] & 0xff);
-               active_time = 110;
-               recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
-       }
-
-       qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
-                               active_time, recovery_time));
-}
-
-static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-       unsigned int cycle_time;
-       int active_time   = 175;
-       int recovery_time = 415; /* worst case values from the dos driver */
-       u8 base = (hwif->config_data & 0xff00) >> 8;
-
-       if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
-               cycle_time = ide_pio_cycle_time(drive, pio);
-
-               switch (pio) {
-                       case 0: break;
-                       case 3:
-                               if (cycle_time >= 110) {
-                                       active_time = 86;
-                                       recovery_time = cycle_time - 102;
-                               } else
-                                       printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-                               break;
-                       case 4:
-                               if (cycle_time >= 69) {
-                                       active_time = 70;
-                                       recovery_time = cycle_time - 61;
-                               } else
-                                       printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-                               break;
-                       default:
-                               if (cycle_time >= 180) {
-                                       active_time = 110;
-                                       recovery_time = cycle_time - 120;
-                               } else {
-                                       active_time = t->active;
-                                       recovery_time = cycle_time - active_time;
-                               }
-               }
-               printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
-       }
-
-       if (!hwif->channel && drive->media != ide_disk) {
-               outb(0x5f, QD_CONTROL_PORT);
-               printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
-                       "and post-write buffer on %s.\n",
-                       drive->name, hwif->name);
-       }
-
-       qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
-       unsigned long flags;
-       u8 savereg, readreg;
-
-       local_irq_save(flags);
-       savereg = inb_p(port);
-       outb_p(QD_TESTVAL, port);       /* safe value */
-       readreg = inb_p(port);
-       outb(savereg, port);
-       local_irq_restore(flags);
-
-       if (savereg == QD_TESTVAL) {
-               printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
-               printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
-               printk(KERN_ERR "Assuming qd65xx is not present.\n");
-               return 1;
-       }
-
-       return (readreg != QD_TESTVAL);
-}
-
-static void __init qd6500_init_dev(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 base = (hwif->config_data & 0xff00) >> 8;
-       u8 config = QD_CONFIG(hwif);
-
-       ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
-}
-
-static void __init qd6580_init_dev(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long t1, t2;
-       u8 base = (hwif->config_data & 0xff00) >> 8;
-       u8 config = QD_CONFIG(hwif);
-
-       if (hwif->host_flags & IDE_HFLAG_SINGLE) {
-               t1 = QD6580_DEF_DATA;
-               t2 = QD6580_DEF_DATA2;
-       } else
-               t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
-
-       ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
-}
-
-static const struct ide_tp_ops qd65xx_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = qd65xx_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 qd6500_port_ops = {
-       .init_dev               = qd6500_init_dev,
-       .set_pio_mode           = qd6500_set_pio_mode,
-};
-
-static const struct ide_port_ops qd6580_port_ops = {
-       .init_dev               = qd6580_init_dev,
-       .set_pio_mode           = qd6580_set_pio_mode,
-};
-
-static const struct ide_port_info qd65xx_port_info __initconst = {
-       .name                   = DRV_NAME,
-       .tp_ops                 = &qd65xx_tp_ops,
-       .chipset                = ide_qd65xx,
-       .host_flags             = IDE_HFLAG_IO_32BIT |
-                                 IDE_HFLAG_NO_DMA,
-       .pio_mask               = ATA_PIO4,
-};
-
-/*
- * qd_probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-static int __init qd_probe(int base)
-{
-       int rc;
-       u8 config, unit, control;
-       struct ide_port_info d = qd65xx_port_info;
-
-       config = inb(QD_CONFIG_PORT);
-
-       if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
-               return -ENODEV;
-
-       unit = ! (config & QD_CONFIG_IDE_BASEPORT);
-
-       if (unit)
-               d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
-
-       switch (config & 0xf0) {
-       case QD_CONFIG_QD6500:
-               if (qd_testreg(base))
-                        return -ENODEV;        /* bad register */
-
-               if (config & QD_CONFIG_DISABLED) {
-                       printk(KERN_WARNING "qd6500 is disabled !\n");
-                       return -ENODEV;
-               }
-
-               printk(KERN_NOTICE "qd6500 at %#x\n", base);
-               printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-                       config, QD_ID3);
-
-               d.port_ops = &qd6500_port_ops;
-               d.host_flags |= IDE_HFLAG_SINGLE;
-               break;
-       case QD_CONFIG_QD6580_A:
-       case QD_CONFIG_QD6580_B:
-               if (qd_testreg(base) || qd_testreg(base + 0x02))
-                       return -ENODEV; /* bad registers */
-
-               control = inb(QD_CONTROL_PORT);
-
-               printk(KERN_NOTICE "qd6580 at %#x\n", base);
-               printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-                       config, control, QD_ID3);
-
-               outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
-               d.port_ops = &qd6580_port_ops;
-               if (control & QD_CONTR_SEC_DISABLED)
-                       d.host_flags |= IDE_HFLAG_SINGLE;
-
-               printk(KERN_INFO "qd6580: %s IDE board\n",
-                       (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
-               break;
-       default:
-               return -ENODEV;
-       }
-
-       rc = ide_legacy_device_add(&d, (base << 8) | config);
-
-       if (d.host_flags & IDE_HFLAG_SINGLE)
-               return (rc == 0) ? 1 : rc;
-
-       return rc;
-}
-
-static bool probe_qd65xx;
-
-module_param_named(probe, probe_qd65xx, bool, 0);
-MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
-
-static int __init qd65xx_init(void)
-{
-       int rc1, rc2 = -ENODEV;
-
-       if (probe_qd65xx == 0)
-               return -ENODEV;
-
-       rc1 = qd_probe(0x30);
-       if (rc1)
-               rc2 = qd_probe(0xb0);
-
-       if (rc1 < 0 && rc2 < 0)
-               return -ENODEV;
-
-       return 0;
-}
-
-module_init(qd65xx_init);
-
-MODULE_AUTHOR("Samuel Thibault");
-MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
deleted file mode 100644 (file)
index 01a43ab..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2000  Linus Torvalds & authors
- */
-
-/*
- * Authors:    Petr Soucek <petr@ryston.cz>
- *             Samuel Thibault <samuel.thibault@ens-lyon.org>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b) ((!(a)) || (b))
-
-#define QD_TIM1_PORT           (base)
-#define QD_CONFIG_PORT         (base+0x01)
-#define QD_TIM2_PORT           (base+0x02)
-#define QD_CONTROL_PORT                (base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT 0x01
-#define QD_CONFIG_BASEPORT     0x02
-#define QD_CONFIG_ID3          0x04
-#define QD_CONFIG_DISABLED     0x08
-#define QD_CONFIG_QD6500       0xc0
-#define QD_CONFIG_QD6580_A     0xa0
-#define QD_CONFIG_QD6580_B     0x50
-
-#define QD_CONTR_SEC_DISABLED  0x01
-
-#define QD_ID3                 ((config & QD_CONFIG_ID3)!=0)
-
-#define QD_CONFIG(hwif)                ((hwif)->config_data & 0x00ff)
-
-static inline u8 QD_TIMING(ide_drive_t *drive)
-{
-       return (unsigned long)ide_get_drivedata(drive) & 0x00ff;
-}
-
-static inline u8 QD_TIMREG(ide_drive_t *drive)
-{
-       return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8;
-}
-
-#define QD6500_DEF_DATA                ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
-#define QD6580_DEF_DATA                ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD6580_DEF_DATA2       ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD_DEF_CONTR           (0x40 | ((control & 0x02) ? 0x9f : 0x1f))
-
-#define QD_TESTVAL             0x19    /* safe value */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-static struct qd65xx_timing_s {
-       s8      offset;   /* ofset from the beginning of Model Number" */
-       char    model[4];    /* 4 chars from Model number, no conversion */
-       s16     active;   /* active time */
-       s16     recovery; /* recovery time */
-} qd65xx_timing [] = {
-       { 30, "2040", 110, 225 },  /* Conner CP30204                    */
-       { 30, "2045", 135, 225 },  /* Conner CP30254                    */
-       { 30, "1040", 155, 325 },  /* Conner CP30104                    */
-       { 30, "1047", 135, 265 },  /* Conner CP30174                    */
-       { 30, "5344", 135, 225 },  /* Conner CP3544                     */
-       { 30, "01 4", 175, 405 },  /* Conner CP-3104                    */
-       { 27, "C030", 175, 375 },  /* Conner CP3000                     */
-       {  8, "PL42", 110, 295 },  /* Quantum LP240                     */
-       {  8, "PL21", 110, 315 },  /* Quantum LP120                     */
-       {  8, "PL25", 175, 385 },  /* Quantum LP52                      */
-       {  4, "PA24", 110, 285 },  /* WD Piranha SP4200                 */
-       {  6, "2200", 110, 260 },  /* WD Caviar AC2200                  */
-       {  6, "3204", 110, 235 },  /* WD Caviar AC2340                  */
-       {  6, "1202", 110, 265 },  /* WD Caviar AC2120                  */
-       {  0, "DS3-", 135, 315 },  /* Teac SD340                        */
-       {  8, "KM32", 175, 355 },  /* Toshiba MK234                     */
-       {  2, "53A1", 175, 355 },  /* Seagate ST351A                    */
-       {  2, "4108", 175, 295 },  /* Seagate ST1480A                   */
-       {  2, "1344", 175, 335 },  /* Seagate ST3144A                   */
-       {  6, "7 12", 110, 225 },  /* Maxtor 7213A                      */
-       { 30, "02F4", 145, 295 },  /* Conner 3204F                      */
-       {  2, "1302", 175, 335 },  /* Seagate ST3120A                   */
-       {  2, "2334", 145, 265 },  /* Seagate ST3243A                   */
-       {  2, "2338", 145, 275 },  /* Seagate ST3283A                   */
-       {  2, "3309", 145, 275 },  /* Seagate ST3390A                   */
-       {  2, "5305", 145, 275 },  /* Seagate ST3550A                   */
-       {  2, "4100", 175, 295 },  /* Seagate ST1400A                   */
-       {  2, "4110", 175, 295 },  /* Seagate ST1401A                   */
-       {  2, "6300", 135, 265 },  /* Seagate ST3600A                   */
-       {  2, "5300", 135, 265 },  /* Seagate ST3500A                   */
-       {  6, "7 31", 135, 225 },  /* Maxtor 7131 AT                    */
-       {  6, "7 43", 115, 265 },  /* Maxtor 7345 AT                    */
-       {  6, "7 42", 110, 255 },  /* Maxtor 7245 AT                    */
-       {  6, "3 04", 135, 265 },  /* Maxtor 340 AT                     */
-       {  6, "61 0", 135, 285 },  /* WD AC160                          */
-       {  6, "1107", 135, 235 },  /* WD AC1170                         */
-       {  6, "2101", 110, 220 },  /* WD AC1210                         */
-       {  6, "4202", 135, 245 },  /* WD AC2420                         */
-       {  6, "41 0", 175, 355 },  /* WD Caviar 140                     */
-       {  6, "82 0", 175, 355 },  /* WD Caviar 280                     */
-       {  8, "PL01", 175, 375 },  /* Quantum LP105                     */
-       {  8, "PL25", 110, 295 },  /* Quantum LP525                     */
-       { 10, "4S 2", 175, 385 },  /* Quantum ELS42                     */
-       { 10, "8S 5", 175, 385 },  /* Quantum ELS85                     */
-       { 10, "1S72", 175, 385 },  /* Quantum ELS127                    */
-       { 10, "1S07", 175, 385 },  /* Quantum ELS170                    */
-       {  8, "ZE42", 135, 295 },  /* Quantum EZ240                     */
-       {  8, "ZE21", 175, 385 },  /* Quantum EZ127                     */
-       {  8, "ZE58", 175, 385 },  /* Quantum EZ85                      */
-       {  8, "ZE24", 175, 385 },  /* Quantum EZ42                      */
-       { 27, "C036", 155, 325 },  /* Conner CP30064                    */
-       { 27, "C038", 155, 325 },  /* Conner CP30084                    */
-       {  6, "2205", 110, 255 },  /* WDC AC2250                        */
-       {  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC     */
-       {  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,  */
-       {  4, "UC41", 140, 415 },  /* WDC CU140                         */
-       {  6, "1207", 130, 275 },  /* WDC AC2170                        */
-       {  6, "2107", 130, 275 },  /* WDC AC1270                        */
-       {  6, "5204", 130, 275 },  /* WDC AC2540                        */
-       { 30, "3004", 110, 235 },  /* Conner CP30340                    */
-       { 30, "0345", 135, 255 },  /* Conner CP30544                    */
-       { 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A                   */
-       { 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A                   */
-       {  6, "7 21", 180, 290 },  /* Maxtor 7120 AT                    */
-       {  6, "7 71", 135, 240 },  /* Maxtor 7170 AT                    */
-       { 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540                */
-       {  8, "PL11", 180, 290 },  /* QUANTUM LP110A                    */
-       {  8, "OG21", 150, 275 },  /* QUANTUM GO120                     */
-       { 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A                   */
-       {  2, "2309", 175, 295 },  /* ST3290A                           */
-       {  2, "3358", 180, 310 },  /* ST3385A                           */
-       {  2, "6355", 180, 310 },  /* ST3655A                           */
-       {  2, "1900", 175, 270 },  /* ST9100A                           */
-       {  2, "1954", 175, 270 },  /* ST9145A                           */
-       {  2, "1909", 175, 270 },  /* ST9190AG                          */
-       {  2, "2953", 175, 270 },  /* ST9235A                           */
-       {  2, "1359", 175, 270 },  /* ST3195A                           */
-       { 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C     */
-       {  0, "2M26", 175, 215 },  /* M262XT-0Ah                        */
-       {  4, "2253", 175, 300 },  /* HP C2235A                         */
-       {  4, "-32A", 145, 245 },  /* H3133-A2                          */
-       { 30, "0326", 150, 270 },  /* Samsung Electronics 120MB         */
-       { 30, "3044", 110, 195 },  /* Conner CFA340A                    */
-       { 30, "43A0", 110, 195 },  /* Conner CFA340A                    */
-       { -1, "    ", 175, 415 }   /* unknown disk name                 */
-};
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
deleted file mode 100644 (file)
index 0ab8b86..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 1996-2002 Russell King.
- */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static const struct ide_port_info rapide_port_info = {
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-       .chipset                = ide_generic,
-};
-
-static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base,
-                              void __iomem *ctrl, unsigned int sz, int irq)
-{
-       unsigned long port = (unsigned long)base;
-       int i;
-
-       for (i = 0; i <= 7; i++) {
-               hw->io_ports_array[i] = port;
-               port += sz;
-       }
-       hw->io_ports.ctl_addr = (unsigned long)ctrl;
-       hw->irq = irq;
-}
-
-static int rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-       void __iomem *base;
-       struct ide_host *host;
-       int ret;
-       struct ide_hw hw, *hws[] = { &hw };
-
-       ret = ecard_request_resources(ec);
-       if (ret)
-               goto out;
-
-       base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
-       if (!base) {
-               ret = -ENOMEM;
-               goto release;
-       }
-
-       memset(&hw, 0, sizeof(hw));
-       rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
-       hw.dev = &ec->dev;
-
-       ret = ide_host_add(&rapide_port_info, hws, 1, &host);
-       if (ret)
-               goto release;
-
-       ecard_set_drvdata(ec, host);
-       goto out;
-
- release:
-       ecard_release_resources(ec);
- out:
-       return ret;
-}
-
-static void rapide_remove(struct expansion_card *ec)
-{
-       struct ide_host *host = ecard_get_drvdata(ec);
-
-       ecard_set_drvdata(ec, NULL);
-
-       ide_host_remove(host);
-
-       ecard_release_resources(ec);
-}
-
-static struct ecard_id rapide_ids[] = {
-       { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-       { 0xffff, 0xffff }
-};
-
-static struct ecard_driver rapide_driver = {
-       .probe          = rapide_probe,
-       .remove         = rapide_remove,
-       .id_table       = rapide_ids,
-       .drv = {
-               .name   = "rapide",
-       },
-};
-
-static int __init rapide_init(void)
-{
-       return ecard_register_driver(&rapide_driver);
-}
-
-static void __exit rapide_exit(void)
-{
-       ecard_remove_driver(&rapide_driver);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Yellowstone RAPIDE driver");
-
-module_init(rapide_init);
-module_exit(rapide_exit);
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
deleted file mode 100644 (file)
index fce2b7d..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author:  mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for disabling the buggy read-ahead
- *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- *  Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "rz1000"
-
-static int rz1000_disable_readahead(struct pci_dev *dev)
-{
-       u16 reg;
-
-       if (!pci_read_config_word (dev, 0x40, &reg) &&
-           !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
-               printk(KERN_INFO "%s: disabled chipset read-ahead "
-                       "(buggy RZ1000/RZ1001)\n", pci_name(dev));
-               return 0;
-       } else {
-               printk(KERN_INFO "%s: serialized, disabled unmasking "
-                       "(buggy RZ1000/RZ1001)\n", pci_name(dev));
-               return 1;
-       }
-}
-
-static const struct ide_port_info rz1000_chipset = {
-       .name           = DRV_NAME,
-       .host_flags     = IDE_HFLAG_NO_DMA,
-};
-
-static int rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d = rz1000_chipset;
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       if (rz1000_disable_readahead(dev)) {
-               d.host_flags |= IDE_HFLAG_SERIALIZE;
-               d.host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
-       }
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static void rz1000_remove(struct pci_dev *dev)
-{
-       ide_pci_remove(dev);
-       pci_disable_device(dev);
-}
-
-static const struct pci_device_id rz1000_pci_tbl[] = {
-       { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 },
-       { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
-
-static struct pci_driver rz1000_pci_driver = {
-       .name           = "RZ1000_IDE",
-       .id_table       = rz1000_pci_tbl,
-       .probe          = rz1000_init_one,
-       .remove         = rz1000_remove,
-};
-
-static int __init rz1000_ide_init(void)
-{
-       return ide_pci_register_driver(&rz1000_pci_driver);
-}
-
-static void __exit rz1000_ide_exit(void)
-{
-       pci_unregister_driver(&rz1000_pci_driver);
-}
-
-module_init(rz1000_ide_init);
-module_exit(rz1000_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c
deleted file mode 100644 (file)
index a5b7018..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2000-2002             Mark Lord <mlord@pobox.com>
- * Copyright (C)      2007             Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- *
- * Documentation:
- *     Available from National Semiconductor
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/pm.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "sc1200"
-
-#define SC1200_REV_A   0x00
-#define SC1200_REV_B1  0x01
-#define SC1200_REV_B3  0x02
-#define SC1200_REV_C1  0x03
-#define SC1200_REV_D1  0x04
-
-#define PCI_CLK_33     0x00
-#define PCI_CLK_48     0x01
-#define PCI_CLK_66     0x02
-#define PCI_CLK_33A    0x03
-
-static unsigned short sc1200_get_pci_clock (void)
-{
-       unsigned char chip_id, silicon_revision;
-       unsigned int pci_clock;
-       /*
-        * Check the silicon revision, as not all versions of the chip
-        * have the register with the fast PCI bus timings.
-        */
-       chip_id = inb (0x903c);
-       silicon_revision = inb (0x903d);
-
-       // Read the fast pci clock frequency
-       if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
-               pci_clock = PCI_CLK_33;
-       } else {
-               // check clock generator configuration (cfcc)
-               // the clock is in bits 8 and 9 of this word
-
-               pci_clock = inw (0x901e);
-               pci_clock >>= 8;
-               pci_clock &= 0x03;
-               if (pci_clock == PCI_CLK_33A)
-                       pci_clock = PCI_CLK_33;
-       }
-       return pci_clock;
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static const unsigned int sc1200_pio_timings[4][5] =
-       {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},  // format0  33Mhz
-        {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010},  // format1, 33Mhz
-        {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021},  // format1, 48Mhz
-        {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz
-
-/*
- * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
- */
-//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
-
-static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0;
-
-       pci_read_config_dword(pdev, basereg + 4, &format);
-       format = (format >> 31) & 1;
-       if (format)
-               format += sc1200_get_pci_clock();
-       pci_write_config_dword(pdev, basereg + ((drive->dn & 1) << 3),
-                              sc1200_pio_timings[format][pio]);
-}
-
-/*
- *     The SC1200 specifies that two drives sharing a cable cannot mix
- *     UDMA/MDMA.  It has to be one or the other, for the pair, though
- *     different timings can still be chosen for each drive.  We could
- *     set the appropriate timing bits on the fly, but that might be
- *     a bit confusing.  So, for now we statically handle this requirement
- *     by looking at our mate drive to see what it is capable of, before
- *     choosing a mode for our own drive.
- */
-static u8 sc1200_udma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *mate = ide_get_pair_dev(drive);
-       u16 *mateid;
-       u8 mask = hwif->ultra_mask;
-
-       if (mate == NULL)
-               goto out;
-       mateid = mate->id;
-
-       if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
-               if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
-                   (mateid[ATA_ID_UDMA_MODES] & 7))
-                       goto out;
-               if (mateid[ATA_ID_MWDMA_MODES] & 7)
-                       mask = 0;
-       }
-out:
-       return mask;
-}
-
-static void sc1200_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev          *dev = to_pci_dev(hwif->dev);
-       unsigned int            reg, timings;
-       unsigned short          pci_clock;
-       unsigned int            basereg = hwif->channel ? 0x50 : 0x40;
-       const u8                mode = drive->dma_mode;
-
-       static const u32 udma_timing[3][3] = {
-               { 0x00921250, 0x00911140, 0x00911030 },
-               { 0x00932470, 0x00922260, 0x00922140 },
-               { 0x009436a1, 0x00933481, 0x00923261 },
-       };
-
-       static const u32 mwdma_timing[3][3] = {
-               { 0x00077771, 0x00012121, 0x00002020 },
-               { 0x000bbbb2, 0x00024241, 0x00013131 },
-               { 0x000ffff3, 0x00035352, 0x00015151 },
-       };
-
-       pci_clock = sc1200_get_pci_clock();
-
-       /*
-        * Note that each DMA mode has several timings associated with it.
-        * The correct timing depends on the fast PCI clock freq.
-        */
-
-       if (mode >= XFER_UDMA_0)
-               timings =  udma_timing[pci_clock][mode - XFER_UDMA_0];
-       else
-               timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
-
-       if ((drive->dn & 1) == 0) {
-               pci_read_config_dword(dev, basereg + 4, &reg);
-               timings |= reg & 0x80000000;    /* preserve PIO format bit */
-               pci_write_config_dword(dev, basereg + 4, timings);
-       } else
-               pci_write_config_dword(dev, basereg + 12, timings);
-}
-
-/*  Replacement for the standard ide_dma_end action in
- *  dma_proc.
- *
- *  returns 1 on error, 0 otherwise
- */
-static int sc1200_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned long dma_base = hwif->dma_base;
-       u8 dma_stat;
-
-       dma_stat = inb(dma_base+2);             /* get DMA status */
-
-       if (!(dma_stat & 4))
-               printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
-                 dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
-
-       outb(dma_stat|0x1b, dma_base+2);        /* clear the INTR & ERROR bits */
-       outb(inb(dma_base)&~1, dma_base);       /* !! DO THIS HERE !! stop DMA */
-
-       return (dma_stat & 7) != 4;             /* verify good DMA status */
-}
-
-/*
- * sc1200_set_pio_mode() handles setting of PIO modes
- * for both the chipset and drive.
- *
- * All existing BIOSs for this chipset guarantee that all drives
- * will have valid default PIO timings set up before we get here.
- */
-
-static void sc1200_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int             mode = -1;
-       const u8        pio = drive->pio_mode - XFER_PIO_0;
-
-       /*
-        * bad abuse of ->set_pio_mode interface
-        */
-       switch (pio) {
-               case 200: mode = XFER_UDMA_0;   break;
-               case 201: mode = XFER_UDMA_1;   break;
-               case 202: mode = XFER_UDMA_2;   break;
-               case 100: mode = XFER_MW_DMA_0; break;
-               case 101: mode = XFER_MW_DMA_1; break;
-               case 102: mode = XFER_MW_DMA_2; break;
-       }
-       if (mode != -1) {
-               printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
-               ide_dma_off_quietly(drive);
-               if (ide_set_dma_mode(drive, mode) == 0 &&
-                   (drive->dev_flags & IDE_DFLAG_USING_DMA))
-                       hwif->dma_ops->dma_host_set(drive, 1);
-               return;
-       }
-
-       sc1200_tunepio(drive, pio);
-}
-
-#ifdef CONFIG_PM
-struct sc1200_saved_state {
-       u32 regs[8];
-};
-
-static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
-{
-       printk("SC1200: suspend(%u)\n", state.event);
-
-       /*
-        * we only save state when going from full power to less
-        */
-       if (state.event == PM_EVENT_ON) {
-               struct ide_host *host = pci_get_drvdata(dev);
-               struct sc1200_saved_state *ss = host->host_priv;
-               unsigned int r;
-
-               /*
-                * save timing registers
-                * (this may be unnecessary if BIOS also does it)
-                */
-               for (r = 0; r < 8; r++)
-                       pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
-       }
-
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-       return 0;
-}
-
-static int sc1200_resume (struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct sc1200_saved_state *ss = host->host_priv;
-       unsigned int r;
-       int i;
-
-       i = pci_enable_device(dev);
-       if (i)
-               return i;
-
-       /*
-        * restore timing registers
-        * (this may be unnecessary if BIOS also does it)
-        */
-       for (r = 0; r < 8; r++)
-               pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
-
-       return 0;
-}
-#endif
-
-static const struct ide_port_ops sc1200_port_ops = {
-       .set_pio_mode           = sc1200_set_pio_mode,
-       .set_dma_mode           = sc1200_set_dma_mode,
-       .udma_filter            = sc1200_udma_filter,
-};
-
-static const struct ide_dma_ops sc1200_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = sc1200_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info sc1200_chipset = {
-       .name           = DRV_NAME,
-       .port_ops       = &sc1200_port_ops,
-       .dma_ops        = &sc1200_dma_ops,
-       .host_flags     = IDE_HFLAG_SERIALIZE |
-                         IDE_HFLAG_POST_SET_MODE |
-                         IDE_HFLAG_ABUSE_DMA_MODES,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA2,
-};
-
-static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct sc1200_saved_state *ss = NULL;
-       int rc;
-
-#ifdef CONFIG_PM
-       ss = kmalloc(sizeof(*ss), GFP_KERNEL);
-       if (ss == NULL)
-               return -ENOMEM;
-#endif
-       rc = ide_pci_init_one(dev, &sc1200_chipset, ss);
-       if (rc)
-               kfree(ss);
-
-       return rc;
-}
-
-static const struct pci_device_id sc1200_pci_tbl[] = {
-       { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
-
-static struct pci_driver sc1200_pci_driver = {
-       .name           = "SC1200_IDE",
-       .id_table       = sc1200_pci_tbl,
-       .probe          = sc1200_init_one,
-       .remove         = ide_pci_remove,
-#ifdef CONFIG_PM
-       .suspend        = sc1200_suspend,
-       .resume         = sc1200_resume,
-#endif
-};
-
-static int __init sc1200_ide_init(void)
-{
-       return ide_pci_register_driver(&sc1200_pci_driver);
-}
-
-static void __exit sc1200_ide_exit(void)
-{
-       pci_unregister_driver(&sc1200_pci_driver);
-}
-
-module_init(sc1200_ide_init);
-module_exit(sc1200_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
deleted file mode 100644 (file)
index 458e72e..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1998-2000 Michel Aubry
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- * Portions copyright (c) 2001 Sun Microsystems
- *
- *
- * RCC/ServerWorks IDE driver for Linux
- *
- *   OSB4: `Open South Bridge' IDE Interface (fn 1)
- *         supports UDMA mode 2 (33 MB/s)
- *
- *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
- *         all revisions support UDMA mode 4 (66 MB/s)
- *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
- *
- *         *** The CSB5 does not provide ANY register ***
- *         *** to detect 80-conductor cable presence. ***
- *
- *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
- *
- *   HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE
- *   controller same as the CSB6. Single channel ATA100 only.
- *
- * Documentation:
- *     Available under NDA only. Errata info very hard to get.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "serverworks"
-
-#define SVWKS_CSB5_REVISION_NEW        0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-#define SVWKS_CSB6_REVISION    0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
-
-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
- * can overrun their FIFOs when used with the CSB5 */
-static const char *svwks_bad_ata100[] = {
-       "ST320011A",
-       "ST340016A",
-       "ST360021A",
-       "ST380021A",
-       NULL
-};
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-       char *m = (char *)&drive->id[ATA_ID_PROD];
-
-       while (*list)
-               if (!strcmp(*list++, m))
-                       return 1;
-       return 0;
-}
-
-static u8 svwks_udma_filter(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-
-       if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
-               return 0x1f;
-       } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) {
-               return 0x07;
-       } else {
-               u8 btr = 0, mode, mask;
-
-               pci_read_config_byte(dev, 0x5A, &btr);
-               mode = btr & 0x3;
-
-               /* If someone decides to do UDMA133 on CSB5 the same
-                  issue will bite so be inclusive */
-               if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
-                       mode = 2;
-
-               switch(mode) {
-               case 3:  mask = 0x3f; break;
-               case 2:  mask = 0x1f; break;
-               case 1:  mask = 0x07; break;
-               default: mask = 0x00; break;
-               }
-
-               return mask;
-       }
-}
-
-static u8 svwks_csb_check (struct pci_dev *dev)
-{
-       switch (dev->device) {
-               case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-               case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
-               case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
-               case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
-                       return 1;
-               default:
-                       break;
-       }
-       return 0;
-}
-
-static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-       static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
-
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       if (drive->dn >= ARRAY_SIZE(drive_pci))
-               return;
-
-       pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
-
-       if (svwks_csb_check(dev)) {
-               u16 csb_pio = 0;
-
-               pci_read_config_word(dev, 0x4a, &csb_pio);
-
-               csb_pio &= ~(0x0f << (4 * drive->dn));
-               csb_pio |= (pio << (4 * drive->dn));
-
-               pci_write_config_word(dev, 0x4a, csb_pio);
-       }
-}
-
-static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u8 udma_modes[]            = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-       static const u8 dma_modes[]             = { 0x77, 0x21, 0x20 };
-       static const u8 drive_pci2[]            = { 0x45, 0x44, 0x47, 0x46 };
-
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       const u8 speed          = drive->dma_mode;
-       u8 unit                 = drive->dn & 1;
-
-       u8 ultra_enable  = 0, ultra_timing = 0, dma_timing = 0;
-
-       if (drive->dn >= ARRAY_SIZE(drive_pci2))
-               return;
-
-       pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
-       pci_read_config_byte(dev, 0x54, &ultra_enable);
-
-       ultra_timing    &= ~(0x0F << (4*unit));
-       ultra_enable    &= ~(0x01 << drive->dn);
-
-       if (speed >= XFER_UDMA_0) {
-               dma_timing   |= dma_modes[2];
-               ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
-               ultra_enable |= (0x01 << drive->dn);
-       } else if (speed >= XFER_MW_DMA_0)
-               dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
-
-       pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
-       pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
-       pci_write_config_byte(dev, 0x54, ultra_enable);
-}
-
-static int init_chipset_svwks(struct pci_dev *dev)
-{
-       unsigned int reg;
-       u8 btr;
-
-       /* force Master Latency Timer value to 64 PCICLKs */
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
-       /* OSB4 : South Bridge and IDE */
-       if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-               struct pci_dev *isa_dev =
-                       pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
-                                       PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
-               if (isa_dev) {
-                       pci_read_config_dword(isa_dev, 0x64, &reg);
-                       reg &= ~0x00002000; /* disable 600ns interrupt mask */
-                       if(!(reg & 0x00004000))
-                               printk(KERN_DEBUG DRV_NAME " %s: UDMA not BIOS "
-                                       "enabled.\n", pci_name(dev));
-                       reg |=  0x00004000; /* enable UDMA/33 support */
-                       pci_write_config_dword(isa_dev, 0x64, reg);
-                       pci_dev_put(isa_dev);
-               }
-       }
-
-       /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
-       else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
-                (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
-                (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
-
-               /* Third Channel Test */
-               if (!(PCI_FUNC(dev->devfn) & 1)) {
-                       struct pci_dev * findev = NULL;
-                       u32 reg4c = 0;
-                       findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
-                               PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
-                       if (findev) {
-                               pci_read_config_dword(findev, 0x4C, &reg4c);
-                               reg4c &= ~0x000007FF;
-                               reg4c |=  0x00000040;
-                               reg4c |=  0x00000020;
-                               pci_write_config_dword(findev, 0x4C, reg4c);
-                               pci_dev_put(findev);
-                       }
-                       outb_p(0x06, 0x0c00);
-                       dev->irq = inb_p(0x0c01);
-               } else {
-                       struct pci_dev * findev = NULL;
-                       u8 reg41 = 0;
-
-                       findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
-                                       PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
-                       if (findev) {
-                               pci_read_config_byte(findev, 0x41, &reg41);
-                               reg41 &= ~0x40;
-                               pci_write_config_byte(findev, 0x41, reg41);
-                               pci_dev_put(findev);
-                       }
-                       /*
-                        * This is a device pin issue on CSB6.
-                        * Since there will be a future raid mode,
-                        * early versions of the chipset require the
-                        * interrupt pin to be set, and it is a compatibility
-                        * mode issue.
-                        */
-                       if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
-                               dev->irq = 0;
-               }
-//             pci_read_config_dword(dev, 0x40, &pioreg)
-//             pci_write_config_dword(dev, 0x40, 0x99999999);
-//             pci_read_config_dword(dev, 0x44, &dmareg);
-//             pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
-               /* setup the UDMA Control register
-                *
-                * 1. clear bit 6 to enable DMA
-                * 2. enable DMA modes with bits 0-1
-                *      00 : legacy
-                *      01 : udma2
-                *      10 : udma2/udma4
-                *      11 : udma2/udma4/udma5
-                */
-               pci_read_config_byte(dev, 0x5A, &btr);
-               btr &= ~0x40;
-               if (!(PCI_FUNC(dev->devfn) & 1))
-                       btr |= 0x2;
-               else
-                       btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
-               pci_write_config_byte(dev, 0x5A, btr);
-       }
-       /* Setup HT1000 SouthBridge Controller - Single Channel Only */
-       else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
-               pci_read_config_byte(dev, 0x5A, &btr);
-               btr &= ~0x40;
-               btr |= 0x3;
-               pci_write_config_byte(dev, 0x5A, btr);
-       }
-
-       return 0;
-}
-
-static u8 ata66_svwks_svwks(ide_hwif_t *hwif)
-{
-       return ATA_CBL_PATA80;
-}
-
-/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
- * of the subsystem device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set   = secondary IDE channel has 80-pin cable.
- * Bit 14 clear = primary IDE channel does not have 80-pin cable.
- * Bit 14 set   = primary IDE channel has 80-pin cable.
- */
-static u8 ata66_svwks_dell(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-           dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
-           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
-            dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
-               return ((1 << (hwif->channel + 14)) &
-                       dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-       return ATA_CBL_PATA40;
-}
-
-/* Sun Cobalt Alpine hardware avoids the 80-pin cable
- * detect issue by attaching the drives directly to the board.
- * This check follows the Dell precedent (how scary is that?!)
- *
- * WARNING: this only works on Alpine hardware!
- */
-static u8 ata66_svwks_cobalt(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
-           dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
-           dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-               return ((1 << (hwif->channel + 14)) &
-                       dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-       return ATA_CBL_PATA40;
-}
-
-static u8 svwks_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       /* Server Works */
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
-               return ata66_svwks_svwks (hwif);
-       
-       /* Dell PowerEdge */
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
-               return ata66_svwks_dell (hwif);
-
-       /* Cobalt Alpine */
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
-               return ata66_svwks_cobalt (hwif);
-
-       /* Per Specified Design by OEM, and ASIC Architect */
-       if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
-           (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
-               return ATA_CBL_PATA80;
-
-       return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops osb4_port_ops = {
-       .set_pio_mode           = svwks_set_pio_mode,
-       .set_dma_mode           = svwks_set_dma_mode,
-};
-
-static const struct ide_port_ops svwks_port_ops = {
-       .set_pio_mode           = svwks_set_pio_mode,
-       .set_dma_mode           = svwks_set_dma_mode,
-       .udma_filter            = svwks_udma_filter,
-       .cable_detect           = svwks_cable_detect,
-};
-
-static const struct ide_port_info serverworks_chipsets[] = {
-       {       /* 0: OSB4 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_svwks,
-               .port_ops       = &osb4_port_ops,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = 0x00, /* UDMA is problematic on OSB4 */
-       },
-       {       /* 1: CSB5 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_svwks,
-               .port_ops       = &svwks_port_ops,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-       {       /* 2: CSB6 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_svwks,
-               .port_ops       = &svwks_port_ops,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-       {       /* 3: CSB6-2 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_svwks,
-               .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAG_SINGLE,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       },
-       {       /* 4: HT1000 */
-               .name           = DRV_NAME,
-               .init_chipset   = init_chipset_svwks,
-               .port_ops       = &svwks_port_ops,
-               .host_flags     = IDE_HFLAG_SINGLE,
-               .pio_mask       = ATA_PIO4,
-               .mwdma_mask     = ATA_MWDMA2,
-               .udma_mask      = ATA_UDMA5,
-       }
-};
-
-/**
- *     svwks_init_one  -       called when a OSB/CSB is found
- *     @dev: the svwks device
- *     @id: the matching pci id
- *
- *     Called when the PCI registration layer (or the IDE initialization)
- *     finds a device matching our IDE device tables.
- */
-static int svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-
-       d = serverworks_chipsets[idx];
-
-       if (idx == 1)
-               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
-       else if (idx == 2 || idx == 3) {
-               if ((PCI_FUNC(dev->devfn) & 1) == 0) {
-                       if (pci_resource_start(dev, 0) != 0x01f1)
-                               d.host_flags |= IDE_HFLAG_NON_BOOTABLE;
-                       d.host_flags |= IDE_HFLAG_SINGLE;
-               } else
-                       d.host_flags &= ~IDE_HFLAG_SINGLE;
-       }
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id svwks_pci_tbl[] = {
-       { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE),   0 },
-       { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE),   1 },
-       { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE),   2 },
-       { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2),  3 },
-       { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
-
-static struct pci_driver svwks_pci_driver = {
-       .name           = "Serverworks_IDE",
-       .id_table       = svwks_pci_tbl,
-       .probe          = svwks_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init svwks_ide_init(void)
-{
-       return ide_pci_register_driver(&svwks_pci_driver);
-}
-
-static void __exit svwks_ide_exit(void)
-{
-       pci_unregister_driver(&svwks_pci_driver);
-}
-
-module_init(svwks_ide_init);
-module_exit(svwks_ide_exit);
-
-MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
deleted file mode 100644 (file)
index fdc8e81..0000000
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 1995-1998  Mark Lord
- *  Copyright (C) 2007-2009  Bartlomiej Zolnierkiewicz
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-
-/**
- *     ide_setup_pci_baseregs  -       place a PCI IDE controller native
- *     @dev: PCI device of interface to switch native
- *     @name: Name of interface
- *
- *     We attempt to place the PCI interface into PCI native mode. If
- *     we succeed the BARs are ok and the controller is in PCI mode.
- *     Returns 0 on success or an errno code.
- *
- *     FIXME: if we program the interface and then fail to set the BARS
- *     we don't switch it back to legacy mode. Do we actually care ??
- */
-
-static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name)
-{
-       u8 progif = 0;
-
-       /*
-        * Place both IDE interfaces into PCI "native" mode:
-        */
-       if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
-                        (progif & 5) != 5) {
-               if ((progif & 0xa) != 0xa) {
-                       printk(KERN_INFO "%s %s: device not capable of full "
-                               "native PCI mode\n", name, pci_name(dev));
-                       return -EOPNOTSUPP;
-               }
-               printk(KERN_INFO "%s %s: placing both ports into native PCI "
-                       "mode\n", name, pci_name(dev));
-               (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-               if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
-                   (progif & 5) != 5) {
-                       printk(KERN_ERR "%s %s: rewrite of PROGIF failed, "
-                               "wanted 0x%04x, got 0x%04x\n",
-                               name, pci_name(dev), progif | 5, progif);
-                       return -EOPNOTSUPP;
-               }
-       }
-       return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-static int ide_pci_clear_simplex(unsigned long dma_base, const char *name)
-{
-       u8 dma_stat = inb(dma_base + 2);
-
-       outb(dma_stat & 0x60, dma_base + 2);
-       dma_stat = inb(dma_base + 2);
-
-       return (dma_stat & 0x80) ? 1 : 0;
-}
-
-/**
- *     ide_pci_dma_base        -       setup BMIBA
- *     @hwif: IDE interface
- *     @d: IDE port info
- *
- *     Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
- */
-
-unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long dma_base = 0;
-
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               return hwif->dma_base;
-
-       if (hwif->mate && hwif->mate->dma_base) {
-               dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-       } else {
-               u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4;
-
-               dma_base = pci_resource_start(dev, baridx);
-
-               if (dma_base == 0) {
-                       printk(KERN_ERR "%s %s: DMA base is invalid\n",
-                               d->name, pci_name(dev));
-                       return 0;
-               }
-       }
-
-       if (hwif->channel)
-               dma_base += 8;
-
-       return dma_base;
-}
-EXPORT_SYMBOL_GPL(ide_pci_dma_base);
-
-int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 dma_stat;
-
-       if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520))
-               goto out;
-
-       if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
-               if (ide_pci_clear_simplex(hwif->dma_base, d->name))
-                       printk(KERN_INFO "%s %s: simplex device: DMA forced\n",
-                               d->name, pci_name(dev));
-               goto out;
-       }
-
-       /*
-        * If the device claims "simplex" DMA, this means that only one of
-        * the two interfaces can be trusted with DMA at any point in time
-        * (so we should enable DMA only on one of the two interfaces).
-        *
-        * FIXME: At this point we haven't probed the drives so we can't make
-        * the appropriate decision.  Really we should defer this problem until
-        * we tune the drive then try to grab DMA ownership if we want to be
-        * the DMA end.  This has to be become dynamic to handle hot-plug.
-        */
-       dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-       if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
-               printk(KERN_INFO "%s %s: simplex device: DMA disabled\n",
-                       d->name, pci_name(dev));
-               return -1;
-       }
-out:
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_check_simplex);
-
-/*
- * Set up BM-DMA capability (PnP BIOS should have done this)
- */
-int ide_pci_set_master(struct pci_dev *dev, const char *name)
-{
-       u16 pcicmd;
-
-       pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-
-       if ((pcicmd & PCI_COMMAND_MASTER) == 0) {
-               pci_set_master(dev);
-
-               if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) ||
-                   (pcicmd & PCI_COMMAND_MASTER) == 0) {
-                       printk(KERN_ERR "%s %s: error updating PCICMD\n",
-                               name, pci_name(dev));
-                       return -EIO;
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_set_master);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
-
-void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
-{
-       printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n",
-               d->name, pci_name(dev),
-               dev->vendor, dev->device, dev->revision);
-}
-EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
-
-
-/**
- *     ide_pci_enable  -       do PCI enables
- *     @dev: PCI device
- *     @bars: PCI BARs mask
- *     @d: IDE port info
- *
- *     Enable the IDE PCI device. We attempt to enable the device in full
- *     but if that fails then we only need IO space. The PCI code should
- *     have setup the proper resources for us already for controllers in
- *     legacy mode.
- *
- *     Returns zero on success or an error code
- */
-
-static int ide_pci_enable(struct pci_dev *dev, int bars,
-                         const struct ide_port_info *d)
-{
-       int ret;
-
-       if (pci_enable_device(dev)) {
-               ret = pci_enable_device_io(dev);
-               if (ret < 0) {
-                       printk(KERN_WARNING "%s %s: couldn't enable device\n",
-                               d->name, pci_name(dev));
-                       goto out;
-               }
-               printk(KERN_WARNING "%s %s: BIOS configuration fixed\n",
-                       d->name, pci_name(dev));
-       }
-
-       /*
-        * assume all devices can do 32-bit DMA for now, we can add
-        * a DMA mask field to the struct ide_port_info if we need it
-        * (or let lower level driver set the DMA mask)
-        */
-       ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
-       if (ret < 0) {
-               printk(KERN_ERR "%s %s: can't set DMA mask\n",
-                       d->name, pci_name(dev));
-               goto out;
-       }
-
-       ret = pci_request_selected_regions(dev, bars, d->name);
-       if (ret < 0)
-               printk(KERN_ERR "%s %s: can't reserve resources\n",
-                       d->name, pci_name(dev));
-out:
-       return ret;
-}
-
-/**
- *     ide_pci_configure       -       configure an unconfigured device
- *     @dev: PCI device
- *     @d: IDE port info
- *
- *     Enable and configure the PCI device we have been passed.
- *     Returns zero on success or an error code.
- */
-
-static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
-{
-       u16 pcicmd = 0;
-       /*
-        * PnP BIOS was *supposed* to have setup this device, but we
-        * can do it ourselves, so long as the BIOS has assigned an IRQ
-        * (or possibly the device is using a "legacy header" for IRQs).
-        * Maybe the user deliberately *disabled* the device,
-        * but we'll eventually ignore it again if no drives respond.
-        */
-       if (ide_setup_pci_baseregs(dev, d->name) ||
-           pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-               printk(KERN_INFO "%s %s: device disabled (BIOS)\n",
-                       d->name, pci_name(dev));
-               return -ENODEV;
-       }
-       if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-               printk(KERN_ERR "%s %s: error accessing PCI regs\n",
-                       d->name, pci_name(dev));
-               return -EIO;
-       }
-       if (!(pcicmd & PCI_COMMAND_IO)) {
-               printk(KERN_ERR "%s %s: unable to enable IDE controller\n",
-                       d->name, pci_name(dev));
-               return -ENXIO;
-       }
-       return 0;
-}
-
-/**
- *     ide_pci_check_iomem     -       check a register is I/O
- *     @dev: PCI device
- *     @d: IDE port info
- *     @bar: BAR number
- *
- *     Checks if a BAR is configured and points to MMIO space. If so,
- *     return an error code. Otherwise return 0
- */
-
-static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d,
-                              int bar)
-{
-       ulong flags = pci_resource_flags(dev, bar);
-
-       /* Unconfigured ? */
-       if (!flags || pci_resource_len(dev, bar) == 0)
-               return 0;
-
-       /* I/O space */
-       if (flags & IORESOURCE_IO)
-               return 0;
-
-       /* Bad */
-       return -EINVAL;
-}
-
-/**
- *     ide_hw_configure        -       configure a struct ide_hw instance
- *     @dev: PCI device holding interface
- *     @d: IDE port info
- *     @port: port number
- *     @hw: struct ide_hw instance corresponding to this port
- *
- *     Perform the initial set up for the hardware interface structure. This
- *     is done per interface port rather than per PCI device. There may be
- *     more than one port per device.
- *
- *     Returns zero on success or an error code.
- */
-
-static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
-                           unsigned int port, struct ide_hw *hw)
-{
-       unsigned long ctl = 0, base = 0;
-
-       if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
-               if (ide_pci_check_iomem(dev, d, 2 * port) ||
-                   ide_pci_check_iomem(dev, d, 2 * port + 1)) {
-                       printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are "
-                               "reported as MEM for port %d!\n",
-                               d->name, pci_name(dev), port);
-                       return -EINVAL;
-               }
-
-               ctl  = pci_resource_start(dev, 2*port+1);
-               base = pci_resource_start(dev, 2*port);
-       } else {
-               /* Use default values */
-               ctl = port ? 0x374 : 0x3f4;
-               base = port ? 0x170 : 0x1f0;
-       }
-
-       if (!base || !ctl) {
-               printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n",
-                       d->name, pci_name(dev), port);
-               return -EINVAL;
-       }
-
-       memset(hw, 0, sizeof(*hw));
-       hw->dev = &dev->dev;
-       ide_std_init_ports(hw, base, ctl | 2);
-
-       return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-/**
- *     ide_hwif_setup_dma      -       configure DMA interface
- *     @hwif: IDE interface
- *     @d: IDE port info
- *
- *     Set up the DMA base for the interface. Enable the master bits as
- *     necessary and attempt to bring the device DMA into a ready to use
- *     state
- */
-
-int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-
-       if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
-           ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
-            (dev->class & 0x80))) {
-               unsigned long base = ide_pci_dma_base(hwif, d);
-
-               if (base == 0)
-                       return -1;
-
-               hwif->dma_base = base;
-
-               if (hwif->dma_ops == NULL)
-                       hwif->dma_ops = &sff_dma_ops;
-
-               if (ide_pci_check_simplex(hwif, d) < 0)
-                       return -1;
-
-               if (ide_pci_set_master(dev, d->name) < 0)
-                       return -1;
-
-               if (hwif->host_flags & IDE_HFLAG_MMIO)
-                       printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
-               else
-                       printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx\n",
-                                        hwif->name, base, base + 7);
-
-               hwif->extra_base = base + (hwif->channel ? 8 : 16);
-
-               if (ide_allocate_dma_engine(hwif))
-                       return -1;
-       }
-
-       return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
-
-/**
- *     ide_setup_pci_controller        -       set up IDE PCI
- *     @dev: PCI device
- *     @bars: PCI BARs mask
- *     @d: IDE port info
- *     @noisy: verbose flag
- *
- *     Set up the PCI and controller side of the IDE interface. This brings
- *     up the PCI side of the device, checks that the device is enabled
- *     and enables it if need be
- */
-
-static int ide_setup_pci_controller(struct pci_dev *dev, int bars,
-                                   const struct ide_port_info *d, int noisy)
-{
-       int ret;
-       u16 pcicmd;
-
-       if (noisy)
-               ide_setup_pci_noise(dev, d);
-
-       ret = ide_pci_enable(dev, bars, d);
-       if (ret < 0)
-               goto out;
-
-       ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-       if (ret < 0) {
-               printk(KERN_ERR "%s %s: error accessing PCI regs\n",
-                       d->name, pci_name(dev));
-               goto out_free_bars;
-       }
-       if (!(pcicmd & PCI_COMMAND_IO)) {       /* is device disabled? */
-               ret = ide_pci_configure(dev, d);
-               if (ret < 0)
-                       goto out_free_bars;
-               printk(KERN_INFO "%s %s: device enabled (Linux)\n",
-                       d->name, pci_name(dev));
-       }
-
-       goto out;
-
-out_free_bars:
-       pci_release_selected_regions(dev, bars);
-out:
-       return ret;
-}
-
-/**
- *     ide_pci_setup_ports     -       configure ports/devices on PCI IDE
- *     @dev: PCI device
- *     @d: IDE port info
- *     @hw: struct ide_hw instances corresponding to this PCI IDE device
- *     @hws: struct ide_hw pointers table to update
- *
- *     Scan the interfaces attached to this device and do any
- *     necessary per port setup. Attach the devices and ask the
- *     generic DMA layer to do its work for us.
- *
- *     Normally called automaticall from do_ide_pci_setup_device,
- *     but is also used directly as a helper function by some controllers
- *     where the chipset setup is not the default PCI IDE one.
- */
-
-void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
-                        struct ide_hw *hw, struct ide_hw **hws)
-{
-       int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
-       u8 tmp;
-
-       /*
-        * Set up the IDE ports
-        */
-
-       for (port = 0; port < channels; ++port) {
-               const struct ide_pci_enablebit *e = &d->enablebits[port];
-
-               if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-                   (tmp & e->mask) != e->val)) {
-                       printk(KERN_INFO "%s %s: IDE port disabled\n",
-                               d->name, pci_name(dev));
-                       continue;       /* port not enabled */
-               }
-
-               if (ide_hw_configure(dev, d, port, hw + port))
-                       continue;
-
-               *(hws + port) = hw + port;
-       }
-}
-EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the struct ide_port_info;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-static int do_ide_setup_pci_device(struct pci_dev *dev,
-                                  const struct ide_port_info *d,
-                                  u8 noisy)
-{
-       int pciirq, ret;
-
-       /*
-        * Can we trust the reported IRQ?
-        */
-       pciirq = dev->irq;
-
-       /*
-        * This allows offboard ide-pci cards the enable a BIOS,
-        * verify interrupt settings of split-mirror pci-config
-        * space, place chipset into init-mode, and/or preserve
-        * an interrupt if the card is not native ide support.
-        */
-       ret = d->init_chipset ? d->init_chipset(dev) : 0;
-       if (ret < 0)
-               goto out;
-
-       if (ide_pci_is_in_compatibility_mode(dev)) {
-               if (noisy)
-                       printk(KERN_INFO "%s %s: not 100%% native mode: will "
-                               "probe irqs later\n", d->name, pci_name(dev));
-               pciirq = 0;
-       } else if (!pciirq && noisy) {
-               printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n",
-                       d->name, pci_name(dev), pciirq);
-       } else if (noisy) {
-               printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n",
-                       d->name, pci_name(dev), pciirq);
-       }
-
-       ret = pciirq;
-out:
-       return ret;
-}
-
-int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
-                    const struct ide_port_info *d, void *priv)
-{
-       struct pci_dev *pdev[] = { dev1, dev2 };
-       struct ide_host *host;
-       int ret, i, n_ports = dev2 ? 4 : 2, bars;
-       struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL };
-
-       if (d->host_flags & IDE_HFLAG_SINGLE)
-               bars = (1 << 2) - 1;
-       else
-               bars = (1 << 4) - 1;
-
-       if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
-               if (d->host_flags & IDE_HFLAG_CS5520)
-                       bars |= (1 << 2);
-               else
-                       bars |= (1 << 4);
-       }
-
-       for (i = 0; i < n_ports / 2; i++) {
-               ret = ide_setup_pci_controller(pdev[i], bars, d, !i);
-               if (ret < 0) {
-                       if (i == 1)
-                               pci_release_selected_regions(pdev[0], bars);
-                       goto out;
-               }
-
-               ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
-       }
-
-       host = ide_host_alloc(d, hws, n_ports);
-       if (host == NULL) {
-               ret = -ENOMEM;
-               goto out_free_bars;
-       }
-
-       host->dev[0] = &dev1->dev;
-       if (dev2)
-               host->dev[1] = &dev2->dev;
-
-       host->host_priv = priv;
-       host->irq_flags = IRQF_SHARED;
-
-       pci_set_drvdata(pdev[0], host);
-       if (dev2)
-               pci_set_drvdata(pdev[1], host);
-
-       for (i = 0; i < n_ports / 2; i++) {
-               ret = do_ide_setup_pci_device(pdev[i], d, !i);
-
-               /*
-                * FIXME: Mom, mom, they stole me the helper function to undo
-                * do_ide_setup_pci_device() on the first device!
-                */
-               if (ret < 0)
-                       goto out_free_bars;
-
-               /* fixup IRQ */
-               if (ide_pci_is_in_compatibility_mode(pdev[i])) {
-                       hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0);
-                       hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1);
-               } else
-                       hw[i*2 + 1].irq = hw[i*2].irq = ret;
-       }
-
-       ret = ide_host_register(host, d, hws);
-       if (ret)
-               ide_host_free(host);
-       else
-               goto out;
-
-out_free_bars:
-       i = n_ports / 2;
-       while (i--)
-               pci_release_selected_regions(pdev[i], bars);
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_two);
-
-int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
-                    void *priv)
-{
-       return ide_pci_init_two(dev, NULL, d, priv);
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_one);
-
-void ide_pci_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-       int bars;
-
-       if (host->host_flags & IDE_HFLAG_SINGLE)
-               bars = (1 << 2) - 1;
-       else
-               bars = (1 << 4) - 1;
-
-       if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) {
-               if (host->host_flags & IDE_HFLAG_CS5520)
-                       bars |= (1 << 2);
-               else
-                       bars |= (1 << 4);
-       }
-
-       ide_host_remove(host);
-
-       if (dev2)
-               pci_release_selected_regions(dev2, bars);
-       pci_release_selected_regions(dev, bars);
-
-       if (dev2)
-               pci_disable_device(dev2);
-       pci_disable_device(dev);
-}
-EXPORT_SYMBOL_GPL(ide_pci_remove);
-
-#ifdef CONFIG_PM
-int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_suspend);
-
-int ide_pci_resume(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       int rc;
-
-       pci_set_power_state(dev, PCI_D0);
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       pci_restore_state(dev);
-       pci_set_master(dev);
-
-       if (host->init_chipset)
-               host->init_chipset(dev);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_resume);
-#endif
diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c
deleted file mode 100644 (file)
index c4b20f3..0000000
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003          Red Hat
- * Copyright (C) 2007-2008     MontaVista Software, Inc.
- * Copyright (C) 2007-2008     Bartlomiej Zolnierkiewicz
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Documentation for CMD680:
- *  http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2
- *
- *  Documentation for SiI 3112:
- *  http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
- *
- *  Errata and other documentation only available under NDA.
- *
- *
- *  FAQ Items:
- *     If you are using Marvell SATA-IDE adapters with Maxtor drives
- *     ensure the system is set up for ATA100/UDMA5, not UDMA6.
- *
- *     If you are using WD drives with SATA bridges you must set the
- *     drive to "Single". "Master" will hang.
- *
- *     If you have strange problems with nVidia chipset systems please
- *     see the SI support documentation and update your system BIOS
- *     if necessary
- *
- *  The Dell DRAC4 has some interesting features including effectively hot
- *  unplugging/replugging the virtual CD interface when the DRAC is reset.
- *  This often causes drivers/ide/siimage to panic but is ok with the rather
- *  smarter code in libata.
- *
- * TODO:
- * - VDMA support
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#define DRV_NAME "siimage"
-
-/**
- *     pdev_is_sata            -       check if device is SATA
- *     @pdev:  PCI device to check
- *
- *     Returns true if this is a SATA controller
- */
-
-static int pdev_is_sata(struct pci_dev *pdev)
-{
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       switch (pdev->device) {
-       case PCI_DEVICE_ID_SII_3112:
-       case PCI_DEVICE_ID_SII_1210SA:
-               return 1;
-       case PCI_DEVICE_ID_SII_680:
-               return 0;
-       }
-       BUG();
-#endif
-       return 0;
-}
-
-/**
- *     is_sata                 -       check if hwif is SATA
- *     @hwif:  interface to check
- *
- *     Returns true if this is a SATA controller
- */
-
-static inline int is_sata(ide_hwif_t *hwif)
-{
-       return pdev_is_sata(to_pci_dev(hwif->dev));
-}
-
-/**
- *     siimage_selreg          -       return register base
- *     @hwif: interface
- *     @r: config offset
- *
- *     Turn a config register offset into the right address in either
- *     PCI space or MMIO space to access the control register in question
- *     Thankfully this is a configuration operation, so isn't performance
- *     critical.
- */
-
-static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
-{
-       unsigned long base = (unsigned long)hwif->hwif_data;
-
-       base += 0xA0 + r;
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               base += hwif->channel << 6;
-       else
-               base += hwif->channel << 4;
-       return base;
-}
-
-/**
- *     siimage_seldev          -       return register base
- *     @hwif: interface
- *     @r: config offset
- *
- *     Turn a config register offset into the right address in either
- *     PCI space or MMIO space to access the control register in question
- *     including accounting for the unit shift.
- */
-
-static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       unsigned long base      = (unsigned long)hwif->hwif_data;
-       u8 unit                 = drive->dn & 1;
-
-       base += 0xA0 + r;
-       if (hwif->host_flags & IDE_HFLAG_MMIO)
-               base += hwif->channel << 6;
-       else
-               base += hwif->channel << 4;
-       base |= unit << unit;
-       return base;
-}
-
-static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       u8 tmp = 0;
-
-       if (host->host_priv)
-               tmp = readb((void __iomem *)addr);
-       else
-               pci_read_config_byte(dev, addr, &tmp);
-
-       return tmp;
-}
-
-static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       u16 tmp = 0;
-
-       if (host->host_priv)
-               tmp = readw((void __iomem *)addr);
-       else
-               pci_read_config_word(dev, addr, &tmp);
-
-       return tmp;
-}
-
-static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-
-       if (host->host_priv)
-               writeb(val, (void __iomem *)addr);
-       else
-               pci_write_config_byte(dev, addr, val);
-}
-
-static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-
-       if (host->host_priv)
-               writew(val, (void __iomem *)addr);
-       else
-               pci_write_config_word(dev, addr, val);
-}
-
-static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-
-       if (host->host_priv)
-               writel(val, (void __iomem *)addr);
-       else
-               pci_write_config_dword(dev, addr, val);
-}
-
-/**
- *     sil_udma_filter         -       compute UDMA mask
- *     @drive: IDE device
- *
- *     Compute the available UDMA speeds for the device on the interface.
- *
- *     For the CMD680 this depends on the clocking mode (scsc), for the
- *     SI3112 SATA controller life is a bit simpler.
- */
-
-static u8 sil_pata_udma_filter(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long base      = (unsigned long)hwif->hwif_data;
-       u8 scsc, mask           = 0;
-
-       base += (hwif->host_flags & IDE_HFLAG_MMIO) ? 0x4A : 0x8A;
-
-       scsc = sil_ioread8(dev, base);
-
-       switch (scsc & 0x30) {
-       case 0x10:      /* 133 */
-               mask = ATA_UDMA6;
-               break;
-       case 0x20:      /* 2xPCI */
-               mask = ATA_UDMA6;
-               break;
-       case 0x00:      /* 100 */
-               mask = ATA_UDMA5;
-               break;
-       default:        /* Disabled ? */
-               BUG();
-       }
-
-       return mask;
-}
-
-static u8 sil_sata_udma_filter(ide_drive_t *drive)
-{
-       char *m = (char *)&drive->id[ATA_ID_PROD];
-
-       return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
-}
-
-/**
- *     sil_set_pio_mode        -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Load the timing settings for this device mode into the
- *     controller.
- */
-
-static void sil_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u16 tf_speed[]   = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
-       static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
-
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       ide_drive_t *pair       = ide_get_pair_dev(drive);
-       u32 speedt              = 0;
-       u16 speedp              = 0;
-       unsigned long addr      = siimage_seldev(drive, 0x04);
-       unsigned long tfaddr    = siimage_selreg(hwif,  0x02);
-       unsigned long base      = (unsigned long)hwif->hwif_data;
-       const u8 pio            = drive->pio_mode - XFER_PIO_0;
-       u8 tf_pio               = pio;
-       u8 mmio                 = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 addr_mask            = hwif->channel ? (mmio ? 0xF4 : 0x84)
-                                               : (mmio ? 0xB4 : 0x80);
-       u8 mode                 = 0;
-       u8 unit                 = drive->dn & 1;
-
-       /* trim *taskfile* PIO to the slowest of the master/slave */
-       if (pair) {
-               u8 pair_pio = pair->pio_mode - XFER_PIO_0;
-
-               if (pair_pio < tf_pio)
-                       tf_pio = pair_pio;
-       }
-
-       /* cheat for now and use the docs */
-       speedp = data_speed[pio];
-       speedt = tf_speed[tf_pio];
-
-       sil_iowrite16(dev, speedp, addr);
-       sil_iowrite16(dev, speedt, tfaddr);
-
-       /* now set up IORDY */
-       speedp = sil_ioread16(dev, tfaddr - 2);
-       speedp &= ~0x200;
-
-       mode = sil_ioread8(dev, base + addr_mask);
-       mode &= ~(unit ? 0x30 : 0x03);
-
-       if (ide_pio_need_iordy(drive, pio)) {
-               speedp |= 0x200;
-               mode |= unit ? 0x10 : 0x01;
-       }
-
-       sil_iowrite16(dev, speedp, tfaddr - 2);
-       sil_iowrite8(dev, mode, base + addr_mask);
-}
-
-/**
- *     sil_set_dma_mode        -       set host controller for DMA mode
- *     @hwif: port
- *     @drive: drive
- *
- *     Tune the SiI chipset for the desired DMA mode.
- */
-
-static void sil_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
-       static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
-       static const u16 dma[]   = { 0x2208, 0x10C2, 0x10C1 };
-
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long base      = (unsigned long)hwif->hwif_data;
-       u16 ultra = 0, multi    = 0;
-       u8 mode = 0, unit       = drive->dn & 1;
-       u8 mmio                 = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 scsc = 0, addr_mask  = hwif->channel ? (mmio ? 0xF4 : 0x84)
-                                               : (mmio ? 0xB4 : 0x80);
-       unsigned long ma        = siimage_seldev(drive, 0x08);
-       unsigned long ua        = siimage_seldev(drive, 0x0C);
-       const u8 speed          = drive->dma_mode;
-
-       scsc  = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A));
-       mode  = sil_ioread8 (dev, base + addr_mask);
-       multi = sil_ioread16(dev, ma);
-       ultra = sil_ioread16(dev, ua);
-
-       mode  &= ~(unit ? 0x30 : 0x03);
-       ultra &= ~0x3F;
-       scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
-
-       scsc = is_sata(hwif) ? 1 : scsc;
-
-       if (speed >= XFER_UDMA_0) {
-               multi  = dma[2];
-               ultra |= scsc ? ultra6[speed - XFER_UDMA_0] :
-                               ultra5[speed - XFER_UDMA_0];
-               mode  |= unit ? 0x30 : 0x03;
-       } else {
-               multi = dma[speed - XFER_MW_DMA_0];
-               mode |= unit ? 0x20 : 0x02;
-       }
-
-       sil_iowrite8 (dev, mode, base + addr_mask);
-       sil_iowrite16(dev, multi, ma);
-       sil_iowrite16(dev, ultra, ua);
-}
-
-static int sil_test_irq(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long addr      = siimage_selreg(hwif, 1);
-       u8 val                  = sil_ioread8(dev, addr);
-
-       /* Return 1 if INTRQ asserted */
-       return (val & 8) ? 1 : 0;
-}
-
-/**
- *     siimage_mmio_dma_test_irq       -       check we caused an IRQ
- *     @drive: drive we are testing
- *
- *     Check if we caused an IDE DMA interrupt. We may also have caused
- *     SATA status interrupts, if so we clean them up and continue.
- */
-
-static int siimage_mmio_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       void __iomem *sata_error_addr
-               = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
-
-       if (sata_error_addr) {
-               unsigned long base      = (unsigned long)hwif->hwif_data;
-               u32 ext_stat            = readl((void __iomem *)(base + 0x10));
-               u8 watchdog             = 0;
-
-               if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
-                       u32 sata_error = readl(sata_error_addr);
-
-                       writel(sata_error, sata_error_addr);
-                       watchdog = (sata_error & 0x00680000) ? 1 : 0;
-                       printk(KERN_WARNING "%s: sata_error = 0x%08x, "
-                               "watchdog = %d, %s\n",
-                               drive->name, sata_error, watchdog, __func__);
-               } else
-                       watchdog = (ext_stat & 0x8000) ? 1 : 0;
-
-               ext_stat >>= 16;
-               if (!(ext_stat & 0x0404) && !watchdog)
-                       return 0;
-       }
-
-       /* return 1 if INTR asserted */
-       if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4)
-               return 1;
-
-       return 0;
-}
-
-static int siimage_dma_test_irq(ide_drive_t *drive)
-{
-       if (drive->hwif->host_flags & IDE_HFLAG_MMIO)
-               return siimage_mmio_dma_test_irq(drive);
-       else
-               return ide_dma_test_irq(drive);
-}
-
-/**
- *     sil_sata_reset_poll     -       wait for SATA reset
- *     @drive: drive we are resetting
- *
- *     Poll the SATA phy and see whether it has come back from the dead
- *     yet.
- */
-
-static blk_status_t sil_sata_reset_poll(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       void __iomem *sata_status_addr
-               = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET];
-
-       if (sata_status_addr) {
-               /* SATA Status is available only when in MMIO mode */
-               u32 sata_stat = readl(sata_status_addr);
-
-               if ((sata_stat & 0x03) != 0x03) {
-                       printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
-                                           hwif->name, sata_stat);
-                       return BLK_STS_IOERR;
-               }
-       }
-
-       return BLK_STS_OK;
-}
-
-/**
- *     sil_sata_pre_reset      -       reset hook
- *     @drive: IDE device being reset
- *
- *     For the SATA devices we need to handle recalibration/geometry
- *     differently
- */
-
-static void sil_sata_pre_reset(ide_drive_t *drive)
-{
-       if (drive->media == ide_disk) {
-               drive->special_flags &=
-                       ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE);
-       }
-}
-
-/**
- *     init_chipset_siimage    -       set up an SI device
- *     @dev: PCI device
- *
- *     Perform the initial PCI set up for this device. Attempt to switch
- *     to 133 MHz clocking if the system isn't already set up to do it.
- */
-
-static int init_chipset_siimage(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       void __iomem *ioaddr = host->host_priv;
-       unsigned long base, scsc_addr;
-       u8 rev = dev->revision, tmp;
-
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255);
-
-       if (ioaddr)
-               pci_set_master(dev);
-
-       base = (unsigned long)ioaddr;
-
-       if (ioaddr && pdev_is_sata(dev)) {
-               u32 tmp32, irq_mask;
-
-               /* make sure IDE0/1 interrupts are not masked */
-               irq_mask = (1 << 22) | (1 << 23);
-               tmp32 = readl(ioaddr + 0x48);
-               if (tmp32 & irq_mask) {
-                       tmp32 &= ~irq_mask;
-                       writel(tmp32, ioaddr + 0x48);
-                       readl(ioaddr + 0x48); /* flush */
-               }
-               writel(0, ioaddr + 0x148);
-               writel(0, ioaddr + 0x1C8);
-       }
-
-       sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80);
-       sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84);
-
-       scsc_addr = base ? (base + 0x4A) : 0x8A;
-       tmp = sil_ioread8(dev, scsc_addr);
-
-       switch (tmp & 0x30) {
-       case 0x00:
-               /* On 100 MHz clocking, try and switch to 133 MHz */
-               sil_iowrite8(dev, tmp | 0x10, scsc_addr);
-               break;
-       case 0x30:
-               /* Clocking is disabled, attempt to force 133MHz clocking. */
-               sil_iowrite8(dev, tmp & ~0x20, scsc_addr);
-       case 0x10:
-               /* On 133Mhz clocking. */
-               break;
-       case 0x20:
-               /* On PCIx2 clocking. */
-               break;
-       }
-
-       tmp = sil_ioread8(dev, scsc_addr);
-
-       sil_iowrite8 (dev,       0x72, base + 0xA1);
-       sil_iowrite16(dev,     0x328A, base + 0xA2);
-       sil_iowrite32(dev, 0x62DD62DD, base + 0xA4);
-       sil_iowrite32(dev, 0x43924392, base + 0xA8);
-       sil_iowrite32(dev, 0x40094009, base + 0xAC);
-       sil_iowrite8 (dev,       0x72, base ? (base + 0xE1) : 0xB1);
-       sil_iowrite16(dev,     0x328A, base ? (base + 0xE2) : 0xB2);
-       sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4);
-       sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8);
-       sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC);
-
-       if (base && pdev_is_sata(dev)) {
-               writel(0xFFFF0000, ioaddr + 0x108);
-               writel(0xFFFF0000, ioaddr + 0x188);
-               writel(0x00680000, ioaddr + 0x148);
-               writel(0x00680000, ioaddr + 0x1C8);
-       }
-
-       /* report the clocking mode of the controller */
-       if (!pdev_is_sata(dev)) {
-               static const char *clk_str[] =
-                       { "== 100", "== 133", "== 2X PCI", "DISABLED!" };
-
-               tmp >>= 4;
-               printk(KERN_INFO DRV_NAME " %s: BASE CLOCK %s\n",
-                       pci_name(dev), clk_str[tmp & 3]);
-       }
-
-       return 0;
-}
-
-/**
- *     init_mmio_iops_siimage  -       set up the iops for MMIO
- *     @hwif: interface to set up
- *
- *     The basic setup here is fairly simple, we can use standard MMIO
- *     operations. However we do have to set the taskfile register offsets
- *     by hand as there isn't a standard defined layout for them this time.
- *
- *     The hardware supports buffered taskfiles and also some rather nice
- *     extended PRD tables. For better SI3112 support use the libata driver
- */
-
-static void init_mmio_iops_siimage(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       struct ide_host *host   = pci_get_drvdata(dev);
-       void *addr              = host->host_priv;
-       u8 ch                   = hwif->channel;
-       struct ide_io_ports *io_ports = &hwif->io_ports;
-       unsigned long base;
-
-       /*
-        *      Fill in the basic hwif bits
-        */
-       hwif->host_flags |= IDE_HFLAG_MMIO;
-
-       hwif->hwif_data = addr;
-
-       /*
-        *      Now set up the hw. We have to do this ourselves as the
-        *      MMIO layout isn't the same as the standard port based I/O.
-        */
-       memset(io_ports, 0, sizeof(*io_ports));
-
-       base = (unsigned long)addr;
-       if (ch)
-               base += 0xC0;
-       else
-               base += 0x80;
-
-       /*
-        *      The buffered task file doesn't have status/control, so we
-        *      can't currently use it sanely since we want to use LBA48 mode.
-        */
-       io_ports->data_addr     = base;
-       io_ports->error_addr    = base + 1;
-       io_ports->nsect_addr    = base + 2;
-       io_ports->lbal_addr     = base + 3;
-       io_ports->lbam_addr     = base + 4;
-       io_ports->lbah_addr     = base + 5;
-       io_ports->device_addr   = base + 6;
-       io_ports->status_addr   = base + 7;
-       io_ports->ctl_addr      = base + 10;
-
-       if (pdev_is_sata(dev)) {
-               base = (unsigned long)addr;
-               if (ch)
-                       base += 0x80;
-               hwif->sata_scr[SATA_STATUS_OFFSET]      = base + 0x104;
-               hwif->sata_scr[SATA_ERROR_OFFSET]       = base + 0x108;
-               hwif->sata_scr[SATA_CONTROL_OFFSET]     = base + 0x100;
-       }
-
-       hwif->irq = dev->irq;
-
-       hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00);
-}
-
-static int is_dev_seagate_sata(ide_drive_t *drive)
-{
-       const char *s   = (const char *)&drive->id[ATA_ID_PROD];
-       unsigned len    = strnlen(s, ATA_ID_PROD_LEN);
-
-       if ((len > 4) && (!memcmp(s, "ST", 2)))
-               if ((!memcmp(s + len - 2, "AS", 2)) ||
-                   (!memcmp(s + len - 3, "ASL", 3))) {
-                       printk(KERN_INFO "%s: applying pessimistic Seagate "
-                                        "errata fix\n", drive->name);
-                       return 1;
-               }
-
-       return 0;
-}
-
-/**
- *     sil_quirkproc           -       post probe fixups
- *     @drive: drive
- *
- *     Called after drive probe we use this to decide whether the
- *     Seagate fixup must be applied. This used to be in init_iops but
- *     that can occur before we know what drives are present.
- */
-
-static void sil_quirkproc(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-
-       /* Try and rise the rqsize */
-       if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
-               hwif->rqsize = 128;
-}
-
-/**
- *     init_iops_siimage       -       set up iops
- *     @hwif: interface to set up
- *
- *     Do the basic setup for the SIIMAGE hardware interface
- *     and then do the MMIO setup if we can. This is the first
- *     look in we get for setting up the hwif so that we
- *     can get the iops right before using them.
- */
-
-static void init_iops_siimage(ide_hwif_t *hwif)
-{
-       struct ide_host *host = dev_get_drvdata(hwif->dev);
-
-       hwif->hwif_data = NULL;
-
-       /* Pessimal until we finish probing */
-       hwif->rqsize = 15;
-
-       if (host->host_priv)
-               init_mmio_iops_siimage(hwif);
-}
-
-/**
- *     sil_cable_detect        -       cable detection
- *     @hwif: interface to check
- *
- *     Check for the presence of an ATA66 capable cable on the interface.
- */
-
-static u8 sil_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long addr      = siimage_selreg(hwif, 0);
-       u8 ata66                = sil_ioread8(dev, addr);
-
-       return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops sil_pata_port_ops = {
-       .set_pio_mode           = sil_set_pio_mode,
-       .set_dma_mode           = sil_set_dma_mode,
-       .quirkproc              = sil_quirkproc,
-       .test_irq               = sil_test_irq,
-       .udma_filter            = sil_pata_udma_filter,
-       .cable_detect           = sil_cable_detect,
-};
-
-static const struct ide_port_ops sil_sata_port_ops = {
-       .set_pio_mode           = sil_set_pio_mode,
-       .set_dma_mode           = sil_set_dma_mode,
-       .reset_poll             = sil_sata_reset_poll,
-       .pre_reset              = sil_sata_pre_reset,
-       .quirkproc              = sil_quirkproc,
-       .test_irq               = sil_test_irq,
-       .udma_filter            = sil_sata_udma_filter,
-       .cable_detect           = sil_cable_detect,
-};
-
-static const struct ide_dma_ops sil_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = siimage_dma_test_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-#define DECLARE_SII_DEV(p_ops)                         \
-       {                                               \
-               .name           = DRV_NAME,             \
-               .init_chipset   = init_chipset_siimage, \
-               .init_iops      = init_iops_siimage,    \
-               .port_ops       = p_ops,                \
-               .dma_ops        = &sil_dma_ops,         \
-               .pio_mask       = ATA_PIO4,             \
-               .mwdma_mask     = ATA_MWDMA2,           \
-               .udma_mask      = ATA_UDMA6,            \
-       }
-
-static const struct ide_port_info siimage_chipsets[] = {
-       /* 0: SiI680 */  DECLARE_SII_DEV(&sil_pata_port_ops),
-       /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops)
-};
-
-/**
- *     siimage_init_one        -       PCI layer discovery entry
- *     @dev: PCI device
- *     @id: ident table entry
- *
- *     Called by the PCI code when it finds an SiI680 or SiI3112 controller.
- *     We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       void __iomem *ioaddr = NULL;
-       resource_size_t bar5 = pci_resource_start(dev, 5);
-       unsigned long barsize = pci_resource_len(dev, 5);
-       int rc;
-       struct ide_port_info d;
-       u8 idx = id->driver_data;
-       u8 BA5_EN;
-
-       d = siimage_chipsets[idx];
-
-       if (idx) {
-               static int first = 1;
-
-               if (first) {
-                       printk(KERN_INFO DRV_NAME ": For full SATA support you "
-                               "should use the libata sata_sil module.\n");
-                       first = 0;
-               }
-
-               d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-       }
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       pci_read_config_byte(dev, 0x8A, &BA5_EN);
-       if ((BA5_EN & 0x01) || bar5) {
-               /*
-               * Drop back to PIO if we can't map the MMIO. Some systems
-               * seem to get terminally confused in the PCI spaces.
-               */
-               if (!request_mem_region(bar5, barsize, d.name)) {
-                       printk(KERN_WARNING DRV_NAME " %s: MMIO ports not "
-                               "available\n", pci_name(dev));
-               } else {
-                       ioaddr = pci_ioremap_bar(dev, 5);
-                       if (ioaddr == NULL)
-                               release_mem_region(bar5, barsize);
-               }
-       }
-
-       rc = ide_pci_init_one(dev, &d, ioaddr);
-       if (rc) {
-               if (ioaddr) {
-                       iounmap(ioaddr);
-                       release_mem_region(bar5, barsize);
-               }
-               pci_disable_device(dev);
-       }
-
-       return rc;
-}
-
-static void siimage_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       void __iomem *ioaddr = host->host_priv;
-
-       ide_pci_remove(dev);
-
-       if (ioaddr) {
-               resource_size_t bar5 = pci_resource_start(dev, 5);
-               unsigned long barsize = pci_resource_len(dev, 5);
-
-               iounmap(ioaddr);
-               release_mem_region(bar5, barsize);
-       }
-
-       pci_disable_device(dev);
-}
-
-static const struct pci_device_id siimage_pci_tbl[] = {
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680),    0 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112),   1 },
-       { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 1 },
-#endif
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
-
-static struct pci_driver siimage_pci_driver = {
-       .name           = "SiI_IDE",
-       .id_table       = siimage_pci_tbl,
-       .probe          = siimage_init_one,
-       .remove         = siimage_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init siimage_ide_init(void)
-{
-       return ide_pci_register_driver(&siimage_pci_driver);
-}
-
-static void __exit siimage_ide_exit(void)
-{
-       pci_unregister_driver(&siimage_pci_driver);
-}
-
-module_init(siimage_ide_init);
-module_exit(siimage_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for SiI IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
deleted file mode 100644 (file)
index 1a700be..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002          Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * Copyright (C) 2003          Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (C) 2007-2009     Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan          : for direct support and hardware.
- * Daniela Engert      : for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt       :
- *                       for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620 chipset.
- * ATA100 tests and design on the SiS735 chipset.
- * ATA16/33 support from specs
- * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
- * ATA133 961/962/963 fixes by Vojtech Pavlik <vojtech@suse.cz>
- *
- * Documentation:
- *     SiS chipset documentation available under NDA to companies only
- *      (not to individuals).
- */
-
-/*
- * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original
- * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511
- * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip.
- *
- * Later SiS chipsets integrated the 5513 functionality into the NorthBridge,
- * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We
- * can figure out that we have a more modern and more capable 5513 by looking
- * for the respective NorthBridge IDs.
- *
- * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513
- * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI
- * ID, while the now ATA-133 capable 5513 still has the same PCI ID.
- * Fortunately the 5513 can be 'unmasked' by fiddling with some config space
- * bits, changing its device id to the true one - 5517 for 961 and 5518 for
- * 962/963.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "sis5513"
-
-/* registers layout and init values are chipset family dependent */
-#undef ATA_16
-#define ATA_16         0x01
-#define ATA_33         0x02
-#define ATA_66         0x03
-#define ATA_100a       0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */
-#define ATA_100                0x05
-#define ATA_133a       0x06 /* SiS961b with 133 support */
-#define ATA_133                0x07 /* SiS962/963 */
-
-static u8 chipset_family;
-
-/*
- * Devices supported
- */
-static const struct {
-       const char *name;
-       u16 host_id;
-       u8 chipset_family;
-       u8 flags;
-} SiSHostChipInfo[] = {
-       { "SiS968",     PCI_DEVICE_ID_SI_968,   ATA_133  },
-       { "SiS966",     PCI_DEVICE_ID_SI_966,   ATA_133  },
-       { "SiS965",     PCI_DEVICE_ID_SI_965,   ATA_133  },
-       { "SiS745",     PCI_DEVICE_ID_SI_745,   ATA_100  },
-       { "SiS735",     PCI_DEVICE_ID_SI_735,   ATA_100  },
-       { "SiS733",     PCI_DEVICE_ID_SI_733,   ATA_100  },
-       { "SiS635",     PCI_DEVICE_ID_SI_635,   ATA_100  },
-       { "SiS633",     PCI_DEVICE_ID_SI_633,   ATA_100  },
-
-       { "SiS730",     PCI_DEVICE_ID_SI_730,   ATA_100a },
-       { "SiS550",     PCI_DEVICE_ID_SI_550,   ATA_100a },
-
-       { "SiS640",     PCI_DEVICE_ID_SI_640,   ATA_66   },
-       { "SiS630",     PCI_DEVICE_ID_SI_630,   ATA_66   },
-       { "SiS620",     PCI_DEVICE_ID_SI_620,   ATA_66   },
-       { "SiS540",     PCI_DEVICE_ID_SI_540,   ATA_66   },
-       { "SiS530",     PCI_DEVICE_ID_SI_530,   ATA_66   },
-
-       { "SiS5600",    PCI_DEVICE_ID_SI_5600,  ATA_33   },
-       { "SiS5598",    PCI_DEVICE_ID_SI_5598,  ATA_33   },
-       { "SiS5597",    PCI_DEVICE_ID_SI_5597,  ATA_33   },
-       { "SiS5591/2",  PCI_DEVICE_ID_SI_5591,  ATA_33   },
-       { "SiS5582",    PCI_DEVICE_ID_SI_5582,  ATA_33   },
-       { "SiS5581",    PCI_DEVICE_ID_SI_5581,  ATA_33   },
-
-       { "SiS5596",    PCI_DEVICE_ID_SI_5596,  ATA_16   },
-       { "SiS5571",    PCI_DEVICE_ID_SI_5571,  ATA_16   },
-       { "SiS5517",    PCI_DEVICE_ID_SI_5517,  ATA_16   },
-       { "SiS551x",    PCI_DEVICE_ID_SI_5511,  ATA_16   },
-};
-
-/* Cycle time bits and values vary across chip dma capabilities
-   These three arrays hold the register layout and the values to set.
-   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-
-/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
-static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 };
-static u8 cycle_time_range[]  = { 0, 0, 2, 3, 3, 4, 4 };
-static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
-       {  0,  0, 0, 0, 0, 0, 0 }, /* no UDMA */
-       {  0,  0, 0, 0, 0, 0, 0 }, /* no UDMA */
-       {  3,  2, 1, 0, 0, 0, 0 }, /* ATA_33 */
-       {  7,  5, 3, 2, 1, 0, 0 }, /* ATA_66 */
-       {  7,  5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific),
-                                     different cycle_time range and offset */
-       { 11,  7, 5, 4, 2, 1, 0 }, /* ATA_100 */
-       { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */
-       { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */
-};
-/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
-   See SiS962 data sheet for more detail */
-static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
-       { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
-       { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
-       { 2, 1, 1, 0, 0, 0, 0 },
-       { 4, 3, 2, 1, 0, 0, 0 },
-       { 4, 3, 2, 1, 0, 0, 0 },
-       { 6, 4, 3, 1, 1, 1, 0 },
-       { 9, 6, 4, 2, 2, 2, 2 },
-       { 9, 6, 4, 2, 2, 2, 2 },
-};
-/* Initialize time, Active time, Recovery time vary across
-   IDE clock settings. These 3 arrays hold the register value
-   for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
-static u8 ini_time_value[][8] = {
-       { 0, 0, 0, 0, 0, 0, 0, 0 },
-       { 0, 0, 0, 0, 0, 0, 0, 0 },
-       { 2, 1, 0, 0, 0, 1, 0, 0 },
-       { 4, 3, 1, 1, 1, 3, 1, 1 },
-       { 4, 3, 1, 1, 1, 3, 1, 1 },
-       { 6, 4, 2, 2, 2, 4, 2, 2 },
-       { 9, 6, 3, 3, 3, 6, 3, 3 },
-       { 9, 6, 3, 3, 3, 6, 3, 3 },
-};
-static u8 act_time_value[][8] = {
-       {  0,  0,  0,  0, 0,  0,  0, 0 },
-       {  0,  0,  0,  0, 0,  0,  0, 0 },
-       {  9,  9,  9,  2, 2,  7,  2, 2 },
-       { 19, 19, 19,  5, 4, 14,  5, 4 },
-       { 19, 19, 19,  5, 4, 14,  5, 4 },
-       { 28, 28, 28,  7, 6, 21,  7, 6 },
-       { 38, 38, 38, 10, 9, 28, 10, 9 },
-       { 38, 38, 38, 10, 9, 28, 10, 9 },
-};
-static u8 rco_time_value[][8] = {
-       {  0,  0, 0,  0, 0,  0,  0, 0 },
-       {  0,  0, 0,  0, 0,  0,  0, 0 },
-       {  9,  2, 0,  2, 0,  7,  1, 1 },
-       { 19,  5, 1,  5, 2, 16,  3, 2 },
-       { 19,  5, 1,  5, 2, 16,  3, 2 },
-       { 30,  9, 3,  9, 4, 25,  6, 4 },
-       { 40, 12, 4, 12, 5, 34, 12, 5 },
-       { 40, 12, 4, 12, 5, 34, 12, 5 },
-};
-
-/*
- * Printing configuration
- */
-/* Used for chipset type printing at boot time */
-static char *chipset_capability[] = {
-       "ATA", "ATA 16",
-       "ATA 33", "ATA 66",
-       "ATA 100 (1st gen)", "ATA 100 (2nd gen)",
-       "ATA 133 (1st gen)", "ATA 133 (2nd gen)"
-};
-
-/*
- * Configuration functions
- */
-
-static u8 sis_ata133_get_base(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u32 reg54 = 0;
-
-       pci_read_config_dword(dev, 0x54, &reg54);
-
-       return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
-}
-
-static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u16 t1 = 0;
-       u8 drive_pci = 0x40 + drive->dn * 2;
-
-       const u16 pio_timings[]   = { 0x000, 0x607, 0x404, 0x303, 0x301 };
-       const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 };
-
-       pci_read_config_word(dev, drive_pci, &t1);
-
-       /* clear active/recovery timings */
-       t1 &= ~0x070f;
-       if (mode >= XFER_MW_DMA_0) {
-               if (chipset_family > ATA_16)
-                       t1 &= ~0x8000;  /* disable UDMA */
-               t1 |= mwdma_timings[mode - XFER_MW_DMA_0];
-       } else
-               t1 |= pio_timings[mode - XFER_PIO_0];
-
-       pci_write_config_word(dev, drive_pci, t1);
-}
-
-static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u8 t1, drive_pci = 0x40 + drive->dn * 2;
-
-       /* timing bits: 7:4 active 3:0 recovery */
-       const u8 pio_timings[]   = { 0x00, 0x67, 0x44, 0x33, 0x31 };
-       const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 };
-
-       if (mode >= XFER_MW_DMA_0) {
-               u8 t2 = 0;
-
-               pci_read_config_byte(dev, drive_pci, &t2);
-               t2 &= ~0x80;    /* disable UDMA */
-               pci_write_config_byte(dev, drive_pci, t2);
-
-               t1 = mwdma_timings[mode - XFER_MW_DMA_0];
-       } else
-               t1 = pio_timings[mode - XFER_PIO_0];
-
-       pci_write_config_byte(dev, drive_pci + 1, t1);
-}
-
-static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u32 t1 = 0;
-       u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
-
-       pci_read_config_dword(dev, drive_pci, &t1);
-
-       t1 &= 0xc0c00fff;
-       clk = (t1 & 0x08) ? ATA_133 : ATA_100;
-       if (mode >= XFER_MW_DMA_0) {
-               t1 &= ~0x04;    /* disable UDMA */
-               idx = mode - XFER_MW_DMA_0 + 5;
-       } else
-               idx = mode - XFER_PIO_0;
-       t1 |= ini_time_value[clk][idx] << 12;
-       t1 |= act_time_value[clk][idx] << 16;
-       t1 |= rco_time_value[clk][idx] << 24;
-
-       pci_write_config_dword(dev, drive_pci, t1);
-}
-
-static void sis_program_timings(ide_drive_t *drive, const u8 mode)
-{
-       if (chipset_family < ATA_100)           /* ATA_16/33/66/100a */
-               sis_ata16_program_timings(drive, mode);
-       else if (chipset_family < ATA_133)      /* ATA_100/133a */
-               sis_ata100_program_timings(drive, mode);
-       else                                    /* ATA_133 */
-               sis_ata133_program_timings(drive, mode);
-}
-
-static void config_drive_art_rwp(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 reg4bh               = 0;
-       u8 rw_prefetch          = 0;
-
-       pci_read_config_byte(dev, 0x4b, &reg4bh);
-
-       rw_prefetch = reg4bh & ~(0x11 << drive->dn);
-
-       if (drive->media == ide_disk)
-               rw_prefetch |= 0x11 << drive->dn;
-
-       if (reg4bh != rw_prefetch)
-               pci_write_config_byte(dev, 0x4b, rw_prefetch);
-}
-
-static void sis_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       config_drive_art_rwp(drive);
-       sis_program_timings(drive, drive->pio_mode);
-}
-
-static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u32 regdw = 0;
-       u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
-
-       pci_read_config_dword(dev, drive_pci, &regdw);
-
-       regdw |= 0x04;
-       regdw &= 0xfffff00f;
-       /* check if ATA133 enable */
-       clk = (regdw & 0x08) ? ATA_133 : ATA_100;
-       idx = mode - XFER_UDMA_0;
-       regdw |= cycle_time_value[clk][idx] << 4;
-       regdw |= cvs_time_value[clk][idx] << 8;
-
-       pci_write_config_dword(dev, drive_pci, regdw);
-}
-
-static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
-
-       pci_read_config_byte(dev, drive_pci + 1, &reg);
-
-       /* force the UDMA bit on if we want to use UDMA */
-       reg |= 0x80;
-       /* clean reg cycle time bits */
-       reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
-       /* set reg cycle time bits */
-       reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
-
-       pci_write_config_byte(dev, drive_pci + 1, reg);
-}
-
-static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
-       if (chipset_family >= ATA_133)  /* ATA_133 */
-               sis_ata133_program_udma_timings(drive, mode);
-       else                            /* ATA_33/66/100a/100/133a */
-               sis_ata33_program_udma_timings(drive, mode);
-}
-
-static void sis_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       const u8 speed = drive->dma_mode;
-
-       if (speed >= XFER_UDMA_0)
-               sis_program_udma_timings(drive, speed);
-       else
-               sis_program_timings(drive, speed);
-}
-
-static u8 sis_ata133_udma_filter(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u32 regdw = 0;
-       u8 drive_pci = sis_ata133_get_base(drive);
-
-       pci_read_config_dword(dev, drive_pci, &regdw);
-
-       /* if ATA133 disable, we should not set speed above UDMA5 */
-       return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
-}
-
-static int sis_find_family(struct pci_dev *dev)
-{
-       struct pci_dev *host;
-       int i = 0;
-
-       chipset_family = 0;
-
-       for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
-
-               host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
-
-               if (!host)
-                       continue;
-
-               chipset_family = SiSHostChipInfo[i].chipset_family;
-
-               /* Special case for SiS630 : 630S/ET is ATA_100a */
-               if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) {
-                       if (host->revision >= 0x30)
-                               chipset_family = ATA_100a;
-               }
-               pci_dev_put(host);
-
-               printk(KERN_INFO DRV_NAME " %s: %s %s controller\n",
-                       pci_name(dev), SiSHostChipInfo[i].name,
-                       chipset_capability[chipset_family]);
-       }
-
-       if (!chipset_family) { /* Belongs to pci-quirks */
-
-                       u32 idemisc;
-                       u16 trueid;
-
-                       /* Disable ID masking and register remapping */
-                       pci_read_config_dword(dev, 0x54, &idemisc);
-                       pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff));
-                       pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
-                       pci_write_config_dword(dev, 0x54, idemisc);
-
-                       if (trueid == 0x5518) {
-                               printk(KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller\n",
-                                       pci_name(dev));
-                               chipset_family = ATA_133;
-
-                               /* Check for 5513 compatibility mapping
-                                * We must use this, else the port enabled code will fail,
-                                * as it expects the enablebits at 0x4a.
-                                */
-                               if ((idemisc & 0x40000000) == 0) {
-                                       pci_write_config_dword(dev, 0x54, idemisc | 0x40000000);
-                                       printk(KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping\n",
-                                               pci_name(dev));
-                               }
-                       }
-       }
-
-       if (!chipset_family) { /* Belongs to pci-quirks */
-
-                       struct pci_dev *lpc_bridge;
-                       u16 trueid;
-                       u8 prefctl;
-                       u8 idecfg;
-
-                       pci_read_config_byte(dev, 0x4a, &idecfg);
-                       pci_write_config_byte(dev, 0x4a, idecfg | 0x10);
-                       pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
-                       pci_write_config_byte(dev, 0x4a, idecfg);
-
-                       if (trueid == 0x5517) { /* SiS 961/961B */
-
-                               lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
-                               pci_read_config_byte(dev, 0x49, &prefctl);
-                               pci_dev_put(lpc_bridge);
-
-                               if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) {
-                                       printk(KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller\n",
-                                               pci_name(dev));
-                                       chipset_family = ATA_133a;
-                               } else {
-                                       printk(KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller\n",
-                                               pci_name(dev));
-                                       chipset_family = ATA_100;
-                               }
-                       }
-       }
-
-       return chipset_family;
-}
-
-static int init_chipset_sis5513(struct pci_dev *dev)
-{
-       /* Make general config ops here
-          1/ tell IDE channels to operate in Compatibility mode only
-          2/ tell old chips to allow per drive IDE timings */
-
-       u8 reg;
-       u16 regw;
-
-       switch (chipset_family) {
-       case ATA_133:
-               /* SiS962 operation mode */
-               pci_read_config_word(dev, 0x50, &regw);
-               if (regw & 0x08)
-                       pci_write_config_word(dev, 0x50, regw&0xfff7);
-               pci_read_config_word(dev, 0x52, &regw);
-               if (regw & 0x08)
-                       pci_write_config_word(dev, 0x52, regw&0xfff7);
-               break;
-       case ATA_133a:
-       case ATA_100:
-               /* Fixup latency */
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
-               /* Set compatibility bit */
-               pci_read_config_byte(dev, 0x49, &reg);
-               if (!(reg & 0x01))
-                       pci_write_config_byte(dev, 0x49, reg|0x01);
-               break;
-       case ATA_100a:
-       case ATA_66:
-               /* Fixup latency */
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
-
-               /* On ATA_66 chips the bit was elsewhere */
-               pci_read_config_byte(dev, 0x52, &reg);
-               if (!(reg & 0x04))
-                       pci_write_config_byte(dev, 0x52, reg|0x04);
-               break;
-       case ATA_33:
-               /* On ATA_33 we didn't have a single bit to set */
-               pci_read_config_byte(dev, 0x09, &reg);
-               if ((reg & 0x0f) != 0x00)
-                       pci_write_config_byte(dev, 0x09, reg&0xf0);
-               fallthrough;
-       case ATA_16:
-               /* force per drive recovery and active timings
-                  needed on ATA_33 and below chips */
-               pci_read_config_byte(dev, 0x52, &reg);
-               if (!(reg & 0x08))
-                       pci_write_config_byte(dev, 0x52, reg|0x08);
-               break;
-       }
-
-       return 0;
-}
-
-struct sis_laptop {
-       u16 device;
-       u16 subvendor;
-       u16 subdevice;
-};
-
-static const struct sis_laptop sis_laptop[] = {
-       /* devid, subvendor, subdev */
-       { 0x5513, 0x1043, 0x1107 },     /* ASUS A6K */
-       { 0x5513, 0x1734, 0x105f },     /* FSC Amilo A1630 */
-       { 0x5513, 0x1071, 0x8640 },     /* EasyNote K5305 */
-       /* end marker */
-       { 0, }
-};
-
-static u8 sis_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       const struct sis_laptop *lap = &sis_laptop[0];
-       u8 ata66 = 0;
-
-       while (lap->device) {
-               if (lap->device == pdev->device &&
-                   lap->subvendor == pdev->subsystem_vendor &&
-                   lap->subdevice == pdev->subsystem_device)
-                       return ATA_CBL_PATA40_SHORT;
-               lap++;
-       }
-
-       if (chipset_family >= ATA_133) {
-               u16 regw = 0;
-               u16 reg_addr = hwif->channel ? 0x52: 0x50;
-               pci_read_config_word(pdev, reg_addr, &regw);
-               ata66 = (regw & 0x8000) ? 0 : 1;
-       } else if (chipset_family >= ATA_66) {
-               u8 reg48h = 0;
-               u8 mask = hwif->channel ? 0x20 : 0x10;
-               pci_read_config_byte(pdev, 0x48, &reg48h);
-               ata66 = (reg48h & mask) ? 0 : 1;
-       }
-
-       return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops sis_port_ops = {
-       .set_pio_mode           = sis_set_pio_mode,
-       .set_dma_mode           = sis_set_dma_mode,
-       .cable_detect           = sis_cable_detect,
-};
-
-static const struct ide_port_ops sis_ata133_port_ops = {
-       .set_pio_mode           = sis_set_pio_mode,
-       .set_dma_mode           = sis_set_dma_mode,
-       .udma_filter            = sis_ata133_udma_filter,
-       .cable_detect           = sis_cable_detect,
-};
-
-static const struct ide_port_info sis5513_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_sis5513,
-       .enablebits     = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
-       .host_flags     = IDE_HFLAG_NO_AUTODMA,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-static int sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d = sis5513_chipset;
-       u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               return rc;
-
-       if (sis_find_family(dev) == 0)
-               return -ENOTSUPP;
-
-       if (chipset_family >= ATA_133)
-               d.port_ops = &sis_ata133_port_ops;
-       else
-               d.port_ops = &sis_port_ops;
-
-       d.udma_mask = udma_rates[chipset_family];
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static void sis5513_remove(struct pci_dev *dev)
-{
-       ide_pci_remove(dev);
-       pci_disable_device(dev);
-}
-
-static const struct pci_device_id sis5513_pci_tbl[] = {
-       { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 },
-       { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 },
-       { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
-
-static struct pci_driver sis5513_pci_driver = {
-       .name           = "SIS_IDE",
-       .id_table       = sis5513_pci_tbl,
-       .probe          = sis5513_init_one,
-       .remove         = sis5513_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init sis5513_ide_init(void)
-{
-       return ide_pci_register_driver(&sis5513_pci_driver);
-}
-
-static void __exit sis5513_ide_exit(void)
-{
-       pci_unregister_driver(&sis5513_pci_driver);
-}
-
-module_init(sis5513_ide_init);
-module_exit(sis5513_ide_exit);
-
-MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");
-MODULE_DESCRIPTION("PCI driver module for SIS IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
deleted file mode 100644 (file)
index 5c24c42..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- *  -- Russell King (15/11/98) linux@arm.linux.org.uk
- * 
- * Merge in Russell's HW workarounds, fix various problems
- * with the timing registers setup.
- *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
- *
- * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. <source@mvista.com>
- * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "sl82c105"
-
-/*
- * SL82C105 PCI config register 0x40 bits.
- */
-#define CTRL_IDE_IRQB   (1 << 30)
-#define CTRL_IDE_IRQA   (1 << 28)
-#define CTRL_LEGIRQ     (1 << 11)
-#define CTRL_P1F16      (1 << 5)
-#define CTRL_P1EN       (1 << 4)
-#define CTRL_P0F16      (1 << 1)
-#define CTRL_P0EN       (1 << 0)
-
-/*
- * Convert a PIO mode and cycle time to the required on/off times
- * for the interface.  This has protection against runaway timings.
- */
-static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
-{
-       struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-       unsigned int cmd_on, cmd_off;
-       u8 iordy = 0;
-
-       cmd_on  = (t->active + 29) / 30;
-       cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
-
-       if (cmd_on == 0)
-               cmd_on = 1;
-
-       if (cmd_off == 0)
-               cmd_off = 1;
-
-       if (ide_pio_need_iordy(drive, pio))
-               iordy = 0x40;
-
-       return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
-}
-
-/*
- * Configure the chipset for PIO mode.
- */
-static void sl82c105_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long timings   = (unsigned long)ide_get_drivedata(drive);
-       int reg                 = 0x44 + drive->dn * 4;
-       u16 drv_ctrl;
-       const u8 pio            = drive->pio_mode - XFER_PIO_0;
-
-       drv_ctrl = get_pio_timings(drive, pio);
-
-       /*
-        * Store the PIO timings so that we can restore them
-        * in case DMA will be turned off...
-        */
-       timings &= 0xffff0000;
-       timings |= drv_ctrl;
-       ide_set_drivedata(drive, (void *)timings);
-
-       pci_write_config_word(dev, reg,  drv_ctrl);
-       pci_read_config_word (dev, reg, &drv_ctrl);
-
-       printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
-                         ide_xfer_verbose(pio + XFER_PIO_0),
-                         ide_pio_cycle_time(drive, pio), drv_ctrl);
-}
-
-/*
- * Configure the chipset for DMA mode.
- */
-static void sl82c105_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
-       unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-       u16 drv_ctrl;
-       const u8 speed = drive->dma_mode;
-
-       drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
-
-       /*
-        * Store the DMA timings so that we can actually program
-        * them when DMA will be turned on...
-        */
-       timings &= 0x0000ffff;
-       timings |= (unsigned long)drv_ctrl << 16;
-       ide_set_drivedata(drive, (void *)timings);
-}
-
-static int sl82c105_test_irq(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u32 val, mask           = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
-
-       pci_read_config_dword(dev, 0x40, &val);
-
-       return (val & mask) ? 1 : 0;
-}
-
-/*
- * The SL82C105 holds off all IDE interrupts while in DMA mode until
- * all DMA activity is completed.  Sometimes this causes problems (eg,
- * when the drive wants to report an error condition).
- *
- * 0x7e is a "chip testing" register.  Bit 2 resets the DMA controller
- * state machine.  We need to kick this to work around various bugs.
- */
-static inline void sl82c105_reset_host(struct pci_dev *dev)
-{
-       u16 val;
-
-       pci_read_config_word(dev, 0x7e, &val);
-       pci_write_config_word(dev, 0x7e, val | (1 << 2));
-       pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
-}
-
-/*
- * If we get an IRQ timeout, it might be that the DMA state machine
- * got confused.  Fix from Todd Inglett.  Details from Winbond.
- *
- * This function is called when the IDE timer expires, the drive
- * indicates that it is READY, and we were waiting for DMA to complete.
- */
-static void sl82c105_dma_lost_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u32 val, mask           = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
-       u8 dma_cmd;
-
-       printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n");
-
-       /*
-        * Check the raw interrupt from the drive.
-        */
-       pci_read_config_dword(dev, 0x40, &val);
-       if (val & mask)
-               printk(KERN_INFO "sl82c105: drive was requesting IRQ, "
-                      "but host lost it\n");
-
-       /*
-        * Was DMA enabled?  If so, disable it - we're resetting the
-        * host.  The IDE layer will be handling the drive for us.
-        */
-       dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-       if (dma_cmd & 1) {
-               outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
-               printk(KERN_INFO "sl82c105: DMA was enabled\n");
-       }
-
-       sl82c105_reset_host(dev);
-}
-
-/*
- * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
- * Winbond recommend that the DMA state machine is reset prior to
- * setting the bus master DMA enable bit.
- *
- * The generic IDE core will have disabled the BMEN bit before this
- * function is called.
- */
-static void sl82c105_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int reg                 = 0x44 + drive->dn * 4;
-
-       pci_write_config_word(dev, reg,
-                             (unsigned long)ide_get_drivedata(drive) >> 16);
-
-       sl82c105_reset_host(dev);
-       ide_dma_start(drive);
-}
-
-static void sl82c105_dma_clear(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-
-       sl82c105_reset_host(dev);
-}
-
-static int sl82c105_dma_end(ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(drive->hwif->dev);
-       int reg                 = 0x44 + drive->dn * 4;
-       int ret                 = ide_dma_end(drive);
-
-       pci_write_config_word(dev, reg,
-                             (unsigned long)ide_get_drivedata(drive));
-
-       return ret;
-}
-
-/*
- * ATA reset will clear the 16 bits mode in the control
- * register, we need to reprogram it
- */
-static void sl82c105_resetproc(ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-       u32 val;
-
-       pci_read_config_dword(dev, 0x40, &val);
-       val |= (CTRL_P1F16 | CTRL_P0F16);
-       pci_write_config_dword(dev, 0x40, val);
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static u8 sl82c105_bridge_revision(struct pci_dev *dev)
-{
-       struct pci_dev *bridge;
-
-       /*
-        * The bridge should be part of the same device, but function 0.
-        */
-       bridge = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
-                                       dev->bus->number,
-                                       PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-       if (!bridge)
-               return -1;
-
-       /*
-        * Make sure it is a Winbond 553 and is an ISA bridge.
-        */
-       if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
-           bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
-           bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) {
-               pci_dev_put(bridge);
-               return -1;
-       }
-       /*
-        * We need to find function 0's revision, not function 1
-        */
-       pci_dev_put(bridge);
-
-       return bridge->revision;
-}
-
-/*
- * Enable the PCI device
- * 
- * --BenH: It's arch fixup code that should enable channels that
- * have not been enabled by firmware. I decided we can still enable
- * channel 0 here at least, but channel 1 has to be enabled by
- * firmware or arch code. We still set both to 16 bits mode.
- */
-static int init_chipset_sl82c105(struct pci_dev *dev)
-{
-       u32 val;
-
-       pci_read_config_dword(dev, 0x40, &val);
-       val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
-       pci_write_config_dword(dev, 0x40, val);
-
-       return 0;
-}
-
-static const struct ide_port_ops sl82c105_port_ops = {
-       .set_pio_mode           = sl82c105_set_pio_mode,
-       .set_dma_mode           = sl82c105_set_dma_mode,
-       .resetproc              = sl82c105_resetproc,
-       .test_irq               = sl82c105_test_irq,
-};
-
-static const struct ide_dma_ops sl82c105_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = sl82c105_dma_start,
-       .dma_end                = sl82c105_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = sl82c105_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_clear              = sl82c105_dma_clear,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info sl82c105_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_sl82c105,
-       .enablebits     = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
-       .port_ops       = &sl82c105_port_ops,
-       .dma_ops        = &sl82c105_dma_ops,
-       .host_flags     = IDE_HFLAG_IO_32BIT |
-                         IDE_HFLAG_UNMASK_IRQS |
-                         IDE_HFLAG_SERIALIZE_DMA |
-                         IDE_HFLAG_NO_AUTODMA,
-       .pio_mask       = ATA_PIO5,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct ide_port_info d = sl82c105_chipset;
-       u8 rev = sl82c105_bridge_revision(dev);
-
-       if (rev <= 5) {
-               /*
-                * Never ever EVER under any circumstances enable
-                * DMA when the bridge is this old.
-                */
-               printk(KERN_INFO DRV_NAME ": Winbond W83C553 bridge "
-                                "revision %d, BM-DMA disabled\n", rev);
-               d.dma_ops = NULL;
-               d.mwdma_mask = 0;
-               d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA;
-       }
-
-       return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id sl82c105_pci_tbl[] = {
-       { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
-
-static struct pci_driver sl82c105_pci_driver = {
-       .name           = "W82C105_IDE",
-       .id_table       = sl82c105_pci_tbl,
-       .probe          = sl82c105_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init sl82c105_ide_init(void)
-{
-       return ide_pci_register_driver(&sl82c105_pci_driver);
-}
-
-static void __exit sl82c105_ide_exit(void)
-{
-       pci_unregister_driver(&sl82c105_pci_driver);
-}
-
-module_init(sl82c105_ide_init);
-module_exit(sl82c105_ide_exit);
-
-MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
deleted file mode 100644 (file)
index f521d5e..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
- *
- * This is a look-alike variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "slc90e66"
-
-static DEFINE_SPINLOCK(slc90e66_lock);
-
-static void slc90e66_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       int is_slave            = drive->dn & 1;
-       int master_port         = hwif->channel ? 0x42 : 0x40;
-       int slave_port          = 0x44;
-       unsigned long flags;
-       u16 master_data;
-       u8 slave_data;
-       int control = 0;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-                                    /* ISP  RTC */
-       static const u8 timings[][2] = {
-                                       { 0, 0 },
-                                       { 0, 0 },
-                                       { 1, 0 },
-                                       { 2, 1 },
-                                       { 2, 3 }, };
-
-       spin_lock_irqsave(&slc90e66_lock, flags);
-       pci_read_config_word(dev, master_port, &master_data);
-
-       if (pio > 1)
-               control |= 1;   /* Programmable timing on */
-       if (drive->media == ide_disk)
-               control |= 4;   /* Prefetch, post write */
-       if (ide_pio_need_iordy(drive, pio))
-               control |= 2;   /* IORDY */
-       if (is_slave) {
-               master_data |=  0x4000;
-               master_data &= ~0x0070;
-               if (pio > 1) {
-                       /* Set PPE, IE and TIME */
-                       master_data |= control << 4;
-               }
-               pci_read_config_byte(dev, slave_port, &slave_data);
-               slave_data &= hwif->channel ? 0x0f : 0xf0;
-               slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
-                              (hwif->channel ? 4 : 0);
-       } else {
-               master_data &= ~0x3307;
-               if (pio > 1) {
-                       /* enable PPE, IE and TIME */
-                       master_data |= control;
-               }
-               master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
-       }
-       pci_write_config_word(dev, master_port, master_data);
-       if (is_slave)
-               pci_write_config_byte(dev, slave_port, slave_data);
-       spin_unlock_irqrestore(&slc90e66_lock, flags);
-}
-
-static void slc90e66_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       u8 maslave              = hwif->channel ? 0x42 : 0x40;
-       int sitre = 0, a_speed  = 7 << (drive->dn * 4);
-       int u_speed = 0, u_flag = 1 << drive->dn;
-       u16                     reg4042, reg44, reg48, reg4a;
-       const u8 speed          = drive->dma_mode;
-
-       pci_read_config_word(dev, maslave, &reg4042);
-       sitre = (reg4042 & 0x4000) ? 1 : 0;
-       pci_read_config_word(dev, 0x44, &reg44);
-       pci_read_config_word(dev, 0x48, &reg48);
-       pci_read_config_word(dev, 0x4a, &reg4a);
-
-       if (speed >= XFER_UDMA_0) {
-               u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
-
-               if (!(reg48 & u_flag))
-                       pci_write_config_word(dev, 0x48, reg48|u_flag);
-               if ((reg4a & a_speed) != u_speed) {
-                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-                       pci_read_config_word(dev, 0x4a, &reg4a);
-                       pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-               }
-       } else {
-               const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
-               if (reg48 & u_flag)
-                       pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-               if (reg4a & a_speed)
-                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-
-               if (speed >= XFER_MW_DMA_0)
-                       drive->pio_mode =
-                               mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
-               else
-                       drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
-               slc90e66_set_pio_mode(hwif, drive);
-       }
-}
-
-static u8 slc90e66_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02;
-
-       pci_read_config_byte(dev, 0x47, &reg47);
-
-       /* bit[0(1)]: 0:80, 1:40 */
-       return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops slc90e66_port_ops = {
-       .set_pio_mode           = slc90e66_set_pio_mode,
-       .set_dma_mode           = slc90e66_set_dma_mode,
-       .cable_detect           = slc90e66_cable_detect,
-};
-
-static const struct ide_port_info slc90e66_chipset = {
-       .name           = DRV_NAME,
-       .enablebits     = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
-       .port_ops       = &slc90e66_port_ops,
-       .pio_mask       = ATA_PIO4,
-       .swdma_mask     = ATA_SWDMA2_ONLY,
-       .mwdma_mask     = ATA_MWDMA12_ONLY,
-       .udma_mask      = ATA_UDMA4,
-};
-
-static int slc90e66_init_one(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &slc90e66_chipset, NULL);
-}
-
-static const struct pci_device_id slc90e66_pci_tbl[] = {
-       { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
-
-static struct pci_driver slc90e66_pci_driver = {
-       .name           = "SLC90e66_IDE",
-       .id_table       = slc90e66_pci_tbl,
-       .probe          = slc90e66_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init slc90e66_ide_init(void)
-{
-       return ide_pci_register_driver(&slc90e66_pci_driver);
-}
-
-static void __exit slc90e66_ide_exit(void)
-{
-       pci_unregister_driver(&slc90e66_pci_driver);
-}
-
-module_init(slc90e66_ide_init);
-module_exit(slc90e66_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c
deleted file mode 100644 (file)
index 17e6132..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2002 Toshiba Corporation
- * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#define DRV_NAME "tc86c001"
-
-static void tc86c001_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       unsigned long scr_port  = hwif->config_data + (drive->dn ? 0x02 : 0x00);
-       u16 mode, scr           = inw(scr_port);
-       const u8 speed          = drive->dma_mode;
-
-       switch (speed) {
-       case XFER_UDMA_4:       mode = 0x00c0; break;
-       case XFER_UDMA_3:       mode = 0x00b0; break;
-       case XFER_UDMA_2:       mode = 0x00a0; break;
-       case XFER_UDMA_1:       mode = 0x0090; break;
-       case XFER_UDMA_0:       mode = 0x0080; break;
-       case XFER_MW_DMA_2:     mode = 0x0070; break;
-       case XFER_MW_DMA_1:     mode = 0x0060; break;
-       case XFER_MW_DMA_0:     mode = 0x0050; break;
-       case XFER_PIO_4:        mode = 0x0400; break;
-       case XFER_PIO_3:        mode = 0x0300; break;
-       case XFER_PIO_2:        mode = 0x0200; break;
-       case XFER_PIO_1:        mode = 0x0100; break;
-       case XFER_PIO_0:
-       default:                mode = 0x0000; break;
-       }
-
-       scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
-       scr |= mode;
-       outw(scr, scr_port);
-}
-
-static void tc86c001_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       tc86c001_set_mode(hwif, drive);
-}
-
-/*
- * HACKITY HACK
- *
- * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
- * if a DMA transfer terminates prematurely, the controller leaves the device's
- * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
- * set the interrupt bit in the DMA status register), thus no PCI interrupt
- * will occur until a DMA transfer has been successfully completed.
- *
- * We work around this by initiating dummy, zero-length DMA transfer on
- * a DMA timeout expiration. I found no better way to do this with the current
- * IDE core than to temporarily replace a higher level driver's timer expiry
- * handler with our own backing up to that handler in case our recovery fails.
- */
-static int tc86c001_timer_expiry(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       ide_expiry_t *expiry    = ide_get_hwifdata(hwif);
-       u8 dma_stat             = inb(hwif->dma_base + ATA_DMA_STATUS);
-
-       /* Restore a higher level driver's expiry handler first. */
-       hwif->expiry = expiry;
-
-       if ((dma_stat & 5) == 1) {      /* DMA active and no interrupt */
-               unsigned long sc_base   = hwif->config_data;
-               unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
-               u8 dma_cmd              = inb(hwif->dma_base + ATA_DMA_CMD);
-
-               printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
-                      "attempting recovery...\n", drive->name);
-
-               /* Stop DMA */
-               outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD);
-
-               /* Setup the dummy DMA transfer */
-               outw(0, sc_base + 0x0a);        /* Sector Count */
-               outw(0, twcr_port);     /* Transfer Word Count 1 or 2 */
-
-               /* Start the dummy DMA transfer */
-
-               /* clear R_OR_WCTR for write */
-               outb(0x00, hwif->dma_base + ATA_DMA_CMD);
-               /* set START_STOPBM */
-               outb(0x01, hwif->dma_base + ATA_DMA_CMD);
-
-               /*
-                * If an interrupt was pending, it should come thru shortly.
-                * If not, a higher level driver's expiry handler should
-                * eventually cause some kind of recovery from the DMA stall.
-                */
-               return WAIT_MIN_SLEEP;
-       }
-
-       /* Chain to the restored expiry handler if DMA wasn't active. */
-       if (likely(expiry != NULL))
-               return expiry(drive);
-
-       /* If there was no handler, "emulate" that for ide_timer_expiry()... */
-       return -1;
-}
-
-static void tc86c001_dma_start(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       unsigned long sc_base   = hwif->config_data;
-       unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
-       unsigned long nsectors  = blk_rq_sectors(hwif->rq);
-
-       /*
-        * We have to manually load the sector count and size into
-        * the appropriate system control registers for DMA to work
-        * with LBA48 and ATAPI devices...
-        */
-       outw(nsectors, sc_base + 0x0a); /* Sector Count */
-       outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
-
-       /* Install our timeout expiry hook, saving the current handler... */
-       ide_set_hwifdata(hwif, hwif->expiry);
-       hwif->expiry = &tc86c001_timer_expiry;
-
-       ide_dma_start(drive);
-}
-
-static u8 tc86c001_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       unsigned long sc_base = pci_resource_start(dev, 5);
-       u16 scr1 = inw(sc_base + 0x00);
-
-       /*
-        * System Control  1 Register bit 13 (PDIAGN):
-        * 0=80-pin cable, 1=40-pin cable
-        */
-       return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static void init_hwif_tc86c001(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned long sc_base   = pci_resource_start(dev, 5);
-       u16 scr1                = inw(sc_base + 0x00);
-
-       /* System Control 1 Register bit 15 (Soft Reset) set */
-       outw(scr1 |  0x8000, sc_base + 0x00);
-
-       /* System Control 1 Register bit 14 (FIFO Reset) set */
-       outw(scr1 |  0x4000, sc_base + 0x00);
-
-       /* System Control 1 Register: reset clear */
-       outw(scr1 & ~0xc000, sc_base + 0x00);
-
-       /* Store the system control register base for convenience... */
-       hwif->config_data = sc_base;
-
-       if (!hwif->dma_base)
-               return;
-
-       /*
-        * Sector Count Control Register bits 0 and 1 set:
-        * software sets Sector Count Register for master and slave device
-        */
-       outw(0x0003, sc_base + 0x0c);
-
-       /* Sector Count Register limit */
-       hwif->rqsize     = 0xffff;
-}
-
-static const struct ide_port_ops tc86c001_port_ops = {
-       .set_pio_mode           = tc86c001_set_pio_mode,
-       .set_dma_mode           = tc86c001_set_mode,
-       .cable_detect           = tc86c001_cable_detect,
-};
-
-static const struct ide_dma_ops tc86c001_dma_ops = {
-       .dma_host_set           = ide_dma_host_set,
-       .dma_setup              = ide_dma_setup,
-       .dma_start              = tc86c001_dma_start,
-       .dma_end                = ide_dma_end,
-       .dma_test_irq           = ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info tc86c001_chipset = {
-       .name           = DRV_NAME,
-       .init_hwif      = init_hwif_tc86c001,
-       .port_ops       = &tc86c001_port_ops,
-       .dma_ops        = &tc86c001_dma_ops,
-       .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
-       .pio_mask       = ATA_PIO4,
-       .mwdma_mask     = ATA_MWDMA2,
-       .udma_mask      = ATA_UDMA4,
-};
-
-static int tc86c001_init_one(struct pci_dev *dev,
-                            const struct pci_device_id *id)
-{
-       int rc;
-
-       rc = pci_enable_device(dev);
-       if (rc)
-               goto out;
-
-       rc = pci_request_region(dev, 5, DRV_NAME);
-       if (rc) {
-               printk(KERN_ERR DRV_NAME ": system control regs already in use");
-               goto out_disable;
-       }
-
-       rc = ide_pci_init_one(dev, &tc86c001_chipset, NULL);
-       if (rc)
-               goto out_release;
-
-       goto out;
-
-out_release:
-       pci_release_region(dev, 5);
-out_disable:
-       pci_disable_device(dev);
-out:
-       return rc;
-}
-
-static void tc86c001_remove(struct pci_dev *dev)
-{
-       ide_pci_remove(dev);
-       pci_release_region(dev, 5);
-       pci_disable_device(dev);
-}
-
-static const struct pci_device_id tc86c001_pci_tbl[] = {
-       { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 },
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
-
-static struct pci_driver tc86c001_pci_driver = {
-       .name           = "TC86C001",
-       .id_table       = tc86c001_pci_tbl,
-       .probe          = tc86c001_init_one,
-       .remove         = tc86c001_remove,
-};
-
-static int __init tc86c001_ide_init(void)
-{
-       return ide_pci_register_driver(&tc86c001_pci_driver);
-}
-
-static void __exit tc86c001_ide_exit(void)
-{
-       pci_unregister_driver(&tc86c001_pci_driver);
-}
-
-module_init(tc86c001_ide_init);
-module_exit(tc86c001_ide_exit);
-
-MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
-MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c
deleted file mode 100644 (file)
index 16ddd09..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * IDE Chipset driver for the Compaq TriFlex IDE controller.
- * 
- * Known to work with the Compaq Workstation 5x00 series.
- *
- * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
- * Author: Torben Mathiasen <torben.mathiasen@hp.com>
- * 
- * Loosely based on the piix & svwks drivers.
- *
- * Documentation:
- *     Not publicly available.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "triflex"
-
-static void triflex_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       u32 triflex_timings = 0;
-       u16 timing = 0;
-       u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1;
-
-       pci_read_config_dword(dev, channel_offset, &triflex_timings);
-
-       switch (drive->dma_mode) {
-               case XFER_MW_DMA_2:
-                       timing = 0x0103; 
-                       break;
-               case XFER_MW_DMA_1:
-                       timing = 0x0203;
-                       break;
-               case XFER_MW_DMA_0:
-                       timing = 0x0808;
-                       break;
-               case XFER_SW_DMA_2:
-               case XFER_SW_DMA_1:
-               case XFER_SW_DMA_0:
-                       timing = 0x0f0f;
-                       break;
-               case XFER_PIO_4:
-                       timing = 0x0202;
-                       break;
-               case XFER_PIO_3:
-                       timing = 0x0204;
-                       break;
-               case XFER_PIO_2:
-                       timing = 0x0404;
-                       break;
-               case XFER_PIO_1:
-                       timing = 0x0508;
-                       break;
-               case XFER_PIO_0:
-                       timing = 0x0808;
-                       break;
-       }
-
-       triflex_timings &= ~(0xFFFF << (16 * unit));
-       triflex_timings |= (timing << (16 * unit));
-       
-       pci_write_config_dword(dev, channel_offset, triflex_timings);
-}
-
-static void triflex_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       triflex_set_mode(hwif, drive);
-}
-
-static const struct ide_port_ops triflex_port_ops = {
-       .set_pio_mode           = triflex_set_pio_mode,
-       .set_dma_mode           = triflex_set_mode,
-};
-
-static const struct ide_port_info triflex_device = {
-       .name           = DRV_NAME,
-       .enablebits     = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
-       .port_ops       = &triflex_port_ops,
-       .pio_mask       = ATA_PIO4,
-       .swdma_mask     = ATA_SWDMA2,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &triflex_device, NULL);
-}
-
-static const struct pci_device_id triflex_pci_tbl[] = {
-       { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
-
-#ifdef CONFIG_PM
-static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       /*
-        * We must not disable or powerdown the device.
-        * APM bios refuses to suspend if IDE is not accessible.
-        */
-       pci_save_state(dev);
-       return 0;
-}
-#else
-#define triflex_ide_pci_suspend NULL
-#endif
-
-static struct pci_driver triflex_pci_driver = {
-       .name           = "TRIFLEX_IDE",
-       .id_table       = triflex_pci_tbl,
-       .probe          = triflex_init_one,
-       .remove         = ide_pci_remove,
-       .suspend        = triflex_ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init triflex_ide_init(void)
-{
-       return ide_pci_register_driver(&triflex_pci_driver);
-}
-
-static void __exit triflex_ide_exit(void)
-{
-       pci_unregister_driver(&triflex_pci_driver);
-}
-
-module_init(triflex_ide_init);
-module_exit(triflex_ide_exit);
-
-MODULE_AUTHOR("Torben Mathiasen");
-MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
-MODULE_LICENSE("GPL");
-
-
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
deleted file mode 100644 (file)
index d550b37..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- *  Copyright (c) 1997-1998  Mark Lord
- *  Copyright (c) 2007       MontaVista Software, Inc. <source@mvista.com>
- *
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  June 22, 2004 - get rid of check_region
- *                   - Jesper Juhl
- *
- */
-
-/*
- * This module provides support for the bus-master IDE DMA function
- * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board.  The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL!  It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES   /* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- *     bit7 must always be written as "1"
- *     bits6-2 undefined
- *     bit1 1=legacy_compatible_mode, 0=native_pci_mode
- *     bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- *     bits7-2 undefined
- *     bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- *     bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- *     bits7-5 undefined
- *     bit4 legacy_header: 1=present, 0=absent
- *     bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- *     bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- *     bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- *     bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- *     bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- *     bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- *     bit5 0=enabled master burst access (default), 1=disable  (write only)
- *     bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- *     bit3 0=primary IDE channel, 1=secondary IDE channel
- *     bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- *     two sets of seven config registers,
- *     selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- *     each index defined below:
- *
- * Index-0 Base address register for command block (word)
- *     defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- *     bit7 1=DMA enable, 0=DMA disable
- *     bit6 1=activate IDE_RESET, 0=no action (default)
- *     bit5 1=enable IORDY, 0=disable IORDY (default)
- *     bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- *     bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- *     bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- *     bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- *     bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- *     bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- *     bit7 1=enable_readahead, 0=disable_readahead(default)
- *     bit6 1=clear_FIFO, 0=no_action
- *     bit5 undefined
- *     bit4 mode4 timing control: 1=enable, 0=disable(default)
- *     bit3 undefined
- *     bit2 undefined
- *     bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- *     defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- *     standard PCI "clk" (clock) counts, default value = 0xf5
- *
- *     bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
- *     bits5-3 hold time:      000=1clk, 001=2clk, 010=3clk,
- *                             011=4clk, 100=5clk, 101=6clk,
- *                             110=8clk, 111=12clk
- *     bits2-0 active time:    000=2clk, 001=3clk, 010=4clk,
- *                             011=5clk, 100=6clk, 101=8clk,
- *                             110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- *     same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- *     0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde  ; primary
- *     0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde  ; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- *     0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde  ; primary
- *     0x0170,0x21,0xff,0x80,0x0376,0x09,0xde  ; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- *     0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde  ; primary
- *     0x0170,0x21,0xff,0x80,0x0376,0x00,0xde  ; secondary
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "trm290"
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u16 reg = 0;
-       unsigned long flags;
-
-       /* select PIO or DMA */
-       reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
-       local_irq_save(flags);
-
-       if (reg != hwif->select_data) {
-               hwif->select_data = reg;
-               /* set PIO/DMA */
-               outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
-               outw(reg & 0xff, hwif->config_data);
-       }
-
-       /* enable IRQ if not probing */
-       if (drive->dev_flags & IDE_DFLAG_PRESENT) {
-               reg = inw(hwif->config_data + 3);
-               reg &= 0x13;
-               reg &= ~(1 << hwif->channel);
-               outw(reg, hwif->config_data + 3);
-       }
-
-       local_irq_restore(flags);
-}
-
-static void trm290_dev_select(ide_drive_t *drive)
-{
-       trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
-
-       outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       if (cmd->tf_flags & IDE_TFLAG_WRITE) {
-#ifdef TRM290_NO_DMA_WRITES
-               /* always use PIO for writes */
-               return 1;
-#endif
-       }
-       return 0;
-}
-
-static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2;
-
-       count = ide_build_dmatable(drive, cmd);
-       if (count == 0)
-               /* try PIO instead of DMA */
-               return 1;
-
-       outl(hwif->dmatable_dma | rw, hwif->dma_base);
-       /* start DMA */
-       outw(count * 2 - 1, hwif->dma_base + 2);
-
-       return 0;
-}
-
-static void trm290_dma_start(ide_drive_t *drive)
-{
-       trm290_prepare_drive(drive, 1);
-}
-
-static int trm290_dma_end(ide_drive_t *drive)
-{
-       u16 status = inw(drive->hwif->dma_base + 2);
-
-       trm290_prepare_drive(drive, 0);
-
-       return status != 0x00ff;
-}
-
-static int trm290_dma_test_irq(ide_drive_t *drive)
-{
-       u16 status = inw(drive->hwif->dma_base + 2);
-
-       return status == 0x00ff;
-}
-
-static void trm290_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void init_hwif_trm290(ide_hwif_t *hwif)
-{
-       struct pci_dev *dev     = to_pci_dev(hwif->dev);
-       unsigned int  cfg_base  = pci_resource_start(dev, 4);
-       unsigned long flags;
-       u8 reg = 0;
-
-       if ((dev->class & 5) && cfg_base)
-               printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev));
-       else {
-               cfg_base = 0x3df0;
-               printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev));
-       }
-       printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
-       hwif->config_data = cfg_base;
-       hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
-
-       printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx\n",
-              hwif->name, hwif->dma_base, hwif->dma_base + 3);
-
-       if (ide_allocate_dma_engine(hwif))
-               return;
-
-       local_irq_save(flags);
-       /* put config reg into first byte of hwif->select_data */
-       outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
-       /* select PIO as default */
-       hwif->select_data = 0x21;
-       outb(hwif->select_data, hwif->config_data);
-       /* get IRQ info */
-       reg = inb(hwif->config_data + 3);
-       /* mask IRQs for both ports */
-       reg = (reg & 0x10) | 0x03;
-       outb(reg, hwif->config_data + 3);
-       local_irq_restore(flags);
-
-       if (reg & 0x10)
-               /* legacy mode */
-               hwif->irq = hwif->channel ? 15 : 14;
-
-#if 1
-       {
-       /*
-        * My trm290-based card doesn't seem to work with all possible values
-        * for the control basereg, so this kludge ensures that we use only
-        * values that are known to work.  Ugh.         -ml
-        */
-               u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
-               static u16 next_offset = 0;
-               u8 old_mask;
-
-               outb(0x54 | (hwif->channel << 3), hwif->config_data + 1);
-               old = inw(hwif->config_data);
-               old &= ~1;
-               old_mask = inb(old + 2);
-               if (old != compat && old_mask == 0xff) {
-                       /* leave lower 10 bits untouched */
-                       compat += (next_offset += 0x400);
-                       hwif->io_ports.ctl_addr = compat + 2;
-                       outw(compat | 1, hwif->config_data);
-                       new = inw(hwif->config_data);
-                       printk(KERN_INFO "%s: control basereg workaround: "
-                               "old=0x%04x, new=0x%04x\n",
-                               hwif->name, old, new & ~1);
-               }
-       }
-#endif
-}
-
-static const struct ide_tp_ops trm290_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = trm290_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_dma_ops trm290_dma_ops = {
-       .dma_host_set           = trm290_dma_host_set,
-       .dma_setup              = trm290_dma_setup,
-       .dma_start              = trm290_dma_start,
-       .dma_end                = trm290_dma_end,
-       .dma_test_irq           = trm290_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_check              = trm290_dma_check,
-};
-
-static const struct ide_port_info trm290_chipset = {
-       .name           = DRV_NAME,
-       .init_hwif      = init_hwif_trm290,
-       .tp_ops         = &trm290_tp_ops,
-       .dma_ops        = &trm290_dma_ops,
-       .host_flags     = IDE_HFLAG_TRM290 |
-                         IDE_HFLAG_NO_ATAPI_DMA |
-#if 0 /* play it safe for now */
-                         IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-#endif
-                         IDE_HFLAG_NO_AUTODMA |
-                         IDE_HFLAG_NO_LBA48,
-};
-
-static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       return ide_pci_init_one(dev, &trm290_chipset, NULL);
-}
-
-static const struct pci_device_id trm290_pci_tbl[] = {
-       { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
-
-static struct pci_driver trm290_pci_driver = {
-       .name           = "TRM290_IDE",
-       .id_table       = trm290_pci_tbl,
-       .probe          = trm290_init_one,
-       .remove         = ide_pci_remove,
-};
-
-static int __init trm290_ide_init(void)
-{
-       return ide_pci_register_driver(&trm290_pci_driver);
-}
-
-static void __exit trm290_ide_exit(void)
-{
-       pci_unregister_driver(&trm290_pci_driver);
-}
-
-module_init(trm290_ide_init);
-module_exit(trm290_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
deleted file mode 100644 (file)
index 962eb92..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * TX4938 internal IDE driver
- * Based on tx4939ide.c.
- *
- * 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.
- *
- * (C) Copyright TOSHIBA CORPORATION 2005-2007
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/ide.h>
-#include <asm/txx9/tx4938.h>
-
-static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
-                                unsigned int gbus_clock,
-                                u8 pio)
-{
-       struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-       u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]);
-       unsigned int sp = (cr >> 4) & 3;
-       unsigned int clock = gbus_clock / (4 - sp);
-       unsigned int cycle = 1000000000 / clock;
-       unsigned int shwt;
-       int wt;
-
-       /* Minimum DIOx- active time */
-       wt = DIV_ROUND_UP(t->act8b, cycle) - 2;
-       /* IORDY setup time: 35ns */
-       wt = max_t(int, wt, DIV_ROUND_UP(35, cycle));
-       /* actual wait-cycle is max(wt & ~1, 1) */
-       if (wt > 2 && (wt & 1))
-               wt++;
-       wt &= ~1;
-       /* Address-valid to DIOR/DIOW setup */
-       shwt = DIV_ROUND_UP(t->setup, cycle);
-
-       /* -DIOx recovery time (SHWT * 4) and cycle time requirement */
-       while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle)
-               shwt++;
-       if (shwt > 7) {
-               pr_warn("tx4938ide: SHWT violation (%d)\n", shwt);
-               shwt = 7;
-       }
-       pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n",
-                ebus_ch, cycle, wt, shwt);
-
-       __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt,
-                    &tx4938_ebuscptr->cr[ebus_ch]);
-}
-
-static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       struct tx4938ide_platform_info *pdata = dev_get_platdata(hwif->dev);
-       u8 safe = drive->pio_mode - XFER_PIO_0;
-       ide_drive_t *pair;
-
-       pair = ide_get_pair_dev(drive);
-       if (pair)
-               safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
-       tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
-}
-
-#ifdef __BIG_ENDIAN
-
-/* custom iops (independent from SWAP_IO_SPACE) */
-static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
-                               void *buf, unsigned int len)
-{
-       unsigned long port = drive->hwif->io_ports.data_addr;
-       unsigned short *ptr = buf;
-       unsigned int count = (len + 1) / 2;
-
-       while (count--)
-               *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
-       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
-                               void *buf, unsigned int len)
-{
-       unsigned long port = drive->hwif->io_ports.data_addr;
-       unsigned short *ptr = buf;
-       unsigned int count = (len + 1) / 2;
-
-       while (count--) {
-               __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
-               ptr++;
-       }
-       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static const struct ide_tp_ops tx4938ide_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_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             = tx4938ide_input_data_swap,
-       .output_data            = tx4938ide_output_data_swap,
-};
-
-#endif /* __BIG_ENDIAN */
-
-static const struct ide_port_ops tx4938ide_port_ops = {
-       .set_pio_mode           = tx4938ide_set_pio_mode,
-};
-
-static const struct ide_port_info tx4938ide_port_info __initconst = {
-       .port_ops               = &tx4938ide_port_ops,
-#ifdef __BIG_ENDIAN
-       .tp_ops                 = &tx4938ide_tp_ops,
-#endif
-       .host_flags             = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-       .pio_mask               = ATA_PIO5,
-       .chipset                = ide_generic,
-};
-
-static int __init tx4938ide_probe(struct platform_device *pdev)
-{
-       struct ide_hw hw, *hws[] = { &hw };
-       struct ide_host *host;
-       struct resource *res;
-       struct tx4938ide_platform_info *pdata = dev_get_platdata(&pdev->dev);
-       int irq, ret, i;
-       unsigned long mapbase, mapctl;
-       struct ide_port_info d = tx4938ide_port_info;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return -ENODEV;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), "tx4938ide"))
-               return -EBUSY;
-       mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
-                                             8 << pdata->ioport_shift);
-       mapctl = (unsigned long)devm_ioremap(&pdev->dev,
-                                            res->start + 0x10000 +
-                                            (6 << pdata->ioport_shift),
-                                            1 << pdata->ioport_shift);
-       if (!mapbase || !mapctl)
-               return -EBUSY;
-
-       memset(&hw, 0, sizeof(hw));
-       if (pdata->ioport_shift) {
-               unsigned long port = mapbase;
-               unsigned long ctl = mapctl;
-
-               hw.io_ports_array[0] = port;
-#ifdef __BIG_ENDIAN
-               port++;
-               ctl++;
-#endif
-               for (i = 1; i <= 7; i++)
-                       hw.io_ports_array[i] =
-                               port + (i << pdata->ioport_shift);
-               hw.io_ports.ctl_addr = ctl;
-       } else
-               ide_std_init_ports(&hw, mapbase, mapctl);
-       hw.irq = irq;
-       hw.dev = &pdev->dev;
-
-       pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n",
-               mapbase, mapctl, hw.irq);
-       if (pdata->gbus_clock)
-               tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
-       else
-               d.port_ops = NULL;
-       ret = ide_host_add(&d, hws, 1, &host);
-       if (!ret)
-               platform_set_drvdata(pdev, host);
-       return ret;
-}
-
-static int __exit tx4938ide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = platform_get_drvdata(pdev);
-
-       ide_host_remove(host);
-       return 0;
-}
-
-static struct platform_driver tx4938ide_driver = {
-       .driver         = {
-               .name   = "tx4938ide",
-       },
-       .remove = __exit_p(tx4938ide_remove),
-};
-
-module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe);
-
-MODULE_DESCRIPTION("TX4938 internal IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:tx4938ide");
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
deleted file mode 100644 (file)
index b1bbf80..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * TX4939 internal IDE driver
- * Based on RBTX49xx patch from CELF patch archive.
- *
- * 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.
- *
- * (C) Copyright TOSHIBA CORPORATION 2005-2007
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/scatterlist.h>
-
-#include <asm/ide.h>
-
-#define MODNAME        "tx4939ide"
-
-/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */
-#define TX4939IDE_Data                 0x000
-#define TX4939IDE_Error_Feature                0x001
-#define TX4939IDE_Sec                  0x002
-#define TX4939IDE_LBA0                 0x003
-#define TX4939IDE_LBA1                 0x004
-#define TX4939IDE_LBA2                 0x005
-#define TX4939IDE_DevHead              0x006
-#define TX4939IDE_Stat_Cmd             0x007
-#define TX4939IDE_AltStat_DevCtl       0x402
-/* H/W DMA Registers  */
-#define TX4939IDE_DMA_Cmd      0x800   /* 8-bit */
-#define TX4939IDE_DMA_Stat     0x802   /* 8-bit */
-#define TX4939IDE_PRD_Ptr      0x804   /* 32-bit */
-/* ATA100 CORE Registers (16-bit) */
-#define TX4939IDE_Sys_Ctl      0xc00
-#define TX4939IDE_Xfer_Cnt_1   0xc08
-#define TX4939IDE_Xfer_Cnt_2   0xc0a
-#define TX4939IDE_Sec_Cnt      0xc10
-#define TX4939IDE_Start_Lo_Addr        0xc18
-#define TX4939IDE_Start_Up_Addr        0xc20
-#define TX4939IDE_Add_Ctl      0xc28
-#define TX4939IDE_Lo_Burst_Cnt 0xc30
-#define TX4939IDE_Up_Burst_Cnt 0xc38
-#define TX4939IDE_PIO_Addr     0xc88
-#define TX4939IDE_H_Rst_Tim    0xc90
-#define TX4939IDE_Int_Ctl      0xc98
-#define TX4939IDE_Pkt_Cmd      0xcb8
-#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0
-#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8
-#define TX4939IDE_Dev_TErr     0xcd0
-#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8
-#define TX4939IDE_Start_TAddr  0xce0
-
-/* bits for Int_Ctl */
-#define TX4939IDE_INT_ADDRERR  0x80
-#define TX4939IDE_INT_REACHMUL 0x40
-#define TX4939IDE_INT_DEVTIMING        0x20
-#define TX4939IDE_INT_UDMATERM 0x10
-#define TX4939IDE_INT_TIMER    0x08
-#define TX4939IDE_INT_BUSERR   0x04
-#define TX4939IDE_INT_XFEREND  0x02
-#define TX4939IDE_INT_HOST     0x01
-
-#define TX4939IDE_IGNORE_INTS  \
-       (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \
-        TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \
-        TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND)
-
-#ifdef __BIG_ENDIAN
-#define tx4939ide_swizzlel(a)  ((a) ^ 4)
-#define tx4939ide_swizzlew(a)  ((a) ^ 6)
-#define tx4939ide_swizzleb(a)  ((a) ^ 7)
-#else
-#define tx4939ide_swizzlel(a)  (a)
-#define tx4939ide_swizzlew(a)  (a)
-#define tx4939ide_swizzleb(a)  (a)
-#endif
-
-static u16 tx4939ide_readw(void __iomem *base, u32 reg)
-{
-       return __raw_readw(base + tx4939ide_swizzlew(reg));
-}
-static u8 tx4939ide_readb(void __iomem *base, u32 reg)
-{
-       return __raw_readb(base + tx4939ide_swizzleb(reg));
-}
-static void tx4939ide_writel(u32 val, void __iomem *base, u32 reg)
-{
-       __raw_writel(val, base + tx4939ide_swizzlel(reg));
-}
-static void tx4939ide_writew(u16 val, void __iomem *base, u32 reg)
-{
-       __raw_writew(val, base + tx4939ide_swizzlew(reg));
-}
-static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg)
-{
-       __raw_writeb(val, base + tx4939ide_swizzleb(reg));
-}
-
-#define TX4939IDE_BASE(hwif)   ((void __iomem *)(hwif)->extra_base)
-
-static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int is_slave = drive->dn;
-       u32 mask, val;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-       u8 safe = pio;
-       ide_drive_t *pair;
-
-       pair = ide_get_pair_dev(drive);
-       if (pair)
-               safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
-       /*
-        * Update Command Transfer Mode for master/slave and Data
-        * Transfer Mode for this drive.
-        */
-       mask = is_slave ? 0x07f00000 : 0x000007f0;
-       val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0);
-       hwif->select_data = (hwif->select_data & ~mask) | val;
-       /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
-}
-
-static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       u32 mask, val;
-       const u8 mode = drive->dma_mode;
-
-       /* Update Data Transfer Mode for this drive. */
-       if (mode >= XFER_UDMA_0)
-               val = mode - XFER_UDMA_0 + 8;
-       else
-               val = mode - XFER_MW_DMA_0 + 5;
-       if (drive->dn) {
-               mask = 0x00f00000;
-               val <<= 20;
-       } else {
-               mask = 0x000000f0;
-               val <<= 4;
-       }
-       hwif->select_data = (hwif->select_data & ~mask) | val;
-       /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
-}
-
-static u16 tx4939ide_check_error_ints(ide_hwif_t *hwif)
-{
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
-
-       if (ctl & TX4939IDE_INT_BUSERR) {
-               /* reset FIFO */
-               u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl);
-
-               tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl);
-               /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */
-               ndelay(270);
-               tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
-       }
-       if (ctl & (TX4939IDE_INT_ADDRERR |
-                  TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR))
-               pr_err("%s: Error interrupt %#x (%s%s%s )\n",
-                      hwif->name, ctl,
-                      ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "",
-                      ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "",
-                      ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : "");
-       return ctl;
-}
-
-static void tx4939ide_clear_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif;
-       void __iomem *base;
-       u16 ctl;
-
-       /*
-        * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job
-        * for DMA case.
-        */
-       if (drive->waiting_for_dma)
-               return;
-       hwif = drive->hwif;
-       base = TX4939IDE_BASE(hwif);
-       ctl = tx4939ide_check_error_ints(hwif);
-       tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
-}
-
-static u8 tx4939ide_cable_detect(ide_hwif_t *hwif)
-{
-       void __iomem *base = TX4939IDE_BASE(hwif);
-
-       return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ?
-               ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-#ifdef __BIG_ENDIAN
-static void tx4939ide_dma_host_set(ide_drive_t *drive, int on)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 unit = drive->dn;
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-
-       if (on)
-               dma_stat |= (1 << (5 + unit));
-       else
-               dma_stat &= ~(1 << (5 + unit));
-
-       tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat);
-}
-#else
-#define tx4939ide_dma_host_set ide_dma_host_set
-#endif
-
-static u8 tx4939ide_clear_dma_status(void __iomem *base)
-{
-       u8 dma_stat;
-
-       /* read DMA status for INTR & ERROR flags */
-       dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-       /* clear INTR & ERROR flags */
-       tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base,
-                        TX4939IDE_DMA_Stat);
-       /* recover intmask cleared by writing to bit2 of DMA_Stat */
-       tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl);
-       return dma_stat;
-}
-
-#ifdef __BIG_ENDIAN
-/* custom ide_build_dmatable to handle swapped layout */
-static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u32 *table = (u32 *)hwif->dmatable_cpu;
-       unsigned int count = 0;
-       int i;
-       struct scatterlist *sg;
-
-       for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
-               u32 cur_addr, cur_len, bcount;
-
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               /*
-                * Fill in the DMA table, without crossing any 64kB boundaries.
-                */
-
-               while (cur_len) {
-                       if (count++ >= PRD_ENTRIES)
-                               goto use_pio_instead;
-
-                       bcount = 0x10000 - (cur_addr & 0xffff);
-                       if (bcount > cur_len)
-                               bcount = cur_len;
-                       /*
-                        * This workaround for zero count seems required.
-                        * (standard ide_build_dmatable does it too)
-                        */
-                       if (bcount == 0x10000)
-                               bcount = 0x8000;
-                       *table++ = bcount & 0xffff;
-                       *table++ = cur_addr;
-                       cur_addr += bcount;
-                       cur_len -= bcount;
-               }
-       }
-
-       if (count) {
-               *(table - 2) |= 0x80000000;
-               return count;
-       }
-
-use_pio_instead:
-       printk(KERN_ERR "%s: %s\n", drive->name,
-               count ? "DMA table too small" : "empty DMA table?");
-
-       return 0; /* revert to PIO for this request */
-}
-#else
-#define tx4939ide_build_dmatable       ide_build_dmatable
-#endif
-
-static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
-
-       /* fall back to PIO! */
-       if (tx4939ide_build_dmatable(drive, cmd) == 0)
-               return 1;
-
-       /* PRD table */
-       tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr);
-
-       /* specify r/w */
-       tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd);
-
-       /* clear INTR & ERROR flags */
-       tx4939ide_clear_dma_status(base);
-
-       tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
-                        TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
-
-       tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt);
-
-       return 0;
-}
-
-static int tx4939ide_dma_end(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       u8 dma_stat, dma_cmd;
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
-
-       /* get DMA command mode */
-       dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd);
-       /* stop DMA */
-       tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd);
-
-       /* read and clear the INTR & ERROR bits */
-       dma_stat = tx4939ide_clear_dma_status(base);
-
-#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
-
-       /* verify good DMA status */
-       if ((dma_stat & CHECK_DMA_MASK) == 0 &&
-           (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) ==
-           (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST))
-               /* INT_IDE lost... bug? */
-               return 0;
-       return ((dma_stat & CHECK_DMA_MASK) !=
-               ATA_DMA_INTR) ? 0x10 | dma_stat : 0;
-}
-
-/* returns 1 if DMA IRQ issued, 0 otherwise */
-static int tx4939ide_dma_test_irq(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u16 ctl, ide_int;
-       u8 dma_stat, stat;
-       int found = 0;
-
-       ctl = tx4939ide_check_error_ints(hwif);
-       ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST);
-       switch (ide_int) {
-       case TX4939IDE_INT_HOST:
-               /* On error, XFEREND might not be asserted. */
-               stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl);
-               if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR)
-                       found = 1;
-               else
-                       /* Wait for XFEREND (Mask HOST and unmask XFEREND) */
-                       ctl &= ~TX4939IDE_INT_XFEREND << 8;
-               ctl |= ide_int << 8;
-               break;
-       case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND:
-               dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-               if (!(dma_stat & ATA_DMA_INTR))
-                       pr_warn("%s: weird interrupt status. "
-                               "DMA_Stat %#02x int_ctl %#04x\n",
-                               hwif->name, dma_stat, ctl);
-               found = 1;
-               break;
-       }
-       /*
-        * Do not clear XFEREND, HOST now.  They will be cleared by
-        * clearing bit2 of DMA_Stat.
-        */
-       ctl &= ~ide_int;
-       tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
-       return found;
-}
-
-#ifdef __BIG_ENDIAN
-static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif)
-{
-       void __iomem *base = TX4939IDE_BASE(hwif);
-
-       return tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-}
-#else
-#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status
-#endif
-
-static void tx4939ide_init_hwif(ide_hwif_t *hwif)
-{
-       void __iomem *base = TX4939IDE_BASE(hwif);
-
-       /* Soft Reset */
-       tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl);
-       /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */
-       ndelay(450);
-       tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl);
-       /* mask some interrupts and clear all interrupts */
-       tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base,
-                        TX4939IDE_Int_Ctl);
-
-       tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt);
-       tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt);
-}
-
-static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       hwif->dma_base =
-               hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd);
-       /*
-        * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS
-        * for big endian.
-        */
-       return ide_allocate_dma_engine(hwif);
-}
-
-static void tx4939ide_tf_load_fixup(ide_drive_t *drive)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       void __iomem *base = TX4939IDE_BASE(hwif);
-       u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0);
-
-       /*
-        * Fix ATA100 CORE System Control Register. (The write to the
-        * Device/Head register may write wrong data to the System
-        * Control Register)
-        * While Sys_Ctl is written here, dev_select() is not needed.
-        */
-       tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
-}
-
-static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf,
-                             u8 valid)
-{
-       ide_tf_load(drive, tf, valid);
-
-       if (valid & IDE_VALID_DEVICE)
-               tx4939ide_tf_load_fixup(drive);
-}
-
-#ifdef __BIG_ENDIAN
-
-/* custom iops (independent from SWAP_IO_SPACE) */
-static void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
-                               void *buf, unsigned int len)
-{
-       unsigned long port = drive->hwif->io_ports.data_addr;
-       unsigned short *ptr = buf;
-       unsigned int count = (len + 1) / 2;
-
-       while (count--)
-               *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
-       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
-                               void *buf, unsigned int len)
-{
-       unsigned long port = drive->hwif->io_ports.data_addr;
-       unsigned short *ptr = buf;
-       unsigned int count = (len + 1) / 2;
-
-       while (count--) {
-               __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
-               ptr++;
-       }
-       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static const struct ide_tp_ops tx4939ide_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ide_dev_select,
-       .tf_load                = tx4939ide_tf_load,
-       .tf_read                = ide_tf_read,
-
-       .input_data             = tx4939ide_input_data_swap,
-       .output_data            = tx4939ide_output_data_swap,
-};
-
-#else  /* __LITTLE_ENDIAN */
-
-static const struct ide_tp_ops tx4939ide_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ide_dev_select,
-       .tf_load                = tx4939ide_tf_load,
-       .tf_read                = ide_tf_read,
-
-       .input_data             = ide_input_data,
-       .output_data            = ide_output_data,
-};
-
-#endif /* __LITTLE_ENDIAN */
-
-static const struct ide_port_ops tx4939ide_port_ops = {
-       .set_pio_mode           = tx4939ide_set_pio_mode,
-       .set_dma_mode           = tx4939ide_set_dma_mode,
-       .clear_irq              = tx4939ide_clear_irq,
-       .cable_detect           = tx4939ide_cable_detect,
-};
-
-static const struct ide_dma_ops tx4939ide_dma_ops = {
-       .dma_host_set           = tx4939ide_dma_host_set,
-       .dma_setup              = tx4939ide_dma_setup,
-       .dma_start              = ide_dma_start,
-       .dma_end                = tx4939ide_dma_end,
-       .dma_test_irq           = tx4939ide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-       .dma_timer_expiry       = ide_dma_sff_timer_expiry,
-       .dma_sff_read_status    = tx4939ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info tx4939ide_port_info __initconst = {
-       .init_hwif              = tx4939ide_init_hwif,
-       .init_dma               = tx4939ide_init_dma,
-       .port_ops               = &tx4939ide_port_ops,
-       .dma_ops                = &tx4939ide_dma_ops,
-       .tp_ops                 = &tx4939ide_tp_ops,
-       .host_flags             = IDE_HFLAG_MMIO,
-       .pio_mask               = ATA_PIO4,
-       .mwdma_mask             = ATA_MWDMA2,
-       .udma_mask              = ATA_UDMA5,
-       .chipset                = ide_generic,
-};
-
-static int __init tx4939ide_probe(struct platform_device *pdev)
-{
-       struct ide_hw hw, *hws[] = { &hw };
-       struct ide_host *host;
-       struct resource *res;
-       int irq, ret;
-       unsigned long mapbase;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return -ENODEV;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), MODNAME))
-               return -EBUSY;
-       mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
-                                             resource_size(res));
-       if (!mapbase)
-               return -EBUSY;
-       memset(&hw, 0, sizeof(hw));
-       hw.io_ports.data_addr =
-               mapbase + tx4939ide_swizzlew(TX4939IDE_Data);
-       hw.io_ports.error_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature);
-       hw.io_ports.nsect_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_Sec);
-       hw.io_ports.lbal_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0);
-       hw.io_ports.lbam_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1);
-       hw.io_ports.lbah_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2);
-       hw.io_ports.device_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead);
-       hw.io_ports.command_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd);
-       hw.io_ports.ctl_addr =
-               mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl);
-       hw.irq = irq;
-       hw.dev = &pdev->dev;
-
-       pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq);
-       host = ide_host_alloc(&tx4939ide_port_info, hws, 1);
-       if (!host)
-               return -ENOMEM;
-       /* use extra_base for base address of the all registers */
-       host->ports[0]->extra_base = mapbase;
-       ret = ide_host_register(host, &tx4939ide_port_info, hws);
-       if (ret) {
-               ide_host_free(host);
-               return ret;
-       }
-       platform_set_drvdata(pdev, host);
-       return 0;
-}
-
-static int __exit tx4939ide_remove(struct platform_device *pdev)
-{
-       struct ide_host *host = platform_get_drvdata(pdev);
-
-       ide_host_remove(host);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int tx4939ide_resume(struct platform_device *dev)
-{
-       struct ide_host *host = platform_get_drvdata(dev);
-       ide_hwif_t *hwif = host->ports[0];
-
-       tx4939ide_init_hwif(hwif);
-       return 0;
-}
-#else
-#define tx4939ide_resume       NULL
-#endif
-
-static struct platform_driver tx4939ide_driver = {
-       .driver = {
-               .name = MODNAME,
-       },
-       .remove = __exit_p(tx4939ide_remove),
-       .resume = tx4939ide_resume,
-};
-
-module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe);
-
-MODULE_DESCRIPTION("TX4939 internal IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:tx4939ide");
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
deleted file mode 100644 (file)
index cf996f7..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- *  This file provides support for the advanced features
- *  of the UMC 8672 IDE interface.
- *
- *  Version 0.01       Initial version, hacked out of ide.c,
- *                     and #include'd rather than compiled separately.
- *                     This will get cleaned up in a subsequent release.
- *
- *  Version 0.02       now configs/compiles separate from ide.c  -ml
- *  Version 0.03       enhanced auto-tune, fix display bug
- *  Version 0.05       replace sti() with restore_flags()  -ml
- *                     add detection of possible race condition  -ml
- */
-
-/*
- * VLB Controller Support from
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO         /* some systems can safely undef this */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "umc8672"
-
-/*
- * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0      1              /* DOS measured drive speeds */
-#define UMC_DRIVE1      1              /* 0 to 11 allowed */
-#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
-#define UMC_DRIVE3      1              /* In case of crash reduce speed */
-
-static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11};    /* rough guesses */
-
-/*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const u8 speedtab [3][12] = {
-       {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
-       {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
-       {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0}
-};
-
-static void out_umc(char port, char wert)
-{
-       outb_p(port, 0x108);
-       outb_p(wert, 0x109);
-}
-
-static inline u8 in_umc(char port)
-{
-       outb_p(port, 0x108);
-       return inb_p(0x109);
-}
-
-static void umc_set_speeds(u8 speeds[])
-{
-       int i, tmp;
-
-       outb_p(0x5A, 0x108); /* enable umc */
-
-       out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
-       out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
-       tmp = 0;
-       for (i = 3; i >= 0; i--)
-               tmp = (tmp << 2) | speedtab[1][speeds[i]];
-       out_umc(0xdc, tmp);
-       for (i = 0; i < 4; i++) {
-               out_umc(0xd0 + i, speedtab[2][speeds[i]]);
-               out_umc(0xd8 + i, speedtab[2][speeds[i]]);
-       }
-       outb_p(0xa5, 0x108); /* disable umc */
-
-       printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
-               speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       ide_hwif_t *mate = hwif->mate;
-       unsigned long flags;
-       const u8 pio = drive->pio_mode - XFER_PIO_0;
-
-       printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
-               drive->name, pio, pio_to_umc[pio]);
-       if (mate)
-               spin_lock_irqsave(&mate->lock, flags);
-       if (mate && mate->handler) {
-               printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
-       } else {
-               current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-               umc_set_speeds(current_speeds);
-       }
-       if (mate)
-               spin_unlock_irqrestore(&mate->lock, flags);
-}
-
-static const struct ide_port_ops umc8672_port_ops = {
-       .set_pio_mode           = umc_set_pio_mode,
-};
-
-static const struct ide_port_info umc8672_port_info __initconst = {
-       .name                   = DRV_NAME,
-       .chipset                = ide_umc8672,
-       .port_ops               = &umc8672_port_ops,
-       .host_flags             = IDE_HFLAG_NO_DMA,
-       .pio_mask               = ATA_PIO4,
-};
-
-static int __init umc8672_probe(void)
-{
-       unsigned long flags;
-
-       if (!request_region(0x108, 2, "umc8672")) {
-               printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
-               return 1;
-       }
-       local_irq_save(flags);
-       outb_p(0x5A, 0x108); /* enable umc */
-       if (in_umc (0xd5) != 0xa0) {
-               local_irq_restore(flags);
-               printk(KERN_ERR "umc8672: not found\n");
-               release_region(0x108, 2);
-               return 1;
-       }
-       outb_p(0xa5, 0x108); /* disable umc */
-
-       umc_set_speeds(current_speeds);
-       local_irq_restore(flags);
-
-       return ide_legacy_device_add(&umc8672_port_info, 0);
-}
-
-static bool probe_umc8672;
-
-module_param_named(probe, probe_umc8672, bool, 0);
-MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
-
-static int __init umc8672_init(void)
-{
-       if (probe_umc8672 == 0)
-               goto out;
-
-       if (umc8672_probe() == 0)
-               return 0;
-out:
-       return -ENODEV;
-}
-
-module_init(umc8672_init);
-
-MODULE_AUTHOR("Wolfram Podien");
-MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
deleted file mode 100644 (file)
index 63a3aca..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * VIA IDE driver for Linux. Supported southbridges:
- *
- *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- *   vt8235, vt8237, vt8237a
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * Based on the work of:
- *     Michel Aubry
- *     Jeff Garzik
- *     Andre Hedrick
- *
- * Documentation:
- *     Obsolete device documentation publicly available from via.com.tw
- *     Current device documentation available under NDA only
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/dmi.h>
-
-#ifdef CONFIG_PPC_CHRP
-#include <asm/processor.h>
-#endif
-
-#define DRV_NAME "via82cxxx"
-
-#define VIA_IDE_ENABLE         0x40
-#define VIA_IDE_CONFIG         0x41
-#define VIA_FIFO_CONFIG                0x43
-#define VIA_MISC_1             0x44
-#define VIA_MISC_2             0x45
-#define VIA_MISC_3             0x46
-#define VIA_DRIVE_TIMING       0x48
-#define VIA_8BIT_TIMING                0x4e
-#define VIA_ADDRESS_SETUP      0x4c
-#define VIA_UDMA_TIMING                0x50
-
-#define VIA_BAD_PREQ           0x01 /* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66          0x02 /* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO           0x04 /* Needs to have FIFO split set */
-#define VIA_NO_UNMASK          0x08 /* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID             0x10 /* Has wrong vendor ID (0x1107) */
-#define VIA_BAD_AST            0x20 /* Don't touch Address Setup Timing */
-#define VIA_SATA_PATA          0x80 /* SATA/PATA combined configuration */
-
-enum {
-       VIA_IDFLAG_SINGLE = (1 << 1), /* single channel controller */
-};
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
-       char *name;
-       u16 id;
-       u8 rev_min;
-       u8 rev_max;
-       u8 udma_mask;
-       u8 flags;
-} via_isa_bridges[] = {
-       { "vx855",      PCI_DEVICE_ID_VIA_VX855,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
-       { "vx800",      PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
-       { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
-       { "vt8261",     PCI_DEVICE_ID_VIA_8261,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt6415",     PCI_DEVICE_ID_VIA_6415,     0x00, 0xff, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8233a",    PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { "vt8233c",    PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, ATA_UDMA5, },
-       { "vt8233",     PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, ATA_UDMA5, },
-       { "vt8231",     PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, ATA_UDMA5, },
-       { "vt82c686b",  PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, ATA_UDMA5, },
-       { "vt82c686a",  PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, ATA_UDMA4, },
-       { "vt82c686",   PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
-       { "vt82c596b",  PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, ATA_UDMA4, },
-       { "vt82c596a",  PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
-       { "vt82c586b",  PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
-       { "vt82c586a",  PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
-       { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f,      0x00, VIA_SET_FIFO },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
-       { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f,      0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-       { "vtxxxx",     PCI_DEVICE_ID_VIA_ANON,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
-       { NULL }
-};
-
-static unsigned int via_clock;
-static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
-
-struct via82cxxx_dev
-{
-       struct via_isa_bridge *via_config;
-       unsigned int via_80w;
-};
-
-/**
- *     via_set_speed                   -       write timing registers
- *     @dev: PCI device
- *     @dn: device
- *     @timing: IDE timing data to use
- *
- *     via_set_speed writes timing values to the chipset registers
- */
-
-static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
-{
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct via82cxxx_dev *vdev = host->host_priv;
-       u8 t;
-
-       if (~vdev->via_config->flags & VIA_BAD_AST) {
-               pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-               t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-               pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
-       }
-
-       pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
-               ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
-
-       pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
-               ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
-
-       switch (vdev->via_config->udma_mask) {
-       case ATA_UDMA2: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
-       case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break;
-       case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
-       case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
-       }
-
-       /* Set UDMA unless device is not UDMA capable */
-       if (vdev->via_config->udma_mask) {
-               u8 udma_etc;
-
-               pci_read_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, &udma_etc);
-
-               /* clear transfer mode bit */
-               udma_etc &= ~0x20;
-
-               if (timing->udma) {
-                       /* preserve 80-wire cable detection bit */
-                       udma_etc &= 0x10;
-                       udma_etc |= t;
-               }
-
-               pci_write_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, udma_etc);
-       }
-}
-
-/**
- *     via_set_drive           -       configure transfer mode
- *     @hwif: port
- *     @drive: Drive to set up
- *
- *     via_set_drive() computes timing values configures the chipset to
- *     a desired transfer mode.  It also can be called by upper layers.
- */
-
-static void via_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       ide_drive_t *peer = ide_get_pair_dev(drive);
-       struct ide_host *host = dev_get_drvdata(hwif->dev);
-       struct via82cxxx_dev *vdev = host->host_priv;
-       struct ide_timing t, p;
-       unsigned int T, UT;
-       const u8 speed = drive->dma_mode;
-
-       T = 1000000000 / via_clock;
-
-       switch (vdev->via_config->udma_mask) {
-       case ATA_UDMA2: UT = T;   break;
-       case ATA_UDMA4: UT = T/2; break;
-       case ATA_UDMA5: UT = T/3; break;
-       case ATA_UDMA6: UT = T/4; break;
-       default:        UT = T;
-       }
-
-       ide_timing_compute(drive, speed, &t, T, UT);
-
-       if (peer) {
-               ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
-               ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-       }
-
-       via_set_speed(hwif, drive->dn, &t);
-}
-
-/**
- *     via_set_pio_mode        -       set host controller for PIO mode
- *     @hwif: port
- *     @drive: drive
- *
- *     A callback from the upper layers for PIO-only tuning.
- */
-
-static void via_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       drive->dma_mode = drive->pio_mode;
-       via_set_drive(hwif, drive);
-}
-
-static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
-{
-       struct via_isa_bridge *via_config;
-
-       for (via_config = via_isa_bridges;
-            via_config->id != PCI_DEVICE_ID_VIA_ANON; via_config++)
-               if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
-                       !!(via_config->flags & VIA_BAD_ID),
-                       via_config->id, NULL))) {
-
-                       if ((*isa)->revision >= via_config->rev_min &&
-                           (*isa)->revision <= via_config->rev_max)
-                               break;
-                       pci_dev_put(*isa);
-               }
-
-       return via_config;
-}
-
-/*
- * Check and handle 80-wire cable presence
- */
-static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
-{
-       int i;
-
-       switch (vdev->via_config->udma_mask) {
-               case ATA_UDMA4:
-                       for (i = 24; i >= 0; i -= 8)
-                               if (((u >> (i & 16)) & 8) &&
-                                   ((u >> i) & 0x20) &&
-                                    (((u >> i) & 7) < 2)) {
-                                       /*
-                                        * 2x PCI clock and
-                                        * UDMA w/ < 3T/cycle
-                                        */
-                                       vdev->via_80w |= (1 << (1 - (i >> 4)));
-                               }
-                       break;
-
-               case ATA_UDMA5:
-                       for (i = 24; i >= 0; i -= 8)
-                               if (((u >> i) & 0x10) ||
-                                   (((u >> i) & 0x20) &&
-                                    (((u >> i) & 7) < 4))) {
-                                       /* BIOS 80-wire bit or
-                                        * UDMA w/ < 60ns/cycle
-                                        */
-                                       vdev->via_80w |= (1 << (1 - (i >> 4)));
-                               }
-                       break;
-
-               case ATA_UDMA6:
-                       for (i = 24; i >= 0; i -= 8)
-                               if (((u >> i) & 0x10) ||
-                                   (((u >> i) & 0x20) &&
-                                    (((u >> i) & 7) < 6))) {
-                                       /* BIOS 80-wire bit or
-                                        * UDMA w/ < 60ns/cycle
-                                        */
-                                       vdev->via_80w |= (1 << (1 - (i >> 4)));
-                               }
-                       break;
-       }
-}
-
-/**
- *     init_chipset_via82cxxx  -       initialization handler
- *     @dev: PCI device
- *
- *     The initialization callback. Here we determine the IDE chip type
- *     and initialize its drive independent registers.
- */
-
-static int init_chipset_via82cxxx(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct via82cxxx_dev *vdev = host->host_priv;
-       struct via_isa_bridge *via_config = vdev->via_config;
-       u8 t, v;
-       u32 u;
-
-       /*
-        * Detect cable and configure Clk66
-        */
-       pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-
-       via_cable_detect(vdev, u);
-
-       if (via_config->udma_mask == ATA_UDMA4) {
-               /* Enable Clk66 */
-               pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
-       } else if (via_config->flags & VIA_BAD_CLK66) {
-               /* Would cause trouble on 596a and 686 */
-               pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
-       }
-
-       /*
-        * Check whether interfaces are enabled.
-        */
-
-       pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-
-       /*
-        * Set up FIFO sizes and thresholds.
-        */
-
-       pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
-       /* Disable PREQ# till DDACK# */
-       if (via_config->flags & VIA_BAD_PREQ) {
-               /* Would crash on 586b rev 41 */
-               t &= 0x7f;
-       }
-
-       /* Fix FIFO split between channels */
-       if (via_config->flags & VIA_SET_FIFO) {
-               t &= (t & 0x9f);
-               switch (v & 3) {
-                       case 2: t |= 0x00; break;       /* 16 on primary */
-                       case 1: t |= 0x60; break;       /* 16 on secondary */
-                       case 3: t |= 0x20; break;       /* 8 pri 8 sec */
-               }
-       }
-
-       pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
-       return 0;
-}
-
-/*
- *     Cable special cases
- */
-
-static const struct dmi_system_id cable_dmi_table[] = {
-       {
-               .ident = "Acer Ferrari 3400",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."),
-                       DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"),
-               },
-       },
-       { }
-};
-
-static int via_cable_override(struct pci_dev *pdev)
-{
-       /* Systems by DMI */
-       if (dmi_check_system(cable_dmi_table))
-               return 1;
-
-       /* Arima W730-K8/Targa Visionary 811/... */
-       if (pdev->subsystem_vendor == 0x161F &&
-           pdev->subsystem_device == 0x2032)
-               return 1;
-
-       return 0;
-}
-
-static u8 via82cxxx_cable_detect(ide_hwif_t *hwif)
-{
-       struct pci_dev *pdev = to_pci_dev(hwif->dev);
-       struct ide_host *host = pci_get_drvdata(pdev);
-       struct via82cxxx_dev *vdev = host->host_priv;
-
-       if (via_cable_override(pdev))
-               return ATA_CBL_PATA40_SHORT;
-
-       if ((vdev->via_config->flags & VIA_SATA_PATA) && hwif->channel == 0)
-               return ATA_CBL_SATA;
-
-       if ((vdev->via_80w >> hwif->channel) & 1)
-               return ATA_CBL_PATA80;
-       else
-               return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops via_port_ops = {
-       .set_pio_mode           = via_set_pio_mode,
-       .set_dma_mode           = via_set_drive,
-       .cable_detect           = via82cxxx_cable_detect,
-};
-
-static const struct ide_port_info via82cxxx_chipset = {
-       .name           = DRV_NAME,
-       .init_chipset   = init_chipset_via82cxxx,
-       .enablebits     = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
-       .port_ops       = &via_port_ops,
-       .host_flags     = IDE_HFLAG_PIO_NO_BLACKLIST |
-                         IDE_HFLAG_POST_SET_MODE |
-                         IDE_HFLAG_IO_32BIT,
-       .pio_mask       = ATA_PIO5,
-       .swdma_mask     = ATA_SWDMA2,
-       .mwdma_mask     = ATA_MWDMA2,
-};
-
-static int via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct pci_dev *isa = NULL;
-       struct via_isa_bridge *via_config;
-       struct via82cxxx_dev *vdev;
-       int rc;
-       u8 idx = id->driver_data;
-       struct ide_port_info d;
-
-       d = via82cxxx_chipset;
-
-       /*
-        * Find the ISA bridge and check we know what it is.
-        */
-       via_config = via_config_find(&isa);
-
-       /*
-        * Print the boot message.
-        */
-       printk(KERN_INFO DRV_NAME " %s: VIA %s (rev %02x) IDE %sDMA%s\n",
-               pci_name(dev), via_config->name, isa->revision,
-               via_config->udma_mask ? "U" : "MW",
-               via_dma[via_config->udma_mask ?
-                       (fls(via_config->udma_mask) - 1) : 0]);
-
-       pci_dev_put(isa);
-
-       /*
-        * Determine system bus clock.
-        */
-       via_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
-
-       switch (via_clock) {
-       case 33000: via_clock = 33333; break;
-       case 37000: via_clock = 37500; break;
-       case 41000: via_clock = 41666; break;
-       }
-
-       if (via_clock < 20000 || via_clock > 50000) {
-               printk(KERN_WARNING DRV_NAME ": User given PCI clock speed "
-                       "impossible (%d), using 33 MHz instead.\n", via_clock);
-               via_clock = 33333;
-       }
-
-       if (idx == 1)
-               d.enablebits[1].reg = d.enablebits[0].reg = 0;
-       else
-               d.host_flags |= IDE_HFLAG_NO_AUTODMA;
-
-       if (idx == VIA_IDFLAG_SINGLE)
-               d.host_flags |= IDE_HFLAG_SINGLE;
-
-       if ((via_config->flags & VIA_NO_UNMASK) == 0)
-               d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
-
-       d.udma_mask = via_config->udma_mask;
-
-       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
-       if (!vdev) {
-               printk(KERN_ERR DRV_NAME " %s: out of memory :(\n",
-                       pci_name(dev));
-               return -ENOMEM;
-       }
-
-       vdev->via_config = via_config;
-
-       rc = ide_pci_init_one(dev, &d, vdev);
-       if (rc)
-               kfree(vdev);
-
-       return rc;
-}
-
-static void via_remove(struct pci_dev *dev)
-{
-       struct ide_host *host = pci_get_drvdata(dev);
-       struct via82cxxx_dev *vdev = host->host_priv;
-
-       ide_pci_remove(dev);
-       kfree(vdev);
-}
-
-static const struct pci_device_id via_pci_tbl[] = {
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1),  0 },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1),  0 },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), VIA_IDFLAG_SINGLE },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410),      1 },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6415),      1 },
-       { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, via_pci_tbl);
-
-static struct pci_driver via_pci_driver = {
-       .name           = "VIA_IDE",
-       .id_table       = via_pci_tbl,
-       .probe          = via_init_one,
-       .remove         = via_remove,
-       .suspend        = ide_pci_suspend,
-       .resume         = ide_pci_resume,
-};
-
-static int __init via_ide_init(void)
-{
-       return ide_pci_register_driver(&via_pci_driver);
-}
-
-static void __exit via_ide_exit(void)
-{
-       pci_unregister_driver(&via_pci_driver);
-}
-
-module_init(via_ide_init);
-module_exit(via_ide_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz, Michel Aubry, Jeff Garzik, Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for VIA IDE");
-MODULE_LICENSE("GPL");
index ec1b9d3..e6c543b 100644 (file)
@@ -1484,6 +1484,36 @@ static void __init sklh_idle_state_table_update(void)
        skl_cstates[6].flags |= CPUIDLE_FLAG_UNUSABLE;  /* C9-SKL */
 }
 
+/**
+ * skx_idle_state_table_update - Adjust the Sky Lake/Cascade Lake
+ * idle states table.
+ */
+static void __init skx_idle_state_table_update(void)
+{
+       unsigned long long msr;
+
+       rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, msr);
+
+       /*
+        * 000b: C0/C1 (no package C-state support)
+        * 001b: C2
+        * 010b: C6 (non-retention)
+        * 011b: C6 (retention)
+        * 111b: No Package C state limits.
+        */
+       if ((msr & 0x7) < 2) {
+               /*
+                * Uses the CC6 + PC0 latency and 3 times of
+                * latency for target_residency if the PC6
+                * is disabled in BIOS. This is consistent
+                * with how intel_idle driver uses _CST
+                * to set the target_residency.
+                */
+               skx_cstates[2].exit_latency = 92;
+               skx_cstates[2].target_residency = 276;
+       }
+}
+
 static bool __init intel_idle_verify_cstate(unsigned int mwait_hint)
 {
        unsigned int mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint) + 1;
@@ -1515,6 +1545,9 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
        case INTEL_FAM6_SKYLAKE:
                sklh_idle_state_table_update();
                break;
+       case INTEL_FAM6_SKYLAKE_X:
+               skx_idle_state_table_update();
+               break;
        }
 
        for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
index 32d1580..40a070a 100644 (file)
@@ -67,9 +67,6 @@ config KEYBOARD_AMIGA
          To compile this driver as a module, choose M here: the
          module will be called amikbd.
 
-config ATARI_KBD_CORE
-       bool
-
 config KEYBOARD_APPLESPI
        tristate "Apple SPI keyboard and trackpad"
        depends on ACPI && EFI
index 62543a4..4d5924e 100644 (file)
@@ -415,7 +415,7 @@ config GOLDFISH_PIC
          for Goldfish based virtual platforms.
 
 config QCOM_PDC
-       bool "QCOM PDC"
+       tristate "QCOM PDC"
        depends on ARCH_QCOM
        select IRQ_DOMAIN_HIERARCHY
        help
index 0b85d9a..552aa04 100644 (file)
@@ -66,8 +66,9 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc)
 {
        struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned int cascade_irq, combiner_irq;
+       unsigned int combiner_irq;
        unsigned long status;
+       int ret;
 
        chained_irq_enter(chip, desc);
 
@@ -80,12 +81,9 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc)
                goto out;
 
        combiner_irq = chip_data->hwirq_offset + __ffs(status);
-       cascade_irq = irq_find_mapping(combiner_irq_domain, combiner_irq);
-
-       if (unlikely(!cascade_irq))
+       ret = generic_handle_domain_irq(combiner_irq_domain, combiner_irq);
+       if (unlikely(ret))
                handle_bad_irq(desc);
-       else
-               generic_handle_irq(cascade_irq);
 
  out:
        chained_irq_exit(chip, desc);
@@ -179,10 +177,8 @@ static void __init combiner_init(void __iomem *combiner_base,
        nr_irq = max_nr * IRQ_IN_COMBINER;
 
        combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL);
-       if (!combiner_data) {
-               pr_warn("%s: could not allocate combiner data\n", __func__);
+       if (!combiner_data)
                return;
-       }
 
        combiner_irq_domain = irq_domain_add_linear(np, nr_irq,
                                &combiner_irq_domain_ops, combiner_data);
index 0b0a737..886de02 100644 (file)
@@ -111,7 +111,6 @@ static void al_fic_irq_handler(struct irq_desc *desc)
        struct irq_chip *irqchip = irq_desc_get_chip(desc);
        struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
        unsigned long pending;
-       unsigned int irq;
        u32 hwirq;
 
        chained_irq_enter(irqchip, desc);
@@ -119,10 +118,8 @@ static void al_fic_irq_handler(struct irq_desc *desc)
        pending = readl_relaxed(fic->base + AL_FIC_CAUSE);
        pending &= ~gc->mask_cache;
 
-       for_each_set_bit(hwirq, &pending, NR_FIC_IRQS) {
-               irq = irq_find_mapping(domain, hwirq);
-               generic_handle_irq(irq);
-       }
+       for_each_set_bit(hwirq, &pending, NR_FIC_IRQS)
+               generic_handle_domain_irq(domain, hwirq);
 
        chained_irq_exit(irqchip, desc);
 }
index c179e27..b8c06bd 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/cpuhotplug.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
+#include <linux/irqchip/arm-vgic-info.h>
 #include <linux/irqdomain.h>
 #include <linux/limits.h>
 #include <linux/of_address.h>
@@ -787,6 +788,12 @@ static int aic_init_cpu(unsigned int cpu)
        return 0;
 }
 
+static struct gic_kvm_info vgic_info __initdata = {
+       .type                   = GIC_V3,
+       .no_maint_irq_mask      = true,
+       .no_hw_deactivation     = true,
+};
+
 static int __init aic_of_ic_init(struct device_node *node, struct device_node *parent)
 {
        int i;
@@ -843,6 +850,8 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
                          "irqchip/apple-aic/ipi:starting",
                          aic_init_cpu, NULL);
 
+       vgic_set_kvm_info(&vgic_info);
+
        pr_info("Initialized with %d IRQs, %d FIQs, %d vIPIs\n",
                irqc->nr_hw, AIC_NR_FIQ, AIC_NR_SWIPI);
 
index 32938df..7557ab5 100644 (file)
@@ -582,20 +582,19 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
 
        for (msinr = PCI_MSI_DOORBELL_START;
             msinr < PCI_MSI_DOORBELL_END; msinr++) {
-               int irq;
+               unsigned int irq;
 
                if (!(msimask & BIT(msinr)))
                        continue;
 
-               if (is_chained) {
-                       irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
-                                              msinr - PCI_MSI_DOORBELL_START);
-                       generic_handle_irq(irq);
-               } else {
-                       irq = msinr - PCI_MSI_DOORBELL_START;
+               irq = msinr - PCI_MSI_DOORBELL_START;
+
+               if (is_chained)
+                       generic_handle_domain_irq(armada_370_xp_msi_inner_domain,
+                                                 irq);
+               else
                        handle_domain_irq(armada_370_xp_msi_inner_domain,
                                          irq, regs);
-               }
        }
 }
 #else
@@ -606,7 +605,6 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned long irqmap, irqn, irqsrc, cpuid;
-       unsigned int cascade_irq;
 
        chained_irq_enter(chip, desc);
 
@@ -628,8 +626,7 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
                        continue;
                }
 
-               cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
-               generic_handle_irq(cascade_irq);
+               generic_handle_domain_irq(armada_370_xp_mpic_domain, irqn);
        }
 
        chained_irq_exit(chip, desc);
index 8d591c1..a47db16 100644 (file)
@@ -34,14 +34,12 @@ static void aspeed_i2c_ic_irq_handler(struct irq_desc *desc)
        struct aspeed_i2c_ic *i2c_ic = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned long bit, status;
-       unsigned int bus_irq;
 
        chained_irq_enter(chip, desc);
        status = readl(i2c_ic->base);
-       for_each_set_bit(bit, &status, ASPEED_I2C_IC_NUM_BUS) {
-               bus_irq = irq_find_mapping(i2c_ic->irq_domain, bit);
-               generic_handle_irq(bus_irq);
-       }
+       for_each_set_bit(bit, &status, ASPEED_I2C_IC_NUM_BUS)
+               generic_handle_domain_irq(i2c_ic->irq_domain, bit);
+
        chained_irq_exit(chip, desc);
 }
 
index c90a334..f3c6855 100644 (file)
@@ -44,7 +44,6 @@ struct aspeed_scu_ic {
 
 static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
 {
-       unsigned int irq;
        unsigned int sts;
        unsigned long bit;
        unsigned long enabled;
@@ -74,9 +73,8 @@ static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
        max = scu_ic->num_irqs + bit;
 
        for_each_set_bit_from(bit, &status, max) {
-               irq = irq_find_mapping(scu_ic->irq_domain,
-                                      bit - scu_ic->irq_shift);
-               generic_handle_irq(irq);
+               generic_handle_domain_irq(scu_ic->irq_domain,
+                                         bit - scu_ic->irq_shift);
 
                regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
                                   BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
index 3d641bb..92f001a 100644 (file)
@@ -50,7 +50,7 @@ static void ath79_misc_irq_handler(struct irq_desc *desc)
        while (pending) {
                int bit = __ffs(pending);
 
-               generic_handle_irq(irq_linear_revmap(domain, bit));
+               generic_handle_domain_irq(domain, bit);
                pending &= ~BIT(bit);
        }
 
index a1e004a..adc1556 100644 (file)
@@ -254,7 +254,7 @@ static void bcm2836_chained_handle_irq(struct irq_desc *desc)
        u32 hwirq;
 
        while ((hwirq = get_next_armctrl_hwirq()) != ~0)
-               generic_handle_irq(irq_linear_revmap(intc.domain, hwirq));
+               generic_handle_domain_irq(intc.domain, hwirq);
 }
 
 IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic",
index 25c9a9c..501facd 100644 (file)
@@ -161,7 +161,7 @@ static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
        mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
        if (mbox_val) {
                int hwirq = ffs(mbox_val) - 1;
-               generic_handle_irq(irq_find_mapping(ipi_domain, hwirq));
+               generic_handle_domain_irq(ipi_domain, hwirq);
        }
 
        chained_irq_exit(chip, desc);
index 9dc9bf8..a035c38 100644 (file)
@@ -145,10 +145,8 @@ static void bcm7038_l1_irq_handle(struct irq_desc *desc)
                          ~cpu->mask_cache[idx];
                raw_spin_unlock_irqrestore(&intc->lock, flags);
 
-               for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
-                       generic_handle_irq(irq_find_mapping(intc->domain,
-                                                           base + hwirq));
-               }
+               for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
+                       generic_handle_domain_irq(intc->domain, base + hwirq);
        }
 
        chained_irq_exit(chip, desc);
index ad59656..f23d765 100644 (file)
@@ -74,10 +74,8 @@ static void bcm7120_l2_intc_irq_handle(struct irq_desc *desc)
                                            data->irq_map_mask[idx];
                irq_gc_unlock(gc);
 
-               for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
-                       generic_handle_irq(irq_find_mapping(b->domain,
-                                          base + hwirq));
-               }
+               for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
+                       generic_handle_domain_irq(b->domain, base + hwirq);
        }
 
        chained_irq_exit(chip, desc);
index cdd6a42..8e09115 100644 (file)
@@ -110,7 +110,7 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
        do {
                irq = ffs(status) - 1;
                status &= ~(1 << irq);
-               generic_handle_irq(irq_linear_revmap(b->domain, irq));
+               generic_handle_domain_irq(b->domain, irq);
        } while (status);
 out:
        chained_irq_exit(chip, desc);
index 54b09d6..a67266e 100644 (file)
@@ -62,9 +62,8 @@ static void dw_apb_ictl_handle_irq_cascaded(struct irq_desc *desc)
 
                while (stat) {
                        u32 hwirq = ffs(stat) - 1;
-                       u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
+                       generic_handle_domain_irq(d, gc->irq_base + hwirq);
 
-                       generic_handle_irq(virq);
                        stat &= ~BIT(hwirq);
                }
        }
index f47b41d..a610821 100644 (file)
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
-static const struct gic_kvm_info *gic_kvm_info;
-
-const struct gic_kvm_info *gic_get_kvm_info(void)
-{
-       return gic_kvm_info;
-}
-
-void gic_set_kvm_info(const struct gic_kvm_info *info)
-{
-       BUG_ON(gic_kvm_info != NULL);
-       gic_kvm_info = info;
-}
-
 void gic_enable_of_quirks(const struct device_node *np,
                          const struct gic_quirk *quirks, void *data)
 {
index ccba8b0..27e3d4e 100644 (file)
@@ -28,6 +28,4 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
 void gic_enable_of_quirks(const struct device_node *np,
                          const struct gic_quirk *quirks, void *data);
 
-void gic_set_kvm_info(const struct gic_kvm_info *info);
-
 #endif /* _IRQ_GIC_COMMON_H */
index 1337cec..b60e185 100644 (file)
@@ -30,10 +30,8 @@ static int gic_runtime_resume(struct device *dev)
        int ret;
 
        ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks);
-       if (ret) {
-               dev_err(dev, "clk_enable failed: %d\n", ret);
+       if (ret)
                return ret;
-       }
 
        /*
         * On the very first resume, the pointer to chip_pm->chip_data
index 4116b48..be9ea6f 100644 (file)
@@ -323,10 +323,8 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
        struct v2m_data *v2m;
 
        v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
-       if (!v2m) {
-               pr_err("Failed to allocate struct v2m_data.\n");
+       if (!v2m)
                return -ENOMEM;
-       }
 
        INIT_LIST_HEAD(&v2m->entry);
        v2m->fwnode = fwnode;
index 2e6923c..ba39668 100644 (file)
@@ -4895,10 +4895,8 @@ static int its_init_vpe_domain(void)
        entries = roundup_pow_of_two(nr_cpu_ids);
        vpe_proxy.vpes = kcalloc(entries, sizeof(*vpe_proxy.vpes),
                                 GFP_KERNEL);
-       if (!vpe_proxy.vpes) {
-               pr_err("ITS: Can't allocate GICv4 proxy device array\n");
+       if (!vpe_proxy.vpes)
                return -ENOMEM;
-       }
 
        /* Use the last possible DevID */
        devid = GENMASK(device_ids(its) - 1, 0);
@@ -5314,10 +5312,8 @@ static void __init acpi_table_parse_srat_its(void)
 
        its_srat_maps = kmalloc_array(count, sizeof(struct its_srat_map),
                                      GFP_KERNEL);
-       if (!its_srat_maps) {
-               pr_warn("SRAT: Failed to allocate memory for its_srat_maps!\n");
+       if (!its_srat_maps)
                return;
-       }
 
        acpi_table_parse_entries(ACPI_SIG_SRAT,
                        sizeof(struct acpi_table_srat),
index 37a23aa..e0f4deb 100644 (file)
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(gic_nonsecure_priorities);
 /* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
 static refcount_t *ppi_nmi_refs;
 
-static struct gic_kvm_info gic_v3_kvm_info;
+static struct gic_kvm_info gic_v3_kvm_info __initdata;
 static DEFINE_PER_CPU(bool, has_rss);
 
 #define MPIDR_RS(mpidr)                        (((mpidr) & 0xF0UL) >> 4)
@@ -642,11 +642,45 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
                nmi_exit();
 }
 
+static u32 do_read_iar(struct pt_regs *regs)
+{
+       u32 iar;
+
+       if (gic_supports_nmi() && unlikely(!interrupts_enabled(regs))) {
+               u64 pmr;
+
+               /*
+                * We were in a context with IRQs disabled. However, the
+                * entry code has set PMR to a value that allows any
+                * interrupt to be acknowledged, and not just NMIs. This can
+                * lead to surprising effects if the NMI has been retired in
+                * the meantime, and that there is an IRQ pending. The IRQ
+                * would then be taken in NMI context, something that nobody
+                * wants to debug twice.
+                *
+                * Until we sort this, drop PMR again to a level that will
+                * actually only allow NMIs before reading IAR, and then
+                * restore it to what it was.
+                */
+               pmr = gic_read_pmr();
+               gic_pmr_mask_irqs();
+               isb();
+
+               iar = gic_read_iar();
+
+               gic_write_pmr(pmr);
+       } else {
+               iar = gic_read_iar();
+       }
+
+       return iar;
+}
+
 static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
        u32 irqnr;
 
-       irqnr = gic_read_iar();
+       irqnr = do_read_iar(regs);
 
        /* Check for special IDs first */
        if ((irqnr >= 1020 && irqnr <= 1023))
@@ -1852,7 +1886,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
 
        gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
        gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
-       gic_set_kvm_info(&gic_v3_kvm_info);
+       vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
@@ -2168,7 +2202,7 @@ static void __init gic_acpi_setup_kvm_info(void)
 
        gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
        gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
-       gic_set_kvm_info(&gic_v3_kvm_info);
+       vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
 static int __init
index b1d9c22..d329ec3 100644 (file)
@@ -119,7 +119,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
 
 static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
 
-static struct gic_kvm_info gic_v2_kvm_info;
+static struct gic_kvm_info gic_v2_kvm_info __initdata;
 
 static DEFINE_PER_CPU(u32, sgi_intid);
 
@@ -375,8 +375,9 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
 {
        struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned int cascade_irq, gic_irq;
+       unsigned int gic_irq;
        unsigned long status;
+       int ret;
 
        chained_irq_enter(chip, desc);
 
@@ -386,14 +387,10 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
        if (gic_irq == GICC_INT_SPURIOUS)
                goto out;
 
-       cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
-       if (unlikely(gic_irq < 32 || gic_irq > 1020)) {
+       isb();
+       ret = generic_handle_domain_irq(chip_data->domain, gic_irq);
+       if (unlikely(ret))
                handle_bad_irq(desc);
-       } else {
-               isb();
-               generic_handle_irq(cascade_irq);
-       }
-
  out:
        chained_irq_exit(chip, desc);
 }
@@ -1451,7 +1448,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
                return;
 
        if (static_branch_likely(&supports_deactivate_key))
-               gic_set_kvm_info(&gic_v2_kvm_info);
+               vgic_set_kvm_info(&gic_v2_kvm_info);
 }
 
 int __init
@@ -1618,7 +1615,7 @@ static void __init gic_acpi_setup_kvm_info(void)
 
        gic_v2_kvm_info.maint_irq = irq;
 
-       gic_set_kvm_info(&gic_v2_kvm_info);
+       vgic_set_kvm_info(&gic_v2_kvm_info);
 }
 
 static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
index 4f02153..513f6ed 100644 (file)
@@ -34,15 +34,14 @@ static void goldfish_pic_cascade(struct irq_desc *desc)
 {
        struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc);
        struct irq_chip *host_chip = irq_desc_get_chip(desc);
-       u32 pending, hwirq, virq;
+       u32 pending, hwirq;
 
        chained_irq_enter(host_chip, desc);
 
        pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
        while (pending) {
                hwirq = __fls(pending);
-               virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
-               generic_handle_irq(virq);
+               generic_handle_domain_irq(gfpic->irq_domain, hwirq);
                pending &= ~(1 << hwirq);
        }
 
index b6f6aa7..b70ce0d 100644 (file)
@@ -333,13 +333,11 @@ static void i8259_irq_dispatch(struct irq_desc *desc)
 {
        struct irq_domain *domain = irq_desc_get_handler_data(desc);
        int hwirq = i8259_poll();
-       unsigned int irq;
 
        if (hwirq < 0)
                return;
 
-       irq = irq_linear_revmap(domain, hwirq);
-       generic_handle_irq(irq);
+       generic_handle_domain_irq(domain, hwirq);
 }
 
 int __init i8259_of_init(struct device_node *node, struct device_node *parent)
index f099682..0732a0e 100644 (file)
@@ -28,7 +28,7 @@ static void idt_irq_dispatch(struct irq_desc *desc)
 {
        struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc);
        struct irq_chip *host_chip = irq_desc_get_chip(desc);
-       u32 pending, hwirq, virq;
+       u32 pending, hwirq;
 
        chained_irq_enter(host_chip, desc);
 
@@ -36,9 +36,7 @@ static void idt_irq_dispatch(struct irq_desc *desc)
        pending &= ~idtpic->gc->mask_cache;
        while (pending) {
                hwirq = __fls(pending);
-               virq = irq_linear_revmap(idtpic->irq_domain, hwirq);
-               if (virq)
-                       generic_handle_irq(virq);
+               generic_handle_domain_irq(idtpic->irq_domain, hwirq);
                pending &= ~(1 << hwirq);
        }
 
index 698d07f..5831be4 100644 (file)
@@ -223,7 +223,7 @@ static void pdc_intc_perip_isr(struct irq_desc *desc)
 {
        unsigned int irq = irq_desc_get_irq(desc);
        struct pdc_intc_priv *priv;
-       unsigned int i, irq_no;
+       unsigned int i;
 
        priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
 
@@ -237,14 +237,13 @@ static void pdc_intc_perip_isr(struct irq_desc *desc)
 found:
 
        /* pass on the interrupt */
-       irq_no = irq_linear_revmap(priv->domain, i);
-       generic_handle_irq(irq_no);
+       generic_handle_domain_irq(priv->domain, i);
 }
 
 static void pdc_intc_syswake_isr(struct irq_desc *desc)
 {
        struct pdc_intc_priv *priv;
-       unsigned int syswake, irq_no;
+       unsigned int syswake;
        unsigned int status;
 
        priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
@@ -258,9 +257,7 @@ static void pdc_intc_syswake_isr(struct irq_desc *desc)
                if (!(status & 1))
                        continue;
 
-               irq_no = irq_linear_revmap(priv->domain,
-                                          syswake_to_hwirq(syswake));
-               generic_handle_irq(irq_no);
+               generic_handle_domain_irq(priv->domain, syswake_to_hwirq(syswake));
        }
 }
 
@@ -316,10 +313,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
 
        /* Allocate driver data */
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "cannot allocate device data\n");
+       if (!priv)
                return -ENOMEM;
-       }
        raw_spin_lock_init(&priv->lock);
        platform_set_drvdata(pdev, priv);
 
@@ -356,10 +351,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
        /* Get peripheral IRQ numbers */
        priv->perip_irqs = devm_kcalloc(&pdev->dev, 4, priv->nr_perips,
                                        GFP_KERNEL);
-       if (!priv->perip_irqs) {
-               dev_err(&pdev->dev, "cannot allocate perip IRQ list\n");
+       if (!priv->perip_irqs)
                return -ENOMEM;
-       }
        for (i = 0; i < priv->nr_perips; ++i) {
                irq = platform_get_irq(pdev, 1 + i);
                if (irq < 0)
index 7031ef4..5b5a365 100644 (file)
@@ -228,10 +228,8 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
        }
 
        cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
-       if (!cd) {
-               pr_err("%pOF: kzalloc failed!\n", node);
+       if (!cd)
                return -ENOMEM;
-       }
 
        raw_spin_lock_init(&cd->rlock);
 
index 7709f97..e86ff74 100644 (file)
@@ -182,18 +182,15 @@ static void imx_intmux_irq_handler(struct irq_desc *desc)
        struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
                                                irqchip_data[idx]);
        unsigned long irqstat;
-       int pos, virq;
+       int pos;
 
        chained_irq_enter(irq_desc_get_chip(desc), desc);
 
        /* read the interrupt source pending status of this channel */
        irqstat = readl_relaxed(data->regs + CHANIPR(idx));
 
-       for_each_set_bit(pos, &irqstat, 32) {
-               virq = irq_find_mapping(irqchip_data->domain, pos);
-               if (virq)
-                       generic_handle_irq(virq);
-       }
+       for_each_set_bit(pos, &irqstat, 32)
+               generic_handle_domain_irq(irqchip_data->domain, pos);
 
        chained_irq_exit(irq_desc_get_chip(desc), desc);
 }
index 1edf769..8d91a02 100644 (file)
@@ -122,7 +122,7 @@ static void imx_irqsteer_irq_handler(struct irq_desc *desc)
        for (i = 0; i < 2; i++, hwirq += 32) {
                int idx = imx_irqsteer_get_reg_index(data, hwirq);
                unsigned long irqmap;
-               int pos, virq;
+               int pos;
 
                if (hwirq >= data->reg_num * 32)
                        break;
@@ -130,11 +130,8 @@ static void imx_irqsteer_irq_handler(struct irq_desc *desc)
                irqmap = readl_relaxed(data->regs +
                                       CHANSTATUS(idx, data->reg_num));
 
-               for_each_set_bit(pos, &irqmap, 32) {
-                       virq = irq_find_mapping(data->domain, pos + hwirq);
-                       if (virq)
-                               generic_handle_irq(virq);
-               }
+               for_each_set_bit(pos, &irqmap, 32)
+                       generic_handle_domain_irq(data->domain, pos + hwirq);
        }
 
        chained_irq_exit(irq_desc_get_chip(desc), desc);
index b938d1d..34a7d26 100644 (file)
@@ -38,7 +38,7 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
        irq_reg &= ~irq_mask;
 
        for_each_set_bit(i, (unsigned long *)&irq_reg, 32)
-               generic_handle_irq(irq_linear_revmap(domain, i));
+               generic_handle_domain_irq(domain, i);
 
        chained_irq_exit(irq_chip, desc);
 }
index ea36bb0..cee839c 100644 (file)
@@ -49,8 +49,7 @@ static irqreturn_t intc_cascade(int irq, void *data)
                while (pending) {
                        int bit = __fls(pending);
 
-                       irq = irq_linear_revmap(domain, bit + (i * 32));
-                       generic_handle_irq(irq);
+                       generic_handle_domain_irq(domain, bit + (i * 32));
                        pending &= ~BIT(bit);
                }
        }
index 8118ebe..d47c804 100644 (file)
@@ -89,7 +89,7 @@ static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
        struct keystone_irq_device *kirq = keystone_irq;
        unsigned long wa_lock_flags;
        unsigned long pending;
-       int src, virq;
+       int src, err;
 
        dev_dbg(kirq->dev, "start irq %d\n", irq);
 
@@ -104,16 +104,14 @@ static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
 
        for (src = 0; src < KEYSTONE_N_IRQ; src++) {
                if (BIT(src) & pending) {
-                       virq = irq_find_mapping(kirq->irqd, src);
-                       dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n",
-                               src, virq);
-                       if (!virq)
-                               dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n",
-                                        src, virq);
                        raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags);
-                       generic_handle_irq(virq);
+                       err = generic_handle_domain_irq(kirq->irqd, src);
                        raw_spin_unlock_irqrestore(&kirq->wa_lock,
                                                   wa_lock_flags);
+
+                       if (err)
+                               dev_warn_ratelimited(kirq->dev, "spurious irq detected hwirq %d\n",
+                                                    src);
                }
        }
 
index 1b801c4..f4abdf1 100644 (file)
@@ -48,7 +48,7 @@ static void htpic_irq_dispatch(struct irq_desc *desc)
                        break;
                }
 
-               generic_handle_irq(irq_linear_revmap(priv->domain, bit));
+               generic_handle_domain_irq(priv->domain, bit);
                pending &= ~BIT(bit);
        }
        chained_irq_exit(chip, desc);
index 6392aaf..60a335d 100644 (file)
@@ -47,8 +47,8 @@ static void htvec_irq_dispatch(struct irq_desc *desc)
                while (pending) {
                        int bit = __ffs(pending);
 
-                       generic_handle_irq(irq_linear_revmap(priv->htvec_domain, bit +
-                                                            VEC_COUNT_PER_REG * i));
+                       generic_handle_domain_irq(priv->htvec_domain,
+                                                 bit + VEC_COUNT_PER_REG * i);
                        pending &= ~BIT(bit);
                        handled = true;
                }
index 8ccb304..649c583 100644 (file)
@@ -73,7 +73,7 @@ static void liointc_chained_handle_irq(struct irq_desc *desc)
        while (pending) {
                int bit = __ffs(pending);
 
-               generic_handle_irq(irq_find_mapping(gc->domain, bit));
+               generic_handle_domain_irq(gc->domain, bit);
                pending &= ~BIT(bit);
        }
 
index 7d9b388..5e6f6e2 100644 (file)
@@ -141,7 +141,7 @@ static void lpc32xx_sic_handler(struct irq_desc *desc)
        while (hwirq) {
                irq = __ffs(hwirq);
                hwirq &= ~BIT(irq);
-               generic_handle_irq(irq_find_mapping(ic->domain, irq));
+               generic_handle_domain_irq(ic->domain, irq);
        }
 
        chained_irq_exit(chip, desc);
index 61dbfda..55322da 100644 (file)
@@ -194,7 +194,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
        struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
        struct ls_scfg_msi *msi_data = msir->msi_data;
        unsigned long val;
-       int pos, size, virq, hwirq;
+       int pos, size, hwirq;
 
        chained_irq_enter(irq_desc_get_chip(desc), desc);
 
@@ -206,9 +206,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
        for_each_set_bit_from(pos, &val, size) {
                hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
                        msir->srs;
-               virq = irq_find_mapping(msi_data->parent, hwirq);
-               if (virq)
-                       generic_handle_irq(virq);
+               generic_handle_domain_irq(msi_data->parent, hwirq);
        }
 
        chained_irq_exit(irq_desc_get_chip(desc), desc);
index 353111a..77a3f7d 100644 (file)
@@ -50,7 +50,7 @@ static void ls1x_chained_handle_irq(struct irq_desc *desc)
        while (pending) {
                int bit = __ffs(pending);
 
-               generic_handle_irq(irq_find_mapping(priv->domain, bit));
+               generic_handle_domain_irq(priv->domain, bit);
                pending &= ~BIT(bit);
        }
 
index 2cb45c6..f565317 100644 (file)
@@ -273,6 +273,12 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
 }
 
 #ifdef CONFIG_ACPI
+static const struct acpi_device_id mbigen_acpi_match[] = {
+       { "HISI0152", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
+
 static int mbigen_acpi_create_domain(struct platform_device *pdev,
                                     struct mbigen_device *mgn_chip)
 {
@@ -369,12 +375,6 @@ static const struct of_device_id mbigen_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, mbigen_of_match);
 
-static const struct acpi_device_id mbigen_acpi_match[] = {
-       { "HISI0152", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
-
 static struct platform_driver mbigen_platform_driver = {
        .driver = {
                .name           = "Hisilicon MBIGEN-V2",
index 2158859..b146e06 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
+#include <linux/irqdomain.h>
 #include <linux/of_address.h>
 #include <linux/percpu.h>
 #include <linux/sched.h>
@@ -147,7 +148,7 @@ int gic_get_c0_fdc_int(void)
 
 static void gic_handle_shared_int(bool chained)
 {
-       unsigned int intr, virq;
+       unsigned int intr;
        unsigned long *pcpu_mask;
        DECLARE_BITMAP(pending, GIC_MAX_INTRS);
 
@@ -164,12 +165,12 @@ static void gic_handle_shared_int(bool chained)
        bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
 
        for_each_set_bit(intr, pending, gic_shared_intrs) {
-               virq = irq_linear_revmap(gic_irq_domain,
-                                        GIC_SHARED_TO_HWIRQ(intr));
                if (chained)
-                       generic_handle_irq(virq);
+                       generic_handle_domain_irq(gic_irq_domain,
+                                                 GIC_SHARED_TO_HWIRQ(intr));
                else
-                       do_IRQ(virq);
+                       do_IRQ(irq_find_mapping(gic_irq_domain,
+                                               GIC_SHARED_TO_HWIRQ(intr)));
        }
 }
 
@@ -307,7 +308,7 @@ static struct irq_chip gic_edge_irq_controller = {
 static void gic_handle_local_int(bool chained)
 {
        unsigned long pending, masked;
-       unsigned int intr, virq;
+       unsigned int intr;
 
        pending = read_gic_vl_pend();
        masked = read_gic_vl_mask();
@@ -315,12 +316,12 @@ static void gic_handle_local_int(bool chained)
        bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
 
        for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) {
-               virq = irq_linear_revmap(gic_irq_domain,
-                                        GIC_LOCAL_TO_HWIRQ(intr));
                if (chained)
-                       generic_handle_irq(virq);
+                       generic_handle_domain_irq(gic_irq_domain,
+                                                 GIC_LOCAL_TO_HWIRQ(intr));
                else
-                       do_IRQ(virq);
+                       do_IRQ(irq_find_mapping(gic_irq_domain,
+                                               GIC_LOCAL_TO_HWIRQ(intr)));
        }
 }
 
index 8235d98..4d0c353 100644 (file)
@@ -107,7 +107,7 @@ static void ocelot_irq_handler(struct irq_desc *desc)
        while (reg) {
                u32 hwirq = __fls(reg);
 
-               generic_handle_irq(irq_find_mapping(d, hwirq));
+               generic_handle_domain_irq(d, hwirq);
                reg &= ~(BIT(hwirq));
        }
 
index eec6395..dc1cee4 100644 (file)
@@ -91,15 +91,12 @@ static void mvebu_pic_handle_cascade_irq(struct irq_desc *desc)
        struct mvebu_pic *pic = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned long irqmap, irqn;
-       unsigned int cascade_irq;
 
        irqmap = readl_relaxed(pic->base + PIC_CAUSE);
        chained_irq_enter(chip, desc);
 
-       for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
-               cascade_irq = irq_find_mapping(pic->domain, irqn);
-               generic_handle_irq(cascade_irq);
-       }
+       for_each_set_bit(irqn, &irqmap, BITS_PER_LONG)
+               generic_handle_domain_irq(pic->domain, irqn);
 
        chained_irq_exit(chip, desc);
 }
index 3a7b7a7..4ecef6d 100644 (file)
@@ -337,17 +337,12 @@ static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
                irqmap = readl_relaxed(sei->base + GICP_SECR(idx));
                for_each_set_bit(bit, &irqmap, SEI_IRQ_COUNT_PER_REG) {
                        unsigned long hwirq;
-                       unsigned int virq;
+                       int err;
 
                        hwirq = idx * SEI_IRQ_COUNT_PER_REG + bit;
-                       virq = irq_find_mapping(sei->sei_domain, hwirq);
-                       if (likely(virq)) {
-                               generic_handle_irq(virq);
-                               continue;
-                       }
-
-                       dev_warn(sei->dev,
-                                "Spurious IRQ detected (hwirq %lu)\n", hwirq);
+                       err = generic_handle_domain_irq(sei->sei_domain, hwirq);
+                       if (unlikely(err))
+                               dev_warn(sei->dev, "Spurious IRQ detected (hwirq %lu)\n", hwirq);
                }
        }
 
index f747e22..b31c4cf 100644 (file)
@@ -40,9 +40,7 @@ static struct irq_domain *nvic_irq_domain;
 asmlinkage void __exception_irq_entry
 nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
 {
-       unsigned int irq = irq_linear_revmap(nvic_irq_domain, hwirq);
-
-       handle_IRQ(irq, regs);
+       handle_domain_irq(nvic_irq_domain, hwirq, regs);
 }
 
 static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
index c4b5ffb..b6868f7 100644 (file)
@@ -117,7 +117,7 @@ static void orion_bridge_irq_handler(struct irq_desc *desc)
        while (stat) {
                u32 hwirq = __fls(stat);
 
-               generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+               generic_handle_domain_irq(d, gc->irq_base + hwirq);
                stat &= ~(1 << hwirq);
        }
 }
index 0c4c8ed..89c23a1 100644 (file)
@@ -124,13 +124,10 @@ static void partition_handle_irq(struct irq_desc *desc)
                        break;
        }
 
-       if (unlikely(hwirq == part->nr_parts)) {
+       if (unlikely(hwirq == part->nr_parts))
                handle_bad_irq(desc);
-       } else {
-               unsigned int irq;
-               irq = irq_find_mapping(part->domain, hwirq);
-               generic_handle_irq(irq);
-       }
+       else
+               generic_handle_domain_irq(part->domain, hwirq);
 
        chained_irq_exit(chip, desc);
 }
index 92fb578..fa8d89b 100644 (file)
@@ -488,8 +488,7 @@ static void pruss_intc_irq_handler(struct irq_desc *desc)
 
        while (true) {
                u32 hipir;
-               unsigned int virq;
-               int hwirq;
+               int hwirq, err;
 
                /* get highest priority pending PRUSS system event */
                hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq));
@@ -497,16 +496,14 @@ static void pruss_intc_irq_handler(struct irq_desc *desc)
                        break;
 
                hwirq = hipir & GENMASK(9, 0);
-               virq = irq_find_mapping(intc->domain, hwirq);
+               err = generic_handle_domain_irq(intc->domain, hwirq);
 
                /*
                 * NOTE: manually ACK any system events that do not have a
                 * handler mapped yet
                 */
-               if (WARN_ON_ONCE(!virq))
+               if (WARN_ON_ONCE(err))
                        pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
-               else
-                       generic_handle_irq(virq);
        }
 
        chained_irq_exit(chip, desc);
index b57c67d..fd9f275 100644 (file)
@@ -85,7 +85,7 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
                goto out;
        }
        domain = irq_desc_get_handler_data(desc);
-       generic_handle_irq(irq_find_mapping(domain, __ffs(pending)));
+       generic_handle_domain_irq(domain, __ffs(pending));
 
 out:
        chained_irq_exit(chip, desc);
index 11abc09..07a6d8b 100644 (file)
@@ -115,7 +115,7 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
        if (ioread32(p->iomem + DETECT_STATUS) & bit) {
                iowrite32(bit, p->iomem + DETECT_STATUS);
                irqc_dbg(i, "demux2");
-               generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq));
+               generic_handle_domain_irq(p->irq_domain, i->hw_irq);
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
index 97d4d04..cf74cfa 100644 (file)
@@ -233,13 +233,11 @@ static void plic_handle_irq(struct irq_desc *desc)
        chained_irq_enter(chip, desc);
 
        while ((hwirq = readl(claim))) {
-               int irq = irq_find_mapping(handler->priv->irqdomain, hwirq);
-
-               if (unlikely(irq <= 0))
+               int err = generic_handle_domain_irq(handler->priv->irqdomain,
+                                                   hwirq);
+               if (unlikely(err))
                        pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
                                        hwirq);
-               else
-                       generic_handle_irq(irq);
        }
 
        chained_irq_exit(chip, desc);
index 4704f2e..33c7671 100644 (file)
@@ -257,7 +257,7 @@ static void stm32_irq_handler(struct irq_desc *desc)
 {
        struct irq_domain *domain = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned int virq, nbanks = domain->gc->num_chips;
+       unsigned int nbanks = domain->gc->num_chips;
        struct irq_chip_generic *gc;
        unsigned long pending;
        int n, i, irq_base = 0;
@@ -268,11 +268,9 @@ static void stm32_irq_handler(struct irq_desc *desc)
                gc = irq_get_domain_generic_chip(domain, irq_base);
 
                while ((pending = stm32_exti_pending(gc))) {
-                       for_each_set_bit(n, &pending, IRQS_PER_BANK) {
-                               virq = irq_find_mapping(domain, irq_base + n);
-                               generic_handle_irq(virq);
-                       }
-               }
+                       for_each_set_bit(n, &pending, IRQS_PER_BANK)
+                               generic_handle_domain_irq(domain, irq_base + n);
+               }
        }
 
        chained_irq_exit(chip, desc);
index 9ea9445..8a315d6 100644 (file)
@@ -147,10 +147,8 @@ static int __init sun4i_ic_of_init(struct device_node *node,
                                   struct device_node *parent)
 {
        irq_ic_data = kzalloc(sizeof(struct sun4i_irq_chip_data), GFP_KERNEL);
-       if (!irq_ic_data) {
-               pr_err("kzalloc failed!\n");
+       if (!irq_ic_data)
                return -ENOMEM;
-       }
 
        irq_ic_data->enable_reg_offset = SUN4I_IRQ_ENABLE_REG_OFFSET;
        irq_ic_data->mask_reg_offset = SUN4I_IRQ_MASK_REG_OFFSET;
@@ -164,10 +162,8 @@ static int __init suniv_ic_of_init(struct device_node *node,
                                   struct device_node *parent)
 {
        irq_ic_data = kzalloc(sizeof(struct sun4i_irq_chip_data), GFP_KERNEL);
-       if (!irq_ic_data) {
-               pr_err("kzalloc failed!\n");
+       if (!irq_ic_data)
                return -ENOMEM;
-       }
 
        irq_ic_data->enable_reg_offset = SUNIV_IRQ_ENABLE_REG_OFFSET;
        irq_ic_data->mask_reg_offset = SUNIV_IRQ_MASK_REG_OFFSET;
index 9f2bd0c..21d4979 100644 (file)
@@ -88,10 +88,9 @@ static void sunxi_sc_nmi_handle_irq(struct irq_desc *desc)
 {
        struct irq_domain *domain = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       unsigned int virq = irq_find_mapping(domain, 0);
 
        chained_irq_enter(chip, desc);
-       generic_handle_irq(virq);
+       generic_handle_domain_irq(domain, 0);
        chained_irq_exit(chip, desc);
 }
 
index 9a63b02..8a0e692 100644 (file)
@@ -91,7 +91,7 @@ static void tb10x_irq_cascade(struct irq_desc *desc)
        struct irq_domain *domain = irq_desc_get_handler_data(desc);
        unsigned int irq = irq_desc_get_irq(desc);
 
-       generic_handle_irq(irq_find_mapping(domain, irq));
+       generic_handle_domain_irq(domain, irq);
 }
 
 static int __init of_tb10x_init_irq(struct device_node *ictl,
index ca1f593..97f454e 100644 (file)
@@ -147,7 +147,7 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
        struct ti_sci_inta_vint_desc *vint_desc;
        struct ti_sci_inta_irq_domain *inta;
        struct irq_domain *domain;
-       unsigned int virq, bit;
+       unsigned int bit;
        unsigned long val;
 
        vint_desc = irq_desc_get_handler_data(desc);
@@ -159,11 +159,8 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
        val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
                            VINT_STATUS_MASKED_OFFSET);
 
-       for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
-               virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
-               if (virq)
-                       generic_handle_irq(virq);
-       }
+       for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT)
+               generic_handle_domain_irq(domain, vint_desc->events[bit].hwirq);
 
        chained_irq_exit(irq_desc_get_chip(desc), desc);
 }
index 2325fb3..34337a6 100644 (file)
@@ -79,10 +79,9 @@ static void ts4800_ic_chained_handle_irq(struct irq_desc *desc)
 
        do {
                unsigned int bit = __ffs(status);
-               int irq = irq_find_mapping(data->domain, bit);
 
+               generic_handle_domain_irq(data->domain, bit);
                status &= ~(1 << bit);
-               generic_handle_irq(irq);
        } while (status);
 
 out:
index f138673..75be350 100644 (file)
@@ -85,7 +85,7 @@ static void fpga_irq_handle(struct irq_desc *desc)
                unsigned int irq = ffs(status) - 1;
 
                status &= ~(1 << irq);
-               generic_handle_irq(irq_find_mapping(f->domain, irq));
+               generic_handle_domain_irq(f->domain, irq);
        } while (status);
 
 out:
index 62f3d29..1e1f2d1 100644 (file)
@@ -225,7 +225,7 @@ static void vic_handle_irq_cascaded(struct irq_desc *desc)
 
        while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
                hwirq = ffs(stat) - 1;
-               generic_handle_irq(irq_find_mapping(vic->domain, hwirq));
+               generic_handle_domain_irq(vic->domain, hwirq);
        }
 
        chained_irq_exit(host_chip, desc);
index 8cd1bfc..356a597 100644 (file)
@@ -110,20 +110,6 @@ static struct irq_chip intc_dev = {
        .irq_mask_ack = intc_mask_ack,
 };
 
-static unsigned int xintc_get_irq_local(struct xintc_irq_chip *irqc)
-{
-       unsigned int irq = 0;
-       u32 hwirq;
-
-       hwirq = xintc_read(irqc, IVR);
-       if (hwirq != -1U)
-               irq = irq_find_mapping(irqc->root_domain, hwirq);
-
-       pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
-
-       return irq;
-}
-
 unsigned int xintc_get_irq(void)
 {
        unsigned int irq = -1;
@@ -164,15 +150,16 @@ static void xil_intc_irq_handler(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct xintc_irq_chip *irqc;
-       u32 pending;
 
        irqc = irq_data_get_irq_handler_data(&desc->irq_data);
        chained_irq_enter(chip, desc);
        do {
-               pending = xintc_get_irq_local(irqc);
-               if (pending == 0)
+               u32 hwirq = xintc_read(irqc, IVR);
+
+               if (hwirq == -1U)
                        break;
-               generic_handle_irq(pending);
+
+               generic_handle_domain_irq(irqc->root_domain, hwirq);
        } while (true);
        chained_irq_exit(chip, desc);
 }
index aa54bfc..18e696d 100644 (file)
@@ -53,7 +53,6 @@ static void combiner_handle_irq(struct irq_desc *desc)
        chained_irq_enter(chip, desc);
 
        for (reg = 0; reg < combiner->nregs; reg++) {
-               int virq;
                int hwirq;
                u32 bit;
                u32 status;
@@ -70,10 +69,7 @@ static void combiner_handle_irq(struct irq_desc *desc)
                        bit = __ffs(status);
                        status &= ~(1 << bit);
                        hwirq = irq_nr(reg, bit);
-                       virq = irq_find_mapping(combiner->domain, hwirq);
-                       if (virq > 0)
-                               generic_handle_irq(virq);
-
+                       generic_handle_domain_irq(combiner->domain, hwirq);
                }
        }
 
index 5dc63c2..32d5920 100644 (file)
 #include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/soc/qcom/irq.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -459,4 +461,8 @@ fail:
        return ret;
 }
 
-IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
+IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
+IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init)
+IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
+MODULE_LICENSE("GPL v2");
index ca2aedd..190e714 100644 (file)
@@ -2328,7 +2328,7 @@ static bool md_in_flight_bios(struct mapped_device *md)
        return sum != 0;
 }
 
-static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state)
+static int dm_wait_for_bios_completion(struct mapped_device *md, unsigned int task_state)
 {
        int r = 0;
        DEFINE_WAIT(wait);
@@ -2351,7 +2351,7 @@ static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state
        return r;
 }
 
-static int dm_wait_for_completion(struct mapped_device *md, long task_state)
+static int dm_wait_for_completion(struct mapped_device *md, unsigned int task_state)
 {
        int r = 0;
 
@@ -2478,7 +2478,7 @@ static void unlock_fs(struct mapped_device *md)
  * are being added to md->deferred list.
  */
 static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
-                       unsigned suspend_flags, long task_state,
+                       unsigned suspend_flags, unsigned int task_state,
                        int dmf_suspended_flag)
 {
        bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
index 2a3e7ff..028a09a 100644 (file)
@@ -35,10 +35,13 @@ MODULE_PARM_DESC(debug, "debug level (0-2)");
 
 static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
 {
+       int ret;
        struct s5p_cec_dev *cec = cec_get_drvdata(adap);
 
        if (enable) {
-               pm_runtime_get_sync(cec->dev);
+               ret = pm_runtime_resume_and_get(cec->dev);
+               if (ret < 0)
+                       return ret;
 
                s5p_cec_reset(cec);
 
@@ -51,7 +54,7 @@ static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
        } else {
                s5p_cec_mask_tx_interrupts(cec);
                s5p_cec_mask_rx_interrupts(cec);
-               pm_runtime_disable(cec->dev);
+               pm_runtime_put(cec->dev);
        }
 
        return 0;
index 4ea03b7..0f6bde0 100644 (file)
@@ -13,6 +13,10 @@ config VIDEO_TVEEPROM
        tristate
        depends on I2C
 
+config TTPCI_EEPROM
+        tristate
+        depends on I2C
+
 config CYPRESS_FIRMWARE
        tristate
        depends on USB
index b71e4b6..55b5a19 100644 (file)
@@ -3,3 +3,4 @@ obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
index 410cc3a..bceaf91 100644 (file)
@@ -908,7 +908,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
                                         void *buffer, size_t size)
 {
        struct sms_firmware *firmware = (struct sms_firmware *) buffer;
-       struct sms_msg_data4 *msg;
+       struct sms_msg_data5 *msg;
        u32 mem_address,  calc_checksum = 0;
        u32 i, *ptr;
        u8 *payload = firmware->payload;
@@ -989,24 +989,20 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
                goto exit_fw_download;
 
        if (coredev->mode == DEVICE_MODE_NONE) {
-               struct sms_msg_data *trigger_msg =
-                       (struct sms_msg_data *) msg;
-
                pr_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ\n");
                SMS_INIT_MSG(&msg->x_msg_header,
                                MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
-                               sizeof(struct sms_msg_hdr) +
-                               sizeof(u32) * 5);
+                               sizeof(*msg));
 
-               trigger_msg->msg_data[0] = firmware->start_address;
+               msg->msg_data[0] = firmware->start_address;
                                        /* Entry point */
-               trigger_msg->msg_data[1] = 6; /* Priority */
-               trigger_msg->msg_data[2] = 0x200; /* Stack size */
-               trigger_msg->msg_data[3] = 0; /* Parameter */
-               trigger_msg->msg_data[4] = 4; /* Task ID */
+               msg->msg_data[1] = 6; /* Priority */
+               msg->msg_data[2] = 0x200; /* Stack size */
+               msg->msg_data[3] = 0; /* Parameter */
+               msg->msg_data[4] = 4; /* Task ID */
 
-               rc = smscore_sendrequest_and_wait(coredev, trigger_msg,
-                                       trigger_msg->x_msg_header.msg_length,
+               rc = smscore_sendrequest_and_wait(coredev, msg,
+                                       msg->x_msg_header.msg_length,
                                        &coredev->trigger_done);
        } else {
                SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ,
index 4a6b9f4..f8789ee 100644 (file)
@@ -624,9 +624,9 @@ struct sms_msg_data2 {
        u32 msg_data[2];
 };
 
-struct sms_msg_data4 {
+struct sms_msg_data5 {
        struct sms_msg_hdr x_msg_header;
-       u32 msg_data[4];
+       u32 msg_data[5];
 };
 
 struct sms_data_download {
index cd5bafe..f80caaa 100644 (file)
@@ -26,8 +26,8 @@ Copyright (C) 2006-2008, Uri Shkolnik
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static struct list_head g_smsdvb_clients;
-static struct mutex g_smsdvb_clientslock;
+static LIST_HEAD(g_smsdvb_clients);
+static DEFINE_MUTEX(g_smsdvb_clientslock);
 
 static u32 sms_to_guard_interval_table[] = {
        [0] = GUARD_INTERVAL_1_32,
@@ -1212,6 +1212,10 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
        return 0;
 
 media_graph_error:
+       mutex_lock(&g_smsdvb_clientslock);
+       list_del(&client->entry);
+       mutex_unlock(&g_smsdvb_clientslock);
+
        smsdvb_debugfs_release(client);
 
 client_error:
@@ -1236,9 +1240,6 @@ static int __init smsdvb_module_init(void)
 {
        int rc;
 
-       INIT_LIST_HEAD(&g_smsdvb_clients);
-       mutex_init(&g_smsdvb_clientslock);
-
        smsdvb_debugfs_register();
 
        rc = smscore_register_hotplug(smsdvb_hotplug);
index 7e96f67..2988bb3 100644 (file)
@@ -939,6 +939,20 @@ void vb2_queue_release(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
+int vb2_queue_change_type(struct vb2_queue *q, unsigned int type)
+{
+       if (type == q->type)
+               return 0;
+
+       if (vb2_is_busy(q))
+               return -EBUSY;
+
+       q->type = type;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_change_type);
+
 __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
 {
        struct video_device *vfd = video_devdata(file);
index f14a872..5d5a484 100644 (file)
@@ -720,7 +720,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
                        ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
                                                                   secfeed,
                                                                   dvb_dmxdev_section_callback);
-                       if (ret < 0) {
+                       if (!*secfeed) {
                                pr_err("DVB (%s): could not alloc feed\n",
                                       __func__);
                                return ret;
index b7e4a33..15a08d8 100644 (file)
@@ -1386,6 +1386,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
                        err = -EINVAL;
                        goto out_unlock;
                }
+               slot = array_index_nospec(slot, ca->slot_count);
 
                info->type = CA_CI_LINK;
                info->flags = 0;
index a691558..258637d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/poll.h>
 #include <linux/semaphore.h>
 #include <linux/module.h>
+#include <linux/nospec.h>
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
@@ -1063,107 +1064,97 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
        return 0;
 }
 
-#define _DTV_CMD(n, s, b) \
-[n] = { \
-       .name = #n, \
-       .cmd  = n, \
-       .set  = s,\
-       .buffer = b \
-}
-
-struct dtv_cmds_h {
-       char    *name;          /* A display name for debugging purposes */
+#define _DTV_CMD(n) \
+       [n] =  #n
 
-       __u32   cmd;            /* A unique ID */
-
-       /* Flags */
-       __u32   set:1;          /* Either a set or get property */
-       __u32   buffer:1;       /* Does this property use the buffer? */
-       __u32   reserved:30;    /* Align */
-};
-
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
-       _DTV_CMD(DTV_TUNE, 1, 0),
-       _DTV_CMD(DTV_CLEAR, 1, 0),
+static char *dtv_cmds[DTV_MAX_COMMAND + 1] = {
+       _DTV_CMD(DTV_TUNE),
+       _DTV_CMD(DTV_CLEAR),
 
        /* Set */
-       _DTV_CMD(DTV_FREQUENCY, 1, 0),
-       _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
-       _DTV_CMD(DTV_MODULATION, 1, 0),
-       _DTV_CMD(DTV_INVERSION, 1, 0),
-       _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
-       _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
-       _DTV_CMD(DTV_INNER_FEC, 1, 0),
-       _DTV_CMD(DTV_VOLTAGE, 1, 0),
-       _DTV_CMD(DTV_TONE, 1, 0),
-       _DTV_CMD(DTV_PILOT, 1, 0),
-       _DTV_CMD(DTV_ROLLOFF, 1, 0),
-       _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
-       _DTV_CMD(DTV_HIERARCHY, 1, 0),
-       _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
-       _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
-       _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
-       _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
-       _DTV_CMD(DTV_INTERLEAVING, 1, 0),
-
-       _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
-       _DTV_CMD(DTV_STREAM_ID, 1, 0),
-       _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0),
-       _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0),
-       _DTV_CMD(DTV_LNA, 1, 0),
+       _DTV_CMD(DTV_FREQUENCY),
+       _DTV_CMD(DTV_BANDWIDTH_HZ),
+       _DTV_CMD(DTV_MODULATION),
+       _DTV_CMD(DTV_INVERSION),
+       _DTV_CMD(DTV_DISEQC_MASTER),
+       _DTV_CMD(DTV_SYMBOL_RATE),
+       _DTV_CMD(DTV_INNER_FEC),
+       _DTV_CMD(DTV_VOLTAGE),
+       _DTV_CMD(DTV_TONE),
+       _DTV_CMD(DTV_PILOT),
+       _DTV_CMD(DTV_ROLLOFF),
+       _DTV_CMD(DTV_DELIVERY_SYSTEM),
+       _DTV_CMD(DTV_HIERARCHY),
+       _DTV_CMD(DTV_CODE_RATE_HP),
+       _DTV_CMD(DTV_CODE_RATE_LP),
+       _DTV_CMD(DTV_GUARD_INTERVAL),
+       _DTV_CMD(DTV_TRANSMISSION_MODE),
+       _DTV_CMD(DTV_INTERLEAVING),
+
+       _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION),
+       _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING),
+       _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID),
+       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX),
+       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT),
+       _DTV_CMD(DTV_ISDBT_LAYER_ENABLED),
+       _DTV_CMD(DTV_ISDBT_LAYERA_FEC),
+       _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION),
+       _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT),
+       _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING),
+       _DTV_CMD(DTV_ISDBT_LAYERB_FEC),
+       _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION),
+       _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT),
+       _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING),
+       _DTV_CMD(DTV_ISDBT_LAYERC_FEC),
+       _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION),
+       _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT),
+       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING),
+
+       _DTV_CMD(DTV_STREAM_ID),
+       _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY),
+       _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX),
+       _DTV_CMD(DTV_LNA),
 
        /* Get */
-       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
-       _DTV_CMD(DTV_API_VERSION, 0, 0),
-
-       _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
-
-       _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
-       _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY),
+       _DTV_CMD(DTV_API_VERSION),
+
+       _DTV_CMD(DTV_ENUM_DELSYS),
+
+       _DTV_CMD(DTV_ATSCMH_PARADE_ID),
+       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE),
+
+       _DTV_CMD(DTV_ATSCMH_FIC_VER),
+       _DTV_CMD(DTV_ATSCMH_NOG),
+       _DTV_CMD(DTV_ATSCMH_TNOG),
+       _DTV_CMD(DTV_ATSCMH_SGN),
+       _DTV_CMD(DTV_ATSCMH_PRC),
+       _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE),
+       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI),
+       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC),
+       _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D),
 
        /* Statistics API */
-       _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH, 0, 0),
-       _DTV_CMD(DTV_STAT_CNR, 0, 0),
-       _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0, 0),
-       _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0, 0),
-       _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0, 0),
-       _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0, 0),
-       _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT, 0, 0),
-       _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
+       _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH),
+       _DTV_CMD(DTV_STAT_CNR),
+       _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT),
+       _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT),
+       _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT),
+       _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT),
+       _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT),
+       _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT),
 };
 
+static char *dtv_cmd_name(u32 cmd)
+{
+       cmd = array_index_nospec(cmd, DTV_MAX_COMMAND);
+       return dtv_cmds[cmd];
+}
+
 /* Synchronise the legacy tuning parameters into the cache, so that demodulator
  * drivers can use a single set_frontend tuning function, regardless of whether
  * it's being used for the legacy or new API, reducing code and complexity.
@@ -1346,6 +1337,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
                                    struct file *file)
 {
        int ncaps;
+       unsigned int len = 1;
 
        switch (tvp->cmd) {
        case DTV_ENUM_DELSYS:
@@ -1355,6 +1347,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
                        ncaps++;
                }
                tvp->u.buffer.len = ncaps;
+               len = ncaps;
                break;
        case DTV_FREQUENCY:
                tvp->u.data = c->frequency;
@@ -1532,27 +1525,51 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
        /* Fill quality measures */
        case DTV_STAT_SIGNAL_STRENGTH:
                tvp->u.st = c->strength;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_CNR:
                tvp->u.st = c->cnr;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_PRE_ERROR_BIT_COUNT:
                tvp->u.st = c->pre_bit_error;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_PRE_TOTAL_BIT_COUNT:
                tvp->u.st = c->pre_bit_count;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_POST_ERROR_BIT_COUNT:
                tvp->u.st = c->post_bit_error;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_POST_TOTAL_BIT_COUNT:
                tvp->u.st = c->post_bit_count;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_ERROR_BLOCK_COUNT:
                tvp->u.st = c->block_error;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        case DTV_STAT_TOTAL_BLOCK_COUNT:
                tvp->u.st = c->block_count;
+               if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+                       tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+               len = tvp->u.buffer.len;
                break;
        default:
                dev_dbg(fe->dvb->device,
@@ -1561,18 +1578,13 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       if (!dtv_cmds[tvp->cmd].buffer)
-               dev_dbg(fe->dvb->device,
-                       "%s: GET cmd 0x%08x (%s) = 0x%08x\n",
-                       __func__, tvp->cmd, dtv_cmds[tvp->cmd].name,
-                       tvp->u.data);
-       else
-               dev_dbg(fe->dvb->device,
-                       "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
-                       __func__,
-                       tvp->cmd, dtv_cmds[tvp->cmd].name,
-                       tvp->u.buffer.len,
-                       tvp->u.buffer.len, tvp->u.buffer.data);
+       if (len < 1)
+               len = 1;
+
+       dev_dbg(fe->dvb->device,
+               "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
+               __func__, tvp->cmd, dtv_cmd_name(tvp->cmd),
+               tvp->u.buffer.len, tvp->u.buffer.len, tvp->u.buffer.data);
 
        return 0;
 }
@@ -1870,7 +1882,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
        else
                dev_dbg(fe->dvb->device,
                        "%s: SET cmd 0x%08x (%s) to 0x%08x\n",
-                       __func__, cmd, dtv_cmds[cmd].name, data);
+                       __func__, cmd, dtv_cmd_name(cmd), data);
        switch (cmd) {
        case DTV_CLEAR:
                /*
index 89620da..dddebea 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/nospec.h>
 #include <linux/etherdevice.h>
 #include <linux/dvb/net.h>
 #include <linux/uio.h>
@@ -1462,14 +1463,20 @@ static int dvb_net_do_ioctl(struct file *file,
                struct net_device *netdev;
                struct dvb_net_priv *priv_data;
                struct dvb_net_if *dvbnetif = parg;
+               int if_num = dvbnetif->if_num;
 
-               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-                   !dvbnet->state[dvbnetif->if_num]) {
+               if (if_num >= DVB_NET_DEVICES_MAX) {
                        ret = -EINVAL;
                        goto ioctl_error;
                }
+               if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
 
-               netdev = dvbnet->device[dvbnetif->if_num];
+               if (!dvbnet->state[if_num]) {
+                       ret = -EINVAL;
+                       goto ioctl_error;
+               }
+
+               netdev = dvbnet->device[if_num];
 
                priv_data = netdev_priv(netdev);
                dvbnetif->pid=priv_data->pid;
@@ -1522,14 +1529,20 @@ static int dvb_net_do_ioctl(struct file *file,
                struct net_device *netdev;
                struct dvb_net_priv *priv_data;
                struct __dvb_net_if_old *dvbnetif = parg;
+               int if_num = dvbnetif->if_num;
+
+               if (if_num >= DVB_NET_DEVICES_MAX) {
+                       ret = -EINVAL;
+                       goto ioctl_error;
+               }
+               if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
 
-               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-                   !dvbnet->state[dvbnetif->if_num]) {
+               if (!dvbnet->state[if_num]) {
                        ret = -EINVAL;
                        goto ioctl_error;
                }
 
-               netdev = dvbnet->device[dvbnetif->if_num];
+               netdev = dvbnet->device[if_num];
 
                priv_data = netdev_priv(netdev);
                dvbnetif->pid=priv_data->pid;
index 3862ddc..795d9bf 100644 (file)
@@ -506,6 +506,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                        break;
 
        if (minor == MAX_DVB_MINORS) {
+               list_del (&dvbdev->list_head);
                kfree(dvbdevfops);
                kfree(dvbdev);
                up_write(&minor_rwsem);
@@ -526,6 +527,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                      __func__);
 
                dvb_media_device_free(dvbdev);
+               list_del (&dvbdev->list_head);
                kfree(dvbdevfops);
                kfree(dvbdev);
                mutex_unlock(&dvbdev_register_lock);
@@ -541,6 +543,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
                pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
                dvb_media_device_free(dvbdev);
+               list_del (&dvbdev->list_head);
                kfree(dvbdevfops);
                kfree(dvbdev);
                return PTR_ERR(clsdev);
index 3468b07..2c1ed98 100644 (file)
@@ -323,18 +323,6 @@ config DVB_TDA10071
 comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
-config DVB_SP8870
-       tristate "Spase sp8870 based"
-       depends on DVB_CORE && I2C
-       default m if !MEDIA_SUBDRV_AUTOSELECT
-       help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
-
-         This driver needs external firmware. Please use the command
-         "<kerneldir>/scripts/get_dvb_firmware sp8870" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware
-         or /lib/firmware (depending on configuration of firmware hotplug).
-
 config DVB_SP887X
        tristate "Spase sp887x based"
        depends on DVB_CORE && I2C
index b9f47d6..d32e4c0 100644 (file)
@@ -20,7 +20,6 @@ obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
 obj-$(CONFIG_DVB_STB0899) += stb0899.o
 obj-$(CONFIG_DVB_STB6100) += stb6100.o
-obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
 obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
index d62412f..232b3b0 100644 (file)
@@ -75,9 +75,9 @@ TYPEDEFS
                u16 result_len;
                        /*< result length in byte */
                u16 *parameter;
-                       /*< General purpous param */
+                       /*< General purpose param */
                u16 *result;
-                       /*< General purpous param */};
+                       /*< General purpose param */};
 
 /*============================================================================*/
 /*============================================================================*/
@@ -131,7 +131,7 @@ TYPEDEFS
                DRXJ_CFG_MAX    /* dummy, never to be used */};
 
 /*
-* /struct enum drxj_cfg_smart_ant_io * smart antenna i/o.
+* /enum drxj_cfg_smart_ant_io * smart antenna i/o.
 */
 enum drxj_cfg_smart_ant_io {
        DRXJ_SMT_ANT_OUTPUT = 0,
@@ -139,7 +139,7 @@ enum drxj_cfg_smart_ant_io {
 };
 
 /*
-* /struct struct drxj_cfg_smart_ant * Set smart antenna.
+* /struct drxj_cfg_smart_ant * Set smart antenna.
 */
        struct drxj_cfg_smart_ant {
                enum drxj_cfg_smart_ant_io io;
@@ -159,7 +159,7 @@ struct drxj_agc_status {
 /* DRXJ_CFG_AGC_RF, DRXJ_CFG_AGC_IF */
 
 /*
-* /struct enum drxj_agc_ctrl_mode * Available AGCs modes in the DRXJ.
+* /enum drxj_agc_ctrl_mode * Available AGCs modes in the DRXJ.
 */
        enum drxj_agc_ctrl_mode {
                DRX_AGC_CTRL_AUTO = 0,
@@ -167,7 +167,7 @@ struct drxj_agc_status {
                DRX_AGC_CTRL_OFF};
 
 /*
-* /struct struct drxj_cfg_agc * Generic interface for all AGCs present on the DRXJ.
+* /struct drxj_cfg_agc * Generic interface for all AGCs present on the DRXJ.
 */
        struct drxj_cfg_agc {
                enum drx_standard standard;     /* standard for which these settings apply */
@@ -183,7 +183,7 @@ struct drxj_agc_status {
 /* DRXJ_CFG_PRE_SAW */
 
 /*
-* /struct struct drxj_cfg_pre_saw * Interface to configure pre SAW sense.
+* /struct drxj_cfg_pre_saw * Interface to configure pre SAW sense.
 */
        struct drxj_cfg_pre_saw {
                enum drx_standard standard;     /* standard to which these settings apply */
@@ -193,7 +193,7 @@ struct drxj_agc_status {
 /* DRXJ_CFG_AFE_GAIN */
 
 /*
-* /struct struct drxj_cfg_afe_gain * Interface to configure gain of AFE (LNA + PGA).
+* /struct drxj_cfg_afe_gain * Interface to configure gain of AFE (LNA + PGA).
 */
        struct drxj_cfg_afe_gain {
                enum drx_standard standard;     /* standard to which these settings apply */
@@ -220,14 +220,14 @@ struct drxj_agc_status {
        };
 
 /*
-* /struct struct drxj_cfg_vsb_misc * symbol error rate
+* /struct drxj_cfg_vsb_misc * symbol error rate
 */
        struct drxj_cfg_vsb_misc {
                u32 symb_error;
                              /*< symbol error rate sps */};
 
 /*
-* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+* /enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
 *
 */
        enum drxj_mpeg_start_width {
@@ -235,7 +235,7 @@ struct drxj_agc_status {
                DRXJ_MPEG_START_WIDTH_8CLKCYC};
 
 /*
-* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+* /enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
 *
 */
        enum drxj_mpeg_output_clock_rate {
@@ -261,7 +261,7 @@ struct drxj_agc_status {
                enum drxj_mpeg_start_width mpeg_start_width;  /*< set MPEG output start width */};
 
 /*
-* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+* /enum drxj_xtal_freq * Supported external crystal reference frequency.
 */
        enum drxj_xtal_freq {
                DRXJ_XTAL_FREQ_RSVD,
@@ -270,14 +270,15 @@ struct drxj_agc_status {
                DRXJ_XTAL_FREQ_4MHZ};
 
 /*
-* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+* /enum drxj_xtal_freq * Supported external crystal reference frequency.
 */
        enum drxji2c_speed {
                DRXJ_I2C_SPEED_400KBPS,
                DRXJ_I2C_SPEED_100KBPS};
 
 /*
-* /struct struct drxj_cfg_hw_cfg * Get hw configuration, such as crystal reference frequency, I2C speed, etc...
+* /struct drxj_cfg_hw_cfg * Get hw configuration, such as crystal
+*  reference frequency, I2C speed, etc...
 */
        struct drxj_cfg_hw_cfg {
                enum drxj_xtal_freq xtal_freq;
@@ -364,7 +365,7 @@ struct drxj_cfg_oob_misc {
                DRXJ_SIF_ATTENUATION_9DB};
 
 /*
-* /struct struct drxj_cfg_atv_output * SIF attenuation setting.
+* /struct drxj_cfg_atv_output * SIF attenuation setting.
 *
 */
 struct drxj_cfg_atv_output {
@@ -453,10 +454,10 @@ struct drxj_cfg_atv_output {
                enum drxuio_mode uio_gpio_mode; /*< current mode of ASEL pin                         */
                enum drxuio_mode uio_irqn_mode; /*< current mode of IRQN pin                         */
 
-               /* IQM fs frequecy shift and inversion */
+               /* IQM fs frequency shift and inversion */
                u32 iqm_fs_rate_ofs;       /*< frequency shifter setting after setchannel      */
                bool pos_image;    /*< True: positive image                            */
-               /* IQM RC frequecy shift */
+               /* IQM RC frequency shift */
                u32 iqm_rc_rate_ofs;       /*< frequency shifter setting after setchannel      */
 
                /* ATV configuration */
index 8303064..a246db6 100644 (file)
@@ -224,7 +224,9 @@ static int mxl692_validate_fw_header(struct mxl692_dev *dev,
        u32 ix, temp;
        __be32 *local_buf = NULL;
        u8 temp_cksum = 0;
-       const u8 fw_hdr[] = { 0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80 };
+       static const u8 fw_hdr[] = {
+               0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80
+       };
 
        if (memcmp(buffer, fw_hdr, 8) != 0) {
                status = -EINVAL;
index ef6feb2..1a2f0d2 100644 (file)
@@ -1130,8 +1130,6 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
        f->fmt.sdr.pixelformat = dev->pixelformat;
        f->fmt.sdr.buffersize = dev->buffersize;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-
        return 0;
 }
 
@@ -1149,7 +1147,6 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
        if (vb2_is_busy(q))
                return -EBUSY;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < dev->num_formats; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        dev->pixelformat = formats[i].pixelformat;
@@ -1177,7 +1174,6 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
        dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
                (char *)&f->fmt.sdr.pixelformat);
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < dev->num_formats; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        f->fmt.sdr.buffersize = formats[i].buffersize;
index 462c0e0..588f8eb 100644 (file)
@@ -217,6 +217,7 @@ config VIDEO_ADV7180
        depends on GPIOLIB && VIDEO_V4L2 && I2C
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
+       select V4L2_ASYNC
        help
          Support for the Analog Devices ADV7180 video decoder.
 
@@ -534,6 +535,7 @@ config VIDEO_ADV7175
 config VIDEO_ADV7343
        tristate "ADV7343 video encoder"
        depends on I2C
+       select V4L2_ASYNC
        help
          Support for Analog Devices I2C bus based ADV7343 encoder.
 
@@ -652,6 +654,7 @@ config SDR_MAX2175
        tristate "Maxim 2175 RF to Bits tuner"
        depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C
        select REGMAP_I2C
+       select V4L2_ASYNC
        help
          Support for Maxim 2175 tuner. It is an advanced analog/digital
          radio receiver with RF-to-Bits front-end designed for SDR solutions.
@@ -668,6 +671,7 @@ menu "Miscellaneous helper chips"
 config VIDEO_THS7303
        tristate "THS7303/53 Video Amplifier"
        depends on VIDEO_V4L2 && I2C
+       select V4L2_ASYNC
        help
          Support for TI THS7303/53 video amplifier
 
@@ -738,6 +742,17 @@ config VIDEO_HI556
          To compile this driver as a module, choose M here: the
          module will be called hi556.
 
+config VIDEO_IMX208
+       tristate "Sony IMX208 sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
+       help
+         This is a Video4Linux2 sensor driver for the Sony
+         IMX208 camera.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx208.
+
 config VIDEO_IMX214
        tristate "Sony IMX214 sensor support"
        depends on GPIOLIB && I2C && VIDEO_V4L2
@@ -1341,6 +1356,7 @@ config VIDEO_AD5820
        tristate "AD5820 lens voice coil support"
        depends on GPIOLIB && I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
+       select V4L2_ASYNC
        help
          This is a driver for the AD5820 camera lens voice coil.
          It is used for example in Nokia N900 (RX-51).
@@ -1350,6 +1366,7 @@ config VIDEO_AK7375
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
+       select V4L2_ASYNC
        help
          This is a driver for the AK7375 camera lens voice coil.
          AK7375 is a 12 bit DAC with 120mA output current sink
@@ -1361,6 +1378,7 @@ config VIDEO_DW9714
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
+       select V4L2_ASYNC
        help
          This is a driver for the DW9714 camera lens voice coil.
          DW9714 is a 10 bit DAC with 120mA output current sink
@@ -1384,6 +1402,7 @@ config VIDEO_DW9807_VCM
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
+       select V4L2_ASYNC
        help
          This is a driver for the DW9807 camera lens voice coil.
          DW9807 is a 10 bit DAC with 100mA output current sink
@@ -1399,6 +1418,7 @@ config VIDEO_ADP1653
        tristate "ADP1653 flash support"
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
+       select V4L2_ASYNC
        help
          This is a driver for the ADP1653 flash controller. It is used for
          example in Nokia N900.
@@ -1408,6 +1428,7 @@ config VIDEO_LM3560
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select REGMAP_I2C
+       select V4L2_ASYNC
        help
          This is a driver for the lm3560 dual flash controllers. It controls
          flash, torch LEDs.
@@ -1417,6 +1438,7 @@ config VIDEO_LM3646
        depends on I2C && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select REGMAP_I2C
+       select V4L2_ASYNC
        help
          This is a driver for the lm3646 dual flash controllers. It controls
          flash, torch LEDs.
index 0c067be..1168fa6 100644 (file)
@@ -116,6 +116,7 @@ obj-$(CONFIG_VIDEO_ML86V7667)       += ml86v7667.o
 obj-$(CONFIG_VIDEO_OV2659)     += ov2659.o
 obj-$(CONFIG_VIDEO_TC358743)   += tc358743.o
 obj-$(CONFIG_VIDEO_HI556)      += hi556.o
+obj-$(CONFIG_VIDEO_IMX208)     += imx208.o
 obj-$(CONFIG_VIDEO_IMX214)     += imx214.o
 obj-$(CONFIG_VIDEO_IMX219)     += imx219.o
 obj-$(CONFIG_VIDEO_IMX258)     += imx258.o
index e4e8fda..714e31f 100644 (file)
@@ -250,7 +250,7 @@ static int adv7170_s_routing(struct v4l2_subdev *sd,
 }
 
 static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes))
@@ -261,7 +261,7 @@ static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int adv7170_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -284,7 +284,7 @@ static int adv7170_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int adv7170_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
index 0cdd8e0..1813f67 100644 (file)
@@ -288,7 +288,7 @@ static int adv7175_s_routing(struct v4l2_subdev *sd,
 }
 
 static int adv7175_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(adv7175_codes))
@@ -299,7 +299,7 @@ static int adv7175_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int adv7175_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -322,7 +322,7 @@ static int adv7175_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int adv7175_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
index 44bb6fe..fa5bc55 100644 (file)
@@ -633,7 +633,7 @@ static void adv7180_exit_controls(struct adv7180_state *state)
 }
 
 static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index != 0)
@@ -699,13 +699,13 @@ static int adv7180_set_field_mode(struct adv7180_state *state)
 }
 
 static int adv7180_get_pad_format(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *format)
 {
        struct adv7180_state *state = to_state(sd);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+               format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
        } else {
                adv7180_mbus_fmt(sd, &format->format);
                format->format.field = state->field;
@@ -715,7 +715,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd,
 }
 
 static int adv7180_set_pad_format(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *format)
 {
        struct adv7180_state *state = to_state(sd);
@@ -742,7 +742,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
                        adv7180_set_power(state, true);
                }
        } else {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
                *framefmt = format->format;
        }
 
@@ -750,14 +750,14 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
 }
 
 static int adv7180_init_cfg(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg)
+                           struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = {
-               .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
-                       : V4L2_SUBDEV_FORMAT_ACTIVE,
+               .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+               : V4L2_SUBDEV_FORMAT_ACTIVE,
        };
 
-       return adv7180_set_pad_format(sd, cfg, &fmt);
+       return adv7180_set_pad_format(sd, sd_state, &fmt);
 }
 
 static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
index 8bcd632..92cafde 100644 (file)
@@ -409,7 +409,7 @@ static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
 }
 
 static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -420,7 +420,7 @@ static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int adv7183_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct adv7183 *decoder = to_adv7183(sd);
@@ -443,12 +443,12 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                decoder->fmt = *fmt;
        else
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
        return 0;
 }
 
 static int adv7183_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct adv7183 *decoder = to_adv7183(sd);
index 4052cf6..02eabe1 100644 (file)
@@ -331,7 +331,7 @@ static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe)
 }
 
 static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index != 0)
@@ -343,7 +343,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int adv748x_afe_get_format(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_format *sdformat)
 {
        struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
@@ -354,7 +354,8 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+               mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
+                                                       sdformat->pad);
                sdformat->format = *mbusformat;
        } else {
                adv748x_afe_fill_format(afe, &sdformat->format);
@@ -365,7 +366,7 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd,
 }
 
 static int adv748x_afe_set_format(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_format *sdformat)
 {
        struct v4l2_mbus_framefmt *mbusformat;
@@ -375,9 +376,9 @@ static int adv748x_afe_set_format(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return adv748x_afe_get_format(sd, cfg, sdformat);
+               return adv748x_afe_get_format(sd, sd_state, sdformat);
 
-       mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+       mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
        *mbusformat = sdformat->format;
 
        return 0;
index fa9278a..589e964 100644 (file)
@@ -141,26 +141,26 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
 
 static struct v4l2_mbus_framefmt *
 adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            unsigned int pad, u32 which)
 {
        struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
 
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(sd, cfg, pad);
+               return v4l2_subdev_get_try_format(sd, sd_state, pad);
 
        return &tx->format;
 }
 
 static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *sdformat)
 {
        struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
        struct adv748x_state *state = tx->state;
        struct v4l2_mbus_framefmt *mbusformat;
 
-       mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
+       mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
                                                 sdformat->which);
        if (!mbusformat)
                return -EINVAL;
@@ -175,7 +175,7 @@ static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
 }
 
 static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *sdformat)
 {
        struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
@@ -183,7 +183,7 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *mbusformat;
        int ret = 0;
 
-       mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
+       mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
                                                 sdformat->which);
        if (!mbusformat)
                return -EINVAL;
@@ -193,7 +193,7 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
        if (sdformat->pad == ADV748X_CSI2_SOURCE) {
                const struct v4l2_mbus_framefmt *sink_fmt;
 
-               sink_fmt = adv748x_csi2_get_pad_format(sd, cfg,
+               sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
                                                       ADV748X_CSI2_SINK,
                                                       sdformat->which);
 
index c557f8f..52fa7bd 100644 (file)
@@ -409,7 +409,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
 }
 
 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index != 0)
@@ -421,7 +421,7 @@ static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *sdformat)
 {
        struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -431,7 +431,8 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+               mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
+                                                       sdformat->pad);
                sdformat->format = *mbusformat;
        } else {
                adv748x_hdmi_fill_format(hdmi, &sdformat->format);
@@ -442,7 +443,7 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
 }
 
 static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *sdformat)
 {
        struct v4l2_mbus_framefmt *mbusformat;
@@ -451,9 +452,9 @@ static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return adv748x_hdmi_get_format(sd, cfg, sdformat);
+               return adv748x_hdmi_get_format(sd, sd_state, sdformat);
 
-       mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+       mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
        *mbusformat = sdformat->format;
 
        return 0;
index 5fc6c06..41f4e74 100644 (file)
@@ -1216,7 +1216,7 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
 }
 
 static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad != 0)
@@ -1247,7 +1247,7 @@ static void adv7511_fill_format(struct adv7511_state *state,
 }
 
 static int adv7511_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct adv7511_state *state = get_adv7511_state(sd);
@@ -1261,7 +1261,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                format->format.code = fmt->code;
                format->format.colorspace = fmt->colorspace;
                format->format.ycbcr_enc = fmt->ycbcr_enc;
@@ -1279,7 +1279,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int adv7511_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct adv7511_state *state = get_adv7511_state(sd);
@@ -1316,7 +1316,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                fmt->code = format->format.code;
                fmt->colorspace = format->format.colorspace;
                fmt->ycbcr_enc = format->format.ycbcr_enc;
index 3049aa2..122e1fd 100644 (file)
@@ -1833,7 +1833,7 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd,
 }
 
 static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -1913,7 +1913,7 @@ static void adv76xx_setup_format(struct adv76xx_state *state)
 }
 
 static int adv76xx_get_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -1926,7 +1926,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                format->format.code = fmt->code;
        } else {
                format->format.code = state->format->code;
@@ -1936,7 +1936,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
 }
 
 static int adv76xx_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -1956,7 +1956,7 @@ static int adv76xx_get_selection(struct v4l2_subdev *sd,
 }
 
 static int adv76xx_set_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -1975,7 +1975,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                fmt->code = format->format.code;
        } else {
                state->format = info;
index ff10af7..7f8acbd 100644 (file)
@@ -98,12 +98,12 @@ struct adv7842_state {
 
        v4l2_std_id norm;
        struct {
-               u8 edid[256];
+               u8 edid[512];
                u32 blocks;
                u32 present;
        } hdmi_edid;
        struct {
-               u8 edid[256];
+               u8 edid[128];
                u32 blocks;
                u32 present;
        } vga_edid;
@@ -720,6 +720,9 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd)
 
        v4l2_dbg(2, debug, sd, "%s: write EDID on VGA port\n", __func__);
 
+       if (!state->vga_edid.present)
+               return 0;
+
        /* HPA disable on port A and B */
        io_write_and_or(sd, 0x20, 0xcf, 0x00);
 
@@ -763,7 +766,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
        struct adv7842_state *state = to_state(sd);
        const u8 *edid = state->hdmi_edid.edid;
        u32 blocks = state->hdmi_edid.blocks;
-       int spa_loc;
+       unsigned int spa_loc;
        u16 pa, parent_pa;
        int err = 0;
        int i;
@@ -796,12 +799,14 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
                pa = (edid[spa_loc] << 8) | edid[spa_loc + 1];
        }
 
-       /* edid segment pointer '0' for HDMI ports */
-       rep_write_and_or(sd, 0x77, 0xef, 0x00);
 
-       for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX)
+       for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX) {
+               /* set edid segment pointer for HDMI ports */
+               if (i % 256 == 0)
+                       rep_write_and_or(sd, 0x77, 0xef, i >= 256 ? 0x10 : 0x00);
                err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i,
                                                     I2C_SMBUS_BLOCK_MAX, edid + i);
+       }
        if (err)
                return err;
 
@@ -1988,7 +1993,7 @@ static int adv7842_s_routing(struct v4l2_subdev *sd,
 }
 
 static int adv7842_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(adv7842_formats))
@@ -2064,7 +2069,7 @@ static void adv7842_setup_format(struct adv7842_state *state)
 }
 
 static int adv7842_get_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct adv7842_state *state = to_state(sd);
@@ -2092,7 +2097,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                format->format.code = fmt->code;
        } else {
                format->format.code = state->format->code;
@@ -2102,7 +2107,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd,
 }
 
 static int adv7842_set_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct adv7842_state *state = to_state(sd);
@@ -2112,7 +2117,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (state->mode == ADV7842_MODE_SDP)
-               return adv7842_get_format(sd, cfg, format);
+               return adv7842_get_format(sd, sd_state, format);
 
        info = adv7842_format_info(state, format->format.code);
        if (info == NULL)
@@ -2124,7 +2129,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                fmt->code = format->format.code;
        } else {
                state->format = info;
@@ -2491,9 +2496,17 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
        return 0;
 }
 
+/*
+ * If the VGA_EDID_ENABLE bit is set (Repeater Map 0x7f, bit 7), then
+ * the first two blocks of the EDID are for the HDMI, and the first block
+ * of segment 1 (i.e. the third block of the EDID) is for VGA.
+ * So if a VGA EDID is installed, then the maximum size of the HDMI EDID
+ * is 2 blocks.
+ */
 static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
 {
        struct adv7842_state *state = to_state(sd);
+       unsigned int max_blocks = e->pad == ADV7842_EDID_PORT_VGA ? 1 : 4;
        int err = 0;
 
        memset(e->reserved, 0, sizeof(e->reserved));
@@ -2502,8 +2515,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
                return -EINVAL;
        if (e->start_block != 0)
                return -EINVAL;
-       if (e->blocks > 2) {
-               e->blocks = 2;
+       if (e->pad < ADV7842_EDID_PORT_VGA && state->vga_edid.blocks)
+               max_blocks = 2;
+       if (e->pad == ADV7842_EDID_PORT_VGA && state->hdmi_edid.blocks > 2)
+               return -EBUSY;
+       if (e->blocks > max_blocks) {
+               e->blocks = max_blocks;
                return -E2BIG;
        }
 
@@ -2514,20 +2531,20 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
 
        switch (e->pad) {
        case ADV7842_EDID_PORT_VGA:
-               memset(&state->vga_edid.edid, 0, 256);
+               memset(state->vga_edid.edid, 0, sizeof(state->vga_edid.edid));
                state->vga_edid.blocks = e->blocks;
                state->vga_edid.present = e->blocks ? 0x1 : 0x0;
                if (e->blocks)
-                       memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks);
+                       memcpy(state->vga_edid.edid, e->edid, 128);
                err = edid_write_vga_segment(sd);
                break;
        case ADV7842_EDID_PORT_A:
        case ADV7842_EDID_PORT_B:
-               memset(&state->hdmi_edid.edid, 0, 256);
+               memset(state->hdmi_edid.edid, 0, sizeof(state->hdmi_edid.edid));
                state->hdmi_edid.blocks = e->blocks;
                if (e->blocks) {
                        state->hdmi_edid.present |= 0x04 << e->pad;
-                       memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks);
+                       memcpy(state->hdmi_edid.edid, e->edid, 128 * e->blocks);
                } else {
                        state->hdmi_edid.present &= ~(0x04 << e->pad);
                        adv7842_s_detect_tx_5v_ctrl(sd);
index e1f94ee..40b1a4a 100644 (file)
@@ -87,15 +87,7 @@ static const struct v4l2_ctrl_ops ak7375_vcm_ctrl_ops = {
 
 static int ak7375_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       int ret;
-
-       ret = pm_runtime_get_sync(sd->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(sd->dev);
-               return ret;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(sd->dev);
 }
 
 static int ak7375_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
index 1adaf47..dc569d5 100644 (file)
@@ -91,7 +91,7 @@ static int ak881x_s_register(struct v4l2_subdev *sd,
 #endif
 
 static int ak881x_fill_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -111,7 +111,7 @@ static int ak881x_fill_fmt(struct v4l2_subdev *sd,
 }
 
 static int ak881x_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index)
@@ -122,7 +122,7 @@ static int ak881x_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ak881x_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
index 9dc3f45..a9403a2 100644 (file)
@@ -1880,21 +1880,33 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor)
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
        int rval;
 
+       /*
+        * It can't use pm_runtime_resume_and_get() here, as the driver
+        * relies at the returned value to detect if the device was already
+        * active or not.
+        */
        rval = pm_runtime_get_sync(&client->dev);
-       if (rval < 0) {
-               pm_runtime_put_noidle(&client->dev);
+       if (rval < 0)
+               goto error;
 
-               return rval;
-       } else if (!rval) {
-               rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->
-                                              ctrl_handler);
-               if (rval)
-                       return rval;
+       /* Device was already active, so don't set controls */
+       if (rval == 1)
+               return 0;
 
-               return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
-       }
+       /* Restore V4L2 controls to the previously suspended device */
+       rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler);
+       if (rval)
+               goto error;
+
+       rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+       if (rval)
+               goto error;
 
+       /* Keep PM runtime usage_count incremented on success */
        return 0;
+error:
+       pm_runtime_put(&client->dev);
+       return rval;
 }
 
 static int ccs_set_stream(struct v4l2_subdev *subdev, int enable)
@@ -1932,7 +1944,7 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable)
 }
 
 static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        struct i2c_client *client = v4l2_get_subdevdata(subdev);
@@ -1985,13 +1997,13 @@ static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad)
 }
 
 static int __ccs_get_format(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct ccs_subdev *ssd = to_ccs_subdev(subdev);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               fmt->format = *v4l2_subdev_get_try_format(subdev, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(subdev, sd_state,
                                                          fmt->pad);
        } else {
                struct v4l2_rect *r;
@@ -2011,21 +2023,21 @@ static int __ccs_get_format(struct v4l2_subdev *subdev,
 }
 
 static int ccs_get_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
        int rval;
 
        mutex_lock(&sensor->mutex);
-       rval = __ccs_get_format(subdev, cfg, fmt);
+       rval = __ccs_get_format(subdev, sd_state, fmt);
        mutex_unlock(&sensor->mutex);
 
        return rval;
 }
 
 static void ccs_get_crop_compose(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_rect **crops,
                                 struct v4l2_rect **comps, int which)
 {
@@ -2042,24 +2054,25 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev,
                if (crops) {
                        for (i = 0; i < subdev->entity.num_pads; i++)
                                crops[i] = v4l2_subdev_get_try_crop(subdev,
-                                                                   cfg, i);
+                                                                   sd_state,
+                                                                   i);
                }
                if (comps)
-                       *comps = v4l2_subdev_get_try_compose(subdev, cfg,
+                       *comps = v4l2_subdev_get_try_compose(subdev, sd_state,
                                                             CCS_PAD_SINK);
        }
 }
 
 /* Changes require propagation only on sink pad. */
 static void ccs_propagate(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg, int which,
+                         struct v4l2_subdev_state *sd_state, int which,
                          int target)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
        struct ccs_subdev *ssd = to_ccs_subdev(subdev);
        struct v4l2_rect *comp, *crops[CCS_PADS];
 
-       ccs_get_crop_compose(subdev, cfg, crops, &comp, which);
+       ccs_get_crop_compose(subdev, sd_state, crops, &comp, which);
 
        switch (target) {
        case V4L2_SEL_TGT_CROP:
@@ -2099,7 +2112,7 @@ static const struct ccs_csi_data_format
 }
 
 static int ccs_set_format_source(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2110,7 +2123,7 @@ static int ccs_set_format_source(struct v4l2_subdev *subdev,
        unsigned int i;
        int rval;
 
-       rval = __ccs_get_format(subdev, cfg, fmt);
+       rval = __ccs_get_format(subdev, sd_state, fmt);
        if (rval)
                return rval;
 
@@ -2152,7 +2165,7 @@ static int ccs_set_format_source(struct v4l2_subdev *subdev,
 }
 
 static int ccs_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2164,7 +2177,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
        if (fmt->pad == ssd->source_pad) {
                int rval;
 
-               rval = ccs_set_format_source(subdev, cfg, fmt);
+               rval = ccs_set_format_source(subdev, sd_state, fmt);
 
                mutex_unlock(&sensor->mutex);
 
@@ -2186,7 +2199,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
                      CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE),
                      CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE));
 
-       ccs_get_crop_compose(subdev, cfg, crops, NULL, fmt->which);
+       ccs_get_crop_compose(subdev, sd_state, crops, NULL, fmt->which);
 
        crops[ssd->sink_pad]->left = 0;
        crops[ssd->sink_pad]->top = 0;
@@ -2194,7 +2207,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
        crops[ssd->sink_pad]->height = fmt->format.height;
        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                ssd->sink_fmt = *crops[ssd->sink_pad];
-       ccs_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP);
+       ccs_propagate(subdev, sd_state, fmt->which, V4L2_SEL_TGT_CROP);
 
        mutex_unlock(&sensor->mutex);
 
@@ -2246,7 +2259,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
 }
 
 static void ccs_set_compose_binner(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_selection *sel,
                                   struct v4l2_rect **crops,
                                   struct v4l2_rect *comp)
@@ -2294,7 +2307,7 @@ static void ccs_set_compose_binner(struct v4l2_subdev *subdev,
  * result.
  */
 static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_selection *sel,
                                   struct v4l2_rect **crops,
                                   struct v4l2_rect *comp)
@@ -2409,25 +2422,25 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
 }
 /* We're only called on source pads. This function sets scaling. */
 static int ccs_set_compose(struct v4l2_subdev *subdev,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_selection *sel)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
        struct ccs_subdev *ssd = to_ccs_subdev(subdev);
        struct v4l2_rect *comp, *crops[CCS_PADS];
 
-       ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
+       ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which);
 
        sel->r.top = 0;
        sel->r.left = 0;
 
        if (ssd == sensor->binner)
-               ccs_set_compose_binner(subdev, cfg, sel, crops, comp);
+               ccs_set_compose_binner(subdev, sd_state, sel, crops, comp);
        else
-               ccs_set_compose_scaler(subdev, cfg, sel, crops, comp);
+               ccs_set_compose_scaler(subdev, sd_state, sel, crops, comp);
 
        *comp = sel->r;
-       ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE);
+       ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_COMPOSE);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return ccs_pll_blanking_update(sensor);
@@ -2474,7 +2487,7 @@ static int __ccs_sel_supported(struct v4l2_subdev *subdev,
 }
 
 static int ccs_set_crop(struct v4l2_subdev *subdev,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_selection *sel)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2482,7 +2495,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
        struct v4l2_rect *src_size, *crops[CCS_PADS];
        struct v4l2_rect _r;
 
-       ccs_get_crop_compose(subdev, cfg, crops, NULL, sel->which);
+       ccs_get_crop_compose(subdev, sd_state, crops, NULL, sel->which);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                if (sel->pad == ssd->sink_pad)
@@ -2493,16 +2506,18 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
                if (sel->pad == ssd->sink_pad) {
                        _r.left = 0;
                        _r.top = 0;
-                       _r.width = v4l2_subdev_get_try_format(subdev, cfg,
+                       _r.width = v4l2_subdev_get_try_format(subdev,
+                                                             sd_state,
                                                              sel->pad)
                                ->width;
-                       _r.height = v4l2_subdev_get_try_format(subdev, cfg,
+                       _r.height = v4l2_subdev_get_try_format(subdev,
+                                                              sd_state,
                                                               sel->pad)
                                ->height;
                        src_size = &_r;
                } else {
                        src_size = v4l2_subdev_get_try_compose(
-                               subdev, cfg, ssd->sink_pad);
+                               subdev, sd_state, ssd->sink_pad);
                }
        }
 
@@ -2520,7 +2535,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
        *crops[sel->pad] = sel->r;
 
        if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK)
-               ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP);
+               ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_CROP);
 
        return 0;
 }
@@ -2534,7 +2549,7 @@ static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r)
 }
 
 static int __ccs_get_selection(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_selection *sel)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2547,13 +2562,14 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev,
        if (ret)
                return ret;
 
-       ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
+       ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                sink_fmt = ssd->sink_fmt;
        } else {
                struct v4l2_mbus_framefmt *fmt =
-                       v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad);
+                       v4l2_subdev_get_try_format(subdev, sd_state,
+                                                  ssd->sink_pad);
 
                sink_fmt.left = 0;
                sink_fmt.top = 0;
@@ -2584,21 +2600,21 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev,
 }
 
 static int ccs_get_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
        int rval;
 
        mutex_lock(&sensor->mutex);
-       rval = __ccs_get_selection(subdev, cfg, sel);
+       rval = __ccs_get_selection(subdev, sd_state, sel);
        mutex_unlock(&sensor->mutex);
 
        return rval;
 }
 
 static int ccs_set_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2622,10 +2638,10 @@ static int ccs_set_selection(struct v4l2_subdev *subdev,
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
-               ret = ccs_set_crop(subdev, cfg, sel);
+               ret = ccs_set_crop(subdev, sd_state, sel);
                break;
        case V4L2_SEL_TGT_COMPOSE:
-               ret = ccs_set_compose(subdev, cfg, sel);
+               ret = ccs_set_compose(subdev, sd_state, sel);
                break;
        default:
                ret = -EINVAL;
@@ -3016,9 +3032,9 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        for (i = 0; i < ssd->npads; i++) {
                struct v4l2_mbus_framefmt *try_fmt =
-                       v4l2_subdev_get_try_format(sd, fh->pad, i);
+                       v4l2_subdev_get_try_format(sd, fh->state, i);
                struct v4l2_rect *try_crop =
-                       v4l2_subdev_get_try_crop(sd, fh->pad, i);
+                       v4l2_subdev_get_try_crop(sd, fh->state, i);
                struct v4l2_rect *try_comp;
 
                ccs_get_native_size(ssd, try_crop);
@@ -3031,7 +3047,7 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                if (ssd != sensor->pixel_array)
                        continue;
 
-               try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i);
+               try_comp = v4l2_subdev_get_try_compose(sd, fh->state, i);
                *try_comp = *try_crop;
        }
 
@@ -3089,12 +3105,9 @@ static int __maybe_unused ccs_suspend(struct device *dev)
        bool streaming = sensor->streaming;
        int rval;
 
-       rval = pm_runtime_get_sync(dev);
-       if (rval < 0) {
-               pm_runtime_put_noidle(dev);
-
-               return -EAGAIN;
-       }
+       rval = pm_runtime_resume_and_get(dev);
+       if (rval < 0)
+               return rval;
 
        if (sensor->streaming)
                ccs_stop_streaming(sensor);
index f551178..4969fa4 100644 (file)
@@ -1,5 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
 /* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
 
 #include "ccs-limits.h"
 #include "ccs-regs.h"
index 1efa43c..551d3ee 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
 /* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
 
 #ifndef __CCS_LIMITS_H__
 #define __CCS_LIMITS_H__
index 4b3e5df..6ce84c5 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
 /* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
 
 #ifndef __CCS_REGS_H__
 #define __CCS_REGS_H__
 #define CCS_R_OP_PIX_CLK_DIV                                   (0x0308 | CCS_FL_16BIT)
 #define CCS_R_OP_SYS_CLK_DIV                                   (0x030a | CCS_FL_16BIT)
 #define CCS_R_OP_PRE_PLL_CLK_DIV                               (0x030c | CCS_FL_16BIT)
-#define CCS_R_OP_PLL_MULTIPLIER                                        (0x031e | CCS_FL_16BIT)
+#define CCS_R_OP_PLL_MULTIPLIER                                        (0x030e | CCS_FL_16BIT)
 #define CCS_R_PLL_MODE                                         0x0310
 #define CCS_PLL_MODE_SHIFT                                     0U
 #define CCS_PLL_MODE_MASK                                      0x1
index e2e935f..dc31944 100644 (file)
@@ -1746,7 +1746,7 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
 /* ----------------------------------------------------------------------- */
 
 static int cx25840_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
index 3f0b082..c8b4292 100644 (file)
@@ -85,15 +85,7 @@ static const struct v4l2_ctrl_ops dw9714_vcm_ctrl_ops = {
 
 static int dw9714_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       int rval;
-
-       rval = pm_runtime_get_sync(sd->dev);
-       if (rval < 0) {
-               pm_runtime_put_noidle(sd->dev);
-               return rval;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(sd->dev);
 }
 
 static int dw9714_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
index 8b8cb4b..c086580 100644 (file)
@@ -374,15 +374,7 @@ static const struct v4l2_ctrl_ops dw9768_ctrl_ops = {
 
 static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       int ret;
-
-       ret = pm_runtime_get_sync(sd->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(sd->dev);
-               return ret;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(sd->dev);
 }
 
 static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
index 438a44b..95e06f1 100644 (file)
@@ -130,15 +130,7 @@ static const struct v4l2_ctrl_ops dw9807_vcm_ctrl_ops = {
 
 static int dw9807_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       int rval;
-
-       rval = pm_runtime_get_sync(sd->dev);
-       if (rval < 0) {
-               pm_runtime_put_noidle(sd->dev);
-               return rval;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(sd->dev);
 }
 
 static int dw9807_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
index bb3eac5..c7b91c0 100644 (file)
@@ -882,7 +882,7 @@ out:
  */
 #define MAX_FMTS 4
 static int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct et8ek8_reglist **list =
@@ -920,7 +920,7 @@ static int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int et8ek8_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct et8ek8_reglist **list =
@@ -958,7 +958,7 @@ static int et8ek8_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct et8ek8_reglist **list =
@@ -990,12 +990,13 @@ static int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev,
 
 static struct v4l2_mbus_framefmt *
 __et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
+                                                 pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &sensor->format;
        default:
@@ -1004,13 +1005,14 @@ __et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
 }
 
 static int et8ek8_get_pad_format(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
        struct v4l2_mbus_framefmt *format;
 
-       format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+       format = __et8ek8_get_pad_format(sensor, sd_state, fmt->pad,
+                                        fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -1020,14 +1022,15 @@ static int et8ek8_get_pad_format(struct v4l2_subdev *subdev,
 }
 
 static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
        struct v4l2_mbus_framefmt *format;
        struct et8ek8_reglist *reglist;
 
-       format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+       format = __et8ek8_get_pad_format(sensor, sd_state, fmt->pad,
+                                        fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -1327,7 +1330,7 @@ static int et8ek8_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        struct et8ek8_reglist *reglist;
 
        reglist = et8ek8_reglist_find_type(&meta_reglist, ET8EK8_REGLIST_MODE);
-       format = __et8ek8_get_pad_format(sensor, fh->pad, 0,
+       format = __et8ek8_get_pad_format(sensor, fh->state, 0,
                                         V4L2_SUBDEV_FORMAT_TRY);
        et8ek8_reglist_to_mbus(reglist, format);
 
index 6f05c11..8db1cbe 100644 (file)
@@ -813,9 +813,8 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable)
 
        mutex_lock(&hi556->mutex);
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
                        mutex_unlock(&hi556->mutex);
                        return ret;
                }
@@ -876,7 +875,7 @@ error:
 }
 
 static int hi556_set_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct hi556 *hi556 = to_hi556(sd);
@@ -891,7 +890,7 @@ static int hi556_set_format(struct v4l2_subdev *sd,
        mutex_lock(&hi556->mutex);
        hi556_assign_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                hi556->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index);
@@ -918,14 +917,15 @@ static int hi556_set_format(struct v4l2_subdev *sd,
 }
 
 static int hi556_get_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct hi556 *hi556 = to_hi556(sd);
 
        mutex_lock(&hi556->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&hi556->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&hi556->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                hi556_assign_pad_format(hi556->cur_mode, &fmt->format);
@@ -936,7 +936,7 @@ static int hi556_get_format(struct v4l2_subdev *sd,
 }
 
 static int hi556_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -948,7 +948,7 @@ static int hi556_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int hi556_enum_frame_size(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -971,7 +971,7 @@ static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&hi556->mutex);
        hi556_assign_pad_format(&supported_modes[0],
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                               v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&hi556->mutex);
 
        return 0;
diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c
new file mode 100644 (file)
index 0000000..6f3d9c1
--- /dev/null
@@ -0,0 +1,1088 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2021 Intel Corporation
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <asm/unaligned.h>
+
+#define IMX208_REG_MODE_SELECT         0x0100
+#define IMX208_MODE_STANDBY            0x00
+#define IMX208_MODE_STREAMING          0x01
+
+/* Chip ID */
+#define IMX208_REG_CHIP_ID             0x0000
+#define IMX208_CHIP_ID                 0x0208
+
+/* V_TIMING internal */
+#define IMX208_REG_VTS                 0x0340
+#define IMX208_VTS_60FPS               0x0472
+#define IMX208_VTS_BINNING             0x0239
+#define IMX208_VTS_60FPS_MIN           0x0458
+#define IMX208_VTS_BINNING_MIN         0x0230
+#define IMX208_VTS_MAX                 0xffff
+
+/* HBLANK control - read only */
+#define IMX208_PPL_384MHZ              2248
+#define IMX208_PPL_96MHZ               2248
+
+/* Exposure control */
+#define IMX208_REG_EXPOSURE            0x0202
+#define IMX208_EXPOSURE_MIN            4
+#define IMX208_EXPOSURE_STEP           1
+#define IMX208_EXPOSURE_DEFAULT                0x190
+#define IMX208_EXPOSURE_MAX            65535
+
+/* Analog gain control */
+#define IMX208_REG_ANALOG_GAIN         0x0204
+#define IMX208_ANA_GAIN_MIN            0
+#define IMX208_ANA_GAIN_MAX            0x00e0
+#define IMX208_ANA_GAIN_STEP           1
+#define IMX208_ANA_GAIN_DEFAULT                0x0
+
+/* Digital gain control */
+#define IMX208_REG_GR_DIGITAL_GAIN     0x020e
+#define IMX208_REG_R_DIGITAL_GAIN      0x0210
+#define IMX208_REG_B_DIGITAL_GAIN      0x0212
+#define IMX208_REG_GB_DIGITAL_GAIN     0x0214
+#define IMX208_DIGITAL_GAIN_SHIFT      8
+
+/* Orientation */
+#define IMX208_REG_ORIENTATION_CONTROL 0x0101
+
+/* Test Pattern Control */
+#define IMX208_REG_TEST_PATTERN_MODE   0x0600
+#define IMX208_TEST_PATTERN_DISABLE    0x0
+#define IMX208_TEST_PATTERN_SOLID_COLOR        0x1
+#define IMX208_TEST_PATTERN_COLOR_BARS 0x2
+#define IMX208_TEST_PATTERN_GREY_COLOR 0x3
+#define IMX208_TEST_PATTERN_PN9                0x4
+#define IMX208_TEST_PATTERN_FIX_1      0x100
+#define IMX208_TEST_PATTERN_FIX_2      0x101
+#define IMX208_TEST_PATTERN_FIX_3      0x102
+#define IMX208_TEST_PATTERN_FIX_4      0x103
+#define IMX208_TEST_PATTERN_FIX_5      0x104
+#define IMX208_TEST_PATTERN_FIX_6      0x105
+
+/* OTP Access */
+#define IMX208_OTP_BASE                        0x3500
+#define IMX208_OTP_SIZE                        40
+
+struct imx208_reg {
+       u16 address;
+       u8 val;
+};
+
+struct imx208_reg_list {
+       u32 num_of_regs;
+       const struct imx208_reg *regs;
+};
+
+/* Link frequency config */
+struct imx208_link_freq_config {
+       u32 pixels_per_line;
+
+       /* PLL registers for this link frequency */
+       struct imx208_reg_list reg_list;
+};
+
+/* Mode : resolution and related config&values */
+struct imx208_mode {
+       /* Frame width */
+       u32 width;
+       /* Frame height */
+       u32 height;
+
+       /* V-timing */
+       u32 vts_def;
+       u32 vts_min;
+
+       /* Index of Link frequency config to be used */
+       u32 link_freq_index;
+       /* Default register values */
+       struct imx208_reg_list reg_list;
+};
+
+static const struct imx208_reg pll_ctrl_reg[] = {
+       {0x0305, 0x02},
+       {0x0307, 0x50},
+       {0x303C, 0x3C},
+};
+
+static const struct imx208_reg mode_1936x1096_60fps_regs[] = {
+       {0x0340, 0x04},
+       {0x0341, 0x72},
+       {0x0342, 0x04},
+       {0x0343, 0x64},
+       {0x034C, 0x07},
+       {0x034D, 0x90},
+       {0x034E, 0x04},
+       {0x034F, 0x48},
+       {0x0381, 0x01},
+       {0x0383, 0x01},
+       {0x0385, 0x01},
+       {0x0387, 0x01},
+       {0x3048, 0x00},
+       {0x3050, 0x01},
+       {0x30D5, 0x00},
+       {0x3301, 0x00},
+       {0x3318, 0x62},
+       {0x0202, 0x01},
+       {0x0203, 0x90},
+       {0x0205, 0x00},
+};
+
+static const struct imx208_reg mode_968_548_60fps_regs[] = {
+       {0x0340, 0x02},
+       {0x0341, 0x39},
+       {0x0342, 0x08},
+       {0x0343, 0xC8},
+       {0x034C, 0x03},
+       {0x034D, 0xC8},
+       {0x034E, 0x02},
+       {0x034F, 0x24},
+       {0x0381, 0x01},
+       {0x0383, 0x03},
+       {0x0385, 0x01},
+       {0x0387, 0x03},
+       {0x3048, 0x01},
+       {0x3050, 0x02},
+       {0x30D5, 0x03},
+       {0x3301, 0x10},
+       {0x3318, 0x75},
+       {0x0202, 0x01},
+       {0x0203, 0x90},
+       {0x0205, 0x00},
+};
+
+static const s64 imx208_discrete_digital_gain[] = {
+       1, 2, 4, 8, 16,
+};
+
+static const char * const imx208_test_pattern_menu[] = {
+       "Disabled",
+       "Solid Color",
+       "100% Color Bar",
+       "Fade to Grey Color Bar",
+       "PN9",
+       "Fixed Pattern1",
+       "Fixed Pattern2",
+       "Fixed Pattern3",
+       "Fixed Pattern4",
+       "Fixed Pattern5",
+       "Fixed Pattern6"
+};
+
+static const int imx208_test_pattern_val[] = {
+       IMX208_TEST_PATTERN_DISABLE,
+       IMX208_TEST_PATTERN_SOLID_COLOR,
+       IMX208_TEST_PATTERN_COLOR_BARS,
+       IMX208_TEST_PATTERN_GREY_COLOR,
+       IMX208_TEST_PATTERN_PN9,
+       IMX208_TEST_PATTERN_FIX_1,
+       IMX208_TEST_PATTERN_FIX_2,
+       IMX208_TEST_PATTERN_FIX_3,
+       IMX208_TEST_PATTERN_FIX_4,
+       IMX208_TEST_PATTERN_FIX_5,
+       IMX208_TEST_PATTERN_FIX_6,
+};
+
+/* Configurations for supported link frequencies */
+#define IMX208_MHZ                     (1000 * 1000ULL)
+#define IMX208_LINK_FREQ_384MHZ                (384ULL * IMX208_MHZ)
+#define IMX208_LINK_FREQ_96MHZ         (96ULL * IMX208_MHZ)
+
+#define IMX208_DATA_RATE_DOUBLE                2
+#define IMX208_NUM_OF_LANES            2
+#define IMX208_PIXEL_BITS              10
+
+enum {
+       IMX208_LINK_FREQ_384MHZ_INDEX,
+       IMX208_LINK_FREQ_96MHZ_INDEX,
+};
+
+/*
+ * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
+ * data rate => double data rate; number of lanes => 2; bits per pixel => 10
+ */
+static u64 link_freq_to_pixel_rate(u64 f)
+{
+       f *= IMX208_DATA_RATE_DOUBLE * IMX208_NUM_OF_LANES;
+       do_div(f, IMX208_PIXEL_BITS);
+
+       return f;
+}
+
+/* Menu items for LINK_FREQ V4L2 control */
+static const s64 link_freq_menu_items[] = {
+       [IMX208_LINK_FREQ_384MHZ_INDEX] = IMX208_LINK_FREQ_384MHZ,
+       [IMX208_LINK_FREQ_96MHZ_INDEX] = IMX208_LINK_FREQ_96MHZ,
+};
+
+/* Link frequency configs */
+static const struct imx208_link_freq_config link_freq_configs[] = {
+       [IMX208_LINK_FREQ_384MHZ_INDEX] = {
+               .pixels_per_line = IMX208_PPL_384MHZ,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
+                       .regs = pll_ctrl_reg,
+               }
+       },
+       [IMX208_LINK_FREQ_96MHZ_INDEX] = {
+               .pixels_per_line = IMX208_PPL_96MHZ,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
+                       .regs = pll_ctrl_reg,
+               }
+       },
+};
+
+/* Mode configs */
+static const struct imx208_mode supported_modes[] = {
+       {
+               .width = 1936,
+               .height = 1096,
+               .vts_def = IMX208_VTS_60FPS,
+               .vts_min = IMX208_VTS_60FPS_MIN,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_1936x1096_60fps_regs),
+                       .regs = mode_1936x1096_60fps_regs,
+               },
+               .link_freq_index = IMX208_LINK_FREQ_384MHZ_INDEX,
+       },
+       {
+               .width = 968,
+               .height = 548,
+               .vts_def = IMX208_VTS_BINNING,
+               .vts_min = IMX208_VTS_BINNING_MIN,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_968_548_60fps_regs),
+                       .regs = mode_968_548_60fps_regs,
+               },
+               .link_freq_index = IMX208_LINK_FREQ_96MHZ_INDEX,
+       },
+};
+
+struct imx208 {
+       struct v4l2_subdev sd;
+       struct media_pad pad;
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       /* V4L2 Controls */
+       struct v4l2_ctrl *link_freq;
+       struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *vblank;
+       struct v4l2_ctrl *hblank;
+       struct v4l2_ctrl *vflip;
+       struct v4l2_ctrl *hflip;
+
+       /* Current mode */
+       const struct imx208_mode *cur_mode;
+
+       /*
+        * Mutex for serialized access:
+        * Protect sensor set pad format and start/stop streaming safely.
+        * Protect access to sensor v4l2 controls.
+        */
+       struct mutex imx208_mx;
+
+       /* Streaming on/off */
+       bool streaming;
+
+       /* OTP data */
+       bool otp_read;
+       char otp_data[IMX208_OTP_SIZE];
+};
+
+static inline struct imx208 *to_imx208(struct v4l2_subdev *_sd)
+{
+       return container_of(_sd, struct imx208, sd);
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx208_get_format_code(struct imx208 *imx208)
+{
+       /*
+        * Only one bayer order is supported.
+        * It depends on the flip settings.
+        */
+       static const u32 codes[2][2] = {
+               { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
+               { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
+       };
+
+       return codes[imx208->vflip->val][imx208->hflip->val];
+}
+
+/* Read registers up to 4 at a time */
+static int imx208_read_reg(struct imx208 *imx208, u16 reg, u32 len, u32 *val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       struct i2c_msg msgs[2];
+       u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+       u8 data_buf[4] = { 0, };
+       int ret;
+
+       if (len > 4)
+               return -EINVAL;
+
+       /* Write register address */
+       msgs[0].addr = client->addr;
+       msgs[0].flags = 0;
+       msgs[0].len = ARRAY_SIZE(addr_buf);
+       msgs[0].buf = addr_buf;
+
+       /* Read data from register */
+       msgs[1].addr = client->addr;
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].len = len;
+       msgs[1].buf = &data_buf[4 - len];
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
+
+       *val = get_unaligned_be32(data_buf);
+
+       return 0;
+}
+
+/* Write registers up to 4 at a time */
+static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       u8 buf[6];
+
+       if (len > 4)
+               return -EINVAL;
+
+       put_unaligned_be16(reg, buf);
+       put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+       if (i2c_master_send(client, buf, len + 2) != len + 2)
+               return -EIO;
+
+       return 0;
+}
+
+/* Write a list of registers */
+static int imx208_write_regs(struct imx208 *imx208,
+                            const struct imx208_reg *regs, u32 len)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < len; i++) {
+               ret = imx208_write_reg(imx208, regs[i].address, 1,
+                                      regs[i].val);
+               if (ret) {
+                       dev_err_ratelimited(&client->dev,
+                                           "Failed to write reg 0x%4.4x. error = %d\n",
+                                           regs[i].address, ret);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* Open sub-device */
+static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *try_fmt =
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
+
+       /* Initialize try_fmt */
+       try_fmt->width = supported_modes[0].width;
+       try_fmt->height = supported_modes[0].height;
+       try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+       try_fmt->field = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int imx208_update_digital_gain(struct imx208 *imx208, u32 len, u32 val)
+{
+       int ret;
+
+       val = imx208_discrete_digital_gain[val] << IMX208_DIGITAL_GAIN_SHIFT;
+
+       ret = imx208_write_reg(imx208, IMX208_REG_GR_DIGITAL_GAIN, 2, val);
+       if (ret)
+               return ret;
+
+       ret = imx208_write_reg(imx208, IMX208_REG_GB_DIGITAL_GAIN, 2, val);
+       if (ret)
+               return ret;
+
+       ret = imx208_write_reg(imx208, IMX208_REG_R_DIGITAL_GAIN, 2, val);
+       if (ret)
+               return ret;
+
+       return imx208_write_reg(imx208, IMX208_REG_B_DIGITAL_GAIN, 2, val);
+}
+
+static int imx208_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct imx208 *imx208 =
+               container_of(ctrl->handler, struct imx208, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       int ret;
+
+       /*
+        * Applying V4L2 control value only happens
+        * when power is up for streaming
+        */
+       if (!pm_runtime_get_if_in_use(&client->dev))
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_ANALOGUE_GAIN:
+               ret = imx208_write_reg(imx208, IMX208_REG_ANALOG_GAIN,
+                                      2, ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE:
+               ret = imx208_write_reg(imx208, IMX208_REG_EXPOSURE,
+                                      2, ctrl->val);
+               break;
+       case V4L2_CID_DIGITAL_GAIN:
+               ret = imx208_update_digital_gain(imx208, 2, ctrl->val);
+               break;
+       case V4L2_CID_VBLANK:
+               /* Update VTS that meets expected vertical blanking */
+               ret = imx208_write_reg(imx208, IMX208_REG_VTS, 2,
+                                      imx208->cur_mode->height + ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN:
+               ret = imx208_write_reg(imx208, IMX208_REG_TEST_PATTERN_MODE,
+                                      2, imx208_test_pattern_val[ctrl->val]);
+               break;
+       case V4L2_CID_HFLIP:
+       case V4L2_CID_VFLIP:
+               ret = imx208_write_reg(imx208, IMX208_REG_ORIENTATION_CONTROL,
+                                      1,
+                                      imx208->hflip->val |
+                                      imx208->vflip->val << 1);
+               break;
+       default:
+               ret = -EINVAL;
+               dev_err(&client->dev,
+                       "ctrl(id:0x%x,val:0x%x) is not handled\n",
+                       ctrl->id, ctrl->val);
+               break;
+       }
+
+       pm_runtime_put(&client->dev);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops imx208_ctrl_ops = {
+       .s_ctrl = imx208_set_ctrl,
+};
+
+static const struct v4l2_ctrl_config imx208_digital_gain_control = {
+       .ops = &imx208_ctrl_ops,
+       .id = V4L2_CID_DIGITAL_GAIN,
+       .name = "Digital Gain",
+       .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+       .min = 0,
+       .max = ARRAY_SIZE(imx208_discrete_digital_gain) - 1,
+       .step = 0,
+       .def = 0,
+       .menu_skip_mask = 0,
+       .qmenu_int = imx208_discrete_digital_gain,
+};
+
+static int imx208_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_state *sd_state,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct imx208 *imx208 = to_imx208(sd);
+
+       if (code->index > 0)
+               return -EINVAL;
+
+       code->code = imx208_get_format_code(imx208);
+
+       return 0;
+}
+
+static int imx208_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_state *sd_state,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct imx208 *imx208 = to_imx208(sd);
+
+       if (fse->index >= ARRAY_SIZE(supported_modes))
+               return -EINVAL;
+
+       if (fse->code != imx208_get_format_code(imx208))
+               return -EINVAL;
+
+       fse->min_width = supported_modes[fse->index].width;
+       fse->max_width = fse->min_width;
+       fse->min_height = supported_modes[fse->index].height;
+       fse->max_height = fse->min_height;
+
+       return 0;
+}
+
+static void imx208_mode_to_pad_format(struct imx208 *imx208,
+                                     const struct imx208_mode *mode,
+                                     struct v4l2_subdev_format *fmt)
+{
+       fmt->format.width = mode->width;
+       fmt->format.height = mode->height;
+       fmt->format.code = imx208_get_format_code(imx208);
+       fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int __imx208_get_pad_format(struct imx208 *imx208,
+                                  struct v4l2_subdev_state *sd_state,
+                                  struct v4l2_subdev_format *fmt)
+{
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+               fmt->format = *v4l2_subdev_get_try_format(&imx208->sd,
+                                                         sd_state,
+                                                         fmt->pad);
+       else
+               imx208_mode_to_pad_format(imx208, imx208->cur_mode, fmt);
+
+       return 0;
+}
+
+static int imx208_get_pad_format(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_state *sd_state,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct imx208 *imx208 = to_imx208(sd);
+       int ret;
+
+       mutex_lock(&imx208->imx208_mx);
+       ret = __imx208_get_pad_format(imx208, sd_state, fmt);
+       mutex_unlock(&imx208->imx208_mx);
+
+       return ret;
+}
+
+static int imx208_set_pad_format(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_state *sd_state,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct imx208 *imx208 = to_imx208(sd);
+       const struct imx208_mode *mode;
+       s32 vblank_def;
+       s32 vblank_min;
+       s64 h_blank;
+       s64 pixel_rate;
+       s64 link_freq;
+
+       mutex_lock(&imx208->imx208_mx);
+
+       fmt->format.code = imx208_get_format_code(imx208);
+       mode = v4l2_find_nearest_size(supported_modes,
+                                     ARRAY_SIZE(supported_modes), width, height,
+                                     fmt->format.width, fmt->format.height);
+       imx208_mode_to_pad_format(imx208, mode, fmt);
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+       } else {
+               imx208->cur_mode = mode;
+               __v4l2_ctrl_s_ctrl(imx208->link_freq, mode->link_freq_index);
+               link_freq = link_freq_menu_items[mode->link_freq_index];
+               pixel_rate = link_freq_to_pixel_rate(link_freq);
+               __v4l2_ctrl_s_ctrl_int64(imx208->pixel_rate, pixel_rate);
+               /* Update limits and set FPS to default */
+               vblank_def = imx208->cur_mode->vts_def -
+                            imx208->cur_mode->height;
+               vblank_min = imx208->cur_mode->vts_min -
+                            imx208->cur_mode->height;
+               __v4l2_ctrl_modify_range(imx208->vblank, vblank_min,
+                                        IMX208_VTS_MAX - imx208->cur_mode->height,
+                                        1, vblank_def);
+               __v4l2_ctrl_s_ctrl(imx208->vblank, vblank_def);
+               h_blank =
+                       link_freq_configs[mode->link_freq_index].pixels_per_line
+                        - imx208->cur_mode->width;
+               __v4l2_ctrl_modify_range(imx208->hblank, h_blank,
+                                        h_blank, 1, h_blank);
+       }
+
+       mutex_unlock(&imx208->imx208_mx);
+
+       return 0;
+}
+
+/* Start streaming */
+static int imx208_start_streaming(struct imx208 *imx208)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       const struct imx208_reg_list *reg_list;
+       int ret, link_freq_index;
+
+       /* Setup PLL */
+       link_freq_index = imx208->cur_mode->link_freq_index;
+       reg_list = &link_freq_configs[link_freq_index].reg_list;
+       ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
+       if (ret) {
+               dev_err(&client->dev, "%s failed to set plls\n", __func__);
+               return ret;
+       }
+
+       /* Apply default values of current mode */
+       reg_list = &imx208->cur_mode->reg_list;
+       ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
+       if (ret) {
+               dev_err(&client->dev, "%s failed to set mode\n", __func__);
+               return ret;
+       }
+
+       /* Apply customized values from user */
+       ret =  __v4l2_ctrl_handler_setup(imx208->sd.ctrl_handler);
+       if (ret)
+               return ret;
+
+       /* set stream on register */
+       return imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
+                               1, IMX208_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static int imx208_stop_streaming(struct imx208 *imx208)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       int ret;
+
+       /* set stream off register */
+       ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
+                              1, IMX208_MODE_STANDBY);
+       if (ret)
+               dev_err(&client->dev, "%s failed to set stream\n", __func__);
+
+       /*
+        * Return success even if it was an error, as there is nothing the
+        * caller can do about it.
+        */
+       return 0;
+}
+
+static int imx208_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct imx208 *imx208 = to_imx208(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       mutex_lock(&imx208->imx208_mx);
+       if (imx208->streaming == enable) {
+               mutex_unlock(&imx208->imx208_mx);
+               return 0;
+       }
+
+       if (enable) {
+               ret = pm_runtime_get_sync(&client->dev);
+               if (ret < 0)
+                       goto err_rpm_put;
+
+               /*
+                * Apply default & customized values
+                * and then start streaming.
+                */
+               ret = imx208_start_streaming(imx208);
+               if (ret)
+                       goto err_rpm_put;
+       } else {
+               imx208_stop_streaming(imx208);
+               pm_runtime_put(&client->dev);
+       }
+
+       imx208->streaming = enable;
+       mutex_unlock(&imx208->imx208_mx);
+
+       /* vflip and hflip cannot change during streaming */
+       v4l2_ctrl_grab(imx208->vflip, enable);
+       v4l2_ctrl_grab(imx208->hflip, enable);
+
+       return ret;
+
+err_rpm_put:
+       pm_runtime_put(&client->dev);
+       mutex_unlock(&imx208->imx208_mx);
+
+       return ret;
+}
+
+static int __maybe_unused imx208_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx208 *imx208 = to_imx208(sd);
+
+       if (imx208->streaming)
+               imx208_stop_streaming(imx208);
+
+       return 0;
+}
+
+static int __maybe_unused imx208_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx208 *imx208 = to_imx208(sd);
+       int ret;
+
+       if (imx208->streaming) {
+               ret = imx208_start_streaming(imx208);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+
+error:
+       imx208_stop_streaming(imx208);
+       imx208->streaming = 0;
+
+       return ret;
+}
+
+/* Verify chip ID */
+static int imx208_identify_module(struct imx208 *imx208)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       int ret;
+       u32 val;
+
+       ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID,
+                             2, &val);
+       if (ret) {
+               dev_err(&client->dev, "failed to read chip id %x\n",
+                       IMX208_CHIP_ID);
+               return ret;
+       }
+
+       if (val != IMX208_CHIP_ID) {
+               dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+                       IMX208_CHIP_ID, val);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx208_video_ops = {
+       .s_stream = imx208_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx208_pad_ops = {
+       .enum_mbus_code = imx208_enum_mbus_code,
+       .get_fmt = imx208_get_pad_format,
+       .set_fmt = imx208_set_pad_format,
+       .enum_frame_size = imx208_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx208_subdev_ops = {
+       .video = &imx208_video_ops,
+       .pad = &imx208_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx208_internal_ops = {
+       .open = imx208_open,
+};
+
+static int imx208_read_otp(struct imx208 *imx208)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       struct i2c_msg msgs[2];
+       u8 addr_buf[2] = { IMX208_OTP_BASE >> 8, IMX208_OTP_BASE & 0xff };
+       int ret = 0;
+
+       mutex_lock(&imx208->imx208_mx);
+
+       if (imx208->otp_read)
+               goto out_unlock;
+
+       ret = pm_runtime_get_sync(&client->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(&client->dev);
+               goto out_unlock;
+       }
+
+       /* Write register address */
+       msgs[0].addr = client->addr;
+       msgs[0].flags = 0;
+       msgs[0].len = ARRAY_SIZE(addr_buf);
+       msgs[0].buf = addr_buf;
+
+       /* Read data from registers */
+       msgs[1].addr = client->addr;
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].len = sizeof(imx208->otp_data);
+       msgs[1].buf = imx208->otp_data;
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret == ARRAY_SIZE(msgs)) {
+               imx208->otp_read = true;
+               ret = 0;
+       }
+
+       pm_runtime_put(&client->dev);
+
+out_unlock:
+       mutex_unlock(&imx208->imx208_mx);
+
+       return ret;
+}
+
+static ssize_t otp_read(struct file *filp, struct kobject *kobj,
+                       struct bin_attribute *bin_attr,
+                       char *buf, loff_t off, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx208 *imx208 = to_imx208(sd);
+       int ret;
+
+       ret = imx208_read_otp(imx208);
+       if (ret)
+               return ret;
+
+       memcpy(buf, &imx208->otp_data[off], count);
+       return count;
+}
+
+static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE);
+
+/* Initialize control handlers */
+static int imx208_init_controls(struct imx208 *imx208)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+       struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler;
+       s64 exposure_max;
+       s64 vblank_def;
+       s64 vblank_min;
+       s64 pixel_rate_min;
+       s64 pixel_rate_max;
+       int ret;
+
+       ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+       if (ret)
+               return ret;
+
+       mutex_init(&imx208->imx208_mx);
+       ctrl_hdlr->lock = &imx208->imx208_mx;
+       imx208->link_freq =
+               v4l2_ctrl_new_int_menu(ctrl_hdlr,
+                                      &imx208_ctrl_ops,
+                                      V4L2_CID_LINK_FREQ,
+                                      ARRAY_SIZE(link_freq_menu_items) - 1,
+                                      0, link_freq_menu_items);
+
+       if (imx208->link_freq)
+               imx208->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
+       pixel_rate_min =
+               link_freq_to_pixel_rate(link_freq_menu_items[ARRAY_SIZE(link_freq_menu_items) - 1]);
+       /* By default, PIXEL_RATE is read only */
+       imx208->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+                                              V4L2_CID_PIXEL_RATE,
+                                              pixel_rate_min, pixel_rate_max,
+                                              1, pixel_rate_max);
+
+       vblank_def = imx208->cur_mode->vts_def - imx208->cur_mode->height;
+       vblank_min = imx208->cur_mode->vts_min - imx208->cur_mode->height;
+       imx208->vblank =
+               v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_VBLANK,
+                                 vblank_min,
+                                 IMX208_VTS_MAX - imx208->cur_mode->height, 1,
+                                 vblank_def);
+
+       imx208->hblank =
+               v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_HBLANK,
+                                 IMX208_PPL_384MHZ - imx208->cur_mode->width,
+                                 IMX208_PPL_384MHZ - imx208->cur_mode->width,
+                                 1,
+                                 IMX208_PPL_384MHZ - imx208->cur_mode->width);
+
+       if (imx208->hblank)
+               imx208->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       exposure_max = imx208->cur_mode->vts_def - 8;
+       v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_EXPOSURE,
+                         IMX208_EXPOSURE_MIN, exposure_max,
+                         IMX208_EXPOSURE_STEP, IMX208_EXPOSURE_DEFAULT);
+
+       imx208->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+                                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       imx208->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+                                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+       v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+                         IMX208_ANA_GAIN_MIN, IMX208_ANA_GAIN_MAX,
+                         IMX208_ANA_GAIN_STEP, IMX208_ANA_GAIN_DEFAULT);
+
+       v4l2_ctrl_new_custom(ctrl_hdlr, &imx208_digital_gain_control, NULL);
+
+       v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx208_ctrl_ops,
+                                    V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(imx208_test_pattern_menu) - 1,
+                                    0, 0, imx208_test_pattern_menu);
+
+       if (ctrl_hdlr->error) {
+               ret = ctrl_hdlr->error;
+               dev_err(&client->dev, "%s control init failed (%d)\n",
+                       __func__, ret);
+               goto error;
+       }
+
+       imx208->sd.ctrl_handler = ctrl_hdlr;
+
+       return 0;
+
+error:
+       v4l2_ctrl_handler_free(ctrl_hdlr);
+       mutex_destroy(&imx208->imx208_mx);
+
+       return ret;
+}
+
+static void imx208_free_controls(struct imx208 *imx208)
+{
+       v4l2_ctrl_handler_free(imx208->sd.ctrl_handler);
+}
+
+static int imx208_probe(struct i2c_client *client)
+{
+       struct imx208 *imx208;
+       int ret;
+       u32 val = 0;
+
+       device_property_read_u32(&client->dev, "clock-frequency", &val);
+       if (val != 19200000) {
+               dev_err(&client->dev,
+                       "Unsupported clock-frequency %u. Expected 19200000.\n",
+                       val);
+               return -EINVAL;
+       }
+
+       imx208 = devm_kzalloc(&client->dev, sizeof(*imx208), GFP_KERNEL);
+       if (!imx208)
+               return -ENOMEM;
+
+       /* Initialize subdev */
+       v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops);
+
+       /* Check module identity */
+       ret = imx208_identify_module(imx208);
+       if (ret) {
+               dev_err(&client->dev, "failed to find sensor: %d", ret);
+               goto error_probe;
+       }
+
+       /* Set default mode to max resolution */
+       imx208->cur_mode = &supported_modes[0];
+
+       ret = imx208_init_controls(imx208);
+       if (ret) {
+               dev_err(&client->dev, "failed to init controls: %d", ret);
+               goto error_probe;
+       }
+
+       /* Initialize subdev */
+       imx208->sd.internal_ops = &imx208_internal_ops;
+       imx208->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       imx208->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       /* Initialize source pad */
+       imx208->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_pads_init(&imx208->sd.entity, 1, &imx208->pad);
+       if (ret) {
+               dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
+               goto error_handler_free;
+       }
+
+       ret = v4l2_async_register_subdev_sensor(&imx208->sd);
+       if (ret < 0)
+               goto error_media_entity;
+
+       ret = device_create_bin_file(&client->dev, &bin_attr_otp);
+       if (ret) {
+               dev_err(&client->dev, "sysfs otp creation failed\n");
+               goto error_async_subdev;
+       }
+
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_enable(&client->dev);
+       pm_runtime_idle(&client->dev);
+
+       return 0;
+
+error_async_subdev:
+       v4l2_async_unregister_subdev(&imx208->sd);
+
+error_media_entity:
+       media_entity_cleanup(&imx208->sd.entity);
+
+error_handler_free:
+       imx208_free_controls(imx208);
+
+error_probe:
+       mutex_destroy(&imx208->imx208_mx);
+
+       return ret;
+}
+
+static int imx208_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx208 *imx208 = to_imx208(sd);
+
+       device_remove_bin_file(&client->dev, &bin_attr_otp);
+       v4l2_async_unregister_subdev(sd);
+       media_entity_cleanup(&sd->entity);
+       imx208_free_controls(imx208);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       mutex_destroy(&imx208->imx208_mx);
+
+       return 0;
+}
+
+static const struct dev_pm_ops imx208_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(imx208_suspend, imx208_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id imx208_acpi_ids[] = {
+       { "INT3478" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids);
+#endif
+
+static struct i2c_driver imx208_i2c_driver = {
+       .driver = {
+               .name = "imx208",
+               .pm = &imx208_pm_ops,
+               .acpi_match_table = ACPI_PTR(imx208_acpi_ids),
+       },
+       .probe_new = imx208_probe,
+       .remove = imx208_remove,
+};
+
+module_i2c_driver(imx208_i2c_driver);
+
+MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
+MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@intel.com>");
+MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
+MODULE_DESCRIPTION("Sony IMX208 sensor driver");
+MODULE_LICENSE("GPL v2");
index e8b281e..83c1737 100644 (file)
@@ -474,7 +474,7 @@ static int __maybe_unused imx214_power_off(struct device *dev)
 }
 
 static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -486,7 +486,7 @@ static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->code != IMX214_MBUS_CODE)
@@ -534,13 +534,13 @@ static const struct v4l2_subdev_core_ops imx214_core_ops = {
 
 static struct v4l2_mbus_framefmt *
 __imx214_get_pad_format(struct imx214 *imx214,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad,
                        enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&imx214->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &imx214->fmt;
        default:
@@ -549,13 +549,14 @@ __imx214_get_pad_format(struct imx214 *imx214,
 }
 
 static int imx214_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct imx214 *imx214 = to_imx214(sd);
 
        mutex_lock(&imx214->mutex);
-       format->format = *__imx214_get_pad_format(imx214, cfg, format->pad,
+       format->format = *__imx214_get_pad_format(imx214, sd_state,
+                                                 format->pad,
                                                  format->which);
        mutex_unlock(&imx214->mutex);
 
@@ -563,12 +564,13 @@ static int imx214_get_format(struct v4l2_subdev *sd,
 }
 
 static struct v4l2_rect *
-__imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
+__imx214_get_pad_crop(struct imx214 *imx214,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&imx214->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &imx214->crop;
        default:
@@ -577,7 +579,7 @@ __imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
 }
 
 static int imx214_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct imx214 *imx214 = to_imx214(sd);
@@ -587,7 +589,8 @@ static int imx214_set_format(struct v4l2_subdev *sd,
 
        mutex_lock(&imx214->mutex);
 
-       __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which);
+       __crop = __imx214_get_pad_crop(imx214, sd_state, format->pad,
+                                      format->which);
 
        mode = v4l2_find_nearest_size(imx214_modes,
                                      ARRAY_SIZE(imx214_modes), width, height,
@@ -597,7 +600,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
        __crop->width = mode->width;
        __crop->height = mode->height;
 
-       __format = __imx214_get_pad_format(imx214, cfg, format->pad,
+       __format = __imx214_get_pad_format(imx214, sd_state, format->pad,
                                           format->which);
        __format->width = __crop->width;
        __format->height = __crop->height;
@@ -617,7 +620,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
 }
 
 static int imx214_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct imx214 *imx214 = to_imx214(sd);
@@ -626,22 +629,22 @@ static int imx214_get_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        mutex_lock(&imx214->mutex);
-       sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad,
+       sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
                                        sel->which);
        mutex_unlock(&imx214->mutex);
        return 0;
 }
 
 static int imx214_entity_init_cfg(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = { };
 
-       fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
        fmt.format.width = imx214_modes[0].width;
        fmt.format.height = imx214_modes[0].height;
 
-       imx214_set_format(subdev, cfg, &fmt);
+       imx214_set_format(subdev, sd_state, &fmt);
 
        return 0;
 }
@@ -776,11 +779,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
                return 0;
 
        if (enable) {
-               ret = pm_runtime_get_sync(imx214->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(imx214->dev);
+               ret = pm_runtime_resume_and_get(imx214->dev);
+               if (ret < 0)
                        return ret;
-               }
 
                ret = imx214_start_streaming(imx214);
                if (ret < 0)
@@ -810,7 +811,7 @@ static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
 }
 
 static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_interval_enum *fie)
 {
        const struct imx214_mode *mode;
index 1054ffe..e10af3f 100644 (file)
@@ -689,7 +689,7 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct imx219 *imx219 = to_imx219(sd);
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
        struct v4l2_rect *try_crop;
 
        mutex_lock(&imx219->mutex);
@@ -702,7 +702,7 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        try_fmt->field = V4L2_FIELD_NONE;
 
        /* Initialize try_crop rectangle. */
-       try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+       try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
        try_crop->top = IMX219_PIXEL_ARRAY_TOP;
        try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
        try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
@@ -803,7 +803,7 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
 };
 
 static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct imx219 *imx219 = to_imx219(sd);
@@ -819,7 +819,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx219_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct imx219 *imx219 = to_imx219(sd);
@@ -863,12 +863,13 @@ static void imx219_update_pad_format(struct imx219 *imx219,
 }
 
 static int __imx219_get_pad_format(struct imx219 *imx219,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *fmt)
 {
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *try_fmt =
-                       v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
+                       v4l2_subdev_get_try_format(&imx219->sd, sd_state,
+                                                  fmt->pad);
                /* update the code which could change due to vflip or hflip: */
                try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
                fmt->format = *try_fmt;
@@ -882,21 +883,21 @@ static int __imx219_get_pad_format(struct imx219 *imx219,
 }
 
 static int imx219_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx219 *imx219 = to_imx219(sd);
        int ret;
 
        mutex_lock(&imx219->mutex);
-       ret = __imx219_get_pad_format(imx219, cfg, fmt);
+       ret = __imx219_get_pad_format(imx219, sd_state, fmt);
        mutex_unlock(&imx219->mutex);
 
        return ret;
 }
 
 static int imx219_set_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx219 *imx219 = to_imx219(sd);
@@ -922,7 +923,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
        imx219_update_pad_format(imx219, mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else if (imx219->mode != mode ||
                   imx219->fmt.code != fmt->format.code) {
@@ -979,12 +980,13 @@ static int imx219_set_framefmt(struct imx219 *imx219)
 }
 
 static const struct v4l2_rect *
-__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg,
+__imx219_get_pad_crop(struct imx219 *imx219,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&imx219->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &imx219->mode->crop;
        }
@@ -993,7 +995,7 @@ __imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg,
 }
 
 static int imx219_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        switch (sel->target) {
@@ -1001,7 +1003,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
                struct imx219 *imx219 = to_imx219(sd);
 
                mutex_lock(&imx219->mutex);
-               sel->r = *__imx219_get_pad_crop(imx219, cfg, sel->pad,
+               sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
                                                sel->which);
                mutex_unlock(&imx219->mutex);
 
@@ -1035,11 +1037,9 @@ static int imx219_start_streaming(struct imx219 *imx219)
        const struct imx219_reg_list *reg_list;
        int ret;
 
-       ret = pm_runtime_get_sync(&client->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&client->dev);
+       ret = pm_runtime_resume_and_get(&client->dev);
+       if (ret < 0)
                return ret;
-       }
 
        /* Apply default values of current mode */
        reg_list = &imx219->mode->reg_list;
index a017ec4..7ab9e5f 100644 (file)
@@ -710,7 +710,7 @@ static int imx258_write_regs(struct imx258 *imx258,
 static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        /* Initialize try_fmt */
        try_fmt->width = supported_modes[0].width;
@@ -820,7 +820,7 @@ static const struct v4l2_ctrl_ops imx258_ctrl_ops = {
 };
 
 static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        /* Only one bayer order(GRBG) is supported */
@@ -833,7 +833,7 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx258_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -860,11 +860,12 @@ static void imx258_update_pad_format(const struct imx258_mode *mode,
 }
 
 static int __imx258_get_pad_format(struct imx258 *imx258,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *fmt)
 {
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&imx258->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&imx258->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                imx258_update_pad_format(imx258->cur_mode, fmt);
@@ -873,21 +874,21 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
 }
 
 static int imx258_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx258 *imx258 = to_imx258(sd);
        int ret;
 
        mutex_lock(&imx258->mutex);
-       ret = __imx258_get_pad_format(imx258, cfg, fmt);
+       ret = __imx258_get_pad_format(imx258, sd_state, fmt);
        mutex_unlock(&imx258->mutex);
 
        return ret;
 }
 
 static int imx258_set_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx258 *imx258 = to_imx258(sd);
@@ -909,7 +910,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
                fmt->format.width, fmt->format.height);
        imx258_update_pad_format(mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else {
                imx258->cur_mode = mode;
@@ -1039,11 +1040,9 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto err_unlock;
-               }
 
                /*
                 * Apply default & customized values
index cdccaab..0dce928 100644 (file)
@@ -996,7 +996,7 @@ static int imx274_binning_goodness(struct stimx274 *imx274,
  * Must be called with imx274->lock locked.
  *
  * @imx274: The device object
- * @cfg:    The pad config we are editing for TRY requests
+ * @sd_state: The subdev state we are editing for TRY requests
  * @which:  V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY from the caller
  * @width:  Input-output parameter: set to the desired width before
  *          the call, contains the chosen value after returning successfully
@@ -1005,7 +1005,7 @@ static int imx274_binning_goodness(struct stimx274 *imx274,
  *          available (when called from set_fmt)
  */
 static int __imx274_change_compose(struct stimx274 *imx274,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   u32 which,
                                   u32 *width,
                                   u32 *height,
@@ -1019,8 +1019,8 @@ static int __imx274_change_compose(struct stimx274 *imx274,
        int best_goodness = INT_MIN;
 
        if (which == V4L2_SUBDEV_FORMAT_TRY) {
-               cur_crop = &cfg->try_crop;
-               tgt_fmt = &cfg->try_fmt;
+               cur_crop = &sd_state->pads->try_crop;
+               tgt_fmt = &sd_state->pads->try_fmt;
        } else {
                cur_crop = &imx274->crop;
                tgt_fmt = &imx274->format;
@@ -1061,7 +1061,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
 /**
  * imx274_get_fmt - Get the pad format
  * @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
  * @fmt: Pointer to pad level media bus format
  *
  * This function is used to get the pad format information.
@@ -1069,7 +1069,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
  * Return: 0 on success
  */
 static int imx274_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct stimx274 *imx274 = to_imx274(sd);
@@ -1083,7 +1083,7 @@ static int imx274_get_fmt(struct v4l2_subdev *sd,
 /**
  * imx274_set_fmt - This is used to set the pad format
  * @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state information structure
  * @format: Pointer to pad level media bus format
  *
  * This function is used to set the pad format.
@@ -1091,7 +1091,7 @@ static int imx274_get_fmt(struct v4l2_subdev *sd,
  * Return: 0 on success
  */
 static int imx274_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1100,7 +1100,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&imx274->lock);
 
-       err = __imx274_change_compose(imx274, cfg, format->which,
+       err = __imx274_change_compose(imx274, sd_state, format->which,
                                      &fmt->width, &fmt->height, 0);
 
        if (err)
@@ -1113,7 +1113,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
         */
        fmt->field = V4L2_FIELD_NONE;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
        else
                imx274->format = *fmt;
 
@@ -1124,7 +1124,7 @@ out:
 }
 
 static int imx274_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct stimx274 *imx274 = to_imx274(sd);
@@ -1144,8 +1144,8 @@ static int imx274_get_selection(struct v4l2_subdev *sd,
        }
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               src_crop = &cfg->try_crop;
-               src_fmt = &cfg->try_fmt;
+               src_crop = &sd_state->pads->try_crop;
+               src_fmt = &sd_state->pads->try_fmt;
        } else {
                src_crop = &imx274->crop;
                src_fmt = &imx274->format;
@@ -1179,7 +1179,7 @@ static int imx274_get_selection(struct v4l2_subdev *sd,
 }
 
 static int imx274_set_selection_crop(struct stimx274 *imx274,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct v4l2_rect *tgt_crop;
@@ -1216,7 +1216,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
        sel->r = new_crop;
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
-               tgt_crop = &cfg->try_crop;
+               tgt_crop = &sd_state->pads->try_crop;
        else
                tgt_crop = &imx274->crop;
 
@@ -1230,7 +1230,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
 
        /* if crop size changed then reset the output image size */
        if (size_changed)
-               __imx274_change_compose(imx274, cfg, sel->which,
+               __imx274_change_compose(imx274, sd_state, sel->which,
                                        &new_crop.width, &new_crop.height,
                                        sel->flags);
 
@@ -1240,7 +1240,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
 }
 
 static int imx274_set_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct stimx274 *imx274 = to_imx274(sd);
@@ -1249,13 +1249,13 @@ static int imx274_set_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sel->target == V4L2_SEL_TGT_CROP)
-               return imx274_set_selection_crop(imx274, cfg, sel);
+               return imx274_set_selection_crop(imx274, sd_state, sel);
 
        if (sel->target == V4L2_SEL_TGT_COMPOSE) {
                int err;
 
                mutex_lock(&imx274->lock);
-               err =  __imx274_change_compose(imx274, cfg, sel->which,
+               err =  __imx274_change_compose(imx274, sd_state, sel->which,
                                               &sel->r.width, &sel->r.height,
                                               sel->flags);
                mutex_unlock(&imx274->lock);
@@ -1441,9 +1441,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
        mutex_lock(&imx274->lock);
 
        if (on) {
-               ret = pm_runtime_get_sync(&imx274->client->dev);
+               ret = pm_runtime_resume_and_get(&imx274->client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&imx274->client->dev);
                        mutex_unlock(&imx274->lock);
                        return ret;
                }
index 6319a42..bf7a6c3 100644 (file)
@@ -516,7 +516,7 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
 };
 
 static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(imx290_formats))
@@ -528,7 +528,7 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx290_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        const struct imx290 *imx290 = to_imx290(sd);
@@ -550,7 +550,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int imx290_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct imx290 *imx290 = to_imx290(sd);
@@ -559,7 +559,7 @@ static int imx290_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&imx290->lock);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               framefmt = v4l2_subdev_get_try_format(&imx290->sd, cfg,
+               framefmt = v4l2_subdev_get_try_format(&imx290->sd, sd_state,
                                                      fmt->pad);
        else
                framefmt = &imx290->current_format;
@@ -596,8 +596,8 @@ static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
 }
 
 static int imx290_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                     struct v4l2_subdev_format *fmt)
+                         struct v4l2_subdev_state *sd_state,
+                         struct v4l2_subdev_format *fmt)
 {
        struct imx290 *imx290 = to_imx290(sd);
        const struct imx290_mode *mode;
@@ -624,7 +624,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
        fmt->format.field = V4L2_FIELD_NONE;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               format = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
        } else {
                format = &imx290->current_format;
                imx290->current_mode = mode;
@@ -646,15 +646,15 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = { 0 };
 
-       fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
        fmt.format.width = 1920;
        fmt.format.height = 1080;
 
-       imx290_set_fmt(subdev, cfg, &fmt);
+       imx290_set_fmt(subdev, sd_state, &fmt);
 
        return 0;
 }
@@ -764,11 +764,9 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
        int ret = 0;
 
        if (enable) {
-               ret = pm_runtime_get_sync(imx290->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(imx290->dev);
+               ret = pm_runtime_resume_and_get(imx290->dev);
+               if (ret < 0)
                        goto unlock_and_return;
-               }
 
                ret = imx290_start_streaming(imx290);
                if (ret) {
index 3854032..dba0854 100644 (file)
@@ -1860,7 +1860,7 @@ static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct imx319 *imx319 = to_imx319(sd);
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        mutex_lock(&imx319->mutex);
 
@@ -1947,7 +1947,7 @@ static const struct v4l2_ctrl_ops imx319_ctrl_ops = {
 };
 
 static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct imx319 *imx319 = to_imx319(sd);
@@ -1963,7 +1963,7 @@ static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx319_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct imx319 *imx319 = to_imx319(sd);
@@ -1997,14 +1997,14 @@ static void imx319_update_pad_format(struct imx319 *imx319,
 }
 
 static int imx319_do_get_pad_format(struct imx319 *imx319,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *framefmt;
        struct v4l2_subdev *sd = &imx319->sd;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *framefmt;
        } else {
                imx319_update_pad_format(imx319, imx319->cur_mode, fmt);
@@ -2014,14 +2014,14 @@ static int imx319_do_get_pad_format(struct imx319 *imx319,
 }
 
 static int imx319_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx319 *imx319 = to_imx319(sd);
        int ret;
 
        mutex_lock(&imx319->mutex);
-       ret = imx319_do_get_pad_format(imx319, cfg, fmt);
+       ret = imx319_do_get_pad_format(imx319, sd_state, fmt);
        mutex_unlock(&imx319->mutex);
 
        return ret;
@@ -2029,7 +2029,7 @@ static int imx319_get_pad_format(struct v4l2_subdev *sd,
 
 static int
 imx319_set_pad_format(struct v4l2_subdev *sd,
-                     struct v4l2_subdev_pad_config *cfg,
+                     struct v4l2_subdev_state *sd_state,
                      struct v4l2_subdev_format *fmt)
 {
        struct imx319 *imx319 = to_imx319(sd);
@@ -2055,7 +2055,7 @@ imx319_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
        imx319_update_pad_format(imx319, mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else {
                imx319->cur_mode = mode;
@@ -2141,11 +2141,9 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto err_unlock;
-               }
 
                /*
                 * Apply default & customized values
index 047aa76..0621255 100644 (file)
@@ -497,13 +497,13 @@ static const struct v4l2_ctrl_ops imx334_ctrl_ops = {
 /**
  * imx334_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes
  * @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
  * @code: V4L2 sub-device code enumeration need to be filled
  *
  * Return: 0 if successful, error code otherwise.
  */
 static int imx334_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -517,13 +517,13 @@ static int imx334_enum_mbus_code(struct v4l2_subdev *sd,
 /**
  * imx334_enum_frame_size() - Enumerate V4L2 sub-device frame sizes
  * @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
  * @fsize: V4L2 sub-device size enumeration need to be filled
  *
  * Return: 0 if successful, error code otherwise.
  */
 static int imx334_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fsize)
 {
        if (fsize->index > 0)
@@ -564,13 +564,13 @@ static void imx334_fill_pad_format(struct imx334 *imx334,
 /**
  * imx334_get_pad_format() - Get subdevice pad format
  * @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
  * @fmt: V4L2 sub-device format need to be set
  *
  * Return: 0 if successful, error code otherwise.
  */
 static int imx334_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx334 *imx334 = to_imx334(sd);
@@ -580,7 +580,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *framefmt;
 
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *framefmt;
        } else {
                imx334_fill_pad_format(imx334, imx334->cur_mode, fmt);
@@ -594,13 +594,13 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
 /**
  * imx334_set_pad_format() - Set subdevice pad format
  * @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
  * @fmt: V4L2 sub-device format need to be set
  *
  * Return: 0 if successful, error code otherwise.
  */
 static int imx334_set_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx334 *imx334 = to_imx334(sd);
@@ -615,7 +615,7 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *framefmt;
 
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else {
                ret = imx334_update_controls(imx334, mode);
@@ -631,20 +631,20 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
 /**
  * imx334_init_pad_cfg() - Initialize sub-device pad configuration
  * @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
  *
  * Return: 0 if successful, error code otherwise.
  */
 static int imx334_init_pad_cfg(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg)
+                              struct v4l2_subdev_state *sd_state)
 {
        struct imx334 *imx334 = to_imx334(sd);
        struct v4l2_subdev_format fmt = { 0 };
 
-       fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
        imx334_fill_pad_format(imx334, &supported_mode, &fmt);
 
-       return imx334_set_pad_format(sd, cfg, &fmt);
+       return imx334_set_pad_format(sd, sd_state, &fmt);
 }
 
 /**
@@ -717,9 +717,9 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(imx334->dev);
-               if (ret)
-                       goto error_power_off;
+               ret = pm_runtime_resume_and_get(imx334->dev);
+               if (ret < 0)
+                       goto error_unlock;
 
                ret = imx334_start_streaming(imx334);
                if (ret)
@@ -737,6 +737,7 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable)
 
 error_power_off:
        pm_runtime_put(imx334->dev);
+error_unlock:
        mutex_unlock(&imx334->mutex);
 
        return ret;
index ccedcd4..cb51c81 100644 (file)
@@ -1161,7 +1161,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct imx355 *imx355 = to_imx355(sd);
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        mutex_lock(&imx355->mutex);
 
@@ -1248,7 +1248,7 @@ static const struct v4l2_ctrl_ops imx355_ctrl_ops = {
 };
 
 static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct imx355 *imx355 = to_imx355(sd);
@@ -1264,7 +1264,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int imx355_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct imx355 *imx355 = to_imx355(sd);
@@ -1298,14 +1298,14 @@ static void imx355_update_pad_format(struct imx355 *imx355,
 }
 
 static int imx355_do_get_pad_format(struct imx355 *imx355,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *framefmt;
        struct v4l2_subdev *sd = &imx355->sd;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *framefmt;
        } else {
                imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
@@ -1315,14 +1315,14 @@ static int imx355_do_get_pad_format(struct imx355 *imx355,
 }
 
 static int imx355_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct imx355 *imx355 = to_imx355(sd);
        int ret;
 
        mutex_lock(&imx355->mutex);
-       ret = imx355_do_get_pad_format(imx355, cfg, fmt);
+       ret = imx355_do_get_pad_format(imx355, sd_state, fmt);
        mutex_unlock(&imx355->mutex);
 
        return ret;
@@ -1330,7 +1330,7 @@ static int imx355_get_pad_format(struct v4l2_subdev *sd,
 
 static int
 imx355_set_pad_format(struct v4l2_subdev *sd,
-                     struct v4l2_subdev_pad_config *cfg,
+                     struct v4l2_subdev_state *sd_state,
                      struct v4l2_subdev_format *fmt)
 {
        struct imx355 *imx355 = to_imx355(sd);
@@ -1356,7 +1356,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
        imx355_update_pad_format(imx355, mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else {
                imx355->cur_mode = mode;
@@ -1442,11 +1442,9 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto err_unlock;
-               }
 
                /*
                 * Apply default & customized values
index e8119ad..9237659 100644 (file)
@@ -678,8 +678,8 @@ static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf,
                goto out_unlock;
        }
 
-       i = i2c_master_recv(ir->tx_c, buf, 1);
-       if (i != 1) {
+       ret = i2c_master_recv(ir->tx_c, buf, 1);
+       if (ret != 1) {
                dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret);
                ret = -EIO;
                goto out_unlock;
index 21666d7..e29be02 100644 (file)
@@ -539,17 +539,19 @@ static int __find_resolution(struct v4l2_subdev *sd,
 }
 
 static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                enum v4l2_subdev_format_whence which,
                                enum m5mols_restype type)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return cfg ? v4l2_subdev_get_try_format(&info->sd, cfg, 0) : NULL;
+               return sd_state ? v4l2_subdev_get_try_format(&info->sd,
+                                                            sd_state, 0) : NULL;
 
        return &info->ffmt[type];
 }
 
-static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int m5mols_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct m5mols_info *info = to_m5mols(sd);
@@ -558,7 +560,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
 
        mutex_lock(&info->lock);
 
-       format = __find_format(info, cfg, fmt->which, info->res_type);
+       format = __find_format(info, sd_state, fmt->which, info->res_type);
        if (format)
                fmt->format = *format;
        else
@@ -568,7 +570,8 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        return ret;
 }
 
-static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int m5mols_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct m5mols_info *info = to_m5mols(sd);
@@ -582,7 +585,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        if (ret < 0)
                return ret;
 
-       sfmt = __find_format(info, cfg, fmt->which, type);
+       sfmt = __find_format(info, sd_state, fmt->which, type);
        if (!sfmt)
                return 0;
 
@@ -648,7 +651,7 @@ static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
 
 
 static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (!code || code->index >= SIZE_DEFAULT_FFMT)
@@ -909,7 +912,9 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = {
  */
 static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+                                                                      fh->state,
+                                                                      0);
 
        *format = m5mols_default_ffmt[0];
        return 0;
index c495582..ff86c8c 100644 (file)
@@ -80,6 +80,18 @@ static int max9271_pclk_detect(struct max9271_device *dev)
        return -EIO;
 }
 
+void max9271_wake_up(struct max9271_device *dev)
+{
+       /*
+        * Use the chip default address as this function has to be called
+        * before any other one.
+        */
+       dev->client->addr = MAX9271_DEFAULT_ADDR;
+       i2c_smbus_read_byte(dev->client);
+       usleep_range(5000, 8000);
+}
+EXPORT_SYMBOL_GPL(max9271_wake_up);
+
 int max9271_set_serial_link(struct max9271_device *dev, bool enable)
 {
        int ret;
@@ -106,7 +118,10 @@ int max9271_set_serial_link(struct max9271_device *dev, bool enable)
         * Short delays here appear to show bit-errors in the writes following.
         * Therefore a conservative delay seems best here.
         */
-       max9271_write(dev, 0x04, val);
+       ret = max9271_write(dev, 0x04, val);
+       if (ret < 0)
+               return ret;
+
        usleep_range(5000, 8000);
 
        return 0;
@@ -118,7 +133,7 @@ int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
        int ret;
 
        ret = max9271_write(dev, 0x0d, i2c_config);
-       if (ret)
+       if (ret < 0)
                return ret;
 
        /* The delay required after an I2C bus configuration change is not
@@ -143,7 +158,10 @@ int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
         * Enable or disable reverse channel high threshold to increase
         * immunity to power supply noise.
         */
-       max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+       ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+       if (ret < 0)
+               return ret;
+
        usleep_range(2000, 2500);
 
        return 0;
@@ -152,6 +170,8 @@ EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
 
 int max9271_configure_gmsl_link(struct max9271_device *dev)
 {
+       int ret;
+
        /*
         * Configure the GMSL link:
         *
@@ -162,16 +182,24 @@ int max9271_configure_gmsl_link(struct max9271_device *dev)
         *
         * TODO: Make the GMSL link configuration parametric.
         */
-       max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
-                     MAX9271_EDC_1BIT_PARITY);
+       ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
+                           MAX9271_EDC_1BIT_PARITY);
+       if (ret < 0)
+               return ret;
+
        usleep_range(5000, 8000);
 
        /*
         * Adjust spread spectrum to +4% and auto-detect pixel clock
         * and serial link rate.
         */
-       max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
-                     MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
+       ret = max9271_write(dev, 0x02,
+                           MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
+                           MAX9271_PCLK_AUTODETECT |
+                           MAX9271_SERIAL_AUTODETECT);
+       if (ret < 0)
+               return ret;
+
        usleep_range(5000, 8000);
 
        return 0;
index d78fb21..dc5e4e7 100644 (file)
@@ -86,6 +86,15 @@ struct max9271_device {
 };
 
 /**
+ * max9271_wake_up() - Wake up the serializer by issuing an i2c transaction
+ * @dev: The max9271 device
+ *
+ * This function shall be called before any other interaction with the
+ * serializer.
+ */
+void max9271_wake_up(struct max9271_device *dev);
+
+/**
  * max9271_set_serial_link() - Enable/disable serial link
  * @dev: The max9271 device
  * @enable: Serial link enable/disable flag
index 6fd4d59..1aa2c58 100644 (file)
 #define MAX9286_REV_TRF(n)             ((n) << 4)
 #define MAX9286_REV_AMP(n)             ((((n) - 30) / 10) << 1) /* in mV */
 #define MAX9286_REV_AMP_X              BIT(0)
+#define MAX9286_REV_AMP_HIGH           170
 /* Register 0x3f */
 #define MAX9286_EN_REV_CFG             BIT(6)
 #define MAX9286_REV_FLEN(n)            ((n) - 20)
@@ -163,7 +164,9 @@ struct max9286_priv {
        unsigned int mux_channel;
        bool mux_open;
 
-       u32 reverse_channel_mv;
+       /* The initial reverse control channel amplitude. */
+       u32 init_rev_chan_mv;
+       u32 rev_chan_mv;
 
        struct v4l2_ctrl_handler ctrls;
        struct v4l2_ctrl *pixelrate;
@@ -287,9 +290,8 @@ static int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
 
        priv->mux_channel = chan;
 
-       max9286_i2c_mux_configure(priv,
-                                 MAX9286_FWDCCEN(chan) |
-                                 MAX9286_REVCCEN(chan));
+       max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) |
+                                       MAX9286_REVCCEN(chan));
 
        return 0;
 }
@@ -341,8 +343,15 @@ static void max9286_configure_i2c(struct max9286_priv *priv, bool localack)
 static void max9286_reverse_channel_setup(struct max9286_priv *priv,
                                          unsigned int chan_amplitude)
 {
+       u8 chan_config;
+
+       if (priv->rev_chan_mv == chan_amplitude)
+               return;
+
+       priv->rev_chan_mv = chan_amplitude;
+
        /* Reverse channel transmission time: default to 1. */
-       u8 chan_config = MAX9286_REV_TRF(1);
+       chan_config = MAX9286_REV_TRF(1);
 
        /*
         * Reverse channel setup.
@@ -547,9 +556,9 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
                subdev->name, src_pad, index);
 
        /*
-        * We can only register v4l2_async_notifiers, which do not provide a
-        * means to register a complete callback. bound_sources allows us to
-        * identify when all remote serializers have completed their probe.
+        * As we register a subdev notifiers we won't get a .complete() callback
+        * here, so we have to use bound_sources to identify when all remote
+        * serializers have probed.
         */
        if (priv->bound_sources != priv->source_mask)
                return 0;
@@ -559,19 +568,13 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
         * channels:
         *
         * - Increase the reverse channel amplitude to compensate for the
-        *   remote ends high threshold, if not done already
+        *   remote ends high threshold
         * - Verify all configuration links are properly detected
         * - Disable auto-ack as communication on the control channel are now
         *   stable.
         */
-       if (priv->reverse_channel_mv < 170)
-               max9286_reverse_channel_setup(priv, 170);
+       max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
        max9286_check_config_link(priv, priv->source_mask);
-
-       /*
-        * Re-configure I2C with local acknowledge disabled after cameras have
-        * probed.
-        */
        max9286_configure_i2c(priv, false);
 
        return max9286_set_pixelrate(priv);
@@ -712,7 +715,7 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -725,12 +728,12 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
 
 static struct v4l2_mbus_framefmt *
 max9286_get_pad_format(struct max9286_priv *priv,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &priv->fmt[pad];
        default:
@@ -739,7 +742,7 @@ max9286_get_pad_format(struct max9286_priv *priv,
 }
 
 static int max9286_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct max9286_priv *priv = sd_to_max9286(sd);
@@ -760,7 +763,8 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
                break;
        }
 
-       cfg_fmt = max9286_get_pad_format(priv, cfg, format->pad, format->which);
+       cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
+                                        format->which);
        if (!cfg_fmt)
                return -EINVAL;
 
@@ -772,7 +776,7 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int max9286_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct max9286_priv *priv = sd_to_max9286(sd);
@@ -788,7 +792,7 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
        if (pad == MAX9286_SRC_PAD)
                pad = __ffs(priv->bound_sources);
 
-       cfg_fmt = max9286_get_pad_format(priv, cfg, pad, format->which);
+       cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
        if (!cfg_fmt)
                return -EINVAL;
 
@@ -832,7 +836,7 @@ static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        unsigned int i;
 
        for (i = 0; i < MAX9286_N_SINKS; i++) {
-               format = v4l2_subdev_get_try_format(subdev, fh->pad, i);
+               format = v4l2_subdev_get_try_format(subdev, fh->state, i);
                max9286_init_format(format);
        }
 
@@ -972,7 +976,7 @@ static int max9286_setup(struct max9286_priv *priv)
         * only. This should be disabled after the mux is initialised.
         */
        max9286_configure_i2c(priv, true);
-       max9286_reverse_channel_setup(priv, priv->reverse_channel_mv);
+       max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv);
 
        /*
         * Enable GMSL links, mask unused ones and autodetect link
@@ -1237,9 +1241,9 @@ static int max9286_parse_dt(struct max9286_priv *priv)
        if (of_property_read_u32(dev->of_node,
                                 "maxim,reverse-channel-microvolt",
                                 &reverse_channel_microvolt))
-               priv->reverse_channel_mv = 170;
+               priv->init_rev_chan_mv = 170;
        else
-               priv->reverse_channel_mv = reverse_channel_microvolt / 1000U;
+               priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U;
 
        priv->route_mask = priv->source_mask;
 
index ff21233..4a1410e 100644 (file)
@@ -188,7 +188,7 @@ static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
 }
 
 static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -200,7 +200,7 @@ static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct ml86v7667_priv *priv = to_ml86v7667(sd);
index 3b0ba8e..c9f0bd9 100644 (file)
@@ -217,9 +217,9 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
                goto done;
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0)
-                       goto put_unlock;
+                       goto unlock;
 
                ret = mt9m001_apply_selection(sd);
                if (ret)
@@ -247,13 +247,14 @@ done:
 
 put_unlock:
        pm_runtime_put(&client->dev);
+unlock:
        mutex_unlock(&mt9m001->mutex);
 
        return ret;
 }
 
 static int mt9m001_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -294,7 +295,7 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9m001_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -319,7 +320,7 @@ static int mt9m001_get_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9m001_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -330,7 +331,7 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                format->format = *mf;
                return 0;
        }
@@ -376,7 +377,7 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd,
 }
 
 static int mt9m001_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -410,7 +411,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return mt9m001_s_fmt(sd, fmt, mf);
-       cfg->try_fmt = *mf;
+       sd_state->pads->try_fmt = *mf;
        return 0;
 }
 
@@ -656,12 +657,12 @@ static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
 };
 
 static int mt9m001_init_cfg(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg)
+                           struct v4l2_subdev_state *sd_state)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, cfg, 0);
+               v4l2_subdev_get_try_format(sd, sd_state, 0);
 
        try_fmt->width          = MT9M001_MAX_WIDTH;
        try_fmt->height         = MT9M001_MAX_HEIGHT;
@@ -676,7 +677,7 @@ static int mt9m001_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -834,6 +835,10 @@ static int mt9m001_remove(struct i2c_client *client)
 {
        struct mt9m001 *mt9m001 = to_mt9m001(client);
 
+       /*
+        * As it increments RPM usage_count even on errors, we don't need to
+        * check the returned code here.
+        */
        pm_runtime_get_sync(&client->dev);
 
        v4l2_async_unregister_subdev(&mt9m001->subdev);
index 5a4c0f9..ba0c0ea 100644 (file)
@@ -304,7 +304,7 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
  */
 
 static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index != 0)
@@ -315,7 +315,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8)
@@ -332,18 +332,19 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
 /**
  * __mt9m032_get_pad_crop() - get crop rect
  * @sensor: pointer to the sensor struct
- * @cfg: v4l2_subdev_pad_config for getting the try crop rect from
+ * @sd_state: v4l2_subdev_state for getting the try crop rect from
  * @which: select try or active crop rect
  *
  * Returns a pointer the current active or fh relative try crop rect
  */
 static struct v4l2_rect *
-__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
+__mt9m032_get_pad_crop(struct mt9m032 *sensor,
+                      struct v4l2_subdev_state *sd_state,
                       enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&sensor->subdev, cfg, 0);
+               return v4l2_subdev_get_try_crop(&sensor->subdev, sd_state, 0);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &sensor->crop;
        default:
@@ -354,18 +355,20 @@ __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cf
 /**
  * __mt9m032_get_pad_format() - get format
  * @sensor: pointer to the sensor struct
- * @cfg: v4l2_subdev_pad_config for getting the try format from
+ * @sd_state: v4l2_subdev_state for getting the try format from
  * @which: select try or active format
  *
  * Returns a pointer the current active or fh relative try format
  */
 static struct v4l2_mbus_framefmt *
-__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
+__mt9m032_get_pad_format(struct mt9m032 *sensor,
+                        struct v4l2_subdev_state *sd_state,
                         enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&sensor->subdev, cfg, 0);
+               return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
+                                                 0);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &sensor->format;
        default:
@@ -374,20 +377,20 @@ __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *
 }
 
 static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *fmt)
 {
        struct mt9m032 *sensor = to_mt9m032(subdev);
 
        mutex_lock(&sensor->lock);
-       fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
+       fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
        mutex_unlock(&sensor->lock);
 
        return 0;
 }
 
 static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *fmt)
 {
        struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -401,7 +404,7 @@ static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
        }
 
        /* Scaling is not supported, the format is thus fixed. */
-       fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
+       fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
        ret = 0;
 
 done:
@@ -410,7 +413,7 @@ done:
 }
 
 static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -419,14 +422,14 @@ static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
                return -EINVAL;
 
        mutex_lock(&sensor->lock);
-       sel->r = *__mt9m032_get_pad_crop(sensor, cfg, sel->which);
+       sel->r = *__mt9m032_get_pad_crop(sensor, sd_state, sel->which);
        mutex_unlock(&sensor->lock);
 
        return 0;
 }
 
 static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -462,13 +465,14 @@ static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
        rect.height = min_t(unsigned int, rect.height,
                            MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
 
-       __crop = __mt9m032_get_pad_crop(sensor, cfg, sel->which);
+       __crop = __mt9m032_get_pad_crop(sensor, sd_state, sel->which);
 
        if (rect.width != __crop->width || rect.height != __crop->height) {
                /* Reset the output image size if the crop rectangle size has
                 * been modified.
                 */
-               format = __mt9m032_get_pad_format(sensor, cfg, sel->which);
+               format = __mt9m032_get_pad_format(sensor, sd_state,
+                                                 sel->which);
                format->width = rect.width;
                format->height = rect.height;
        }
index 0e11734..91a4435 100644 (file)
@@ -449,7 +449,7 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
 }
 
 static int mt9m111_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -493,7 +493,7 @@ static int mt9m111_set_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9m111_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -518,7 +518,7 @@ static int mt9m111_get_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9m111_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -529,7 +529,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mf = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                format->format = *mf;
                return 0;
 #else
@@ -624,7 +624,7 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
 }
 
 static int mt9m111_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -678,7 +678,7 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
        mf->xfer_func   = V4L2_XFER_FUNC_DEFAULT;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
+               sd_state->pads->try_fmt = *mf;
                return 0;
        }
 
@@ -1100,7 +1100,7 @@ static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts))
@@ -1119,11 +1119,11 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int mt9m111_init_cfg(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg)
+                           struct v4l2_subdev_state *sd_state)
 {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
        struct v4l2_mbus_framefmt *format =
-               v4l2_subdev_get_try_format(sd, cfg, 0);
+               v4l2_subdev_get_try_format(sd, sd_state, 0);
 
        format->width   = MT9M111_MAX_WIDTH;
        format->height  = MT9M111_MAX_HEIGHT;
index a633b93..6eb88ef 100644 (file)
@@ -470,7 +470,7 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
 }
 
 static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -483,7 +483,7 @@ static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -501,12 +501,14 @@ static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static struct v4l2_mbus_framefmt *
-__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
+__mt9p031_get_pad_format(struct mt9p031 *mt9p031,
+                        struct v4l2_subdev_state *sd_state,
                         unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&mt9p031->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&mt9p031->subdev, sd_state,
+                                                 pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9p031->format;
        default:
@@ -515,12 +517,14 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config
 }
 
 static struct v4l2_rect *
-__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
-                    unsigned int pad, u32 which)
+__mt9p031_get_pad_crop(struct mt9p031 *mt9p031,
+                      struct v4l2_subdev_state *sd_state,
+                      unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&mt9p031->subdev, cfg, pad);
+               return v4l2_subdev_get_try_crop(&mt9p031->subdev, sd_state,
+                                               pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9p031->crop;
        default:
@@ -529,18 +533,18 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *c
 }
 
 static int mt9p031_get_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
 
-       fmt->format = *__mt9p031_get_pad_format(mt9p031, cfg, fmt->pad,
+       fmt->format = *__mt9p031_get_pad_format(mt9p031, sd_state, fmt->pad,
                                                fmt->which);
        return 0;
 }
 
 static int mt9p031_set_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -551,7 +555,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
        unsigned int hratio;
        unsigned int vratio;
 
-       __crop = __mt9p031_get_pad_crop(mt9p031, cfg, format->pad,
+       __crop = __mt9p031_get_pad_crop(mt9p031, sd_state, format->pad,
                                        format->which);
 
        /* Clamp the width and height to avoid dividing by zero. */
@@ -567,7 +571,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
        hratio = DIV_ROUND_CLOSEST(__crop->width, width);
        vratio = DIV_ROUND_CLOSEST(__crop->height, height);
 
-       __format = __mt9p031_get_pad_format(mt9p031, cfg, format->pad,
+       __format = __mt9p031_get_pad_format(mt9p031, sd_state, format->pad,
                                            format->which);
        __format->width = __crop->width / hratio;
        __format->height = __crop->height / vratio;
@@ -578,7 +582,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
 }
 
 static int mt9p031_get_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -586,12 +590,13 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev,
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       sel->r = *__mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
+       sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
+                                        sel->which);
        return 0;
 }
 
 static int mt9p031_set_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -621,13 +626,15 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev,
        rect.height = min_t(unsigned int, rect.height,
                            MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
 
-       __crop = __mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
+       __crop = __mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
+                                       sel->which);
 
        if (rect.width != __crop->width || rect.height != __crop->height) {
                /* Reset the output image size if the crop rectangle size has
                 * been modified.
                 */
-               __format = __mt9p031_get_pad_format(mt9p031, cfg, sel->pad,
+               __format = __mt9p031_get_pad_format(mt9p031, sd_state,
+                                                   sel->pad,
                                                    sel->which);
                __format->width = rect.width;
                __format->height = rect.height;
@@ -942,13 +949,13 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+       crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
        crop->left = MT9P031_COLUMN_START_DEF;
        crop->top = MT9P031_ROW_START_DEF;
        crop->width = MT9P031_WINDOW_WIDTH_DEF;
        crop->height = MT9P031_WINDOW_HEIGHT_DEF;
 
-       format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+       format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
 
        if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
                format->code = MEDIA_BUS_FMT_Y12_1X12;
index 2e96ff5..b651ee4 100644 (file)
@@ -252,12 +252,14 @@ e_power:
  */
 
 static struct v4l2_mbus_framefmt *
-__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
+__mt9t001_get_pad_format(struct mt9t001 *mt9t001,
+                        struct v4l2_subdev_state *sd_state,
                         unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&mt9t001->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&mt9t001->subdev, sd_state,
+                                                 pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9t001->format;
        default:
@@ -266,12 +268,14 @@ __mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config
 }
 
 static struct v4l2_rect *
-__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
+__mt9t001_get_pad_crop(struct mt9t001 *mt9t001,
+                      struct v4l2_subdev_state *sd_state,
                       unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&mt9t001->subdev, cfg, pad);
+               return v4l2_subdev_get_try_crop(&mt9t001->subdev, sd_state,
+                                               pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9t001->crop;
        default:
@@ -335,7 +339,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
 }
 
 static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -346,7 +350,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -361,18 +365,19 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int mt9t001_get_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9t001 *mt9t001 = to_mt9t001(subdev);
 
-       format->format = *__mt9t001_get_pad_format(mt9t001, cfg, format->pad,
+       format->format = *__mt9t001_get_pad_format(mt9t001, sd_state,
+                                                  format->pad,
                                                   format->which);
        return 0;
 }
 
 static int mt9t001_set_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -383,7 +388,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
        unsigned int hratio;
        unsigned int vratio;
 
-       __crop = __mt9t001_get_pad_crop(mt9t001, cfg, format->pad,
+       __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, format->pad,
                                        format->which);
 
        /* Clamp the width and height to avoid dividing by zero. */
@@ -399,7 +404,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
        hratio = DIV_ROUND_CLOSEST(__crop->width, width);
        vratio = DIV_ROUND_CLOSEST(__crop->height, height);
 
-       __format = __mt9t001_get_pad_format(mt9t001, cfg, format->pad,
+       __format = __mt9t001_get_pad_format(mt9t001, sd_state, format->pad,
                                            format->which);
        __format->width = __crop->width / hratio;
        __format->height = __crop->height / vratio;
@@ -410,7 +415,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
 }
 
 static int mt9t001_get_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -418,12 +423,13 @@ static int mt9t001_get_selection(struct v4l2_subdev *subdev,
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       sel->r = *__mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
+       sel->r = *__mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
+                                        sel->which);
        return 0;
 }
 
 static int mt9t001_set_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -455,13 +461,15 @@ static int mt9t001_set_selection(struct v4l2_subdev *subdev,
        rect.height = min_t(unsigned int, rect.height,
                            MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
 
-       __crop = __mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
+       __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
+                                       sel->which);
 
        if (rect.width != __crop->width || rect.height != __crop->height) {
                /* Reset the output image size if the crop rectangle size has
                 * been modified.
                 */
-               __format = __mt9t001_get_pad_format(mt9t001, cfg, sel->pad,
+               __format = __mt9t001_get_pad_format(mt9t001, sd_state,
+                                                   sel->pad,
                                                    sel->which);
                __format->width = rect.width;
                __format->height = rect.height;
@@ -798,13 +806,13 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+       crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
        crop->left = MT9T001_COLUMN_START_DEF;
        crop->top = MT9T001_ROW_START_DEF;
        crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
        crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
 
-       format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+       format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
        format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
        format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
index ae3c336..8d2e3ca 100644 (file)
@@ -872,8 +872,8 @@ static int mt9t112_set_params(struct mt9t112_priv *priv,
 }
 
 static int mt9t112_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
+                                struct v4l2_subdev_state *sd_state,
+                                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t112_priv *priv = to_mt9t112(client);
@@ -897,7 +897,7 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9t112_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -912,7 +912,7 @@ static int mt9t112_set_selection(struct v4l2_subdev *sd,
 }
 
 static int mt9t112_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -953,7 +953,7 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd,
 }
 
 static int mt9t112_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -982,13 +982,13 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return mt9t112_s_fmt(sd, mf);
-       cfg->try_fmt = *mf;
+       sd_state->pads->try_fmt = *mf;
 
        return 0;
 }
 
 static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
index 46ef74a..7699e64 100644 (file)
@@ -327,7 +327,7 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
 }
 
 static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -338,7 +338,7 @@ static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int mt9v011_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -358,7 +358,7 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
 
                set_res(sd);
        } else {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
        }
 
        return 0;
index 5bd3ae8..4cfdd3d 100644 (file)
@@ -349,12 +349,14 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
  */
 
 static struct v4l2_mbus_framefmt *
-__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032,
+                        struct v4l2_subdev_state *sd_state,
                         unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&mt9v032->subdev, sd_state,
+                                                 pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9v032->format;
        default:
@@ -363,12 +365,14 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config
 }
 
 static struct v4l2_rect *
-__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032,
+                      struct v4l2_subdev_state *sd_state,
                       unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad);
+               return v4l2_subdev_get_try_crop(&mt9v032->subdev, sd_state,
+                                               pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9v032->crop;
        default:
@@ -425,7 +429,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
 }
 
 static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -438,7 +442,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -457,12 +461,13 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int mt9v032_get_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
 
-       format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad,
+       format->format = *__mt9v032_get_pad_format(mt9v032, sd_state,
+                                                  format->pad,
                                                   format->which);
        return 0;
 }
@@ -492,7 +497,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
 }
 
 static int mt9v032_set_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -503,7 +508,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
        unsigned int hratio;
        unsigned int vratio;
 
-       __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad,
+       __crop = __mt9v032_get_pad_crop(mt9v032, sd_state, format->pad,
                                        format->which);
 
        /* Clamp the width and height to avoid dividing by zero. */
@@ -519,7 +524,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
        hratio = mt9v032_calc_ratio(__crop->width, width);
        vratio = mt9v032_calc_ratio(__crop->height, height);
 
-       __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad,
+       __format = __mt9v032_get_pad_format(mt9v032, sd_state, format->pad,
                                            format->which);
        __format->width = __crop->width / hratio;
        __format->height = __crop->height / vratio;
@@ -536,7 +541,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
 }
 
 static int mt9v032_get_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -544,12 +549,13 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev,
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
+       sel->r = *__mt9v032_get_pad_crop(mt9v032, sd_state, sel->pad,
+                                        sel->which);
        return 0;
 }
 
 static int mt9v032_set_selection(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -581,13 +587,15 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,
        rect.height = min_t(unsigned int,
                            rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
 
-       __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
+       __crop = __mt9v032_get_pad_crop(mt9v032, sd_state, sel->pad,
+                                       sel->which);
 
        if (rect.width != __crop->width || rect.height != __crop->height) {
                /* Reset the output image size if the crop rectangle size has
                 * been modified.
                 */
-               __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad,
+               __format = __mt9v032_get_pad_format(mt9v032, sd_state,
+                                                   sel->pad,
                                                    sel->which);
                __format->width = rect.width;
                __format->height = rect.height;
@@ -922,13 +930,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+       crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
        crop->left = MT9V032_COLUMN_START_DEF;
        crop->top = MT9V032_ROW_START_DEF;
        crop->width = MT9V032_WINDOW_WIDTH_DEF;
        crop->height = MT9V032_WINDOW_HEIGHT_DEF;
 
-       format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+       format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
 
        if (mt9v032->model->color)
                format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
index 97c7527..2dc4a0f 100644 (file)
@@ -791,16 +791,16 @@ static int mt9v111_g_frame_interval(struct v4l2_subdev *sd,
 
 static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format(
                                        struct mt9v111_dev *mt9v111,
-                                       struct v4l2_subdev_pad_config *cfg,
+                                       struct v4l2_subdev_state *sd_state,
                                        unsigned int pad,
                                        enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
 #if IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API)
-               return v4l2_subdev_get_try_format(&mt9v111->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad);
 #else
-               return &cfg->try_fmt;
+               return &sd_state->pads->try_fmt;
 #endif
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &mt9v111->fmt;
@@ -810,7 +810,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format(
 }
 
 static int mt9v111_enum_mbus_code(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > ARRAY_SIZE(mt9v111_formats) - 1)
@@ -822,7 +822,7 @@ static int mt9v111_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int mt9v111_enum_frame_interval(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_interval_enum *fie)
 {
        unsigned int i;
@@ -845,7 +845,7 @@ static int mt9v111_enum_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int mt9v111_enum_frame_size(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->pad || fse->index >= ARRAY_SIZE(mt9v111_frame_sizes))
@@ -860,7 +860,7 @@ static int mt9v111_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int mt9v111_get_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9v111_dev *mt9v111 = sd_to_mt9v111(subdev);
@@ -869,7 +869,8 @@ static int mt9v111_get_format(struct v4l2_subdev *subdev,
                return -EINVAL;
 
        mutex_lock(&mt9v111->stream_mutex);
-       format->format = *__mt9v111_get_pad_format(mt9v111, cfg, format->pad,
+       format->format = *__mt9v111_get_pad_format(mt9v111, sd_state,
+                                                  format->pad,
                                                   format->which);
        mutex_unlock(&mt9v111->stream_mutex);
 
@@ -877,7 +878,7 @@ static int mt9v111_get_format(struct v4l2_subdev *subdev,
 }
 
 static int mt9v111_set_format(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct mt9v111_dev *mt9v111 = sd_to_mt9v111(subdev);
@@ -925,7 +926,7 @@ static int mt9v111_set_format(struct v4l2_subdev *subdev,
        new_fmt.height = mt9v111_frame_sizes[idx].height;
 
        /* Update the device (or pad) format if it has changed. */
-       __fmt = __mt9v111_get_pad_format(mt9v111, cfg, format->pad,
+       __fmt = __mt9v111_get_pad_format(mt9v111, sd_state, format->pad,
                                         format->which);
 
        /* Format hasn't changed, stop here. */
@@ -954,9 +955,9 @@ done:
 }
 
 static int mt9v111_init_cfg(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg)
+                           struct v4l2_subdev_state *sd_state)
 {
-       cfg->try_fmt = mt9v111_def_fmt;
+       sd_state->pads->try_fmt = mt9v111_def_fmt;
 
        return 0;
 }
index 87d76a7..f3ac379 100644 (file)
@@ -488,7 +488,7 @@ unlock:
 }
 
 static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(noon010_formats))
@@ -499,15 +499,15 @@ static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int noon010_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct noon010_info *info = to_noon010(sd);
        struct v4l2_mbus_framefmt *mf;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               if (cfg) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               if (sd_state) {
+                       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                        fmt->format = *mf;
                }
                return 0;
@@ -539,7 +539,8 @@ static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
        return &noon010_formats[i];
 }
 
-static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int noon010_set_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct noon010_info *info = to_noon010(sd);
@@ -554,8 +555,8 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        fmt->format.field = V4L2_FIELD_NONE;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               if (cfg) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               if (sd_state) {
+                       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                        *mf = fmt->format;
                }
                return 0;
@@ -637,7 +638,9 @@ static int noon010_log_status(struct v4l2_subdev *sd)
 
 static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
+                                                                  fh->state,
+                                                                  0);
 
        mf->width = noon010_sizes[0].width;
        mf->height = noon010_sizes[0].height;
index c47b1d4..a3ce550 100644 (file)
@@ -295,7 +295,7 @@ static void ov02a10_fill_fmt(const struct ov02a10_mode *mode,
 }
 
 static int ov02a10_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -315,7 +315,7 @@ static int ov02a10_set_fmt(struct v4l2_subdev *sd,
        ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               frame_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
        else
                frame_fmt = &ov02a10->fmt;
 
@@ -327,7 +327,7 @@ out_unlock:
 }
 
 static int ov02a10_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -336,7 +336,8 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&ov02a10->mutex);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+                                                         fmt->pad);
        } else {
                fmt->format = ov02a10->fmt;
                mbus_fmt->code = ov02a10->fmt.code;
@@ -349,7 +350,7 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -363,7 +364,7 @@ static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -511,7 +512,7 @@ static int __ov02a10_stop_stream(struct ov02a10 *ov02a10)
 }
 
 static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg)
+                                  struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
@@ -521,7 +522,7 @@ static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd,
                }
        };
 
-       ov02a10_set_fmt(sd, cfg, &fmt);
+       ov02a10_set_fmt(sd, sd_state, &fmt);
 
        return 0;
 }
@@ -540,11 +541,9 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on)
        }
 
        if (on) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto unlock_and_return;
-               }
 
                ret = __ov02a10_start_stream(ov02a10);
                if (ret) {
index 4a2885f..7fc70af 100644 (file)
@@ -1150,7 +1150,7 @@ static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct ov13858 *ov13858 = to_ov13858(sd);
        struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
-                                                                       fh->pad,
+                                                                       fh->state,
                                                                        0);
 
        mutex_lock(&ov13858->mutex);
@@ -1275,7 +1275,7 @@ static const struct v4l2_ctrl_ops ov13858_ctrl_ops = {
 };
 
 static int ov13858_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        /* Only one bayer order(GRBG) is supported */
@@ -1288,7 +1288,7 @@ static int ov13858_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov13858_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -1315,14 +1315,14 @@ static void ov13858_update_pad_format(const struct ov13858_mode *mode,
 }
 
 static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *framefmt;
        struct v4l2_subdev *sd = &ov13858->sd;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *framefmt;
        } else {
                ov13858_update_pad_format(ov13858->cur_mode, fmt);
@@ -1332,14 +1332,14 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
 }
 
 static int ov13858_get_pad_format(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *fmt)
 {
        struct ov13858 *ov13858 = to_ov13858(sd);
        int ret;
 
        mutex_lock(&ov13858->mutex);
-       ret = ov13858_do_get_pad_format(ov13858, cfg, fmt);
+       ret = ov13858_do_get_pad_format(ov13858, sd_state, fmt);
        mutex_unlock(&ov13858->mutex);
 
        return ret;
@@ -1347,7 +1347,7 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd,
 
 static int
 ov13858_set_pad_format(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *fmt)
 {
        struct ov13858 *ov13858 = to_ov13858(sd);
@@ -1371,7 +1371,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
        ov13858_update_pad_format(mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *framefmt = fmt->format;
        } else {
                ov13858->cur_mode = mode;
@@ -1472,11 +1472,9 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto err_unlock;
-               }
 
                /*
                 * Apply default & customized values
index 4a4bd5b..4b75da5 100644 (file)
@@ -913,7 +913,7 @@ err:
 }
 
 static int ov2640_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -925,7 +925,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                format->format = *mf;
                return 0;
 #else
@@ -946,7 +946,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov2640_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -996,7 +996,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd,
                /* select format */
                priv->cfmt_code = mf->code;
        } else {
-               cfg->try_fmt = *mf;
+               sd_state->pads->try_fmt = *mf;
        }
 out:
        mutex_unlock(&priv->lock);
@@ -1005,11 +1005,11 @@ out:
 }
 
 static int ov2640_init_cfg(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg)
+                          struct v4l2_subdev_state *sd_state)
 {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
        struct v4l2_mbus_framefmt *try_fmt =
-               v4l2_subdev_get_try_format(sd, cfg, 0);
+               v4l2_subdev_get_try_format(sd, sd_state, 0);
        const struct ov2640_win_size *win =
                ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT);
 
@@ -1026,7 +1026,7 @@ static int ov2640_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes))
@@ -1037,7 +1037,7 @@ static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2640_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
index 42f6417..13ded5b 100644 (file)
@@ -204,6 +204,7 @@ struct ov2659 {
        struct i2c_client *client;
        struct v4l2_ctrl_handler ctrls;
        struct v4l2_ctrl *link_frequency;
+       struct clk *clk;
        const struct ov2659_framesize *frame_size;
        struct sensor_register *format_ctrl_regs;
        struct ov2659_pll_ctrl pll;
@@ -979,7 +980,7 @@ static int ov2659_init(struct v4l2_subdev *sd, u32 val)
  */
 
 static int ov2659_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -995,7 +996,7 @@ static int ov2659_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1021,7 +1022,7 @@ static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd,
 }
 
 static int ov2659_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1033,7 +1034,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd,
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
                struct v4l2_mbus_framefmt *mf;
 
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                mutex_lock(&ov2659->lock);
                fmt->format = *mf;
                mutex_unlock(&ov2659->lock);
@@ -1083,7 +1084,7 @@ static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf,
 }
 
 static int ov2659_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1113,7 +1114,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd,
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
 #endif
        } else {
@@ -1186,11 +1187,9 @@ static int ov2659_s_stream(struct v4l2_subdev *sd, int on)
                goto unlock;
        }
 
-       ret = pm_runtime_get_sync(&client->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&client->dev);
+       ret = pm_runtime_resume_and_get(&client->dev);
+       if (ret < 0)
                goto unlock;
-       }
 
        ret = ov2659_init(sd, 0);
        if (!ret)
@@ -1270,6 +1269,8 @@ static int ov2659_power_off(struct device *dev)
 
        gpiod_set_value(ov2659->pwdn_gpio, 1);
 
+       clk_disable_unprepare(ov2659->clk);
+
        return 0;
 }
 
@@ -1278,9 +1279,17 @@ static int ov2659_power_on(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct ov2659 *ov2659 = to_ov2659(sd);
+       int ret;
 
        dev_dbg(&client->dev, "%s:\n", __func__);
 
+       ret = clk_prepare_enable(ov2659->clk);
+       if (ret) {
+               dev_err(&client->dev, "%s: failed to enable clock\n",
+                       __func__);
+               return ret;
+       }
+
        gpiod_set_value(ov2659->pwdn_gpio, 0);
 
        if (ov2659->resetb_gpio) {
@@ -1302,7 +1311,7 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        dev_dbg(&client->dev, "%s:\n", __func__);
 
@@ -1368,8 +1377,7 @@ static int ov2659_detect(struct v4l2_subdev *sd)
                id = OV265X_ID(pid, ver);
                if (id != OV2659_ID) {
                        dev_err(&client->dev,
-                               "Sensor detection failed (%04X, %d)\n",
-                               id, ret);
+                               "Sensor detection failed (%04X)\n", id);
                        ret = -ENODEV;
                } else {
                        dev_info(&client->dev, "Found OV%04X sensor\n", id);
@@ -1425,7 +1433,6 @@ static int ov2659_probe(struct i2c_client *client)
        const struct ov2659_platform_data *pdata = ov2659_get_pdata(client);
        struct v4l2_subdev *sd;
        struct ov2659 *ov2659;
-       struct clk *clk;
        int ret;
 
        if (!pdata) {
@@ -1440,11 +1447,11 @@ static int ov2659_probe(struct i2c_client *client)
        ov2659->pdata = pdata;
        ov2659->client = client;
 
-       clk = devm_clk_get(&client->dev, "xvclk");
-       if (IS_ERR(clk))
-               return PTR_ERR(clk);
+       ov2659->clk = devm_clk_get(&client->dev, "xvclk");
+       if (IS_ERR(ov2659->clk))
+               return PTR_ERR(ov2659->clk);
 
-       ov2659->xvclk_frequency = clk_get_rate(clk);
+       ov2659->xvclk_frequency = clk_get_rate(ov2659->clk);
        if (ov2659->xvclk_frequency < 6000000 ||
            ov2659->xvclk_frequency > 27000000)
                return -EINVAL;
@@ -1506,7 +1513,9 @@ static int ov2659_probe(struct i2c_client *client)
        ov2659->frame_size = &ov2659_framesizes[2];
        ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs;
 
-       ov2659_power_on(&client->dev);
+       ret = ov2659_power_on(&client->dev);
+       if (ret < 0)
+               goto error;
 
        ret = ov2659_detect(sd);
        if (ret < 0)
index 178dfe9..906c711 100644 (file)
@@ -645,7 +645,7 @@ unlock:
 }
 
 static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -659,7 +659,7 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2680_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -673,7 +673,8 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
+                                                format->pad);
 #else
                ret = -EINVAL;
 #endif
@@ -690,7 +691,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov2680_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -721,7 +722,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               try_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
                format->format = *try_fmt;
 #endif
                goto unlock;
@@ -743,22 +744,22 @@ unlock:
 }
 
 static int ov2680_init_cfg(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg)
+                          struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = {
-               .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
-                               : V4L2_SUBDEV_FORMAT_ACTIVE,
+               .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+               : V4L2_SUBDEV_FORMAT_ACTIVE,
                .format = {
                        .width = 800,
                        .height = 600,
                }
        };
 
-       return ov2680_set_fmt(sd, cfg, &fmt);
+       return ov2680_set_fmt(sd, sd_state, &fmt);
 }
 
 static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
@@ -775,7 +776,7 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int ov2680_enum_frame_interval(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct v4l2_fract tpf;
index 49a2dce..b6e010e 100644 (file)
@@ -328,7 +328,7 @@ static void ov2685_fill_fmt(const struct ov2685_mode *mode,
 }
 
 static int ov2685_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ov2685 *ov2685 = to_ov2685(sd);
@@ -341,7 +341,7 @@ static int ov2685_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov2685_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ov2685 *ov2685 = to_ov2685(sd);
@@ -353,7 +353,7 @@ static int ov2685_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(supported_modes))
@@ -365,7 +365,7 @@ static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
@@ -456,11 +456,10 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
                goto unlock_and_return;
 
        if (on) {
-               ret = pm_runtime_get_sync(&ov2685->client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&ov2685->client->dev);
+               if (ret < 0)
                        goto unlock_and_return;
-               }
+
                ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
                if (ret) {
                        pm_runtime_put(&client->dev);
@@ -494,7 +493,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&ov2685->mutex);
 
-       try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
        /* Initialize try_fmt */
        ov2685_fill_fmt(&supported_modes[0], try_fmt);
 
index 0f3f17f..599369a 100644 (file)
@@ -751,9 +751,8 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable)
 
        mutex_lock(&ov2740->mutex);
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
                        mutex_unlock(&ov2740->mutex);
                        return ret;
                }
@@ -811,7 +810,7 @@ exit:
 }
 
 static int ov2740_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov2740 *ov2740 = to_ov2740(sd);
@@ -826,7 +825,7 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
        mutex_lock(&ov2740->mutex);
        ov2740_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov2740->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index);
@@ -851,14 +850,15 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov2740_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov2740 *ov2740 = to_ov2740(sd);
 
        mutex_lock(&ov2740->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                ov2740_update_pad_format(ov2740->cur_mode, &fmt->format);
@@ -869,7 +869,7 @@ static int ov2740_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov2740_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -881,7 +881,7 @@ static int ov2740_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2740_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -904,7 +904,7 @@ static int ov2740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&ov2740->mutex);
        ov2740_update_pad_format(&supported_modes[0],
-                                v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                                v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&ov2740->mutex);
 
        return 0;
@@ -1049,9 +1049,8 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
                goto exit;
        }
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
-               pm_runtime_put_noidle(dev);
                goto exit;
        }
 
index 5b9cc71..f6e1e51 100644 (file)
@@ -2227,7 +2227,7 @@ find_mode:
 }
 
 static int ov5640_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2239,7 +2239,7 @@ static int ov5640_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&sensor->lock);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg,
+               fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
                                                 format->pad);
        else
                fmt = &sensor->fmt;
@@ -2285,7 +2285,7 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
 }
 
 static int ov5640_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2310,7 +2310,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
                goto out;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
        else
                fmt = &sensor->fmt;
 
@@ -2818,7 +2818,7 @@ free_ctrls:
 }
 
 static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->pad != 0)
@@ -2838,7 +2838,7 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
 
 static int ov5640_enum_frame_interval(
        struct v4l2_subdev *sd,
-       struct v4l2_subdev_pad_config *cfg,
+       struct v4l2_subdev_state *sd_state,
        struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2924,7 +2924,7 @@ out:
 }
 
 static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad != 0)
index a6c17d1..368fa21 100644 (file)
@@ -837,7 +837,7 @@ static const struct v4l2_ctrl_ops ov5645_ctrl_ops = {
 };
 
 static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -849,7 +849,7 @@ static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
@@ -868,13 +868,13 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
 
 static struct v4l2_mbus_framefmt *
 __ov5645_get_pad_format(struct ov5645 *ov5645,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad,
                        enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&ov5645->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&ov5645->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &ov5645->fmt;
        default:
@@ -883,23 +883,25 @@ __ov5645_get_pad_format(struct ov5645 *ov5645,
 }
 
 static int ov5645_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct ov5645 *ov5645 = to_ov5645(sd);
 
-       format->format = *__ov5645_get_pad_format(ov5645, cfg, format->pad,
+       format->format = *__ov5645_get_pad_format(ov5645, sd_state,
+                                                 format->pad,
                                                  format->which);
        return 0;
 }
 
 static struct v4l2_rect *
-__ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
+__ov5645_get_pad_crop(struct ov5645 *ov5645,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&ov5645->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&ov5645->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &ov5645->crop;
        default:
@@ -908,7 +910,7 @@ __ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
 }
 
 static int ov5645_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct ov5645 *ov5645 = to_ov5645(sd);
@@ -917,8 +919,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
        const struct ov5645_mode_info *new_mode;
        int ret;
 
-       __crop = __ov5645_get_pad_crop(ov5645, cfg, format->pad,
-                       format->which);
+       __crop = __ov5645_get_pad_crop(ov5645, sd_state, format->pad,
+                                      format->which);
 
        new_mode = v4l2_find_nearest_size(ov5645_mode_info_data,
                               ARRAY_SIZE(ov5645_mode_info_data),
@@ -942,8 +944,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
                ov5645->current_mode = new_mode;
        }
 
-       __format = __ov5645_get_pad_format(ov5645, cfg, format->pad,
-                       format->which);
+       __format = __ov5645_get_pad_format(ov5645, sd_state, format->pad,
+                                          format->which);
        __format->width = __crop->width;
        __format->height = __crop->height;
        __format->code = MEDIA_BUS_FMT_UYVY8_2X8;
@@ -956,21 +958,21 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = { 0 };
 
-       fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
        fmt.format.width = 1920;
        fmt.format.height = 1080;
 
-       ov5645_set_format(subdev, cfg, &fmt);
+       ov5645_set_format(subdev, sd_state, &fmt);
 
        return 0;
 }
 
 static int ov5645_get_selection(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_selection *sel)
 {
        struct ov5645 *ov5645 = to_ov5645(sd);
@@ -978,7 +980,7 @@ static int ov5645_get_selection(struct v4l2_subdev *sd,
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
-       sel->r = *__ov5645_get_pad_crop(ov5645, cfg, sel->pad,
+       sel->r = *__ov5645_get_pad_crop(ov5645, sd_state, sel->pad,
                                        sel->which);
        return 0;
 }
index 1cefa15..d346d18 100644 (file)
@@ -856,12 +856,13 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 };
 
 static const struct v4l2_rect *
-__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
+__ov5647_get_pad_crop(struct ov5647 *ov5647,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&ov5647->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &ov5647->mode->crop;
        }
@@ -882,20 +883,20 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0)
                        goto error_unlock;
 
                ret = ov5647_stream_on(sd);
                if (ret < 0) {
                        dev_err(&client->dev, "stream start failed: %d\n", ret);
-                       goto error_unlock;
+                       goto error_pm;
                }
        } else {
                ret = ov5647_stream_off(sd);
                if (ret < 0) {
                        dev_err(&client->dev, "stream stop failed: %d\n", ret);
-                       goto error_unlock;
+                       goto error_pm;
                }
                pm_runtime_put(&client->dev);
        }
@@ -905,8 +906,9 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 
        return 0;
 
-error_unlock:
+error_pm:
        pm_runtime_put(&client->dev);
+error_unlock:
        mutex_unlock(&sensor->lock);
 
        return ret;
@@ -917,7 +919,7 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
 };
 
 static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -929,7 +931,7 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        const struct v4l2_mbus_framefmt *fmt;
@@ -948,7 +950,7 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -958,7 +960,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
        mutex_lock(&sensor->lock);
        switch (format->which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               sensor_format = v4l2_subdev_get_try_format(sd, sd_state,
+                                                          format->pad);
                break;
        default:
                sensor_format = &sensor->mode->format;
@@ -972,7 +975,7 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -986,7 +989,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
        /* Update the sensor mode and apply at it at streamon time. */
        mutex_lock(&sensor->lock);
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = mode->format;
        } else {
                int exposure_max, exposure_def;
                int hblank, vblank;
@@ -1019,7 +1022,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov5647_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        switch (sel->target) {
@@ -1027,7 +1030,7 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
                struct ov5647 *sensor = to_sensor(sd);
 
                mutex_lock(&sensor->lock);
-               sel->r = *__ov5647_get_pad_crop(sensor, cfg, sel->pad,
+               sel->r = *__ov5647_get_pad_crop(sensor, sd_state, sel->pad,
                                                sel->which);
                mutex_unlock(&sensor->lock);
 
@@ -1103,8 +1106,8 @@ static int ov5647_detect(struct v4l2_subdev *sd)
 static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *format =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
-       struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
+       struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
 
        crop->left = OV5647_PIXEL_ARRAY_LEFT;
        crop->top = OV5647_PIXEL_ARRAY_TOP;
index 3ecb4a3..947d437 100644 (file)
@@ -2132,11 +2132,9 @@ static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
        int ret;
 
        if (enable) {
-               ret = pm_runtime_get_sync(sensor->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(sensor->dev);
+               ret = pm_runtime_resume_and_get(sensor->dev);
+               if (ret < 0)
                        return ret;
-               }
        }
 
        mutex_lock(&sensor->mutex);
@@ -2190,7 +2188,7 @@ static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
 /* Subdev Pad Operations */
 
 static int ov5648_enum_mbus_code(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *config,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code_enum)
 {
        if (code_enum->index >= ARRAY_SIZE(ov5648_mbus_codes))
@@ -2219,7 +2217,7 @@ static void ov5648_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format,
 }
 
 static int ov5648_get_fmt(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *config,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
@@ -2228,7 +2226,7 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev,
        mutex_lock(&sensor->mutex);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               *mbus_format = *v4l2_subdev_get_try_format(subdev, config,
+               *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
                                                           format->pad);
        else
                ov5648_mbus_format_fill(mbus_format, sensor->state.mbus_code,
@@ -2240,7 +2238,7 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev,
 }
 
 static int ov5648_set_fmt(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *config,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
@@ -2281,7 +2279,7 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev,
        ov5648_mbus_format_fill(mbus_format, mbus_code, mode);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               *v4l2_subdev_get_try_format(subdev, config, format->pad) =
+               *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
                        *mbus_format;
        else if (sensor->state.mode != mode ||
                 sensor->state.mbus_code != mbus_code)
@@ -2294,7 +2292,7 @@ complete:
 }
 
 static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *config,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *size_enum)
 {
        const struct ov5648_mode *mode;
@@ -2311,7 +2309,7 @@ static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int ov5648_enum_frame_interval(struct v4l2_subdev *subdev,
-                                     struct v4l2_subdev_pad_config *config,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_interval_enum *interval_enum)
 {
        const struct ov5648_mode *mode = NULL;
index dee7df8..4918992 100644 (file)
@@ -1937,7 +1937,7 @@ static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct ov5670 *ov5670 = to_ov5670(sd);
        struct v4l2_mbus_framefmt *try_fmt =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        mutex_lock(&ov5670->mutex);
 
@@ -2153,7 +2153,7 @@ error:
 }
 
 static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        /* Only one bayer order GRBG is supported */
@@ -2166,7 +2166,7 @@ static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5670_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -2193,11 +2193,12 @@ static void ov5670_update_pad_format(const struct ov5670_mode *mode,
 }
 
 static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                ov5670_update_pad_format(ov5670->cur_mode, fmt);
@@ -2206,21 +2207,21 @@ static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
 }
 
 static int ov5670_get_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct ov5670 *ov5670 = to_ov5670(sd);
        int ret;
 
        mutex_lock(&ov5670->mutex);
-       ret = ov5670_do_get_pad_format(ov5670, cfg, fmt);
+       ret = ov5670_do_get_pad_format(ov5670, sd_state, fmt);
        mutex_unlock(&ov5670->mutex);
 
        return ret;
 }
 
 static int ov5670_set_pad_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct ov5670 *ov5670 = to_ov5670(sd);
@@ -2238,7 +2239,7 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
                                      fmt->format.width, fmt->format.height);
        ov5670_update_pad_format(mode, fmt);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov5670->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index);
@@ -2347,11 +2348,9 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable)
                goto unlock_and_return;
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto unlock_and_return;
-               }
 
                ret = ov5670_start_streaming(ov5670);
                if (ret)
index dea3285..da5850b 100644 (file)
@@ -863,9 +863,8 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable)
 
        mutex_lock(&ov5675->mutex);
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
                        mutex_unlock(&ov5675->mutex);
                        return ret;
                }
@@ -924,7 +923,7 @@ static int __maybe_unused ov5675_resume(struct device *dev)
 }
 
 static int ov5675_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov5675 *ov5675 = to_ov5675(sd);
@@ -939,7 +938,7 @@ static int ov5675_set_format(struct v4l2_subdev *sd,
        mutex_lock(&ov5675->mutex);
        ov5675_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov5675->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index);
@@ -965,14 +964,15 @@ static int ov5675_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov5675_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov5675 *ov5675 = to_ov5675(sd);
 
        mutex_lock(&ov5675->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                ov5675_update_pad_format(ov5675->cur_mode, &fmt->format);
@@ -983,7 +983,7 @@ static int ov5675_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -995,7 +995,7 @@ static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5675_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -1018,7 +1018,7 @@ static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&ov5675->mutex);
        ov5675_update_pad_format(&supported_modes[0],
-                                v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                                v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&ov5675->mutex);
 
        return 0;
index 09bee57..4393859 100644 (file)
@@ -806,7 +806,7 @@ ov5695_find_best_fit(struct v4l2_subdev_format *fmt)
 }
 
 static int ov5695_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ov5695 *ov5695 = to_ov5695(sd);
@@ -822,7 +822,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd,
        fmt->format.field = V4L2_FIELD_NONE;
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
 #endif
        } else {
                ov5695->cur_mode = mode;
@@ -841,7 +841,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov5695_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ov5695 *ov5695 = to_ov5695(sd);
@@ -850,7 +850,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&ov5695->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+                                                         fmt->pad);
 #else
                mutex_unlock(&ov5695->mutex);
                return -EINVAL;
@@ -867,7 +868,7 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index != 0)
@@ -878,7 +879,7 @@ static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -946,11 +947,9 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on)
                goto unlock_and_return;
 
        if (on) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto unlock_and_return;
-               }
 
                ret = __ov5695_start_stream(ov5695);
                if (ret) {
@@ -1054,7 +1053,7 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct ov5695 *ov5695 = to_ov5695(sd);
        struct v4l2_mbus_framefmt *try_fmt =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
        const struct ov5695_mode *def_mode = &supported_modes[0];
 
        mutex_lock(&ov5695->mutex);
index 85dd136..f674121 100644 (file)
@@ -467,7 +467,7 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
 }
 
 static int ov6650_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -492,7 +492,7 @@ static int ov6650_get_selection(struct v4l2_subdev *sd,
 }
 
 static int ov6650_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -535,7 +535,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
 }
 
 static int ov6650_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -550,9 +550,9 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
 
        /* update media bus format code and frame size */
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf->width = cfg->try_fmt.width;
-               mf->height = cfg->try_fmt.height;
-               mf->code = cfg->try_fmt.code;
+               mf->width = sd_state->pads->try_fmt.width;
+               mf->height = sd_state->pads->try_fmt.height;
+               mf->code = sd_state->pads->try_fmt.code;
 
        } else {
                mf->width = priv->rect.width >> priv->half_scale;
@@ -668,7 +668,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 }
 
 static int ov6650_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -701,15 +701,15 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                /* store media bus format code and frame size in pad config */
-               cfg->try_fmt.width = mf->width;
-               cfg->try_fmt.height = mf->height;
-               cfg->try_fmt.code = mf->code;
+               sd_state->pads->try_fmt.width = mf->width;
+               sd_state->pads->try_fmt.height = mf->height;
+               sd_state->pads->try_fmt.code = mf->code;
 
                /* return default mbus frame format updated with pad config */
                *mf = ov6650_def_fmt;
-               mf->width = cfg->try_fmt.width;
-               mf->height = cfg->try_fmt.height;
-               mf->code = cfg->try_fmt.code;
+               mf->width = sd_state->pads->try_fmt.width;
+               mf->height = sd_state->pads->try_fmt.height;
+               mf->code = sd_state->pads->try_fmt.code;
 
        } else {
                /* apply new media bus format code and frame size */
@@ -728,7 +728,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov6650_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes))
index 0c10203..ebb299f 100644 (file)
@@ -898,7 +898,7 @@ static const struct v4l2_ctrl_ops ov7251_ctrl_ops = {
 };
 
 static int ov7251_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -910,7 +910,7 @@ static int ov7251_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov7251_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->code != MEDIA_BUS_FMT_Y10_1X10)
@@ -928,7 +928,7 @@ static int ov7251_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int ov7251_enum_frame_ival(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_interval_enum *fie)
 {
        unsigned int index = fie->index;
@@ -950,13 +950,13 @@ static int ov7251_enum_frame_ival(struct v4l2_subdev *subdev,
 
 static struct v4l2_mbus_framefmt *
 __ov7251_get_pad_format(struct ov7251 *ov7251,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad,
                        enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&ov7251->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&ov7251->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &ov7251->fmt;
        default:
@@ -965,13 +965,14 @@ __ov7251_get_pad_format(struct ov7251 *ov7251,
 }
 
 static int ov7251_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct ov7251 *ov7251 = to_ov7251(sd);
 
        mutex_lock(&ov7251->lock);
-       format->format = *__ov7251_get_pad_format(ov7251, cfg, format->pad,
+       format->format = *__ov7251_get_pad_format(ov7251, sd_state,
+                                                 format->pad,
                                                  format->which);
        mutex_unlock(&ov7251->lock);
 
@@ -979,12 +980,13 @@ static int ov7251_get_format(struct v4l2_subdev *sd,
 }
 
 static struct v4l2_rect *
-__ov7251_get_pad_crop(struct ov7251 *ov7251, struct v4l2_subdev_pad_config *cfg,
+__ov7251_get_pad_crop(struct ov7251 *ov7251,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_crop(&ov7251->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&ov7251->sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &ov7251->crop;
        default:
@@ -1027,7 +1029,7 @@ ov7251_find_mode_by_ival(struct ov7251 *ov7251, struct v4l2_fract *timeperframe)
 }
 
 static int ov7251_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *format)
 {
        struct ov7251 *ov7251 = to_ov7251(sd);
@@ -1038,7 +1040,8 @@ static int ov7251_set_format(struct v4l2_subdev *sd,
 
        mutex_lock(&ov7251->lock);
 
-       __crop = __ov7251_get_pad_crop(ov7251, cfg, format->pad, format->which);
+       __crop = __ov7251_get_pad_crop(ov7251, sd_state, format->pad,
+                                      format->which);
 
        new_mode = v4l2_find_nearest_size(ov7251_mode_info_data,
                                ARRAY_SIZE(ov7251_mode_info_data),
@@ -1077,7 +1080,7 @@ static int ov7251_set_format(struct v4l2_subdev *sd,
                ov7251->current_mode = new_mode;
        }
 
-       __format = __ov7251_get_pad_format(ov7251, cfg, format->pad,
+       __format = __ov7251_get_pad_format(ov7251, sd_state, format->pad,
                                           format->which);
        __format->width = __crop->width;
        __format->height = __crop->height;
@@ -1098,24 +1101,24 @@ exit:
 }
 
 static int ov7251_entity_init_cfg(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format fmt = {
-               .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
-                            : V4L2_SUBDEV_FORMAT_ACTIVE,
+               .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+               : V4L2_SUBDEV_FORMAT_ACTIVE,
                .format = {
                        .width = 640,
                        .height = 480
                }
        };
 
-       ov7251_set_format(subdev, cfg, &fmt);
+       ov7251_set_format(subdev, sd_state, &fmt);
 
        return 0;
 }
 
 static int ov7251_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct ov7251 *ov7251 = to_ov7251(sd);
@@ -1124,7 +1127,7 @@ static int ov7251_get_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        mutex_lock(&ov7251->lock);
-       sel->r = *__ov7251_get_pad_crop(ov7251, cfg, sel->pad,
+       sel->r = *__ov7251_get_pad_crop(ov7251, sd_state, sel->pad,
                                        sel->which);
        mutex_unlock(&ov7251->lock);
 
index d2df811..1967464 100644 (file)
@@ -960,7 +960,7 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
 
 
 static int ov7670_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= N_OV7670_FMTS)
@@ -1105,7 +1105,7 @@ static int ov7670_apply_fmt(struct v4l2_subdev *sd)
  * Set a format.
  */
 static int ov7670_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct ov7670_info *info = to_state(sd);
@@ -1122,7 +1122,8 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
                if (ret)
                        return ret;
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+                                                     format->pad);
                *mbus_fmt = format->format;
 #endif
                return 0;
@@ -1144,7 +1145,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov7670_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov7670_info *info = to_state(sd);
@@ -1154,7 +1155,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
                format->format = *mbus_fmt;
                return 0;
 #else
@@ -1202,7 +1203,7 @@ static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
 static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
 
 static int ov7670_enum_frame_interval(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct ov7670_info *info = to_state(sd);
@@ -1241,7 +1242,7 @@ static int ov7670_enum_frame_interval(struct v4l2_subdev *sd,
  * Frame size enumeration
  */
 static int ov7670_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct ov7670_info *info = to_state(sd);
@@ -1724,7 +1725,7 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd,
 static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *format =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        ov7670_get_default_format(sd, format);
 
index d94cf2d..78602a2 100644 (file)
@@ -1157,7 +1157,7 @@ ov772x_set_fmt_error:
 }
 
 static int ov772x_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct ov772x_priv *priv = to_ov772x(sd);
@@ -1179,7 +1179,7 @@ static int ov772x_get_selection(struct v4l2_subdev *sd,
 }
 
 static int ov772x_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -1198,7 +1198,7 @@ static int ov772x_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov772x_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov772x_priv *priv = to_ov772x(sd);
@@ -1222,7 +1222,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd,
        mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
+               sd_state->pads->try_fmt = *mf;
                return 0;
        }
 
@@ -1320,7 +1320,7 @@ static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
 };
 
 static int ov772x_enum_frame_interval(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_interval_enum *fie)
 {
        if (fie->pad || fie->index >= ARRAY_SIZE(ov772x_frame_intervals))
@@ -1338,7 +1338,7 @@ static int ov772x_enum_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
index 47a9003..2539cfe 100644 (file)
@@ -624,11 +624,9 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
+               if (ret < 0)
                        goto err_unlock;
-               }
 
                ret = ov7740_start_streaming(ov7740);
                if (ret)
@@ -709,7 +707,7 @@ static const struct ov7740_pixfmt ov7740_formats[] = {
 #define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
 
 static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= N_OV7740_FMTS)
@@ -721,7 +719,7 @@ static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_interval_enum *fie)
 {
        if (fie->pad)
@@ -740,7 +738,7 @@ static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->pad)
@@ -803,7 +801,7 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
 }
 
 static int ov7740_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
@@ -825,7 +823,8 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd,
                if (ret)
                        goto error;
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+                                                     format->pad);
                *mbus_fmt = format->format;
 #endif
                mutex_unlock(&ov7740->mutex);
@@ -848,7 +847,7 @@ error:
 }
 
 static int ov7740_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
@@ -860,7 +859,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&ov7740->mutex);
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
-               mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
                format->format = *mbus_fmt;
                ret = 0;
 #else
@@ -905,7 +904,7 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
        struct v4l2_mbus_framefmt *format =
-                               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+                               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        mutex_lock(&ov7740->mutex);
        ov7740_get_default_format(sd, format);
index e3af3ea..88e19f3 100644 (file)
@@ -18,8 +18,6 @@
 #define OV8856_REG_VALUE_16BIT         2
 #define OV8856_REG_VALUE_24BIT         3
 
-#define OV8856_LINK_FREQ_360MHZ                360000000ULL
-#define OV8856_LINK_FREQ_180MHZ                180000000ULL
 #define OV8856_SCLK                    144000000ULL
 #define OV8856_XVCLK_19_2              19200000
 #define OV8856_DATA_LANES              4
 #define OV8856_TEST_PATTERN_ENABLE     BIT(7)
 #define OV8856_TEST_PATTERN_BAR_SHIFT  2
 
+#define NUM_REGS                               7
+#define NUM_MODE_REGS                          187
+#define NUM_MODE_REGS_2                                200
+
+/* Flip Mirror Controls from sensor */
+#define OV8856_REG_FORMAT1                     0x3820
+#define OV8856_REG_FORMAT2                     0x3821
+#define OV8856_REG_FORMAT1_OP_1                        BIT(1)
+#define OV8856_REG_FORMAT1_OP_2                        BIT(2)
+#define OV8856_REG_FORMAT1_OP_3                        BIT(6)
+#define OV8856_REG_FORMAT2_OP_1                        BIT(1)
+#define OV8856_REG_FORMAT2_OP_2                        BIT(2)
+#define OV8856_REG_FORMAT2_OP_3                        BIT(6)
+#define OV8856_REG_FLIP_OPT_1                  0x376b
+#define OV8856_REG_FLIP_OPT_2                  0x5001
+#define OV8856_REG_FLIP_OPT_3                  0x502e
+#define OV8856_REG_MIRROR_OPT_1                        0x5004
+#define OV8856_REG_FLIP_OP_0                   BIT(0)
+#define OV8856_REG_FLIP_OP_1                   BIT(1)
+#define OV8856_REG_FLIP_OP_2                   BIT(2)
+#define OV8856_REG_MIRROR_OP_1                 BIT(1)
+#define OV8856_REG_MIRROR_OP_2                 BIT(2)
+
 #define to_ov8856(_sd)                 container_of(_sd, struct ov8856, sd)
 
 static const char * const ov8856_supply_names[] = {
@@ -86,11 +107,6 @@ static const char * const ov8856_supply_names[] = {
        "dvdd",         /* Digital core power */
 };
 
-enum {
-       OV8856_LINK_FREQ_720MBPS,
-       OV8856_LINK_FREQ_360MBPS,
-};
-
 struct ov8856_reg {
        u16 address;
        u8 val;
@@ -126,891 +142,1242 @@ struct ov8856_mode {
 
        /* Sensor register settings for this resolution */
        const struct ov8856_reg_list reg_list;
+
+       /* Number of data lanes */
+       u8 data_lanes;
 };
 
-static const struct ov8856_reg mipi_data_rate_720mbps[] = {
-       {0x0103, 0x01},
-       {0x0100, 0x00},
-       {0x0302, 0x4b},
-       {0x0303, 0x01},
-       {0x030b, 0x02},
-       {0x030d, 0x4b},
-       {0x031e, 0x0c},
+struct ov8856_mipi_data_rates {
+       const struct ov8856_reg regs_0[NUM_REGS];
+       const struct ov8856_reg regs_1[NUM_REGS];
 };
 
-static const struct ov8856_reg mipi_data_rate_360mbps[] = {
-       {0x0103, 0x01},
-       {0x0100, 0x00},
-       {0x0302, 0x4b},
-       {0x0303, 0x03},
-       {0x030b, 0x02},
-       {0x030d, 0x4b},
-       {0x031e, 0x0c},
+static const struct ov8856_mipi_data_rates mipi_data_rate_lane_2 = {
+       //mipi_data_rate_1440mbps
+       {
+               {0x0103, 0x01},
+               {0x0100, 0x00},
+               {0x0302, 0x43},
+               {0x0303, 0x00},
+               {0x030b, 0x02},
+               {0x030d, 0x4b},
+               {0x031e, 0x0c}
+       },
+       //mipi_data_rate_720mbps
+       {
+               {0x0103, 0x01},
+               {0x0100, 0x00},
+               {0x0302, 0x4b},
+               {0x0303, 0x01},
+               {0x030b, 0x02},
+               {0x030d, 0x4b},
+               {0x031e, 0x0c}
+       }
 };
 
-static const struct ov8856_reg mode_3280x2464_regs[] = {
-       {0x3000, 0x20},
-       {0x3003, 0x08},
-       {0x300e, 0x20},
-       {0x3010, 0x00},
-       {0x3015, 0x84},
-       {0x3018, 0x72},
-       {0x3021, 0x23},
-       {0x3033, 0x24},
-       {0x3500, 0x00},
-       {0x3501, 0x9a},
-       {0x3502, 0x20},
-       {0x3503, 0x08},
-       {0x3505, 0x83},
-       {0x3508, 0x01},
-       {0x3509, 0x80},
-       {0x350c, 0x00},
-       {0x350d, 0x80},
-       {0x350e, 0x04},
-       {0x350f, 0x00},
-       {0x3510, 0x00},
-       {0x3511, 0x02},
-       {0x3512, 0x00},
-       {0x3600, 0x72},
-       {0x3601, 0x40},
-       {0x3602, 0x30},
-       {0x3610, 0xc5},
-       {0x3611, 0x58},
-       {0x3612, 0x5c},
-       {0x3613, 0xca},
-       {0x3614, 0x20},
-       {0x3628, 0xff},
-       {0x3629, 0xff},
-       {0x362a, 0xff},
-       {0x3633, 0x10},
-       {0x3634, 0x10},
-       {0x3635, 0x10},
-       {0x3636, 0x10},
-       {0x3663, 0x08},
-       {0x3669, 0x34},
-       {0x366e, 0x10},
-       {0x3706, 0x86},
-       {0x370b, 0x7e},
-       {0x3714, 0x23},
-       {0x3730, 0x12},
-       {0x3733, 0x10},
-       {0x3764, 0x00},
-       {0x3765, 0x00},
-       {0x3769, 0x62},
-       {0x376a, 0x2a},
-       {0x376b, 0x30},
-       {0x3780, 0x00},
-       {0x3781, 0x24},
-       {0x3782, 0x00},
-       {0x3783, 0x23},
-       {0x3798, 0x2f},
-       {0x37a1, 0x60},
-       {0x37a8, 0x6a},
-       {0x37ab, 0x3f},
-       {0x37c2, 0x04},
-       {0x37c3, 0xf1},
-       {0x37c9, 0x80},
-       {0x37cb, 0x16},
-       {0x37cc, 0x16},
-       {0x37cd, 0x16},
-       {0x37ce, 0x16},
-       {0x3800, 0x00},
-       {0x3801, 0x00},
-       {0x3802, 0x00},
-       {0x3803, 0x06},
-       {0x3804, 0x0c},
-       {0x3805, 0xdf},
-       {0x3806, 0x09},
-       {0x3807, 0xa7},
-       {0x3808, 0x0c},
-       {0x3809, 0xd0},
-       {0x380a, 0x09},
-       {0x380b, 0xa0},
-       {0x380c, 0x07},
-       {0x380d, 0x88},
-       {0x380e, 0x09},
-       {0x380f, 0xb8},
-       {0x3810, 0x00},
-       {0x3811, 0x00},
-       {0x3812, 0x00},
-       {0x3813, 0x01},
-       {0x3814, 0x01},
-       {0x3815, 0x01},
-       {0x3816, 0x00},
-       {0x3817, 0x00},
-       {0x3818, 0x00},
-       {0x3819, 0x10},
-       {0x3820, 0x80},
-       {0x3821, 0x46},
-       {0x382a, 0x01},
-       {0x382b, 0x01},
-       {0x3830, 0x06},
-       {0x3836, 0x02},
-       {0x3862, 0x04},
-       {0x3863, 0x08},
-       {0x3cc0, 0x33},
-       {0x3d85, 0x17},
-       {0x3d8c, 0x73},
-       {0x3d8d, 0xde},
-       {0x4001, 0xe0},
-       {0x4003, 0x40},
-       {0x4008, 0x00},
-       {0x4009, 0x0b},
-       {0x400a, 0x00},
-       {0x400b, 0x84},
-       {0x400f, 0x80},
-       {0x4010, 0xf0},
-       {0x4011, 0xff},
-       {0x4012, 0x02},
-       {0x4013, 0x01},
-       {0x4014, 0x01},
-       {0x4015, 0x01},
-       {0x4042, 0x00},
-       {0x4043, 0x80},
-       {0x4044, 0x00},
-       {0x4045, 0x80},
-       {0x4046, 0x00},
-       {0x4047, 0x80},
-       {0x4048, 0x00},
-       {0x4049, 0x80},
-       {0x4041, 0x03},
-       {0x404c, 0x20},
-       {0x404d, 0x00},
-       {0x404e, 0x20},
-       {0x4203, 0x80},
-       {0x4307, 0x30},
-       {0x4317, 0x00},
-       {0x4503, 0x08},
-       {0x4601, 0x80},
-       {0x4800, 0x44},
-       {0x4816, 0x53},
-       {0x481b, 0x58},
-       {0x481f, 0x27},
-       {0x4837, 0x16},
-       {0x483c, 0x0f},
-       {0x484b, 0x05},
-       {0x5000, 0x57},
-       {0x5001, 0x0a},
-       {0x5004, 0x04},
-       {0x502e, 0x03},
-       {0x5030, 0x41},
-       {0x5780, 0x14},
-       {0x5781, 0x0f},
-       {0x5782, 0x44},
-       {0x5783, 0x02},
-       {0x5784, 0x01},
-       {0x5785, 0x01},
-       {0x5786, 0x00},
-       {0x5787, 0x04},
-       {0x5788, 0x02},
-       {0x5789, 0x0f},
-       {0x578a, 0xfd},
-       {0x578b, 0xf5},
-       {0x578c, 0xf5},
-       {0x578d, 0x03},
-       {0x578e, 0x08},
-       {0x578f, 0x0c},
-       {0x5790, 0x08},
-       {0x5791, 0x04},
-       {0x5792, 0x00},
-       {0x5793, 0x52},
-       {0x5794, 0xa3},
-       {0x5795, 0x02},
-       {0x5796, 0x20},
-       {0x5797, 0x20},
-       {0x5798, 0xd5},
-       {0x5799, 0xd5},
-       {0x579a, 0x00},
-       {0x579b, 0x50},
-       {0x579c, 0x00},
-       {0x579d, 0x2c},
-       {0x579e, 0x0c},
-       {0x579f, 0x40},
-       {0x57a0, 0x09},
-       {0x57a1, 0x40},
-       {0x59f8, 0x3d},
-       {0x5a08, 0x02},
-       {0x5b00, 0x02},
-       {0x5b01, 0x10},
-       {0x5b02, 0x03},
-       {0x5b03, 0xcf},
-       {0x5b05, 0x6c},
-       {0x5e00, 0x00}
+static const struct ov8856_mipi_data_rates mipi_data_rate_lane_4 = {
+       //mipi_data_rate_720mbps
+       {
+               {0x0103, 0x01},
+               {0x0100, 0x00},
+               {0x0302, 0x4b},
+               {0x0303, 0x01},
+               {0x030b, 0x02},
+               {0x030d, 0x4b},
+               {0x031e, 0x0c}
+       },
+       //mipi_data_rate_360mbps
+       {
+               {0x0103, 0x01},
+               {0x0100, 0x00},
+               {0x0302, 0x4b},
+               {0x0303, 0x03},
+               {0x030b, 0x02},
+               {0x030d, 0x4b},
+               {0x031e, 0x0c}
+       }
 };
 
-static const struct ov8856_reg mode_3264x2448_regs[] = {
-       {0x0103, 0x01},
-       {0x0302, 0x3c},
-       {0x0303, 0x01},
-       {0x031e, 0x0c},
-       {0x3000, 0x20},
-       {0x3003, 0x08},
-       {0x300e, 0x20},
-       {0x3010, 0x00},
-       {0x3015, 0x84},
-       {0x3018, 0x72},
-       {0x3021, 0x23},
-       {0x3033, 0x24},
-       {0x3500, 0x00},
-       {0x3501, 0x9a},
-       {0x3502, 0x20},
-       {0x3503, 0x08},
-       {0x3505, 0x83},
-       {0x3508, 0x01},
-       {0x3509, 0x80},
-       {0x350c, 0x00},
-       {0x350d, 0x80},
-       {0x350e, 0x04},
-       {0x350f, 0x00},
-       {0x3510, 0x00},
-       {0x3511, 0x02},
-       {0x3512, 0x00},
-       {0x3600, 0x72},
-       {0x3601, 0x40},
-       {0x3602, 0x30},
-       {0x3610, 0xc5},
-       {0x3611, 0x58},
-       {0x3612, 0x5c},
-       {0x3613, 0xca},
-       {0x3614, 0x60},
-       {0x3628, 0xff},
-       {0x3629, 0xff},
-       {0x362a, 0xff},
-       {0x3633, 0x10},
-       {0x3634, 0x10},
-       {0x3635, 0x10},
-       {0x3636, 0x10},
-       {0x3663, 0x08},
-       {0x3669, 0x34},
-       {0x366d, 0x00},
-       {0x366e, 0x10},
-       {0x3706, 0x86},
-       {0x370b, 0x7e},
-       {0x3714, 0x23},
-       {0x3730, 0x12},
-       {0x3733, 0x10},
-       {0x3764, 0x00},
-       {0x3765, 0x00},
-       {0x3769, 0x62},
-       {0x376a, 0x2a},
-       {0x376b, 0x30},
-       {0x3780, 0x00},
-       {0x3781, 0x24},
-       {0x3782, 0x00},
-       {0x3783, 0x23},
-       {0x3798, 0x2f},
-       {0x37a1, 0x60},
-       {0x37a8, 0x6a},
-       {0x37ab, 0x3f},
-       {0x37c2, 0x04},
-       {0x37c3, 0xf1},
-       {0x37c9, 0x80},
-       {0x37cb, 0x16},
-       {0x37cc, 0x16},
-       {0x37cd, 0x16},
-       {0x37ce, 0x16},
-       {0x3800, 0x00},
-       {0x3801, 0x00},
-       {0x3802, 0x00},
-       {0x3803, 0x0c},
-       {0x3804, 0x0c},
-       {0x3805, 0xdf},
-       {0x3806, 0x09},
-       {0x3807, 0xa3},
-       {0x3808, 0x0c},
-       {0x3809, 0xc0},
-       {0x380a, 0x09},
-       {0x380b, 0x90},
-       {0x380c, 0x07},
-       {0x380d, 0x8c},
-       {0x380e, 0x09},
-       {0x380f, 0xb2},
-       {0x3810, 0x00},
-       {0x3811, 0x04},
-       {0x3812, 0x00},
-       {0x3813, 0x01},
-       {0x3814, 0x01},
-       {0x3815, 0x01},
-       {0x3816, 0x00},
-       {0x3817, 0x00},
-       {0x3818, 0x00},
-       {0x3819, 0x10},
-       {0x3820, 0x80},
-       {0x3821, 0x46},
-       {0x382a, 0x01},
-       {0x382b, 0x01},
-       {0x3830, 0x06},
-       {0x3836, 0x02},
-       {0x3862, 0x04},
-       {0x3863, 0x08},
-       {0x3cc0, 0x33},
-       {0x3d85, 0x17},
-       {0x3d8c, 0x73},
-       {0x3d8d, 0xde},
-       {0x4001, 0xe0},
-       {0x4003, 0x40},
-       {0x4008, 0x00},
-       {0x4009, 0x0b},
-       {0x400a, 0x00},
-       {0x400b, 0x84},
-       {0x400f, 0x80},
-       {0x4010, 0xf0},
-       {0x4011, 0xff},
-       {0x4012, 0x02},
-       {0x4013, 0x01},
-       {0x4014, 0x01},
-       {0x4015, 0x01},
-       {0x4042, 0x00},
-       {0x4043, 0x80},
-       {0x4044, 0x00},
-       {0x4045, 0x80},
-       {0x4046, 0x00},
-       {0x4047, 0x80},
-       {0x4048, 0x00},
-       {0x4049, 0x80},
-       {0x4041, 0x03},
-       {0x404c, 0x20},
-       {0x404d, 0x00},
-       {0x404e, 0x20},
-       {0x4203, 0x80},
-       {0x4307, 0x30},
-       {0x4317, 0x00},
-       {0x4502, 0x50},
-       {0x4503, 0x08},
-       {0x4601, 0x80},
-       {0x4800, 0x44},
-       {0x4816, 0x53},
-       {0x481b, 0x50},
-       {0x481f, 0x27},
-       {0x4823, 0x3c},
-       {0x482b, 0x00},
-       {0x4831, 0x66},
-       {0x4837, 0x16},
-       {0x483c, 0x0f},
-       {0x484b, 0x05},
-       {0x5000, 0x77},
-       {0x5001, 0x0a},
-       {0x5003, 0xc8},
-       {0x5004, 0x04},
-       {0x5006, 0x00},
-       {0x5007, 0x00},
-       {0x502e, 0x03},
-       {0x5030, 0x41},
-       {0x5780, 0x14},
-       {0x5781, 0x0f},
-       {0x5782, 0x44},
-       {0x5783, 0x02},
-       {0x5784, 0x01},
-       {0x5785, 0x01},
-       {0x5786, 0x00},
-       {0x5787, 0x04},
-       {0x5788, 0x02},
-       {0x5789, 0x0f},
-       {0x578a, 0xfd},
-       {0x578b, 0xf5},
-       {0x578c, 0xf5},
-       {0x578d, 0x03},
-       {0x578e, 0x08},
-       {0x578f, 0x0c},
-       {0x5790, 0x08},
-       {0x5791, 0x04},
-       {0x5792, 0x00},
-       {0x5793, 0x52},
-       {0x5794, 0xa3},
-       {0x5795, 0x02},
-       {0x5796, 0x20},
-       {0x5797, 0x20},
-       {0x5798, 0xd5},
-       {0x5799, 0xd5},
-       {0x579a, 0x00},
-       {0x579b, 0x50},
-       {0x579c, 0x00},
-       {0x579d, 0x2c},
-       {0x579e, 0x0c},
-       {0x579f, 0x40},
-       {0x57a0, 0x09},
-       {0x57a1, 0x40},
-       {0x59f8, 0x3d},
-       {0x5a08, 0x02},
-       {0x5b00, 0x02},
-       {0x5b01, 0x10},
-       {0x5b02, 0x03},
-       {0x5b03, 0xcf},
-       {0x5b05, 0x6c},
-       {0x5e00, 0x00},
-       {0x5e10, 0xfc}
+static const struct ov8856_reg lane_2_mode_3280x2464[] = {
+       /* 3280x2464 resolution */
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x32},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x9a},
+               {0x3502, 0x20},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x50},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366e, 0x10},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x23},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x04},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x06},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xa7},
+               {0x3808, 0x0c},
+               {0x3809, 0xd0},
+               {0x380a, 0x09},
+               {0x380b, 0xa0},
+               {0x380c, 0x07},
+               {0x380d, 0x88},
+               {0x380e, 0x09},
+               {0x380f, 0xb8},
+               {0x3810, 0x00},
+               {0x3811, 0x00},
+               {0x3812, 0x00},
+               {0x3813, 0x01},
+               {0x3814, 0x01},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x00},
+               {0x3820, 0x80},
+               {0x3821, 0x46},
+               {0x382a, 0x01},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3837, 0x10},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x14},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x0b},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x58},
+               {0x481f, 0x27},
+               {0x4837, 0x0c},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x57},
+               {0x5001, 0x0a},
+               {0x5004, 0x04},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5795, 0x02},
+               {0x5796, 0x20},
+               {0x5797, 0x20},
+               {0x5798, 0xd5},
+               {0x5799, 0xd5},
+               {0x579a, 0x00},
+               {0x579b, 0x50},
+               {0x579c, 0x00},
+               {0x579d, 0x2c},
+               {0x579e, 0x0c},
+               {0x579f, 0x40},
+               {0x57a0, 0x09},
+               {0x57a1, 0x40},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00}
 };
 
-static const struct ov8856_reg mode_1640x1232_regs[] = {
-       {0x3000, 0x20},
-       {0x3003, 0x08},
-       {0x300e, 0x20},
-       {0x3010, 0x00},
-       {0x3015, 0x84},
-       {0x3018, 0x72},
-       {0x3021, 0x23},
-       {0x3033, 0x24},
-       {0x3500, 0x00},
-       {0x3501, 0x4c},
-       {0x3502, 0xe0},
-       {0x3503, 0x08},
-       {0x3505, 0x83},
-       {0x3508, 0x01},
-       {0x3509, 0x80},
-       {0x350c, 0x00},
-       {0x350d, 0x80},
-       {0x350e, 0x04},
-       {0x350f, 0x00},
-       {0x3510, 0x00},
-       {0x3511, 0x02},
-       {0x3512, 0x00},
-       {0x3600, 0x72},
-       {0x3601, 0x40},
-       {0x3602, 0x30},
-       {0x3610, 0xc5},
-       {0x3611, 0x58},
-       {0x3612, 0x5c},
-       {0x3613, 0xca},
-       {0x3614, 0x20},
-       {0x3628, 0xff},
-       {0x3629, 0xff},
-       {0x362a, 0xff},
-       {0x3633, 0x10},
-       {0x3634, 0x10},
-       {0x3635, 0x10},
-       {0x3636, 0x10},
-       {0x3663, 0x08},
-       {0x3669, 0x34},
-       {0x366e, 0x08},
-       {0x3706, 0x86},
-       {0x370b, 0x7e},
-       {0x3714, 0x27},
-       {0x3730, 0x12},
-       {0x3733, 0x10},
-       {0x3764, 0x00},
-       {0x3765, 0x00},
-       {0x3769, 0x62},
-       {0x376a, 0x2a},
-       {0x376b, 0x30},
-       {0x3780, 0x00},
-       {0x3781, 0x24},
-       {0x3782, 0x00},
-       {0x3783, 0x23},
-       {0x3798, 0x2f},
-       {0x37a1, 0x60},
-       {0x37a8, 0x6a},
-       {0x37ab, 0x3f},
-       {0x37c2, 0x14},
-       {0x37c3, 0xf1},
-       {0x37c9, 0x80},
-       {0x37cb, 0x16},
-       {0x37cc, 0x16},
-       {0x37cd, 0x16},
-       {0x37ce, 0x16},
-       {0x3800, 0x00},
-       {0x3801, 0x00},
-       {0x3802, 0x00},
-       {0x3803, 0x06},
-       {0x3804, 0x0c},
-       {0x3805, 0xdf},
-       {0x3806, 0x09},
-       {0x3807, 0xa7},
-       {0x3808, 0x06},
-       {0x3809, 0x68},
-       {0x380a, 0x04},
-       {0x380b, 0xd0},
-       {0x380c, 0x0e},
-       {0x380d, 0xec},
-       {0x380e, 0x04},
-       {0x380f, 0xe8},
-       {0x3810, 0x00},
-       {0x3811, 0x00},
-       {0x3812, 0x00},
-       {0x3813, 0x01},
-       {0x3814, 0x03},
-       {0x3815, 0x01},
-       {0x3816, 0x00},
-       {0x3817, 0x00},
-       {0x3818, 0x00},
-       {0x3819, 0x10},
-       {0x3820, 0x90},
-       {0x3821, 0x67},
-       {0x382a, 0x03},
-       {0x382b, 0x01},
-       {0x3830, 0x06},
-       {0x3836, 0x02},
-       {0x3862, 0x04},
-       {0x3863, 0x08},
-       {0x3cc0, 0x33},
-       {0x3d85, 0x17},
-       {0x3d8c, 0x73},
-       {0x3d8d, 0xde},
-       {0x4001, 0xe0},
-       {0x4003, 0x40},
-       {0x4008, 0x00},
-       {0x4009, 0x05},
-       {0x400a, 0x00},
-       {0x400b, 0x84},
-       {0x400f, 0x80},
-       {0x4010, 0xf0},
-       {0x4011, 0xff},
-       {0x4012, 0x02},
-       {0x4013, 0x01},
-       {0x4014, 0x01},
-       {0x4015, 0x01},
-       {0x4042, 0x00},
-       {0x4043, 0x80},
-       {0x4044, 0x00},
-       {0x4045, 0x80},
-       {0x4046, 0x00},
-       {0x4047, 0x80},
-       {0x4048, 0x00},
-       {0x4049, 0x80},
-       {0x4041, 0x03},
-       {0x404c, 0x20},
-       {0x404d, 0x00},
-       {0x404e, 0x20},
-       {0x4203, 0x80},
-       {0x4307, 0x30},
-       {0x4317, 0x00},
-       {0x4503, 0x08},
-       {0x4601, 0x80},
-       {0x4800, 0x44},
-       {0x4816, 0x53},
-       {0x481b, 0x58},
-       {0x481f, 0x27},
-       {0x4837, 0x16},
-       {0x483c, 0x0f},
-       {0x484b, 0x05},
-       {0x5000, 0x57},
-       {0x5001, 0x0a},
-       {0x5004, 0x04},
-       {0x502e, 0x03},
-       {0x5030, 0x41},
-       {0x5780, 0x14},
-       {0x5781, 0x0f},
-       {0x5782, 0x44},
-       {0x5783, 0x02},
-       {0x5784, 0x01},
-       {0x5785, 0x01},
-       {0x5786, 0x00},
-       {0x5787, 0x04},
-       {0x5788, 0x02},
-       {0x5789, 0x0f},
-       {0x578a, 0xfd},
-       {0x578b, 0xf5},
-       {0x578c, 0xf5},
-       {0x578d, 0x03},
-       {0x578e, 0x08},
-       {0x578f, 0x0c},
-       {0x5790, 0x08},
-       {0x5791, 0x04},
-       {0x5792, 0x00},
-       {0x5793, 0x52},
-       {0x5794, 0xa3},
-       {0x5795, 0x00},
-       {0x5796, 0x10},
-       {0x5797, 0x10},
-       {0x5798, 0x73},
-       {0x5799, 0x73},
-       {0x579a, 0x00},
-       {0x579b, 0x28},
-       {0x579c, 0x00},
-       {0x579d, 0x16},
-       {0x579e, 0x06},
-       {0x579f, 0x20},
-       {0x57a0, 0x04},
-       {0x57a1, 0xa0},
-       {0x59f8, 0x3d},
-       {0x5a08, 0x02},
-       {0x5b00, 0x02},
-       {0x5b01, 0x10},
-       {0x5b02, 0x03},
-       {0x5b03, 0xcf},
-       {0x5b05, 0x6c},
-       {0x5e00, 0x00}
+static const struct ov8856_reg lane_2_mode_1640x1232[] = {
+       /* 1640x1232 resolution */
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x32},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x4c},
+               {0x3502, 0xe0},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x50},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366e, 0x08},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x27},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x14},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x00},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xaf},
+               {0x3808, 0x06},
+               {0x3809, 0x68},
+               {0x380a, 0x04},
+               {0x380b, 0xd0},
+               {0x380c, 0x0c},
+               {0x380d, 0x60},
+               {0x380e, 0x05},
+               {0x380f, 0xea},
+               {0x3810, 0x00},
+               {0x3811, 0x04},
+               {0x3812, 0x00},
+               {0x3813, 0x05},
+               {0x3814, 0x03},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x00},
+               {0x3820, 0x90},
+               {0x3821, 0x67},
+               {0x382a, 0x03},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3837, 0x10},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x14},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x05},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x58},
+               {0x481f, 0x27},
+               {0x4837, 0x16},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x57},
+               {0x5001, 0x0a},
+               {0x5004, 0x04},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5795, 0x00},
+               {0x5796, 0x10},
+               {0x5797, 0x10},
+               {0x5798, 0x73},
+               {0x5799, 0x73},
+               {0x579a, 0x00},
+               {0x579b, 0x28},
+               {0x579c, 0x00},
+               {0x579d, 0x16},
+               {0x579e, 0x06},
+               {0x579f, 0x20},
+               {0x57a0, 0x04},
+               {0x57a1, 0xa0},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00}
 };
 
-static const struct ov8856_reg mode_1632x1224_regs[] = {
-       {0x0103, 0x01},
-       {0x0302, 0x3c},
-       {0x0303, 0x01},
-       {0x031e, 0x0c},
-       {0x3000, 0x20},
-       {0x3003, 0x08},
-       {0x300e, 0x20},
-       {0x3010, 0x00},
-       {0x3015, 0x84},
-       {0x3018, 0x72},
-       {0x3021, 0x23},
-       {0x3033, 0x24},
-       {0x3500, 0x00},
-       {0x3501, 0x4c},
-       {0x3502, 0xe0},
-       {0x3503, 0x08},
-       {0x3505, 0x83},
-       {0x3508, 0x01},
-       {0x3509, 0x80},
-       {0x350c, 0x00},
-       {0x350d, 0x80},
-       {0x350e, 0x04},
-       {0x350f, 0x00},
-       {0x3510, 0x00},
-       {0x3511, 0x02},
-       {0x3512, 0x00},
-       {0x3600, 0x72},
-       {0x3601, 0x40},
-       {0x3602, 0x30},
-       {0x3610, 0xc5},
-       {0x3611, 0x58},
-       {0x3612, 0x5c},
-       {0x3613, 0xca},
-       {0x3614, 0x60},
-       {0x3628, 0xff},
-       {0x3629, 0xff},
-       {0x362a, 0xff},
-       {0x3633, 0x10},
-       {0x3634, 0x10},
-       {0x3635, 0x10},
-       {0x3636, 0x10},
-       {0x3663, 0x08},
-       {0x3669, 0x34},
-       {0x366d, 0x00},
-       {0x366e, 0x08},
-       {0x3706, 0x86},
-       {0x370b, 0x7e},
-       {0x3714, 0x27},
-       {0x3730, 0x12},
-       {0x3733, 0x10},
-       {0x3764, 0x00},
-       {0x3765, 0x00},
-       {0x3769, 0x62},
-       {0x376a, 0x2a},
-       {0x376b, 0x30},
-       {0x3780, 0x00},
-       {0x3781, 0x24},
-       {0x3782, 0x00},
-       {0x3783, 0x23},
-       {0x3798, 0x2f},
-       {0x37a1, 0x60},
-       {0x37a8, 0x6a},
-       {0x37ab, 0x3f},
-       {0x37c2, 0x14},
-       {0x37c3, 0xf1},
-       {0x37c9, 0x80},
-       {0x37cb, 0x16},
-       {0x37cc, 0x16},
-       {0x37cd, 0x16},
-       {0x37ce, 0x16},
-       {0x3800, 0x00},
-       {0x3801, 0x00},
-       {0x3802, 0x00},
-       {0x3803, 0x0c},
-       {0x3804, 0x0c},
-       {0x3805, 0xdf},
-       {0x3806, 0x09},
-       {0x3807, 0xa3},
-       {0x3808, 0x06},
-       {0x3809, 0x60},
-       {0x380a, 0x04},
-       {0x380b, 0xc8},
-       {0x380c, 0x07},
-       {0x380d, 0x8c},
-       {0x380e, 0x09},
-       {0x380f, 0xb2},
-       {0x3810, 0x00},
-       {0x3811, 0x02},
-       {0x3812, 0x00},
-       {0x3813, 0x01},
-       {0x3814, 0x03},
-       {0x3815, 0x01},
-       {0x3816, 0x00},
-       {0x3817, 0x00},
-       {0x3818, 0x00},
-       {0x3819, 0x10},
-       {0x3820, 0x80},
-       {0x3821, 0x47},
-       {0x382a, 0x03},
-       {0x382b, 0x01},
-       {0x3830, 0x06},
-       {0x3836, 0x02},
-       {0x3862, 0x04},
-       {0x3863, 0x08},
-       {0x3cc0, 0x33},
-       {0x3d85, 0x17},
-       {0x3d8c, 0x73},
-       {0x3d8d, 0xde},
-       {0x4001, 0xe0},
-       {0x4003, 0x40},
-       {0x4008, 0x00},
-       {0x4009, 0x05},
-       {0x400a, 0x00},
-       {0x400b, 0x84},
-       {0x400f, 0x80},
-       {0x4010, 0xf0},
-       {0x4011, 0xff},
-       {0x4012, 0x02},
-       {0x4013, 0x01},
-       {0x4014, 0x01},
-       {0x4015, 0x01},
-       {0x4042, 0x00},
-       {0x4043, 0x80},
-       {0x4044, 0x00},
-       {0x4045, 0x80},
-       {0x4046, 0x00},
-       {0x4047, 0x80},
-       {0x4048, 0x00},
-       {0x4049, 0x80},
-       {0x4041, 0x03},
-       {0x404c, 0x20},
-       {0x404d, 0x00},
-       {0x404e, 0x20},
-       {0x4203, 0x80},
-       {0x4307, 0x30},
-       {0x4317, 0x00},
-       {0x4502, 0x50},
-       {0x4503, 0x08},
-       {0x4601, 0x80},
-       {0x4800, 0x44},
-       {0x4816, 0x53},
-       {0x481b, 0x50},
-       {0x481f, 0x27},
-       {0x4823, 0x3c},
-       {0x482b, 0x00},
-       {0x4831, 0x66},
-       {0x4837, 0x16},
-       {0x483c, 0x0f},
-       {0x484b, 0x05},
-       {0x5000, 0x77},
-       {0x5001, 0x0a},
-       {0x5003, 0xc8},
-       {0x5004, 0x04},
-       {0x5006, 0x00},
-       {0x5007, 0x00},
-       {0x502e, 0x03},
-       {0x5030, 0x41},
-       {0x5795, 0x00},
-       {0x5796, 0x10},
-       {0x5797, 0x10},
-       {0x5798, 0x73},
-       {0x5799, 0x73},
-       {0x579a, 0x00},
-       {0x579b, 0x28},
-       {0x579c, 0x00},
-       {0x579d, 0x16},
-       {0x579e, 0x06},
-       {0x579f, 0x20},
-       {0x57a0, 0x04},
-       {0x57a1, 0xa0},
-       {0x5780, 0x14},
-       {0x5781, 0x0f},
-       {0x5782, 0x44},
-       {0x5783, 0x02},
-       {0x5784, 0x01},
-       {0x5785, 0x01},
-       {0x5786, 0x00},
-       {0x5787, 0x04},
-       {0x5788, 0x02},
-       {0x5789, 0x0f},
-       {0x578a, 0xfd},
-       {0x578b, 0xf5},
-       {0x578c, 0xf5},
-       {0x578d, 0x03},
-       {0x578e, 0x08},
-       {0x578f, 0x0c},
-       {0x5790, 0x08},
-       {0x5791, 0x04},
-       {0x5792, 0x00},
-       {0x5793, 0x52},
-       {0x5794, 0xa3},
-       {0x59f8, 0x3d},
-       {0x5a08, 0x02},
-       {0x5b00, 0x02},
-       {0x5b01, 0x10},
-       {0x5b02, 0x03},
-       {0x5b03, 0xcf},
-       {0x5b05, 0x6c},
-       {0x5e00, 0x00},
-       {0x5e10, 0xfc}
+static const struct ov8856_reg lane_4_mode_3280x2464[] = {
+       /* 3280x2464 resolution */
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x72},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x9a},
+               {0x3502, 0x20},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x20},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366e, 0x10},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x23},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x04},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x06},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xa7},
+               {0x3808, 0x0c},
+               {0x3809, 0xd0},
+               {0x380a, 0x09},
+               {0x380b, 0xa0},
+               {0x380c, 0x07},
+               {0x380d, 0x88},
+               {0x380e, 0x09},
+               {0x380f, 0xb8},
+               {0x3810, 0x00},
+               {0x3811, 0x00},
+               {0x3812, 0x00},
+               {0x3813, 0x01},
+               {0x3814, 0x01},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x10},
+               {0x3820, 0x80},
+               {0x3821, 0x46},
+               {0x382a, 0x01},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x17},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x0b},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x58},
+               {0x481f, 0x27},
+               {0x4837, 0x16},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x57},
+               {0x5001, 0x0a},
+               {0x5004, 0x04},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x5795, 0x02},
+               {0x5796, 0x20},
+               {0x5797, 0x20},
+               {0x5798, 0xd5},
+               {0x5799, 0xd5},
+               {0x579a, 0x00},
+               {0x579b, 0x50},
+               {0x579c, 0x00},
+               {0x579d, 0x2c},
+               {0x579e, 0x0c},
+               {0x579f, 0x40},
+               {0x57a0, 0x09},
+               {0x57a1, 0x40},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00}
 };
 
-static const char * const ov8856_test_pattern_menu[] = {
-       "Disabled",
-       "Standard Color Bar",
-       "Top-Bottom Darker Color Bar",
-       "Right-Left Darker Color Bar",
-       "Bottom-Top Darker Color Bar"
+static const struct ov8856_reg lane_4_mode_1640x1232[] = {
+       /* 1640x1232 resolution */
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x72},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x4c},
+               {0x3502, 0xe0},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x20},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366e, 0x08},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x27},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x14},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x00},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xaf},
+               {0x3808, 0x06},
+               {0x3809, 0x68},
+               {0x380a, 0x04},
+               {0x380b, 0xd0},
+               {0x380c, 0x0e},
+               {0x380d, 0xec},
+               {0x380e, 0x04},
+               {0x380f, 0xe8},
+               {0x3810, 0x00},
+               {0x3811, 0x04},
+               {0x3812, 0x00},
+               {0x3813, 0x05},
+               {0x3814, 0x03},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x10},
+               {0x3820, 0x90},
+               {0x3821, 0x67},
+               {0x382a, 0x03},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x17},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x05},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x58},
+               {0x481f, 0x27},
+               {0x4837, 0x16},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x57},
+               {0x5001, 0x0a},
+               {0x5004, 0x04},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x5795, 0x00},
+               {0x5796, 0x10},
+               {0x5797, 0x10},
+               {0x5798, 0x73},
+               {0x5799, 0x73},
+               {0x579a, 0x00},
+               {0x579b, 0x28},
+               {0x579c, 0x00},
+               {0x579d, 0x16},
+               {0x579e, 0x06},
+               {0x579f, 0x20},
+               {0x57a0, 0x04},
+               {0x57a1, 0xa0},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00}
 };
 
-static const s64 link_freq_menu_items[] = {
-       OV8856_LINK_FREQ_360MHZ,
-       OV8856_LINK_FREQ_180MHZ
+static const struct ov8856_reg lane_4_mode_3264x2448[] = {
+       /* 3264x2448 resolution */
+               {0x0103, 0x01},
+               {0x0302, 0x3c},
+               {0x0303, 0x01},
+               {0x031e, 0x0c},
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x72},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x9a},
+               {0x3502, 0x20},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x60},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366d, 0x00},
+               {0x366e, 0x10},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x23},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x04},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x0c},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xa3},
+               {0x3808, 0x0c},
+               {0x3809, 0xc0},
+               {0x380a, 0x09},
+               {0x380b, 0x90},
+               {0x380c, 0x07},
+               {0x380d, 0x8c},
+               {0x380e, 0x09},
+               {0x380f, 0xb2},
+               {0x3810, 0x00},
+               {0x3811, 0x04},
+               {0x3812, 0x00},
+               {0x3813, 0x01},
+               {0x3814, 0x01},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x10},
+               {0x3820, 0x80},
+               {0x3821, 0x46},
+               {0x382a, 0x01},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x17},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x0b},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4502, 0x50},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x50},
+               {0x481f, 0x27},
+               {0x4823, 0x3c},
+               {0x482b, 0x00},
+               {0x4831, 0x66},
+               {0x4837, 0x16},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x77},
+               {0x5001, 0x0a},
+               {0x5003, 0xc8},
+               {0x5004, 0x04},
+               {0x5006, 0x00},
+               {0x5007, 0x00},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x5795, 0x02},
+               {0x5796, 0x20},
+               {0x5797, 0x20},
+               {0x5798, 0xd5},
+               {0x5799, 0xd5},
+               {0x579a, 0x00},
+               {0x579b, 0x50},
+               {0x579c, 0x00},
+               {0x579d, 0x2c},
+               {0x579e, 0x0c},
+               {0x579f, 0x40},
+               {0x57a0, 0x09},
+               {0x57a1, 0x40},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00},
+               {0x5e10, 0xfc}
 };
 
-static const struct ov8856_link_freq_config link_freq_configs[] = {
-       [OV8856_LINK_FREQ_720MBPS] = {
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mipi_data_rate_720mbps),
-                       .regs = mipi_data_rate_720mbps,
-               }
-       },
-       [OV8856_LINK_FREQ_360MBPS] = {
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mipi_data_rate_360mbps),
-                       .regs = mipi_data_rate_360mbps,
-               }
-       }
+static const struct ov8856_reg lane_4_mode_1632x1224[] = {
+       /* 1632x1224 resolution */
+               {0x0103, 0x01},
+               {0x0302, 0x3c},
+               {0x0303, 0x01},
+               {0x031e, 0x0c},
+               {0x3000, 0x20},
+               {0x3003, 0x08},
+               {0x300e, 0x20},
+               {0x3010, 0x00},
+               {0x3015, 0x84},
+               {0x3018, 0x72},
+               {0x3021, 0x23},
+               {0x3033, 0x24},
+               {0x3500, 0x00},
+               {0x3501, 0x4c},
+               {0x3502, 0xe0},
+               {0x3503, 0x08},
+               {0x3505, 0x83},
+               {0x3508, 0x01},
+               {0x3509, 0x80},
+               {0x350c, 0x00},
+               {0x350d, 0x80},
+               {0x350e, 0x04},
+               {0x350f, 0x00},
+               {0x3510, 0x00},
+               {0x3511, 0x02},
+               {0x3512, 0x00},
+               {0x3600, 0x72},
+               {0x3601, 0x40},
+               {0x3602, 0x30},
+               {0x3610, 0xc5},
+               {0x3611, 0x58},
+               {0x3612, 0x5c},
+               {0x3613, 0xca},
+               {0x3614, 0x60},
+               {0x3628, 0xff},
+               {0x3629, 0xff},
+               {0x362a, 0xff},
+               {0x3633, 0x10},
+               {0x3634, 0x10},
+               {0x3635, 0x10},
+               {0x3636, 0x10},
+               {0x3663, 0x08},
+               {0x3669, 0x34},
+               {0x366d, 0x00},
+               {0x366e, 0x08},
+               {0x3706, 0x86},
+               {0x370b, 0x7e},
+               {0x3714, 0x27},
+               {0x3730, 0x12},
+               {0x3733, 0x10},
+               {0x3764, 0x00},
+               {0x3765, 0x00},
+               {0x3769, 0x62},
+               {0x376a, 0x2a},
+               {0x376b, 0x30},
+               {0x3780, 0x00},
+               {0x3781, 0x24},
+               {0x3782, 0x00},
+               {0x3783, 0x23},
+               {0x3798, 0x2f},
+               {0x37a1, 0x60},
+               {0x37a8, 0x6a},
+               {0x37ab, 0x3f},
+               {0x37c2, 0x14},
+               {0x37c3, 0xf1},
+               {0x37c9, 0x80},
+               {0x37cb, 0x16},
+               {0x37cc, 0x16},
+               {0x37cd, 0x16},
+               {0x37ce, 0x16},
+               {0x3800, 0x00},
+               {0x3801, 0x00},
+               {0x3802, 0x00},
+               {0x3803, 0x0c},
+               {0x3804, 0x0c},
+               {0x3805, 0xdf},
+               {0x3806, 0x09},
+               {0x3807, 0xa3},
+               {0x3808, 0x06},
+               {0x3809, 0x60},
+               {0x380a, 0x04},
+               {0x380b, 0xc8},
+               {0x380c, 0x07},
+               {0x380d, 0x8c},
+               {0x380e, 0x09},
+               {0x380f, 0xb2},
+               {0x3810, 0x00},
+               {0x3811, 0x02},
+               {0x3812, 0x00},
+               {0x3813, 0x01},
+               {0x3814, 0x03},
+               {0x3815, 0x01},
+               {0x3816, 0x00},
+               {0x3817, 0x00},
+               {0x3818, 0x00},
+               {0x3819, 0x10},
+               {0x3820, 0x80},
+               {0x3821, 0x47},
+               {0x382a, 0x03},
+               {0x382b, 0x01},
+               {0x3830, 0x06},
+               {0x3836, 0x02},
+               {0x3862, 0x04},
+               {0x3863, 0x08},
+               {0x3cc0, 0x33},
+               {0x3d85, 0x17},
+               {0x3d8c, 0x73},
+               {0x3d8d, 0xde},
+               {0x4001, 0xe0},
+               {0x4003, 0x40},
+               {0x4008, 0x00},
+               {0x4009, 0x05},
+               {0x400a, 0x00},
+               {0x400b, 0x84},
+               {0x400f, 0x80},
+               {0x4010, 0xf0},
+               {0x4011, 0xff},
+               {0x4012, 0x02},
+               {0x4013, 0x01},
+               {0x4014, 0x01},
+               {0x4015, 0x01},
+               {0x4042, 0x00},
+               {0x4043, 0x80},
+               {0x4044, 0x00},
+               {0x4045, 0x80},
+               {0x4046, 0x00},
+               {0x4047, 0x80},
+               {0x4048, 0x00},
+               {0x4049, 0x80},
+               {0x4041, 0x03},
+               {0x404c, 0x20},
+               {0x404d, 0x00},
+               {0x404e, 0x20},
+               {0x4203, 0x80},
+               {0x4307, 0x30},
+               {0x4317, 0x00},
+               {0x4502, 0x50},
+               {0x4503, 0x08},
+               {0x4601, 0x80},
+               {0x4800, 0x44},
+               {0x4816, 0x53},
+               {0x481b, 0x50},
+               {0x481f, 0x27},
+               {0x4823, 0x3c},
+               {0x482b, 0x00},
+               {0x4831, 0x66},
+               {0x4837, 0x16},
+               {0x483c, 0x0f},
+               {0x484b, 0x05},
+               {0x5000, 0x77},
+               {0x5001, 0x0a},
+               {0x5003, 0xc8},
+               {0x5004, 0x04},
+               {0x5006, 0x00},
+               {0x5007, 0x00},
+               {0x502e, 0x03},
+               {0x5030, 0x41},
+               {0x5795, 0x00},
+               {0x5796, 0x10},
+               {0x5797, 0x10},
+               {0x5798, 0x73},
+               {0x5799, 0x73},
+               {0x579a, 0x00},
+               {0x579b, 0x28},
+               {0x579c, 0x00},
+               {0x579d, 0x16},
+               {0x579e, 0x06},
+               {0x579f, 0x20},
+               {0x57a0, 0x04},
+               {0x57a1, 0xa0},
+               {0x5780, 0x14},
+               {0x5781, 0x0f},
+               {0x5782, 0x44},
+               {0x5783, 0x02},
+               {0x5784, 0x01},
+               {0x5785, 0x01},
+               {0x5786, 0x00},
+               {0x5787, 0x04},
+               {0x5788, 0x02},
+               {0x5789, 0x0f},
+               {0x578a, 0xfd},
+               {0x578b, 0xf5},
+               {0x578c, 0xf5},
+               {0x578d, 0x03},
+               {0x578e, 0x08},
+               {0x578f, 0x0c},
+               {0x5790, 0x08},
+               {0x5791, 0x04},
+               {0x5792, 0x00},
+               {0x5793, 0x52},
+               {0x5794, 0xa3},
+               {0x59f8, 0x3d},
+               {0x5a08, 0x02},
+               {0x5b00, 0x02},
+               {0x5b01, 0x10},
+               {0x5b02, 0x03},
+               {0x5b03, 0xcf},
+               {0x5b05, 0x6c},
+               {0x5e00, 0x00},
+               {0x5e10, 0xfc}
 };
 
-static const struct ov8856_mode supported_modes[] = {
-       {
-               .width = 3280,
-               .height = 2464,
-               .hts = 1928,
-               .vts_def = 2488,
-               .vts_min = 2488,
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
-                       .regs = mode_3280x2464_regs,
-               },
-               .link_freq_index = OV8856_LINK_FREQ_720MBPS,
-       },
-       {
-               .width = 3264,
-               .height = 2448,
-               .hts = 1932,
-               .vts_def = 2482,
-               .vts_min = 2482,
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
-                       .regs = mode_3264x2448_regs,
-               },
-               .link_freq_index = OV8856_LINK_FREQ_720MBPS,
-       },
-       {
-               .width = 1640,
-               .height = 1232,
-               .hts = 3820,
-               .vts_def = 1256,
-               .vts_min = 1256,
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
-                       .regs = mode_1640x1232_regs,
-               },
-               .link_freq_index = OV8856_LINK_FREQ_360MBPS,
-       },
-       {
-               .width = 1632,
-               .height = 1224,
-               .hts = 1932,
-               .vts_def = 2482,
-               .vts_min = 2482,
-               .reg_list = {
-                       .num_of_regs = ARRAY_SIZE(mode_1632x1224_regs),
-                       .regs = mode_1632x1224_regs,
-               },
-               .link_freq_index = OV8856_LINK_FREQ_360MBPS,
-       }
+static const char * const ov8856_test_pattern_menu[] = {
+       "Disabled",
+       "Standard Color Bar",
+       "Top-Bottom Darker Color Bar",
+       "Right-Left Darker Color Bar",
+       "Bottom-Top Darker Color Bar"
 };
 
 struct ov8856 {
@@ -1037,20 +1404,173 @@ struct ov8856 {
 
        /* Streaming on/off */
        bool streaming;
+
+       /* lanes index */
+       u8 nlanes;
+
+       const struct ov8856_lane_cfg *priv_lane;
+       u8 modes_size;
+};
+
+struct ov8856_lane_cfg {
+       const s64 link_freq_menu_items[2];
+       const struct ov8856_link_freq_config link_freq_configs[2];
+       const struct ov8856_mode supported_modes[4];
+};
+
+static const struct ov8856_lane_cfg lane_cfg_2 = {
+       {
+               720000000,
+               360000000,
+       },
+       {{
+               .reg_list = {
+                       .num_of_regs =
+                       ARRAY_SIZE(mipi_data_rate_lane_2.regs_0),
+                       .regs = mipi_data_rate_lane_2.regs_0,
+               }
+       },
+       {
+               .reg_list = {
+                       .num_of_regs =
+                       ARRAY_SIZE(mipi_data_rate_lane_2.regs_1),
+                       .regs = mipi_data_rate_lane_2.regs_1,
+               }
+       }},
+       {{
+               .width = 3280,
+               .height = 2464,
+               .hts = 1928,
+               .vts_def = 2488,
+               .vts_min = 2488,
+               .reg_list = {
+                       .num_of_regs =
+                       ARRAY_SIZE(lane_2_mode_3280x2464),
+                       .regs = lane_2_mode_3280x2464,
+               },
+               .link_freq_index = 0,
+               .data_lanes = 2,
+       },
+       {
+               .width = 1640,
+               .height = 1232,
+               .hts = 3168,
+               .vts_def = 1514,
+               .vts_min = 1514,
+               .reg_list = {
+                       .num_of_regs =
+                       ARRAY_SIZE(lane_2_mode_1640x1232),
+                       .regs = lane_2_mode_1640x1232,
+               },
+               .link_freq_index = 1,
+               .data_lanes = 2,
+       }}
 };
 
-static u64 to_pixel_rate(u32 f_index)
+static const struct ov8856_lane_cfg lane_cfg_4 = {
+               {
+                       360000000,
+                       180000000,
+               },
+               {{
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(mipi_data_rate_lane_4.regs_0),
+                               .regs = mipi_data_rate_lane_4.regs_0,
+                       }
+               },
+               {
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(mipi_data_rate_lane_4.regs_1),
+                               .regs = mipi_data_rate_lane_4.regs_1,
+                       }
+               }},
+               {{
+                       .width = 3280,
+                       .height = 2464,
+                       .hts = 1928,
+                       .vts_def = 2488,
+                       .vts_min = 2488,
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(lane_4_mode_3280x2464),
+                               .regs = lane_4_mode_3280x2464,
+                       },
+                       .link_freq_index = 0,
+                       .data_lanes = 4,
+               },
+               {
+                       .width = 1640,
+                       .height = 1232,
+                       .hts = 3820,
+                       .vts_def = 1256,
+                       .vts_min = 1256,
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(lane_4_mode_1640x1232),
+                               .regs = lane_4_mode_1640x1232,
+                       },
+                       .link_freq_index = 1,
+                       .data_lanes = 4,
+               },
+               {
+                       .width = 3264,
+                       .height = 2448,
+                       .hts = 1932,
+                       .vts_def = 2482,
+                       .vts_min = 2482,
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(lane_4_mode_3264x2448),
+                               .regs = lane_4_mode_3264x2448,
+                       },
+                       .link_freq_index = 0,
+                       .data_lanes = 4,
+               },
+               {
+                       .width = 1632,
+                       .height = 1224,
+                       .hts = 1932,
+                       .vts_def = 2482,
+                       .vts_min = 2482,
+                       .reg_list = {
+                               .num_of_regs =
+                                ARRAY_SIZE(lane_4_mode_1632x1224),
+                               .regs = lane_4_mode_1632x1224,
+                       },
+                       .link_freq_index = 1,
+                       .data_lanes = 4,
+               }}
+};
+
+static unsigned int ov8856_modes_num(const struct ov8856 *ov8856)
 {
-       u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV8856_DATA_LANES;
+       unsigned int i, count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(ov8856->priv_lane->supported_modes); i++) {
+               if (ov8856->priv_lane->supported_modes[i].width == 0)
+                       break;
+               count++;
+       }
+
+       return count;
+}
+
+static u64 to_rate(const s64 *link_freq_menu_items,
+                  u32 f_index, u8 nlanes)
+{
+       u64 pixel_rate = link_freq_menu_items[f_index] * 2 * nlanes;
 
        do_div(pixel_rate, OV8856_RGB_DEPTH);
 
        return pixel_rate;
 }
 
-static u64 to_pixels_per_line(u32 hts, u32 f_index)
+static u64 to_pixels_per_line(const s64 *link_freq_menu_items, u32 hts,
+                             u32 f_index, u8 nlanes)
 {
-       u64 ppl = hts * to_pixel_rate(f_index);
+       u64 ppl = hts * to_rate(link_freq_menu_items, f_index, nlanes);
 
        do_div(ppl, OV8856_SCLK);
 
@@ -1152,6 +1672,93 @@ static int ov8856_test_pattern(struct ov8856 *ov8856, u32 pattern)
                                OV8856_REG_VALUE_08BIT, pattern);
 }
 
+static int ov8856_set_ctrl_hflip(struct ov8856 *ov8856, u32 ctrl_val)
+{
+       int ret;
+       u32 val;
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       ret = ov8856_write_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+                              OV8856_REG_VALUE_08BIT,
+                              ctrl_val ? val & ~OV8856_REG_MIRROR_OP_2 :
+                              val | OV8856_REG_MIRROR_OP_2);
+
+       if (ret)
+               return ret;
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT2,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       return ov8856_write_reg(ov8856, OV8856_REG_FORMAT2,
+                               OV8856_REG_VALUE_08BIT,
+                               ctrl_val ? val & ~OV8856_REG_FORMAT2_OP_1 &
+                               ~OV8856_REG_FORMAT2_OP_2 &
+                               ~OV8856_REG_FORMAT2_OP_3 :
+                               val | OV8856_REG_FORMAT2_OP_1 |
+                               OV8856_REG_FORMAT2_OP_2 |
+                               OV8856_REG_FORMAT2_OP_3);
+}
+
+static int ov8856_set_ctrl_vflip(struct ov8856 *ov8856, u8 ctrl_val)
+{
+       int ret;
+       u32 val;
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+                              OV8856_REG_VALUE_08BIT,
+                              ctrl_val ? val | OV8856_REG_FLIP_OP_1 |
+                              OV8856_REG_FLIP_OP_2 :
+                              val & ~OV8856_REG_FLIP_OP_1 &
+                              ~OV8856_REG_FLIP_OP_2);
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+                              OV8856_REG_VALUE_08BIT,
+                              ctrl_val ? val | OV8856_REG_FLIP_OP_2 :
+                              val & ~OV8856_REG_FLIP_OP_2);
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+                              OV8856_REG_VALUE_08BIT,
+                              ctrl_val ? val & ~OV8856_REG_FLIP_OP_0 &
+                              ~OV8856_REG_FLIP_OP_1 :
+                              val | OV8856_REG_FLIP_OP_0 |
+                              OV8856_REG_FLIP_OP_1);
+
+       ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT1,
+                             OV8856_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       return ov8856_write_reg(ov8856, OV8856_REG_FORMAT1,
+                              OV8856_REG_VALUE_08BIT,
+                              ctrl_val ? val | OV8856_REG_FORMAT1_OP_1 |
+                              OV8856_REG_FORMAT1_OP_3 |
+                              OV8856_REG_FORMAT1_OP_2 :
+                              val & ~OV8856_REG_FORMAT1_OP_1 &
+                              ~OV8856_REG_FORMAT1_OP_3 &
+                              ~OV8856_REG_FORMAT1_OP_2);
+}
+
 static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct ov8856 *ov8856 = container_of(ctrl->handler,
@@ -1201,6 +1808,14 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
                ret = ov8856_test_pattern(ov8856, ctrl->val);
                break;
 
+       case V4L2_CID_HFLIP:
+               ret = ov8856_set_ctrl_hflip(ov8856, ctrl->val);
+               break;
+
+       case V4L2_CID_VFLIP:
+               ret = ov8856_set_ctrl_vflip(ov8856, ctrl->val);
+               break;
+
        default:
                ret = -EINVAL;
                break;
@@ -1229,23 +1844,32 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
        ctrl_hdlr->lock = &ov8856->mutex;
        ov8856->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov8856_ctrl_ops,
                                           V4L2_CID_LINK_FREQ,
-                                          ARRAY_SIZE(link_freq_menu_items) - 1,
-                                          0, link_freq_menu_items);
+                                          ARRAY_SIZE
+                                          (ov8856->priv_lane->link_freq_menu_items)
+                                          - 1,
+                                          0, ov8856->priv_lane->link_freq_menu_items);
        if (ov8856->link_freq)
                ov8856->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        ov8856->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
                                       V4L2_CID_PIXEL_RATE, 0,
-                                      to_pixel_rate(OV8856_LINK_FREQ_720MBPS),
-                                      1,
-                                      to_pixel_rate(OV8856_LINK_FREQ_720MBPS));
+                                      to_rate(ov8856->priv_lane->link_freq_menu_items,
+                                              0,
+                                              ov8856->cur_mode->data_lanes), 1,
+                                      to_rate(ov8856->priv_lane->link_freq_menu_items,
+                                              0,
+                                              ov8856->cur_mode->data_lanes));
        ov8856->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
                          V4L2_CID_VBLANK,
                          ov8856->cur_mode->vts_min - ov8856->cur_mode->height,
                          OV8856_VTS_MAX - ov8856->cur_mode->height, 1,
-                         ov8856->cur_mode->vts_def - ov8856->cur_mode->height);
-       h_blank = to_pixels_per_line(ov8856->cur_mode->hts,
-                 ov8856->cur_mode->link_freq_index) - ov8856->cur_mode->width;
+                         ov8856->cur_mode->vts_def -
+                         ov8856->cur_mode->height);
+       h_blank = to_pixels_per_line(ov8856->priv_lane->link_freq_menu_items,
+                                    ov8856->cur_mode->hts,
+                                    ov8856->cur_mode->link_freq_index,
+                                    ov8856->cur_mode->data_lanes) -
+                                    ov8856->cur_mode->width;
        ov8856->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
                                           V4L2_CID_HBLANK, h_blank, h_blank, 1,
                                           h_blank);
@@ -1268,6 +1892,10 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
                                     V4L2_CID_TEST_PATTERN,
                                     ARRAY_SIZE(ov8856_test_pattern_menu) - 1,
                                     0, 0, ov8856_test_pattern_menu);
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+                         V4L2_CID_VFLIP, 0, 1, 1, 0);
        if (ctrl_hdlr->error)
                return ctrl_hdlr->error;
 
@@ -1292,7 +1920,8 @@ static int ov8856_start_streaming(struct ov8856 *ov8856)
        int link_freq_index, ret;
 
        link_freq_index = ov8856->cur_mode->link_freq_index;
-       reg_list = &link_freq_configs[link_freq_index].reg_list;
+       reg_list = &ov8856->priv_lane->link_freq_configs[link_freq_index].reg_list;
+
        ret = ov8856_write_reg_list(ov8856, reg_list);
        if (ret) {
                dev_err(&client->dev, "failed to set plls");
@@ -1340,9 +1969,8 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable)
 
        mutex_lock(&ov8856->mutex);
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
                        mutex_unlock(&ov8856->mutex);
                        return ret;
                }
@@ -1455,27 +2083,29 @@ static int __maybe_unused ov8856_resume(struct device *dev)
 }
 
 static int ov8856_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov8856 *ov8856 = to_ov8856(sd);
        const struct ov8856_mode *mode;
        s32 vblank_def, h_blank;
 
-       mode = v4l2_find_nearest_size(supported_modes,
-                                     ARRAY_SIZE(supported_modes), width,
-                                     height, fmt->format.width,
+       mode = v4l2_find_nearest_size(ov8856->priv_lane->supported_modes,
+                                     ov8856->modes_size,
+                                     width, height, fmt->format.width,
                                      fmt->format.height);
 
        mutex_lock(&ov8856->mutex);
        ov8856_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov8856->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov8856->link_freq, mode->link_freq_index);
                __v4l2_ctrl_s_ctrl_int64(ov8856->pixel_rate,
-                                        to_pixel_rate(mode->link_freq_index));
+                                        to_rate(ov8856->priv_lane->link_freq_menu_items,
+                                                mode->link_freq_index,
+                                                ov8856->cur_mode->data_lanes));
 
                /* Update limits and set FPS to default */
                vblank_def = mode->vts_def - mode->height;
@@ -1484,8 +2114,11 @@ static int ov8856_set_format(struct v4l2_subdev *sd,
                                         OV8856_VTS_MAX - mode->height, 1,
                                         vblank_def);
                __v4l2_ctrl_s_ctrl(ov8856->vblank, vblank_def);
-               h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
-                         mode->width;
+               h_blank = to_pixels_per_line(ov8856->priv_lane->link_freq_menu_items,
+                                            mode->hts,
+                                            mode->link_freq_index,
+                                            ov8856->cur_mode->data_lanes)
+                                            - mode->width;
                __v4l2_ctrl_modify_range(ov8856->hblank, h_blank, h_blank, 1,
                                         h_blank);
        }
@@ -1496,14 +2129,15 @@ static int ov8856_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov8856_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov8856 *ov8856 = to_ov8856(sd);
 
        mutex_lock(&ov8856->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                ov8856_update_pad_format(ov8856->cur_mode, &fmt->format);
@@ -1514,7 +2148,7 @@ static int ov8856_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov8856_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        /* Only one bayer order GRBG is supported */
@@ -1527,18 +2161,20 @@ static int ov8856_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov8856_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
-       if (fse->index >= ARRAY_SIZE(supported_modes))
+       struct ov8856 *ov8856 = to_ov8856(sd);
+
+       if (fse->index >= ov8856->modes_size)
                return -EINVAL;
 
        if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
                return -EINVAL;
 
-       fse->min_width = supported_modes[fse->index].width;
+       fse->min_width = ov8856->priv_lane->supported_modes[fse->index].width;
        fse->max_width = fse->min_width;
-       fse->min_height = supported_modes[fse->index].height;
+       fse->min_height = ov8856->priv_lane->supported_modes[fse->index].height;
        fse->max_height = fse->min_height;
 
        return 0;
@@ -1549,8 +2185,8 @@ static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        struct ov8856 *ov8856 = to_ov8856(sd);
 
        mutex_lock(&ov8856->mutex);
-       ov8856_update_pad_format(&supported_modes[0],
-                                v4l2_subdev_get_try_format(sd, fh->pad, 0));
+       ov8856_update_pad_format(&ov8856->priv_lane->supported_modes[0],
+                                v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&ov8856->mutex);
 
        return 0;
@@ -1696,29 +2332,40 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev)
        if (ret)
                return ret;
 
-       if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV8856_DATA_LANES) {
+       /* Get number of data lanes */
+       if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
+           bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
                dev_err(dev, "number of CSI2 data lanes %d is not supported",
                        bus_cfg.bus.mipi_csi2.num_data_lanes);
                ret = -EINVAL;
                goto check_hwcfg_error;
        }
 
+       dev_dbg(dev, "Using %u data lanes\n", ov8856->cur_mode->data_lanes);
+
+       if (bus_cfg.bus.mipi_csi2.num_data_lanes == 2)
+               ov8856->priv_lane = &lane_cfg_2;
+       else
+               ov8856->priv_lane = &lane_cfg_4;
+
+       ov8856->modes_size = ov8856_modes_num(ov8856);
+
        if (!bus_cfg.nr_of_link_frequencies) {
                dev_err(dev, "no link frequencies defined");
                ret = -EINVAL;
                goto check_hwcfg_error;
        }
 
-       for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
+       for (i = 0; i < ARRAY_SIZE(ov8856->priv_lane->link_freq_menu_items); i++) {
                for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
-                       if (link_freq_menu_items[i] ==
-                               bus_cfg.link_frequencies[j])
+                       if (ov8856->priv_lane->link_freq_menu_items[i] ==
+                           bus_cfg.link_frequencies[j])
                                break;
                }
 
                if (j == bus_cfg.nr_of_link_frequencies) {
                        dev_err(dev, "no link frequency %lld supported",
-                               link_freq_menu_items[i]);
+                               ov8856->priv_lane->link_freq_menu_items[i]);
                        ret = -EINVAL;
                        goto check_hwcfg_error;
                }
@@ -1777,7 +2424,7 @@ static int ov8856_probe(struct i2c_client *client)
        }
 
        mutex_init(&ov8856->mutex);
-       ov8856->cur_mode = &supported_modes[0];
+       ov8856->cur_mode = &ov8856->priv_lane->supported_modes[0];
        ret = ov8856_init_controls(ov8856);
        if (ret) {
                dev_err(&client->dev, "failed to init controls: %d", ret);
index 9ecf180..ce50f3e 100644 (file)
@@ -2497,11 +2497,9 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
        int ret;
 
        if (enable) {
-               ret = pm_runtime_get_sync(sensor->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(sensor->dev);
+               ret = pm_runtime_resume_and_get(sensor->dev);
+               if (ret < 0)
                        return ret;
-               }
        }
 
        mutex_lock(&sensor->mutex);
@@ -2544,7 +2542,7 @@ static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
 /* Subdev Pad Operations */
 
 static int ov8865_enum_mbus_code(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *config,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code_enum)
 {
        if (code_enum->index >= ARRAY_SIZE(ov8865_mbus_codes))
@@ -2573,7 +2571,7 @@ static void ov8865_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format,
 }
 
 static int ov8865_get_fmt(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *config,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
@@ -2582,7 +2580,7 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev,
        mutex_lock(&sensor->mutex);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               *mbus_format = *v4l2_subdev_get_try_format(subdev, config,
+               *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
                                                           format->pad);
        else
                ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code,
@@ -2594,7 +2592,7 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev,
 }
 
 static int ov8865_set_fmt(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *config,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
@@ -2635,7 +2633,7 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev,
        ov8865_mbus_format_fill(mbus_format, mbus_code, mode);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               *v4l2_subdev_get_try_format(subdev, config, format->pad) =
+               *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
                        *mbus_format;
        else if (sensor->state.mode != mode ||
                 sensor->state.mbus_code != mbus_code)
@@ -2648,7 +2646,7 @@ complete:
 }
 
 static int ov8865_enum_frame_size(struct v4l2_subdev *subdev,
-                                 struct v4l2_subdev_pad_config *config,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *size_enum)
 {
        const struct ov8865_mode *mode;
@@ -2665,7 +2663,7 @@ static int ov8865_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev,
-                                     struct v4l2_subdev_pad_config *config,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_interval_enum *interval_enum)
 {
        const struct ov8865_mode *mode = NULL;
@@ -2691,7 +2689,7 @@ static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev,
                }
        }
 
-       if (mode_index == ARRAY_SIZE(ov8865_modes) || !mode)
+       if (mode_index == ARRAY_SIZE(ov8865_modes))
                return -EINVAL;
 
        interval_enum->interval = mode->frame_interval;
index d36b04c..0bab8c2 100644 (file)
@@ -519,7 +519,7 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
 }
 
 static int ov9640_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -547,13 +547,13 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return ov9640_s_fmt(sd, mf);
 
-       cfg->try_fmt = *mf;
+       sd_state->pads->try_fmt = *mf;
 
        return 0;
 }
 
 static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes))
@@ -565,7 +565,7 @@ static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov9640_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_selection *sel)
 {
        if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
index 4fe68aa..c313e11 100644 (file)
@@ -1070,7 +1070,7 @@ static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf)
 }
 
 static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(ov965x_formats))
@@ -1081,7 +1081,7 @@ static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        int i = ARRAY_SIZE(ov965x_formats);
@@ -1167,14 +1167,14 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov965x_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct ov965x *ov965x = to_ov965x(sd);
        struct v4l2_mbus_framefmt *mf;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                fmt->format = *mf;
                return 0;
        }
@@ -1212,7 +1212,7 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf,
 }
 
 static int ov965x_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        unsigned int index = ARRAY_SIZE(ov965x_formats);
@@ -1234,8 +1234,9 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd,
        mutex_lock(&ov965x->lock);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               if (cfg) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               if (sd_state) {
+                       mf = v4l2_subdev_get_try_format(sd, sd_state,
+                                                       fmt->pad);
                        *mf = fmt->format;
                }
        } else {
@@ -1364,7 +1365,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
 static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *mf =
-               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+               v4l2_subdev_get_try_format(sd, fh->state, 0);
 
        ov965x_get_default_format(mf);
        return 0;
@@ -1479,8 +1480,8 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
                if (ov965x->id == OV9650_ID || ov965x->id == OV9652_ID) {
                        v4l2_info(sd, "Found OV%04X sensor\n", ov965x->id);
                } else {
-                       v4l2_err(sd, "Sensor detection failed (%04X, %d)\n",
-                                ov965x->id, ret);
+                       v4l2_err(sd, "Sensor detection failed (%04X)\n",
+                                ov965x->id);
                        ret = -ENODEV;
                }
        }
index b7309a5..af50c66 100644 (file)
@@ -644,9 +644,8 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable)
        }
 
        if (enable) {
-               ret = pm_runtime_get_sync(&client->dev);
+               ret = pm_runtime_resume_and_get(&client->dev);
                if (ret < 0) {
-                       pm_runtime_put_noidle(&client->dev);
                        mutex_unlock(&ov9734->mutex);
                        return ret;
                }
@@ -706,7 +705,7 @@ exit:
 }
 
 static int ov9734_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov9734 *ov9734 = to_ov9734(sd);
@@ -721,7 +720,7 @@ static int ov9734_set_format(struct v4l2_subdev *sd,
        mutex_lock(&ov9734->mutex);
        ov9734_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov9734->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov9734->link_freq, mode->link_freq_index);
@@ -747,14 +746,15 @@ static int ov9734_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov9734_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ov9734 *ov9734 = to_ov9734(sd);
 
        mutex_lock(&ov9734->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd, cfg,
+               fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd,
+                                                         sd_state,
                                                          fmt->pad);
        else
                ov9734_update_pad_format(ov9734->cur_mode, &fmt->format);
@@ -765,7 +765,7 @@ static int ov9734_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov9734_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -777,7 +777,7 @@ static int ov9734_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov9734_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -800,7 +800,7 @@ static int ov9734_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&ov9734->mutex);
        ov9734_update_pad_format(&supported_modes[0],
-                                v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                                v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&ov9734->mutex);
 
        return 0;
index 90eb73f..025a610 100644 (file)
@@ -312,7 +312,7 @@ static const struct ov10635_reg {
 
 struct rdacm20_device {
        struct device                   *dev;
-       struct max9271_device           *serializer;
+       struct max9271_device           serializer;
        struct i2c_client               *sensor;
        struct v4l2_subdev              sd;
        struct media_pad                pad;
@@ -399,11 +399,11 @@ static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct rdacm20_device *dev = sd_to_rdacm20(sd);
 
-       return max9271_set_serial_link(dev->serializer, enable);
+       return max9271_set_serial_link(&dev->serializer, enable);
 }
 
 static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -415,7 +415,7 @@ static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int rdacm20_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -455,12 +455,10 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
        unsigned int retry = 3;
        int ret;
 
-       /* Verify communication with the MAX9271: ping to wakeup. */
-       dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
-       i2c_smbus_read_byte(dev->serializer->client);
+       max9271_wake_up(&dev->serializer);
 
        /* Serial link disabled during config as it needs a valid pixel clock. */
-       ret = max9271_set_serial_link(dev->serializer, false);
+       ret = max9271_set_serial_link(&dev->serializer, false);
        if (ret)
                return ret;
 
@@ -468,38 +466,48 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
         *  Ensure that we have a good link configuration before attempting to
         *  identify the device.
         */
-       max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
-                                              MAX9271_I2CSLVTO_1024US |
-                                              MAX9271_I2CMSTBT_105KBPS);
-
-       max9271_configure_gmsl_link(dev->serializer);
-
-       ret = max9271_verify_id(dev->serializer);
-       if (ret < 0)
-               return ret;
-
-       ret = max9271_set_address(dev->serializer, dev->addrs[0]);
-       if (ret < 0)
+       ret = max9271_configure_i2c(&dev->serializer,
+                                   MAX9271_I2CSLVSH_469NS_234NS |
+                                   MAX9271_I2CSLVTO_1024US |
+                                   MAX9271_I2CMSTBT_105KBPS);
+       if (ret)
                return ret;
-       dev->serializer->client->addr = dev->addrs[0];
 
        /*
-        * Reset the sensor by cycling the OV10635 reset signal connected to the
-        * MAX9271 GPIO1 and verify communication with the OV10635.
+        * Hold OV10635 in reset during max9271 configuration. The reset signal
+        * has to be asserted for at least 200 microseconds.
         */
-       ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT);
+       ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
+       if (ret)
+               return ret;
+
+       ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
        if (ret)
                return ret;
+       usleep_range(200, 500);
 
-       ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT);
+       ret = max9271_configure_gmsl_link(&dev->serializer);
        if (ret)
                return ret;
-       usleep_range(10000, 15000);
 
-       ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT);
+       ret = max9271_verify_id(&dev->serializer);
+       if (ret < 0)
+               return ret;
+
+       ret = max9271_set_address(&dev->serializer, dev->addrs[0]);
+       if (ret < 0)
+               return ret;
+       dev->serializer.client->addr = dev->addrs[0];
+
+       /*
+        * Release ov10635 from reset and initialize it. The image sensor
+        * requires at least 2048 XVCLK cycles (85 micro-seconds at 24MHz)
+        * before being available. Stay safe and wait up to 500 micro-seconds.
+        */
+       ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);
        if (ret)
                return ret;
-       usleep_range(10000, 15000);
+       usleep_range(100, 500);
 
 again:
        ret = ov10635_read16(dev, OV10635_PID);
@@ -539,9 +547,21 @@ again:
        if (ret)
                return ret;
 
-       dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
+       dev_info(dev->dev, "Identified RDACM20 camera module\n");
 
-       return 0;
+       /*
+        * Set reverse channel high threshold to increase noise immunity.
+        *
+        * This should be compensated by increasing the reverse channel
+        * amplitude on the remote deserializer side.
+        *
+        * TODO Inspect the embedded MCU programming sequence to make sure
+        * there are no conflicts with the configuration applied here.
+        *
+        * TODO Clarify the embedded MCU startup delay to avoid write
+        * collisions on the I2C bus.
+        */
+       return max9271_set_high_threshold(&dev->serializer, true);
 }
 
 static int rdacm20_probe(struct i2c_client *client)
@@ -554,13 +574,7 @@ static int rdacm20_probe(struct i2c_client *client)
        if (!dev)
                return -ENOMEM;
        dev->dev = &client->dev;
-
-       dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
-                                      GFP_KERNEL);
-       if (!dev->serializer)
-               return -ENOMEM;
-
-       dev->serializer->client = client;
+       dev->serializer.client = client;
 
        ret = of_property_read_u32_array(client->dev.of_node, "reg",
                                         dev->addrs, 2);
index 179d107..12ec546 100644 (file)
@@ -69,6 +69,7 @@
 #define OV490_ISP_VSIZE_LOW            0x80820062
 #define OV490_ISP_VSIZE_HIGH           0x80820063
 
+#define OV10640_PID_TIMEOUT            20
 #define OV10640_ID_HIGH                        0xa6
 #define OV10640_CHIP_ID                        0x300a
 #define OV10640_PIXEL_RATE             55000000
@@ -281,7 +282,7 @@ static int rdacm21_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int rdacm21_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index > 0)
@@ -293,7 +294,7 @@ static int rdacm21_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int rdacm21_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -329,30 +330,51 @@ static const struct v4l2_subdev_ops rdacm21_subdev_ops = {
        .pad            = &rdacm21_subdev_pad_ops,
 };
 
-static int ov10640_initialize(struct rdacm21_device *dev)
+static void ov10640_power_up(struct rdacm21_device *dev)
 {
-       u8 val;
-
-       /* Power-up OV10640 by setting RESETB and PWDNB pins high. */
+       /* Enable GPIO0#0 (reset) and GPIO1#0 (pwdn) as output lines. */
        ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
        ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
        ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);
        ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);
+
+       /* Power up OV10640 and then reset it. */
+       ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);
+       usleep_range(1500, 3000);
+
+       ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, 0x00);
+       usleep_range(1500, 3000);
        ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
-       ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_SPWDN0);
        usleep_range(3000, 5000);
+}
 
-       /* Read OV10640 ID to test communications. */
-       ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
-       ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
-       ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff);
-
-       /* Trigger SCCB slave transaction and give it some time to complete. */
-       ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
-       usleep_range(1000, 1500);
+static int ov10640_check_id(struct rdacm21_device *dev)
+{
+       unsigned int i;
+       u8 val;
 
-       ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
-       if (val != OV10640_ID_HIGH) {
+       /* Read OV10640 ID to test communications. */
+       for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
+               ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR,
+                               OV490_SCCB_SLAVE_READ);
+               ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH,
+                               OV10640_CHIP_ID >> 8);
+               ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW,
+                               OV10640_CHIP_ID & 0xff);
+
+               /*
+                * Trigger SCCB slave transaction and give it some time
+                * to complete.
+                */
+               ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
+               usleep_range(1000, 1500);
+
+               ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
+               if (val == OV10640_ID_HIGH)
+                       break;
+               usleep_range(1000, 1500);
+       }
+       if (i == OV10640_PID_TIMEOUT) {
                dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val);
                return -ENODEV;
        }
@@ -368,6 +390,8 @@ static int ov490_initialize(struct rdacm21_device *dev)
        unsigned int i;
        int ret;
 
+       ov10640_power_up(dev);
+
        /*
         * Read OV490 Id to test communications. Give it up to 40msec to
         * exit from reset.
@@ -405,7 +429,7 @@ static int ov490_initialize(struct rdacm21_device *dev)
                return -ENODEV;
        }
 
-       ret = ov10640_initialize(dev);
+       ret = ov10640_check_id(dev);
        if (ret)
                return ret;
 
@@ -450,10 +474,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
 {
        int ret;
 
-       /* Verify communication with the MAX9271: ping to wakeup. */
-       dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
-       i2c_smbus_read_byte(dev->serializer.client);
-       usleep_range(3000, 5000);
+       max9271_wake_up(&dev->serializer);
 
        /* Enable reverse channel and disable the serial link. */
        ret = max9271_set_serial_link(&dev->serializer, false);
@@ -472,7 +493,10 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
        if (ret)
                return ret;
 
-       /* Enable GPIO1 and hold OV490 in reset during max9271 configuration. */
+       /*
+        * Enable GPIO1 and hold OV490 in reset during max9271 configuration.
+        * The reset signal has to be asserted for at least 250 useconds.
+        */
        ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
        if (ret)
                return ret;
@@ -480,6 +504,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
        ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
        if (ret)
                return ret;
+       usleep_range(250, 500);
 
        ret = max9271_configure_gmsl_link(&dev->serializer);
        if (ret)
index 4cc51e0..2e4018c 100644 (file)
@@ -488,7 +488,7 @@ static int reg_write_multiple(struct i2c_client *client,
 }
 
 static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts))
@@ -541,7 +541,7 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
                               s32 *out_w, s32 *out_h);
 
 static int rj54n1_set_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -578,7 +578,7 @@ static int rj54n1_set_selection(struct v4l2_subdev *sd,
 }
 
 static int rj54n1_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -603,7 +603,7 @@ static int rj54n1_get_selection(struct v4l2_subdev *sd,
 }
 
 static int rj54n1_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -973,7 +973,7 @@ static int rj54n1_reg_init(struct i2c_client *client)
 }
 
 static int rj54n1_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -1009,7 +1009,7 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd,
                              &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
+               sd_state->pads->try_fmt = *mf;
                return 0;
        }
 
index 5b4c4a3..e2b88c5 100644 (file)
@@ -817,7 +817,7 @@ static const struct s5c73m3_frame_size *s5c73m3_find_frame_size(
 }
 
 static void s5c73m3_oif_try_format(struct s5c73m3 *state,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *fmt,
                                   const struct s5c73m3_frame_size **fs)
 {
@@ -844,8 +844,8 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
                        *fs = state->oif_pix_size[RES_ISP];
                else
                        *fs = s5c73m3_find_frame_size(
-                                               v4l2_subdev_get_try_format(sd, cfg,
-                                                       OIF_ISP_PAD),
+                                               v4l2_subdev_get_try_format(sd, sd_state,
+                                                                          OIF_ISP_PAD),
                                                RES_ISP);
                break;
        }
@@ -854,7 +854,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
 }
 
 static void s5c73m3_try_format(struct s5c73m3 *state,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt,
                              const struct s5c73m3_frame_size **fs)
 {
@@ -946,7 +946,7 @@ static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -984,7 +984,7 @@ static int s5c73m3_oif_get_pad_code(int pad, int index)
 }
 
 static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
@@ -992,7 +992,8 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
        u32 code;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+                                                         fmt->pad);
                return 0;
        }
 
@@ -1018,7 +1019,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -1026,7 +1027,8 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
        u32 code;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+                                                         fmt->pad);
                return 0;
        }
 
@@ -1056,7 +1058,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1066,10 +1068,10 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&state->lock);
 
-       s5c73m3_try_format(state, cfg, fmt, &frame_size);
+       s5c73m3_try_format(state, sd_state, fmt, &frame_size);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
        } else {
                switch (fmt->pad) {
@@ -1095,7 +1097,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_subdev_format *fmt)
 {
        const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1105,13 +1107,14 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&state->lock);
 
-       s5c73m3_oif_try_format(state, cfg, fmt, &frame_size);
+       s5c73m3_oif_try_format(state, sd_state, fmt, &frame_size);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
                if (fmt->pad == OIF_ISP_PAD) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD);
+                       mf = v4l2_subdev_get_try_format(sd, sd_state,
+                                                       OIF_SOURCE_PAD);
                        mf->width = fmt->format.width;
                        mf->height = fmt->format.height;
                }
@@ -1183,7 +1186,7 @@ static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
 }
 
 static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        static const int codes[] = {
@@ -1199,7 +1202,7 @@ static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        int ret;
@@ -1214,7 +1217,7 @@ static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        int idx;
@@ -1241,7 +1244,7 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -1259,7 +1262,7 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
                        if (fse->which == V4L2_SUBDEV_FORMAT_TRY) {
                                struct v4l2_mbus_framefmt *mf;
 
-                               mf = v4l2_subdev_get_try_format(sd, cfg,
+                               mf = v4l2_subdev_get_try_format(sd, sd_state,
                                                                OIF_ISP_PAD);
 
                                w = mf->width;
@@ -1315,11 +1318,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *mf;
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_ISP_PAD);
        s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
                                                S5C73M3_ISP_FMT);
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_JPEG_PAD);
        s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
                                        S5C73M3_JPEG_FMT);
 
@@ -1330,15 +1333,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *mf;
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_ISP_PAD);
        s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
                                                S5C73M3_ISP_FMT);
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_JPEG_PAD);
        s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
                                        S5C73M3_JPEG_FMT);
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_SOURCE_PAD);
        s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
                                                S5C73M3_ISP_FMT);
        return 0;
@@ -1386,7 +1389,7 @@ static int __s5c73m3_power_on(struct s5c73m3 *state)
        s5c73m3_gpio_deassert(state, STBY);
        usleep_range(100, 200);
 
-       s5c73m3_gpio_deassert(state, RST);
+       s5c73m3_gpio_deassert(state, RSET);
        usleep_range(50, 100);
 
        return 0;
@@ -1401,7 +1404,7 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
 {
        int i, ret;
 
-       if (s5c73m3_gpio_assert(state, RST))
+       if (s5c73m3_gpio_assert(state, RSET))
                usleep_range(10, 50);
 
        if (s5c73m3_gpio_assert(state, STBY))
@@ -1606,7 +1609,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
 
                state->mclk_frequency = pdata->mclk_frequency;
                state->gpio[STBY] = pdata->gpio_stby;
-               state->gpio[RST] = pdata->gpio_reset;
+               state->gpio[RSET] = pdata->gpio_reset;
                return 0;
        }
 
index ef7e85b..c3fcfdd 100644 (file)
@@ -353,7 +353,7 @@ struct s5c73m3_ctrls {
 
 enum s5c73m3_gpio_id {
        STBY,
-       RST,
+       RSET,
        GPIO_NUM,
 };
 
index b2d5341..af9a305 100644 (file)
@@ -173,7 +173,7 @@ static const char * const s5k4ecgx_supply_names[] = {
 
 enum s5k4ecgx_gpio_id {
        STBY,
-       RST,
+       RSET,
        GPIO_NUM,
 };
 
@@ -476,7 +476,7 @@ static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
        if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level))
                usleep_range(30, 50);
 
-       if (s5k4ecgx_gpio_set_value(priv, RST, priv->gpio[RST].level))
+       if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level))
                usleep_range(30, 50);
 
        return 0;
@@ -484,7 +484,7 @@ static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
 
 static int __s5k4ecgx_power_off(struct s5k4ecgx *priv)
 {
-       if (s5k4ecgx_gpio_set_value(priv, RST, !priv->gpio[RST].level))
+       if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level))
                usleep_range(30, 50);
 
        if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level))
@@ -525,7 +525,7 @@ static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf,
 }
 
 static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
@@ -535,15 +535,16 @@ static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                          struct v4l2_subdev_format *fmt)
+static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_subdev_state *sd_state,
+                           struct v4l2_subdev_format *fmt)
 {
        struct s5k4ecgx *priv = to_s5k4ecgx(sd);
        struct v4l2_mbus_framefmt *mf;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               if (cfg) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               if (sd_state) {
+                       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                        fmt->format = *mf;
                }
                return 0;
@@ -575,7 +576,8 @@ static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd,
        return &s5k4ecgx_formats[i];
 }
 
-static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct s5k4ecgx *priv = to_s5k4ecgx(sd);
@@ -590,8 +592,8 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_confi
        fmt->format.field = V4L2_FIELD_NONE;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               if (cfg) {
-                       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               if (sd_state) {
+                       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                        *mf = fmt->format;
                }
                return 0;
@@ -686,7 +688,9 @@ static int s5k4ecgx_registered(struct v4l2_subdev *sd)
  */
 static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
+                                                                  fh->state,
+                                                                  0);
 
        mf->width = s5k4ecgx_prev_sizes[0].size.width;
        mf->height = s5k4ecgx_prev_sizes[0].size.height;
@@ -872,7 +876,7 @@ static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
        int ret;
 
        priv->gpio[STBY].gpio = -EINVAL;
-       priv->gpio[RST].gpio  = -EINVAL;
+       priv->gpio[RSET].gpio  = -EINVAL;
 
        ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY");
 
@@ -891,7 +895,7 @@ static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
                s5k4ecgx_free_gpios(priv);
                return ret;
        }
-       priv->gpio[RST] = *gpio;
+       priv->gpio[RSET] = *gpio;
        if (gpio_is_valid(gpio->gpio))
                gpio_set_value(gpio->gpio, 0);
 
index 6e702b5..6a5dceb 100644 (file)
@@ -235,7 +235,7 @@ struct s5k5baf_gpio {
 
 enum s5k5baf_gpio_id {
        STBY,
-       RST,
+       RSET,
        NUM_GPIOS,
 };
 
@@ -969,7 +969,7 @@ static int s5k5baf_power_on(struct s5k5baf *state)
 
        s5k5baf_gpio_deassert(state, STBY);
        usleep_range(50, 100);
-       s5k5baf_gpio_deassert(state, RST);
+       s5k5baf_gpio_deassert(state, RSET);
        return 0;
 
 err_reg_dis:
@@ -987,7 +987,7 @@ static int s5k5baf_power_off(struct s5k5baf *state)
        state->apply_cfg = 0;
        state->apply_crop = 0;
 
-       s5k5baf_gpio_assert(state, RST);
+       s5k5baf_gpio_assert(state, RSET);
        s5k5baf_gpio_assert(state, STBY);
 
        if (!IS_ERR(state->clock))
@@ -1180,7 +1180,7 @@ static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
  * V4L2 subdev pad level and video operations
  */
 static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_frame_interval_enum *fie)
 {
        if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME ||
@@ -1199,7 +1199,7 @@ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad == PAD_CIS) {
@@ -1217,7 +1217,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int i;
@@ -1274,15 +1274,16 @@ static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf)
        return pixfmt;
 }
 
-static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
+static int s5k5baf_get_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
+                          struct v4l2_subdev_format *fmt)
 {
        struct s5k5baf *state = to_s5k5baf(sd);
        const struct s5k5baf_pixfmt *pixfmt;
        struct v4l2_mbus_framefmt *mf;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *mf;
                return 0;
        }
@@ -1304,8 +1305,9 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        return 0;
 }
 
-static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *fmt)
+static int s5k5baf_set_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
+                          struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *mf = &fmt->format;
        struct s5k5baf *state = to_s5k5baf(sd);
@@ -1315,7 +1317,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        mf->field = V4L2_FIELD_NONE;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = *mf;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = *mf;
                return 0;
        }
 
@@ -1367,7 +1369,7 @@ static int s5k5baf_is_bound_target(u32 target)
 }
 
 static int s5k5baf_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        enum selection_rect rtype;
@@ -1387,9 +1389,11 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd,
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
                if (rtype == R_COMPOSE)
-                       sel->r = *v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+                       sel->r = *v4l2_subdev_get_try_compose(sd, sd_state,
+                                                             sel->pad);
                else
-                       sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+                       sel->r = *v4l2_subdev_get_try_crop(sd, sd_state,
+                                                          sel->pad);
                return 0;
        }
 
@@ -1458,7 +1462,7 @@ static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1,
 }
 
 static int s5k5baf_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        static enum selection_rect rtype;
@@ -1479,9 +1483,12 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
                rects = (struct v4l2_rect * []) {
                                &s5k5baf_cis_rect,
-                               v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
-                               v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
-                               v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+                               v4l2_subdev_get_try_crop(sd, sd_state,
+                                                        PAD_CIS),
+                               v4l2_subdev_get_try_compose(sd, sd_state,
+                                                           PAD_CIS),
+                               v4l2_subdev_get_try_crop(sd, sd_state,
+                                                        PAD_OUT)
                        };
                s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
                return 0;
@@ -1699,22 +1706,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
        struct v4l2_mbus_framefmt *mf;
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_CIS);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_CIS);
        s5k5baf_try_cis_format(mf);
 
        if (s5k5baf_is_cis_subdev(sd))
                return 0;
 
-       mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_OUT);
+       mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_OUT);
        mf->colorspace = s5k5baf_formats[0].colorspace;
        mf->code = s5k5baf_formats[0].code;
        mf->width = s5k5baf_cis_rect.width;
        mf->height = s5k5baf_cis_rect.height;
        mf->field = V4L2_FIELD_NONE;
 
-       *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
-       *v4l2_subdev_get_try_compose(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
-       *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_OUT) = s5k5baf_cis_rect;
+       *v4l2_subdev_get_try_crop(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
+       *v4l2_subdev_get_try_compose(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
+       *v4l2_subdev_get_try_crop(sd, fh->state, PAD_OUT) = s5k5baf_cis_rect;
 
        return 0;
 }
index f26c168..b97dd61 100644 (file)
@@ -99,7 +99,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format(
 }
 
 static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(s5k6a3_formats))
@@ -123,17 +123,18 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
 }
 
 static struct v4l2_mbus_framefmt *__s5k6a3_get_format(
-               struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg,
+               struct s5k6a3 *sensor, struct v4l2_subdev_state *sd_state,
                u32 pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL;
+               return sd_state ? v4l2_subdev_get_try_format(&sensor->subdev,
+                                                            sd_state, pad) : NULL;
 
        return &sensor->format;
 }
 
 static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *fmt)
 {
        struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
@@ -141,7 +142,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
 
        s5k6a3_try_format(&fmt->format);
 
-       mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
+       mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
        if (mf) {
                mutex_lock(&sensor->lock);
                *mf = fmt->format;
@@ -151,13 +152,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int s5k6a3_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
        struct v4l2_mbus_framefmt *mf;
 
-       mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
+       mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
 
        mutex_lock(&sensor->lock);
        fmt->format = *mf;
@@ -173,7 +174,9 @@ static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
 
 static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+                                                                      fh->state,
+                                                                      0);
 
        *format         = s5k6a3_formats[0];
        format->width   = S5K6A3_DEFAULT_WIDTH;
index 038e385..105a4b7 100644 (file)
@@ -177,7 +177,7 @@ static const char * const s5k6aa_supply_names[] = {
 
 enum s5k6aa_gpio_id {
        STBY,
-       RST,
+       RSET,
        GPIO_NUM,
 };
 
@@ -841,7 +841,7 @@ static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
                ret = s5k6aa->s_power(1);
        usleep_range(4000, 5000);
 
-       if (s5k6aa_gpio_deassert(s5k6aa, RST))
+       if (s5k6aa_gpio_deassert(s5k6aa, RSET))
                msleep(20);
 
        return ret;
@@ -851,7 +851,7 @@ static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
 {
        int ret;
 
-       if (s5k6aa_gpio_assert(s5k6aa, RST))
+       if (s5k6aa_gpio_assert(s5k6aa, RSET))
                usleep_range(100, 150);
 
        if (s5k6aa->s_power) {
@@ -997,7 +997,7 @@ static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
  * V4L2 subdev pad level and video operations
  */
 static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1024,7 +1024,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(s5k6aa_formats))
@@ -1035,7 +1035,7 @@ static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int i = ARRAY_SIZE(s5k6aa_formats);
@@ -1057,14 +1057,15 @@ static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static struct v4l2_rect *
-__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg,
+__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa,
+                      struct v4l2_subdev_state *sd_state,
                       enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return &s5k6aa->ccd_rect;
 
        WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
-       return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0);
+       return v4l2_subdev_get_try_crop(&s5k6aa->sd, sd_state, 0);
 }
 
 static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
@@ -1088,7 +1089,8 @@ static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
        mf->field       = V4L2_FIELD_NONE;
 }
 
-static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k6aa_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1097,7 +1099,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        memset(fmt->reserved, 0, sizeof(fmt->reserved));
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
                fmt->format = *mf;
                return 0;
        }
@@ -1109,7 +1111,8 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        return 0;
 }
 
-static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k6aa_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1122,8 +1125,8 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        s5k6aa_try_format(s5k6aa, &fmt->format);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
-               crop = v4l2_subdev_get_try_crop(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+               crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
        } else {
                if (s5k6aa->streaming) {
                        ret = -EBUSY;
@@ -1163,7 +1166,7 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
 }
 
 static int s5k6aa_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1175,7 +1178,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
        memset(sel->reserved, 0, sizeof(sel->reserved));
 
        mutex_lock(&s5k6aa->lock);
-       rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
+       rect = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
        sel->r = *rect;
        mutex_unlock(&s5k6aa->lock);
 
@@ -1186,7 +1189,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
 }
 
 static int s5k6aa_set_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1198,13 +1201,13 @@ static int s5k6aa_set_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        mutex_lock(&s5k6aa->lock);
-       crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
+       crop_r = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                mf = &s5k6aa->preset->mbus_fmt;
                s5k6aa->apply_crop = 1;
        } else {
-               mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
        }
        v4l_bound_align_image(&sel->r.width, mf->width,
                              S5K6AA_WIN_WIDTH_MAX, 1,
@@ -1425,8 +1428,10 @@ static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
  */
 static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
-       struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+                                                                      fh->state,
+                                                                      0);
+       struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
 
        format->colorspace = s5k6aa_formats[0].colorspace;
        format->code = s5k6aa_formats[0].code;
@@ -1510,7 +1515,7 @@ static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
        int ret;
 
        s5k6aa->gpio[STBY].gpio = -EINVAL;
-       s5k6aa->gpio[RST].gpio  = -EINVAL;
+       s5k6aa->gpio[RSET].gpio  = -EINVAL;
 
        gpio = &pdata->gpio_stby;
        if (gpio_is_valid(gpio->gpio)) {
@@ -1533,7 +1538,7 @@ static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
                if (ret < 0)
                        return ret;
 
-               s5k6aa->gpio[RST] = *gpio;
+               s5k6aa->gpio[RSET] = *gpio;
        }
 
        return 0;
index ecb491d..d1e0716 100644 (file)
@@ -380,7 +380,7 @@ static void saa6588_configure(struct saa6588 *s)
 
 /* ---------------------------------------------------------------------- */
 
-static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+static long saa6588_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
        struct saa6588 *s = to_saa6588(sd);
        struct saa6588_command *a = arg;
@@ -433,7 +433,7 @@ static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_subdev_core_ops saa6588_core_ops = {
-       .ioctl = saa6588_ioctl,
+       .command = saa6588_command,
 };
 
 static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
index 6171ced..a7f043c 100644 (file)
@@ -543,7 +543,7 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
 }
 
 static int saa6752hs_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *f = &format->format;
@@ -563,7 +563,7 @@ static int saa6752hs_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int saa6752hs_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *f = &format->format;
@@ -595,7 +595,7 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd,
        f->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *f;
+               sd_state->pads->try_fmt = *f;
                return 0;
        }
 
index 88dc6ba..a958bbc 100644 (file)
@@ -1167,7 +1167,7 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
 }
 
 static int saa711x_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
index ba103a6..adf9053 100644 (file)
@@ -980,7 +980,7 @@ static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
 #endif
 
 static int saa717x_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
index 4692402..19c0252 100644 (file)
@@ -468,7 +468,7 @@ static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (!code || code->pad ||
@@ -480,7 +480,7 @@ static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int sr030pc30_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf;
@@ -525,7 +525,7 @@ static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
 
 /* Return nearest media bus frame format. */
 static int sr030pc30_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct sr030pc30_info *info = sd ? to_sr030pc30(sd) : NULL;
@@ -541,7 +541,7 @@ static int sr030pc30_set_fmt(struct v4l2_subdev *sd,
 
        fmt = try_fmt(sd, mf);
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
+               sd_state->pads->try_fmt = *mf;
                return 0;
        }
 
index 7f07ef5..f630b88 100644 (file)
@@ -643,7 +643,7 @@ out:
 }
 
 static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -670,7 +670,7 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int mipid02_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
@@ -687,7 +687,8 @@ static int mipid02_get_fmt(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state,
+                                                format->pad);
        else
                fmt = &bridge->fmt;
 
@@ -704,7 +705,7 @@ static int mipid02_get_fmt(struct v4l2_subdev *sd,
 }
 
 static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *format)
 {
        struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -718,11 +719,11 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
        if (format->which != V4L2_SUBDEV_FORMAT_TRY)
                return;
 
-       *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format;
+       *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = format->format;
 }
 
 static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *format)
 {
        struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -731,7 +732,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
        format->format.code = get_fmt_code(format->format.code);
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
        else
                fmt = &bridge->fmt;
 
@@ -739,7 +740,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
 }
 
 static int mipid02_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -762,9 +763,9 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd,
        }
 
        if (format->pad == MIPID02_SOURCE)
-               mipid02_set_fmt_source(sd, cfg, format);
+               mipid02_set_fmt_source(sd, sd_state, format);
        else
-               mipid02_set_fmt_sink(sd, cfg, format);
+               mipid02_set_fmt_sink(sd, sd_state, format);
 
 error:
        mutex_unlock(&bridge->lock);
index 1b309bb..3205cd8 100644 (file)
@@ -1649,7 +1649,7 @@ static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
 /* --------------- PAD OPS --------------- */
 
 static int tc358743_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        switch (code->index) {
@@ -1666,7 +1666,7 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int tc358743_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct tc358743_state *state = to_state(sd);
@@ -1702,13 +1702,13 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int tc358743_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct tc358743_state *state = to_state(sd);
 
        u32 code = format->format.code; /* is overwritten by get_fmt */
-       int ret = tc358743_get_fmt(sd, cfg, format);
+       int ret = tc358743_get_fmt(sd, sd_state, format);
 
        format->format.code = code;
 
@@ -1974,6 +1974,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
        bps_pr_lane = 2 * endpoint.link_frequencies[0];
        if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
                dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
+               ret = -EINVAL;
                goto disable_clk;
        }
 
index 89bb7e6..91e6db8 100644 (file)
@@ -1718,19 +1718,19 @@ static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
  */
 
 static int tda1997x_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg)
+                            struct v4l2_subdev_state *sd_state)
 {
        struct tda1997x_state *state = to_state(sd);
        struct v4l2_mbus_framefmt *mf;
 
-       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
        mf->code = state->mbus_codes[0];
 
        return 0;
 }
 
 static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct tda1997x_state *state = to_state(sd);
@@ -1762,7 +1762,7 @@ static void tda1997x_fill_format(struct tda1997x_state *state,
 }
 
 static int tda1997x_get_format(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *format)
 {
        struct tda1997x_state *state = to_state(sd);
@@ -1775,7 +1775,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                format->format.code = fmt->code;
        } else
                format->format.code = state->mbus_code;
@@ -1784,7 +1784,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd,
 }
 
 static int tda1997x_set_format(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *format)
 {
        struct tda1997x_state *state = to_state(sd);
@@ -1809,7 +1809,7 @@ static int tda1997x_set_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+               fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
                *fmt = format->format;
        } else {
                int ret = tda1997x_setup_format(state, format->format.code);
index a7fbe5b..cee60f9 100644 (file)
@@ -853,13 +853,13 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
 /**
  * tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code
  * @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
  * @code: pointer to v4l2_subdev_mbus_code_enum structure
  *
  * Enumertaes mbus codes supported
  */
 static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        u32 pad = code->pad;
@@ -880,13 +880,13 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
 /**
  * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format
  * @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
  * @format: pointer to v4l2_subdev_format structure
  *
  * Retrieves pad format which is active or tried based on requirement
  */
 static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *format)
 {
        struct tvp514x_decoder *decoder = to_decoder(sd);
@@ -912,13 +912,13 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
 /**
  * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format
  * @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
  * @fmt: pointer to v4l2_subdev_format structure
  *
  * Set pad format for the output pad
  */
 static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_format *fmt)
 {
        struct tvp514x_decoder *decoder = to_decoder(sd);
index e26e3f5..30c6355 100644 (file)
@@ -1027,7 +1027,7 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
 
 static struct v4l2_rect *
 tvp5150_get_pad_crop(struct tvp5150 *decoder,
-                    struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                    struct v4l2_subdev_state *sd_state, unsigned int pad,
                     enum v4l2_subdev_format_whence which)
 {
        switch (which) {
@@ -1035,7 +1035,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder,
                return &decoder->rect;
        case V4L2_SUBDEV_FORMAT_TRY:
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-               return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&decoder->sd, sd_state, pad);
 #else
                return ERR_PTR(-EINVAL);
 #endif
@@ -1045,7 +1045,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder,
 }
 
 static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *f;
@@ -1104,7 +1104,7 @@ static void tvp5150_set_hw_selection(struct v4l2_subdev *sd,
 }
 
 static int tvp5150_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1138,7 +1138,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
            sel->which == V4L2_SUBDEV_FORMAT_TRY)
                return 0;
 
-       crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
+       crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad, sel->which);
        if (IS_ERR(crop))
                return PTR_ERR(crop);
 
@@ -1156,7 +1156,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 }
 
 static int tvp5150_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
@@ -1180,7 +1180,7 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
                        sel->r.height = TVP5150_V_MAX_OTHERS;
                return 0;
        case V4L2_SEL_TGT_CROP:
-               crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad,
+               crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad,
                                            sel->which);
                if (IS_ERR(crop))
                        return PTR_ERR(crop);
@@ -1208,7 +1208,7 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
                        V4L2 subdev pad ops
  ****************************************************************************/
 static int tvp5150_init_cfg(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg)
+                           struct v4l2_subdev_state *sd_state)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
        v4l2_std_id std;
@@ -1229,7 +1229,7 @@ static int tvp5150_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index)
@@ -1240,7 +1240,7 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1448,11 +1448,9 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
               TVP5150_MISC_CTL_CLOCK_OE;
 
        if (enable) {
-               ret = pm_runtime_get_sync(sd->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(sd->dev);
+               ret = pm_runtime_resume_and_get(sd->dev);
+               if (ret < 0)
                        return ret;
-               }
 
                tvp5150_enable(sd);
 
@@ -1675,15 +1673,7 @@ err:
 
 static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 {
-       int ret;
-
-       ret = pm_runtime_get_sync(sd->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(sd->dev);
-               return ret;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(sd->dev);
 }
 
 static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
index ada4ec5..2de1883 100644 (file)
@@ -797,7 +797,8 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
  * Enumerate supported digital video formats for pad.
  */
 static int
-tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_enum_mbus_code(struct v4l2_subdev *sd,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_mbus_code_enum *code)
 {
        /* Check requested format index is within range */
@@ -818,7 +819,8 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf
  * get video format for pad.
  */
 static int
-tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_get_pad_format(struct v4l2_subdev *sd,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *fmt)
 {
        struct tvp7002 *tvp7002 = to_tvp7002(sd);
@@ -841,10 +843,11 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf
  * set video format for pad.
  */
 static int
-tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_set_pad_format(struct v4l2_subdev *sd,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *fmt)
 {
-       return tvp7002_get_pad_format(sd, cfg, fmt);
+       return tvp7002_get_pad_format(sd, sd_state, fmt);
 }
 
 /* V4L2 core operation handlers */
index a25a350..09f5b39 100644 (file)
@@ -720,7 +720,7 @@ tw9910_set_fmt_error:
 }
 
 static int tw9910_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -746,7 +746,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd,
 }
 
 static int tw9910_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
 }
 
 static int tw9910_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
@@ -829,7 +829,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return tw9910_s_fmt(sd, mf);
 
-       cfg->try_fmt = *mf;
+       sd_state->pads->try_fmt = *mf;
 
        return 0;
 }
@@ -886,7 +886,7 @@ static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
 };
 
 static int tw9910_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index)
index 0465832..de12f38 100644 (file)
@@ -286,11 +286,9 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type,
        __le16 buf;
        int tmp;
 
-       tmp = pm_runtime_get_sync(regmap_get_device(data->regmap));
-       if (tmp < 0) {
-               pm_runtime_put_noidle(regmap_get_device(data->regmap));
+       tmp = pm_runtime_resume_and_get(regmap_get_device(data->regmap));
+       if (tmp < 0)
                return tmp;
-       }
 
        tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2);
        pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
@@ -512,11 +510,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        if (data->kthread_vid_cap)
                return 0;
 
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(dev);
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
                goto error_del_list;
-       }
 
        ret = data->chip->setup(data);
        if (ret)
index c292c92..29003de 100644 (file)
@@ -546,7 +546,7 @@ static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
@@ -557,7 +557,7 @@ static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int vs6624_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -587,7 +587,7 @@ static int vs6624_set_fmt(struct v4l2_subdev *sd,
        fmt->colorspace = vs6624_formats[index].colorspace;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                return 0;
        }
 
@@ -637,7 +637,7 @@ static int vs6624_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int vs6624_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct vs6624 *sensor = to_vs6624(sd);
index 119037f..2b7af42 100644 (file)
@@ -3,7 +3,7 @@
 mc-objs        := mc-device.o mc-devnode.o mc-entity.o \
           mc-request.o
 
-ifeq ($(CONFIG_USB),y)
+ifneq ($(CONFIG_USB),)
        mc-objs += mc-dev-allocator.o
 endif
 
index 678b997..f40f419 100644 (file)
@@ -323,7 +323,7 @@ static void media_graph_walk_iter(struct media_graph *graph)
                return;
        }
 
-       /* Get the entity in the other end of the link . */
+       /* Get the entity at the other end of the link. */
        next = media_entity_other(entity, link);
 
        /* Has the entity already been visited? */
index c0782fd..addb8f2 100644 (file)
@@ -414,7 +414,8 @@ int media_request_object_bind(struct media_request *req,
 
        spin_lock_irqsave(&req->lock, flags);
 
-       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING &&
+                   req->state != MEDIA_REQUEST_STATE_QUEUED))
                goto unlock;
 
        obj->req = req;
index 78dd35c..90972d6 100644 (file)
@@ -300,7 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
                }
                if (astat & BT878_ARISCI) {
                        bt->finished_block = (stat & BT878_ARISCS) >> 28;
-                       tasklet_schedule(&bt->tasklet);
+                       if (bt->tasklet.callback)
+                               tasklet_schedule(&bt->tasklet);
                        break;
                }
                count++;
@@ -477,6 +478,9 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
        btwrite(0, BT878_AINT_MASK);
        bt878_num++;
 
+       if (!bt->tasklet.func)
+               tasklet_disable(&bt->tasklet);
+
        return 0;
 
       fail2:
index 1f62a9d..0e9df8b 100644 (file)
@@ -3179,7 +3179,7 @@ static int radio_release(struct file *file)
 
        btv->radio_user--;
 
-       bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+       bttv_call_all(btv, core, command, SAA6588_CMD_CLOSE, &cmd);
 
        if (btv->radio_user == 0)
                btv->has_radio_tuner = 0;
@@ -3260,7 +3260,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
        cmd.result = -ENODEV;
        radio_enable(btv);
 
-       bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
+       bttv_call_all(btv, core, command, SAA6588_CMD_READ, &cmd);
 
        return cmd.result;
 }
@@ -3281,7 +3281,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
        cmd.instance = file;
        cmd.event_list = wait;
        cmd.poll_mask = res;
-       bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
+       bttv_call_all(btv, core, command, SAA6588_CMD_POLL, &cmd);
 
        return cmd.poll_mask;
 }
index 839503e..16af58f 100644 (file)
@@ -667,6 +667,7 @@ static int cobalt_probe(struct pci_dev *pci_dev,
                return -ENOMEM;
        cobalt->pci_dev = pci_dev;
        cobalt->instance = i;
+       mutex_init(&cobalt->pci_lock);
 
        retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev);
        if (retval) {
index bca6857..12c33e0 100644 (file)
@@ -251,6 +251,8 @@ struct cobalt {
        int instance;
        struct pci_dev *pci_dev;
        struct v4l2_device v4l2_dev;
+       /* serialize PCI access in cobalt_s_bit_sysctrl() */
+       struct mutex pci_lock;
 
        void __iomem *bar0, *bar1;
 
@@ -320,10 +322,13 @@ static inline u32 cobalt_g_sysctrl(struct cobalt *cobalt)
 static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt,
                                        int bit, int val)
 {
-       u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
+       u32 ctrl;
 
+       mutex_lock(&cobalt->pci_lock);
+       ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
        cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE,
                        (ctrl & ~(1UL << bit)) | (val << bit));
+       mutex_unlock(&cobalt->pci_lock);
 }
 
 static inline u32 cobalt_g_sysstat(struct cobalt *cobalt)
index 11cfe35..76e5a50 100644 (file)
@@ -930,7 +930,7 @@ static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static int cx18_av_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
index c83814c..29fb131 100644 (file)
@@ -357,8 +357,8 @@ static int dsp_buffer_free(struct cx88_audio_dev *chip)
        cx88_alsa_dma_unmap(chip);
        cx88_alsa_dma_free(chip->buf);
        if (risc->cpu)
-               pci_free_consistent(chip->pci, risc->size,
-                                   risc->cpu, risc->dma);
+               dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu,
+                                 risc->dma);
        kfree(chip->buf);
 
        chip->buf = NULL;
@@ -868,7 +868,7 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
                return err;
        }
 
-       err = pci_set_dma_mask(pci, DMA_BIT_MASK(32));
+       err = dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
        if (err) {
                dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n", core->name);
                cx88_core_put(core, pci);
index fa4ca00..d5da3bd 100644 (file)
@@ -685,7 +685,8 @@ static void buffer_finish(struct vb2_buffer *vb)
        struct cx88_riscmem *risc = &buf->risc;
 
        if (risc->cpu)
-               pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+               dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+                                 risc->dma);
        memset(risc, 0, sizeof(*risc));
 }
 
index 48c8a34..89d4d5a 100644 (file)
@@ -152,7 +152,8 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc,
        instructions += 4;
        risc->size = instructions * 8;
        risc->dma = 0;
-       risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+       risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
+                                      GFP_KERNEL);
        if (!risc->cpu)
                return -ENOMEM;
 
@@ -190,7 +191,8 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc,
        instructions += 3;
        risc->size = instructions * 8;
        risc->dma = 0;
-       risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+       risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
+                                      GFP_KERNEL);
        if (!risc->cpu)
                return -ENOMEM;
 
index 202ff9e..2087f24 100644 (file)
@@ -103,7 +103,8 @@ static void buffer_finish(struct vb2_buffer *vb)
        struct cx88_riscmem *risc = &buf->risc;
 
        if (risc->cpu)
-               pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+               dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+                                 risc->dma);
        memset(risc, 0, sizeof(*risc));
 }
 
index a3edb54..680e1e3 100644 (file)
@@ -226,8 +226,8 @@ int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev,
                                  dev->ts_packet_size, dev->ts_packet_count, 0);
        if (rc) {
                if (risc->cpu)
-                       pci_free_consistent(dev->pci, risc->size,
-                                           risc->cpu, risc->dma);
+                       dma_free_coherent(&dev->pci->dev, risc->size,
+                                         risc->cpu, risc->dma);
                memset(risc, 0, sizeof(*risc));
                return rc;
        }
@@ -386,7 +386,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
        if (pci_enable_device(dev->pci))
                return -EIO;
        pci_set_master(dev->pci);
-       err = pci_set_dma_mask(dev->pci, DMA_BIT_MASK(32));
+       err = dma_set_mask(&dev->pci->dev, DMA_BIT_MASK(32));
        if (err) {
                pr_err("Oops: no 32bit PCI DMA ???\n");
                return -EIO;
index 58489ea..a075788 100644 (file)
@@ -159,7 +159,8 @@ static void buffer_finish(struct vb2_buffer *vb)
        struct cx88_riscmem *risc = &buf->risc;
 
        if (risc->cpu)
-               pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+               dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+                                 risc->dma);
        memset(risc, 0, sizeof(*risc));
 }
 
index 8cffdac..c17ad9f 100644 (file)
@@ -492,7 +492,8 @@ static void buffer_finish(struct vb2_buffer *vb)
        struct cx88_riscmem *risc = &buf->risc;
 
        if (risc->cpu)
-               pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+               dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+                                 risc->dma);
        memset(risc, 0, sizeof(*risc));
 }
 
@@ -1288,7 +1289,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
                (unsigned long long)pci_resource_start(pci_dev, 0));
 
        pci_set_master(pci_dev);
-       err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+       err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
        if (err) {
                pr_err("Oops: no 32bit PCI DMA ???\n");
                goto fail_core;
index e851178..4657e99 100644 (file)
@@ -173,14 +173,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
        int ret;
 
        for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
-               if (!adev->status.enabled)
+               if (!adev->status.enabled) {
+                       acpi_dev_put(adev);
                        continue;
+               }
 
                if (bridge->n_sensors >= CIO2_NUM_PORTS) {
+                       acpi_dev_put(adev);
                        dev_err(&cio2->dev, "Exceeded available CIO2 ports\n");
-                       cio2_bridge_unregister_sensors(bridge);
-                       ret = -EINVAL;
-                       goto err_out;
+                       return -EINVAL;
                }
 
                sensor = &bridge->sensors[bridge->n_sensors];
@@ -228,7 +229,6 @@ err_free_swnodes:
        software_node_unregister_nodes(sensor->swnodes);
 err_put_adev:
        acpi_dev_put(sensor->adev);
-err_out:
        return ret;
 }
 
index fecef85..47db0ee 100644 (file)
@@ -975,10 +975,9 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
        cio2->cur_queue = q;
        atomic_set(&q->frame_sequence, 0);
 
-       r = pm_runtime_get_sync(&cio2->pci_dev->dev);
+       r = pm_runtime_resume_and_get(&cio2->pci_dev->dev);
        if (r < 0) {
                dev_info(&cio2->pci_dev->dev, "failed to set power %d\n", r);
-               pm_runtime_put_noidle(&cio2->pci_dev->dev);
                return r;
        }
 
@@ -1200,11 +1199,11 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        };
 
        /* Initialize try_fmt */
-       format = v4l2_subdev_get_try_format(sd, fh->pad, CIO2_PAD_SINK);
+       format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SINK);
        *format = fmt_default;
 
        /* same as sink */
-       format = v4l2_subdev_get_try_format(sd, fh->pad, CIO2_PAD_SOURCE);
+       format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SOURCE);
        *format = fmt_default;
 
        return 0;
@@ -1218,7 +1217,7 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
  * return -EINVAL or zero on success
  */
 static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
@@ -1226,7 +1225,8 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
        mutex_lock(&q->subdev_lock);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+                                                         fmt->pad);
        else
                fmt->format = q->subdev_fmt;
 
@@ -1243,7 +1243,7 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
@@ -1256,10 +1256,10 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
         * source always propagates from sink
         */
        if (fmt->pad == CIO2_PAD_SOURCE)
-               return cio2_subdev_get_fmt(sd, cfg, fmt);
+               return cio2_subdev_get_fmt(sd, sd_state, fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               mbus = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mbus = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
        else
                mbus = &q->subdev_fmt;
 
@@ -1284,7 +1284,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int cio2_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(formats))
index c729e54..e705029 100644 (file)
@@ -29,18 +29,6 @@ config VIDEO_IVTV
          To compile this driver as a module, choose M here: the
          module will be called ivtv.
 
-config VIDEO_IVTV_DEPRECATED_IOCTLS
-       bool "enable the DVB ioctls abuse on ivtv driver"
-       depends on VIDEO_IVTV
-       help
-         Enable the usage of the a DVB set of ioctls that were abused by
-         IVTV driver for a while.
-
-         Those ioctls were not needed for a long time, as IVTV implements
-         the proper V4L2 ioctls since kernel 3.3.
-
-         If unsure, say N.
-
 config VIDEO_IVTV_ALSA
        tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture"
        depends on VIDEO_IVTV && SND
index e5efe52..4cf92de 100644 (file)
@@ -57,8 +57,6 @@
 #include <linux/uaccess.h>
 #include <asm/byteorder.h>
 
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
index 35dccb3..da19b2e 100644 (file)
 #include <media/i2c/saa7127.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-event.h>
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-#include <linux/compat.h>
-#include <linux/dvb/audio.h>
-#include <linux/dvb/video.h>
-#endif
 
 u16 ivtv_service2vbi(int type)
 {
@@ -1606,38 +1601,11 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder
        return ivtv_video_command(itv, id, dec, true);
 }
 
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-static __inline__ void warn_deprecated_ioctl(const char *name)
-{
-       pr_warn_once("warning: the %s ioctl is deprecated. Don't use it, as it will be removed soon\n",
-                    name);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_video_event {
-       __s32 type;
-       /* unused, make sure to use atomic time for y2038 if it ever gets used */
-       compat_long_t timestamp;
-       union {
-               video_size_t size;
-               unsigned int frame_rate;        /* in frames per 1000sec */
-               unsigned char vsync_field;      /* unknown/odd/even/progressive */
-       } u;
-};
-#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event)
-#endif
-
-#endif
-
 static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
 {
        struct ivtv_open_id *id = fh2id(filp->private_data);
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-       int nonblocking = filp->f_flags & O_NONBLOCK;
-       unsigned long iarg = (unsigned long)arg;
-#endif
 
        switch (cmd) {
        case IVTV_IOC_DMA_FRAME: {
@@ -1669,169 +1637,6 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
                return ivtv_passthrough_mode(itv, *(int *)arg != 0);
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-       case VIDEO_GET_PTS: {
-               s64 *pts = arg;
-               s64 frame;
-
-               warn_deprecated_ioctl("VIDEO_GET_PTS");
-               if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
-                       *pts = s->dma_pts;
-                       break;
-               }
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               return ivtv_g_pts_frame(itv, pts, &frame);
-       }
-
-       case VIDEO_GET_FRAME_COUNT: {
-               s64 *frame = arg;
-               s64 pts;
-
-               warn_deprecated_ioctl("VIDEO_GET_FRAME_COUNT");
-               if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
-                       *frame = 0;
-                       break;
-               }
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               return ivtv_g_pts_frame(itv, &pts, frame);
-       }
-
-       case VIDEO_PLAY: {
-               struct v4l2_decoder_cmd dc;
-
-               warn_deprecated_ioctl("VIDEO_PLAY");
-               memset(&dc, 0, sizeof(dc));
-               dc.cmd = V4L2_DEC_CMD_START;
-               return ivtv_video_command(itv, id, &dc, 0);
-       }
-
-       case VIDEO_STOP: {
-               struct v4l2_decoder_cmd dc;
-
-               warn_deprecated_ioctl("VIDEO_STOP");
-               memset(&dc, 0, sizeof(dc));
-               dc.cmd = V4L2_DEC_CMD_STOP;
-               dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
-               return ivtv_video_command(itv, id, &dc, 0);
-       }
-
-       case VIDEO_FREEZE: {
-               struct v4l2_decoder_cmd dc;
-
-               warn_deprecated_ioctl("VIDEO_FREEZE");
-               memset(&dc, 0, sizeof(dc));
-               dc.cmd = V4L2_DEC_CMD_PAUSE;
-               return ivtv_video_command(itv, id, &dc, 0);
-       }
-
-       case VIDEO_CONTINUE: {
-               struct v4l2_decoder_cmd dc;
-
-               warn_deprecated_ioctl("VIDEO_CONTINUE");
-               memset(&dc, 0, sizeof(dc));
-               dc.cmd = V4L2_DEC_CMD_RESUME;
-               return ivtv_video_command(itv, id, &dc, 0);
-       }
-
-       case VIDEO_COMMAND:
-       case VIDEO_TRY_COMMAND: {
-               /* Note: struct v4l2_decoder_cmd has the same layout as
-                  struct video_command */
-               struct v4l2_decoder_cmd *dc = arg;
-               int try = (cmd == VIDEO_TRY_COMMAND);
-
-               if (try)
-                       warn_deprecated_ioctl("VIDEO_TRY_COMMAND");
-               else
-                       warn_deprecated_ioctl("VIDEO_COMMAND");
-               return ivtv_video_command(itv, id, dc, try);
-       }
-
-#ifdef CONFIG_COMPAT
-       case VIDEO_GET_EVENT32:
-#endif
-       case VIDEO_GET_EVENT: {
-#ifdef CONFIG_COMPAT
-               struct compat_video_event *ev32 = arg;
-#endif
-               struct video_event *ev = arg;
-               DEFINE_WAIT(wait);
-
-               warn_deprecated_ioctl("VIDEO_GET_EVENT");
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               memset(ev, 0, sizeof(*ev));
-               set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
-
-               while (1) {
-                       if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
-                               ev->type = VIDEO_EVENT_DECODER_STOPPED;
-                       else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) {
-                               unsigned char vsync_field;
-
-                               ev->type = VIDEO_EVENT_VSYNC;
-                               vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ?
-                                       VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN;
-                               if (itv->output_mode == OUT_UDMA_YUV &&
-                                       (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) ==
-                                                               IVTV_YUV_MODE_PROGRESSIVE) {
-                                       vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE;
-                               }
-#ifdef CONFIG_COMPAT
-                               if (cmd == VIDEO_GET_EVENT32)
-                                       ev32->u.vsync_field = vsync_field;
-                               else
-#endif
-                                       ev->u.vsync_field = vsync_field;
-                       }
-                       if (ev->type)
-                               return 0;
-                       if (nonblocking)
-                               return -EAGAIN;
-                       /* Wait for event. Note that serialize_lock is locked,
-                          so to allow other processes to access the driver while
-                          we are waiting unlock first and later lock again. */
-                       mutex_unlock(&itv->serialize_lock);
-                       prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
-                       if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) &&
-                           !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags))
-                               schedule();
-                       finish_wait(&itv->event_waitq, &wait);
-                       mutex_lock(&itv->serialize_lock);
-                       if (signal_pending(current)) {
-                               /* return if a signal was received */
-                               IVTV_DEBUG_INFO("User stopped wait for event\n");
-                               return -EINTR;
-                       }
-               }
-               break;
-       }
-
-       case VIDEO_SELECT_SOURCE:
-               warn_deprecated_ioctl("VIDEO_SELECT_SOURCE");
-               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-                       return -EINVAL;
-               return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX);
-
-       case AUDIO_SET_MUTE:
-               warn_deprecated_ioctl("AUDIO_SET_MUTE");
-               itv->speed_mute_audio = iarg;
-               return 0;
-
-       case AUDIO_CHANNEL_SELECT:
-               warn_deprecated_ioctl("AUDIO_CHANNEL_SELECT");
-               if (iarg > AUDIO_STEREO_SWAPPED)
-                       return -EINVAL;
-               return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1);
-
-       case AUDIO_BILINGUAL_CHANNEL_SELECT:
-               warn_deprecated_ioctl("AUDIO_BILINGUAL_CHANNEL_SELECT");
-               if (iarg > AUDIO_STEREO_SWAPPED)
-                       return -EINVAL;
-               return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1);
-#endif
        default:
                return -EINVAL;
        }
@@ -1846,17 +1651,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        if (!valid_prio) {
                switch (cmd) {
                case IVTV_IOC_PASSTHROUGH_MODE:
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-               case VIDEO_PLAY:
-               case VIDEO_STOP:
-               case VIDEO_FREEZE:
-               case VIDEO_CONTINUE:
-               case VIDEO_COMMAND:
-               case VIDEO_SELECT_SOURCE:
-               case AUDIO_SET_MUTE:
-               case AUDIO_CHANNEL_SELECT:
-               case AUDIO_BILINGUAL_CHANNEL_SELECT:
-#endif
                        return -EBUSY;
                }
        }
@@ -1874,21 +1668,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
 
        case IVTV_IOC_DMA_FRAME:
        case IVTV_IOC_PASSTHROUGH_MODE:
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-       case VIDEO_GET_PTS:
-       case VIDEO_GET_FRAME_COUNT:
-       case VIDEO_GET_EVENT:
-       case VIDEO_PLAY:
-       case VIDEO_STOP:
-       case VIDEO_FREEZE:
-       case VIDEO_CONTINUE:
-       case VIDEO_COMMAND:
-       case VIDEO_TRY_COMMAND:
-       case VIDEO_SELECT_SOURCE:
-       case AUDIO_SET_MUTE:
-       case AUDIO_CHANNEL_SELECT:
-       case AUDIO_BILINGUAL_CHANNEL_SELECT:
-#endif
                return ivtv_decoder_ioctls(file, cmd, (void *)arg);
 
        default:
index efb757d..47158ab 100644 (file)
@@ -1031,7 +1031,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        dev->media_dev = kzalloc(sizeof(*dev->media_dev), GFP_KERNEL);
        if (!dev->media_dev) {
                err = -ENOMEM;
-               goto fail0;
+               goto err_free_dev;
        }
        media_device_pci_init(dev->media_dev, pci_dev, dev->name);
        dev->v4l2_dev.mdev = dev->media_dev;
@@ -1039,13 +1039,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
 
        err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
        if (err)
-               goto fail0;
+               goto err_free_dev;
 
        /* pci init */
        dev->pci = pci_dev;
        if (pci_enable_device(pci_dev)) {
                err = -EIO;
-               goto fail1;
+               goto err_v4l2_unregister;
        }
 
        /* pci quirks */
@@ -1095,7 +1095,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
        if (err) {
                pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
-               goto fail1;
+               goto err_v4l2_unregister;
        }
 
        /* board config */
@@ -1129,7 +1129,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
                err = -EBUSY;
                pr_err("%s: can't get MMIO memory @ 0x%llx\n",
                       dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
-               goto fail1;
+               goto err_v4l2_unregister;
        }
        dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
                             pci_resource_len(pci_dev, 0));
@@ -1138,7 +1138,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
                err = -EIO;
                pr_err("%s: can't ioremap() MMIO memory\n",
                       dev->name);
-               goto fail2;
+               goto err_release_mem_reg;
        }
 
        /* initialize hardware #1 */
@@ -1151,7 +1151,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        if (err < 0) {
                pr_err("%s: can't get IRQ %d\n",
                       dev->name,pci_dev->irq);
-               goto fail3;
+               goto err_iounmap;
        }
 
        /* wait a bit, register i2c bus */
@@ -1217,7 +1217,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        if (err < 0) {
                pr_info("%s: can't register video device\n",
                       dev->name);
-               goto fail4;
+               goto err_unregister_video;
        }
        pr_info("%s: registered device %s [v4l2]\n",
               dev->name, video_device_node_name(dev->video_dev));
@@ -1234,7 +1234,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
                                    vbi_nr[dev->nr]);
        if (err < 0)
-               goto fail4;
+               goto err_unregister_video;
        pr_info("%s: registered device %s\n",
               dev->name, video_device_node_name(dev->vbi_dev));
 
@@ -1248,7 +1248,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
                err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
                                            radio_nr[dev->nr]);
                if (err < 0)
-                       goto fail4;
+                       goto err_unregister_video;
                pr_info("%s: registered device %s\n",
                       dev->name, video_device_node_name(dev->radio_dev));
        }
@@ -1259,7 +1259,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        err = v4l2_mc_create_media_graph(dev->media_dev);
        if (err) {
                pr_err("failed to create media graph\n");
-               goto fail4;
+               goto err_unregister_video;
        }
 #endif
        /* everything worked */
@@ -1277,25 +1277,28 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
         */
 #ifdef CONFIG_MEDIA_CONTROLLER
        err = media_device_register(dev->media_dev);
-       if (err)
-               goto fail4;
+       if (err) {
+               media_device_cleanup(dev->media_dev);
+               goto err_unregister_video;
+       }
 #endif
 
        return 0;
 
- fail4:
+err_unregister_video:
        saa7134_unregister_video(dev);
+       list_del(&dev->devlist);
        saa7134_i2c_unregister(dev);
        free_irq(pci_dev->irq, dev);
- fail3:
+err_iounmap:
        saa7134_hwfini(dev);
        iounmap(dev->lmmio);
- fail2:
+err_release_mem_reg:
        release_mem_region(pci_resource_start(pci_dev,0),
                           pci_resource_len(pci_dev,0));
- fail1:
+err_v4l2_unregister:
        v4l2_device_unregister(&dev->v4l2_dev);
- fail0:
+err_free_dev:
 #ifdef CONFIG_MEDIA_CONTROLLER
        kfree(dev->media_dev);
 #endif
@@ -1524,7 +1527,6 @@ static struct pci_driver saa7134_pci_driver = {
 
 static int __init saa7134_init(void)
 {
-       INIT_LIST_HEAD(&saa7134_devlist);
        pr_info("saa7130/34: v4l2 driver version %s loaded\n",
               SAA7134_VERSION);
        return pci_register_driver(&saa7134_pci_driver);
index 76a37fb..aafbb34 100644 (file)
@@ -138,12 +138,15 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
 {
        struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
 
        v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
-       saa_call_all(dev, pad, set_fmt, &pad_cfg, &format);
+       saa_call_all(dev, pad, set_fmt, &pad_state, &format);
        v4l2_fill_pix_format(&f->fmt.pix, &format.format);
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
index aa0895d..9e0c442 100644 (file)
@@ -871,7 +871,7 @@ void saa7134_enable_i2s(struct saa7134_dev *dev)
        switch (dev->pci->device) {
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               /* Set I2S format (SONY)  */
+               /* Set I2S format (SONY) */
                saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
                /* Start I2S */
                saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
index 0f9d6b9..374c8e1 100644 (file)
@@ -1181,7 +1181,7 @@ static int video_release(struct file *file)
 
        saa_call_all(dev, tuner, standby);
        if (vdev->vfl_type == VFL_TYPE_RADIO)
-               saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+               saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
        mutex_unlock(&dev->lock);
 
        return 0;
@@ -1200,7 +1200,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
        cmd.result = -ENODEV;
 
        mutex_lock(&dev->lock);
-       saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
+       saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
        mutex_unlock(&dev->lock);
 
        return cmd.result;
@@ -1216,7 +1216,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
        cmd.event_list = wait;
        cmd.poll_mask = 0;
        mutex_lock(&dev->lock);
-       saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
+       saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
        mutex_unlock(&dev->lock);
 
        return rc | cmd.poll_mask;
index 8a362ee..65a6832 100644 (file)
@@ -1,56 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-config DVB_AV7110_IR
-       bool
-       depends on RC_CORE=y || RC_CORE = DVB_AV7110
-       default DVB_AV7110
-
-config DVB_AV7110
-       tristate "AV7110 cards"
-       depends on DVB_CORE && PCI && I2C
-       select TTPCI_EEPROM
-       select VIDEO_SAA7146_VV
-       depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
-       select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
-       help
-         Support for SAA7146 and AV7110 based DVB cards as produced
-         by Fujitsu-Siemens, Technotrend, Hauppauge and others.
-
-         This driver only supports the fullfeatured cards with
-         onboard MPEG2 decoder.
-
-         This driver needs an external firmware. Please use the script
-         "<kerneldir>/scripts/get_dvb_firmware av7110" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware
-         or /lib/firmware (depending on configuration of firmware hotplug).
-
-         Alternatively, you can download the file and use the kernel's
-         EXTRA_FIRMWARE configuration option to build it into your
-         kernel image by adding the filename to the EXTRA_FIRMWARE
-         configuration option string.
-
-         Say Y if you own such a card and want to use it.
-
-config DVB_AV7110_OSD
-       bool "AV7110 OSD support"
-       depends on DVB_AV7110
-       default y if DVB_AV7110=y || DVB_AV7110=m
-       help
-         The AV7110 firmware provides some code to generate an OnScreenDisplay
-         on the video output. This is kind of nonstandard and not guaranteed to
-         be maintained.
-
-         Anyway, some popular DVB software like VDR uses this OSD to render
-         its menus, so say Y if you want to use this software.
-
-         All other people say N.
-
 config DVB_BUDGET_CORE
        tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
        depends on DVB_CORE && PCI && I2C
@@ -136,25 +84,3 @@ config DVB_BUDGET_AV
 
          To compile this driver as a module, choose M here: the
          module will be called budget-av.
-
-config DVB_BUDGET_PATCH
-       tristate "AV7110 cards with Budget Patch"
-       depends on DVB_BUDGET_CORE && I2C
-       depends on DVB_AV7110
-       select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
-       select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
-       help
-         Support for Budget Patch (full TS) modification on
-         SAA7146+AV7110 based cards (DVB-S cards). This
-         driver doesn't use onboard MPEG2 decoder. The
-         card is driven in Budget-only mode. Card is
-         required to have loaded firmware to tune properly.
-         Firmware can be loaded by insertion and removal of
-         standard AV7110 driver prior to loading this
-         driver.
-
-         Say Y if you own such a card and want to use it.
-
-         To compile this driver as a module, choose M here: the
-         module will be called budget-patch.
index 9b44c47..b0708f6 100644 (file)
@@ -1,22 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0
 #
 # Makefile for the kernel SAA7146 FULL TS DVB device driver
-# and the AV7110 DVB device driver
 #
 
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o dvb_filter.o
-
-ifdef CONFIG_DVB_AV7110_IR
-dvb-ttpci-objs += av7110_ir.o
-endif
-
-obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
 obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
 obj-$(CONFIG_DVB_BUDGET) += budget.o
 obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
 obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/
 ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/common
index d405eea..5d5796f 100644 (file)
@@ -180,7 +180,8 @@ static void vpeirq(struct tasklet_struct *t)
        u32 count;
 
        /* Ensure streamed PCI data is synced to CPU */
-       pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
+       dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist,
+                           budget->pt.nents, DMA_FROM_DEVICE);
 
        /* nearest lower position divisible by 188 */
        newdma -= newdma % 188;
index a7463da..bd87432 100644 (file)
@@ -8,7 +8,6 @@
 #include <media/demux.h>
 #include <media/dvb_demux.h>
 #include <media/dmxdev.h>
-#include "dvb_filter.h"
 #include <media/dvb_net.h>
 
 #include <linux/module.h>
@@ -28,6 +27,7 @@ extern int budget_debug;
                       __func__, ##arg);                                \
 } while (0)
 
+#define TS_SIZE        188
 
 struct budget_info {
        char *name;
index a74f30f..a26a439 100644 (file)
 /* OSD enable bit for each channel */
 #define TW5864_DSP_OSD_ENABLE 0x0228
 
-/* 0x0280 ~ 0x029c  Motion Vector for 1st 4x4 Block, e.g., 80 (X), 84 (Y) */
+/* 0x0280 ~ 0x029c - Motion Vector for 1st 4x4 Block, e.g., 80 (X), 84 (Y) */
 #define TW5864_ME_MV_VEC1 0x0280
-/* 0x02a0 ~ 0x02bc  Motion Vector for 2nd 4x4 Block, e.g., A0 (X), A4 (Y) */
+/* 0x02a0 ~ 0x02bc - Motion Vector for 2nd 4x4 Block, e.g., A0 (X), A4 (Y) */
 #define TW5864_ME_MV_VEC2 0x02a0
-/* 0x02c0 ~ 0x02dc  Motion Vector for 3rd 4x4 Block, e.g., C0 (X), C4 (Y) */
+/* 0x02c0 ~ 0x02dc - Motion Vector for 3rd 4x4 Block, e.g., C0 (X), C4 (Y) */
 #define TW5864_ME_MV_VEC3 0x02c0
-/* 0x02e0 ~ 0x02fc  Motion Vector for 4th 4x4 Block, e.g., E0 (X), E4 (Y) */
+/* 0x02e0 ~ 0x02fc - Motion Vector for 4th 4x4 Block, e.g., E0 (X), E4 (Y) */
 #define TW5864_ME_MV_VEC4 0x02e0
 
 /*
 
 #define TW5864_VLC_BUF 0x100c
 /* Define controls in register TW5864_VLC_BUF */
-/* VLC BK0 full status, write ‘1’ to clear */
+/* VLC BK0 full status, write '1' to clear */
 #define TW5864_VLC_BK0_FULL BIT(0)
-/* VLC BK1 full status, write ‘1’ to clear */
+/* VLC BK1 full status, write '1' to clear */
 #define TW5864_VLC_BK1_FULL BIT(1)
-/* VLC end slice status, write ‘1’ to clear */
+/* VLC end slice status, write '1' to clear */
 #define TW5864_VLC_END_SLICE BIT(2)
-/* VLC Buffer overflow status, write ‘1’ to clear */
+/* VLC Buffer overflow status, write '1' to clear */
 #define TW5864_DSP_RD_OF BIT(3)
 /* VLC string length in either buffer 0 or 1 at end of frame */
 #define TW5864_VLC_STREAM_LEN_SHIFT 4
 
 /* [15:0] Total coefficient number in a frame */
 #define TW5864_TOTAL_COEF_NO 0x1010
-/* [0] VLC Encoder Interrupt. Write ‘1’ to clear */
+/* [0] VLC Encoder Interrupt. Write '1' to clear */
 #define TW5864_VLC_DSP_INTR 0x1014
 /* [31:0] VLC stream CRC checksum */
 #define TW5864_VLC_STREAM_CRC 0x1018
  */
 #define TW5864_VLC_RD_BRST BIT(1)
 
-/* 0x2000 ~ 0x2ffc -- H264 Stream Memory Map */
+/* 0x2000 ~ 0x2ffc - H264 Stream Memory Map */
 /*
  * A word is 4 bytes. I.e.,
  * VLC_STREAM_MEM[0] address: 0x2000
 #define TW5864_VLC_STREAM_MEM_MAX_OFFSET 0x3ff
 #define TW5864_VLC_STREAM_MEM(offset) (TW5864_VLC_STREAM_MEM_START + 4 * offset)
 
-/* 0x4000 ~ 0x4ffc -- Audio Register Map */
+/* 0x4000 ~ 0x4ffc - Audio Register Map */
 /* [31:0] config 1ms cnt = Realtime clk/1000 */
 #define TW5864_CFG_1MS_CNT 0x4000
 
 
 /*
  * [1:0]
- * 2b00 phase set to 180 degree
- * 2b01 phase set to 270 degree
- * 2b10 phase set to 0 degree
- * 2b11 phase set to 90 degree
+ * 2'b00 phase set to 180 degree
+ * 2'b01 phase set to 270 degree
+ * 2'b10 phase set to 0 degree
+ * 2'b11 phase set to 90 degree
  */
 #define TW5864_I2C_PHASE_CFG 0x800c
 
 /* SPLL_IREF, SPLL_LPX4, SPLL_CPX4, SPLL_PD, SPLL_DBG */
 #define TW5864_SPLL 0x8028
 
-/* 0x8800 ~ 0x88fc -- Interrupt Register Map */
+/* 0x8800 ~ 0x88fc - Interrupt Register Map */
 /*
  * Trigger mode of interrupt source 0 ~ 15
  * 1 Edge trigger mode
 #define TW5864_INTR_I2C_DONE BIT(25)
 #define TW5864_INTR_AD BIT(26)
 
-/* 0x9000 ~ 0x920c -- Video Capture (VIF) Register Map */
+/* 0x9000 ~ 0x920c - Video Capture (VIF) Register Map */
 /*
  * H264EN_CH_STATUS[n] Status of Vsync synchronized H264EN_CH_EN (Read Only)
  * 1 Channel Enabled
 /* GPIO Output Enable of Group n */
 #define TW5864_GPIO_OEN (0xff << 8)
 
-/* 0xa000 ~ 0xa8ff  DDR Controller Register Map */
+/* 0xa000 ~ 0xa8ff - DDR Controller Register Map */
 /* DDR Controller A */
 /*
  * [2:0] Data valid counter after read command to DDR. This is the delay value
  */
 #define TW5864_DDR_B_OFFSET 0x0800
 
-/* 0xb004 ~ 0xb018  HW version/ARB12 Register Map */
+/* 0xb004 ~ 0xb018 - HW version/ARB12 Register Map */
 /* [15:0] Default is C013 */
 #define TW5864_HW_VERSION 0xb004
 
 /* ARB12 maximum value of time out counter (default 15"h1FF) */
 #define TW5864_ARB12_TIME_OUT_CNT 0x7fff
 
-/* 0xb800 ~ 0xb80c -- Indirect Access Register Map */
+/* 0xb800 ~ 0xb80c - Indirect Access Register Map */
 /*
  * Spec says:
  * In order to access the indirect register space, the following procedure is
 /* [31:0] Data used to read/write indirect register space */
 #define TW5864_IND_DATA 0xb804
 
-/* 0xc000 ~ 0xc7fc -- Preview Register Map */
+/* 0xc000 ~ 0xc7fc - Preview Register Map */
 /* Mostly skipped this section. */
 /*
  * [15:0] Status of Vsync Synchronized PCI_PV_CH_EN (Read Only)
  */
 #define TW5864_PCI_PV_CH_EN 0xc004
 
-/* 0xc800 ~ 0xc804 -- JPEG Capture Register Map */
+/* 0xc800 ~ 0xc804 - JPEG Capture Register Map */
 /* Skipped. */
-/* 0xd000 ~ 0xd0fc -- JPEG Control Register Map */
+/* 0xd000 ~ 0xd0fc - JPEG Control Register Map */
 /* Skipped. */
 
-/* 0xe000 ~ 0xfc04  Motion Vector Register Map */
+/* 0xe000 ~ 0xfc04 - Motion Vector Register Map */
 
 /* ME Motion Vector data (Four Byte Each) 0xe000 ~ 0xe7fc */
 #define TW5864_ME_MV_VEC_START 0xe000
  */
 #define TW5864_MPI_DDR_SEL2 BIT(15)
 
-/* 0x18000 ~ 0x181fc  PCI Master/Slave Control Map */
+/* 0x18000 ~ 0x181fc - PCI Master/Slave Control Map */
 #define TW5864_PCI_INTR_STATUS 0x18000
 /* Define controls in register TW5864_PCI_INTR_STATUS */
 /* vlc done */
 #define TW5864_VLC_STREAM_BASE_ADDR 0x18080
 /* MV stream base address */
 #define TW5864_MV_STREAM_BASE_ADDR 0x18084
-/* 0x180a0  0x180bc: audio burst base address. Skipped. */
-/* 0x180c0 ~ 0x180dc – JPEG Push Mode Buffer Base Address. Skipped. */
-/* 0x18100  0x1817c: preview burst base address. Skipped. */
+/* 0x180a0 ~ 0x180bc: audio burst base address. Skipped. */
+/* 0x180c0 ~ 0x180dc: JPEG Push Mode Buffer Base Address. Skipped. */
+/* 0x18100 ~ 0x1817c: preview burst base address. Skipped. */
 
-/* 0x80000 ~ 0x87fff -- DDR Burst RW Register Map */
+/* 0x80000 ~ 0x87fff - DDR Burst RW Register Map */
 #define TW5864_DDR_CTL 0x80000
 /* Define controls in register TW5864_DDR_CTL */
 #define TW5864_BRST_LENGTH_SHIFT 2
  * Vertical Sharpness Control. Writable.
  * 0 = None (default)
  * 7 = Highest
- * **Note: VSHP must be set to ‘0’ if COMB = 0
+ * **Note: VSHP must be set to '0' if COMB = 0
  */
 #define TW5864_INDIR_VIN_1_VSHP 0x07
 
 #define TW5864_INDIR_VIN_9_CNTRST(channel) (0x009 + channel * 0x010)
 
 /*
- * These bits control the brightness. They have value of 128 to 127 in 2's
+ * These bits control the brightness. They have value of -128 to 127 in 2's
  * complement form. Positive value increases brightness. A value 0 has no
  * effect on the data. The default is 00h.
  */
index eedc14a..73ce083 100644 (file)
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_RCAR_VIN)          += rcar-vin/
 
 obj-$(CONFIG_VIDEO_ATMEL_ISC)          += atmel/
 obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel/
+obj-$(CONFIG_VIDEO_ATMEL_XISC)         += atmel/
 
 obj-$(CONFIG_VIDEO_STM32_DCMI)         += stm32/
 
index 94dd926..0ab2fcb 100644 (file)
@@ -25,7 +25,7 @@
 #include "nal-rbsp.h"
 
 /*
- * See Rec. ITU-T H.264 (04/2017) Table 7-1  NAL unit type codes, syntax
+ * See Rec. ITU-T H.264 (04/2017) Table 7-1 - NAL unit type codes, syntax
  * element categories, and NAL unit type classes
  */
 enum nal_unit_type {
index 5db540c..15a352e 100644 (file)
@@ -25,7 +25,7 @@
 #include "nal-rbsp.h"
 
 /*
- * See Rec. ITU-T H.265 (02/2018) Table 7-1  NAL unit type codes and NAL unit
+ * See Rec. ITU-T H.265 (02/2018) Table 7-1 - NAL unit type codes and NAL unit
  * type classes
  */
 enum nal_unit_type {
index 6cdc77d..1c9cb9e 100644 (file)
@@ -1021,7 +1021,9 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe)
        if (ret)
                return ret;
 
-       pm_runtime_get_sync(vpfe->pdev);
+       ret = pm_runtime_resume_and_get(vpfe->pdev);
+       if (ret < 0)
+               return ret;
 
        vpfe_config_enable(&vpfe->ccdc, 1);
 
@@ -2443,7 +2445,11 @@ static int vpfe_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
 
        /* for now just enable it here instead of waiting for the open */
-       pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0) {
+               vpfe_err(vpfe, "Unable to resume device.\n");
+               goto probe_out_v4l2_unregister;
+       }
 
        vpfe_ccdc_config_defaults(ccdc);
 
@@ -2530,6 +2536,11 @@ static int vpfe_suspend(struct device *dev)
 
        /* only do full suspend if streaming has started */
        if (vb2_start_streaming_called(&vpfe->buffer_queue)) {
+               /*
+                * ignore RPM resume errors here, as it is already too late.
+                * A check like that should happen earlier, either at
+                * open() or just before start streaming.
+                */
                pm_runtime_get_sync(dev);
                vpfe_config_enable(ccdc, 1);
 
index 1850fe7..99b5121 100644 (file)
@@ -12,6 +12,17 @@ config VIDEO_ATMEL_ISC
           This module makes the ATMEL Image Sensor Controller available
           as a v4l2 device.
 
+config VIDEO_ATMEL_XISC
+       tristate "ATMEL eXtended Image Sensor Controller (XISC) support"
+       depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API
+       depends on ARCH_AT91 || COMPILE_TEST
+       select VIDEOBUF2_DMA_CONTIG
+       select REGMAP_MMIO
+       select V4L2_FWNODE
+       help
+          This module makes the ATMEL eXtended Image Sensor Controller
+          available as a v4l2 device.
+
 config VIDEO_ATMEL_ISI
        tristate "ATMEL Image Sensor Interface (ISI) support"
        depends on VIDEO_V4L2 && OF
index 2dba389..c5c0155 100644 (file)
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o
+atmel-xisc-objs = atmel-sama7g5-isc.o atmel-isc-base.o
 
 obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
 obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
+obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
index fe3ec8d..19daa49 100644 (file)
@@ -45,179 +45,6 @@ module_param(sensor_preferred, uint, 0644);
 MODULE_PARM_DESC(sensor_preferred,
                 "Sensor is preferred to output the specified format (1-on 0-off), default 1");
 
-/* This is a list of the formats that the ISC can *output* */
-const struct isc_format controller_formats[] = {
-       {
-               .fourcc         = V4L2_PIX_FMT_ARGB444,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_ARGB555,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_RGB565,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_ABGR32,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_XBGR32,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_YUV420,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_YUYV,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_YUV422P,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_GREY,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_Y10,
-       },
-};
-
-/* This is a list of formats that the ISC can receive as *input* */
-struct isc_format formats_list[] = {
-       {
-               .fourcc         = V4L2_PIX_FMT_SBGGR8,
-               .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGBRG8,
-               .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGRBG8,
-               .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SRGGB8,
-               .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SBGGR10,
-               .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
-               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGBRG10,
-               .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
-               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGRBG10,
-               .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
-               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SRGGB10,
-               .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
-               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SBGGR12,
-               .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
-               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGBRG12,
-               .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
-               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SGRBG12,
-               .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
-               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_SRGGB12,
-               .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
-               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_GREY,
-               .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_YUYV,
-               .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_RGB565,
-               .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
-               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
-       },
-       {
-               .fourcc         = V4L2_PIX_FMT_Y10,
-               .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
-               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
-       },
-
-};
-
-/* Gamma table with gamma 1/2.2 */
-const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
-       /* 0 --> gamma 1/1.8 */
-       {      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
-         0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
-         0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
-         0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
-         0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
-         0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
-         0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
-         0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
-         0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
-         0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
-         0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
-
-       /* 1 --> gamma 1/2 */
-       {      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
-         0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
-         0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
-         0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
-         0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
-         0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
-         0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
-         0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
-         0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
-         0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
-         0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
-
-       /* 2 --> gamma 1/2.2 */
-       {      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
-         0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
-         0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
-         0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
-         0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
-         0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
-         0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
-         0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
-         0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
-         0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
-         0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
-};
-
 #define ISC_IS_FORMAT_RAW(mbus_code) \
        (((mbus_code) & 0xf000) == 0x3000)
 
@@ -294,9 +121,13 @@ static int isc_wait_clk_stable(struct clk_hw *hw)
 static int isc_clk_prepare(struct clk_hw *hw)
 {
        struct isc_clk *isc_clk = to_isc_clk(hw);
+       int ret;
 
-       if (isc_clk->id == ISC_ISPCK)
-               pm_runtime_get_sync(isc_clk->dev);
+       if (isc_clk->id == ISC_ISPCK) {
+               ret = pm_runtime_resume_and_get(isc_clk->dev);
+               if (ret < 0)
+                       return ret;
+       }
 
        return isc_wait_clk_stable(hw);
 }
@@ -319,8 +150,8 @@ static int isc_clk_enable(struct clk_hw *hw)
        unsigned long flags;
        unsigned int status;
 
-       dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n",
-               __func__, isc_clk->div, isc_clk->parent_id);
+       dev_dbg(isc_clk->dev, "ISC CLK: %s, id = %d, div = %d, parent id = %d\n",
+               __func__, id, isc_clk->div, isc_clk->parent_id);
 
        spin_lock_irqsave(&isc_clk->lock, flags);
        regmap_update_bits(regmap, ISC_CLKCFG,
@@ -353,9 +184,13 @@ static int isc_clk_is_enabled(struct clk_hw *hw)
 {
        struct isc_clk *isc_clk = to_isc_clk(hw);
        u32 status;
+       int ret;
 
-       if (isc_clk->id == ISC_ISPCK)
-               pm_runtime_get_sync(isc_clk->dev);
+       if (isc_clk->id == ISC_ISPCK) {
+               ret = pm_runtime_resume_and_get(isc_clk->dev);
+               if (ret < 0)
+                       return 0;
+       }
 
        regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
 
@@ -635,16 +470,20 @@ static void isc_start_dma(struct isc_device *isc)
                           ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
 
        addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
-       regmap_write(regmap, ISC_DAD0, addr0);
+       regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
 
        switch (isc->config.fourcc) {
        case V4L2_PIX_FMT_YUV420:
-               regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
-               regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
+               regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+                            addr0 + (sizeimage * 2) / 3);
+               regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+                            addr0 + (sizeimage * 5) / 6);
                break;
        case V4L2_PIX_FMT_YUV422P:
-               regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2);
-               regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4);
+               regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+                            addr0 + sizeimage / 2);
+               regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+                            addr0 + (sizeimage * 3) / 4);
                break;
        default:
                break;
@@ -652,7 +491,8 @@ static void isc_start_dma(struct isc_device *isc)
 
        dctrl_dview = isc->config.dctrl_dview;
 
-       regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
+       regmap_write(regmap, ISC_DCTRL + isc->offsets.dma,
+                    dctrl_dview | ISC_DCTRL_IE_IS);
        spin_lock(&isc->awb_lock);
        regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
        spin_unlock(&isc->awb_lock);
@@ -683,21 +523,16 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
 
        regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
 
-       gamma = &isc_gamma_table[ctrls->gamma_index][0];
+       gamma = &isc->gamma_table[ctrls->gamma_index][0];
        regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
        regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
        regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
 
-       /* Convert RGB to YUV */
-       regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16));
-       regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16));
-       regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16));
-       regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16));
-       regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16));
-       regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16));
-
-       regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness);
-       regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast);
+       isc->config_dpc(isc);
+       isc->config_csc(isc);
+       isc->config_cbc(isc);
+       isc->config_cc(isc);
+       isc->config_gam(isc);
 }
 
 static int isc_update_profile(struct isc_device *isc)
@@ -728,12 +563,13 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
        struct isc_ctrls *ctrls = &isc->ctrls;
 
        if (enable) {
-               regmap_write(regmap, ISC_HIS_CFG,
+               regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
                             ISC_HIS_CFG_MODE_GR |
                             (isc->config.sd_format->cfa_baycfg
                                        << ISC_HIS_CFG_BAYSEL_SHIFT) |
                                        ISC_HIS_CFG_RAR);
-               regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
+               regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
+                            ISC_HIS_CTRL_EN);
                regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
                ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
                isc_update_profile(isc);
@@ -742,7 +578,8 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
                ctrls->hist_stat = HIST_ENABLED;
        } else {
                regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
-               regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
+               regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
+                            ISC_HIS_CTRL_DIS);
 
                ctrls->hist_stat = HIST_DISABLED;
        }
@@ -751,28 +588,25 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
 static int isc_configure(struct isc_device *isc)
 {
        struct regmap *regmap = isc->regmap;
-       u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline;
+       u32 pfe_cfg0, dcfg, mask, pipeline;
        struct isc_subdev_entity *subdev = isc->current_subdev;
 
        pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
-       rlp_mode = isc->config.rlp_cfg_mode;
        pipeline = isc->config.bits_pipeline;
 
-       dcfg = isc->config.dcfg_imode |
-                      ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+       dcfg = isc->config.dcfg_imode | isc->dcfg;
 
        pfe_cfg0  |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
        mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
               ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
               ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
-                  ISC_PFE_CFG0_CCIR656;
+              ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
 
        regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
 
-       regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK,
-                          rlp_mode);
+       isc->config_rlp(isc);
 
-       regmap_write(regmap, ISC_DCFG, dcfg);
+       regmap_write(regmap, ISC_DCFG + isc->offsets.dma, dcfg);
 
        /* Set the pipeline */
        isc_set_pipeline(isc, pipeline);
@@ -807,7 +641,12 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
                goto err_start_stream;
        }
 
-       pm_runtime_get_sync(isc->dev);
+       ret = pm_runtime_resume_and_get(isc->dev);
+       if (ret < 0) {
+               v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
+                        ret);
+               goto err_pm_get;
+       }
 
        ret = isc_configure(isc);
        if (unlikely(ret))
@@ -838,7 +677,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 err_configure:
        pm_runtime_put_sync(isc->dev);
-
+err_pm_get:
        v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
 
 err_start_stream:
@@ -938,7 +777,7 @@ static int isc_querycap(struct file *file, void *priv,
 {
        struct isc_device *isc = video_drvdata(file);
 
-       strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver));
+       strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
        strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card));
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                 "platform:%s", isc->v4l2_dev.name);
@@ -949,25 +788,25 @@ static int isc_querycap(struct file *file, void *priv,
 static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
                                 struct v4l2_fmtdesc *f)
 {
+       struct isc_device *isc = video_drvdata(file);
        u32 index = f->index;
        u32 i, supported_index;
 
-       if (index < ARRAY_SIZE(controller_formats)) {
-               f->pixelformat = controller_formats[index].fourcc;
+       if (index < isc->controller_formats_size) {
+               f->pixelformat = isc->controller_formats[index].fourcc;
                return 0;
        }
 
-       index -= ARRAY_SIZE(controller_formats);
+       index -= isc->controller_formats_size;
 
-       i = 0;
        supported_index = 0;
 
-       for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
-               if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) ||
-                   !formats_list[i].sd_support)
+       for (i = 0; i < isc->formats_list_size; i++) {
+               if (!ISC_IS_FORMAT_RAW(isc->formats_list[i].mbus_code) ||
+                   !isc->formats_list[i].sd_support)
                        continue;
                if (supported_index == index) {
-                       f->pixelformat = formats_list[i].fourcc;
+                       f->pixelformat = isc->formats_list[i].fourcc;
                        return 0;
                }
                supported_index++;
@@ -1016,6 +855,8 @@ static int isc_try_validate_formats(struct isc_device *isc)
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YUV422P:
        case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
                ret = 0;
                yuv = true;
                break;
@@ -1030,6 +871,7 @@ static int isc_try_validate_formats(struct isc_device *isc)
                break;
        case V4L2_PIX_FMT_GREY:
        case V4L2_PIX_FMT_Y10:
+       case V4L2_PIX_FMT_Y16:
                ret = 0;
                grey = true;
                break;
@@ -1060,6 +902,8 @@ static int isc_try_validate_formats(struct isc_device *isc)
  */
 static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
 {
+       isc->try_config.rlp_cfg_mode = 0;
+
        switch (isc->try_config.fourcc) {
        case V4L2_PIX_FMT_SBGGR8:
        case V4L2_PIX_FMT_SGBRG8:
@@ -1126,7 +970,19 @@ static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
                isc->try_config.bpp = 16;
                break;
        case V4L2_PIX_FMT_YUYV:
-               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV;
+               isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+               isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+               isc->try_config.bpp = 16;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY;
+               isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+               isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+               isc->try_config.bpp = 16;
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY;
                isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
                isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
                isc->try_config.bpp = 16;
@@ -1137,8 +993,11 @@ static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
                isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
                isc->try_config.bpp = 8;
                break;
+       case V4L2_PIX_FMT_Y16:
+               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH;
+               fallthrough;
        case V4L2_PIX_FMT_Y10:
-               isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10;
+               isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10;
                isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
                isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
                isc->try_config.bpp = 16;
@@ -1172,7 +1031,8 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
                /* if sensor format is RAW, we convert inside ISC */
                if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
                        isc->try_config.bits_pipeline = CFA_ENABLE |
-                               WB_ENABLE | GAM_ENABLES;
+                               WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
+                               CC_ENABLE;
                } else {
                        isc->try_config.bits_pipeline = 0x0;
                }
@@ -1181,8 +1041,9 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
                /* if sensor format is RAW, we convert inside ISC */
                if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
                        isc->try_config.bits_pipeline = CFA_ENABLE |
-                               CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
-                               SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE;
+                               CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
+                               SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+                               DPC_BLCENABLE;
                } else {
                        isc->try_config.bits_pipeline = 0x0;
                }
@@ -1192,39 +1053,49 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
                if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
                        isc->try_config.bits_pipeline = CFA_ENABLE |
                                CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
-                               SUB422_ENABLE | CBC_ENABLE;
+                               SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
                } else {
                        isc->try_config.bits_pipeline = 0x0;
                }
                break;
        case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
                /* if sensor format is RAW, we convert inside ISC */
                if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
                        isc->try_config.bits_pipeline = CFA_ENABLE |
                                CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
-                               SUB422_ENABLE | CBC_ENABLE;
+                               SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
                } else {
                        isc->try_config.bits_pipeline = 0x0;
                }
                break;
        case V4L2_PIX_FMT_GREY:
-               if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+       case V4L2_PIX_FMT_Y16:
                /* if sensor format is RAW, we convert inside ISC */
+               if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
                        isc->try_config.bits_pipeline = CFA_ENABLE |
                                CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
-                               CBC_ENABLE;
+                               CBC_ENABLE | DPC_BLCENABLE;
                } else {
                        isc->try_config.bits_pipeline = 0x0;
                }
                break;
        default:
-               isc->try_config.bits_pipeline = 0x0;
+               if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+                       isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
+               else
+                       isc->try_config.bits_pipeline = 0x0;
        }
+
+       /* Tune the pipeline to product specific */
+       isc->adapt_pipeline(isc);
+
        return 0;
 }
 
 static void isc_try_fse(struct isc_device *isc,
-                       struct v4l2_subdev_pad_config *pad_cfg)
+                       struct v4l2_subdev_state *sd_state)
 {
        int ret;
        struct v4l2_subdev_frame_size_enum fse = {};
@@ -1240,17 +1111,17 @@ static void isc_try_fse(struct isc_device *isc,
        fse.which = V4L2_SUBDEV_FORMAT_TRY;
 
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
-                              pad_cfg, &fse);
+                              sd_state, &fse);
        /*
         * Attempt to obtain format size from subdev. If not available,
         * just use the maximum ISC can receive.
         */
        if (ret) {
-               pad_cfg->try_crop.width = ISC_MAX_SUPPORT_WIDTH;
-               pad_cfg->try_crop.height = ISC_MAX_SUPPORT_HEIGHT;
+               sd_state->pads->try_crop.width = isc->max_width;
+               sd_state->pads->try_crop.height = isc->max_height;
        } else {
-               pad_cfg->try_crop.width = fse.max_width;
-               pad_cfg->try_crop.height = fse.max_height;
+               sd_state->pads->try_crop.width = fse.max_width;
+               sd_state->pads->try_crop.height = fse.max_height;
        }
 }
 
@@ -1261,6 +1132,9 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
        struct isc_format *sd_fmt = NULL, *direct_fmt = NULL;
        struct v4l2_pix_format *pixfmt = &f->fmt.pix;
        struct v4l2_subdev_pad_config pad_cfg = {};
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -1324,10 +1198,10 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
        isc->try_config.sd_format = sd_fmt;
 
        /* Limit to Atmel ISC hardware capabilities */
-       if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH)
-               pixfmt->width = ISC_MAX_SUPPORT_WIDTH;
-       if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
-               pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
+       if (pixfmt->width > isc->max_width)
+               pixfmt->width = isc->max_width;
+       if (pixfmt->height > isc->max_height)
+               pixfmt->height = isc->max_height;
 
        /*
         * The mbus format is the one the subdev outputs.
@@ -1358,16 +1232,22 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
                goto isc_try_fmt_err;
 
        /* Obtain frame sizes if possible to have crop requirements ready */
-       isc_try_fse(isc, &pad_cfg);
+       isc_try_fse(isc, &pad_state);
 
        v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
        ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
-                              &pad_cfg, &format);
+                              &pad_state, &format);
        if (ret < 0)
                goto isc_try_fmt_subdev_err;
 
        v4l2_fill_pix_format(pixfmt, &format.format);
 
+       /* Limit to Atmel ISC hardware capabilities */
+       if (pixfmt->width > isc->max_width)
+               pixfmt->width = isc->max_width;
+       if (pixfmt->height > isc->max_height)
+               pixfmt->height = isc->max_height;
+
        pixfmt->field = V4L2_FIELD_NONE;
        pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3;
        pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
@@ -1403,6 +1283,12 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
        if (ret < 0)
                return ret;
 
+       /* Limit to Atmel ISC hardware capabilities */
+       if (f->fmt.pix.width > isc->max_width)
+               f->fmt.pix.width = isc->max_width;
+       if (f->fmt.pix.height > isc->max_height)
+               f->fmt.pix.height = isc->max_height;
+
        isc->fmt = *f;
 
        if (isc->try_config.sd_format && isc->config.sd_format &&
@@ -1496,8 +1382,8 @@ static int isc_enum_framesizes(struct file *file, void *fh,
                if (isc->user_formats[i]->fourcc == fsize->pixel_format)
                        ret = 0;
 
-       for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
-               if (controller_formats[i].fourcc == fsize->pixel_format)
+       for (i = 0; i < isc->controller_formats_size; i++)
+               if (isc->controller_formats[i].fourcc == fsize->pixel_format)
                        ret = 0;
 
        if (ret)
@@ -1533,8 +1419,8 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
                if (isc->user_formats[i]->fourcc == fival->pixel_format)
                        ret = 0;
 
-       for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
-               if (controller_formats[i].fourcc == fival->pixel_format)
+       for (i = 0; i < isc->controller_formats_size; i++)
+               if (isc->controller_formats[i].fourcc == fival->pixel_format)
                        ret = 0;
 
        if (ret)
@@ -1704,7 +1590,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
        *min = 0;
        *max = HIST_ENTRIES;
 
-       regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
+       regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
+                        hist_entry, HIST_ENTRIES);
 
        *hist_count = 0;
        /*
@@ -1809,6 +1696,7 @@ static void isc_awb_work(struct work_struct *w)
        u32 baysel;
        unsigned long flags;
        u32 min, max;
+       int ret;
 
        /* streaming is not active anymore */
        if (isc->stop)
@@ -1831,7 +1719,9 @@ static void isc_awb_work(struct work_struct *w)
        ctrls->hist_id = hist_id;
        baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
 
-       pm_runtime_get_sync(isc->dev);
+       ret = pm_runtime_resume_and_get(isc->dev);
+       if (ret < 0)
+               return;
 
        /*
         * only update if we have all the required histograms and controls
@@ -1860,7 +1750,8 @@ static void isc_awb_work(struct work_struct *w)
                        ctrls->awb = ISC_WB_NONE;
                }
        }
-       regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
+       regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
+                    hist_id | baysel | ISC_HIS_CFG_RAR);
        isc_update_profile(isc);
        /* if awb has been disabled, we don't need to start another histogram */
        if (ctrls->awb)
@@ -2065,12 +1956,14 @@ static int isc_ctrl_init(struct isc_device *isc)
        if (ret < 0)
                return ret;
 
+       /* Initialize product specific controls. For example, contrast */
+       isc->config_ctrls(isc, ops);
+
        ctrls->brightness = 0;
-       ctrls->contrast = 256;
 
        v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
-       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
-       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
+                         isc->gamma_max);
        isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
                                          V4L2_CID_AUTO_WHITE_BALANCE,
                                          0, 1, 1, 1);
@@ -2138,12 +2031,13 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier,
        v4l2_ctrl_handler_free(&isc->ctrls.handler);
 }
 
-static struct isc_format *find_format_by_code(unsigned int code, int *index)
+static struct isc_format *find_format_by_code(struct isc_device *isc,
+                                             unsigned int code, int *index)
 {
-       struct isc_format *fmt = &formats_list[0];
+       struct isc_format *fmt = &isc->formats_list[0];
        unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
+       for (i = 0; i < isc->formats_list_size; i++) {
                if (fmt->mbus_code == code) {
                        *index = i;
                        return fmt;
@@ -2160,7 +2054,7 @@ static int isc_formats_init(struct isc_device *isc)
        struct isc_format *fmt;
        struct v4l2_subdev *subdev = isc->current_subdev->sd;
        unsigned int num_fmts, i, j;
-       u32 list_size = ARRAY_SIZE(formats_list);
+       u32 list_size = isc->formats_list_size;
        struct v4l2_subdev_mbus_code_enum mbus_code = {
                .which = V4L2_SUBDEV_FORMAT_ACTIVE,
        };
@@ -2170,7 +2064,7 @@ static int isc_formats_init(struct isc_device *isc)
               NULL, &mbus_code)) {
                mbus_code.index++;
 
-               fmt = find_format_by_code(mbus_code.code, &i);
+               fmt = find_format_by_code(isc, mbus_code.code, &i);
                if (!fmt) {
                        v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n",
                                  mbus_code.code);
@@ -2191,7 +2085,7 @@ static int isc_formats_init(struct isc_device *isc)
        if (!isc->user_formats)
                return -ENOMEM;
 
-       fmt = &formats_list[0];
+       fmt = &isc->formats_list[0];
        for (i = 0, j = 0; i < list_size; i++) {
                if (fmt->sd_support)
                        isc->user_formats[j++] = fmt;
@@ -2287,7 +2181,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
        }
 
        /* Register video device */
-       strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
+       strscpy(vdev->name, "microchip-isc", sizeof(vdev->name));
        vdev->release           = video_device_release_empty;
        vdev->fops              = &isc_fops;
        vdev->ioctl_ops         = &isc_ioctl_ops;
@@ -2338,8 +2232,14 @@ int isc_pipeline_init(struct isc_device *isc)
        struct regmap_field *regs;
        unsigned int i;
 
-       /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
+       /*
+        * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
+        * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
+        */
        const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
+               REG_FIELD(ISC_DPC_CTRL, 0, 0),
+               REG_FIELD(ISC_DPC_CTRL, 1, 1),
+               REG_FIELD(ISC_DPC_CTRL, 2, 2),
                REG_FIELD(ISC_WB_CTRL, 0, 0),
                REG_FIELD(ISC_CFA_CTRL, 0, 0),
                REG_FIELD(ISC_CC_CTRL, 0, 0),
@@ -2347,10 +2247,11 @@ int isc_pipeline_init(struct isc_device *isc)
                REG_FIELD(ISC_GAM_CTRL, 1, 1),
                REG_FIELD(ISC_GAM_CTRL, 2, 2),
                REG_FIELD(ISC_GAM_CTRL, 3, 3),
-               REG_FIELD(ISC_CSC_CTRL, 0, 0),
-               REG_FIELD(ISC_CBC_CTRL, 0, 0),
-               REG_FIELD(ISC_SUB422_CTRL, 0, 0),
-               REG_FIELD(ISC_SUB420_CTRL, 0, 0),
+               REG_FIELD(ISC_VHXS_CTRL, 0, 0),
+               REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
+               REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
+               REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
+               REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
        };
 
        for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
@@ -2365,7 +2266,7 @@ int isc_pipeline_init(struct isc_device *isc)
 }
 
 /* regmap configuration */
-#define ATMEL_ISC_REG_MAX    0xbfc
+#define ATMEL_ISC_REG_MAX    0xd5c
 const struct regmap_config isc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
index f1e160e..d06b722 100644 (file)
@@ -26,6 +26,7 @@
 #define ISC_PFE_CFG0_PPOL_LOW   BIT(2)
 #define ISC_PFE_CFG0_CCIR656    BIT(9)
 #define ISC_PFE_CFG0_CCIR_CRC   BIT(10)
+#define ISC_PFE_CFG0_MIPI      BIT(14)
 
 #define ISC_PFE_CFG0_MODE_PROGRESSIVE   (0x0 << 4)
 #define ISC_PFE_CFG0_MODE_MASK          GENMASK(6, 4)
 #define ISC_INT_DDONE          BIT(8)
 #define ISC_INT_HISDONE                BIT(12)
 
+/* ISC DPC Control Register */
+#define ISC_DPC_CTRL   0x40
+
+#define ISC_DPC_CTRL_DPCEN     BIT(0)
+#define ISC_DPC_CTRL_GDCEN     BIT(1)
+#define ISC_DPC_CTRL_BLCEN     BIT(2)
+
+/* ISC DPC Config Register */
+#define ISC_DPC_CFG    0x44
+
+#define ISC_DPC_CFG_BAYSEL_SHIFT       0
+
+#define ISC_DPC_CFG_EITPOL             BIT(4)
+
+#define ISC_DPC_CFG_TA_ENABLE          BIT(14)
+#define ISC_DPC_CFG_TC_ENABLE          BIT(13)
+#define ISC_DPC_CFG_TM_ENABLE          BIT(12)
+
+#define ISC_DPC_CFG_RE_MODE            BIT(17)
+
+#define ISC_DPC_CFG_GDCCLP_SHIFT       20
+#define ISC_DPC_CFG_GDCCLP_MASK                GENMASK(22, 20)
+
+#define ISC_DPC_CFG_BLOFF_SHIFT                24
+#define ISC_DPC_CFG_BLOFF_MASK         GENMASK(31, 24)
+
+#define ISC_DPC_CFG_BAYCFG_SHIFT       0
+#define ISC_DPC_CFG_BAYCFG_MASK                GENMASK(1, 0)
+/* ISC DPC Threshold Median Register */
+#define ISC_DPC_THRESHM        0x48
+
+/* ISC DPC Threshold Closest Register */
+#define ISC_DPC_THRESHC        0x4C
+
+/* ISC DPC Threshold Average Register */
+#define ISC_DPC_THRESHA        0x50
+
+/* ISC DPC STatus Register */
+#define ISC_DPC_SR     0x54
+
 /* ISC White Balance Control Register */
 #define ISC_WB_CTRL     0x00000058
 
 /* ISC Gamma Correction Control Register */
 #define ISC_GAM_CTRL    0x00000094
 
+#define ISC_GAM_CTRL_BIPART    BIT(4)
+
 /* ISC_Gamma Correction Blue Entry Register */
 #define ISC_GAM_BENTRY 0x00000098
 
 /* ISC_Gamma Correction Green Entry Register */
 #define ISC_GAM_RENTRY 0x00000298
 
+/* ISC VHXS Control Register */
+#define ISC_VHXS_CTRL  0x398
+
+/* ISC VHXS Source Size Register */
+#define ISC_VHXS_SS    0x39C
+
+/* ISC VHXS Destination Size Register */
+#define ISC_VHXS_DS    0x3A0
+
+/* ISC Vertical Factor Register */
+#define ISC_VXS_FACT   0x3a4
+
+/* ISC Horizontal Factor Register */
+#define ISC_HXS_FACT   0x3a8
+
+/* ISC Vertical Config Register */
+#define ISC_VXS_CFG    0x3ac
+
+/* ISC Horizontal Config Register */
+#define ISC_HXS_CFG    0x3b0
+
+/* ISC Vertical Tap Register */
+#define ISC_VXS_TAP    0x3b4
+
+/* ISC Horizontal Tap Register */
+#define ISC_HXS_TAP    0x434
+
+/* Offset for CSC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CSC_OFFSET 0
+/* Offset for CSC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CSC_OFFSET 0x11c
+
 /* Color Space Conversion Control Register */
 #define ISC_CSC_CTRL    0x00000398
 
 /* Color Space Conversion CRB OCR Register */
 #define ISC_CSC_CRB_OCR        0x000003b0
 
+/* Offset for CBC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CBC_OFFSET 0
+/* Offset for CBC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CBC_OFFSET 0x11c
+
 /* Contrast And Brightness Control Register */
 #define ISC_CBC_CTRL    0x000003b4
 
 #define ISC_CBC_CONTRAST       0x000003c0
 #define ISC_CBC_CONTRAST_MASK  GENMASK(11, 0)
 
+/* Hue Register */
+#define ISC_CBCHS_HUE  0x4e0
+/* Saturation Register */
+#define ISC_CBCHS_SAT  0x4e4
+
+/* Offset for SUB422 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB422_OFFSET      0
+/* Offset for SUB422 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB422_OFFSET      0x124
+
 /* Subsampling 4:4:4 to 4:2:2 Control Register */
 #define ISC_SUB422_CTRL 0x000003c4
 
+/* Offset for SUB420 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB420_OFFSET      0
+/* Offset for SUB420 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB420_OFFSET      0x124
 /* Subsampling 4:2:2 to 4:2:0 Control Register */
 #define ISC_SUB420_CTRL 0x000003cc
 
+/* Offset for RLP register specific to sama5d2 product */
+#define ISC_SAMA5D2_RLP_OFFSET 0
+/* Offset for RLP register specific to sama7g5 product */
+#define ISC_SAMA7G5_RLP_OFFSET 0x124
 /* Rounding, Limiting and Packing Configuration Register */
 #define ISC_RLP_CFG     0x000003d0
 
 #define ISC_RLP_CFG_MODE_ARGB32         0xa
 #define ISC_RLP_CFG_MODE_YYCC           0xb
 #define ISC_RLP_CFG_MODE_YYCC_LIMITED   0xc
+#define ISC_RLP_CFG_MODE_YCYC           0xd
 #define ISC_RLP_CFG_MODE_MASK           GENMASK(3, 0)
 
+#define ISC_RLP_CFG_LSH                        BIT(5)
+
+#define ISC_RLP_CFG_YMODE_YUYV         (3 << 6)
+#define ISC_RLP_CFG_YMODE_YVYU         (2 << 6)
+#define ISC_RLP_CFG_YMODE_VYUY         (0 << 6)
+#define ISC_RLP_CFG_YMODE_UYVY         (1 << 6)
+
+#define ISC_RLP_CFG_YMODE_MASK         GENMASK(7, 6)
+
+/* Offset for HIS register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_OFFSET 0
+/* Offset for HIS register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_OFFSET 0x124
 /* Histogram Control Register */
 #define ISC_HIS_CTRL   0x000003d4
 
 
 #define ISC_HIS_CFG_RAR                        BIT(8)
 
+/* Offset for DMA register specific to sama5d2 product */
+#define ISC_SAMA5D2_DMA_OFFSET 0
+/* Offset for DMA register specific to sama7g5 product */
+#define ISC_SAMA7G5_DMA_OFFSET 0x13c
+
 /* DMA Configuration Register */
 #define ISC_DCFG        0x000003e0
 #define ISC_DCFG_IMODE_PACKED8          0x0
 #define ISC_DCFG_YMBSIZE_BEATS4         (0x1 << 4)
 #define ISC_DCFG_YMBSIZE_BEATS8         (0x2 << 4)
 #define ISC_DCFG_YMBSIZE_BEATS16        (0x3 << 4)
-#define ISC_DCFG_YMBSIZE_MASK           GENMASK(5, 4)
+#define ISC_DCFG_YMBSIZE_BEATS32        (0x4 << 4)
+#define ISC_DCFG_YMBSIZE_MASK           GENMASK(6, 4)
 
 #define ISC_DCFG_CMBSIZE_SINGLE         (0x0 << 8)
 #define ISC_DCFG_CMBSIZE_BEATS4         (0x1 << 8)
 #define ISC_DCFG_CMBSIZE_BEATS8         (0x2 << 8)
 #define ISC_DCFG_CMBSIZE_BEATS16        (0x3 << 8)
-#define ISC_DCFG_CMBSIZE_MASK           GENMASK(9, 8)
+#define ISC_DCFG_CMBSIZE_BEATS32        (0x4 << 8)
+#define ISC_DCFG_CMBSIZE_MASK           GENMASK(10, 8)
 
 /* DMA Control Register */
 #define ISC_DCTRL       0x000003e4
 /* DMA Address 2 Register */
 #define ISC_DAD2        0x000003fc
 
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_VERSION_OFFSET     0
+#define ISC_SAMA7G5_VERSION_OFFSET     0x13c
+/* Version Register */
+#define ISC_VERSION    0x0000040c
+
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_ENTRY_OFFSET   0
+/* Offset for version register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_ENTRY_OFFSET   0x14c
 /* Histogram Entry */
 #define ISC_HIS_ENTRY  0x00000410
 
index fab8eca..19cc60d 100644 (file)
@@ -10,9 +10,6 @@
  */
 #ifndef _ATMEL_ISC_H_
 
-#define ISC_MAX_SUPPORT_WIDTH   2592
-#define ISC_MAX_SUPPORT_HEIGHT  1944
-
 #define ISC_CLK_MAX_DIV                255
 
 enum isc_clk_id {
@@ -71,17 +68,21 @@ struct isc_format {
 };
 
 /* Pipeline bitmap */
-#define WB_ENABLE      BIT(0)
-#define CFA_ENABLE     BIT(1)
-#define CC_ENABLE      BIT(2)
-#define GAM_ENABLE     BIT(3)
-#define GAM_BENABLE    BIT(4)
-#define GAM_GENABLE    BIT(5)
-#define GAM_RENABLE    BIT(6)
-#define CSC_ENABLE     BIT(7)
-#define CBC_ENABLE     BIT(8)
-#define SUB422_ENABLE  BIT(9)
-#define SUB420_ENABLE  BIT(10)
+#define DPC_DPCENABLE  BIT(0)
+#define DPC_GDCENABLE  BIT(1)
+#define DPC_BLCENABLE  BIT(2)
+#define WB_ENABLE      BIT(3)
+#define CFA_ENABLE     BIT(4)
+#define CC_ENABLE      BIT(5)
+#define GAM_ENABLE     BIT(6)
+#define GAM_BENABLE    BIT(7)
+#define GAM_GENABLE    BIT(8)
+#define GAM_RENABLE    BIT(9)
+#define VHXS_ENABLE    BIT(10)
+#define CSC_ENABLE     BIT(11)
+#define CBC_ENABLE     BIT(12)
+#define SUB422_ENABLE  BIT(13)
+#define SUB420_ENABLE  BIT(14)
 
 #define GAM_ENABLES    (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
 
@@ -145,7 +146,31 @@ struct isc_ctrls {
        u32 hist_minmax[HIST_BAYER][2];
 };
 
-#define ISC_PIPE_LINE_NODE_NUM 11
+#define ISC_PIPE_LINE_NODE_NUM 15
+
+/*
+ * struct isc_reg_offsets - ISC device register offsets
+ * @csc:               Offset for the CSC register
+ * @cbc:               Offset for the CBC register
+ * @sub422:            Offset for the SUB422 register
+ * @sub420:            Offset for the SUB420 register
+ * @rlp:               Offset for the RLP register
+ * @his:               Offset for the HIS related registers
+ * @dma:               Offset for the DMA related registers
+ * @version:           Offset for the version register
+ * @his_entry:         Offset for the HIS entries registers
+ */
+struct isc_reg_offsets {
+       u32 csc;
+       u32 cbc;
+       u32 sub422;
+       u32 sub420;
+       u32 rlp;
+       u32 his;
+       u32 dma;
+       u32 version;
+       u32 his_entry;
+};
 
 /*
  * struct isc_device - ISC device driver data/config struct
@@ -153,6 +178,7 @@ struct isc_ctrls {
  * @hclock:            Hclock clock input (refer datasheet)
  * @ispck:             iscpck clock (refer datasheet)
  * @isc_clks:          ISC clocks
+ * @dcfg:              DMA master configuration, architecture dependent
  *
  * @dev:               Registered device driver
  * @v4l2_dev:          v4l2 registered device
@@ -187,12 +213,46 @@ struct isc_ctrls {
  *
  * @current_subdev:    current subdevice: the sensor
  * @subdev_entities:   list of subdevice entitites
+ *
+ * @gamma_table:       pointer to the table with gamma values, has
+ *                     gamma_max sets of GAMMA_ENTRIES entries each
+ * @gamma_max:         maximum number of sets of inside the gamma_table
+ *
+ * @max_width:         maximum frame width, dependent on the internal RAM
+ * @max_height:                maximum frame height, dependent on the internal RAM
+ *
+ * @config_dpc:                pointer to a function that initializes product
+ *                     specific DPC module
+ * @config_csc:                pointer to a function that initializes product
+ *                     specific CSC module
+ * @config_cbc:                pointer to a function that initializes product
+ *                     specific CBC module
+ * @config_cc:         pointer to a function that initializes product
+ *                     specific CC module
+ * @config_gam:                pointer to a function that initializes product
+ *                     specific GAMMA module
+ * @config_rlp:                pointer to a function that initializes product
+ *                     specific RLP module
+ * @config_ctrls:      pointer to a functoin that initializes product
+ *                     specific v4l2 controls.
+ *
+ * @adapt_pipeline:    pointer to a function that adapts the pipeline bits
+ *                     to the product specific pipeline
+ *
+ * @offsets:           struct holding the product specific register offsets
+ * @controller_formats:        pointer to the array of possible formats that the
+ *                     controller can output
+ * @formats_list:      pointer to the array of possible formats that can
+ *                     be used as an input to the controller
+ * @controller_formats_size:   size of controller_formats array
+ * @formats_list_size: size of formats_list array
  */
 struct isc_device {
        struct regmap           *regmap;
        struct clk              *hclock;
        struct clk              *ispck;
        struct isc_clk          isc_clks[2];
+       u32                     dcfg;
 
        struct device           *dev;
        struct v4l2_device      v4l2_dev;
@@ -245,16 +305,36 @@ struct isc_device {
                struct v4l2_ctrl        *gr_off_ctrl;
                struct v4l2_ctrl        *gb_off_ctrl;
        };
-};
 
-#define GAMMA_MAX      2
 #define GAMMA_ENTRIES  64
+       /* pointer to the defined gamma table */
+       const u32       (*gamma_table)[GAMMA_ENTRIES];
+       u32             gamma_max;
+
+       u32             max_width;
+       u32             max_height;
+
+       struct {
+               void (*config_dpc)(struct isc_device *isc);
+               void (*config_csc)(struct isc_device *isc);
+               void (*config_cbc)(struct isc_device *isc);
+               void (*config_cc)(struct isc_device *isc);
+               void (*config_gam)(struct isc_device *isc);
+               void (*config_rlp)(struct isc_device *isc);
 
-#define ATMEL_ISC_NAME "atmel-isc"
+               void (*config_ctrls)(struct isc_device *isc,
+                                    const struct v4l2_ctrl_ops *ops);
+
+               void (*adapt_pipeline)(struct isc_device *isc);
+       };
+
+       struct isc_reg_offsets          offsets;
+       const struct isc_format         *controller_formats;
+       struct isc_format               *formats_list;
+       u32                             controller_formats_size;
+       u32                             formats_list_size;
+};
 
-extern struct isc_format formats_list[];
-extern const struct isc_format controller_formats[];
-extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES];
 extern const struct regmap_config isc_regmap_config;
 extern const struct v4l2_async_notifier_operations isc_async_ops;
 
index e392b3e..095d80c 100644 (file)
@@ -422,7 +422,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        struct frame_buffer *buf, *node;
        int ret;
 
-       pm_runtime_get_sync(isi->dev);
+       ret = pm_runtime_resume_and_get(isi->dev);
+       if (ret < 0)
+               return ret;
 
        /* Enable stream on the sub device */
        ret = v4l2_subdev_call(isi->entity.subdev, video, s_stream, 1);
@@ -555,7 +557,7 @@ static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi,
 }
 
 static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
-                       struct v4l2_subdev_pad_config *pad_cfg)
+                       struct v4l2_subdev_state *sd_state)
 {
        int ret;
        struct v4l2_subdev_frame_size_enum fse = {
@@ -564,17 +566,17 @@ static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
        };
 
        ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size,
-                              pad_cfg, &fse);
+                              sd_state, &fse);
        /*
         * Attempt to obtain format size from subdev. If not available,
         * just use the maximum ISI can receive.
         */
        if (ret) {
-               pad_cfg->try_crop.width = MAX_SUPPORT_WIDTH;
-               pad_cfg->try_crop.height = MAX_SUPPORT_HEIGHT;
+               sd_state->pads->try_crop.width = MAX_SUPPORT_WIDTH;
+               sd_state->pads->try_crop.height = MAX_SUPPORT_HEIGHT;
        } else {
-               pad_cfg->try_crop.width = fse.max_width;
-               pad_cfg->try_crop.height = fse.max_height;
+               sd_state->pads->try_crop.width = fse.max_width;
+               sd_state->pads->try_crop.height = fse.max_height;
        }
 }
 
@@ -584,6 +586,9 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
        const struct isi_format *isi_fmt;
        struct v4l2_pix_format *pixfmt = &f->fmt.pix;
        struct v4l2_subdev_pad_config pad_cfg = {};
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -601,10 +606,10 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
 
        v4l2_fill_mbus_format(&format.format, pixfmt, isi_fmt->mbus_code);
 
-       isi_try_fse(isi, isi_fmt, &pad_cfg);
+       isi_try_fse(isi, isi_fmt, &pad_state);
 
        ret = v4l2_subdev_call(isi->entity.subdev, pad, set_fmt,
-                              &pad_cfg, &format);
+                              &pad_state, &format);
        if (ret < 0)
                return ret;
 
@@ -782,9 +787,10 @@ static int isi_enum_frameintervals(struct file *file, void *fh,
        return 0;
 }
 
-static void isi_camera_set_bus_param(struct atmel_isi *isi)
+static int isi_camera_set_bus_param(struct atmel_isi *isi)
 {
        u32 cfg1 = 0;
+       int ret;
 
        /* set bus param for ISI */
        if (isi->pdata.hsync_act_low)
@@ -801,12 +807,16 @@ static void isi_camera_set_bus_param(struct atmel_isi *isi)
        cfg1 |= ISI_CFG1_THMASK_BEATS_16;
 
        /* Enable PM and peripheral clock before operate isi registers */
-       pm_runtime_get_sync(isi->dev);
+       ret = pm_runtime_resume_and_get(isi->dev);
+       if (ret < 0)
+               return ret;
 
        isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
        isi_writel(isi, ISI_CFG1, cfg1);
 
        pm_runtime_put(isi->dev);
+
+       return 0;
 }
 
 /* -----------------------------------------------------------------------*/
@@ -1085,7 +1095,11 @@ static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier)
                dev_err(isi->dev, "No supported mediabus format found\n");
                return ret;
        }
-       isi_camera_set_bus_param(isi);
+       ret = isi_camera_set_bus_param(isi);
+       if (ret) {
+               dev_err(isi->dev, "Can't wake up device\n");
+               return ret;
+       }
 
        ret = isi_set_default_fmt(isi);
        if (ret) {
index 61d9885..925aa80 100644 (file)
 #include "atmel-isc-regs.h"
 #include "atmel-isc.h"
 
-#define ISC_MAX_SUPPORT_WIDTH   2592
-#define ISC_MAX_SUPPORT_HEIGHT  1944
+#define ISC_SAMA5D2_MAX_SUPPORT_WIDTH   2592
+#define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT  1944
 
-#define ISC_CLK_MAX_DIV                255
+#define ISC_SAMA5D2_PIPELINE \
+       (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+       CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama5d2_controller_formats[] = {
+       {
+               .fourcc         = V4L2_PIX_FMT_ARGB444,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_ARGB555,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_ABGR32,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_XBGR32,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV422P,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_Y10,
+       },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama5d2_formats_list[] = {
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG8,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG8,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB8,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR10,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG10,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG10,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB10,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR12,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG12,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG12,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB12,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_GREY,
+               .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_Y10,
+               .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+       },
+
+};
+
+static void isc_sama5d2_config_csc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       /* Convert RGB to YUV */
+       regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+                    0x42 | (0x81 << 16));
+       regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+                    0x19 | (0x10 << 16));
+       regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+                    0xFDA | (0xFB6 << 16));
+       regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+                    0x70 | (0x80 << 16));
+       regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+                    0x70 | (0xFA2 << 16));
+       regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+                    0xFEE | (0x80 << 16));
+}
+
+static void isc_sama5d2_config_cbc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
+                    isc->ctrls.brightness);
+       regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
+                    isc->ctrls.contrast);
+}
+
+static void isc_sama5d2_config_cc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+       regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+       regmap_write(regmap, ISC_CC_RB_OR, 0);
+       regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+       regmap_write(regmap, ISC_CC_GB_OG, 0);
+       regmap_write(regmap, ISC_CC_BR_BG, 0);
+       regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama5d2_config_ctrls(struct isc_device *isc,
+                                    const struct v4l2_ctrl_ops *ops)
+{
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+       ctrls->contrast = 256;
+
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
+}
+
+static void isc_sama5d2_config_dpc(struct isc_device *isc)
+{
+       /* This module is not present on sama5d2 pipeline */
+}
+
+static void isc_sama5d2_config_gam(struct isc_device *isc)
+{
+       /* No specific gamma configuration */
+}
+
+static void isc_sama5d2_config_rlp(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+       regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+                          ISC_RLP_CFG_MODE_MASK, rlp_mode);
+}
+
+static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
+{
+       isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
+       /* 0 --> gamma 1/1.8 */
+       {      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
+         0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
+         0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
+         0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
+         0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
+         0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
+         0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
+         0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
+         0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
+         0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
+         0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
+
+       /* 1 --> gamma 1/2 */
+       {      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
+         0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
+         0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
+         0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
+         0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
+         0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
+         0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
+         0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
+         0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
+         0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
+         0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
+
+       /* 2 --> gamma 1/2.2 */
+       {      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
+         0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
+         0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
+         0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
+         0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
+         0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
+         0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
+         0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
+         0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
+         0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
+         0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
+};
 
 static int isc_parse_dt(struct device *dev, struct isc_device *isc)
 {
@@ -118,6 +370,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
        struct isc_subdev_entity *subdev_entity;
        int irq;
        int ret;
+       u32 ver;
 
        isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
        if (!isc)
@@ -143,13 +396,47 @@ static int atmel_isc_probe(struct platform_device *pdev)
                return irq;
 
        ret = devm_request_irq(dev, irq, isc_interrupt, 0,
-                              ATMEL_ISC_NAME, isc);
+                              "atmel-sama5d2-isc", isc);
        if (ret < 0) {
                dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
                        irq, ret);
                return ret;
        }
 
+       isc->gamma_table = isc_sama5d2_gamma_table;
+       isc->gamma_max = 2;
+
+       isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
+       isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
+
+       isc->config_dpc = isc_sama5d2_config_dpc;
+       isc->config_csc = isc_sama5d2_config_csc;
+       isc->config_cbc = isc_sama5d2_config_cbc;
+       isc->config_cc = isc_sama5d2_config_cc;
+       isc->config_gam = isc_sama5d2_config_gam;
+       isc->config_rlp = isc_sama5d2_config_rlp;
+       isc->config_ctrls = isc_sama5d2_config_ctrls;
+
+       isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
+
+       isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
+       isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
+       isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
+       isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
+       isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
+       isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
+       isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
+       isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
+       isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
+
+       isc->controller_formats = sama5d2_controller_formats;
+       isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
+       isc->formats_list = sama5d2_formats_list;
+       isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
+
+       /* sama5d2-isc - 8 bits per beat */
+       isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+
        ret = isc_pipeline_init(isc);
        if (ret)
                return ret;
@@ -241,6 +528,9 @@ static int atmel_isc_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
        pm_request_idle(dev);
 
+       regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+       dev_info(dev, "Microchip ISC version %x\n", ver);
+
        return 0;
 
 cleanup_subdev:
@@ -319,7 +609,7 @@ static struct platform_driver atmel_isc_driver = {
        .probe  = atmel_isc_probe,
        .remove = atmel_isc_remove,
        .driver = {
-               .name           = ATMEL_ISC_NAME,
+               .name           = "atmel-sama5d2-isc",
                .pm             = &atmel_isc_dev_pm_ops,
                .of_match_table = of_match_ptr(atmel_isc_of_match),
        },
diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
new file mode 100644 (file)
index 0000000..f278513
--- /dev/null
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip eXtended Image Sensor Controller (XISC) driver
+ *
+ * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
+ *
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
+ *
+ * ISC video pipeline integrates the following submodules:
+ * PFE: Parallel Front End to sample the camera sensor input stream
+ * DPC: Defective Pixel Correction with black offset correction, green disparity
+ *      correction and defective pixel correction (3 modules total)
+ *  WB: Programmable white balance in the Bayer domain
+ * CFA: Color filter array interpolation module
+ *  CC: Programmable color correction
+ * GAM: Gamma correction
+ *VHXS: Vertical and Horizontal Scaler
+ * CSC: Programmable color space conversion
+ *CBHS: Contrast Brightness Hue and Saturation control
+ * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
+ * RLP: This module performs rounding, range limiting
+ *      and packing of the incoming data
+ * DMA: This module performs DMA master accesses to write frames to external RAM
+ * HIS: Histogram module performs statistic counters on the frames
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "atmel-isc-regs.h"
+#include "atmel-isc.h"
+
+#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH   3264
+#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT  2464
+
+#define ISC_SAMA7G5_PIPELINE \
+       (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+       CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama7g5_controller_formats[] = {
+       {
+               .fourcc         = V4L2_PIX_FMT_ARGB444,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_ARGB555,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_ABGR32,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_XBGR32,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_VYUY,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUV422P,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_GREY,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_Y10,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_Y16,
+       },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama7g5_formats_list[] = {
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG8,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG8,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB8,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR10,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG10,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG10,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB10,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SBGGR12,
+               .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_BGBG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGBRG12,
+               .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_GBGB,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SGRBG12,
+               .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_GRGR,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_SRGGB12,
+               .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
+               .cfa_baycfg     = ISC_BAY_CFG_RGRG,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_GREY,
+               .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+               .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
+               .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
+       },
+       {
+               .fourcc         = V4L2_PIX_FMT_Y10,
+               .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
+               .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
+       },
+
+};
+
+static void isc_sama7g5_config_csc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       /* Convert RGB to YUV */
+       regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+                    0x42 | (0x81 << 16));
+       regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+                    0x19 | (0x10 << 16));
+       regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+                    0xFDA | (0xFB6 << 16));
+       regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+                    0x70 | (0x80 << 16));
+       regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+                    0x70 | (0xFA2 << 16));
+       regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+                    0xFEE | (0x80 << 16));
+}
+
+static void isc_sama7g5_config_cbc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       /* Configure what is set via v4l2 ctrls */
+       regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
+       regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
+       /* Configure Hue and Saturation as neutral midpoint */
+       regmap_write(regmap, ISC_CBCHS_HUE, 0);
+       regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
+}
+
+static void isc_sama7g5_config_cc(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+       regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+       regmap_write(regmap, ISC_CC_RB_OR, 0);
+       regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+       regmap_write(regmap, ISC_CC_GB_OG, 0);
+       regmap_write(regmap, ISC_CC_BR_BG, 0);
+       regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama7g5_config_ctrls(struct isc_device *isc,
+                                    const struct v4l2_ctrl_ops *ops)
+{
+       struct isc_ctrls *ctrls = &isc->ctrls;
+       struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+       ctrls->contrast = 16;
+
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
+}
+
+static void isc_sama7g5_config_dpc(struct isc_device *isc)
+{
+       u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
+       struct regmap *regmap = isc->regmap;
+
+       regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
+                          (64 << ISC_DPC_CFG_BLOFF_SHIFT));
+       regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
+                          (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
+}
+
+static void isc_sama7g5_config_gam(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+
+       regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
+                          ISC_GAM_CTRL_BIPART);
+}
+
+static void isc_sama7g5_config_rlp(struct isc_device *isc)
+{
+       struct regmap *regmap = isc->regmap;
+       u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+       regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+                          ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
+                          ISC_RLP_CFG_YMODE_MASK, rlp_mode);
+}
+
+static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
+{
+       isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
+       /* index 0 --> gamma bipartite */
+       {
+             0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,
+          0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,
+          0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,
+          0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+         0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+         0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+         0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+         0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+         0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+         0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+         0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+};
+
+static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
+{
+       struct device_node *np = dev->of_node;
+       struct device_node *epn = NULL;
+       struct isc_subdev_entity *subdev_entity;
+       unsigned int flags;
+       int ret;
+       bool mipi_mode;
+
+       INIT_LIST_HEAD(&isc->subdev_entities);
+
+       mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
+
+       while (1) {
+               struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
+               epn = of_graph_get_next_endpoint(np, epn);
+               if (!epn)
+                       return 0;
+
+               ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
+                                                &v4l2_epn);
+               if (ret) {
+                       ret = -EINVAL;
+                       dev_err(dev, "Could not parse the endpoint\n");
+                       break;
+               }
+
+               subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
+                                            GFP_KERNEL);
+               if (!subdev_entity) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               subdev_entity->epn = epn;
+
+               flags = v4l2_epn.bus.parallel.flags;
+
+               if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+                       subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
+
+               if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+                       subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
+
+               if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+                       subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
+
+               if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
+                       subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
+                                       ISC_PFE_CFG0_CCIR656;
+
+               if (mipi_mode)
+                       subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
+
+               list_add_tail(&subdev_entity->list, &isc->subdev_entities);
+       }
+       of_node_put(epn);
+
+       return ret;
+}
+
+static int microchip_xisc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct isc_device *isc;
+       struct resource *res;
+       void __iomem *io_base;
+       struct isc_subdev_entity *subdev_entity;
+       int irq;
+       int ret;
+       u32 ver;
+
+       isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
+       if (!isc)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, isc);
+       isc->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       io_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(io_base))
+               return PTR_ERR(io_base);
+
+       isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
+       if (IS_ERR(isc->regmap)) {
+               ret = PTR_ERR(isc->regmap);
+               dev_err(dev, "failed to init register map: %d\n", ret);
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = devm_request_irq(dev, irq, isc_interrupt, 0,
+                              "microchip-sama7g5-xisc", isc);
+       if (ret < 0) {
+               dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+                       irq, ret);
+               return ret;
+       }
+
+       isc->gamma_table = isc_sama7g5_gamma_table;
+       isc->gamma_max = 0;
+
+       isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+       isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+
+       isc->config_dpc = isc_sama7g5_config_dpc;
+       isc->config_csc = isc_sama7g5_config_csc;
+       isc->config_cbc = isc_sama7g5_config_cbc;
+       isc->config_cc = isc_sama7g5_config_cc;
+       isc->config_gam = isc_sama7g5_config_gam;
+       isc->config_rlp = isc_sama7g5_config_rlp;
+       isc->config_ctrls = isc_sama7g5_config_ctrls;
+
+       isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
+
+       isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
+       isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
+       isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
+       isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
+       isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
+       isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
+       isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
+       isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
+       isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
+
+       isc->controller_formats = sama7g5_controller_formats;
+       isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
+       isc->formats_list = sama7g5_formats_list;
+       isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
+
+       /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
+       isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
+
+       ret = isc_pipeline_init(isc);
+       if (ret)
+               return ret;
+
+       isc->hclock = devm_clk_get(dev, "hclock");
+       if (IS_ERR(isc->hclock)) {
+               ret = PTR_ERR(isc->hclock);
+               dev_err(dev, "failed to get hclock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(isc->hclock);
+       if (ret) {
+               dev_err(dev, "failed to enable hclock: %d\n", ret);
+               return ret;
+       }
+
+       ret = isc_clk_init(isc);
+       if (ret) {
+               dev_err(dev, "failed to init isc clock: %d\n", ret);
+               goto unprepare_hclk;
+       }
+
+       isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
+
+       ret = clk_prepare_enable(isc->ispck);
+       if (ret) {
+               dev_err(dev, "failed to enable ispck: %d\n", ret);
+               goto unprepare_hclk;
+       }
+
+       /* ispck should be greater or equal to hclock */
+       ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
+       if (ret) {
+               dev_err(dev, "failed to set ispck rate: %d\n", ret);
+               goto unprepare_clk;
+       }
+
+       ret = v4l2_device_register(dev, &isc->v4l2_dev);
+       if (ret) {
+               dev_err(dev, "unable to register v4l2 device.\n");
+               goto unprepare_clk;
+       }
+
+       ret = xisc_parse_dt(dev, isc);
+       if (ret) {
+               dev_err(dev, "fail to parse device tree\n");
+               goto unregister_v4l2_device;
+       }
+
+       if (list_empty(&isc->subdev_entities)) {
+               dev_err(dev, "no subdev found\n");
+               ret = -ENODEV;
+               goto unregister_v4l2_device;
+       }
+
+       list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
+               struct v4l2_async_subdev *asd;
+
+               v4l2_async_notifier_init(&subdev_entity->notifier);
+
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                                       &subdev_entity->notifier,
+                                       of_fwnode_handle(subdev_entity->epn),
+                                       struct v4l2_async_subdev);
+
+               of_node_put(subdev_entity->epn);
+               subdev_entity->epn = NULL;
+
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
+                       goto cleanup_subdev;
+               }
+
+               subdev_entity->notifier.ops = &isc_async_ops;
+
+               ret = v4l2_async_notifier_register(&isc->v4l2_dev,
+                                                  &subdev_entity->notifier);
+               if (ret) {
+                       dev_err(dev, "fail to register async notifier\n");
+                       goto cleanup_subdev;
+               }
+
+               if (video_is_registered(&isc->video_dev))
+                       break;
+       }
+
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_request_idle(dev);
+
+       regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+       dev_info(dev, "Microchip XISC version %x\n", ver);
+
+       return 0;
+
+cleanup_subdev:
+       isc_subdev_cleanup(isc);
+
+unregister_v4l2_device:
+       v4l2_device_unregister(&isc->v4l2_dev);
+
+unprepare_clk:
+       clk_disable_unprepare(isc->ispck);
+unprepare_hclk:
+       clk_disable_unprepare(isc->hclock);
+
+       isc_clk_cleanup(isc);
+
+       return ret;
+}
+
+static int microchip_xisc_remove(struct platform_device *pdev)
+{
+       struct isc_device *isc = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       isc_subdev_cleanup(isc);
+
+       v4l2_device_unregister(&isc->v4l2_dev);
+
+       clk_disable_unprepare(isc->ispck);
+       clk_disable_unprepare(isc->hclock);
+
+       isc_clk_cleanup(isc);
+
+       return 0;
+}
+
+static int __maybe_unused xisc_runtime_suspend(struct device *dev)
+{
+       struct isc_device *isc = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(isc->ispck);
+       clk_disable_unprepare(isc->hclock);
+
+       return 0;
+}
+
+static int __maybe_unused xisc_runtime_resume(struct device *dev)
+{
+       struct isc_device *isc = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(isc->hclock);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(isc->ispck);
+       if (ret)
+               clk_disable_unprepare(isc->hclock);
+
+       return ret;
+}
+
+static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
+};
+
+static const struct of_device_id microchip_xisc_of_match[] = {
+       { .compatible = "microchip,sama7g5-isc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
+
+static struct platform_driver microchip_xisc_driver = {
+       .probe  = microchip_xisc_probe,
+       .remove = microchip_xisc_remove,
+       .driver = {
+               .name           = "microchip-sama7g5-xisc",
+               .pm             = &microchip_xisc_dev_pm_ops,
+               .of_match_table = of_match_ptr(microchip_xisc_of_match),
+       },
+};
+
+module_platform_driver(microchip_xisc_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
+MODULE_LICENSE("GPL v2");
index c68a3ea..f2b4ddd 100644 (file)
@@ -282,6 +282,7 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
        struct resource *res;
        unsigned char i;
        u32 dev_cfg;
+       int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        csi2rx->base = devm_ioremap_resource(&pdev->dev, res);
@@ -315,7 +316,12 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
                return -EINVAL;
        }
 
-       clk_prepare_enable(csi2rx->p_clk);
+       ret = clk_prepare_enable(csi2rx->p_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't prepare and enable P clock\n");
+               return ret;
+       }
+
        dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG);
        clk_disable_unprepare(csi2rx->p_clk);
 
index e4d08ac..5a67fba 100644 (file)
@@ -156,7 +156,7 @@ static const struct csi2tx_fmt *csi2tx_get_fmt_from_mbus(u32 mbus)
 }
 
 static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad || code->index >= ARRAY_SIZE(csi2tx_formats))
@@ -169,20 +169,20 @@ static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev,
 
 static struct v4l2_mbus_framefmt *
 __csi2tx_get_pad_format(struct v4l2_subdev *subdev,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *fmt)
 {
        struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(subdev, cfg,
+               return v4l2_subdev_get_try_format(subdev, sd_state,
                                                  fmt->pad);
 
        return &csi2tx->pad_fmts[fmt->pad];
 }
 
 static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        const struct v4l2_mbus_framefmt *format;
@@ -191,7 +191,7 @@ static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
        if (fmt->pad == CSI2TX_PAD_SOURCE)
                return -EINVAL;
 
-       format = __csi2tx_get_pad_format(subdev, cfg, fmt);
+       format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
        if (!format)
                return -EINVAL;
 
@@ -201,7 +201,7 @@ static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
 }
 
 static int csi2tx_set_pad_format(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        const struct v4l2_mbus_framefmt *src_format = &fmt->format;
@@ -214,7 +214,7 @@ static int csi2tx_set_pad_format(struct v4l2_subdev *subdev,
        if (!csi2tx_get_fmt_from_mbus(fmt->format.code))
                src_format = &fmt_default;
 
-       dst_format = __csi2tx_get_pad_format(subdev, cfg, fmt);
+       dst_format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
        if (!dst_format)
                return -EINVAL;
 
@@ -436,6 +436,7 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
        struct resource *res;
        unsigned int i;
        u32 dev_cfg;
+       int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        csi2tx->base = devm_ioremap_resource(&pdev->dev, res);
@@ -454,7 +455,12 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
                return PTR_ERR(csi2tx->esc_clk);
        }
 
-       clk_prepare_enable(csi2tx->p_clk);
+       ret = clk_prepare_enable(csi2tx->p_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't prepare and enable p_clk\n");
+               return ret;
+       }
+
        dev_cfg = readl(csi2tx->base + CSI2TX_DEVICE_CONFIG_REG);
        clk_disable_unprepare(csi2tx->p_clk);
 
index bd666c8..0e312b0 100644 (file)
@@ -1935,7 +1935,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
        if (name && parent) {
                buf->blob.data = buf->vaddr;
                buf->blob.size = size;
-               buf->dentry = debugfs_create_blob(name, 0644, parent,
+               buf->dentry = debugfs_create_blob(name, 0444, parent,
                                                  &buf->blob);
        }
 
@@ -2660,7 +2660,7 @@ static int coda_open(struct file *file)
        ctx->use_vdoa = false;
 
        /* Power up and upload firmware if necessary */
-       ret = pm_runtime_get_sync(dev->dev);
+       ret = pm_runtime_resume_and_get(dev->dev);
        if (ret < 0) {
                v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
                goto err_pm_get;
@@ -2668,7 +2668,7 @@ static int coda_open(struct file *file)
 
        ret = clk_prepare_enable(dev->clk_per);
        if (ret)
-               goto err_pm_get;
+               goto err_clk_enable;
 
        ret = clk_prepare_enable(dev->clk_ahb);
        if (ret)
@@ -2707,8 +2707,9 @@ err_ctx_init:
        clk_disable_unprepare(dev->clk_ahb);
 err_clk_ahb:
        clk_disable_unprepare(dev->clk_per);
-err_pm_get:
+err_clk_enable:
        pm_runtime_put_sync(dev->dev);
+err_pm_get:
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
 err_coda_name_init:
@@ -3232,7 +3233,7 @@ static int coda_probe(struct platform_device *pdev)
                memset(dev->iram.vaddr, 0, dev->iram.size);
                dev->iram.blob.data = dev->iram.vaddr;
                dev->iram.blob.size = dev->iram.size;
-               dev->iram.dentry = debugfs_create_blob("iram", 0644,
+               dev->iram.dentry = debugfs_create_blob("iram", 0444,
                                                       dev->debugfs_root,
                                                       &dev->iram.blob);
        }
index d19bad9..bf3c3e7 100644 (file)
@@ -47,7 +47,7 @@ static int venc_is_second_field(struct vpbe_display *disp_dev)
 
        ret = v4l2_subdev_call(vpbe_dev->venc,
                               core,
-                              ioctl,
+                              command,
                               VENC_GET_FLD,
                               &val);
        if (ret < 0) {
index 8caa084..bde241c 100644 (file)
@@ -521,9 +521,7 @@ static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
        return ret;
 }
 
-static long venc_ioctl(struct v4l2_subdev *sd,
-                       unsigned int cmd,
-                       void *arg)
+static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
        u32 val;
 
@@ -542,7 +540,7 @@ static long venc_ioctl(struct v4l2_subdev *sd,
 }
 
 static const struct v4l2_subdev_core_ops venc_core_ops = {
-       .ioctl      = venc_ioctl,
+       .command      = venc_command,
 };
 
 static const struct v4l2_subdev_video_ops venc_video_ops = {
index 8d2e165..c034e25 100644 (file)
@@ -99,7 +99,7 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
  * vpif_buffer_queue_setup : Callback function for buffer setup.
  * @vq: vb2_queue ptr
  * @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @nplanes: contains number of distinct video planes needed to hold a frame
  * @sizes: contains the size (in bytes) of each plane.
  * @alloc_devs: ptr to allocation context
  *
index e5f61d9..59f6b78 100644 (file)
@@ -101,7 +101,7 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
  * vpif_buffer_queue_setup : Callback function for buffer setup.
  * @vq: vb2_queue ptr
  * @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @nplanes: contains number of distinct video planes needed to hold a frame
  * @sizes: contains the size (in bytes) of each plane.
  * @alloc_devs: ptr to allocation context
  *
index 9f41c2e..f49f332 100644 (file)
@@ -1210,18 +1210,19 @@ static int gsc_remove(struct platform_device *pdev)
        struct gsc_dev *gsc = platform_get_drvdata(pdev);
        int i;
 
-       pm_runtime_get_sync(&pdev->dev);
-
        gsc_unregister_m2m_device(gsc);
        v4l2_device_unregister(&gsc->v4l2_dev);
 
        vb2_dma_contig_clear_max_seg_size(&pdev->dev);
-       for (i = 0; i < gsc->num_clocks; i++)
-               clk_disable_unprepare(gsc->clock[i]);
 
-       pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               for (i = 0; i < gsc->num_clocks; i++)
+                       clk_disable_unprepare(gsc->clock[i]);
+
+       pm_runtime_set_suspended(&pdev->dev);
+
        dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
        return 0;
 }
index 27a3c92..f1cf847 100644 (file)
@@ -56,10 +56,8 @@ static void __gsc_m2m_job_abort(struct gsc_ctx *ctx)
 static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct gsc_ctx *ctx = q->drv_priv;
-       int ret;
 
-       ret = pm_runtime_get_sync(&ctx->gsc_dev->pdev->dev);
-       return ret > 0 ? 0 : ret;
+       return pm_runtime_resume_and_get(&ctx->gsc_dev->pdev->dev);
 }
 
 static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
index 13c838d..7ff4024 100644 (file)
@@ -478,11 +478,9 @@ static int fimc_capture_open(struct file *file)
                goto unlock;
 
        set_bit(ST_CAPT_BUSY, &fimc->state);
-       ret = pm_runtime_get_sync(&fimc->pdev->dev);
-       if (ret < 0) {
-               pm_runtime_put_sync(&fimc->pdev->dev);
+       ret = pm_runtime_resume_and_get(&fimc->pdev->dev);
+       if (ret < 0)
                goto unlock;
-       }
 
        ret = v4l2_fh_open(file);
        if (ret) {
@@ -1456,7 +1454,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
 }
 
 static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_mbus_code_enum *code)
 {
        struct fimc_fmt *fmt;
@@ -1469,7 +1467,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1478,7 +1476,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *mf;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *mf;
                return 0;
        }
@@ -1510,7 +1508,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1533,7 +1531,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
        mf->colorspace = V4L2_COLORSPACE_JPEG;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
                return 0;
        }
@@ -1576,7 +1574,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1603,10 +1601,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
                return 0;
 
        case V4L2_SEL_TGT_CROP:
-               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                break;
        case V4L2_SEL_TGT_COMPOSE:
-               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
                f = &ctx->d_frame;
                break;
        default:
@@ -1632,7 +1630,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
 }
 
 static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1650,10 +1648,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
-               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                break;
        case V4L2_SEL_TGT_COMPOSE:
-               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
                f = &ctx->d_frame;
                break;
        default:
index 972d960..1b24f5b 100644 (file)
@@ -828,9 +828,9 @@ static int fimc_is_probe(struct platform_device *pdev)
                        goto err_irq;
        }
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto err_pm;
+               goto err_irq;
 
        vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
 
index 612b987..83688a7 100644 (file)
@@ -275,7 +275,7 @@ static int isp_video_open(struct file *file)
        if (ret < 0)
                goto unlock;
 
-       ret = pm_runtime_get_sync(&isp->pdev->dev);
+       ret = pm_runtime_resume_and_get(&isp->pdev->dev);
        if (ret < 0)
                goto rel_fh;
 
@@ -293,7 +293,6 @@ static int isp_video_open(struct file *file)
        if (!ret)
                goto unlock;
 rel_fh:
-       pm_runtime_put_noidle(&isp->pdev->dev);
        v4l2_fh_release(file);
 unlock:
        mutex_unlock(&isp->video_lock);
@@ -306,17 +305,20 @@ static int isp_video_release(struct file *file)
        struct fimc_is_video *ivc = &isp->video_capture;
        struct media_entity *entity = &ivc->ve.vdev.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
+       bool is_singular_file;
 
        mutex_lock(&isp->video_lock);
 
-       if (v4l2_fh_is_singular_file(file) && ivc->streaming) {
+       is_singular_file = v4l2_fh_is_singular_file(file);
+
+       if (is_singular_file && ivc->streaming) {
                media_pipeline_stop(entity);
                ivc->streaming = 0;
        }
 
        _vb2_fop_release(file, NULL);
 
-       if (v4l2_fh_is_singular_file(file)) {
+       if (is_singular_file) {
                fimc_pipeline_call(&ivc->ve, close);
 
                mutex_lock(&mdev->graph_mutex);
index a77c49b..855235b 100644 (file)
@@ -106,7 +106,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = {
 };
 
 static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        const struct fimc_fmt *fmt;
@@ -119,14 +119,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *fmt)
 {
        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *mf = &fmt->format;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                return 0;
        }
 
@@ -156,7 +156,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
 }
 
 static void __isp_subdev_try_format(struct fimc_isp *isp,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *mf = &fmt->format;
@@ -172,8 +172,9 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
                mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
        } else {
                if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-                       format = v4l2_subdev_get_try_format(&isp->subdev, cfg,
-                                               FIMC_ISP_SD_PAD_SINK);
+                       format = v4l2_subdev_get_try_format(&isp->subdev,
+                                                           sd_state,
+                                                           FIMC_ISP_SD_PAD_SINK);
                else
                        format = &isp->sink_fmt;
 
@@ -191,7 +192,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
 }
 
 static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *fmt)
 {
        struct fimc_isp *isp = v4l2_get_subdevdata(sd);
@@ -203,10 +204,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
                 __func__, fmt->pad, mf->code, mf->width, mf->height);
 
        mutex_lock(&isp->subdev_lock);
-       __isp_subdev_try_format(isp, cfg, fmt);
+       __isp_subdev_try_format(isp, sd_state, fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
 
                /* Propagate format to the source pads */
@@ -217,8 +218,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
                        for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
                                        pad < FIMC_ISP_SD_PADS_NUM; pad++) {
                                format.pad = pad;
-                               __isp_subdev_try_format(isp, cfg, &format);
-                               mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+                               __isp_subdev_try_format(isp, sd_state,
+                                                       &format);
+                               mf = v4l2_subdev_get_try_format(sd, sd_state,
+                                                               pad);
                                *mf = format.format;
                        }
                }
@@ -230,7 +233,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
                                isp->sink_fmt = *mf;
 
                                format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
-                               __isp_subdev_try_format(isp, cfg, &format);
+                               __isp_subdev_try_format(isp, sd_state,
+                                                       &format);
 
                                isp->src_fmt = format.format;
                                __is_set_frame_size(is, &isp->src_fmt);
@@ -304,11 +308,10 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
        pr_debug("on: %d\n", on);
 
        if (on) {
-               ret = pm_runtime_get_sync(&is->pdev->dev);
-               if (ret < 0) {
-                       pm_runtime_put(&is->pdev->dev);
+               ret = pm_runtime_resume_and_get(&is->pdev->dev);
+               if (ret < 0)
                        return ret;
-               }
+
                set_bit(IS_ST_PWR_ON, &is->state);
 
                ret = fimc_is_start_firmware(is);
@@ -371,15 +374,18 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
                .field = V4L2_FIELD_NONE,
        };
 
-       format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK);
+       format = v4l2_subdev_get_try_format(sd, fh->state,
+                                           FIMC_ISP_SD_PAD_SINK);
        *format = fmt;
 
-       format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO);
+       format = v4l2_subdev_get_try_format(sd, fh->state,
+                                           FIMC_ISP_SD_PAD_SRC_FIFO);
        fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
        fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
        *format = fmt;
 
-       format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA);
+       format = v4l2_subdev_get_try_format(sd, fh->state,
+                                           FIMC_ISP_SD_PAD_SRC_DMA);
        *format = fmt;
 
        return 0;
index fe20af3..aaa3af0 100644 (file)
@@ -469,9 +469,9 @@ static int fimc_lite_open(struct file *file)
        }
 
        set_bit(ST_FLITE_IN_USE, &fimc->state);
-       ret = pm_runtime_get_sync(&fimc->pdev->dev);
+       ret = pm_runtime_resume_and_get(&fimc->pdev->dev);
        if (ret < 0)
-               goto err_pm;
+               goto err_in_use;
 
        ret = v4l2_fh_open(file);
        if (ret < 0)
@@ -499,6 +499,7 @@ static int fimc_lite_open(struct file *file)
        v4l2_fh_release(file);
 err_pm:
        pm_runtime_put_sync(&fimc->pdev->dev);
+err_in_use:
        clear_bit(ST_FLITE_IN_USE, &fimc->state);
 unlock:
        mutex_unlock(&fimc->lock);
@@ -549,7 +550,7 @@ static const struct v4l2_file_operations fimc_lite_fops = {
  */
 
 static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
-                                       struct v4l2_subdev_pad_config *cfg,
+                                       struct v4l2_subdev_state *sd_state,
                                        struct v4l2_subdev_format *format)
 {
        struct flite_drvdata *dd = fimc->dd;
@@ -573,14 +574,16 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
                struct v4l2_rect *rect;
 
                if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-                       sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg,
-                                               FLITE_SD_PAD_SINK);
+                       sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev,
+                                                             sd_state,
+                                                             FLITE_SD_PAD_SINK);
 
                        mf->code = sink_fmt->code;
                        mf->colorspace = sink_fmt->colorspace;
 
-                       rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg,
-                                               FLITE_SD_PAD_SINK);
+                       rect = v4l2_subdev_get_try_crop(&fimc->subdev,
+                                                       sd_state,
+                                                       FLITE_SD_PAD_SINK);
                } else {
                        mf->code = sink->fmt->mbus_code;
                        mf->colorspace = sink->fmt->colorspace;
@@ -1001,7 +1004,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = {
 };
 
 static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                          struct v4l2_subdev_pad_config *cfg,
+                                          struct v4l2_subdev_state *sd_state,
                                           struct v4l2_subdev_mbus_code_enum *code)
 {
        const struct fimc_fmt *fmt;
@@ -1015,16 +1018,16 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 
 static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
                struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg, unsigned int pad)
+               struct v4l2_subdev_state *sd_state, unsigned int pad)
 {
        if (pad != FLITE_SD_PAD_SINK)
                pad = FLITE_SD_PAD_SOURCE_DMA;
 
-       return v4l2_subdev_get_try_format(sd, cfg, pad);
+       return v4l2_subdev_get_try_format(sd, sd_state, pad);
 }
 
 static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1032,7 +1035,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
        struct flite_frame *f = &fimc->inp_frame;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
+               mf = __fimc_lite_subdev_get_try_fmt(sd, sd_state, fmt->pad);
                fmt->format = *mf;
                return 0;
        }
@@ -1055,7 +1058,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1077,17 +1080,18 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
                return -EBUSY;
        }
 
-       ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt);
+       ffmt = fimc_lite_subdev_try_fmt(fimc, sd_state, fmt);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                struct v4l2_mbus_framefmt *src_fmt;
 
-               mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
+               mf = __fimc_lite_subdev_get_try_fmt(sd, sd_state, fmt->pad);
                *mf = fmt->format;
 
                if (fmt->pad == FLITE_SD_PAD_SINK) {
                        unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
-                       src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad);
+                       src_fmt = __fimc_lite_subdev_get_try_fmt(sd, sd_state,
+                                                                pad);
                        *src_fmt = *mf;
                }
 
@@ -1115,7 +1119,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
-                                         struct v4l2_subdev_pad_config *cfg,
+                                         struct v4l2_subdev_state *sd_state,
                                          struct v4l2_subdev_selection *sel)
 {
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1127,7 +1131,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                return 0;
        }
 
@@ -1150,7 +1154,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
 }
 
 static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
-                                         struct v4l2_subdev_pad_config *cfg,
+                                         struct v4l2_subdev_state *sd_state,
                                          struct v4l2_subdev_selection *sel)
 {
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1164,7 +1168,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
        fimc_lite_try_crop(fimc, &sel->r);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
+               *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
        } else {
                unsigned long flags;
                spin_lock_irqsave(&fimc->slock, flags);
index c9704a1..df8e2aa 100644 (file)
@@ -73,17 +73,14 @@ static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
 static int start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct fimc_ctx *ctx = q->drv_priv;
-       int ret;
 
-       ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
-       return ret > 0 ? 0 : ret;
+       return pm_runtime_resume_and_get(&ctx->fimc_dev->pdev->dev);
 }
 
 static void stop_streaming(struct vb2_queue *q)
 {
        struct fimc_ctx *ctx = q->drv_priv;
 
-
        fimc_m2m_shutdown(ctx);
        fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
        pm_runtime_put(&ctx->fimc_dev->pdev->dev);
index 13d192b..3b8a24b 100644 (file)
@@ -512,11 +512,9 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
        if (!fmd->pmf)
                return -ENXIO;
 
-       ret = pm_runtime_get_sync(fmd->pmf);
-       if (ret < 0) {
-               pm_runtime_put(fmd->pmf);
+       ret = pm_runtime_resume_and_get(fmd->pmf);
+       if (ret < 0)
                return ret;
-       }
 
        fmd->num_sensors = 0;
 
@@ -1286,13 +1284,11 @@ static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
 static int cam_clk_prepare(struct clk_hw *hw)
 {
        struct cam_clk *camclk = to_cam_clk(hw);
-       int ret;
 
        if (camclk->fmd->pmf == NULL)
                return -ENODEV;
 
-       ret = pm_runtime_get_sync(camclk->fmd->pmf);
-       return ret < 0 ? ret : 0;
+       return pm_runtime_resume_and_get(camclk->fmd->pmf);
 }
 
 static void cam_clk_unprepare(struct clk_hw *hw)
index 1aac167..32b2332 100644 (file)
@@ -494,7 +494,7 @@ static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
        struct device *dev = &state->pdev->dev;
 
        if (on)
-               return pm_runtime_get_sync(dev);
+               return pm_runtime_resume_and_get(dev);
 
        return pm_runtime_put_sync(dev);
 }
@@ -509,11 +509,9 @@ static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
 
        if (enable) {
                s5pcsis_clear_counters(state);
-               ret = pm_runtime_get_sync(&state->pdev->dev);
-               if (ret && ret != 1) {
-                       pm_runtime_put_noidle(&state->pdev->dev);
+               ret = pm_runtime_resume_and_get(&state->pdev->dev);
+               if (ret < 0)
                        return ret;
-               }
        }
 
        mutex_lock(&state->lock);
@@ -535,11 +533,11 @@ unlock:
        if (!enable)
                pm_runtime_put(&state->pdev->dev);
 
-       return ret == 1 ? 0 : ret;
+       return ret;
 }
 
 static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(s5pcsis_formats))
@@ -567,23 +565,25 @@ static struct csis_pix_format const *s5pcsis_try_format(
 }
 
 static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
-               struct csis_state *state, struct v4l2_subdev_pad_config *cfg,
+               struct csis_state *state, struct v4l2_subdev_state *sd_state,
                enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL;
+               return sd_state ? v4l2_subdev_get_try_format(&state->sd,
+                                                            sd_state, 0) : NULL;
 
        return &state->format;
 }
 
-static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct csis_state *state = sd_to_csis_state(sd);
        struct csis_pix_format const *csis_fmt;
        struct v4l2_mbus_framefmt *mf;
 
-       mf = __s5pcsis_get_format(state, cfg, fmt->which);
+       mf = __s5pcsis_get_format(state, sd_state, fmt->which);
 
        if (fmt->pad == CSIS_PAD_SOURCE) {
                if (mf) {
@@ -604,13 +604,14 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
        return 0;
 }
 
-static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct csis_state *state = sd_to_csis_state(sd);
        struct v4l2_mbus_framefmt *mf;
 
-       mf = __s5pcsis_get_format(state, cfg, fmt->which);
+       mf = __s5pcsis_get_format(state, sd_state, fmt->which);
        if (!mf)
                return -EINVAL;
 
index 03b9264..7551380 100644 (file)
@@ -62,7 +62,7 @@
 #include "mxc-jpeg-hw.h"
 #include "mxc-jpeg.h"
 
-static struct mxc_jpeg_fmt mxc_formats[] = {
+static const struct mxc_jpeg_fmt mxc_formats[] = {
        {
                .name           = "JPEG",
                .fourcc         = V4L2_PIX_FMT_JPEG,
@@ -341,7 +341,7 @@ static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh)
        return container_of(fh, struct mxc_jpeg_ctx, fh);
 }
 
-static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
+static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n,
                    struct v4l2_fmtdesc *f, u32 type)
 {
        int i, num = 0;
@@ -368,13 +368,13 @@ static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
        return 0;
 }
 
-static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
-                                                u32 pixelformat)
+static const struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
+                                                      u32 pixelformat)
 {
        unsigned int k;
 
        for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
-               struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
+               const struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
 
                if (fmt->fourcc == pixelformat)
                        return fmt;
@@ -1536,7 +1536,7 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
                                MXC_JPEG_FMT_TYPE_RAW);
 }
 
-static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
+static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt,
                            struct mxc_jpeg_ctx *ctx, int q_type)
 {
        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
@@ -1612,7 +1612,7 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
        struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
        struct device *dev = jpeg->dev;
-       struct mxc_jpeg_fmt *fmt;
+       const struct mxc_jpeg_fmt *fmt;
        u32 fourcc = f->fmt.pix_mp.pixelformat;
 
        int q_type = (jpeg->mode == MXC_JPEG_DECODE) ?
@@ -1643,7 +1643,7 @@ static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
        struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
        struct device *dev = jpeg->dev;
-       struct mxc_jpeg_fmt *fmt;
+       const struct mxc_jpeg_fmt *fmt;
        u32 fourcc = f->fmt.pix_mp.pixelformat;
 
        int q_type = (jpeg->mode == MXC_JPEG_ENCODE) ?
@@ -1890,7 +1890,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = {
        .mmap           = v4l2_m2m_fop_mmap,
 };
 
-static struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
+static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
        .device_run     = mxc_jpeg_device_run,
 };
 
index 7697de4..4c21085 100644 (file)
@@ -51,7 +51,7 @@ enum mxc_jpeg_mode {
  * @flags:     flags describing format applicability
  */
 struct mxc_jpeg_fmt {
-       char                                    *name;
+       const char                              *name;
        u32                                     fourcc;
        enum v4l2_jpeg_chroma_subsampling       subsampling;
        int                                     nc;
@@ -74,14 +74,14 @@ struct mxc_jpeg_desc {
 } __packed;
 
 struct mxc_jpeg_q_data {
-       struct mxc_jpeg_fmt     *fmt;
-       u32                     sizeimage[MXC_JPEG_MAX_PLANES];
-       u32                     bytesperline[MXC_JPEG_MAX_PLANES];
-       int                     w;
-       int                     w_adjusted;
-       int                     h;
-       int                     h_adjusted;
-       unsigned int            sequence;
+       const struct mxc_jpeg_fmt       *fmt;
+       u32                             sizeimage[MXC_JPEG_MAX_PLANES];
+       u32                             bytesperline[MXC_JPEG_MAX_PLANES];
+       int                             w;
+       int                             w_adjusted;
+       int                             h;
+       int                             h_adjusted;
+       unsigned int                    sequence;
 };
 
 struct mxc_jpeg_ctx {
index baac86f..9aa374f 100644 (file)
@@ -486,6 +486,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        struct cafe_camera *cam;
        struct mcam_camera *mcam;
        struct v4l2_async_subdev *asd;
+       struct i2c_client *i2c_dev;
 
        /*
         * Start putting together one of our big camera structures.
@@ -561,11 +562,16 @@ static int cafe_pci_probe(struct pci_dev *pdev,
        clkdev_create(mcam->mclk, "xclk", "%d-%04x",
                i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
 
-       if (!IS_ERR(i2c_new_client_device(cam->i2c_adapter, &ov7670_info))) {
-               cam->registered = 1;
-               return 0;
+       i2c_dev = i2c_new_client_device(cam->i2c_adapter, &ov7670_info);
+       if (IS_ERR(i2c_dev)) {
+               ret = PTR_ERR(i2c_dev);
+               goto out_mccic_shutdown;
        }
 
+       cam->registered = 1;
+       return 0;
+
+out_mccic_shutdown:
        mccic_shutdown(mcam);
 out_smbus_shutdown:
        cafe_smbus_shutdown(cam);
index 141bf5d..070a0f3 100644 (file)
@@ -918,6 +918,7 @@ static int mclk_enable(struct clk_hw *hw)
        struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw);
        int mclk_src;
        int mclk_div;
+       int ret;
 
        /*
         * Clock the sensor appropriately.  Controller clock should
@@ -931,7 +932,9 @@ static int mclk_enable(struct clk_hw *hw)
                mclk_div = 2;
        }
 
-       pm_runtime_get_sync(cam->dev);
+       ret = pm_runtime_resume_and_get(cam->dev);
+       if (ret < 0)
+               return ret;
        clk_enable(cam->clk[0]);
        mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div);
        mcam_ctlr_power_up(cam);
@@ -1347,6 +1350,9 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
        struct mcam_format_struct *f;
        struct v4l2_pix_format *pix = &fmt->fmt.pix;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -1355,7 +1361,7 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
        f = mcam_find_format(pix->pixelformat);
        pix->pixelformat = f->pixelformat;
        v4l2_fill_mbus_format(&format.format, pix, f->mbus_code);
-       ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format);
+       ret = sensor_call(cam, pad, set_fmt, &pad_state, &format);
        v4l2_fill_pix_format(pix, &format.format);
        pix->bytesperline = pix->width * f->bpp;
        switch (f->pixelformat) {
@@ -1611,7 +1617,9 @@ static int mcam_v4l_open(struct file *filp)
                ret = sensor_call(cam, core, s_power, 1);
                if (ret)
                        goto out;
-               pm_runtime_get_sync(cam->dev);
+               ret = pm_runtime_resume_and_get(cam->dev);
+               if (ret < 0)
+                       goto out;
                __mcam_cam_reset(cam);
                mcam_set_config_needed(cam, 1);
        }
index 88a23bc..a89c7b2 100644 (file)
@@ -920,7 +920,7 @@ static void mtk_jpeg_enc_device_run(void *priv)
        src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
-       ret = pm_runtime_get_sync(jpeg->dev);
+       ret = pm_runtime_resume_and_get(jpeg->dev);
        if (ret < 0)
                goto enc_end;
 
@@ -973,7 +973,7 @@ static void mtk_jpeg_dec_device_run(void *priv)
                return;
        }
 
-       ret = pm_runtime_get_sync(jpeg->dev);
+       ret = pm_runtime_resume_and_get(jpeg->dev);
        if (ret < 0)
                goto dec_end;
 
index ace4528..f14779e 100644 (file)
@@ -391,12 +391,12 @@ static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
        struct mtk_mdp_ctx *ctx = q->drv_priv;
        int ret;
 
-       ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+       ret = pm_runtime_resume_and_get(&ctx->mdp_dev->pdev->dev);
        if (ret < 0)
-               mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
+               mtk_mdp_dbg(1, "[%d] pm_runtime_resume_and_get failed:%d",
                            ctx->id, ret);
 
-       return 0;
+       return ret;
 }
 
 static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
index 147dfef..f87dc47 100644 (file)
@@ -126,7 +126,9 @@ static int fops_vcodec_open(struct file *file)
        mtk_vcodec_dec_set_default_params(ctx);
 
        if (v4l2_fh_is_singular(&ctx->fh)) {
-               mtk_vcodec_dec_pw_on(&dev->pm);
+               ret = mtk_vcodec_dec_pw_on(&dev->pm);
+               if (ret < 0)
+                       goto err_load_fw;
                /*
                 * Does nothing if firmware was already loaded.
                 */
index ddee704..6038db9 100644 (file)
@@ -88,13 +88,15 @@ void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
        put_device(dev->pm.larbvdec);
 }
 
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
 {
        int ret;
 
-       ret = pm_runtime_get_sync(pm->dev);
+       ret = pm_runtime_resume_and_get(pm->dev);
        if (ret)
-               mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
+               mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
+
+       return ret;
 }
 
 void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
index 872d8bf..280aeae 100644 (file)
@@ -12,7 +12,7 @@
 int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
 void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
 
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
 void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
index d03cca9..c6c7672 100644 (file)
@@ -25,7 +25,7 @@
 #define MTK_V4L2_BENCHMARK     0
 #define WAIT_INTR_TIMEOUT_MS   1000
 
-/**
+/*
  * enum mtk_hw_reg_idx - MTK hw register base index
  */
 enum mtk_hw_reg_idx {
@@ -49,7 +49,7 @@ enum mtk_hw_reg_idx {
        NUM_MAX_VCODEC_REG_BASE
 };
 
-/**
+/*
  * enum mtk_instance_type - The type of an MTK Vcodec instance.
  */
 enum mtk_instance_type {
@@ -74,7 +74,7 @@ enum mtk_instance_state {
        MTK_STATE_ABORT = 4,
 };
 
-/**
+/*
  * enum mtk_encode_param - General encoding parameters type
  */
 enum mtk_encode_param {
@@ -92,7 +92,7 @@ enum mtk_fmt_type {
        MTK_FMT_FRAME = 2,
 };
 
-/**
+/*
  * struct mtk_video_fmt - Structure used to store information about pixelformats
  */
 struct mtk_video_fmt {
@@ -102,7 +102,7 @@ struct mtk_video_fmt {
        u32     flags;
 };
 
-/**
+/*
  * struct mtk_codec_framesizes - Structure used to store information about
  *                                                     framesizes
  */
@@ -111,7 +111,7 @@ struct mtk_codec_framesizes {
        struct  v4l2_frmsize_stepwise   stepwise;
 };
 
-/**
+/*
  * enum mtk_q_type - Type of queue
  */
 enum mtk_q_type {
@@ -119,7 +119,7 @@ enum mtk_q_type {
        MTK_Q_DATA_DST = 1,
 };
 
-/**
+/*
  * struct mtk_q_data - Structure used to store information about queue
  */
 struct mtk_q_data {
@@ -168,7 +168,7 @@ struct mtk_enc_params {
        unsigned int    force_intra;
 };
 
-/**
+/*
  * struct mtk_vcodec_clk_info - Structure used to store clock name
  */
 struct mtk_vcodec_clk_info {
@@ -176,7 +176,7 @@ struct mtk_vcodec_clk_info {
        struct clk      *vcodec_clk;
 };
 
-/**
+/*
  * struct mtk_vcodec_clk - Structure used to store vcodec clock information
  */
 struct mtk_vcodec_clk {
@@ -184,7 +184,7 @@ struct mtk_vcodec_clk {
        int     clk_num;
 };
 
-/**
+/*
  * struct mtk_vcodec_pm - Power management data structure
  */
 struct mtk_vcodec_pm {
@@ -255,6 +255,7 @@ struct vdec_pic_info {
  * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
  * @quantization: enum v4l2_quantization, colorspace quantization
  * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ * @decoded_frame_cnt: number of decoded frames
  * @lock: protect variables accessed by V4L2 threads and worker thread such as
  *       mtk_video_dec_buf.
  */
@@ -302,6 +303,7 @@ struct mtk_vcodec_ctx {
 enum mtk_chip {
        MTK_MT8173,
        MTK_MT8183,
+       MTK_MT8192,
 };
 
 /**
@@ -310,7 +312,7 @@ enum mtk_chip {
  * @chip: chip this encoder is compatible with
  *
  * @uses_ext: whether the encoder uses the extended firmware messaging format
- * @min_birate: minimum supported encoding bitrate
+ * @min_bitrate: minimum supported encoding bitrate
  * @max_bitrate: maximum supported encoding bitrate
  * @capture_formats: array of supported capture formats
  * @num_capture_formats: number of entries in capture_formats
@@ -347,10 +349,12 @@ struct mtk_vcodec_enc_pdata {
  * @curr_ctx: The context that is waiting for codec hardware
  *
  * @reg_base: Mapped address of MTK Vcodec registers.
+ * @venc_pdata: encoder IC-specific data
  *
  * @fw_handler: used to communicate with the firmware.
  * @id_counter: used to identify current opened instance
  *
+ * @decode_workqueue: decode work queue
  * @encode_workqueue: encode work queue
  *
  * @int_cond: used to identify interrupt condition happen
index 4831052..416f356 100644 (file)
 
 #define MTK_VENC_MIN_W 160U
 #define MTK_VENC_MIN_H 128U
-#define MTK_VENC_MAX_W 1920U
-#define MTK_VENC_MAX_H 1088U
+#define MTK_VENC_HD_MAX_W      1920U
+#define MTK_VENC_HD_MAX_H      1088U
+#define MTK_VENC_4K_MAX_W      3840U
+#define MTK_VENC_4K_MAX_H      2176U
+
 #define DFT_CFG_WIDTH  MTK_VENC_MIN_W
 #define DFT_CFG_HEIGHT MTK_VENC_MIN_H
 #define MTK_MAX_CTRLS_HINT     20
 
 #define MTK_DEFAULT_FRAMERATE_NUM 1001
 #define MTK_DEFAULT_FRAMERATE_DENOM 30000
+#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
 
 static void mtk_venc_worker(struct work_struct *work);
 
-static const struct v4l2_frmsize_stepwise mtk_venc_framesizes = {
-       MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
-       MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16,
+static const struct v4l2_frmsize_stepwise mtk_venc_hd_framesizes = {
+       MTK_VENC_MIN_W, MTK_VENC_HD_MAX_W, 16,
+       MTK_VENC_MIN_H, MTK_VENC_HD_MAX_H, 16,
 };
 
-#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes)
+static const struct v4l2_frmsize_stepwise mtk_venc_4k_framesizes = {
+       MTK_VENC_MIN_W, MTK_VENC_4K_MAX_W, 16,
+       MTK_VENC_MIN_H, MTK_VENC_4K_MAX_H, 16,
+};
 
 static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
 {
@@ -151,17 +158,22 @@ static int vidioc_enum_framesizes(struct file *file, void *fh,
                                  struct v4l2_frmsizeenum *fsize)
 {
        const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
 
        if (fsize->index != 0)
                return -EINVAL;
 
        fmt = mtk_venc_find_format(fsize->pixel_format,
-                                  fh_to_ctx(fh)->dev->venc_pdata);
+                                  ctx->dev->venc_pdata);
        if (!fmt)
                return -EINVAL;
 
        fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-       fsize->stepwise = mtk_venc_framesizes;
+
+       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+               fsize->stepwise = mtk_venc_4k_framesizes;
+       else
+               fsize->stepwise = mtk_venc_hd_framesizes;
 
        return 0;
 }
@@ -248,7 +260,7 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
 /* V4L2 specification suggests the driver corrects the format struct if any of
  * the dimensions is unsupported
  */
-static int vidioc_try_fmt(struct v4l2_format *f,
+static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
                          const struct mtk_video_fmt *fmt)
 {
        struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
@@ -260,13 +272,22 @@ static int vidioc_try_fmt(struct v4l2_format *f,
                pix_fmt_mp->plane_fmt[0].bytesperline = 0;
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                int tmp_w, tmp_h;
+               unsigned int max_width, max_height;
+
+               if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) {
+                       max_width = MTK_VENC_4K_MAX_W;
+                       max_height = MTK_VENC_4K_MAX_H;
+               } else {
+                       max_width = MTK_VENC_HD_MAX_W;
+                       max_height = MTK_VENC_HD_MAX_H;
+               }
 
                pix_fmt_mp->height = clamp(pix_fmt_mp->height,
                                        MTK_VENC_MIN_H,
-                                       MTK_VENC_MAX_H);
+                                       max_height);
                pix_fmt_mp->width = clamp(pix_fmt_mp->width,
                                        MTK_VENC_MIN_W,
-                                       MTK_VENC_MAX_W);
+                                       max_width);
 
                /* find next closer width align 16, heign align 32, size align
                 * 64 rectangle
@@ -275,16 +296,16 @@ static int vidioc_try_fmt(struct v4l2_format *f,
                tmp_h = pix_fmt_mp->height;
                v4l_bound_align_image(&pix_fmt_mp->width,
                                        MTK_VENC_MIN_W,
-                                       MTK_VENC_MAX_W, 4,
+                                       max_width, 4,
                                        &pix_fmt_mp->height,
                                        MTK_VENC_MIN_H,
-                                       MTK_VENC_MAX_H, 5, 6);
+                                       max_height, 5, 6);
 
                if (pix_fmt_mp->width < tmp_w &&
-                       (pix_fmt_mp->width + 16) <= MTK_VENC_MAX_W)
+                       (pix_fmt_mp->width + 16) <= max_width)
                        pix_fmt_mp->width += 16;
                if (pix_fmt_mp->height < tmp_h &&
-                       (pix_fmt_mp->height + 32) <= MTK_VENC_MAX_H)
+                       (pix_fmt_mp->height + 32) <= max_height)
                        pix_fmt_mp->height += 32;
 
                mtk_v4l2_debug(0,
@@ -405,7 +426,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
        }
 
        q_data->fmt = fmt;
-       ret = vidioc_try_fmt(f, q_data->fmt);
+       ret = vidioc_try_fmt(ctx, f, q_data->fmt);
        if (ret)
                return ret;
 
@@ -443,7 +464,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
        struct mtk_q_data *q_data;
        int ret, i;
        const struct mtk_video_fmt *fmt;
-       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
        if (!vq) {
@@ -468,20 +488,13 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
                f->fmt.pix.pixelformat = fmt->fourcc;
        }
 
-       pix_fmt_mp->height = clamp(pix_fmt_mp->height,
-                               MTK_VENC_MIN_H,
-                               MTK_VENC_MAX_H);
-       pix_fmt_mp->width = clamp(pix_fmt_mp->width,
-                               MTK_VENC_MIN_W,
-                               MTK_VENC_MAX_W);
-
-       q_data->visible_width = f->fmt.pix_mp.width;
-       q_data->visible_height = f->fmt.pix_mp.height;
-       q_data->fmt = fmt;
-       ret = vidioc_try_fmt(f, q_data->fmt);
+       ret = vidioc_try_fmt(ctx, f, fmt);
        if (ret)
                return ret;
 
+       q_data->fmt = fmt;
+       q_data->visible_width = f->fmt.pix_mp.width;
+       q_data->visible_height = f->fmt.pix_mp.height;
        q_data->coded_width = f->fmt.pix_mp.width;
        q_data->coded_height = f->fmt.pix_mp.height;
 
@@ -553,7 +566,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
        f->fmt.pix_mp.quantization = ctx->quantization;
        f->fmt.pix_mp.xfer_func = ctx->xfer_func;
 
-       return vidioc_try_fmt(f, fmt);
+       return vidioc_try_fmt(ctx, f, fmt);
 }
 
 static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
@@ -575,7 +588,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
                f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
        }
 
-       return vidioc_try_fmt(f, fmt);
+       return vidioc_try_fmt(ctx, f, fmt);
 }
 
 static int vidioc_venc_g_selection(struct file *file, void *priv,
@@ -1179,16 +1192,16 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
 
        v4l_bound_align_image(&q_data->coded_width,
                                MTK_VENC_MIN_W,
-                               MTK_VENC_MAX_W, 4,
+                               MTK_VENC_HD_MAX_W, 4,
                                &q_data->coded_height,
                                MTK_VENC_MIN_H,
-                               MTK_VENC_MAX_H, 5, 6);
+                               MTK_VENC_HD_MAX_H, 5, 6);
 
        if (q_data->coded_width < DFT_CFG_WIDTH &&
-               (q_data->coded_width + 16) <= MTK_VENC_MAX_W)
+               (q_data->coded_width + 16) <= MTK_VENC_HD_MAX_W)
                q_data->coded_width += 16;
        if (q_data->coded_height < DFT_CFG_HEIGHT &&
-               (q_data->coded_height + 32) <= MTK_VENC_MAX_H)
+               (q_data->coded_height + 32) <= MTK_VENC_HD_MAX_H)
                q_data->coded_height += 32;
 
        q_data->sizeimage[0] =
@@ -1218,6 +1231,12 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
 {
        const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops;
        struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
+       u8 h264_max_level;
+
+       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+       else
+               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
 
        v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
 
@@ -1248,8 +1267,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
                        V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
                        0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
        v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-                       V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
-                       0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+                              h264_max_level,
+                              0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+
        if (handler->error) {
                mtk_v4l2_err("Init control handler fail %d",
                                handler->error);
index 7d7b8cf..45d1870 100644 (file)
@@ -361,6 +361,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
                goto err_event_workq;
        }
 
+       if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+               dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
        ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, 1);
        if (ret) {
                mtk_v4l2_err("Failed to register video device");
@@ -422,12 +425,26 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
        .core_id = VENC_SYS,
 };
 
+static const struct mtk_vcodec_enc_pdata mt8192_pdata = {
+       .chip = MTK_MT8192,
+       .uses_ext = true,
+       /* MT8192 supports the same capture formats as MT8183 */
+       .capture_formats = mtk_video_formats_capture_mt8183,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183),
+       /* MT8192 supports the same output formats as MT8173 */
+       .output_formats = mtk_video_formats_output_mt8173,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173),
+       .min_bitrate = 64,
+       .max_bitrate = 100000000,
+       .core_id = VENC_SYS,
+};
 static const struct of_device_id mtk_vcodec_enc_match[] = {
        {.compatible = "mediatek,mt8173-vcodec-enc",
                        .data = &mt8173_avc_pdata},
        {.compatible = "mediatek,mt8173-vcodec-enc-vp8",
                        .data = &mt8173_vp8_pdata},
        {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
+       {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata},
        {},
 };
 MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
index 47a1c1c..68e8d5c 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _VDEC_IPI_MSG_H_
 #define _VDEC_IPI_MSG_H_
 
-/**
+/*
  * enum vdec_ipi_msgid - message id between AP and VPU
  * @AP_IPIMSG_XXX      : AP to VPU cmd message id
  * @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id
index d0123df..b6a4f20 100644 (file)
@@ -215,6 +215,10 @@ static unsigned int h264_get_level(struct venc_h264_inst *inst,
                return 41;
        case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
                return 42;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 50;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+               return 51;
        default:
                mtk_vcodec_debug(inst, "unsupported level %d", level);
                return 31;
index 5f53d42..587a2cf 100644 (file)
@@ -12,7 +12,7 @@
 #define AP_IPIMSG_VENC_BASE 0xC000
 #define VPU_IPIMSG_VENC_BASE 0xD000
 
-/**
+/*
  * enum venc_ipi_msg_id - message id between AP and VPU
  * (ipi stands for inter-processor interrupt)
  * @AP_IPIMSG_ENC_XXX:         AP to VPU cmd message id
@@ -111,7 +111,7 @@ struct venc_ap_ipi_msg_deinit {
        uint32_t vpu_inst_addr;
 };
 
-/**
+/*
  * enum venc_ipi_msg_status - VPU ack AP cmd status
  */
 enum venc_ipi_msg_status {
index c8a5627..ec290dd 100644 (file)
@@ -821,13 +821,11 @@ static int mtk_vpu_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        vpu->dev = &pdev->dev;
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcm");
-       vpu->reg.tcm = devm_ioremap_resource(dev, res);
+       vpu->reg.tcm = devm_platform_ioremap_resource_byname(pdev, "tcm");
        if (IS_ERR((__force void *)vpu->reg.tcm))
                return PTR_ERR((__force void *)vpu->reg.tcm);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_reg");
-       vpu->reg.cfg = devm_ioremap_resource(dev, res);
+       vpu->reg.cfg = devm_platform_ioremap_resource_byname(pdev, "cfg_reg");
        if (IS_ERR((__force void *)vpu->reg.cfg))
                return PTR_ERR((__force void *)vpu->reg.cfg);
 
@@ -987,6 +985,12 @@ static int mtk_vpu_suspend(struct device *dev)
                return ret;
        }
 
+       if (!vpu_running(vpu)) {
+               vpu_clock_disable(vpu);
+               clk_unprepare(vpu->clk);
+               return 0;
+       }
+
        mutex_lock(&vpu->vpu_mutex);
        /* disable vpu timer interrupt */
        vpu_cfg_writel(vpu, vpu_cfg_readl(vpu, VPU_INT_STATUS) | VPU_IDLE_STATE,
index 4e8905e..108b5e9 100644 (file)
@@ -29,7 +29,8 @@
 #define CCDC_MIN_HEIGHT                32
 
 static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_format(struct isp_ccdc_device *ccdc,
+                 struct v4l2_subdev_state *sd_state,
                  unsigned int pad, enum v4l2_subdev_format_whence which);
 
 static const unsigned int ccdc_fmts[] = {
@@ -1936,21 +1937,25 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_format(struct isp_ccdc_device *ccdc,
+                 struct v4l2_subdev_state *sd_state,
                  unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&ccdc->subdev, sd_state,
+                                                 pad);
        else
                return &ccdc->formats[pad];
 }
 
 static struct v4l2_rect *
-__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_crop(struct isp_ccdc_device *ccdc,
+               struct v4l2_subdev_state *sd_state,
                enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF);
+               return v4l2_subdev_get_try_crop(&ccdc->subdev, sd_state,
+                                               CCDC_PAD_SOURCE_OF);
        else
                return &ccdc->crop;
 }
@@ -1963,7 +1968,8 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
  * @fmt: Format
  */
 static void
-ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+ccdc_try_format(struct isp_ccdc_device *ccdc,
+               struct v4l2_subdev_state *sd_state,
                unsigned int pad, struct v4l2_mbus_framefmt *fmt,
                enum v4l2_subdev_format_whence which)
 {
@@ -1999,7 +2005,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
        case CCDC_PAD_SOURCE_OF:
                pixelcode = fmt->code;
                field = fmt->field;
-               *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
+               *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+                                         which);
 
                /* In SYNC mode the bridge converts YUV formats from 2X8 to
                 * 1X16. In BT.656 no such conversion occurs. As we don't know
@@ -2024,7 +2031,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
                }
 
                /* Hardcode the output size to the crop rectangle size. */
-               crop = __ccdc_get_crop(ccdc, cfg, which);
+               crop = __ccdc_get_crop(ccdc, sd_state, which);
                fmt->width = crop->width;
                fmt->height = crop->height;
 
@@ -2041,7 +2048,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
                break;
 
        case CCDC_PAD_SOURCE_VP:
-               *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
+               *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+                                         which);
 
                /* The video port interface truncates the data to 10 bits. */
                info = omap3isp_video_format_info(fmt->code);
@@ -2118,7 +2126,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
  * return -EINVAL or zero on success
  */
 static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2133,7 +2141,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
                break;
 
        case CCDC_PAD_SOURCE_OF:
-               format = __ccdc_get_format(ccdc, cfg, code->pad,
+               format = __ccdc_get_format(ccdc, sd_state, code->pad,
                                           code->which);
 
                if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
@@ -2164,7 +2172,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index != 0)
                        return -EINVAL;
 
-               format = __ccdc_get_format(ccdc, cfg, code->pad,
+               format = __ccdc_get_format(ccdc, sd_state, code->pad,
                                           code->which);
 
                /* A pixel code equal to 0 means that the video port doesn't
@@ -2184,7 +2192,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2196,7 +2204,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
+       ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -2206,7 +2214,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
+       ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -2224,7 +2232,8 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
  *
  * Return 0 on success or a negative error code otherwise.
  */
-static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_get_selection(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_selection *sel)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2240,12 +2249,13 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
                sel->r.width = INT_MAX;
                sel->r.height = INT_MAX;
 
-               format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
+               format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+                                          sel->which);
                ccdc_try_crop(ccdc, format, &sel->r);
                break;
 
        case V4L2_SEL_TGT_CROP:
-               sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
+               sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);
                break;
 
        default:
@@ -2266,7 +2276,8 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
  *
  * Return 0 on success or a negative error code otherwise.
  */
-static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_set_selection(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_selection *sel)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2285,17 +2296,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
         * rectangle.
         */
        if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
-               sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
+               sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);
                return 0;
        }
 
-       format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
+       format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK, sel->which);
        ccdc_try_crop(ccdc, format, &sel->r);
-       *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r;
+       *__ccdc_get_crop(ccdc, sd_state, sel->which) = sel->r;
 
        /* Update the source format. */
-       format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which);
-       ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which);
+       format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,
+                                  sel->which);
+       ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,
+                       sel->which);
 
        return 0;
 }
@@ -2309,13 +2322,14 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
  * to the format type.
  */
-static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_get_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
+       format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -2332,24 +2346,25 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
  * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
  * to the format type.
  */
-static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_set_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
+       format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which);
+       ccdc_try_format(ccdc, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == CCDC_PAD_SINK) {
                /* Reset the crop rectangle. */
-               crop = __ccdc_get_crop(ccdc, cfg, fmt->which);
+               crop = __ccdc_get_crop(ccdc, sd_state, fmt->which);
                crop->left = 0;
                crop->top = 0;
                crop->width = fmt->format.width;
@@ -2358,16 +2373,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
                ccdc_try_crop(ccdc, &fmt->format, crop);
 
                /* Update the source formats. */
-               format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF,
+               format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,
                                           fmt->which);
                *format = fmt->format;
-               ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format,
+               ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,
                                fmt->which);
 
-               format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP,
+               format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP,
                                           fmt->which);
                *format = fmt->format;
-               ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format,
+               ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP, format,
                                fmt->which);
        }
 
@@ -2454,7 +2469,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       ccdc_set_format(sd, fh ? fh->pad : NULL, &format);
+       ccdc_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index d0a49cd..acb58b6 100644 (file)
@@ -618,11 +618,13 @@ static const unsigned int ccp2_fmts[] = {
  * return format structure or NULL on error
  */
 static struct v4l2_mbus_framefmt *
-__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg,
-                    unsigned int pad, enum v4l2_subdev_format_whence which)
+__ccp2_get_format(struct isp_ccp2_device *ccp2,
+                 struct v4l2_subdev_state *sd_state,
+                 unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&ccp2->subdev, sd_state,
+                                                 pad);
        else
                return &ccp2->formats[pad];
 }
@@ -636,7 +638,8 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *c
  * @which : wanted subdev format
  */
 static void ccp2_try_format(struct isp_ccp2_device *ccp2,
-                              struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                              struct v4l2_subdev_state *sd_state,
+                              unsigned int pad,
                               struct v4l2_mbus_framefmt *fmt,
                               enum v4l2_subdev_format_whence which)
 {
@@ -670,7 +673,8 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
                 * When CCP2 write to memory feature will be added this
                 * should be changed properly.
                 */
-               format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which);
+               format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SINK,
+                                          which);
                memcpy(fmt, format, sizeof(*fmt));
                fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
                break;
@@ -688,7 +692,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
  * return -EINVAL or zero on success
  */
 static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -703,8 +707,8 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index != 0)
                        return -EINVAL;
 
-               format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK,
-                                             code->which);
+               format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SINK,
+                                          code->which);
                code->code = format->code;
        }
 
@@ -712,7 +716,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -724,7 +728,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
+       ccp2_try_format(ccp2, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -734,7 +738,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
+       ccp2_try_format(ccp2, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -748,13 +752,14 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
  * @fmt   : pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                             struct v4l2_subdev_format *fmt)
+static int ccp2_get_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
+                          struct v4l2_subdev_format *fmt)
 {
        struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
+       format = __ccp2_get_format(ccp2, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -769,25 +774,27 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
  * @fmt   : pointer to v4l2 subdev format structure
  * returns zero
  */
-static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
-                             struct v4l2_subdev_format *fmt)
+static int ccp2_set_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
+                          struct v4l2_subdev_format *fmt)
 {
        struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
+       format = __ccp2_get_format(ccp2, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which);
+       ccp2_try_format(ccp2, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == CCP2_PAD_SINK) {
-               format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE,
+               format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SOURCE,
                                           fmt->which);
                *format = fmt->format;
-               ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which);
+               ccp2_try_format(ccp2, sd_state, CCP2_PAD_SOURCE, format,
+                               fmt->which);
        }
 
        return 0;
@@ -812,7 +819,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       ccp2_set_format(sd, fh ? fh->pad : NULL, &format);
+       ccp2_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index fd493c5..6302e0c 100644 (file)
@@ -827,17 +827,20 @@ static const struct isp_video_operations csi2_ispvideo_ops = {
  */
 
 static struct v4l2_mbus_framefmt *
-__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
+__csi2_get_format(struct isp_csi2_device *csi2,
+                 struct v4l2_subdev_state *sd_state,
                  unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+                                                 pad);
        else
                return &csi2->formats[pad];
 }
 
 static void
-csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
+csi2_try_format(struct isp_csi2_device *csi2,
+               struct v4l2_subdev_state *sd_state,
                unsigned int pad, struct v4l2_mbus_framefmt *fmt,
                enum v4l2_subdev_format_whence which)
 {
@@ -867,7 +870,8 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg
                 * compression.
                 */
                pixelcode = fmt->code;
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which);
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
+                                          which);
                memcpy(fmt, format, sizeof(*fmt));
 
                /*
@@ -893,7 +897,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg
  * return -EINVAL or zero on success
  */
 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -906,7 +910,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
 
                code->code = csi2_input_fmts[code->index];
        } else {
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK,
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
                                           code->which);
                switch (code->index) {
                case 0:
@@ -930,7 +934,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int csi2_enum_frame_size(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -942,7 +946,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+       csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -952,7 +956,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+       csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -966,13 +970,14 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
  * @fmt: pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int csi2_get_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+       format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -987,25 +992,27 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
  * @fmt: pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int csi2_set_format(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+       format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which);
+       csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == CSI2_PAD_SINK) {
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE,
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE,
                                           fmt->which);
                *format = fmt->format;
-               csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which);
+               csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format,
+                               fmt->which);
        }
 
        return 0;
@@ -1030,7 +1037,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       csi2_set_format(sd, fh ? fh->pad : NULL, &format);
+       csi2_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index 607b768..53aedec 100644 (file)
@@ -1679,21 +1679,25 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static struct v4l2_mbus_framefmt *
-__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
+__preview_get_format(struct isp_prev_device *prev,
+                    struct v4l2_subdev_state *sd_state,
                     unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&prev->subdev, sd_state,
+                                                 pad);
        else
                return &prev->formats[pad];
 }
 
 static struct v4l2_rect *
-__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
+__preview_get_crop(struct isp_prev_device *prev,
+                  struct v4l2_subdev_state *sd_state,
                   enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK);
+               return v4l2_subdev_get_try_crop(&prev->subdev, sd_state,
+                                               PREV_PAD_SINK);
        else
                return &prev->crop;
 }
@@ -1729,7 +1733,8 @@ static const unsigned int preview_output_fmts[] = {
  * engine limits and the format and crop rectangles on other pads.
  */
 static void preview_try_format(struct isp_prev_device *prev,
-                              struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                              struct v4l2_subdev_state *sd_state,
+                              unsigned int pad,
                               struct v4l2_mbus_framefmt *fmt,
                               enum v4l2_subdev_format_whence which)
 {
@@ -1770,7 +1775,8 @@ static void preview_try_format(struct isp_prev_device *prev,
 
        case PREV_PAD_SOURCE:
                pixelcode = fmt->code;
-               *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which);
+               *fmt = *__preview_get_format(prev, sd_state, PREV_PAD_SINK,
+                                            which);
 
                switch (pixelcode) {
                case MEDIA_BUS_FMT_YUYV8_1X16:
@@ -1788,7 +1794,7 @@ static void preview_try_format(struct isp_prev_device *prev,
                 * is not supported yet, hardcode the output size to the crop
                 * rectangle size.
                 */
-               crop = __preview_get_crop(prev, cfg, which);
+               crop = __preview_get_crop(prev, sd_state, which);
                fmt->width = crop->width;
                fmt->height = crop->height;
 
@@ -1862,7 +1868,7 @@ static void preview_try_crop(struct isp_prev_device *prev,
  * return -EINVAL or zero on success
  */
 static int preview_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        switch (code->pad) {
@@ -1886,7 +1892,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int preview_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1898,7 +1904,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       preview_try_format(prev, cfg, fse->pad, &format, fse->which);
+       preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -1908,7 +1914,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       preview_try_format(prev, cfg, fse->pad, &format, fse->which);
+       preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -1926,7 +1932,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
  * Return 0 on success or a negative error code otherwise.
  */
 static int preview_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1942,13 +1948,13 @@ static int preview_get_selection(struct v4l2_subdev *sd,
                sel->r.width = INT_MAX;
                sel->r.height = INT_MAX;
 
-               format = __preview_get_format(prev, cfg, PREV_PAD_SINK,
+               format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
                                              sel->which);
                preview_try_crop(prev, format, &sel->r);
                break;
 
        case V4L2_SEL_TGT_CROP:
-               sel->r = *__preview_get_crop(prev, cfg, sel->which);
+               sel->r = *__preview_get_crop(prev, sd_state, sel->which);
                break;
 
        default:
@@ -1969,7 +1975,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
  * Return 0 on success or a negative error code otherwise.
  */
 static int preview_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1988,17 +1994,20 @@ static int preview_set_selection(struct v4l2_subdev *sd,
         * rectangle.
         */
        if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
-               sel->r = *__preview_get_crop(prev, cfg, sel->which);
+               sel->r = *__preview_get_crop(prev, sd_state, sel->which);
                return 0;
        }
 
-       format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which);
+       format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
+                                     sel->which);
        preview_try_crop(prev, format, &sel->r);
-       *__preview_get_crop(prev, cfg, sel->which) = sel->r;
+       *__preview_get_crop(prev, sd_state, sel->which) = sel->r;
 
        /* Update the source format. */
-       format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which);
-       preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which);
+       format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
+                                     sel->which);
+       preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
+                          sel->which);
 
        return 0;
 }
@@ -2010,13 +2019,14 @@ static int preview_set_selection(struct v4l2_subdev *sd,
  * @fmt: pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int preview_get_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
+       format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -2031,24 +2041,25 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
  * @fmt: pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int preview_set_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
+       format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which);
+       preview_try_format(prev, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == PREV_PAD_SINK) {
                /* Reset the crop rectangle. */
-               crop = __preview_get_crop(prev, cfg, fmt->which);
+               crop = __preview_get_crop(prev, sd_state, fmt->which);
                crop->left = 0;
                crop->top = 0;
                crop->width = fmt->format.width;
@@ -2057,9 +2068,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
                preview_try_crop(prev, &fmt->format, crop);
 
                /* Update the source format. */
-               format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE,
+               format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
                                              fmt->which);
-               preview_try_format(prev, cfg, PREV_PAD_SOURCE, format,
+               preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
                                   fmt->which);
        }
 
@@ -2086,7 +2097,7 @@ static int preview_init_formats(struct v4l2_subdev *sd,
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       preview_set_format(sd, fh ? fh->pad : NULL, &format);
+       preview_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index 78d9dd7..ed2fb0c 100644 (file)
@@ -114,11 +114,12 @@ static const struct isprsz_coef filter_coefs = {
  * return zero
  */
 static struct v4l2_mbus_framefmt *
-__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
+__resizer_get_format(struct isp_res_device *res,
+                    struct v4l2_subdev_state *sd_state,
                     unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&res->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&res->subdev, sd_state, pad);
        else
                return &res->formats[pad];
 }
@@ -130,11 +131,13 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *
  * @which : wanted subdev crop rectangle
  */
 static struct v4l2_rect *
-__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
+__resizer_get_crop(struct isp_res_device *res,
+                  struct v4l2_subdev_state *sd_state,
                   enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK);
+               return v4l2_subdev_get_try_crop(&res->subdev, sd_state,
+                                               RESZ_PAD_SINK);
        else
                return &res->crop.request;
 }
@@ -1220,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
  * Return 0 on success or a negative error code otherwise.
  */
 static int resizer_get_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1231,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
        if (sel->pad != RESZ_PAD_SINK)
                return -EINVAL;
 
-       format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+       format_sink = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
                                           sel->which);
-       format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+       format_source = __resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
                                             sel->which);
 
        switch (sel->target) {
@@ -1248,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
                break;
 
        case V4L2_SEL_TGT_CROP:
-               sel->r = *__resizer_get_crop(res, cfg, sel->which);
+               sel->r = *__resizer_get_crop(res, sd_state, sel->which);
                resizer_calc_ratios(res, &sel->r, format_source, &ratio);
                break;
 
@@ -1273,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
  * Return 0 on success or a negative error code otherwise.
  */
 static int resizer_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_selection *sel)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1287,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
            sel->pad != RESZ_PAD_SINK)
                return -EINVAL;
 
-       format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+       format_sink = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
                                           sel->which);
-       format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+       format_source = *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
                                              sel->which);
 
        dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1307,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
         * stored the mangled rectangle.
         */
        resizer_try_crop(format_sink, &format_source, &sel->r);
-       *__resizer_get_crop(res, cfg, sel->which) = sel->r;
+       *__resizer_get_crop(res, sd_state, sel->which) = sel->r;
        resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
 
        dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1317,7 +1320,8 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
                format_source.width, format_source.height);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
+               *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
+                                     sel->which) =
                        format_source;
                return 0;
        }
@@ -1328,7 +1332,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
         */
        spin_lock_irqsave(&res->lock, flags);
 
-       *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
+       *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE, sel->which) =
                format_source;
 
        res->ratio = ratio;
@@ -1371,7 +1375,8 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res)
  * @which : wanted subdev format
  */
 static void resizer_try_format(struct isp_res_device *res,
-                              struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                              struct v4l2_subdev_state *sd_state,
+                              unsigned int pad,
                               struct v4l2_mbus_framefmt *fmt,
                               enum v4l2_subdev_format_whence which)
 {
@@ -1392,10 +1397,11 @@ static void resizer_try_format(struct isp_res_device *res,
                break;
 
        case RESZ_PAD_SOURCE:
-               format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which);
+               format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
+                                             which);
                fmt->code = format->code;
 
-               crop = *__resizer_get_crop(res, cfg, which);
+               crop = *__resizer_get_crop(res, sd_state, which);
                resizer_calc_ratios(res, &crop, fmt, &ratio);
                break;
        }
@@ -1412,7 +1418,7 @@ static void resizer_try_format(struct isp_res_device *res,
  * return -EINVAL or zero on success
  */
 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1427,7 +1433,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index != 0)
                        return -EINVAL;
 
-               format = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+               format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
                                              code->which);
                code->code = format->code;
        }
@@ -1436,7 +1442,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1448,7 +1454,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       resizer_try_format(res, cfg, fse->pad, &format, fse->which);
+       resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -1458,7 +1464,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       resizer_try_format(res, cfg, fse->pad, &format, fse->which);
+       resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -1472,13 +1478,14 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
  * @fmt   : pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int resizer_get_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
+       format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -1493,33 +1500,34 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
  * @fmt   : pointer to v4l2 subdev format structure
  * return -EINVAL or zero on success
  */
-static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int resizer_set_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct isp_res_device *res = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
-       format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
+       format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which);
+       resizer_try_format(res, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        if (fmt->pad == RESZ_PAD_SINK) {
                /* reset crop rectangle */
-               crop = __resizer_get_crop(res, cfg, fmt->which);
+               crop = __resizer_get_crop(res, sd_state, fmt->which);
                crop->left = 0;
                crop->top = 0;
                crop->width = fmt->format.width;
                crop->height = fmt->format.height;
 
                /* Propagate the format from sink to source */
-               format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+               format = __resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
                                              fmt->which);
                *format = fmt->format;
-               resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format,
+               resizer_try_format(res, sd_state, RESZ_PAD_SOURCE, format,
                                   fmt->which);
        }
 
@@ -1570,7 +1578,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
        format.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
        format.format.width = 4096;
        format.format.height = 4096;
-       resizer_set_format(sd, fh ? fh->pad : NULL, &format);
+       resizer_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index dd510ee..ec4c010 100644 (file)
@@ -1792,6 +1792,9 @@ static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
        const struct pxa_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -1816,7 +1819,7 @@ static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
                              pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
 
        v4l2_fill_mbus_format(mf, pix, xlate->code);
-       ret = sensor_call(pcdev, pad, set_fmt, &pad_cfg, &format);
+       ret = sensor_call(pcdev, pad, set_fmt, &pad_state, &format);
        if (ret < 0)
                return ret;
 
index cc11fbf..a1637b7 100644 (file)
@@ -156,11 +156,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
        int ret;
 
        if (on) {
-               ret = pm_runtime_get_sync(dev);
-               if (ret < 0) {
-                       pm_runtime_put_sync(dev);
+               ret = pm_runtime_resume_and_get(dev);
+               if (ret < 0)
                        return ret;
-               }
 
                ret = regulator_enable(csid->vdda);
                if (ret < 0) {
@@ -247,12 +245,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
  */
 static struct v4l2_mbus_framefmt *
 __csid_get_format(struct csid_device *csid,
-                 struct v4l2_subdev_pad_config *cfg,
+                 struct v4l2_subdev_state *sd_state,
                  unsigned int pad,
                  enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csid->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&csid->subdev, sd_state,
+                                                 pad);
 
        return &csid->fmt[pad];
 }
@@ -266,7 +265,7 @@ __csid_get_format(struct csid_device *csid,
  * @which: wanted subdev format
  */
 static void csid_try_format(struct csid_device *csid,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            unsigned int pad,
                            struct v4l2_mbus_framefmt *fmt,
                            enum v4l2_subdev_format_whence which)
@@ -299,7 +298,7 @@ static void csid_try_format(struct csid_device *csid,
                        /* keep pad formats in sync */
                        u32 code = fmt->code;
 
-                       *fmt = *__csid_get_format(csid, cfg,
+                       *fmt = *__csid_get_format(csid, sd_state,
                                                      MSM_CSID_PAD_SINK, which);
                        fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
                } else {
@@ -333,7 +332,7 @@ static void csid_try_format(struct csid_device *csid,
  * return -EINVAL or zero on success
  */
 static int csid_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        struct csid_device *csid = v4l2_get_subdevdata(sd);
@@ -347,7 +346,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
                if (csid->testgen_mode->cur.val == 0) {
                        struct v4l2_mbus_framefmt *sink_fmt;
 
-                       sink_fmt = __csid_get_format(csid, cfg,
+                       sink_fmt = __csid_get_format(csid, sd_state,
                                                     MSM_CSID_PAD_SINK,
                                                     code->which);
 
@@ -374,7 +373,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int csid_enum_frame_size(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        struct csid_device *csid = v4l2_get_subdevdata(sd);
@@ -386,7 +385,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       csid_try_format(csid, cfg, fse->pad, &format, fse->which);
+       csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -396,7 +395,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       csid_try_format(csid, cfg, fse->pad, &format, fse->which);
+       csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -412,13 +411,13 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int csid_get_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct csid_device *csid = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
+       format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -436,26 +435,26 @@ static int csid_get_format(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int csid_set_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct csid_device *csid = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
+       format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       csid_try_format(csid, cfg, fmt->pad, &fmt->format, fmt->which);
+       csid_try_format(csid, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == MSM_CSID_PAD_SINK) {
-               format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SRC,
+               format = __csid_get_format(csid, sd_state, MSM_CSID_PAD_SRC,
                                           fmt->which);
 
                *format = fmt->format;
-               csid_try_format(csid, cfg, MSM_CSID_PAD_SRC, format,
+               csid_try_format(csid, sd_state, MSM_CSID_PAD_SRC, format,
                                fmt->which);
        }
 
@@ -484,7 +483,7 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                }
        };
 
-       return csid_set_format(sd, fh ? fh->pad : NULL, &format);
+       return csid_set_format(sd, fh ? fh->state : NULL, &format);
 }
 
 /*
@@ -566,8 +565,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 
        /* Memory */
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-       csid->base = devm_ioremap_resource(dev, r);
+       csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
        if (IS_ERR(csid->base))
                return PTR_ERR(csid->base);
 
@@ -584,14 +582,13 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
        snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
                 dev_name(dev), MSM_CSID_NAME, csid->id);
        ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
-                              IRQF_TRIGGER_RISING, csid->irq_name, csid);
+                              IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
+                              csid->irq_name, csid);
        if (ret < 0) {
                dev_err(dev, "request_irq failed: %d\n", ret);
                return ret;
        }
 
-       disable_irq(csid->irq);
-
        /* Clocks */
 
        csid->nclocks = 0;
index b3c3bf1..24eec16 100644 (file)
@@ -197,11 +197,9 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
        if (on) {
                int ret;
 
-               ret = pm_runtime_get_sync(dev);
-               if (ret < 0) {
-                       pm_runtime_put_sync(dev);
+               ret = pm_runtime_resume_and_get(dev);
+               if (ret < 0)
                        return ret;
-               }
 
                ret = csiphy_set_clock_rates(csiphy);
                if (ret < 0) {
@@ -340,12 +338,13 @@ static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
  */
 static struct v4l2_mbus_framefmt *
 __csiphy_get_format(struct csiphy_device *csiphy,
-                   struct v4l2_subdev_pad_config *cfg,
+                   struct v4l2_subdev_state *sd_state,
                    unsigned int pad,
                    enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csiphy->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&csiphy->subdev, sd_state,
+                                                 pad);
 
        return &csiphy->fmt[pad];
 }
@@ -359,7 +358,7 @@ __csiphy_get_format(struct csiphy_device *csiphy,
  * @which: wanted subdev format
  */
 static void csiphy_try_format(struct csiphy_device *csiphy,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              unsigned int pad,
                              struct v4l2_mbus_framefmt *fmt,
                              enum v4l2_subdev_format_whence which)
@@ -389,7 +388,8 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
        case MSM_CSIPHY_PAD_SRC:
                /* Set and return a format same as sink pad */
 
-               *fmt = *__csiphy_get_format(csiphy, cfg, MSM_CSID_PAD_SINK,
+               *fmt = *__csiphy_get_format(csiphy, sd_state,
+                                           MSM_CSID_PAD_SINK,
                                            which);
 
                break;
@@ -404,7 +404,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
  * return -EINVAL or zero on success
  */
 static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
@@ -419,7 +419,8 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index > 0)
                        return -EINVAL;
 
-               format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SINK,
+               format = __csiphy_get_format(csiphy, sd_state,
+                                            MSM_CSIPHY_PAD_SINK,
                                             code->which);
 
                code->code = format->code;
@@ -436,7 +437,7 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
@@ -448,7 +449,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which);
+       csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -458,7 +459,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which);
+       csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -474,13 +475,13 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int csiphy_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which);
+       format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -498,26 +499,29 @@ static int csiphy_get_format(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int csiphy_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which);
+       format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       csiphy_try_format(csiphy, cfg, fmt->pad, &fmt->format, fmt->which);
+       csiphy_try_format(csiphy, sd_state, fmt->pad, &fmt->format,
+                         fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == MSM_CSIPHY_PAD_SINK) {
-               format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC,
+               format = __csiphy_get_format(csiphy, sd_state,
+                                            MSM_CSIPHY_PAD_SRC,
                                             fmt->which);
 
                *format = fmt->format;
-               csiphy_try_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC, format,
+               csiphy_try_format(csiphy, sd_state, MSM_CSIPHY_PAD_SRC,
+                                 format,
                                  fmt->which);
        }
 
@@ -547,7 +551,7 @@ static int csiphy_init_formats(struct v4l2_subdev *sd,
                }
        };
 
-       return csiphy_set_format(sd, fh ? fh->pad : NULL, &format);
+       return csiphy_set_format(sd, fh ? fh->state : NULL, &format);
 }
 
 /*
@@ -591,16 +595,14 @@ int msm_csiphy_subdev_init(struct camss *camss,
 
        /* Memory */
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-       csiphy->base = devm_ioremap_resource(dev, r);
+       csiphy->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
        if (IS_ERR(csiphy->base))
                return PTR_ERR(csiphy->base);
 
        if (camss->version == CAMSS_8x16 ||
            camss->version == CAMSS_8x96) {
-               r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                res->reg[1]);
-               csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
+               csiphy->base_clk_mux =
+                       devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
                if (IS_ERR(csiphy->base_clk_mux))
                        return PTR_ERR(csiphy->base_clk_mux);
        } else {
@@ -621,14 +623,13 @@ int msm_csiphy_subdev_init(struct camss *camss,
                 dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
 
        ret = devm_request_irq(dev, csiphy->irq, csiphy->ops->isr,
-                              IRQF_TRIGGER_RISING, csiphy->irq_name, csiphy);
+                              IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
+                              csiphy->irq_name, csiphy);
        if (ret < 0) {
                dev_err(dev, "request_irq failed: %d\n", ret);
                return ret;
        }
 
-       disable_irq(csiphy->irq);
-
        /* Clocks */
 
        csiphy->nclocks = 0;
index 37611c8..ba5d65f 100644 (file)
@@ -372,11 +372,9 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
                        goto exit;
                }
 
-               ret = pm_runtime_get_sync(dev);
-               if (ret < 0) {
-                       pm_runtime_put_sync(dev);
+               ret = pm_runtime_resume_and_get(dev);
+               if (ret < 0)
                        goto exit;
-               }
 
                ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev);
                if (ret < 0) {
@@ -876,12 +874,13 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
  */
 static struct v4l2_mbus_framefmt *
 __ispif_get_format(struct ispif_line *line,
-                  struct v4l2_subdev_pad_config *cfg,
+                  struct v4l2_subdev_state *sd_state,
                   unsigned int pad,
                   enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&line->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&line->subdev, sd_state,
+                                                 pad);
 
        return &line->fmt[pad];
 }
@@ -895,7 +894,7 @@ __ispif_get_format(struct ispif_line *line,
  * @which: wanted subdev format
  */
 static void ispif_try_format(struct ispif_line *line,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             unsigned int pad,
                             struct v4l2_mbus_framefmt *fmt,
                             enum v4l2_subdev_format_whence which)
@@ -925,7 +924,7 @@ static void ispif_try_format(struct ispif_line *line,
        case MSM_ISPIF_PAD_SRC:
                /* Set and return a format same as sink pad */
 
-               *fmt = *__ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK,
+               *fmt = *__ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SINK,
                                           which);
 
                break;
@@ -942,7 +941,7 @@ static void ispif_try_format(struct ispif_line *line,
  * return -EINVAL or zero on success
  */
 static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        struct ispif_line *line = v4l2_get_subdevdata(sd);
@@ -957,7 +956,8 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index > 0)
                        return -EINVAL;
 
-               format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK,
+               format = __ispif_get_format(line, sd_state,
+                                           MSM_ISPIF_PAD_SINK,
                                            code->which);
 
                code->code = format->code;
@@ -974,7 +974,7 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int ispif_enum_frame_size(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_frame_size_enum *fse)
 {
        struct ispif_line *line = v4l2_get_subdevdata(sd);
@@ -986,7 +986,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       ispif_try_format(line, cfg, fse->pad, &format, fse->which);
+       ispif_try_format(line, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -996,7 +996,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       ispif_try_format(line, cfg, fse->pad, &format, fse->which);
+       ispif_try_format(line, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -1012,13 +1012,13 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int ispif_get_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct ispif_line *line = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ispif_get_format(line, cfg, fmt->pad, fmt->which);
+       format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -1036,26 +1036,26 @@ static int ispif_get_format(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int ispif_set_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct ispif_line *line = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ispif_get_format(line, cfg, fmt->pad, fmt->which);
+       format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       ispif_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which);
+       ispif_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == MSM_ISPIF_PAD_SINK) {
-               format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SRC,
+               format = __ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SRC,
                                            fmt->which);
 
                *format = fmt->format;
-               ispif_try_format(line, cfg, MSM_ISPIF_PAD_SRC, format,
+               ispif_try_format(line, sd_state, MSM_ISPIF_PAD_SRC, format,
                                 fmt->which);
        }
 
@@ -1084,7 +1084,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                }
        };
 
-       return ispif_set_format(sd, fh ? fh->pad : NULL, &format);
+       return ispif_set_format(sd, fh ? fh->state : NULL, &format);
 }
 
 /*
@@ -1143,13 +1143,11 @@ int msm_ispif_subdev_init(struct camss *camss,
 
        /* Memory */
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-       ispif->base = devm_ioremap_resource(dev, r);
+       ispif->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
        if (IS_ERR(ispif->base))
                return PTR_ERR(ispif->base);
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
-       ispif->base_clk_mux = devm_ioremap_resource(dev, r);
+       ispif->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
        if (IS_ERR(ispif->base_clk_mux))
                return PTR_ERR(ispif->base_clk_mux);
 
index 15695fd..e0f3a36 100644 (file)
@@ -584,9 +584,9 @@ static int vfe_get(struct vfe_device *vfe)
                if (ret < 0)
                        goto error_pm_domain;
 
-               ret = pm_runtime_get_sync(vfe->camss->dev);
+               ret = pm_runtime_resume_and_get(vfe->camss->dev);
                if (ret < 0)
-                       goto error_pm_runtime_get;
+                       goto error_domain_off;
 
                ret = vfe_set_clock_rates(vfe);
                if (ret < 0)
@@ -620,6 +620,7 @@ error_reset:
 
 error_pm_runtime_get:
        pm_runtime_put_sync(vfe->camss->dev);
+error_domain_off:
        vfe->ops->pm_domain_off(vfe);
 
 error_pm_domain:
@@ -762,12 +763,13 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
  */
 static struct v4l2_mbus_framefmt *
 __vfe_get_format(struct vfe_line *line,
-                struct v4l2_subdev_pad_config *cfg,
+                struct v4l2_subdev_state *sd_state,
                 unsigned int pad,
                 enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&line->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&line->subdev, sd_state,
+                                                 pad);
 
        return &line->fmt[pad];
 }
@@ -782,11 +784,11 @@ __vfe_get_format(struct vfe_line *line,
  */
 static struct v4l2_rect *
 __vfe_get_compose(struct vfe_line *line,
-                 struct v4l2_subdev_pad_config *cfg,
+                 struct v4l2_subdev_state *sd_state,
                  enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_compose(&line->subdev, cfg,
+               return v4l2_subdev_get_try_compose(&line->subdev, sd_state,
                                                   MSM_VFE_PAD_SINK);
 
        return &line->compose;
@@ -802,11 +804,11 @@ __vfe_get_compose(struct vfe_line *line,
  */
 static struct v4l2_rect *
 __vfe_get_crop(struct vfe_line *line,
-              struct v4l2_subdev_pad_config *cfg,
+              struct v4l2_subdev_state *sd_state,
               enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&line->subdev, cfg,
+               return v4l2_subdev_get_try_crop(&line->subdev, sd_state,
                                                MSM_VFE_PAD_SRC);
 
        return &line->crop;
@@ -821,7 +823,7 @@ __vfe_get_crop(struct vfe_line *line,
  * @which: wanted subdev format
  */
 static void vfe_try_format(struct vfe_line *line,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad,
                           struct v4l2_mbus_framefmt *fmt,
                           enum v4l2_subdev_format_whence which)
@@ -853,14 +855,15 @@ static void vfe_try_format(struct vfe_line *line,
                /* Set and return a format same as sink pad */
                code = fmt->code;
 
-               *fmt = *__vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, which);
+               *fmt = *__vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,
+                                        which);
 
                fmt->code = vfe_src_pad_code(line, fmt->code, 0, code);
 
                if (line->id == VFE_LINE_PIX) {
                        struct v4l2_rect *rect;
 
-                       rect = __vfe_get_crop(line, cfg, which);
+                       rect = __vfe_get_crop(line, sd_state, which);
 
                        fmt->width = rect->width;
                        fmt->height = rect->height;
@@ -880,13 +883,13 @@ static void vfe_try_format(struct vfe_line *line,
  * @which: wanted subdev format
  */
 static void vfe_try_compose(struct vfe_line *line,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_rect *rect,
                            enum v4l2_subdev_format_whence which)
 {
        struct v4l2_mbus_framefmt *fmt;
 
-       fmt = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, which);
+       fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK, which);
 
        if (rect->width > fmt->width)
                rect->width = fmt->width;
@@ -919,13 +922,13 @@ static void vfe_try_compose(struct vfe_line *line,
  * @which: wanted subdev format
  */
 static void vfe_try_crop(struct vfe_line *line,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_rect *rect,
                         enum v4l2_subdev_format_whence which)
 {
        struct v4l2_rect *compose;
 
-       compose = __vfe_get_compose(line, cfg, which);
+       compose = __vfe_get_compose(line, sd_state, which);
 
        if (rect->width > compose->width)
                rect->width = compose->width;
@@ -963,7 +966,7 @@ static void vfe_try_crop(struct vfe_line *line,
  * return -EINVAL or zero on success
  */
 static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -976,7 +979,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
        } else {
                struct v4l2_mbus_framefmt *sink_fmt;
 
-               sink_fmt = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK,
+               sink_fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,
                                            code->which);
 
                code->code = vfe_src_pad_code(line, sink_fmt->code,
@@ -997,7 +1000,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int vfe_enum_frame_size(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1009,7 +1012,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       vfe_try_format(line, cfg, fse->pad, &format, fse->which);
+       vfe_try_format(line, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -1019,7 +1022,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       vfe_try_format(line, cfg, fse->pad, &format, fse->which);
+       vfe_try_format(line, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -1035,13 +1038,13 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int vfe_get_format(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __vfe_get_format(line, cfg, fmt->pad, fmt->which);
+       format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
@@ -1051,7 +1054,7 @@ static int vfe_get_format(struct v4l2_subdev *sd,
 }
 
 static int vfe_set_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel);
 
 /*
@@ -1063,17 +1066,17 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int vfe_set_format(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __vfe_get_format(line, cfg, fmt->pad, fmt->which);
+       format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);
        if (format == NULL)
                return -EINVAL;
 
-       vfe_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which);
+       vfe_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        if (fmt->pad == MSM_VFE_PAD_SINK) {
@@ -1081,11 +1084,11 @@ static int vfe_set_format(struct v4l2_subdev *sd,
                int ret;
 
                /* Propagate the format from sink to source */
-               format = __vfe_get_format(line, cfg, MSM_VFE_PAD_SRC,
+               format = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SRC,
                                          fmt->which);
 
                *format = fmt->format;
-               vfe_try_format(line, cfg, MSM_VFE_PAD_SRC, format,
+               vfe_try_format(line, sd_state, MSM_VFE_PAD_SRC, format,
                               fmt->which);
 
                if (line->id != VFE_LINE_PIX)
@@ -1097,7 +1100,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
                sel.target = V4L2_SEL_TGT_COMPOSE;
                sel.r.width = fmt->format.width;
                sel.r.height = fmt->format.height;
-               ret = vfe_set_selection(sd, cfg, &sel);
+               ret = vfe_set_selection(sd, sd_state, &sel);
                if (ret < 0)
                        return ret;
        }
@@ -1114,7 +1117,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int vfe_get_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1130,7 +1133,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
                case V4L2_SEL_TGT_COMPOSE_BOUNDS:
                        fmt.pad = sel->pad;
                        fmt.which = sel->which;
-                       ret = vfe_get_format(sd, cfg, &fmt);
+                       ret = vfe_get_format(sd, sd_state, &fmt);
                        if (ret < 0)
                                return ret;
 
@@ -1140,7 +1143,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
                        sel->r.height = fmt.format.height;
                        break;
                case V4L2_SEL_TGT_COMPOSE:
-                       rect = __vfe_get_compose(line, cfg, sel->which);
+                       rect = __vfe_get_compose(line, sd_state, sel->which);
                        if (rect == NULL)
                                return -EINVAL;
 
@@ -1152,7 +1155,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
        else if (sel->pad == MSM_VFE_PAD_SRC)
                switch (sel->target) {
                case V4L2_SEL_TGT_CROP_BOUNDS:
-                       rect = __vfe_get_compose(line, cfg, sel->which);
+                       rect = __vfe_get_compose(line, sd_state, sel->which);
                        if (rect == NULL)
                                return -EINVAL;
 
@@ -1162,7 +1165,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
                        sel->r.height = rect->height;
                        break;
                case V4L2_SEL_TGT_CROP:
-                       rect = __vfe_get_crop(line, cfg, sel->which);
+                       rect = __vfe_get_crop(line, sd_state, sel->which);
                        if (rect == NULL)
                                return -EINVAL;
 
@@ -1184,7 +1187,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
  * Return -EINVAL or zero on success
  */
 static int vfe_set_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1198,11 +1201,11 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
                sel->pad == MSM_VFE_PAD_SINK) {
                struct v4l2_subdev_selection crop = { 0 };
 
-               rect = __vfe_get_compose(line, cfg, sel->which);
+               rect = __vfe_get_compose(line, sd_state, sel->which);
                if (rect == NULL)
                        return -EINVAL;
 
-               vfe_try_compose(line, cfg, &sel->r, sel->which);
+               vfe_try_compose(line, sd_state, &sel->r, sel->which);
                *rect = sel->r;
 
                /* Reset source crop selection */
@@ -1210,28 +1213,28 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
                crop.pad = MSM_VFE_PAD_SRC;
                crop.target = V4L2_SEL_TGT_CROP;
                crop.r = *rect;
-               ret = vfe_set_selection(sd, cfg, &crop);
+               ret = vfe_set_selection(sd, sd_state, &crop);
        } else if (sel->target == V4L2_SEL_TGT_CROP &&
                sel->pad == MSM_VFE_PAD_SRC) {
                struct v4l2_subdev_format fmt = { 0 };
 
-               rect = __vfe_get_crop(line, cfg, sel->which);
+               rect = __vfe_get_crop(line, sd_state, sel->which);
                if (rect == NULL)
                        return -EINVAL;
 
-               vfe_try_crop(line, cfg, &sel->r, sel->which);
+               vfe_try_crop(line, sd_state, &sel->r, sel->which);
                *rect = sel->r;
 
                /* Reset source pad format width and height */
                fmt.which = sel->which;
                fmt.pad = MSM_VFE_PAD_SRC;
-               ret = vfe_get_format(sd, cfg, &fmt);
+               ret = vfe_get_format(sd, sd_state, &fmt);
                if (ret < 0)
                        return ret;
 
                fmt.format.width = rect->width;
                fmt.format.height = rect->height;
-               ret = vfe_set_format(sd, cfg, &fmt);
+               ret = vfe_set_format(sd, sd_state, &fmt);
        } else {
                ret = -EINVAL;
        }
@@ -1261,7 +1264,7 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                }
        };
 
-       return vfe_set_format(sd, fh ? fh->pad : NULL, &format);
+       return vfe_set_format(sd, fh ? fh->state : NULL, &format);
 }
 
 /*
@@ -1301,8 +1304,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 
        /* Memory */
 
-       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-       vfe->base = devm_ioremap_resource(dev, r);
+       vfe->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
        if (IS_ERR(vfe->base)) {
                dev_err(dev, "could not map memory\n");
                return PTR_ERR(vfe->base);
index 54bac7e..91b1584 100644 (file)
@@ -78,22 +78,32 @@ static const struct hfi_core_ops venus_core_ops = {
        .event_notify = venus_event_notify,
 };
 
+#define RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS 10
+
 static void venus_sys_error_handler(struct work_struct *work)
 {
        struct venus_core *core =
                        container_of(work, struct venus_core, work.work);
-       int ret = 0;
-
-       pm_runtime_get_sync(core->dev);
+       int ret, i, max_attempts = RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS;
+       const char *err_msg = "";
+       bool failed = false;
+
+       ret = pm_runtime_get_sync(core->dev);
+       if (ret < 0) {
+               err_msg = "resume runtime PM";
+               max_attempts = 0;
+               failed = true;
+       }
 
        hfi_core_deinit(core, true);
 
-       dev_warn(core->dev, "system error has occurred, starting recovery!\n");
-
        mutex_lock(&core->lock);
 
-       while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc))
+       for (i = 0; i < max_attempts; i++) {
+               if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc))
+                       break;
                msleep(10);
+       }
 
        venus_shutdown(core);
 
@@ -101,31 +111,55 @@ static void venus_sys_error_handler(struct work_struct *work)
 
        pm_runtime_put_sync(core->dev);
 
-       while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0]))
+       for (i = 0; i < max_attempts; i++) {
+               if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0]))
+                       break;
                usleep_range(1000, 1500);
+       }
 
        hfi_reinit(core);
 
-       pm_runtime_get_sync(core->dev);
+       ret = pm_runtime_get_sync(core->dev);
+       if (ret < 0) {
+               err_msg = "resume runtime PM";
+               failed = true;
+       }
 
-       ret |= venus_boot(core);
-       ret |= hfi_core_resume(core, true);
+       ret = venus_boot(core);
+       if (ret && !failed) {
+               err_msg = "boot Venus";
+               failed = true;
+       }
+
+       ret = hfi_core_resume(core, true);
+       if (ret && !failed) {
+               err_msg = "resume HFI";
+               failed = true;
+       }
 
        enable_irq(core->irq);
 
        mutex_unlock(&core->lock);
 
-       ret |= hfi_core_init(core);
+       ret = hfi_core_init(core);
+       if (ret && !failed) {
+               err_msg = "init HFI";
+               failed = true;
+       }
 
        pm_runtime_put_sync(core->dev);
 
-       if (ret) {
+       if (failed) {
                disable_irq_nosync(core->irq);
-               dev_warn(core->dev, "recovery failed (%d)\n", ret);
+               dev_warn_ratelimited(core->dev,
+                                    "System error has occurred, recovery failed to %s\n",
+                                    err_msg);
                schedule_delayed_work(&core->work, msecs_to_jiffies(10));
                return;
        }
 
+       dev_warn(core->dev, "system error has occurred (recovered)\n");
+
        mutex_lock(&core->lock);
        core->sys_error = false;
        mutex_unlock(&core->lock);
index 745f226..8df2d49 100644 (file)
@@ -155,7 +155,6 @@ struct venus_core {
        struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
        struct icc_path *video_path;
        struct icc_path *cpucfg_path;
-       struct opp_table *opp_table;
        bool has_opp_table;
        struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
        struct device_link *opp_dl_venus;
@@ -293,6 +292,7 @@ struct clock_data {
        unsigned long freq;
        unsigned long vpp_freq;
        unsigned long vsp_freq;
+       unsigned long low_power_freq;
 };
 
 #define to_venus_buffer(ptr)   container_of(ptr, struct venus_buffer, vb)
@@ -316,6 +316,10 @@ struct venus_ts_metadata {
        struct v4l2_timecode tc;
 };
 
+enum venus_inst_modes {
+       VENUS_LOW_POWER = BIT(0),
+};
+
 /**
  * struct venus_inst - holds per instance parameters
  *
@@ -445,6 +449,7 @@ struct venus_inst {
        unsigned int pic_struct;
        bool next_buf_last;
        bool drain_active;
+       enum venus_inst_modes flags;
 };
 
 #define IS_V1(core)    ((core)->res->hfi_version == HFI_VERSION_1XX)
index b813d6d..1fe6d46 100644 (file)
@@ -595,8 +595,7 @@ static int platform_get_bufreq(struct venus_inst *inst, u32 buftype,
                params.dec.is_secondary_output =
                        inst->opb_buftype == HFI_BUFFER_OUTPUT2;
                params.dec.is_interlaced =
-                       inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE ?
-                               true : false;
+                       inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE;
        } else {
                params.width = inst->out_width;
                params.height = inst->out_height;
@@ -1627,6 +1626,8 @@ int venus_helper_session_init(struct venus_inst *inst)
                                                                  session_type);
        inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(version, codec,
                                                                  session_type);
+       inst->clk_data.low_power_freq = hfi_platform_get_codec_lp_freq(version, codec,
+                                                                      session_type);
 
        return 0;
 }
index 11a8347..f510247 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  * Copyright (C) 2017 Linaro Ltd.
  */
+#include <linux/overflow.h>
 #include <linux/errno.h>
 #include <linux/hash.h>
 
@@ -27,7 +28,7 @@ void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable)
 {
        struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
 
-       pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+       pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
        pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
        pkt->num_properties = 1;
        pkt->data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
@@ -39,7 +40,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
 {
        struct hfi_debug_config *hfi;
 
-       pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+       pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
        pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
        pkt->num_properties = 1;
        pkt->data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
@@ -50,7 +51,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
 
 void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode)
 {
-       pkt->hdr.size = sizeof(*pkt) + sizeof(u32);
+       pkt->hdr.size = struct_size(pkt, data, 2);
        pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
        pkt->num_properties = 1;
        pkt->data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
@@ -116,7 +117,7 @@ void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable)
 {
        struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
 
-       pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+       pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
        pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
        pkt->num_properties = 1;
        pkt->data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
@@ -1226,6 +1227,17 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
                pkt->shdr.hdr.size += sizeof(u32) + sizeof(*hdr10);
                break;
        }
+       case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
+               struct hfi_conceal_color_v4 *color = prop_data;
+               u32 *in = pdata;
+
+               color->conceal_color_8bit = *in & 0xff;
+               color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
+               color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
+               color->conceal_color_10bit = *in;
+               pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
+               break;
+       }
 
        case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
        case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
@@ -1279,17 +1291,6 @@ pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt,
                pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq);
                break;
        }
-       case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
-               struct hfi_conceal_color_v4 *color = prop_data;
-               u32 *in = pdata;
-
-               color->conceal_color_8bit = *in & 0xff;
-               color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
-               color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
-               color->conceal_color_10bit = *in;
-               pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
-               break;
-       }
        default:
                return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
        }
index 83705e2..327ed90 100644 (file)
@@ -68,7 +68,7 @@ struct hfi_sys_release_resource_pkt {
 struct hfi_sys_set_property_pkt {
        struct hfi_pkt_hdr hdr;
        u32 num_properties;
-       u32 data[1];
+       u32 data[];
 };
 
 struct hfi_sys_get_property_pkt {
index 63cd347..b0a9beb 100644 (file)
 #define HFI_BUFFER_MODE_RING                   0x1000002
 #define HFI_BUFFER_MODE_DYNAMIC                        0x1000003
 
-#define HFI_VENC_PERFMODE_MAX_QUALITY          0x1
-#define HFI_VENC_PERFMODE_POWER_SAVE           0x2
-
 /*
  * HFI_PROPERTY_SYS_COMMON_START
  * HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000
@@ -848,6 +845,13 @@ struct hfi_framesize {
        u32 height;
 };
 
+#define HFI_VENC_PERFMODE_MAX_QUALITY          0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE           0x2
+
+struct hfi_perf_mode {
+       u32 video_perf_mode;
+};
+
 #define VIDC_CORE_ID_DEFAULT   0
 #define VIDC_CORE_ID_1         1
 #define VIDC_CORE_ID_2         2
index a2d436d..d9fde66 100644 (file)
@@ -251,11 +251,11 @@ sys_get_prop_image_version(struct device *dev,
 
        req_bytes = pkt->hdr.size - sizeof(*pkt);
 
-       if (req_bytes < VER_STR_SZ || !pkt->data[1] || pkt->num_properties > 1)
+       if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1)
                /* bad packet */
                return;
 
-       img_ver = (u8 *)&pkt->data[1];
+       img_ver = pkt->data;
 
        dev_dbg(dev, VDBGL "F/W version: %s\n", img_ver);
 
@@ -277,7 +277,7 @@ static void hfi_sys_property_info(struct venus_core *core,
                return;
        }
 
-       switch (pkt->data[0]) {
+       switch (pkt->property) {
        case HFI_PROPERTY_SYS_IMAGE_VERSION:
                sys_get_prop_image_version(dev, pkt);
                break;
@@ -338,7 +338,7 @@ session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
                /* bad packet */
                return HFI_ERR_SESSION_INVALID_PARAMETER;
 
-       hfi = (struct hfi_profile_level *)&pkt->data[1];
+       hfi = (struct hfi_profile_level *)&pkt->data[0];
        profile_level->profile = hfi->profile;
        profile_level->level = hfi->level;
 
@@ -355,11 +355,11 @@ session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
 
        req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
 
-       if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1])
+       if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0])
                /* bad packet */
                return HFI_ERR_SESSION_INVALID_PARAMETER;
 
-       buf_req = (struct hfi_buffer_requirements *)&pkt->data[1];
+       buf_req = (struct hfi_buffer_requirements *)&pkt->data[0];
        if (!buf_req)
                return HFI_ERR_SESSION_INVALID_PARAMETER;
 
@@ -391,7 +391,7 @@ static void hfi_session_prop_info(struct venus_core *core,
                goto done;
        }
 
-       switch (pkt->data[0]) {
+       switch (pkt->property) {
        case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
                memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
                error = session_get_prop_buf_req(pkt, hprop->bufreq);
@@ -404,7 +404,7 @@ static void hfi_session_prop_info(struct venus_core *core,
        case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
                break;
        default:
-               dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->data[0]);
+               dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property);
                return;
        }
 
index 526d9f5..5105136 100644 (file)
@@ -113,7 +113,8 @@ struct hfi_msg_sys_ping_ack_pkt {
 struct hfi_msg_sys_property_info_pkt {
        struct hfi_pkt_hdr hdr;
        u32 num_properties;
-       u32 data[1];
+       u32 property;
+       u8 data[];
 };
 
 struct hfi_msg_session_load_resources_done_pkt {
@@ -233,7 +234,8 @@ struct hfi_msg_session_parse_sequence_header_done_pkt {
 struct hfi_msg_session_property_info_pkt {
        struct hfi_session_hdr_pkt shdr;
        u32 num_properties;
-       u32 data[1];
+       u32 property;
+       u8 data[];
 };
 
 struct hfi_msg_session_release_resources_done_pkt {
index 8f47804..f5b4e1f 100644 (file)
@@ -50,6 +50,22 @@ hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session
        return freq;
 }
 
+unsigned long
+hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type)
+{
+       const struct hfi_platform *plat;
+       unsigned long freq = 0;
+
+       plat = hfi_platform_get(version);
+       if (!plat)
+               return 0;
+
+       if (plat->codec_lp_freq)
+               freq = plat->codec_lp_freq(session_type, codec);
+
+       return freq;
+}
+
 u8 hfi_platform_num_vpp_pipes(enum hfi_version version)
 {
        const struct hfi_platform *plat;
index 3819bb2..2dbe608 100644 (file)
@@ -43,11 +43,13 @@ struct hfi_platform_codec_freq_data {
        u32 session_type;
        unsigned long vpp_freq;
        unsigned long vsp_freq;
+       unsigned long low_power_freq;
 };
 
 struct hfi_platform {
        unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec);
        unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec);
+       unsigned long (*codec_lp_freq)(u32 session_type, u32 codec);
        void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count);
        const struct hfi_plat_caps *(*capabilities)(unsigned int *entries);
        u8 (*num_vpp_pipes)(void);
@@ -63,5 +65,7 @@ unsigned long hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 code
                                              u32 session_type);
 unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec,
                                              u32 session_type);
+unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec,
+                                            u32 session_type);
 u8 hfi_platform_num_vpp_pipes(enum hfi_version version);
 #endif
index 3848bb6..3f7f527 100644 (file)
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
 }
 
 static const struct hfi_platform_codec_freq_data codec_freq_data[] =  {
-       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
-       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
-       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
-       { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
-       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
-       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
-       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
-       { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
+       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+       { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+       { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
 };
 
 static const struct hfi_platform_codec_freq_data *
@@ -311,9 +311,21 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
        return 0;
 }
 
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+       const struct hfi_platform_codec_freq_data *data;
+
+       data = get_codec_freq_data(session_type, codec);
+       if (data)
+               return data->low_power_freq;
+
+       return 0;
+}
+
 const struct hfi_platform hfi_plat_v4 = {
        .codec_vpp_freq = codec_vpp_freq,
        .codec_vsp_freq = codec_vsp_freq,
+       .codec_lp_freq = codec_lp_freq,
        .codecs = get_codecs,
        .capabilities = get_capabilities,
 };
index dd1a039..d8243b2 100644 (file)
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
 }
 
 static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
-       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25 },
-       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25 },
-       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60 },
-       { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25 },
-       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25 },
-       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25 },
-       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60 },
-       { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60 },
+       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60, 320 },
+       { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+       { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+       { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+       { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
+       { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
 };
 
 static const struct hfi_platform_codec_freq_data *
@@ -311,6 +311,17 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
        return 0;
 }
 
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+       const struct hfi_platform_codec_freq_data *data;
+
+       data = get_codec_freq_data(session_type, codec);
+       if (data)
+               return data->low_power_freq;
+
+       return 0;
+}
+
 static u8 num_vpp_pipes(void)
 {
        return 4;
@@ -319,6 +330,7 @@ static u8 num_vpp_pipes(void)
 const struct hfi_platform hfi_plat_v6 = {
        .codec_vpp_freq = codec_vpp_freq,
        .codec_vsp_freq = codec_vsp_freq,
+       .codec_lp_freq = codec_lp_freq,
        .codecs = get_codecs,
        .capabilities = get_capabilities,
        .num_vpp_pipes = num_vpp_pipes,
index c7e1ebe..3e2345e 100644 (file)
@@ -300,16 +300,15 @@ static int core_get_v1(struct venus_core *core)
        if (ret)
                return ret;
 
-       core->opp_table = dev_pm_opp_set_clkname(core->dev, "core");
-       if (IS_ERR(core->opp_table))
-               return PTR_ERR(core->opp_table);
+       ret = devm_pm_opp_set_clkname(core->dev, "core");
+       if (ret)
+               return ret;
 
        return 0;
 }
 
 static void core_put_v1(struct venus_core *core)
 {
-       dev_pm_opp_put_clkname(core->opp_table);
 }
 
 static int core_power_v1(struct venus_core *core, int on)
@@ -524,8 +523,50 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
        return 0;
 }
 
+static inline int power_save_mode_enable(struct venus_inst *inst,
+                                        bool enable)
+{
+       struct venc_controls *enc_ctr = &inst->controls.enc;
+       const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+       u32 venc_mode;
+       int ret = 0;
+
+       if (inst->session_type != VIDC_SESSION_TYPE_ENC)
+               return 0;
+
+       if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+               enable = false;
+
+       venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
+               HFI_VENC_PERFMODE_MAX_QUALITY;
+
+       ret = hfi_session_set_property(inst, ptype, &venc_mode);
+       if (ret)
+               return ret;
+
+       inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
+               inst->flags & ~VENUS_LOW_POWER;
+
+       return ret;
+}
+
+static int move_core_to_power_save_mode(struct venus_core *core,
+                                       u32 core_id)
+{
+       struct venus_inst *inst = NULL;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(inst, &core->instances, list) {
+               if (inst->clk_data.core_id == core_id &&
+                   inst->session_type == VIDC_SESSION_TYPE_ENC)
+                       power_save_mode_enable(inst, true);
+       }
+       mutex_unlock(&core->lock);
+       return 0;
+}
+
 static void
-min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
 {
        u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
        u32 cores_max = core_num_max(inst);
@@ -543,7 +584,14 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
                if (inst_pos->state != INST_START)
                        continue;
 
-               vpp_freq = inst_pos->clk_data.vpp_freq;
+               if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+                       vpp_freq = inst_pos->clk_data.vpp_freq;
+               else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+                       vpp_freq = low_power ? inst_pos->clk_data.vpp_freq :
+                               inst_pos->clk_data.low_power_freq;
+               else
+                       continue;
+
                coreid = inst_pos->clk_data.core_id;
 
                mbs_per_sec = load_per_instance(inst_pos);
@@ -575,9 +623,11 @@ static int decide_core(struct venus_inst *inst)
 {
        const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
        struct venus_core *core = inst->core;
-       u32 min_coreid, min_load, inst_load;
+       u32 min_coreid, min_load, cur_inst_load;
+       u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
        struct hfi_videocores_usage_type cu;
        unsigned long max_freq;
+       int ret = 0;
 
        if (legacy_binding) {
                if (inst->session_type == VIDC_SESSION_TYPE_DEC)
@@ -591,23 +641,43 @@ static int decide_core(struct venus_inst *inst)
        if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
                return 0;
 
-       inst_load = load_per_instance(inst);
-       inst_load *= inst->clk_data.vpp_freq;
-       max_freq = core->res->freq_tbl[0].freq;
+       cur_inst_load = load_per_instance(inst);
+       cur_inst_load *= inst->clk_data.vpp_freq;
+       /*TODO : divide this inst->load by work_route */
 
-       min_loaded_core(inst, &min_coreid, &min_load);
+       cur_inst_lp_load = load_per_instance(inst);
+       cur_inst_lp_load *= inst->clk_data.low_power_freq;
+       /*TODO : divide this inst->load by work_route */
 
-       if ((inst_load + min_load) > max_freq) {
-               dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
-                        inst_load, max_freq);
+       max_freq = core->res->freq_tbl[0].freq;
+
+       min_loaded_core(inst, &min_coreid, &min_load, false);
+       min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
+
+       if (cur_inst_load + min_load <= max_freq) {
+               inst->clk_data.core_id = min_coreid;
+               cu.video_core_enable_mask = min_coreid;
+       } else if (cur_inst_lp_load + min_load <= max_freq) {
+               /* Move current instance to LP and return */
+               inst->clk_data.core_id = min_coreid;
+               cu.video_core_enable_mask = min_coreid;
+               power_save_mode_enable(inst, true);
+       } else if (cur_inst_lp_load + min_lp_load <= max_freq) {
+               /* Move all instances to LP mode and return */
+               inst->clk_data.core_id = min_lp_coreid;
+               cu.video_core_enable_mask = min_lp_coreid;
+               move_core_to_power_save_mode(core, min_lp_coreid);
+       } else {
+               dev_warn(core->dev, "HW can't support this load");
                return -EINVAL;
        }
 
-       inst->clk_data.core_id = min_coreid;
-       cu.video_core_enable_mask = min_coreid;
-
 done:
-       return hfi_session_set_property(inst, ptype, &cu);
+       ret = hfi_session_set_property(inst, ptype, &cu);
+       if (ret)
+               return ret;
+
+       return ret;
 }
 
 static int acquire_core(struct venus_inst *inst)
@@ -788,7 +858,6 @@ static int venc_power_v4(struct device *dev, int on)
 static int vcodec_domains_get(struct venus_core *core)
 {
        int ret;
-       struct opp_table *opp_table;
        struct device **opp_virt_dev;
        struct device *dev = core->dev;
        const struct venus_resources *res = core->res;
@@ -811,11 +880,9 @@ skip_pmdomains:
                return 0;
 
        /* Attach the power domain for setting performance state */
-       opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
-       if (IS_ERR(opp_table)) {
-               ret = PTR_ERR(opp_table);
+       ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
+       if (ret)
                goto opp_attach_err;
-       }
 
        core->opp_pmdomain = *opp_virt_dev;
        core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
@@ -824,13 +891,11 @@ skip_pmdomains:
                                             DL_FLAG_STATELESS);
        if (!core->opp_dl_venus) {
                ret = -ENODEV;
-               goto opp_dl_add_err;
+               goto opp_attach_err;
        }
 
        return 0;
 
-opp_dl_add_err:
-       dev_pm_opp_detach_genpd(core->opp_table);
 opp_attach_err:
        for (i = 0; i < res->vcodec_pmdomains_num; i++) {
                if (IS_ERR_OR_NULL(core->pmdomains[i]))
@@ -861,8 +926,6 @@ skip_pmdomains:
 
        if (core->opp_dl_venus)
                device_link_del(core->opp_dl_venus);
-
-       dev_pm_opp_detach_genpd(core->opp_table);
 }
 
 static int core_resets_reset(struct venus_core *core)
@@ -941,45 +1004,33 @@ static int core_get_v4(struct venus_core *core)
        if (legacy_binding)
                return 0;
 
-       core->opp_table = dev_pm_opp_set_clkname(dev, "core");
-       if (IS_ERR(core->opp_table))
-               return PTR_ERR(core->opp_table);
+       ret = devm_pm_opp_set_clkname(dev, "core");
+       if (ret)
+               return ret;
 
        if (core->res->opp_pmdomain) {
-               ret = dev_pm_opp_of_add_table(dev);
+               ret = devm_pm_opp_of_add_table(dev);
                if (!ret) {
                        core->has_opp_table = true;
                } else if (ret != -ENODEV) {
                        dev_err(dev, "invalid OPP table in device tree\n");
-                       dev_pm_opp_put_clkname(core->opp_table);
                        return ret;
                }
        }
 
        ret = vcodec_domains_get(core);
-       if (ret) {
-               if (core->has_opp_table)
-                       dev_pm_opp_of_remove_table(dev);
-               dev_pm_opp_put_clkname(core->opp_table);
+       if (ret)
                return ret;
-       }
 
        return 0;
 }
 
 static void core_put_v4(struct venus_core *core)
 {
-       struct device *dev = core->dev;
-
        if (legacy_binding)
                return;
 
        vcodec_domains_put(core);
-
-       if (core->has_opp_table)
-               dev_pm_opp_of_remove_table(dev);
-       dev_pm_opp_put_clkname(core->opp_table);
-
 }
 
 static int core_power_v4(struct venus_core *core, int on)
@@ -990,9 +1041,8 @@ static int core_power_v4(struct venus_core *core, int on)
 
        if (on == POWER_ON) {
                if (pmctrl) {
-                       ret = pm_runtime_get_sync(pmctrl);
+                       ret = pm_runtime_resume_and_get(pmctrl);
                        if (ret < 0) {
-                               pm_runtime_put_noidle(pmctrl);
                                return ret;
                        }
                }
@@ -1026,7 +1076,7 @@ static int core_power_v4(struct venus_core *core, int on)
 static unsigned long calculate_inst_freq(struct venus_inst *inst,
                                         unsigned long filled_len)
 {
-       unsigned long vpp_freq = 0, vsp_freq = 0;
+       unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
        u32 fps = (u32)inst->fps;
        u32 mbs_per_sec;
 
@@ -1035,7 +1085,12 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
        if (inst->state != INST_START)
                return 0;
 
-       vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
+       if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+               vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
+                       inst->clk_data.low_power_freq :
+                       inst->clk_data.vpp_freq;
+
+       vpp_freq = mbs_per_sec * vpp_freq_per_mb;
        /* 21 / 20 is overhead factor */
        vpp_freq += vpp_freq / 20;
        vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
index ddb7cd3..198e47e 100644 (file)
@@ -568,10 +568,10 @@ static int vdec_pm_get(struct venus_inst *inst)
        int ret;
 
        mutex_lock(&core->pm_lock);
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        mutex_unlock(&core->pm_lock);
 
-       return ret < 0 ? ret : 0;
+       return ret;
 }
 
 static int vdec_pm_put(struct venus_inst *inst, bool autosuspend)
@@ -601,7 +601,7 @@ static int vdec_pm_get_put(struct venus_inst *inst)
        mutex_lock(&core->pm_lock);
 
        if (pm_runtime_suspended(dev)) {
-               ret = pm_runtime_get_sync(dev);
+               ret = pm_runtime_resume_and_get(dev);
                if (ret < 0)
                        goto error;
 
index 4a7291f..8dd49d4 100644 (file)
@@ -1205,9 +1205,9 @@ static int venc_open(struct file *file)
 
        venus_helper_init_instance(inst);
 
-       ret = pm_runtime_get_sync(core->dev_enc);
+       ret = pm_runtime_resume_and_get(core->dev_enc);
        if (ret < 0)
-               goto err_put_sync;
+               goto err_free;
 
        ret = venc_ctrl_init(inst);
        if (ret)
@@ -1252,6 +1252,7 @@ err_ctrl_deinit:
        venc_ctrl_deinit(inst);
 err_put_sync:
        pm_runtime_put_sync(core->dev_enc);
+err_free:
        kfree(inst);
        return ret;
 }
index 5c03318..eb59a3b 100644 (file)
@@ -96,18 +96,10 @@ EXPORT_SYMBOL_GPL(rcar_fcp_get_device);
  */
 int rcar_fcp_enable(struct rcar_fcp_device *fcp)
 {
-       int ret;
-
        if (!fcp)
                return 0;
 
-       ret = pm_runtime_get_sync(fcp->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(fcp->dev);
-               return ret;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(fcp->dev);
 }
 EXPORT_SYMBOL_GPL(rcar_fcp_enable);
 
index cb30259..33957cc 100644 (file)
@@ -1363,6 +1363,10 @@ static const struct of_device_id rvin_of_id_table[] = {
                .data = &rcar_info_r8a7796,
        },
        {
+               .compatible = "renesas,vin-r8a77961",
+               .data = &rcar_info_r8a7796,
+       },
+       {
                .compatible = "renesas,vin-r8a77965",
                .data = &rcar_info_r8a77965,
        },
index e06cd51..e28eff0 100644 (file)
@@ -320,10 +320,12 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = {
        { .code = MEDIA_BUS_FMT_YUYV8_1X16,     .datatype = 0x1e, .bpp = 16 },
        { .code = MEDIA_BUS_FMT_UYVY8_2X8,      .datatype = 0x1e, .bpp = 16 },
        { .code = MEDIA_BUS_FMT_YUYV10_2X10,    .datatype = 0x1e, .bpp = 20 },
+       { .code = MEDIA_BUS_FMT_Y10_1X10,       .datatype = 0x2b, .bpp = 10 },
        { .code = MEDIA_BUS_FMT_SBGGR8_1X8,     .datatype = 0x2a, .bpp = 8 },
        { .code = MEDIA_BUS_FMT_SGBRG8_1X8,     .datatype = 0x2a, .bpp = 8 },
        { .code = MEDIA_BUS_FMT_SGRBG8_1X8,     .datatype = 0x2a, .bpp = 8 },
        { .code = MEDIA_BUS_FMT_SRGGB8_1X8,     .datatype = 0x2a, .bpp = 8 },
+       { .code = MEDIA_BUS_FMT_Y8_1X8,         .datatype = 0x2a, .bpp = 8 },
 };
 
 static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
@@ -406,10 +408,17 @@ static void rcsi2_enter_standby(struct rcar_csi2 *priv)
        pm_runtime_put(priv->dev);
 }
 
-static void rcsi2_exit_standby(struct rcar_csi2 *priv)
+static int rcsi2_exit_standby(struct rcar_csi2 *priv)
 {
-       pm_runtime_get_sync(priv->dev);
+       int ret;
+
+       ret = pm_runtime_resume_and_get(priv->dev);
+       if (ret < 0)
+               return ret;
+
        reset_control_deassert(priv->rstc);
+
+       return 0;
 }
 
 static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
@@ -657,7 +666,9 @@ static int rcsi2_start(struct rcar_csi2 *priv)
 {
        int ret;
 
-       rcsi2_exit_standby(priv);
+       ret = rcsi2_exit_standby(priv);
+       if (ret < 0)
+               return ret;
 
        ret = rcsi2_start_receiver(priv);
        if (ret) {
@@ -708,7 +719,7 @@ out:
 }
 
 static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_format *format)
 {
        struct rcar_csi2 *priv = sd_to_csi2(sd);
@@ -720,7 +731,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                priv->mf = format->format;
        } else {
-               framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
                *framefmt = format->format;
        }
 
@@ -728,7 +739,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
 }
 
 static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_format *format)
 {
        struct rcar_csi2 *priv = sd_to_csi2(sd);
@@ -736,7 +747,7 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                format->format = priv->mf;
        else
-               format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+               format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
 
        return 0;
 }
@@ -1112,6 +1123,11 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
        .num_channels = 4,
 };
 
+static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
+       .hsfreqrange = hsfreqrange_m3w_h3es1,
+       .num_channels = 4,
+};
+
 static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
        .init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
        .hsfreqrange = hsfreqrange_h3_v3h_m3n,
@@ -1165,6 +1181,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
                .data = &rcar_csi2_info_r8a7796,
        },
        {
+               .compatible = "renesas,r8a77961-csi2",
+               .data = &rcar_csi2_info_r8a77961,
+       },
+       {
                .compatible = "renesas,r8a77965-csi2",
                .data = &rcar_csi2_info_r8a77965,
        },
index f30dafb..f5f722a 100644 (file)
@@ -1458,11 +1458,9 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
        u32 vnmc;
        int ret;
 
-       ret = pm_runtime_get_sync(vin->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(vin->dev);
+       ret = pm_runtime_resume_and_get(vin->dev);
+       if (ret < 0)
                return ret;
-       }
 
        /* Make register writes take effect immediately. */
        vnmc = rvin_read(vin, VNMC_REG);
index 457a65b..cca15a1 100644 (file)
@@ -243,7 +243,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
                           struct v4l2_rect *src_rect)
 {
        struct v4l2_subdev *sd = vin_to_source(vin);
-       struct v4l2_subdev_pad_config *pad_cfg;
+       struct v4l2_subdev_state *sd_state;
        struct v4l2_subdev_format format = {
                .which = which,
                .pad = vin->parallel.source_pad,
@@ -252,8 +252,8 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
        u32 width, height;
        int ret;
 
-       pad_cfg = v4l2_subdev_alloc_pad_config(sd);
-       if (pad_cfg == NULL)
+       sd_state = v4l2_subdev_alloc_state(sd);
+       if (sd_state == NULL)
                return -ENOMEM;
 
        if (!rvin_format_from_pixel(vin, pix->pixelformat))
@@ -266,7 +266,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
        width = pix->width;
        height = pix->height;
 
-       ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
+       ret = v4l2_subdev_call(sd, pad, set_fmt, sd_state, &format);
        if (ret < 0 && ret != -ENOIOCTLCMD)
                goto done;
        ret = 0;
@@ -288,7 +288,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
 
        rvin_format_align(vin, pix);
 done:
-       v4l2_subdev_free_pad_config(pad_cfg);
+       v4l2_subdev_free_state(sd_state);
 
        return ret;
 }
@@ -870,11 +870,9 @@ static int rvin_open(struct file *file)
        struct rvin_dev *vin = video_drvdata(file);
        int ret;
 
-       ret = pm_runtime_get_sync(vin->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(vin->dev);
+       ret = pm_runtime_resume_and_get(vin->dev);
+       if (ret < 0)
                return ret;
-       }
 
        ret = mutex_lock_interruptible(&vin->lock);
        if (ret)
index 01c1fbb..89aac60 100644 (file)
@@ -2117,9 +2117,7 @@ static int fdp1_open(struct file *file)
 
        if (ctx->hdl.error) {
                ret = ctx->hdl.error;
-               v4l2_ctrl_handler_free(&ctx->hdl);
-               kfree(ctx);
-               goto done;
+               goto error_ctx;
        }
 
        ctx->fh.ctrl_handler = &ctx->hdl;
@@ -2133,20 +2131,27 @@ static int fdp1_open(struct file *file)
 
        if (IS_ERR(ctx->fh.m2m_ctx)) {
                ret = PTR_ERR(ctx->fh.m2m_ctx);
-
-               v4l2_ctrl_handler_free(&ctx->hdl);
-               kfree(ctx);
-               goto done;
+               goto error_ctx;
        }
 
        /* Perform any power management required */
-       pm_runtime_get_sync(fdp1->dev);
+       ret = pm_runtime_resume_and_get(fdp1->dev);
+       if (ret < 0)
+               goto error_pm;
 
        v4l2_fh_add(&ctx->fh);
 
        dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n",
                ctx, ctx->fh.m2m_ctx);
 
+       mutex_unlock(&fdp1->dev_mutex);
+       return 0;
+
+error_pm:
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+error_ctx:
+       v4l2_ctrl_handler_free(&ctx->hdl);
+       kfree(ctx);
 done:
        mutex_unlock(&fdp1->dev_mutex);
        return ret;
@@ -2351,7 +2356,9 @@ static int fdp1_probe(struct platform_device *pdev)
 
        /* Power up the cells to read HW */
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(fdp1->dev);
+       ret = pm_runtime_resume_and_get(fdp1->dev);
+       if (ret < 0)
+               goto disable_pm;
 
        hw_version = fdp1_read(fdp1, FD1_IP_INTDATA);
        switch (hw_version) {
@@ -2380,6 +2387,9 @@ static int fdp1_probe(struct platform_device *pdev)
 
        return 0;
 
+disable_pm:
+       pm_runtime_disable(fdp1->dev);
+
 release_m2m:
        v4l2_m2m_release(fdp1->m2m_dev);
 
index a7c198c..f57158b 100644 (file)
@@ -42,7 +42,7 @@
 
 /*
  * Align JPEG header end to cache line to make sure we will not have any issues
- * with cache; additionally to requerment (33.3.27 R01UH0501EJ0100 Rev.1.00)
+ * with cache; additionally to requirement (33.3.27 R01UH0501EJ0100 Rev.1.00)
  */
 #define JPU_JPEG_HDR_SIZE              (ALIGN(0x258, L1_CACHE_BYTES))
 #define JPU_JPEG_MAX_BYTES_PER_PIXEL   2       /* 16 bit precision format */
 #define JCCMD_JEND     (1 << 2)
 #define JCCMD_JSRT     (1 << 0)
 
-/* JPEG code quantanization table number register */
+/* JPEG code quantization table number register */
 #define JCQTN  0x0c
 #define JCQTN_SHIFT(t)         (((t) - 1) << 1)
 
@@ -1644,7 +1644,7 @@ static int jpu_probe(struct platform_device *pdev)
                goto device_register_rollback;
        }
 
-       /* fill in qantization and Huffman tables for encoder */
+       /* fill in quantization and Huffman tables for encoder */
        for (i = 0; i < JPU_MAX_QUALITY; i++)
                jpu_generate_hdr(i, (unsigned char *)jpeg_hdrs[i]);
 
index cd13710..f432032 100644 (file)
@@ -794,6 +794,9 @@ static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt
        struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp;
        struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        const struct ceu_fmt *ceu_fmt;
        u32 mbus_code_old;
        u32 mbus_code;
@@ -850,13 +853,13 @@ static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt
         * time.
         */
        sd_format.format.code = mbus_code;
-       ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format);
+       ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_state, &sd_format);
        if (ret) {
                if (ret == -EINVAL) {
                        /* fallback */
                        sd_format.format.code = mbus_code_old;
                        ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt,
-                                              &pad_cfg, &sd_format);
+                                              &pad_state, &sd_format);
                }
 
                if (ret)
@@ -1099,10 +1102,10 @@ static int ceu_open(struct file *file)
 
        mutex_lock(&ceudev->mlock);
        /* Causes soft-reset and sensor power on on first open */
-       pm_runtime_get_sync(ceudev->dev);
+       ret = pm_runtime_resume_and_get(ceudev->dev);
        mutex_unlock(&ceudev->mlock);
 
-       return 0;
+       return ret;
 }
 
 static int ceu_release(struct file *file)
index bf9a75b..81508ed 100644 (file)
@@ -79,9 +79,8 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
        struct rockchip_rga *rga = ctx->rga;
        int ret;
 
-       ret = pm_runtime_get_sync(rga->dev);
+       ret = pm_runtime_resume_and_get(rga->dev);
        if (ret < 0) {
-               pm_runtime_put_noidle(rga->dev);
                rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
                return ret;
        }
index 9d12242..bf3fd71 100644 (file)
@@ -866,7 +866,9 @@ static int rga_probe(struct platform_device *pdev)
                goto unreg_video_dev;
        }
 
-       pm_runtime_get_sync(rga->dev);
+       ret = pm_runtime_resume_and_get(rga->dev);
+       if (ret < 0)
+               goto unreg_video_dev;
 
        rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
        rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
index 5f6c9d1..60cd220 100644 (file)
@@ -830,8 +830,8 @@ static void rkisp1_return_all_buffers(struct rkisp1_capture *cap,
 }
 
 /*
- * Most of registers inside rockchip ISP1 have shadow register since
- * they must be not be changed during processing a frame.
+ * Most registers inside the rockchip ISP1 have shadow register since
+ * they must not be changed while processing a frame.
  * Usually, each sub-module updates its shadow register after
  * processing the last pixel of a frame.
  */
@@ -847,14 +847,14 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
        spin_lock_irq(&cap->buf.lock);
        rkisp1_set_next_buf(cap);
        cap->ops->enable(cap);
-       /* It's safe to config ACTIVE and SHADOW regs for the
+       /* It's safe to configure ACTIVE and SHADOW registers for the
         * first stream. While when the second is starting, do NOT
-        * force update because it also update the first one.
+        * force update because it also updates the first one.
         *
-        * The latter case would drop one more buf(that is 2) since
-        * there's not buf in shadow when the second FE received. This's
-        * also required because the second FE maybe corrupt especially
-        * when run at 120fps.
+        * The latter case would drop one more buffer(that is 2) since
+        * there's no buffer in a shadow register when the second FE received.
+        * This's also required because the second FE maybe corrupt
+        * especially when run at 120fps.
         */
        if (!other->is_streaming) {
                /* force cfg update */
@@ -1003,9 +1003,8 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
        if (ret)
                goto err_pipeline_stop;
 
-       ret = pm_runtime_get_sync(cap->rkisp1->dev);
+       ret = pm_runtime_resume_and_get(cap->rkisp1->dev);
        if (ret < 0) {
-               pm_runtime_put_noidle(cap->rkisp1->dev);
                dev_err(cap->rkisp1->dev, "power up failed %d\n", ret);
                goto err_destroy_dummy;
        }
index 2e5b57e..d596bc0 100644 (file)
@@ -208,24 +208,30 @@ static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd)
 
 static struct v4l2_mbus_framefmt *
 rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       unsigned int pad, u32 which)
 {
+       struct v4l2_subdev_state state = {
+               .pads = isp->pad_cfg
+               };
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&isp->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad);
        else
-               return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad);
+               return v4l2_subdev_get_try_format(&isp->sd, &state, pad);
 }
 
 static struct v4l2_rect *
 rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad, u32 which)
 {
+       struct v4l2_subdev_state state = {
+               .pads = isp->pad_cfg
+               };
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad);
        else
-               return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad);
+               return v4l2_subdev_get_try_crop(&isp->sd, &state, pad);
 }
 
 /* ----------------------------------------------------------------------------
@@ -561,7 +567,7 @@ static void rkisp1_isp_start(struct rkisp1_device *rkisp1)
  */
 
 static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_mbus_code_enum *code)
 {
        unsigned int i, dir;
@@ -601,7 +607,7 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_size_enum *fse)
 {
        const struct rkisp1_isp_mbus_info *mbus_info;
@@ -634,37 +640,37 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
        struct v4l2_rect *sink_crop, *src_crop;
 
-       sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+       sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
                                              RKISP1_ISP_PAD_SINK_VIDEO);
        sink_fmt->width = RKISP1_DEFAULT_WIDTH;
        sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
        sink_fmt->field = V4L2_FIELD_NONE;
        sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
 
-       sink_crop = v4l2_subdev_get_try_crop(sd, cfg,
+       sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
                                             RKISP1_ISP_PAD_SINK_VIDEO);
        sink_crop->width = RKISP1_DEFAULT_WIDTH;
        sink_crop->height = RKISP1_DEFAULT_HEIGHT;
        sink_crop->left = 0;
        sink_crop->top = 0;
 
-       src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+       src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
                                             RKISP1_ISP_PAD_SOURCE_VIDEO);
        *src_fmt = *sink_fmt;
        src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
 
-       src_crop = v4l2_subdev_get_try_crop(sd, cfg,
+       src_crop = v4l2_subdev_get_try_crop(sd, sd_state,
                                            RKISP1_ISP_PAD_SOURCE_VIDEO);
        *src_crop = *sink_crop;
 
-       sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+       sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
                                              RKISP1_ISP_PAD_SINK_PARAMS);
-       src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+       src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
                                             RKISP1_ISP_PAD_SOURCE_STATS);
        sink_fmt->width = 0;
        sink_fmt->height = 0;
@@ -676,7 +682,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
 }
 
 static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_mbus_framefmt *format,
                                   unsigned int which)
 {
@@ -684,9 +690,9 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
        struct v4l2_mbus_framefmt *src_fmt;
        const struct v4l2_rect *src_crop;
 
-       src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+       src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
                                         RKISP1_ISP_PAD_SOURCE_VIDEO, which);
-       src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+       src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
                                           RKISP1_ISP_PAD_SOURCE_VIDEO, which);
 
        src_fmt->code = format->code;
@@ -717,17 +723,17 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
 }
 
 static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_rect *r, unsigned int which)
 {
        struct v4l2_mbus_framefmt *src_fmt;
        const struct v4l2_rect *sink_crop;
        struct v4l2_rect *src_crop;
 
-       src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+       src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
                                           RKISP1_ISP_PAD_SOURCE_VIDEO,
                                           which);
-       sink_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+       sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
                                            RKISP1_ISP_PAD_SINK_VIDEO,
                                            which);
 
@@ -740,21 +746,23 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
        *r = *src_crop;
 
        /* Propagate to out format */
-       src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+       src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
                                         RKISP1_ISP_PAD_SOURCE_VIDEO, which);
-       rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which);
+       rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt, which);
 }
 
 static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_rect *r, unsigned int which)
 {
        struct v4l2_rect *sink_crop, *src_crop;
        struct v4l2_mbus_framefmt *sink_fmt;
 
-       sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+       sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
+                                           RKISP1_ISP_PAD_SINK_VIDEO,
                                            which);
-       sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+       sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
+                                         RKISP1_ISP_PAD_SINK_VIDEO,
                                          which);
 
        sink_crop->left = ALIGN(r->left, 2);
@@ -766,13 +774,13 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
        *r = *sink_crop;
 
        /* Propagate to out crop */
-       src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+       src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
                                           RKISP1_ISP_PAD_SOURCE_VIDEO, which);
-       rkisp1_isp_set_src_crop(isp, cfg, src_crop, which);
+       rkisp1_isp_set_src_crop(isp, sd_state, src_crop, which);
 }
 
 static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_mbus_framefmt *format,
                                    unsigned int which)
 {
@@ -780,7 +788,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
        struct v4l2_mbus_framefmt *sink_fmt;
        struct v4l2_rect *sink_crop;
 
-       sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+       sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
+                                         RKISP1_ISP_PAD_SINK_VIDEO,
                                          which);
        sink_fmt->code = format->code;
        mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
@@ -801,36 +810,40 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
        *format = *sink_fmt;
 
        /* Propagate to in crop */
-       sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+       sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
+                                           RKISP1_ISP_PAD_SINK_VIDEO,
                                            which);
-       rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which);
+       rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop, which);
 }
 
 static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
 
        mutex_lock(&isp->ops_lock);
-       fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which);
+       fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
+                                             fmt->which);
        mutex_unlock(&isp->ops_lock);
        return 0;
 }
 
 static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
 
        mutex_lock(&isp->ops_lock);
        if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
-               rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which);
+               rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format,
+                                       fmt->which);
        else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
-               rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which);
+               rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format,
+                                      fmt->which);
        else
-               fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad,
+               fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
                                                      fmt->which);
 
        mutex_unlock(&isp->ops_lock);
@@ -838,7 +851,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
@@ -854,20 +867,20 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
                if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
                        struct v4l2_mbus_framefmt *fmt;
 
-                       fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad,
+                       fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, sel->pad,
                                                     sel->which);
                        sel->r.height = fmt->height;
                        sel->r.width = fmt->width;
                        sel->r.left = 0;
                        sel->r.top = 0;
                } else {
-                       sel->r = *rkisp1_isp_get_pad_crop(isp, cfg,
-                                               RKISP1_ISP_PAD_SINK_VIDEO,
-                                               sel->which);
+                       sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state,
+                                                         RKISP1_ISP_PAD_SINK_VIDEO,
+                                                         sel->which);
                }
                break;
        case V4L2_SEL_TGT_CROP:
-               sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad,
+               sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, sel->pad,
                                                  sel->which);
                break;
        default:
@@ -878,7 +891,7 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        struct rkisp1_device *rkisp1 =
@@ -893,9 +906,9 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
                sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
        mutex_lock(&isp->ops_lock);
        if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
-               rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which);
+               rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r, sel->which);
        else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
-               rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which);
+               rkisp1_isp_set_src_crop(isp, sd_state, &sel->r, sel->which);
        else
                ret = -EINVAL;
 
@@ -1037,6 +1050,9 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = {
 
 int rkisp1_isp_register(struct rkisp1_device *rkisp1)
 {
+       struct v4l2_subdev_state state = {
+               .pads = rkisp1->isp.pad_cfg
+               };
        struct rkisp1_isp *isp = &rkisp1->isp;
        struct media_pad *pads = isp->pads;
        struct v4l2_subdev *sd = &isp->sd;
@@ -1069,7 +1085,7 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
                goto err_cleanup_media_entity;
        }
 
-       rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg);
+       rkisp1_isp_init_config(sd, &state);
        return 0;
 
 err_cleanup_media_entity:
index b6beddd..529c6e2 100644 (file)
@@ -1258,7 +1258,10 @@ void rkisp1_params_configure(struct rkisp1_params *params,
        rkisp1_params_config_parameter(params);
 }
 
-/* Not called when the camera active, thus not isr protection. */
+/*
+ * Not called when the camera is active, therefore there is no need to acquire
+ * a lock.
+ */
 void rkisp1_params_disable(struct rkisp1_params *params)
 {
        rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE,
index 79deed8..2070f4b 100644 (file)
@@ -180,24 +180,30 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = {
 
 static struct v4l2_mbus_framefmt *
 rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       unsigned int pad, u32 which)
 {
+       struct v4l2_subdev_state state = {
+               .pads = rsz->pad_cfg
+               };
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&rsz->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&rsz->sd, sd_state, pad);
        else
-               return v4l2_subdev_get_try_format(&rsz->sd, rsz->pad_cfg, pad);
+               return v4l2_subdev_get_try_format(&rsz->sd, &state, pad);
 }
 
 static struct v4l2_rect *
 rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        unsigned int pad, u32 which)
 {
+       struct v4l2_subdev_state state = {
+               .pads = rsz->pad_cfg
+               };
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&rsz->sd, cfg, pad);
+               return v4l2_subdev_get_try_crop(&rsz->sd, sd_state, pad);
        else
-               return v4l2_subdev_get_try_crop(&rsz->sd, rsz->pad_cfg, pad);
+               return v4l2_subdev_get_try_crop(&rsz->sd, &state, pad);
 }
 
 /* ----------------------------------------------------------------------------
@@ -451,12 +457,15 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
  */
 
 static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_mbus_code_enum *code)
 {
        struct rkisp1_resizer *rsz =
                container_of(sd, struct rkisp1_resizer, sd);
        struct v4l2_subdev_pad_config dummy_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &dummy_cfg
+               };
        u32 pad = code->pad;
        int ret;
 
@@ -481,7 +490,7 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
        /* supported mbus codes on the sink pad are the same as isp src pad */
        code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO;
        ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code,
-                              &dummy_cfg, code);
+                              &pad_state, code);
 
        /* restore pad */
        code->pad = pad;
@@ -490,24 +499,27 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg)
+                                 struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
        struct v4l2_rect *sink_crop;
 
-       sink_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SRC);
+       sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+                                             RKISP1_RSZ_PAD_SRC);
        sink_fmt->width = RKISP1_DEFAULT_WIDTH;
        sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
        sink_fmt->field = V4L2_FIELD_NONE;
        sink_fmt->code = RKISP1_DEF_FMT;
 
-       sink_crop = v4l2_subdev_get_try_crop(sd, cfg, RKISP1_RSZ_PAD_SINK);
+       sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
+                                            RKISP1_RSZ_PAD_SINK);
        sink_crop->width = RKISP1_DEFAULT_WIDTH;
        sink_crop->height = RKISP1_DEFAULT_HEIGHT;
        sink_crop->left = 0;
        sink_crop->top = 0;
 
-       src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SINK);
+       src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+                                            RKISP1_RSZ_PAD_SINK);
        *src_fmt = *sink_fmt;
 
        /* NOTE: there is no crop in the source pad, only in the sink */
@@ -516,15 +528,17 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
 }
 
 static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_mbus_framefmt *format,
                                   unsigned int which)
 {
        const struct rkisp1_isp_mbus_info *sink_mbus_info;
        struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
 
-       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
-       src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which);
+       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+                                         which);
+       src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC,
+                                        which);
        sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
 
        /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */
@@ -543,7 +557,7 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
 }
 
 static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_rect *r,
                                     unsigned int which)
 {
@@ -551,8 +565,10 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
        struct v4l2_mbus_framefmt *sink_fmt;
        struct v4l2_rect *sink_crop;
 
-       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
-       sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+                                         which);
+       sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state,
+                                           RKISP1_RSZ_PAD_SINK,
                                            which);
 
        /* Not crop for MP bayer raw data */
@@ -579,7 +595,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
 }
 
 static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_mbus_framefmt *format,
                                    unsigned int which)
 {
@@ -587,9 +603,12 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
        struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
        struct v4l2_rect *sink_crop;
 
-       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
-       src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which);
-       sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+       sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+                                         which);
+       src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC,
+                                        which);
+       sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state,
+                                           RKISP1_RSZ_PAD_SINK,
                                            which);
        if (rsz->id == RKISP1_SELFPATH)
                sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
@@ -617,24 +636,25 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
        *format = *sink_fmt;
 
        /* Update sink crop */
-       rkisp1_rsz_set_sink_crop(rsz, cfg, sink_crop, which);
+       rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which);
 }
 
 static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct rkisp1_resizer *rsz =
                container_of(sd, struct rkisp1_resizer, sd);
 
        mutex_lock(&rsz->ops_lock);
-       fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which);
+       fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, sd_state, fmt->pad,
+                                             fmt->which);
        mutex_unlock(&rsz->ops_lock);
        return 0;
 }
 
 static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct rkisp1_resizer *rsz =
@@ -642,16 +662,18 @@ static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&rsz->ops_lock);
        if (fmt->pad == RKISP1_RSZ_PAD_SINK)
-               rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which);
+               rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format,
+                                       fmt->which);
        else
-               rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which);
+               rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format,
+                                      fmt->which);
 
        mutex_unlock(&rsz->ops_lock);
        return 0;
 }
 
 static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        struct rkisp1_resizer *rsz =
@@ -665,7 +687,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
        mutex_lock(&rsz->ops_lock);
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
-               mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+               mf_sink = rkisp1_rsz_get_pad_fmt(rsz, sd_state,
+                                                RKISP1_RSZ_PAD_SINK,
                                                 sel->which);
                sel->r.height = mf_sink->height;
                sel->r.width = mf_sink->width;
@@ -673,7 +696,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
                sel->r.top = 0;
                break;
        case V4L2_SEL_TGT_CROP:
-               sel->r = *rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+               sel->r = *rkisp1_rsz_get_pad_crop(rsz, sd_state,
+                                                 RKISP1_RSZ_PAD_SINK,
                                                  sel->which);
                break;
        default:
@@ -685,7 +709,7 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
 }
 
 static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        struct rkisp1_resizer *rsz =
@@ -698,7 +722,7 @@ static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
                sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
 
        mutex_lock(&rsz->ops_lock);
-       rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which);
+       rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r, sel->which);
        mutex_unlock(&rsz->ops_lock);
 
        return 0;
@@ -764,6 +788,9 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
 
 static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
 {
+       struct v4l2_subdev_state state = {
+               .pads = rsz->pad_cfg
+               };
        static const char * const dev_names[] = {
                RKISP1_RSZ_MP_DEV_NAME,
                RKISP1_RSZ_SP_DEV_NAME
@@ -802,7 +829,7 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
                goto err_cleanup_media_entity;
        }
 
-       rkisp1_rsz_init_config(sd, rsz->pad_cfg);
+       rkisp1_rsz_init_config(sd, &state);
        return 0;
 
 err_cleanup_media_entity:
index 9ca49af..140854a 100644 (file)
@@ -547,7 +547,7 @@ static int s3c_camif_open(struct file *file)
        if (ret < 0)
                goto unlock;
 
-       ret = pm_runtime_get_sync(camif->dev);
+       ret = pm_runtime_resume_and_get(camif->dev);
        if (ret < 0)
                goto err_pm;
 
@@ -1199,7 +1199,7 @@ static const u32 camif_mbus_formats[] = {
  */
 
 static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                       struct v4l2_subdev_pad_config *cfg,
+                                       struct v4l2_subdev_state *sd_state,
                                        struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(camif_mbus_formats))
@@ -1210,14 +1210,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct camif_dev *camif = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *mf = &fmt->format;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                fmt->format = *mf;
                return 0;
        }
@@ -1278,7 +1278,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif,
 }
 
 static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1306,7 +1306,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
        __camif_subdev_try_format(camif, mf, fmt->pad);
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
                *mf = fmt->format;
                mutex_unlock(&camif->lock);
                return 0;
@@ -1345,7 +1345,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
-                                         struct v4l2_subdev_pad_config *cfg,
+                                         struct v4l2_subdev_state *sd_state,
                                          struct v4l2_subdev_selection *sel)
 {
        struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1358,7 +1358,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                return 0;
        }
 
@@ -1432,7 +1432,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r)
 }
 
 static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
-                                         struct v4l2_subdev_pad_config *cfg,
+                                         struct v4l2_subdev_state *sd_state,
                                          struct v4l2_subdev_selection *sel)
 {
        struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1446,7 +1446,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
        __camif_try_crop(camif, &sel->r);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
+               *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
        } else {
                unsigned long flags;
                unsigned int i;
index 4c3c00d..e1d51fd 100644 (file)
@@ -460,9 +460,9 @@ static int s3c_camif_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dev);
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto err_pm;
+               goto err_disable;
 
        ret = camif_media_dev_init(camif);
        if (ret < 0)
@@ -502,6 +502,7 @@ err_sens:
        camif_unregister_media_entities(camif);
 err_pm:
        pm_runtime_put(dev);
+err_disable:
        pm_runtime_disable(dev);
        camif_clk_put(camif);
 err_clk:
index 15bcb7f..1cb5eaa 100644 (file)
@@ -276,6 +276,9 @@ static int g2d_release(struct file *file)
        struct g2d_dev *dev = video_drvdata(file);
        struct g2d_ctx *ctx = fh2ctx(file->private_data);
 
+       mutex_lock(&dev->mutex);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+       mutex_unlock(&dev->mutex);
        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
index 0261115..d402e45 100644 (file)
@@ -2566,11 +2566,8 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
 static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
-       int ret;
-
-       ret = pm_runtime_get_sync(ctx->jpeg->dev);
 
-       return ret > 0 ? 0 : ret;
+       return pm_runtime_resume_and_get(ctx->jpeg->dev);
 }
 
 static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
index a92a9ca..c1d3bda 100644 (file)
@@ -172,6 +172,7 @@ static struct mfc_control controls[] = {
                .type = V4L2_CTRL_TYPE_INTEGER,
                .minimum = 0,
                .maximum = 16383,
+               .step = 1,
                .default_value = 0,
        },
        {
index 62d2320..88b7d33 100644 (file)
@@ -78,11 +78,9 @@ int s5p_mfc_power_on(void)
 {
        int i, ret = 0;
 
-       ret = pm_runtime_get_sync(pm->device);
-       if (ret < 0) {
-               pm_runtime_put_noidle(pm->device);
+       ret = pm_runtime_resume_and_get(pm->device);
+       if (ret < 0)
                return ret;
-       }
 
        /* clock control */
        for (i = 0; i < pm->num_clocks; i++) {
index 4ac4844..ca4310e 100644 (file)
@@ -1133,7 +1133,11 @@ static int sh_vou_open(struct file *file)
        if (v4l2_fh_is_singular_file(file) &&
            vou_dev->status == SH_VOU_INITIALISING) {
                /* First open */
-               pm_runtime_get_sync(vou_dev->v4l2_dev.dev);
+               err = pm_runtime_resume_and_get(vou_dev->v4l2_dev.dev);
+               if (err < 0) {
+                       v4l2_fh_release(file);
+                       goto done_open;
+               }
                err = sh_vou_hw_init(vou_dev);
                if (err < 0) {
                        pm_runtime_put(vou_dev->v4l2_dev.dev);
index caf7ccd..39ade0a 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_BDISP) := bdisp.o
+obj-$(CONFIG_VIDEO_STI_BDISP) += bdisp.o
 
 bdisp-objs := bdisp-v4l2.o bdisp-hw.o bdisp-debug.o
index 060ca85..6413cd2 100644 (file)
@@ -499,7 +499,7 @@ static int bdisp_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct bdisp_ctx *ctx = q->drv_priv;
        struct vb2_v4l2_buffer *buf;
-       int ret = pm_runtime_get_sync(ctx->bdisp_dev->dev);
+       int ret = pm_runtime_resume_and_get(ctx->bdisp_dev->dev);
 
        if (ret < 0) {
                dev_err(ctx->bdisp_dev->dev, "failed to set runtime PM\n");
@@ -1318,7 +1318,6 @@ static int bdisp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        bdisp->regs = devm_ioremap_resource(dev, res);
        if (IS_ERR(bdisp->regs)) {
-               dev_err(dev, "failed to get regs\n");
                ret = PTR_ERR(bdisp->regs);
                goto err_wq;
        }
@@ -1364,10 +1363,10 @@ static int bdisp_probe(struct platform_device *pdev)
 
        /* Power management */
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "failed to set PM\n");
-               goto err_pm;
+               goto err_remove;
        }
 
        /* Filters */
@@ -1395,6 +1394,7 @@ err_filter:
        bdisp_hw_free_filters(bdisp->dev);
 err_pm:
        pm_runtime_put(dev);
+err_remove:
        bdisp_debugfs_remove(bdisp);
        v4l2_device_unregister(&bdisp->v4l2_dev);
 err_clk:
index 92b37e2..32412fa 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) := st-delta.o
+obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) += st-delta.o
 st-delta-y := delta-v4l2.o delta-mem.o delta-ipc.o delta-debug.o
 
 # MJPEG support
index c691b3d..c887a31 100644 (file)
@@ -954,10 +954,8 @@ static void delta_run_work(struct work_struct *work)
        /* enable the hardware */
        if (!dec->pm) {
                ret = delta_get_sync(ctx);
-               if (ret) {
-                       delta_put_autosuspend(ctx);
+               if (ret)
                        goto err;
-               }
        }
 
        /* decode this access unit */
@@ -1009,7 +1007,6 @@ static void delta_run_work(struct work_struct *work)
                        dev_err(delta->dev,
                                "%s  NULL decoded frame\n",
                                ctx->name);
-                       ret = -EIO;
                        goto out;
                }
 
@@ -1277,9 +1274,9 @@ int delta_get_sync(struct delta_ctx *ctx)
        int ret = 0;
 
        /* enable the hardware */
-       ret = pm_runtime_get_sync(delta->dev);
+       ret = pm_runtime_resume_and_get(delta->dev);
        if (ret < 0) {
-               dev_err(delta->dev, "%s pm_runtime_get_sync failed (%d)\n",
+               dev_err(delta->dev, "%s pm_runtime_resume_and_get failed (%d)\n",
                        __func__, ret);
                return ret;
        }
index 74b41ec..b5a5478 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_HVA) := st-hva.o
+obj-$(CONFIG_VIDEO_STI_HVA) += st-hva.o
 st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
 st-hva-$(CONFIG_VIDEO_STI_HVA_DEBUGFS) += hva-debugfs.o
index f59811e..30fb1aa 100644 (file)
@@ -130,8 +130,7 @@ static irqreturn_t hva_hw_its_irq_thread(int irq, void *arg)
        ctx_id = (hva->sts_reg & 0xFF00) >> 8;
        if (ctx_id >= HVA_MAX_INSTANCES) {
                dev_err(dev, "%s     %s: bad context identifier: %d\n",
-                       ctx->name, __func__, ctx_id);
-               ctx->hw_err = true;
+                       HVA_PREFIX, __func__, ctx_id);
                goto out;
        }
 
@@ -270,9 +269,8 @@ static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva)
        struct device *dev = hva_to_dev(hva);
        unsigned long int version;
 
-       if (pm_runtime_get_sync(dev) < 0) {
+       if (pm_runtime_resume_and_get(dev) < 0) {
                dev_err(dev, "%s     failed to get pm_runtime\n", HVA_PREFIX);
-               pm_runtime_put_noidle(dev);
                mutex_unlock(&hva->protect_mutex);
                return -EFAULT;
        }
@@ -386,10 +384,10 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
        pm_runtime_set_suspended(dev);
        pm_runtime_enable(dev);
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0) {
                dev_err(dev, "%s     failed to set PM\n", HVA_PREFIX);
-               goto err_pm;
+               goto err_clk;
        }
 
        /* check IP hardware version */
@@ -462,6 +460,7 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
        u8 client_id = ctx->id;
        int ret;
        u32 reg = 0;
+       bool got_pm = false;
 
        mutex_lock(&hva->protect_mutex);
 
@@ -469,12 +468,13 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
        enable_irq(hva->irq_its);
        enable_irq(hva->irq_err);
 
-       if (pm_runtime_get_sync(dev) < 0) {
+       if (pm_runtime_resume_and_get(dev) < 0) {
                dev_err(dev, "%s     failed to get pm_runtime\n", ctx->name);
                ctx->sys_errors++;
                ret = -EFAULT;
                goto out;
        }
+       got_pm = true;
 
        reg = readl_relaxed(hva->regs + HVA_HIF_REG_CLK_GATING);
        switch (cmd) {
@@ -537,7 +537,8 @@ out:
                dev_dbg(dev, "%s     unknown command 0x%x\n", ctx->name, cmd);
        }
 
-       pm_runtime_put_autosuspend(dev);
+       if (got_pm)
+               pm_runtime_put_autosuspend(dev);
        mutex_unlock(&hva->protect_mutex);
 
        return ret;
@@ -553,9 +554,8 @@ void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s)
 
        mutex_lock(&hva->protect_mutex);
 
-       if (pm_runtime_get_sync(dev) < 0) {
+       if (pm_runtime_resume_and_get(dev) < 0) {
                seq_puts(s, "Cannot wake up IP\n");
-               pm_runtime_put_noidle(dev);
                mutex_unlock(&hva->protect_mutex);
                return;
        }
index d9b4ad0..d914cce 100644 (file)
@@ -600,7 +600,7 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
 }
 
 static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
-                              struct v4l2_subdev_pad_config *pad_cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *format)
 {
        struct media_entity *entity = &dcmi->source->entity;
@@ -642,7 +642,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
                        format->format.width, format->format.height);
 
                fmt.pad = pad->index;
-               ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt);
+               ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
                if (ret < 0) {
                        dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n",
                                __func__, format->format.code,
@@ -723,11 +723,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
        u32 val = 0;
        int ret;
 
-       ret = pm_runtime_get_sync(dcmi->dev);
+       ret = pm_runtime_resume_and_get(dcmi->dev);
        if (ret < 0) {
                dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
                        __func__, ret);
-               goto err_pm_put;
+               goto err_unlocked;
        }
 
        ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline);
@@ -848,6 +848,7 @@ err_media_pipeline_stop:
 
 err_pm_put:
        pm_runtime_put(dcmi->dev);
+err_unlocked:
        spin_lock_irq(&dcmi->irqlock);
        /*
         * Return all buffers to vb2 in QUEUED state.
@@ -977,6 +978,9 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
        struct dcmi_framesize sd_fsize;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -1012,7 +1016,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
 
        v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
        ret = v4l2_subdev_call(dcmi->source, pad, set_fmt,
-                              &pad_cfg, &format);
+                              &pad_state, &format);
        if (ret < 0)
                return ret;
 
@@ -1162,6 +1166,9 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        int ret;
 
        sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
@@ -1175,7 +1182,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
 
        v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
        ret = v4l2_subdev_call(dcmi->source, pad, set_fmt,
-                              &pad_cfg, &format);
+                              &pad_state, &format);
        if (ret < 0)
                return ret;
 
index 4785fad..3872027 100644 (file)
@@ -206,9 +206,9 @@ static int sun4i_csi_open(struct file *file)
        if (ret)
                return ret;
 
-       ret = pm_runtime_get_sync(csi->dev);
+       ret = pm_runtime_resume_and_get(csi->dev);
        if (ret < 0)
-               goto err_pm_put;
+               goto err_unlock;
 
        ret = v4l2_pipeline_pm_get(&csi->vdev.entity);
        if (ret)
@@ -227,6 +227,8 @@ err_pipeline_pm_put:
 
 err_pm_put:
        pm_runtime_put(csi->dev);
+
+err_unlock:
        mutex_unlock(&csi->lock);
 
        return ret;
@@ -269,25 +271,26 @@ static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
 };
 
 static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
-                                    struct v4l2_subdev_pad_config *cfg)
+                                    struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_mbus_framefmt *fmt;
 
-       fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK);
+       fmt = v4l2_subdev_get_try_format(subdev, sd_state, CSI_SUBDEV_SINK);
        *fmt = sun4i_csi_pad_fmt_default;
 
        return 0;
 }
 
 static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
        struct v4l2_mbus_framefmt *subdev_fmt;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+               subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
+                                                       fmt->pad);
        else
                subdev_fmt = &csi->subdev_fmt;
 
@@ -297,14 +300,15 @@ static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
 }
 
 static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_format *fmt)
 {
        struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
        struct v4l2_mbus_framefmt *subdev_fmt;
 
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+               subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
+                                                       fmt->pad);
        else
                subdev_fmt = &csi->subdev_fmt;
 
@@ -323,7 +327,7 @@ static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
 
 static int
 sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *mbus)
 {
        if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
index 3181d07..07b2161 100644 (file)
@@ -481,8 +481,10 @@ static int sun6i_video_open(struct file *file)
                goto fh_release;
 
        /* check if already powered */
-       if (!v4l2_fh_is_singular_file(file))
+       if (!v4l2_fh_is_singular_file(file)) {
+               ret = -EBUSY;
                goto unlock;
+       }
 
        ret = sun6i_csi_set_power(video->csi, true);
        if (ret < 0)
index 3f81dd1..fbcca59 100644 (file)
@@ -494,7 +494,7 @@ static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count)
                struct device *dev = ctx->dev->dev;
                int ret;
 
-               ret = pm_runtime_get_sync(dev);
+               ret = pm_runtime_resume_and_get(dev);
                if (ret < 0) {
                        dev_err(dev, "Failed to enable module\n");
 
index cbe6114..124a4e2 100644 (file)
@@ -586,12 +586,12 @@ static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd)
 
 static struct v4l2_mbus_framefmt *
 cal_camerarx_get_pad_format(struct cal_camerarx *phy,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&phy->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &phy->formats[pad];
        default:
@@ -611,7 +611,7 @@ static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
-                                         struct v4l2_subdev_pad_config *cfg,
+                                         struct v4l2_subdev_state *sd_state,
                                          struct v4l2_subdev_mbus_code_enum *code)
 {
        struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -623,7 +623,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index > 0)
                        return -EINVAL;
 
-               fmt = cal_camerarx_get_pad_format(phy, cfg,
+               fmt = cal_camerarx_get_pad_format(phy, sd_state,
                                                  CAL_CAMERARX_PAD_SINK,
                                                  code->which);
                code->code = fmt->code;
@@ -639,7 +639,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
-                                          struct v4l2_subdev_pad_config *cfg,
+                                          struct v4l2_subdev_state *sd_state,
                                           struct v4l2_subdev_frame_size_enum *fse)
 {
        struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -652,7 +652,7 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
        if (fse->pad == CAL_CAMERARX_PAD_SOURCE) {
                struct v4l2_mbus_framefmt *fmt;
 
-               fmt = cal_camerarx_get_pad_format(phy, cfg,
+               fmt = cal_camerarx_get_pad_format(phy, sd_state,
                                                  CAL_CAMERARX_PAD_SINK,
                                                  fse->which);
                if (fse->code != fmt->code)
@@ -679,20 +679,21 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *format)
 {
        struct cal_camerarx *phy = to_cal_camerarx(sd);
        struct v4l2_mbus_framefmt *fmt;
 
-       fmt = cal_camerarx_get_pad_format(phy, cfg, format->pad, format->which);
+       fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad,
+                                         format->which);
        format->format = *fmt;
 
        return 0;
 }
 
 static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_format *format)
 {
        struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -702,7 +703,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
 
        /* No transcoding, source and sink formats must match. */
        if (format->pad == CAL_CAMERARX_PAD_SOURCE)
-               return cal_camerarx_sd_get_fmt(sd, cfg, format);
+               return cal_camerarx_sd_get_fmt(sd, sd_state, format);
 
        /*
         * Default to the first format is the requested media bus code isn't
@@ -727,11 +728,13 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
        format->format.code = fmtinfo->code;
 
        /* Store the format and propagate it to the source pad. */
-       fmt = cal_camerarx_get_pad_format(phy, cfg, CAL_CAMERARX_PAD_SINK,
+       fmt = cal_camerarx_get_pad_format(phy, sd_state,
+                                         CAL_CAMERARX_PAD_SINK,
                                          format->which);
        *fmt = format->format;
 
-       fmt = cal_camerarx_get_pad_format(phy, cfg, CAL_CAMERARX_PAD_SOURCE,
+       fmt = cal_camerarx_get_pad_format(phy, sd_state,
+                                         CAL_CAMERARX_PAD_SOURCE,
                                          format->which);
        *fmt = format->format;
 
@@ -742,11 +745,11 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg)
+                                   struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format format = {
-               .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
-                      : V4L2_SUBDEV_FORMAT_ACTIVE,
+               .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+               : V4L2_SUBDEV_FORMAT_ACTIVE,
                .pad = CAL_CAMERARX_PAD_SINK,
                .format = {
                        .width = 640,
@@ -760,7 +763,7 @@ static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
                },
        };
 
-       return cal_camerarx_sd_set_fmt(sd, cfg, &format);
+       return cal_camerarx_sd_set_fmt(sd, sd_state, &format);
 }
 
 static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
index 7b7436a..15fb536 100644 (file)
@@ -700,7 +700,9 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
 
        addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
 
-       pm_runtime_get_sync(ctx->cal->dev);
+       ret = pm_runtime_resume_and_get(ctx->cal->dev);
+       if (ret < 0)
+               goto error_pipeline;
 
        cal_ctx_set_dma_addr(ctx, addr);
        cal_ctx_start(ctx);
index 2e2bef9..76fe7a8 100644 (file)
@@ -1024,7 +1024,7 @@ static int cal_probe(struct platform_device *pdev)
 
        /* Read the revision and hardware info to verify hardware access. */
        pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret)
                goto error_pm_runtime;
 
@@ -1098,10 +1098,11 @@ static int cal_remove(struct platform_device *pdev)
 {
        struct cal_dev *cal = platform_get_drvdata(pdev);
        unsigned int i;
+       int ret;
 
        cal_dbg(1, cal, "Removing %s\n", CAL_MODULE_NAME);
 
-       pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
 
        cal_media_unregister(cal);
 
@@ -1115,7 +1116,8 @@ static int cal_remove(struct platform_device *pdev)
        for (i = 0; i < cal->data->num_csi2_phy; i++)
                cal_camerarx_destroy(cal->phy[i]);
 
-       pm_runtime_put_sync(&pdev->dev);
+       if (ret >= 0)
+               pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
index 10251b7..5b1c5d9 100644 (file)
@@ -2471,11 +2471,9 @@ static int vpe_runtime_get(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "vpe_runtime_get\n");
 
-       r = pm_runtime_get_sync(&pdev->dev);
+       r = pm_runtime_resume_and_get(&pdev->dev);
        WARN_ON(r < 0);
-       if (r)
-               pm_runtime_put_noidle(&pdev->dev);
-       return r < 0 ? r : 0;
+       return r;
 }
 
 static void vpe_runtime_put(struct platform_device *pdev)
@@ -2580,7 +2578,7 @@ static int vpe_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
 
        ret = vpe_runtime_get(pdev);
-       if (ret)
+       if (ret < 0)
                goto rel_m2m;
 
        /* Perform clk enable followed by reset */
index ed0ad68..3655573 100644 (file)
@@ -844,6 +844,9 @@ static int viacam_do_try_fmt(struct via_camera *cam,
 {
        int ret;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -852,7 +855,7 @@ static int viacam_do_try_fmt(struct via_camera *cam,
        upix->pixelformat = f->pixelformat;
        viacam_fmt_pre(upix, spix);
        v4l2_fill_mbus_format(&format.format, spix, f->mbus_code);
-       ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format);
+       ret = sensor_call(cam, pad, set_fmt, &pad_state, &format);
        v4l2_fill_pix_format(spix, &format.format);
        viacam_fmt_post(upix, spix);
        return ret;
index 133122e..905005e 100644 (file)
@@ -140,14 +140,14 @@ static const struct v4l2_subdev_video_ops video_mux_subdev_video_ops = {
 
 static struct v4l2_mbus_framefmt *
 __video_mux_get_pad_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad, u32 which)
 {
        struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
 
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(sd, cfg, pad);
+               return v4l2_subdev_get_try_format(sd, sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &vmux->format_mbus[pad];
        default:
@@ -156,14 +156,15 @@ __video_mux_get_pad_format(struct v4l2_subdev *sd,
 }
 
 static int video_mux_get_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *sdformat)
 {
        struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
 
        mutex_lock(&vmux->lock);
 
-       sdformat->format = *__video_mux_get_pad_format(sd, cfg, sdformat->pad,
+       sdformat->format = *__video_mux_get_pad_format(sd, sd_state,
+                                                      sdformat->pad,
                                                       sdformat->which);
 
        mutex_unlock(&vmux->lock);
@@ -172,7 +173,7 @@ static int video_mux_get_format(struct v4l2_subdev *sd,
 }
 
 static int video_mux_set_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *sdformat)
 {
        struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
@@ -180,12 +181,13 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
        struct media_pad *pad = &vmux->pads[sdformat->pad];
        u16 source_pad = sd->entity.num_pads - 1;
 
-       mbusformat = __video_mux_get_pad_format(sd, cfg, sdformat->pad,
-                                           sdformat->which);
+       mbusformat = __video_mux_get_pad_format(sd, sd_state, sdformat->pad,
+                                               sdformat->which);
        if (!mbusformat)
                return -EINVAL;
 
-       source_mbusformat = __video_mux_get_pad_format(sd, cfg, source_pad,
+       source_mbusformat = __video_mux_get_pad_format(sd, sd_state,
+                                                      source_pad,
                                                       sdformat->which);
        if (!source_mbusformat)
                return -EINVAL;
@@ -310,7 +312,7 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
 }
 
 static int video_mux_init_cfg(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg)
+                             struct v4l2_subdev_state *sd_state)
 {
        struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
        struct v4l2_mbus_framefmt *mbusformat;
@@ -319,7 +321,7 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd,
        mutex_lock(&vmux->lock);
 
        for (i = 0; i < sd->entity.num_pads; i++) {
-               mbusformat = v4l2_subdev_get_try_format(sd, cfg, i);
+               mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i);
                *mbusformat = video_mux_format_mbus_default;
        }
 
@@ -362,7 +364,7 @@ static int video_mux_async_register(struct video_mux *vmux,
 
        for (i = 0; i < num_input_pads; i++) {
                struct v4l2_async_subdev *asd;
-               struct fwnode_handle *ep;
+               struct fwnode_handle *ep, *remote_ep;
 
                ep = fwnode_graph_get_endpoint_by_id(
                        dev_fwnode(vmux->subdev.dev), i, 0,
@@ -370,6 +372,14 @@ static int video_mux_async_register(struct video_mux *vmux,
                if (!ep)
                        continue;
 
+               /* Skip dangling endpoints for backwards compatibility */
+               remote_ep = fwnode_graph_get_remote_endpoint(ep);
+               if (!remote_ep) {
+                       fwnode_handle_put(ep);
+                       continue;
+               }
+               fwnode_handle_put(remote_ep);
+
                asd = v4l2_async_notifier_add_fwnode_remote_subdev(
                        &vmux->notifier, ep, struct v4l2_async_subdev);
 
index 2d86c71..89385b4 100644 (file)
@@ -65,7 +65,7 @@ static const struct v4l2_ctrl_ops brx_ctrl_ops = {
  */
 
 static int brx_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        static const unsigned int codes[] = {
@@ -73,12 +73,12 @@ static int brx_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
 
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
                                          ARRAY_SIZE(codes));
 }
 
 static int brx_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index)
@@ -97,14 +97,14 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
-                                        struct v4l2_subdev_pad_config *cfg,
+                                        struct v4l2_subdev_state *sd_state,
                                         unsigned int pad)
 {
-       return v4l2_subdev_get_try_compose(&brx->entity.subdev, cfg, pad);
+       return v4l2_subdev_get_try_compose(&brx->entity.subdev, sd_state, pad);
 }
 
 static void brx_try_format(struct vsp1_brx *brx,
-                          struct v4l2_subdev_pad_config *config,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
@@ -119,7 +119,7 @@ static void brx_try_format(struct vsp1_brx *brx,
 
        default:
                /* The BRx can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&brx->entity, config,
+               format = vsp1_entity_get_pad_format(&brx->entity, sd_state,
                                                    BRX_PAD_SINK(0));
                fmt->code = format->code;
                break;
@@ -132,17 +132,18 @@ static void brx_try_format(struct vsp1_brx *brx,
 }
 
 static int brx_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_brx *brx = to_brx(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
        mutex_lock(&brx->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&brx->entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
+                                           fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -181,11 +182,11 @@ done:
 }
 
 static int brx_get_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_brx *brx = to_brx(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
 
        if (sel->pad == brx->entity.source_pad)
                return -EINVAL;
@@ -199,7 +200,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
                return 0;
 
        case V4L2_SEL_TGT_COMPOSE:
-               config = vsp1_entity_get_pad_config(&brx->entity, cfg,
+               config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
                                                    sel->which);
                if (!config)
                        return -EINVAL;
@@ -215,11 +216,11 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
 }
 
 static int brx_set_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_brx *brx = to_brx(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *compose;
        int ret = 0;
@@ -232,7 +233,8 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&brx->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&brx->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index a47b23b..c5217fe 100644 (file)
@@ -123,27 +123,28 @@ static const unsigned int clu_codes[] = {
 };
 
 static int clu_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, clu_codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, clu_codes,
                                          ARRAY_SIZE(clu_codes));
 }
 
 static int clu_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          CLU_MIN_SIZE,
                                           CLU_MIN_SIZE, CLU_MAX_SIZE,
                                           CLU_MAX_SIZE);
 }
 
 static int clu_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
-       return vsp1_subdev_set_pad_format(subdev, cfg, fmt, clu_codes,
+       return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, clu_codes,
                                          ARRAY_SIZE(clu_codes),
                                          CLU_MIN_SIZE, CLU_MIN_SIZE,
                                          CLU_MAX_SIZE, CLU_MAX_SIZE);
index aa66e4f..de442d6 100644 (file)
@@ -559,15 +559,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
  */
 int vsp1_device_get(struct vsp1_device *vsp1)
 {
-       int ret;
-
-       ret = pm_runtime_get_sync(vsp1->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(vsp1->dev);
-               return ret;
-       }
-
-       return 0;
+       return pm_runtime_resume_and_get(vsp1->dev);
 }
 
 /*
index aa9d228..6f51e5c 100644 (file)
@@ -103,7 +103,7 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
 /**
  * vsp1_entity_get_pad_config - Get the pad configuration for an entity
  * @entity: the entity
- * @cfg: the TRY pad configuration
+ * @sd_state: the TRY state
  * @which: configuration selector (ACTIVE or TRY)
  *
  * When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold
@@ -114,9 +114,9 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
  * and simply returned when requested. The ACTIVE configuration comes from the
  * entity structure.
  */
-struct v4l2_subdev_pad_config *
+struct v4l2_subdev_state *
 vsp1_entity_get_pad_config(struct vsp1_entity *entity,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           enum v4l2_subdev_format_whence which)
 {
        switch (which) {
@@ -124,14 +124,14 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
                return entity->config;
        case V4L2_SUBDEV_FORMAT_TRY:
        default:
-               return cfg;
+               return sd_state;
        }
 }
 
 /**
  * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
  * @entity: the entity
- * @cfg: the configuration storage
+ * @sd_state: the state storage
  * @pad: the pad number
  *
  * Return the format stored in the given configuration for an entity's pad. The
@@ -139,16 +139,16 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
  */
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad)
 {
-       return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
+       return v4l2_subdev_get_try_format(&entity->subdev, sd_state, pad);
 }
 
 /**
  * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
  * @entity: the entity
- * @cfg: the configuration storage
+ * @sd_state: the state storage
  * @pad: the pad number
  * @target: the selection target
  *
@@ -158,14 +158,16 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
  */
 struct v4l2_rect *
 vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              unsigned int pad, unsigned int target)
 {
        switch (target) {
        case V4L2_SEL_TGT_COMPOSE:
-               return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
+               return v4l2_subdev_get_try_compose(&entity->subdev, sd_state,
+                                                  pad);
        case V4L2_SEL_TGT_CROP:
-               return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
+               return v4l2_subdev_get_try_crop(&entity->subdev, sd_state,
+                                               pad);
        default:
                return NULL;
        }
@@ -180,7 +182,7 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
  * function can be used as a handler for the subdev pad::init_cfg operation.
  */
 int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
-                        struct v4l2_subdev_pad_config *cfg)
+                        struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_subdev_format format;
        unsigned int pad;
@@ -189,10 +191,10 @@ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
                memset(&format, 0, sizeof(format));
 
                format.pad = pad;
-               format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
+               format.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
                             : V4L2_SUBDEV_FORMAT_ACTIVE;
 
-               v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
+               v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format);
        }
 
        return 0;
@@ -208,13 +210,13 @@ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
  * a direct drop-in for the operation handler.
  */
 int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct vsp1_entity *entity = to_vsp1_entity(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
 
-       config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
        if (!config)
                return -EINVAL;
 
@@ -239,7 +241,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
  * the sink pad.
  */
 int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code,
                               const unsigned int *codes, unsigned int ncodes)
 {
@@ -251,7 +253,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
 
                code->code = codes[code->index];
        } else {
-               struct v4l2_subdev_pad_config *config;
+               struct v4l2_subdev_state *config;
                struct v4l2_mbus_framefmt *format;
 
                /*
@@ -261,7 +263,8 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
                if (code->index)
                        return -EINVAL;
 
-               config = vsp1_entity_get_pad_config(entity, cfg, code->which);
+               config = vsp1_entity_get_pad_config(entity, sd_state,
+                                                   code->which);
                if (!config)
                        return -EINVAL;
 
@@ -290,17 +293,17 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
  * source pad size identical to the sink pad.
  */
 int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse,
                                unsigned int min_width, unsigned int min_height,
                                unsigned int max_width, unsigned int max_height)
 {
        struct vsp1_entity *entity = to_vsp1_entity(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
-       config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
+       config = vsp1_entity_get_pad_config(entity, sd_state, fse->which);
        if (!config)
                return -EINVAL;
 
@@ -353,14 +356,14 @@ done:
  * source pad.
  */
 int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt,
                               const unsigned int *codes, unsigned int ncodes,
                               unsigned int min_width, unsigned int min_height,
                               unsigned int max_width, unsigned int max_height)
 {
        struct vsp1_entity *entity = to_vsp1_entity(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *selection;
        unsigned int i;
@@ -368,7 +371,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
 
        mutex_lock(&entity->lock);
 
-       config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -672,7 +675,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
         * Allocate the pad configuration to store formats and selection
         * rectangles.
         */
-       entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
+       entity->config = v4l2_subdev_alloc_state(&entity->subdev);
        if (entity->config == NULL) {
                media_entity_cleanup(&entity->subdev.entity);
                return -ENOMEM;
@@ -687,6 +690,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
                entity->ops->destroy(entity);
        if (entity->subdev.ctrl_handler)
                v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
-       v4l2_subdev_free_pad_config(entity->config);
+       v4l2_subdev_free_state(entity->config);
        media_entity_cleanup(&entity->subdev.entity);
 }
index a1ceb37..f227244 100644 (file)
@@ -115,7 +115,7 @@ struct vsp1_entity {
        unsigned int sink_pad;
 
        struct v4l2_subdev subdev;
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
 
        struct mutex lock;      /* Protects the pad config */
 };
@@ -136,20 +136,20 @@ int vsp1_entity_link_setup(struct media_entity *entity,
                           const struct media_pad *local,
                           const struct media_pad *remote, u32 flags);
 
-struct v4l2_subdev_pad_config *
+struct v4l2_subdev_state *
 vsp1_entity_get_pad_config(struct vsp1_entity *entity,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           enum v4l2_subdev_format_whence which);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad);
 struct v4l2_rect *
 vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              unsigned int pad, unsigned int target);
 int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
-                        struct v4l2_subdev_pad_config *cfg);
+                        struct v4l2_subdev_state *sd_state);
 
 void vsp1_entity_route_setup(struct vsp1_entity *entity,
                             struct vsp1_pipeline *pipe,
@@ -173,20 +173,20 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
 struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad);
 
 int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt);
 int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt,
                               const unsigned int *codes, unsigned int ncodes,
                               unsigned int min_width, unsigned int min_height,
                               unsigned int max_width, unsigned int max_height);
 int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code,
                               const unsigned int *codes, unsigned int ncodes);
 int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse,
                                unsigned int min_w, unsigned int min_h,
                                unsigned int max_w, unsigned int max_h);
index a91e142..5e5013d 100644 (file)
@@ -170,7 +170,7 @@ static const struct vb2_ops histo_video_queue_qops = {
  */
 
 static int histo_enum_mbus_code(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
@@ -180,28 +180,30 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev,
                return 0;
        }
 
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, histo->formats,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code,
+                                         histo->formats,
                                          histo->num_formats);
 }
 
 static int histo_enum_frame_size(struct v4l2_subdev *subdev,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->pad != HISTO_PAD_SINK)
                return -EINVAL;
 
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HISTO_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          HISTO_MIN_SIZE,
                                           HISTO_MIN_SIZE, HISTO_MAX_SIZE,
                                           HISTO_MAX_SIZE);
 }
 
 static int histo_get_selection(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_selection *sel)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
        int ret = 0;
@@ -211,7 +213,8 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&histo->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -256,15 +259,15 @@ done:
 }
 
 static int histo_set_crop(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *config,
-                        struct v4l2_subdev_selection *sel)
+                         struct v4l2_subdev_state *sd_state,
+                         struct v4l2_subdev_selection *sel)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *selection;
 
        /* The crop rectangle must be inside the input frame. */
-       format = vsp1_entity_get_pad_format(&histo->entity, config,
+       format = vsp1_entity_get_pad_format(&histo->entity, sd_state,
                                            HISTO_PAD_SINK);
        sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
        sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -274,11 +277,11 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
                                format->height - sel->r.top);
 
        /* Set the crop rectangle and reset the compose rectangle. */
-       selection = vsp1_entity_get_pad_selection(&histo->entity, config,
+       selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
                                                  sel->pad, V4L2_SEL_TGT_CROP);
        *selection = sel->r;
 
-       selection = vsp1_entity_get_pad_selection(&histo->entity, config,
+       selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
                                                  sel->pad,
                                                  V4L2_SEL_TGT_COMPOSE);
        *selection = sel->r;
@@ -287,7 +290,7 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
 }
 
 static int histo_set_compose(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *config,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
@@ -303,7 +306,8 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
        sel->r.left = 0;
        sel->r.top = 0;
 
-       crop = vsp1_entity_get_pad_selection(&histo->entity, config, sel->pad,
+       crop = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
+                                            sel->pad,
                                             V4L2_SEL_TGT_CROP);
 
        /*
@@ -329,7 +333,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
        ratio = 1 << (crop->height * 2 / sel->r.height / 3);
        sel->r.height = crop->height / ratio;
 
-       compose = vsp1_entity_get_pad_selection(&histo->entity, config,
+       compose = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
                                                sel->pad,
                                                V4L2_SEL_TGT_COMPOSE);
        *compose = sel->r;
@@ -338,11 +342,11 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
 }
 
 static int histo_set_selection(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_selection *sel)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        int ret;
 
        if (sel->pad != HISTO_PAD_SINK)
@@ -350,7 +354,8 @@ static int histo_set_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&histo->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -369,7 +374,7 @@ done:
 }
 
 static int histo_get_format(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        if (fmt->pad == HISTO_PAD_SOURCE) {
@@ -381,19 +386,19 @@ static int histo_get_format(struct v4l2_subdev *subdev,
                return 0;
        }
 
-       return vsp1_subdev_get_pad_format(subdev, cfg, fmt);
+       return vsp1_subdev_get_pad_format(subdev, sd_state, fmt);
 }
 
 static int histo_set_format(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vsp1_histogram *histo = subdev_to_histo(subdev);
 
        if (fmt->pad != HISTO_PAD_SINK)
-               return histo_get_format(subdev, cfg, fmt);
+               return histo_get_format(subdev, sd_state, fmt);
 
-       return vsp1_subdev_set_pad_format(subdev, cfg, fmt,
+       return vsp1_subdev_set_pad_format(subdev, sd_state, fmt,
                                          histo->formats, histo->num_formats,
                                          HISTO_MIN_SIZE, HISTO_MIN_SIZE,
                                          HISTO_MAX_SIZE, HISTO_MAX_SIZE);
index d5ebd9d..361a870 100644 (file)
@@ -34,7 +34,7 @@ static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
  */
 
 static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        struct vsp1_hsit *hsit = to_hsit(subdev);
@@ -52,26 +52,28 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          HSIT_MIN_SIZE,
                                           HSIT_MIN_SIZE, HSIT_MAX_SIZE,
                                           HSIT_MAX_SIZE);
 }
 
 static int hsit_set_format(struct v4l2_subdev *subdev,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct vsp1_hsit *hsit = to_hsit(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
        mutex_lock(&hsit->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(&hsit->entity, sd_state,
+                                           fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index 14ed5d7..6a6857a 100644 (file)
@@ -40,27 +40,28 @@ static const unsigned int lif_codes[] = {
 };
 
 static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lif_codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lif_codes,
                                          ARRAY_SIZE(lif_codes));
 }
 
 static int lif_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          LIF_MIN_SIZE,
                                           LIF_MIN_SIZE, LIF_MAX_SIZE,
                                           LIF_MAX_SIZE);
 }
 
 static int lif_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
-       return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lif_codes,
+       return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lif_codes,
                                          ARRAY_SIZE(lif_codes),
                                          LIF_MIN_SIZE, LIF_MIN_SIZE,
                                          LIF_MAX_SIZE, LIF_MAX_SIZE);
index 9f88842..ac6802a 100644 (file)
@@ -99,27 +99,28 @@ static const unsigned int lut_codes[] = {
 };
 
 static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lut_codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lut_codes,
                                          ARRAY_SIZE(lut_codes));
 }
 
 static int lut_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          LUT_MIN_SIZE,
                                           LUT_MIN_SIZE, LUT_MAX_SIZE,
                                           LUT_MAX_SIZE);
 }
 
 static int lut_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
-       return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lut_codes,
+       return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lut_codes,
                                          ARRAY_SIZE(lut_codes),
                                          LUT_MIN_SIZE, LUT_MIN_SIZE,
                                          LUT_MAX_SIZE, LUT_MAX_SIZE);
index 049bdd9..22a82d2 100644 (file)
@@ -17,9 +17,9 @@
 #define RWPF_MIN_HEIGHT                                1
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
-                                    struct v4l2_subdev_pad_config *config)
+                                    struct v4l2_subdev_state *sd_state)
 {
-       return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+       return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, sd_state,
                                        RWPF_PAD_SINK);
 }
 
@@ -28,7 +28,7 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
  */
 
 static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_mbus_code_enum *code)
 {
        static const unsigned int codes[] = {
@@ -46,28 +46,30 @@ static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 }
 
 static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          RWPF_MIN_WIDTH,
                                           RWPF_MIN_HEIGHT, rwpf->max_width,
                                           rwpf->max_height);
 }
 
 static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_format *fmt)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
        mutex_lock(&rwpf->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+                                           fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -128,11 +130,11 @@ done:
 }
 
 static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_selection *sel)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
@@ -145,7 +147,8 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&rwpf->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -176,11 +179,11 @@ done:
 }
 
 static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_selection *sel)
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
        int ret = 0;
@@ -197,7 +200,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&rwpf->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index 2f35825..eac5c04 100644 (file)
@@ -84,6 +84,6 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
 extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
-                                    struct v4l2_subdev_pad_config *config);
+                                    struct v4l2_subdev_state *sd_state);
 
 #endif /* __VSP1_RWPF_H__ */
index 2b65457..b614a2a 100644 (file)
@@ -106,7 +106,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
  */
 
 static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        static const unsigned int codes[] = {
@@ -114,20 +114,21 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
 
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
                                          ARRAY_SIZE(codes));
 }
 
 static int sru_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_sru *sru = to_sru(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
-       config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
+       config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
+                                           fse->which);
        if (!config)
                return -EINVAL;
 
@@ -164,7 +165,7 @@ done:
 }
 
 static void sru_try_format(struct vsp1_sru *sru,
-                          struct v4l2_subdev_pad_config *config,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
@@ -184,7 +185,7 @@ static void sru_try_format(struct vsp1_sru *sru,
 
        case SRU_PAD_SOURCE:
                /* The SRU can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&sru->entity, config,
+               format = vsp1_entity_get_pad_format(&sru->entity, sd_state,
                                                    SRU_PAD_SINK);
                fmt->code = format->code;
 
@@ -216,17 +217,18 @@ static void sru_try_format(struct vsp1_sru *sru,
 }
 
 static int sru_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_sru *sru = to_sru(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
        mutex_lock(&sru->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
+                                           fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index 5fc04c0..1c290cd 100644 (file)
@@ -111,7 +111,7 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
  */
 
 static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        static const unsigned int codes[] = {
@@ -119,20 +119,21 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
                MEDIA_BUS_FMT_AYUV8_1X32,
        };
 
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
                                          ARRAY_SIZE(codes));
 }
 
 static int uds_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct vsp1_uds *uds = to_uds(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
-       config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which);
+       config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
+                                           fse->which);
        if (!config)
                return -EINVAL;
 
@@ -164,7 +165,7 @@ done:
 }
 
 static void uds_try_format(struct vsp1_uds *uds,
-                          struct v4l2_subdev_pad_config *config,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
        struct v4l2_mbus_framefmt *format;
@@ -184,7 +185,7 @@ static void uds_try_format(struct vsp1_uds *uds,
 
        case UDS_PAD_SOURCE:
                /* The UDS scales but can't perform format conversion. */
-               format = vsp1_entity_get_pad_format(&uds->entity, config,
+               format = vsp1_entity_get_pad_format(&uds->entity, sd_state,
                                                    UDS_PAD_SINK);
                fmt->code = format->code;
 
@@ -200,17 +201,18 @@ static void uds_try_format(struct vsp1_uds *uds,
 }
 
 static int uds_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct vsp1_uds *uds = to_uds(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
        mutex_lock(&uds->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+       config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
+                                           fmt->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index 467d107..83d7f17 100644 (file)
@@ -54,38 +54,39 @@ static const unsigned int uif_codes[] = {
 };
 
 static int uif_enum_mbus_code(struct v4l2_subdev *subdev,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
-       return vsp1_subdev_enum_mbus_code(subdev, cfg, code, uif_codes,
+       return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, uif_codes,
                                          ARRAY_SIZE(uif_codes));
 }
 
 static int uif_enum_frame_size(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
-       return vsp1_subdev_enum_frame_size(subdev, cfg, fse, UIF_MIN_SIZE,
+       return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+                                          UIF_MIN_SIZE,
                                           UIF_MIN_SIZE, UIF_MAX_SIZE,
                                           UIF_MAX_SIZE);
 }
 
 static int uif_set_format(struct v4l2_subdev *subdev,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
-       return vsp1_subdev_set_pad_format(subdev, cfg, fmt, uif_codes,
+       return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, uif_codes,
                                          ARRAY_SIZE(uif_codes),
                                          UIF_MIN_SIZE, UIF_MIN_SIZE,
                                          UIF_MAX_SIZE, UIF_MAX_SIZE);
 }
 
 static int uif_get_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_uif *uif = to_uif(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        int ret = 0;
 
@@ -94,7 +95,8 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&uif->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&uif->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
@@ -127,11 +129,11 @@ done:
 }
 
 static int uif_set_selection(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct vsp1_uif *uif = to_uif(subdev);
-       struct v4l2_subdev_pad_config *config;
+       struct v4l2_subdev_state *config;
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *selection;
        int ret = 0;
@@ -142,7 +144,8 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
 
        mutex_lock(&uif->entity.lock);
 
-       config = vsp1_entity_get_pad_config(&uif->entity, cfg, sel->which);
+       config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
+                                           sel->which);
        if (!config) {
                ret = -EINVAL;
                goto done;
index fff7dde..b1baf9d 100644 (file)
@@ -681,12 +681,13 @@ stream_done:
 
 static struct v4l2_mbus_framefmt *
 __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&xcsi2rxss->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&xcsi2rxss->subdev,
+                                                 sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &xcsi2rxss->format;
        default:
@@ -697,7 +698,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
 /**
  * xcsi2rxss_init_cfg - Initialise the pad format config to default
  * @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
  *
  * This function is used to initialize the pad format with the default
  * values.
@@ -705,7 +706,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
  * Return: 0 on success
  */
 static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg)
+                             struct v4l2_subdev_state *sd_state)
 {
        struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
        struct v4l2_mbus_framefmt *format;
@@ -713,7 +714,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
 
        mutex_lock(&xcsi2rxss->lock);
        for (i = 0; i < XCSI_MEDIA_PADS; i++) {
-               format = v4l2_subdev_get_try_format(sd, cfg, i);
+               format = v4l2_subdev_get_try_format(sd, sd_state, i);
                *format = xcsi2rxss->default_format;
        }
        mutex_unlock(&xcsi2rxss->lock);
@@ -724,7 +725,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
 /**
  * xcsi2rxss_get_format - Get the pad format
  * @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
  * @fmt: Pointer to pad level media bus format
  *
  * This function is used to get the pad format information.
@@ -732,13 +733,14 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
  * Return: 0 on success
  */
 static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_format *fmt)
 {
        struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
 
        mutex_lock(&xcsi2rxss->lock);
-       fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, cfg, fmt->pad,
+       fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
+                                                 fmt->pad,
                                                  fmt->which);
        mutex_unlock(&xcsi2rxss->lock);
 
@@ -748,7 +750,7 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
 /**
  * xcsi2rxss_set_format - This is used to set the pad format
  * @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
  * @fmt: Pointer to pad level media bus format
  *
  * This function is used to set the pad format. Since the pad format is fixed
@@ -759,7 +761,7 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
  * Return: 0 on success
  */
 static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_format *fmt)
 {
        struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
@@ -773,7 +775,7 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
         * CSI format cannot be changed at runtime.
         * Ensure that format to set is copied to over to CSI pad format
         */
-       __format = __xcsi2rxss_get_pad_format(xcsi2rxss, cfg,
+       __format = __xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
                                              fmt->pad, fmt->which);
 
        /* only sink pad format can be updated */
@@ -811,7 +813,7 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
  * Return: -EINVAL or zero on success
  */
 static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_mbus_code_enum *code)
 {
        struct xcsi2rxss_state *state = to_xcsi2rxssstate(sd);
index 2a56201..338c366 100644 (file)
@@ -26,7 +26,6 @@
 #include "xilinx-vip.h"
 #include "xilinx-vipp.h"
 
-#define XVIP_DMA_DEF_FORMAT            V4L2_PIX_FMT_YUYV
 #define XVIP_DMA_DEF_WIDTH             1920
 #define XVIP_DMA_DEF_HEIGHT            1080
 
@@ -549,8 +548,6 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
         * requested format isn't supported.
         */
        info = xvip_get_format_by_fourcc(pix->pixelformat);
-       if (IS_ERR(info))
-               info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
 
        pix->pixelformat = info->fourcc;
        pix->field = V4L2_FIELD_NONE;
@@ -660,7 +657,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
        INIT_LIST_HEAD(&dma->queued_bufs);
        spin_lock_init(&dma->queued_lock);
 
-       dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
+       dma->fmtinfo = xvip_get_format_by_fourcc(V4L2_PIX_FMT_YUYV);
        dma->format.pixelformat = dma->fmtinfo->fourcc;
        dma->format.colorspace = V4L2_COLORSPACE_SRGB;
        dma->format.field = V4L2_FIELD_NONE;
index ed01bed..0f2d5a0 100644 (file)
@@ -251,12 +251,13 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
 
 static struct v4l2_mbus_framefmt *
 __xtpg_get_pad_format(struct xtpg_device *xtpg,
-                     struct v4l2_subdev_pad_config *cfg,
+                     struct v4l2_subdev_state *sd_state,
                      unsigned int pad, u32 which)
 {
        switch (which) {
        case V4L2_SUBDEV_FORMAT_TRY:
-               return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&xtpg->xvip.subdev,
+                                                 sd_state, pad);
        case V4L2_SUBDEV_FORMAT_ACTIVE:
                return &xtpg->formats[pad];
        default:
@@ -265,25 +266,26 @@ __xtpg_get_pad_format(struct xtpg_device *xtpg,
 }
 
 static int xtpg_get_format(struct v4l2_subdev *subdev,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct xtpg_device *xtpg = to_tpg(subdev);
 
-       fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+       fmt->format = *__xtpg_get_pad_format(xtpg, sd_state, fmt->pad,
+                                            fmt->which);
 
        return 0;
 }
 
 static int xtpg_set_format(struct v4l2_subdev *subdev,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct xtpg_device *xtpg = to_tpg(subdev);
        struct v4l2_mbus_framefmt *__format;
        u32 bayer_phase;
 
-       __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+       __format = __xtpg_get_pad_format(xtpg, sd_state, fmt->pad, fmt->which);
 
        /* In two pads mode the source pad format is always identical to the
         * sink pad format.
@@ -306,7 +308,8 @@ static int xtpg_set_format(struct v4l2_subdev *subdev,
 
        /* Propagate the format to the source pad. */
        if (xtpg->npads == 2) {
-               __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which);
+               __format = __xtpg_get_pad_format(xtpg, sd_state, 1,
+                                                fmt->which);
                *__format = fmt->format;
        }
 
@@ -318,12 +321,12 @@ static int xtpg_set_format(struct v4l2_subdev *subdev,
  */
 
 static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        struct v4l2_mbus_framefmt *format;
 
-       format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+       format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
 
        if (fse->index || fse->code != format->code)
                return -EINVAL;
@@ -351,11 +354,11 @@ static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        struct xtpg_device *xtpg = to_tpg(subdev);
        struct v4l2_mbus_framefmt *format;
 
-       format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+       format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
        *format = xtpg->default_format;
 
        if (xtpg->npads == 2) {
-               format = v4l2_subdev_get_try_format(subdev, fh->pad, 1);
+               format = v4l2_subdev_get_try_format(subdev, fh->state, 1);
                *format = xtpg->default_format;
        }
 
index 6ad61b0..425a32d 100644 (file)
@@ -70,8 +70,8 @@ EXPORT_SYMBOL_GPL(xvip_get_format_by_code);
  * @fourcc: the format 4CC
  *
  * Return: a pointer to the format information structure corresponding to the
- * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be
- * found.
+ * given V4L2 format @fourcc. If not found, return a pointer to the first
+ * available format (V4L2_PIX_FMT_YUYV).
  */
 const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
 {
@@ -84,7 +84,7 @@ const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
                        return format;
        }
 
-       return ERR_PTR(-EINVAL);
+       return &xvip_video_formats[0];
 }
 EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
 
@@ -234,7 +234,7 @@ EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
 /**
  * xvip_enum_mbus_code - Enumerate the media format code
  * @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
  * @code: returning media bus code
  *
  * Enumerate the media bus code of the subdevice. Return the corresponding
@@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
  * is not valid.
  */
 int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_mbus_code_enum *code)
 {
        struct v4l2_mbus_framefmt *format;
@@ -260,7 +260,7 @@ int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
        if (code->index)
                return -EINVAL;
 
-       format = v4l2_subdev_get_try_format(subdev, cfg, code->pad);
+       format = v4l2_subdev_get_try_format(subdev, sd_state, code->pad);
 
        code->code = format->code;
 
@@ -271,7 +271,7 @@ EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
 /**
  * xvip_enum_frame_size - Enumerate the media bus frame size
  * @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
  * @fse: returning media bus frame size
  *
  * This function is a drop-in implementation of the subdev enum_frame_size pad
@@ -284,7 +284,7 @@ EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
  * if the index or the code is not valid.
  */
 int xvip_enum_frame_size(struct v4l2_subdev *subdev,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_subdev_frame_size_enum *fse)
 {
        struct v4l2_mbus_framefmt *format;
@@ -295,7 +295,7 @@ int xvip_enum_frame_size(struct v4l2_subdev *subdev,
        if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return -EINVAL;
 
-       format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+       format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
 
        if (fse->index || fse->code != format->code)
                return -EINVAL;
index a528a32..d0b0e06 100644 (file)
@@ -125,10 +125,10 @@ const struct xvip_video_format *xvip_of_get_format(struct device_node *node);
 void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
                          const struct v4l2_subdev_format *fmt);
 int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_mbus_code_enum *code);
 int xvip_enum_frame_size(struct v4l2_subdev *subdev,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_subdev_frame_size_enum *fse);
 
 static inline u32 xvip_read(struct xvip_device *xvip, u32 addr)
index a7dfe5f..433f964 100644 (file)
@@ -110,7 +110,7 @@ static long radio_si4713_default(struct file *file, void *p,
                                          ioctl, cmd, arg);
 }
 
-static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
+static const struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
        .vidioc_querycap        = radio_si4713_querycap,
        .vidioc_g_modulator     = radio_si4713_g_modulator,
        .vidioc_s_modulator     = radio_si4713_s_modulator,
index f016b35..d0a8326 100644 (file)
@@ -19,7 +19,6 @@ source "drivers/media/rc/keymaps/Kconfig"
 
 config LIRC
        bool "LIRC user interface"
-       depends on RC_CORE
        help
           Enable this option to enable the Linux Infrared Remote
           Control user interface (e.g. /dev/lirc*). This interface
@@ -41,12 +40,10 @@ config BPF_LIRC_MODE2
 
 menuconfig RC_DECODERS
        bool "Remote controller decoders"
-       depends on RC_CORE
 
 if RC_DECODERS
 config IR_NEC_DECODER
        tristate "Enable IR raw decoder for the NEC protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -55,7 +52,6 @@ config IR_NEC_DECODER
 
 config IR_RC5_DECODER
        tristate "Enable IR raw decoder for the RC-5 protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -64,7 +60,6 @@ config IR_RC5_DECODER
 
 config IR_RC6_DECODER
        tristate "Enable IR raw decoder for the RC6 protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -73,7 +68,6 @@ config IR_RC6_DECODER
 
 config IR_JVC_DECODER
        tristate "Enable IR raw decoder for the JVC protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -82,7 +76,6 @@ config IR_JVC_DECODER
 
 config IR_SONY_DECODER
        tristate "Enable IR raw decoder for the Sony protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -91,7 +84,6 @@ config IR_SONY_DECODER
 
 config IR_SANYO_DECODER
        tristate "Enable IR raw decoder for the Sanyo protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -101,7 +93,6 @@ config IR_SANYO_DECODER
 
 config IR_SHARP_DECODER
        tristate "Enable IR raw decoder for the Sharp protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -111,7 +102,6 @@ config IR_SHARP_DECODER
 
 config IR_MCE_KBD_DECODER
        tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -121,7 +111,6 @@ config IR_MCE_KBD_DECODER
 
 config IR_XMP_DECODER
        tristate "Enable IR raw decoder for the XMP protocol"
-       depends on RC_CORE
        select BITREVERSE
 
        help
@@ -130,7 +119,6 @@ config IR_XMP_DECODER
 
 config IR_IMON_DECODER
        tristate "Enable IR raw decoder for the iMON protocol"
-       depends on RC_CORE
        help
           Enable this option if you have iMON PAD or Antec Veris infrared
           remote control and you would like to use it with a raw IR
@@ -138,7 +126,6 @@ config IR_IMON_DECODER
 
 config IR_RCMM_DECODER
        tristate "Enable IR raw decoder for the RC-MM protocol"
-       depends on RC_CORE
        help
           Enable this option when you have IR with RC-MM protocol, and
           you need the software decoder. The driver supports 12,
@@ -153,15 +140,12 @@ endif #RC_DECODERS
 
 menuconfig RC_DEVICES
        bool "Remote Controller devices"
-       depends on RC_CORE
 
 if RC_DEVICES
 
 config RC_ATI_REMOTE
        tristate "ATI / X10 based USB RF remote controls"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use an X10 based USB remote control.
           These are RF remotes with USB receivers.
@@ -179,7 +163,6 @@ config RC_ATI_REMOTE
 config IR_ENE
        tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
        depends on PNP || COMPILE_TEST
-       depends on RC_CORE
        help
           Say Y here to enable support for integrated infrared receiver
           /transceiver made by ENE.
@@ -192,7 +175,6 @@ config IR_ENE
 
 config IR_HIX5HD2
        tristate "Hisilicon hix5hd2 IR remote control"
-       depends on RC_CORE
        depends on OF || COMPILE_TEST
        help
           Say Y here if you want to use hisilicon hix5hd2 remote control.
@@ -203,9 +185,7 @@ config IR_HIX5HD2
 
 config IR_IMON
        tristate "SoundGraph iMON Receiver and Display"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
           IR Receiver and/or LCD/VFD/VGA display.
@@ -215,9 +195,7 @@ config IR_IMON
 
 config IR_IMON_RAW
        tristate "SoundGraph iMON Receiver (early raw IR models)"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use a SoundGraph iMON IR Receiver,
           early raw models.
@@ -227,9 +205,7 @@ config IR_IMON_RAW
 
 config IR_MCEUSB
        tristate "Windows Media Center Ed. eHome Infrared Transceiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use a Windows Media Center Edition
           eHome Infrared Transceiver.
@@ -240,7 +216,6 @@ config IR_MCEUSB
 config IR_ITE_CIR
        tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver"
        depends on PNP || COMPILE_TEST
-       depends on RC_CORE
        help
           Say Y here to enable support for integrated infrared receivers
           /transceivers made by ITE Tech Inc. These are found in
@@ -253,7 +228,6 @@ config IR_ITE_CIR
 config IR_FINTEK
        tristate "Fintek Consumer Infrared Transceiver"
        depends on PNP || COMPILE_TEST
-       depends on RC_CORE
        help
           Say Y here to enable support for integrated infrared receiver
           /transceiver made by Fintek. This chip is found on assorted
@@ -264,7 +238,6 @@ config IR_FINTEK
 
 config IR_MESON
        tristate "Amlogic Meson IR remote receiver"
-       depends on RC_CORE
        depends on ARCH_MESON || COMPILE_TEST
        help
           Say Y if you want to use the IR remote receiver available
@@ -275,7 +248,6 @@ config IR_MESON
 
 config IR_MTK
        tristate "Mediatek IR remote receiver"
-       depends on RC_CORE
        depends on ARCH_MEDIATEK || COMPILE_TEST
        help
           Say Y if you want to use the IR remote receiver available
@@ -287,7 +259,6 @@ config IR_MTK
 config IR_NUVOTON
        tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
        depends on PNP || COMPILE_TEST
-       depends on RC_CORE
        help
           Say Y here to enable support for integrated infrared receiver
           /transceiver made by Nuvoton (formerly Winbond). This chip is
@@ -299,11 +270,9 @@ config IR_NUVOTON
 
 config IR_REDRAT3
        tristate "RedRat3 IR Transceiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
+       depends on USB
        select NEW_LEDS
        select LEDS_CLASS
-       select USB
        help
           Say Y here if you want to use a RedRat3 Infrared Transceiver.
 
@@ -322,9 +291,7 @@ config IR_SPI
 
 config IR_STREAMZAP
        tristate "Streamzap PC Remote IR Receiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use a Streamzap PC Remote
           Infrared Receiver.
@@ -335,7 +302,6 @@ config IR_STREAMZAP
 config IR_WINBOND_CIR
        tristate "Winbond IR remote control"
        depends on (X86 && PNP) || COMPILE_TEST
-       depends on RC_CORE
        select NEW_LEDS
        select LEDS_CLASS
        select BITREVERSE
@@ -350,9 +316,7 @@ config IR_WINBOND_CIR
 
 config IR_IGORPLUGUSB
        tristate "IgorPlug-USB IR Receiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use the IgorPlug-USB IR Receiver by
           Igor Cesko. This device is included on the Fit-PC2.
@@ -365,9 +329,7 @@ config IR_IGORPLUGUSB
 
 config IR_IGUANA
        tristate "IguanaWorks USB IR Transceiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        help
           Say Y here if you want to use the IguanaWorks USB IR Transceiver.
           Both infrared receive and send are supported. If you want to
@@ -381,9 +343,7 @@ config IR_IGUANA
 
 config IR_TTUSBIR
        tristate "TechnoTrend USB IR Receiver"
-       depends on USB_ARCH_HAS_HCD
-       depends on RC_CORE
-       select USB
+       depends on USB
        select NEW_LEDS
        select LEDS_CLASS
        help
@@ -407,7 +367,6 @@ source "drivers/media/rc/img-ir/Kconfig"
 
 config RC_LOOPBACK
        tristate "Remote Control Loopback Driver"
-       depends on RC_CORE
        help
           Say Y here if you want support for the remote control loopback
           driver which allows TX data to be sent back as RX data.
@@ -420,7 +379,6 @@ config RC_LOOPBACK
 
 config IR_GPIO_CIR
        tristate "GPIO IR remote control"
-       depends on RC_CORE
        depends on (OF && GPIOLIB) || COMPILE_TEST
        help
           Say Y if you want to use GPIO based IR Receiver.
@@ -430,7 +388,6 @@ config IR_GPIO_CIR
 
 config IR_GPIO_TX
        tristate "GPIO IR Bit Banging Transmitter"
-       depends on RC_CORE
        depends on LIRC
        depends on (OF && GPIOLIB) || COMPILE_TEST
        help
@@ -442,7 +399,6 @@ config IR_GPIO_TX
 
 config IR_PWM_TX
        tristate "PWM IR transmitter"
-       depends on RC_CORE
        depends on LIRC
        depends on PWM
        depends on OF || COMPILE_TEST
@@ -455,7 +411,6 @@ config IR_PWM_TX
 
 config RC_ST
        tristate "ST remote control receiver"
-       depends on RC_CORE
        depends on ARCH_STI || COMPILE_TEST
        help
           Say Y here if you want support for ST remote control driver
@@ -466,7 +421,6 @@ config RC_ST
 
 config IR_SUNXI
        tristate "SUNXI IR remote control"
-       depends on RC_CORE
        depends on ARCH_SUNXI || COMPILE_TEST
        help
           Say Y if you want to use sunXi internal IR Controller
@@ -476,7 +430,6 @@ config IR_SUNXI
 
 config IR_SERIAL
        tristate "Homebrew Serial Port Receiver"
-       depends on RC_CORE
        help
           Say Y if you want to use Homebrew Serial Port Receivers and
           Transceivers.
@@ -492,28 +445,15 @@ config IR_SERIAL_TRANSMITTER
 
 config IR_SIR
        tristate "Built-in SIR IrDA port"
-       depends on RC_CORE
        help
           Say Y if you want to use a IrDA SIR port Transceivers.
 
           To compile this driver as a module, choose M here: the module will
           be called sir-ir.
 
-config IR_TANGO
-       tristate "Sigma Designs SMP86xx IR decoder"
-       depends on RC_CORE
-       depends on ARCH_TANGO || COMPILE_TEST
-       help
-          Adds support for the HW IR decoder embedded on Sigma Designs
-          Tango-based systems (SMP86xx, SMP87xx).
-          The HW decoder supports NEC, RC-5, RC-6 IR protocols.
-          When compiled as a module, look for tango-ir.
-
 config RC_XBOX_DVD
        tristate "Xbox DVD Movie Playback Kit"
-       depends on RC_CORE
-       depends on USB_ARCH_HAS_HCD
-       select USB
+       depends on USB
        help
           Say Y here if you want to use the Xbox DVD Movie Playback Kit.
           These are IR remotes with USB receivers for the Original Xbox (2001).
@@ -523,8 +463,7 @@ config RC_XBOX_DVD
 
 config IR_TOY
        tristate "Infrared Toy and IR Droid"
-       depends on RC_CORE
-       depends on USB_ARCH_HAS_HCD
+       depends on USB
        help
           Say Y here if you want to use the Infrared Toy or IR Droid, USB
           versions.
index f310022..692e9b6 100644 (file)
@@ -48,6 +48,5 @@ obj-$(CONFIG_IR_IMG) += img-ir/
 obj-$(CONFIG_IR_SERIAL) += serial_ir.o
 obj-$(CONFIG_IR_SIR) += sir_ir.o
 obj-$(CONFIG_IR_MTK) += mtk-cir.o
-obj-$(CONFIG_IR_TANGO) += tango-ir.o
 obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o
 obj-$(CONFIG_IR_TOY) += ir_toy.o
index a7962ca..2ca4e86 100644 (file)
@@ -780,7 +780,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
 /*
  * These are the sysfs functions to handle the association on the iMON 2.4G LT.
  */
-static ssize_t show_associate_remote(struct device *d,
+static ssize_t associate_remote_show(struct device *d,
                                     struct device_attribute *attr,
                                     char *buf)
 {
@@ -800,7 +800,7 @@ static ssize_t show_associate_remote(struct device *d,
        return strlen(buf);
 }
 
-static ssize_t store_associate_remote(struct device *d,
+static ssize_t associate_remote_store(struct device *d,
                                      struct device_attribute *attr,
                                      const char *buf, size_t count)
 {
@@ -822,7 +822,7 @@ static ssize_t store_associate_remote(struct device *d,
 /*
  * sysfs functions to control internal imon clock
  */
-static ssize_t show_imon_clock(struct device *d,
+static ssize_t imon_clock_show(struct device *d,
                               struct device_attribute *attr, char *buf)
 {
        struct imon_context *ictx = dev_get_drvdata(d);
@@ -848,7 +848,7 @@ static ssize_t show_imon_clock(struct device *d,
        return len;
 }
 
-static ssize_t store_imon_clock(struct device *d,
+static ssize_t imon_clock_store(struct device *d,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
@@ -895,11 +895,8 @@ exit:
 }
 
 
-static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
-                  store_imon_clock);
-
-static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
-                  store_associate_remote);
+static DEVICE_ATTR_RW(imon_clock);
+static DEVICE_ATTR_RW(associate_remote);
 
 static struct attribute *imon_display_sysfs_entries[] = {
        &dev_attr_imon_clock.attr,
index ce7a40b..4b4294d 100644 (file)
@@ -167,7 +167,7 @@ struct ite_dev {
  * hardware data obtained from:
  *
  * IT8712F
- * Environment Control  Low Pin Count Input / Output
+ * Environment Control - Low Pin Count Input / Output
  * (EC - LPC I/O)
  * Preliminary Specification V0. 81
  */
index 50b2833..5fe5c9e 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-budget-ci-old.o \
                        rc-cinergy-1400.o \
                        rc-cinergy.o \
+                       rc-ct-90405.o \
                        rc-d680-dmb.o \
                        rc-delock-61959.o \
                        rc-dib0700-nec.o \
@@ -100,7 +101,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-reddo.o \
                        rc-snapstream-firefly.o \
                        rc-streamzap.o \
-                       rc-tango.o \
                        rc-tanix-tx3mini.o \
                        rc-tanix-tx5max.o \
                        rc-tbs-nec.o \
diff --git a/drivers/media/rc/keymaps/rc-ct-90405.c b/drivers/media/rc/keymaps/rc-ct-90405.c
new file mode 100644 (file)
index 0000000..8914c83
--- /dev/null
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Toshiba CT-90405 remote controller keytable
+ *
+ * Copyright (C) 2021 Alexander Voronov <avv.0@ya.ru>
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table ct_90405[] = {
+       { 0x4014, KEY_SWITCHVIDEOMODE },
+       { 0x4012, KEY_POWER },
+       { 0x4044, KEY_TV },
+       { 0x40be43, KEY_3D_MODE },
+       { 0x400c, KEY_SUBTITLE },
+       { 0x4001, KEY_NUMERIC_1 },
+       { 0x4002, KEY_NUMERIC_2 },
+       { 0x4003, KEY_NUMERIC_3 },
+       { 0x4004, KEY_NUMERIC_4 },
+       { 0x4005, KEY_NUMERIC_5 },
+       { 0x4006, KEY_NUMERIC_6 },
+       { 0x4007, KEY_NUMERIC_7 },
+       { 0x4008, KEY_NUMERIC_8 },
+       { 0x4009, KEY_NUMERIC_9 },
+       { 0x4062, KEY_AUDIO_DESC },
+       { 0x4000, KEY_NUMERIC_0 },
+       { 0x401a, KEY_VOLUMEUP },
+       { 0x401e, KEY_VOLUMEDOWN },
+       { 0x4016, KEY_INFO },
+       { 0x4010, KEY_MUTE },
+       { 0x401b, KEY_CHANNELUP },
+       { 0x401f, KEY_CHANNELDOWN },
+       { 0x40da, KEY_VENDOR },
+       { 0x4066, KEY_PLAYER },
+       { 0x4017, KEY_TEXT },
+       { 0x4047, KEY_LIST },
+       { 0x4073, KEY_PAGEUP },
+       { 0x4045, KEY_PROGRAM },
+       { 0x4043, KEY_EXIT },
+       { 0x4074, KEY_PAGEDOWN },
+       { 0x4064, KEY_BACK },
+       { 0x405b, KEY_MENU },
+       { 0x4019, KEY_UP },
+       { 0x4040, KEY_RIGHT },
+       { 0x401d, KEY_DOWN },
+       { 0x4042, KEY_LEFT },
+       { 0x4021, KEY_OK },
+       { 0x4053, KEY_REWIND },
+       { 0x4067, KEY_PLAY },
+       { 0x400d, KEY_FASTFORWARD },
+       { 0x4054, KEY_PREVIOUS },
+       { 0x4068, KEY_STOP },
+       { 0x406a, KEY_PAUSE },
+       { 0x4015, KEY_NEXT },
+       { 0x4048, KEY_RED },
+       { 0x4049, KEY_GREEN },
+       { 0x404a, KEY_YELLOW },
+       { 0x404b, KEY_BLUE },
+       { 0x406f, KEY_RECORD }
+};
+
+static struct rc_map_list ct_90405_map = {
+       .map = {
+               .scan     = ct_90405,
+               .size     = ARRAY_SIZE(ct_90405),
+               .rc_proto = RC_PROTO_NEC,
+               .name     = RC_MAP_CT_90405,
+       }
+};
+
+static int __init init_rc_map_ct_90405(void)
+{
+       return rc_map_register(&ct_90405_map);
+}
+
+static void __exit exit_rc_map_ct_90405(void)
+{
+       rc_map_unregister(&ct_90405_map);
+}
+
+module_init(init_rc_map_ct_90405)
+module_exit(exit_rc_map_ct_90405)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Voronov <avv.0@ya.ru>");
diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c
deleted file mode 100644 (file)
index 2b9cef6..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2017 Sigma Designs
- */
-
-#include <linux/module.h>
-#include <media/rc-map.h>
-
-static struct rc_map_table tango_table[] = {
-       { 0x4cb4a, KEY_POWER },
-       { 0x4cb48, KEY_FILE },
-       { 0x4cb0f, KEY_SETUP },
-       { 0x4cb4d, KEY_SUSPEND },
-       { 0x4cb4e, KEY_VOLUMEUP },
-       { 0x4cb44, KEY_EJECTCD },
-       { 0x4cb13, KEY_TV },
-       { 0x4cb51, KEY_MUTE },
-       { 0x4cb52, KEY_VOLUMEDOWN },
-
-       { 0x4cb41, KEY_NUMERIC_1 },
-       { 0x4cb03, KEY_NUMERIC_2 },
-       { 0x4cb42, KEY_NUMERIC_3 },
-       { 0x4cb45, KEY_NUMERIC_4 },
-       { 0x4cb07, KEY_NUMERIC_5 },
-       { 0x4cb46, KEY_NUMERIC_6 },
-       { 0x4cb55, KEY_NUMERIC_7 },
-       { 0x4cb17, KEY_NUMERIC_8 },
-       { 0x4cb56, KEY_NUMERIC_9 },
-       { 0x4cb1b, KEY_NUMERIC_0 },
-       { 0x4cb59, KEY_DELETE },
-       { 0x4cb5a, KEY_CAPSLOCK },
-
-       { 0x4cb47, KEY_BACK },
-       { 0x4cb05, KEY_SWITCHVIDEOMODE },
-       { 0x4cb06, KEY_UP },
-       { 0x4cb43, KEY_LEFT },
-       { 0x4cb01, KEY_RIGHT },
-       { 0x4cb0a, KEY_DOWN },
-       { 0x4cb02, KEY_ENTER },
-       { 0x4cb4b, KEY_INFO },
-       { 0x4cb09, KEY_HOME },
-
-       { 0x4cb53, KEY_MENU },
-       { 0x4cb12, KEY_PREVIOUS },
-       { 0x4cb50, KEY_PLAY },
-       { 0x4cb11, KEY_NEXT },
-       { 0x4cb4f, KEY_TITLE },
-       { 0x4cb0e, KEY_REWIND },
-       { 0x4cb4c, KEY_STOP },
-       { 0x4cb0d, KEY_FORWARD },
-       { 0x4cb57, KEY_MEDIA_REPEAT },
-       { 0x4cb16, KEY_ANGLE },
-       { 0x4cb54, KEY_PAUSE },
-       { 0x4cb15, KEY_SLOW },
-       { 0x4cb5b, KEY_TIME },
-       { 0x4cb1a, KEY_AUDIO },
-       { 0x4cb58, KEY_SUBTITLE },
-       { 0x4cb19, KEY_ZOOM },
-
-       { 0x4cb5f, KEY_RED },
-       { 0x4cb1e, KEY_GREEN },
-       { 0x4cb5c, KEY_YELLOW },
-       { 0x4cb1d, KEY_BLUE },
-};
-
-static struct rc_map_list tango_map = {
-       .map = {
-               .scan = tango_table,
-               .size = ARRAY_SIZE(tango_table),
-               .rc_proto = RC_PROTO_NECX,
-               .name = RC_MAP_TANGO,
-       }
-};
-
-static int __init init_rc_map_tango(void)
-{
-       return rc_map_register(&tango_map);
-}
-
-static void __exit exit_rc_map_tango(void)
-{
-       rc_map_unregister(&tango_map);
-}
-
-module_init(init_rc_map_tango)
-module_exit(exit_rc_map_tango)
-
-MODULE_AUTHOR("Sigma Designs");
-MODULE_LICENSE("GPL");
index 3237fef..d79d1e3 100644 (file)
@@ -157,8 +157,9 @@ static irqreturn_t st_rc_rx_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void st_rc_hardware_init(struct st_rc_device *dev)
+static int st_rc_hardware_init(struct st_rc_device *dev)
 {
+       int ret;
        int baseclock, freqdiff;
        unsigned int rx_max_symbol_per = MAX_SYMB_TIME;
        unsigned int rx_sampling_freq_div;
@@ -166,7 +167,12 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
        /* Enable the IP */
        reset_control_deassert(dev->rstc);
 
-       clk_prepare_enable(dev->sys_clock);
+       ret = clk_prepare_enable(dev->sys_clock);
+       if (ret) {
+               dev_err(dev->dev, "Failed to prepare/enable system clock\n");
+               return ret;
+       }
+
        baseclock = clk_get_rate(dev->sys_clock);
 
        /* IRB input pins are inverted internally from high to low. */
@@ -184,6 +190,8 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
        }
 
        writel(rx_max_symbol_per, dev->rx_base + IRB_MAX_SYM_PERIOD);
+
+       return 0;
 }
 
 static int st_rc_remove(struct platform_device *pdev)
@@ -287,7 +295,9 @@ static int st_rc_probe(struct platform_device *pdev)
 
        rc_dev->dev = dev;
        platform_set_drvdata(pdev, rc_dev);
-       st_rc_hardware_init(rc_dev);
+       ret = st_rc_hardware_init(rc_dev);
+       if (ret)
+               goto err;
 
        rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
        /* rx sampling rate is 10Mhz */
@@ -359,6 +369,7 @@ static int st_rc_suspend(struct device *dev)
 
 static int st_rc_resume(struct device *dev)
 {
+       int ret;
        struct st_rc_device *rc_dev = dev_get_drvdata(dev);
        struct rc_dev   *rdev = rc_dev->rdev;
 
@@ -367,7 +378,10 @@ static int st_rc_resume(struct device *dev)
                rc_dev->irq_wake = 0;
        } else {
                pinctrl_pm_select_default_state(dev);
-               st_rc_hardware_init(rc_dev);
+               ret = st_rc_hardware_init(rc_dev);
+               if (ret)
+                       return ret;
+
                if (rdev->users) {
                        writel(IRB_RX_INTS, rc_dev->rx_base + IRB_RX_INT_EN);
                        writel(0x01, rc_dev->rx_base + IRB_RX_EN);
diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c
deleted file mode 100644 (file)
index b8eb5bc..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <media/rc-core.h>
-
-#define DRIVER_NAME "tango-ir"
-
-#define IR_NEC_CTRL    0x00
-#define IR_NEC_DATA    0x04
-#define IR_CTRL                0x08
-#define IR_RC5_CLK_DIV 0x0c
-#define IR_RC5_DATA    0x10
-#define IR_INT         0x14
-
-#define NEC_TIME_BASE  560
-#define RC5_TIME_BASE  1778
-
-#define RC6_CTRL       0x00
-#define RC6_CLKDIV     0x04
-#define RC6_DATA0      0x08
-#define RC6_DATA1      0x0c
-#define RC6_DATA2      0x10
-#define RC6_DATA3      0x14
-#define RC6_DATA4      0x18
-
-#define RC6_CARRIER    36000
-#define RC6_TIME_BASE  16
-
-#define NEC_CAP(n)     ((n) << 24)
-#define GPIO_SEL(n)    ((n) << 16)
-#define DISABLE_NEC    (BIT(4) | BIT(8))
-#define ENABLE_RC5     (BIT(0) | BIT(9))
-#define ENABLE_RC6     (BIT(0) | BIT(7))
-#define ACK_IR_INT     (BIT(0) | BIT(1))
-#define ACK_RC6_INT    (BIT(31))
-
-#define NEC_ANY (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32)
-
-struct tango_ir {
-       void __iomem *rc5_base;
-       void __iomem *rc6_base;
-       struct rc_dev *rc;
-       struct clk *clk;
-};
-
-static void tango_ir_handle_nec(struct tango_ir *ir)
-{
-       u32 v, code;
-       enum rc_proto proto;
-
-       v = readl_relaxed(ir->rc5_base + IR_NEC_DATA);
-       if (!v) {
-               rc_repeat(ir->rc);
-               return;
-       }
-
-       code = ir_nec_bytes_to_scancode(v, v >> 8, v >> 16, v >> 24, &proto);
-       rc_keydown(ir->rc, proto, code, 0);
-}
-
-static void tango_ir_handle_rc5(struct tango_ir *ir)
-{
-       u32 data, field, toggle, addr, cmd, code;
-
-       data = readl_relaxed(ir->rc5_base + IR_RC5_DATA);
-       if (data & BIT(31))
-               return;
-
-       field = data >> 12 & 1;
-       toggle = data >> 11 & 1;
-       addr = data >> 6 & 0x1f;
-       cmd = (data & 0x3f) | (field ^ 1) << 6;
-
-       code = RC_SCANCODE_RC5(addr, cmd);
-       rc_keydown(ir->rc, RC_PROTO_RC5, code, toggle);
-}
-
-static void tango_ir_handle_rc6(struct tango_ir *ir)
-{
-       u32 data0, data1, toggle, mode, addr, cmd, code;
-
-       data0 = readl_relaxed(ir->rc6_base + RC6_DATA0);
-       data1 = readl_relaxed(ir->rc6_base + RC6_DATA1);
-
-       mode = data0 >> 1 & 7;
-       if (mode != 0)
-               return;
-
-       toggle = data0 & 1;
-       addr = data0 >> 16;
-       cmd = data1;
-
-       code = RC_SCANCODE_RC6_0(addr, cmd);
-       rc_keydown(ir->rc, RC_PROTO_RC6_0, code, toggle);
-}
-
-static irqreturn_t tango_ir_irq(int irq, void *dev_id)
-{
-       struct tango_ir *ir = dev_id;
-       unsigned int rc5_stat;
-       unsigned int rc6_stat;
-
-       rc5_stat = readl_relaxed(ir->rc5_base + IR_INT);
-       writel_relaxed(rc5_stat, ir->rc5_base + IR_INT);
-
-       rc6_stat = readl_relaxed(ir->rc6_base + RC6_CTRL);
-       writel_relaxed(rc6_stat, ir->rc6_base + RC6_CTRL);
-
-       if (!(rc5_stat & 3) && !(rc6_stat & BIT(31)))
-               return IRQ_NONE;
-
-       if (rc5_stat & BIT(0))
-               tango_ir_handle_rc5(ir);
-
-       if (rc5_stat & BIT(1))
-               tango_ir_handle_nec(ir);
-
-       if (rc6_stat & BIT(31))
-               tango_ir_handle_rc6(ir);
-
-       return IRQ_HANDLED;
-}
-
-static int tango_change_protocol(struct rc_dev *dev, u64 *rc_type)
-{
-       struct tango_ir *ir = dev->priv;
-       u32 rc5_ctrl = DISABLE_NEC;
-       u32 rc6_ctrl = 0;
-
-       if (*rc_type & NEC_ANY)
-               rc5_ctrl = 0;
-
-       if (*rc_type & RC_PROTO_BIT_RC5)
-               rc5_ctrl |= ENABLE_RC5;
-
-       if (*rc_type & RC_PROTO_BIT_RC6_0)
-               rc6_ctrl = ENABLE_RC6;
-
-       writel_relaxed(rc5_ctrl, ir->rc5_base + IR_CTRL);
-       writel_relaxed(rc6_ctrl, ir->rc6_base + RC6_CTRL);
-
-       return 0;
-}
-
-static int tango_ir_probe(struct platform_device *pdev)
-{
-       const char *map_name = RC_MAP_TANGO;
-       struct device *dev = &pdev->dev;
-       struct rc_dev *rc;
-       struct tango_ir *ir;
-       u64 clkrate, clkdiv;
-       int irq, err;
-       u32 val;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq <= 0)
-               return -EINVAL;
-
-       ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL);
-       if (!ir)
-               return -ENOMEM;
-
-       ir->rc5_base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(ir->rc5_base))
-               return PTR_ERR(ir->rc5_base);
-
-       ir->rc6_base = devm_platform_ioremap_resource(pdev, 1);
-       if (IS_ERR(ir->rc6_base))
-               return PTR_ERR(ir->rc6_base);
-
-       ir->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(ir->clk))
-               return PTR_ERR(ir->clk);
-
-       rc = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
-       if (!rc)
-               return -ENOMEM;
-
-       of_property_read_string(dev->of_node, "linux,rc-map-name", &map_name);
-
-       rc->device_name = DRIVER_NAME;
-       rc->driver_name = DRIVER_NAME;
-       rc->input_phys = DRIVER_NAME "/input0";
-       rc->map_name = map_name;
-       rc->allowed_protocols = NEC_ANY | RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_0;
-       rc->change_protocol = tango_change_protocol;
-       rc->priv = ir;
-       ir->rc = rc;
-
-       err = clk_prepare_enable(ir->clk);
-       if (err)
-               return err;
-
-       clkrate = clk_get_rate(ir->clk);
-
-       clkdiv = clkrate * NEC_TIME_BASE;
-       do_div(clkdiv, 1000000);
-
-       val = NEC_CAP(31) | GPIO_SEL(12) | clkdiv;
-       writel_relaxed(val, ir->rc5_base + IR_NEC_CTRL);
-
-       clkdiv = clkrate * RC5_TIME_BASE;
-       do_div(clkdiv, 1000000);
-
-       writel_relaxed(DISABLE_NEC, ir->rc5_base + IR_CTRL);
-       writel_relaxed(clkdiv, ir->rc5_base + IR_RC5_CLK_DIV);
-       writel_relaxed(ACK_IR_INT, ir->rc5_base + IR_INT);
-
-       clkdiv = clkrate * RC6_TIME_BASE;
-       do_div(clkdiv, RC6_CARRIER);
-
-       writel_relaxed(ACK_RC6_INT, ir->rc6_base + RC6_CTRL);
-       writel_relaxed((clkdiv >> 2) << 18 | clkdiv, ir->rc6_base + RC6_CLKDIV);
-
-       err = devm_request_irq(dev, irq, tango_ir_irq, IRQF_SHARED,
-                              dev_name(dev), ir);
-       if (err)
-               goto err_clk;
-
-       err = devm_rc_register_device(dev, rc);
-       if (err)
-               goto err_clk;
-
-       platform_set_drvdata(pdev, ir);
-       return 0;
-
-err_clk:
-       clk_disable_unprepare(ir->clk);
-       return err;
-}
-
-static int tango_ir_remove(struct platform_device *pdev)
-{
-       struct tango_ir *ir = platform_get_drvdata(pdev);
-
-       clk_disable_unprepare(ir->clk);
-       return 0;
-}
-
-static const struct of_device_id tango_ir_dt_ids[] = {
-       { .compatible = "sigma,smp8642-ir" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, tango_ir_dt_ids);
-
-static struct platform_driver tango_ir_driver = {
-       .probe  = tango_ir_probe,
-       .remove = tango_ir_remove,
-       .driver = {
-               .name           = DRIVER_NAME,
-               .of_match_table = tango_ir_dt_ids,
-       },
-};
-module_platform_driver(tango_ir_driver);
-
-MODULE_DESCRIPTION("SMP86xx IR decoder driver");
-MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
-MODULE_LICENSE("GPL");
index 931ec07..e5094ff 100644 (file)
@@ -147,7 +147,7 @@ static int cxd2880_spi_read_ts(struct spi_device *spi,
 
        ret = spi_sync(spi, &message);
        if (ret)
-               pr_err("spi_write_then_read failed\n");
+               pr_err("spi_sync failed\n");
 
        return ret;
 }
@@ -401,7 +401,7 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed)
                                                              dvb_spi,
                                                              "cxd2880_ts_read");
                if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
-                       pr_err("kthread_run failed/\n");
+                       pr_err("kthread_run failed\n");
                        kfree(dvb_spi->ts_buf);
                        dvb_spi->ts_buf = NULL;
                        memset(&dvb_spi->filter_config, 0,
@@ -448,7 +448,7 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
                 * in dvb_spi->all_pid_feed_count.
                 */
                if (dvb_spi->all_pid_feed_count <= 0) {
-                       pr_err("PID %d not found.\n", feed->pid);
+                       pr_err("PID %d not found\n", feed->pid);
                        return -EINVAL;
                }
                dvb_spi->all_pid_feed_count--;
@@ -485,7 +485,7 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
 
                ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
                if (ret_stop) {
-                       pr_err("'kthread_stop failed. (%d)\n", ret_stop);
+                       pr_err("kthread_stop failed. (%d)\n", ret_stop);
                        ret = ret_stop;
                }
                kfree(dvb_spi->ts_buf);
@@ -512,7 +512,7 @@ cxd2880_spi_probe(struct spi_device *spi)
        struct cxd2880_config config;
 
        if (!spi) {
-               pr_err("invalid arg.\n");
+               pr_err("invalid arg\n");
                return -EINVAL;
        }
 
@@ -596,7 +596,7 @@ cxd2880_spi_probe(struct spi_device *spi)
        ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
                                                  &dvb_spi->dmx_fe);
        if (ret < 0) {
-               pr_err("dvb_register_frontend() failed\n");
+               pr_err("connect_frontend() failed\n");
                goto fail_fe_conn;
        }
 
index a246243..d714fe5 100644 (file)
@@ -624,11 +624,6 @@ static void device_work(struct work_struct *w)
 
        curr_ctx = container_of(w, struct vim2m_ctx, work_run.work);
 
-       if (!curr_ctx) {
-               pr_err("Instance released before the end of transaction\n");
-               return;
-       }
-
        vim2m_dev = curr_ctx->dev;
 
        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
index c3f6fef..2d06cdb 100644 (file)
@@ -150,17 +150,17 @@ static bool vimc_deb_src_code_is_valid(u32 code)
 }
 
 static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg)
+                            struct v4l2_subdev_state *sd_state)
 {
        struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *mf;
        unsigned int i;
 
-       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
        *mf = sink_fmt_default;
 
        for (i = 1; i < sd->entity.num_pads; i++) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, i);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, i);
                *mf = sink_fmt_default;
                mf->code = vdeb->src_code;
        }
@@ -169,7 +169,7 @@ static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        if (VIMC_IS_SRC(code->pad)) {
@@ -188,7 +188,7 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index)
@@ -213,14 +213,14 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int vimc_deb_get_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
 
        /* Get the current sink format */
        fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
-                     *v4l2_subdev_get_try_format(sd, cfg, 0) :
+                     *v4l2_subdev_get_try_format(sd, sd_state, 0) :
                      vdeb->sink_fmt;
 
        /* Set the right code for the source pad */
@@ -251,7 +251,7 @@ static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
 }
 
 static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
@@ -266,8 +266,8 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
                sink_fmt = &vdeb->sink_fmt;
                src_code = &vdeb->src_code;
        } else {
-               sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
-               src_code = &v4l2_subdev_get_try_format(sd, cfg, 1)->code;
+               sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+               src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code;
        }
 
        /*
index 121fa7d..06880dd 100644 (file)
@@ -84,20 +84,20 @@ static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
 }
 
 static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg)
+                            struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_mbus_framefmt *mf;
        struct v4l2_rect *r;
        unsigned int i;
 
-       mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+       mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
        *mf = sink_fmt_default;
 
-       r = v4l2_subdev_get_try_crop(sd, cfg, 0);
+       r = v4l2_subdev_get_try_crop(sd, sd_state, 0);
        *r = crop_rect_default;
 
        for (i = 1; i < sd->entity.num_pads; i++) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, i);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, i);
                *mf = sink_fmt_default;
                mf->width = mf->width * sca_mult;
                mf->height = mf->height * sca_mult;
@@ -107,7 +107,7 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        u32 mbus_code = vimc_mbus_code_by_index(code->index);
@@ -128,7 +128,7 @@ static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_frame_size_enum *fse)
 {
        const struct vimc_pix_map *vpix;
@@ -156,7 +156,7 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *format)
 {
        struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -164,8 +164,8 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
 
        /* Get the current sink format */
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
-               crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+               format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+               crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
        } else {
                format->format = vsca->sink_fmt;
                crop_rect = &vsca->crop_rect;
@@ -201,7 +201,7 @@ static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
 }
 
 static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -216,8 +216,8 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
                sink_fmt = &vsca->sink_fmt;
                crop_rect = &vsca->crop_rect;
        } else {
-               sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
-               crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+               sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+               crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
        }
 
        /*
@@ -254,7 +254,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int vimc_sca_get_selection(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_selection *sel)
 {
        struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -268,8 +268,8 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
                sink_fmt = &vsca->sink_fmt;
                crop_rect = &vsca->crop_rect;
        } else {
-               sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
-               crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+               sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+               crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
        }
 
        switch (sel->target) {
@@ -287,7 +287,7 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
 }
 
 static int vimc_sca_set_selection(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_selection *sel)
 {
        struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -305,8 +305,8 @@ static int vimc_sca_set_selection(struct v4l2_subdev *sd,
                crop_rect = &vsca->crop_rect;
                sink_fmt = &vsca->sink_fmt;
        } else {
-               crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
-               sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+               crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
+               sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
        }
 
        switch (sel->target) {
index ba5db5a..74ab79c 100644 (file)
@@ -42,14 +42,14 @@ static const struct v4l2_mbus_framefmt fmt_default = {
 };
 
 static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg)
+                            struct v4l2_subdev_state *sd_state)
 {
        unsigned int i;
 
        for (i = 0; i < sd->entity.num_pads; i++) {
                struct v4l2_mbus_framefmt *mf;
 
-               mf = v4l2_subdev_get_try_format(sd, cfg, i);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, i);
                *mf = fmt_default;
        }
 
@@ -57,7 +57,7 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
 }
 
 static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        u32 mbus_code = vimc_mbus_code_by_index(code->index);
@@ -71,7 +71,7 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_frame_size_enum *fse)
 {
        const struct vimc_pix_map *vpix;
@@ -93,14 +93,14 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vimc_sen_device *vsen =
                                container_of(sd, struct vimc_sen_device, sd);
 
        fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
-                     *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) :
+                     *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) :
                      vsen->mbus_format;
 
        return 0;
@@ -146,7 +146,7 @@ static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
 }
 
 static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
@@ -159,7 +159,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
 
                mf = &vsen->mbus_format;
        } else {
-               mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
        }
 
        /* Set the new format */
index ca0ebf6..d2bd265 100644 (file)
@@ -656,6 +656,46 @@ static const struct v4l2_file_operations vivid_radio_fops = {
        .unlocked_ioctl = video_ioctl2,
 };
 
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct video_device *vdev = video_devdata(file);
+       int r;
+
+       /*
+        * Sliced and raw VBI capture share the same queue so we must
+        * change the type.
+        */
+       if (p->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
+           p->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               r = vb2_queue_change_type(vdev->queue, p->type);
+               if (r)
+                       return r;
+       }
+
+       return vb2_ioctl_reqbufs(file, priv, p);
+}
+
+static int vidioc_create_bufs(struct file *file, void *priv,
+                             struct v4l2_create_buffers *p)
+{
+       struct video_device *vdev = video_devdata(file);
+       int r;
+
+       /*
+        * Sliced and raw VBI capture share the same queue so we must
+        * change the type.
+        */
+       if (p->format.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
+           p->format.type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               r = vb2_queue_change_type(vdev->queue, p->format.type);
+               if (r)
+                       return r;
+       }
+
+       return vb2_ioctl_create_bufs(file, priv, p);
+}
+
 static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
        .vidioc_querycap                = vidioc_querycap,
 
@@ -717,8 +757,8 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
        .vidioc_g_fbuf                  = vidioc_g_fbuf,
        .vidioc_s_fbuf                  = vidioc_s_fbuf,
 
-       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
-       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_reqbufs                 = vidioc_reqbufs,
+       .vidioc_create_bufs             = vidioc_create_bufs,
        .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
        .vidioc_querybuf                = vb2_ioctl_querybuf,
        .vidioc_qbuf                    = vb2_ioctl_qbuf,
index cdff6cd..1e3c4f5 100644 (file)
@@ -429,7 +429,6 @@ struct vivid_dev {
        u32                             vbi_cap_seq_start;
        u32                             vbi_cap_seq_count;
        bool                            vbi_cap_streaming;
-       bool                            stream_sliced_vbi_cap;
        u32                             meta_cap_seq_start;
        u32                             meta_cap_seq_count;
        bool                            meta_cap_streaming;
index c0dc609..9da730c 100644 (file)
@@ -752,7 +752,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
 
                v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req,
                                        &dev->ctrl_hdl_vbi_cap);
-               if (dev->stream_sliced_vbi_cap)
+               if (vbi_cap_buf->vb.vb2_buf.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
                        vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
                else
                        vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
index a1e5270..265db21 100644 (file)
@@ -455,7 +455,6 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
 
        f->fmt.sdr.pixelformat = dev->sdr_pixelformat;
        f->fmt.sdr.buffersize = dev->sdr_buffersize;
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        return 0;
 }
 
@@ -468,7 +467,6 @@ int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
        if (vb2_is_busy(q))
                return -EBUSY;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        dev->sdr_pixelformat = formats[i].pixelformat;
@@ -488,7 +486,6 @@ int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
        int i;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        f->fmt.sdr.buffersize = formats[i].buffersize;
index 1a9348e..b65b02e 100644 (file)
@@ -255,10 +255,8 @@ int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
 
        if (ret)
                return ret;
-       if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+       if (f->type != V4L2_BUF_TYPE_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))
                return -EBUSY;
-       dev->stream_sliced_vbi_cap = false;
-       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE;
        return 0;
 }
 
@@ -322,11 +320,9 @@ int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format
 
        if (ret)
                return ret;
-       if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))
                return -EBUSY;
        dev->service_set_cap = vbi->service_set;
-       dev->stream_sliced_vbi_cap = true;
-       dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
        return 0;
 }
 
index 00feadb..f97153d 100644 (file)
@@ -1,10 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-# This Kconfig option is also used by the legacy av7110 driver
-config TTPCI_EEPROM
-       tristate
-       depends on I2C
-
 if USB && MEDIA_SUPPORT
 
 menuconfig MEDIA_USB_SUPPORT
index 751703d..7a81be7 100644 (file)
@@ -632,7 +632,6 @@ static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
 
        f->fmt.sdr.pixelformat = s->pixelformat;
        f->fmt.sdr.buffersize = s->buffersize;
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 
        return 0;
 }
@@ -647,7 +646,6 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
        if (vb2_is_busy(q))
                return -EBUSY;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        s->pixelformat = formats[i].pixelformat;
@@ -670,7 +668,6 @@ static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
 {
        int i;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        f->fmt.sdr.buffersize = formats[i].buffersize;
index a8a72d5..caefac0 100644 (file)
@@ -199,8 +199,8 @@ static int au0828_media_device_init(struct au0828_dev *dev,
        struct media_device *mdev;
 
        mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
-       if (!mdev)
-               return -ENOMEM;
+       if (IS_ERR(mdev))
+               return PTR_ERR(mdev);
 
        dev->media_dev = mdev;
 #endif
index 50835f5..57b7f1e 100644 (file)
@@ -429,6 +429,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
 int cpia2_do_command(struct camera_data *cam,
                     unsigned int command,
                     unsigned char direction, unsigned char param);
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf);
 struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
 int cpia2_init_camera(struct camera_data *cam);
 int cpia2_allocate_buffers(struct camera_data *cam);
index e747548..b5a2d06 100644 (file)
@@ -2167,6 +2167,18 @@ static void reset_camera_struct(struct camera_data *cam)
  *
  *  cpia2_init_camera_struct
  *
+ *  Deinitialize camera struct
+ *****************************************************************************/
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf)
+{
+       v4l2_device_unregister(&cam->v4l2_dev);
+       kfree(cam);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera_struct
+ *
  *  Initializes camera struct, does not call reset to fill in defaults.
  *****************************************************************************/
 struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
index 3ab80a7..76aac06 100644 (file)
@@ -844,15 +844,13 @@ static int cpia2_usb_probe(struct usb_interface *intf,
        ret = set_alternate(cam, USBIF_CMDONLY);
        if (ret < 0) {
                ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
-               kfree(cam);
-               return ret;
+               goto alt_err;
        }
 
 
        if((ret = cpia2_init_camera(cam)) < 0) {
                ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
-               kfree(cam);
-               return ret;
+               goto alt_err;
        }
        LOG("  CPiA Version: %d.%02d (%d.%d)\n",
               cam->params.version.firmware_revision_hi,
@@ -872,11 +870,14 @@ static int cpia2_usb_probe(struct usb_interface *intf,
        ret = cpia2_register_camera(cam);
        if (ret < 0) {
                ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
-               kfree(cam);
-               return ret;
+               goto alt_err;
        }
 
        return 0;
+
+alt_err:
+       cpia2_deinit_camera_struct(cam, intf);
+       return ret;
 }
 
 /******************************************************************************
index 69d5c62..926ecfc 100644 (file)
@@ -140,10 +140,10 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
                              loff_t *off)
 {
        struct camera_data *cam = video_drvdata(file);
-       int noblock = file->f_flags&O_NONBLOCK;
+       int noblock = file->f_flags & O_NONBLOCK;
        ssize_t ret;
 
-       if(!cam)
+       if (!cam)
                return -EINVAL;
 
        if (mutex_lock_interruptible(&cam->v4l2_lock))
@@ -153,7 +153,6 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
        return ret;
 }
 
-
 /******************************************************************************
  *
  *  cpia2_v4l_poll
@@ -170,7 +169,6 @@ static __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait
        return res;
 }
 
-
 static int sync(struct camera_data *cam, int frame_nr)
 {
        struct framebuf *frame = &cam->buffers[frame_nr];
@@ -247,8 +245,8 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
                break;
        }
 
-       if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
-               memset(vc->bus_info,0, sizeof(vc->bus_info));
+       if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) < 0)
+               memset(vc->bus_info, 0, sizeof(vc->bus_info));
        return 0;
 }
 
@@ -289,7 +287,7 @@ static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
  *****************************************************************************/
 
 static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
-                                           struct v4l2_fmtdesc *f)
+                                 struct v4l2_fmtdesc *f)
 {
        if (f->index > 1)
                return -EINVAL;
@@ -310,13 +308,13 @@ static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
  *****************************************************************************/
 
 static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
-                                         struct v4l2_format *f)
+                                struct v4l2_format *f)
 {
        struct camera_data *cam = video_drvdata(file);
 
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
            f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
-              return -EINVAL;
+               return -EINVAL;
 
        f->fmt.pix.field = V4L2_FIELD_NONE;
        f->fmt.pix.bytesperline = 0;
@@ -371,19 +369,20 @@ static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
  *****************************************************************************/
 
 static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
-                                       struct v4l2_format *f)
+                              struct v4l2_format *f)
 {
        struct camera_data *cam = video_drvdata(file);
        int err, frame;
 
        err = cpia2_try_fmt_vid_cap(file, _fh, f);
-       if(err != 0)
+       if (err != 0)
                return err;
 
        cam->pixelformat = f->fmt.pix.pixelformat;
 
        /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
-        * the missing Huffman table properly. */
+        * the missing Huffman table properly.
+        */
        cam->params.compression.inhibit_htables = 0;
                /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
 
@@ -421,7 +420,7 @@ static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
  *****************************************************************************/
 
 static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
-                                       struct v4l2_format *f)
+                              struct v4l2_format *f)
 {
        struct camera_data *cam = video_drvdata(file);
 
@@ -547,9 +546,8 @@ static const struct {
 };
 
 static int cpia2_enum_framesizes(struct file *file, void *fh,
-                                        struct v4l2_frmsizeenum *fsize)
+                                struct v4l2_frmsizeenum *fsize)
 {
-
        if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
            fsize->pixel_format != V4L2_PIX_FMT_JPEG)
                return -EINVAL;
@@ -563,7 +561,7 @@ static int cpia2_enum_framesizes(struct file *file, void *fh,
 }
 
 static int cpia2_enum_frameintervals(struct file *file, void *fh,
-                                          struct v4l2_frmivalenum *fival)
+                                    struct v4l2_frmivalenum *fival)
 {
        struct camera_data *cam = video_drvdata(file);
        int max = ARRAY_SIZE(framerate_controls) - 1;
@@ -665,19 +663,18 @@ static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
        parms->quality = 80; // TODO: Can this be made meaningful?
 
        parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
-       if(!cam->params.compression.inhibit_htables) {
+       if (!cam->params.compression.inhibit_htables)
                parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
-       }
 
        parms->APPn = cam->APPn;
        parms->APP_len = cam->APP_len;
-       if(cam->APP_len > 0) {
+       if (cam->APP_len > 0) {
                memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
                parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
        }
 
        parms->COM_len = cam->COM_len;
-       if(cam->COM_len > 0) {
+       if (cam->COM_len > 0) {
                memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
                parms->jpeg_markers |= JPEG_MARKER_COM;
        }
@@ -698,7 +695,7 @@ static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
  *****************************************************************************/
 
 static int cpia2_s_jpegcomp(struct file *file, void *fh,
-               const struct v4l2_jpegcompression *parms)
+                           const struct v4l2_jpegcompression *parms)
 {
        struct camera_data *cam = video_drvdata(file);
 
@@ -708,9 +705,9 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh,
        cam->params.compression.inhibit_htables =
                !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
 
-       if(parms->APP_len != 0) {
-               if(parms->APP_len > 0 &&
-                  parms->APP_len <= sizeof(cam->APP_data) &&
+       if (parms->APP_len != 0) {
+               if (parms->APP_len > 0 &&
+                   parms->APP_len <= sizeof(cam->APP_data) &&
                   parms->APPn >= 0 && parms->APPn <= 15) {
                        cam->APPn = parms->APPn;
                        cam->APP_len = parms->APP_len;
@@ -724,9 +721,9 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh,
                cam->APP_len = 0;
        }
 
-       if(parms->COM_len != 0) {
-               if(parms->COM_len > 0 &&
-                  parms->COM_len <= sizeof(cam->COM_data)) {
+       if (parms->COM_len != 0) {
+               if (parms->COM_len > 0 &&
+                   parms->COM_len <= sizeof(cam->COM_data)) {
                        cam->COM_len = parms->COM_len;
                        memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
                } else {
@@ -751,8 +748,8 @@ static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers
 {
        struct camera_data *cam = video_drvdata(file);
 
-       if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-          req->memory != V4L2_MEMORY_MMAP)
+       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           req->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
        DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
@@ -774,8 +771,8 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
        struct camera_data *cam = video_drvdata(file);
 
-       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-          buf->index >= cam->num_frames)
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           buf->index >= cam->num_frames)
                return -EINVAL;
 
        buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
@@ -783,7 +780,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 
        buf->memory = V4L2_MEMORY_MMAP;
 
-       if(cam->mmapped)
+       if (cam->mmapped)
                buf->flags = V4L2_BUF_FLAG_MAPPED;
        else
                buf->flags = 0;
@@ -806,8 +803,8 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        }
 
        DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
-            buf->index, buf->m.offset, buf->flags, buf->sequence,
-            buf->bytesused);
+           buf->index, buf->m.offset, buf->flags, buf->sequence,
+           buf->bytesused);
 
        return 0;
 }
@@ -824,14 +821,14 @@ static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
        struct camera_data *cam = video_drvdata(file);
 
-       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-          buf->memory != V4L2_MEMORY_MMAP ||
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           buf->memory != V4L2_MEMORY_MMAP ||
           buf->index >= cam->num_frames)
                return -EINVAL;
 
        DBG("QBUF #%d\n", buf->index);
 
-       if(cam->buffers[buf->index].status == FRAME_READY)
+       if (cam->buffers[buf->index].status == FRAME_READY)
                cam->buffers[buf->index].status = FRAME_EMPTY;
 
        return 0;
@@ -849,9 +846,10 @@ static int find_earliest_filled_buffer(struct camera_data *cam)
 {
        int i;
        int found = -1;
-       for (i=0; i<cam->num_frames; i++) {
-               if(cam->buffers[i].status == FRAME_READY) {
-                       if(found < 0) {
+
+       for (i = 0; i < cam->num_frames; i++) {
+               if (cam->buffers[i].status == FRAME_READY) {
+                       if (found < 0) {
                                found = i;
                        } else {
                                /* find which buffer is earlier */
@@ -876,22 +874,23 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        struct camera_data *cam = video_drvdata(file);
        int frame;
 
-       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-          buf->memory != V4L2_MEMORY_MMAP)
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
        frame = find_earliest_filled_buffer(cam);
 
-       if(frame < 0 && file->f_flags&O_NONBLOCK)
+       if (frame < 0 && file->f_flags & O_NONBLOCK)
                return -EAGAIN;
 
-       if(frame < 0) {
+       if (frame < 0) {
                /* Wait for a frame to become available */
-               struct framebuf *cb=cam->curbuff;
+               struct framebuf *cb = cam->curbuff;
+
                mutex_unlock(&cam->v4l2_lock);
                wait_event_interruptible(cam->wq_stream,
                                         !video_is_registered(&cam->vdev) ||
-                                        (cb=cam->curbuff)->status == FRAME_READY);
+                                        (cb = cam->curbuff)->status == FRAME_READY);
                mutex_lock(&cam->v4l2_lock);
                if (signal_pending(current))
                        return -ERESTARTSYS;
@@ -900,7 +899,6 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
                frame = cb->num;
        }
 
-
        buf->index = frame;
        buf->bytesused = cam->buffers[buf->index].length;
        buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE
@@ -931,7 +929,7 @@ static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 
        if (!cam->streaming) {
                ret = cpia2_usb_stream_start(cam,
-                               cam->params.camera_state.stream_mode);
+                                            cam->params.camera_state.stream_mode);
                if (!ret)
                        v4l2_ctrl_grab(cam->usb_alt, true);
        }
@@ -969,7 +967,7 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
                return -ERESTARTSYS;
        retval = cpia2_remap_buffer(cam, area);
 
-       if(!retval)
+       if (!retval)
                cam->stream_fh = file->private_data;
        mutex_unlock(&cam->v4l2_lock);
        return retval;
@@ -1080,39 +1078,42 @@ int cpia2_register_camera(struct camera_data *cam)
 
        v4l2_ctrl_handler_init(hdl, 12);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_BRIGHTNESS,
-                       cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
-                       255, 1, DEFAULT_BRIGHTNESS);
+                         V4L2_CID_BRIGHTNESS,
+                         cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+                         255, 1, DEFAULT_BRIGHTNESS);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+                         V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+                         V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_JPEG_ACTIVE_MARKER, 0,
-                       V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
-                       V4L2_JPEG_ACTIVE_MARKER_DHT);
+                         V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+                         V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+                         V4L2_JPEG_ACTIVE_MARKER_DHT);
        v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
-                       100, 1, 100);
+                         V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+                         100, 1, 100);
        cpia2_usb_alt.def = alternate;
        cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
        /* VP5 Only */
        if (cam->params.pnp_id.device_type != DEVICE_STV_672)
                v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+                                 V4L2_CID_VFLIP, 0, 1, 1, 0);
        /* Flicker control only valid for 672 */
        if (cam->params.pnp_id.device_type == DEVICE_STV_672)
                v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
-                       V4L2_CID_POWER_LINE_FREQUENCY,
-                       V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+                                      V4L2_CID_POWER_LINE_FREQUENCY,
+                                      V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+                                      0, 0);
        /* Light control only valid for the QX5 Microscope */
        if (cam->params.pnp_id.product == 0x151) {
                cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                               V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+                                                  V4L2_CID_ILLUMINATORS_1,
+                                                  0, 1, 1, 0);
                cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
-                               V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+                                                     V4L2_CID_ILLUMINATORS_2,
+                                                     0, 1, 1, 0);
                v4l2_ctrl_cluster(2, &cam->top_light);
        }
 
@@ -1159,28 +1160,28 @@ void cpia2_unregister_camera(struct camera_data *cam)
  *****************************************************************************/
 static void __init check_parameters(void)
 {
-       if(buffer_size < PAGE_SIZE) {
+       if (buffer_size < PAGE_SIZE) {
                buffer_size = PAGE_SIZE;
                LOG("buffer_size too small, setting to %d\n", buffer_size);
-       } else if(buffer_size > 1024*1024) {
+       } else if (buffer_size > 1024 * 1024) {
                /* arbitrary upper limiit */
-               buffer_size = 1024*1024;
+               buffer_size = 1024 * 1024;
                LOG("buffer_size ridiculously large, setting to %d\n",
                    buffer_size);
        } else {
-               buffer_size += PAGE_SIZE-1;
-               buffer_size &= ~(PAGE_SIZE-1);
+               buffer_size += PAGE_SIZE - 1;
+               buffer_size &= ~(PAGE_SIZE - 1);
        }
 
-       if(num_buffers < 1) {
+       if (num_buffers < 1) {
                num_buffers = 1;
                LOG("num_buffers too small, setting to %d\n", num_buffers);
-       } else if(num_buffers > VIDEO_MAX_FRAME) {
+       } else if (num_buffers > VIDEO_MAX_FRAME) {
                num_buffers = VIDEO_MAX_FRAME;
                LOG("num_buffers too large, setting to %d\n", num_buffers);
        }
 
-       if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+       if (alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
                alternate = DEFAULT_ALT;
                LOG("alternate specified is invalid, using %d\n", alternate);
        }
@@ -1197,7 +1198,6 @@ static void __init check_parameters(void)
 
 /************   Module Stuff ***************/
 
-
 /******************************************************************************
  *
  * cpia2_init/module_init
@@ -1211,7 +1211,6 @@ static int __init cpia2_init(void)
        return cpia2_usb_init();
 }
 
-
 /******************************************************************************
  *
  * cpia2_exit/module_exit
index 1b6d4e4..fe4d886 100644 (file)
@@ -1122,11 +1122,6 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
        return ret;
 }
 
-static int lme2510_get_adapter_count(struct dvb_usb_device *d)
-{
-       return 1;
-}
-
 static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 {
        struct lme2510_state *st = d->priv;
@@ -1211,12 +1206,12 @@ static struct dvb_usb_device_properties lme2510_props = {
        .frontend_attach  = dm04_lme2510_frontend_attach,
        .tuner_attach = dm04_lme2510_tuner,
        .get_stream_config = lme2510_get_stream_config,
-       .get_adapter_count = lme2510_get_adapter_count,
        .streaming_ctrl   = lme2510_streaming_ctrl,
 
        .get_rc_config = lme2510_get_rc_config,
 
        .exit = lme2510_exit,
+       .num_adapters = 1,
        .adapter = {
                {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER|
@@ -1227,8 +1222,6 @@ static struct dvb_usb_device_properties lme2510_props = {
                        .stream =
                        DVB_USB_STREAM_BULK(0x86, 10, 4096),
                },
-               {
-               }
        },
 };
 
index 97ed17a..8370573 100644 (file)
@@ -612,8 +612,9 @@ static int rtl28xxu_read_config(struct dvb_usb_device *d)
 static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
 {
        struct rtl28xxu_dev *dev = d_to_priv(d);
+       u8 buf[1];
        int ret;
-       struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};
+       struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 1, buf};
 
        dev_dbg(&d->intf->dev, "\n");
 
@@ -1776,7 +1777,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
                ir_raw_event_store_with_filter(d->rc_dev, &ev);
        }
 
-       /* 'flush' ir_raw_event_store_with_filter() */
+       /* 'flush' ir_raw_event_store_with_filter() */
        ir_raw_event_handle(d->rc_dev);
 exit:
        return ret;
index 28e4806..c225149 100644 (file)
@@ -83,4 +83,4 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
 # due to tuner-xc3028
 ccflags-y += -I$(srctree)/drivers/media/tuners
-ccflags-y += -I$(srctree)/drivers/media/pci/ttpci
+ccflags-y += -I$(srctree)/drivers/media/common
index 969a7ec..23f1093 100644 (file)
@@ -29,10 +29,8 @@ struct cinergyt2_state {
        unsigned char data[64];
 };
 
-/* We are missing a release hook with usb_device data */
-static struct dvb_usb_device *cinergyt2_usb_device;
-
-static struct dvb_usb_device_properties cinergyt2_properties;
+/* Forward declaration */
+static const struct dvb_usb_device_properties cinergyt2_properties;
 
 static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
 {
@@ -78,13 +76,12 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
 
        ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 3, 0);
        if (ret < 0) {
+               if (adap->fe_adap[0].fe)
+                       adap->fe_adap[0].fe->ops.release(adap->fe_adap[0].fe);
                deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep state info\n");
        }
        mutex_unlock(&d->data_mutex);
 
-       /* Copy this pointer as we are gonna need it in the release phase */
-       cinergyt2_usb_device = adap->dev;
-
        return ret;
 }
 
@@ -203,7 +200,7 @@ static struct usb_device_id cinergyt2_usb_table[] = {
 
 MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
 
-static struct dvb_usb_device_properties cinergyt2_properties = {
+static const struct dvb_usb_device_properties cinergyt2_properties = {
        .size_of_priv = sizeof(struct cinergyt2_state),
        .num_adapters = 1,
        .adapter = {
index 761992a..7707de7 100644 (file)
@@ -1947,7 +1947,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
 
        .size_of_priv     = sizeof(struct cxusb_state),
 
-       .num_adapters = 2,
+       .num_adapters = 1,
        .adapter = {
                {
                .num_frontends = 1,
index fba0693..1c13e49 100644 (file)
@@ -26,6 +26,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
                           u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
        struct dtv5100_state *st = d->priv;
+       unsigned int pipe;
        u8 request;
        u8 type;
        u16 value;
@@ -34,6 +35,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
        switch (wlen) {
        case 1:
                /* write { reg }, read { value } */
+               pipe = usb_rcvctrlpipe(d->udev, 0);
                request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
                                                        DTV5100_TUNER_READ);
                type = USB_TYPE_VENDOR | USB_DIR_IN;
@@ -41,6 +43,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
                break;
        case 2:
                /* write { reg, value } */
+               pipe = usb_sndctrlpipe(d->udev, 0);
                request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
                                                        DTV5100_TUNER_WRITE);
                type = USB_TYPE_VENDOR | USB_DIR_OUT;
@@ -54,7 +57,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
 
        memcpy(st->data, rbuf, rlen);
        msleep(1); /* avoid I2C errors */
-       return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+       return usb_control_msg(d->udev, pipe, request,
                               type, value, index, st->data, rlen,
                               DTV5100_USB_TIMEOUT);
 }
@@ -141,7 +144,7 @@ static int dtv5100_probe(struct usb_interface *intf,
 
        /* initialize non qt1010/zl10353 part? */
        for (i = 0; dtv5100_init[i].request; i++) {
-               ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+               ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                      dtv5100_init[i].request,
                                      USB_TYPE_VENDOR | USB_DIR_OUT,
                                      dtv5100_init[i].value,
index ba9292e..c1e0dcc 100644 (file)
@@ -4065,15 +4065,15 @@ static int em28xx_usb_probe(struct usb_interface *intf,
                dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
                dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
 
-               /* Configuare hardware to support TS2*/
+               /* Configure hardware to support TS2*/
                if (dev->dvb_xfer_bulk) {
-                       /* The ep4 and ep5 are configuared for BULK */
+                       /* The ep4 and ep5 are configured for BULK */
                        em28xx_write_reg(dev, 0x0b, 0x96);
                        mdelay(100);
                        em28xx_write_reg(dev, 0x0b, 0x80);
                        mdelay(100);
                } else {
-                       /* The ep4 and ep5 are configuared for ISO */
+                       /* The ep4 and ep5 are configured for ISO */
                        em28xx_write_reg(dev, 0x0b, 0x96);
                        mdelay(100);
                        em28xx_write_reg(dev, 0x0b, 0x82);
index 5aa15a7..59529cb 100644 (file)
@@ -720,7 +720,8 @@ static int em28xx_ir_init(struct em28xx *dev)
                        dev->board.has_ir_i2c = 0;
                        dev_warn(&dev->intf->dev,
                                 "No i2c IR remote control device found.\n");
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto ref_put;
                }
        }
 
@@ -735,7 +736,7 @@ static int em28xx_ir_init(struct em28xx *dev)
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
        if (!ir)
-               return -ENOMEM;
+               goto ref_put;
        rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!rc)
                goto error;
@@ -839,6 +840,9 @@ error:
        dev->ir = NULL;
        rc_free_device(rc);
        kfree(ir);
+ref_put:
+       em28xx_shutdown_buttons(dev);
+       kref_put(&dev->ref, em28xx_free_device);
        return err;
 }
 
index b9e4512..c742cc8 100644 (file)
@@ -398,7 +398,7 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl)
 }
 
 static int s2250_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
index d93d384..46ed954 100644 (file)
@@ -365,8 +365,9 @@ struct sd {
 static const struct v4l2_pix_format mode[] = {
        {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
                /* The sizeimage is trial and error, as with low framerates
-                  the camera will pad out usb frames, making the image
-                  data larger then strictly necessary */
+                *  the camera will pad out usb frames, making the image
+                *  data larger than strictly necessary
+                */
                .bytesperline = 160,
                .sizeimage = 65536,
                .colorspace = V4L2_COLORSPACE_SRGB,
index 2c05ea2..ce4ee8b 100644 (file)
@@ -561,8 +561,8 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
                                        len, 400 + 200 * (len > 1));
                        memcpy(pdata, gspca_dev->usb_buf, len);
                } else {
-                       r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                                       req, pref, val, index, NULL, len, 400);
+                       gspca_err(gspca_dev, "zero-length read request\n");
+                       r = -EINVAL;
                }
        }
 
index cd6776c..bffa94e 100644 (file)
@@ -614,7 +614,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
        /*
         * From the datasheet: "Note that after writing to register COMH
         * (0x12) to change the sensor mode, registers related to the
-        * sensors cropping window will be reset back to their default
+        * sensor's cropping window will be reset back to their default
         * values."
         *
         * "wait 4096 external clock ... to make sure the sensor is
index 9491110..32504eb 100644 (file)
@@ -116,7 +116,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
        }
 
        ret = usb_control_msg(gspca_dev->dev,
-                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             usb_rcvctrlpipe(gspca_dev->dev, 0),
                              USB_REQ_SYNCH_FRAME,                /* request */
                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              SQ905_PING, 0, gspca_dev->usb_buf, 1,
index ace3da4..971dee0 100644 (file)
@@ -242,6 +242,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
                gspca_err(gspca_dev, "reg_r: buffer overflow\n");
                return;
        }
+       if (len == 0) {
+               gspca_err(gspca_dev, "reg_r: zero-length read\n");
+               return;
+       }
        if (gspca_dev->usb_err < 0)
                return;
        ret = usb_control_msg(gspca_dev->dev,
@@ -250,7 +254,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0,              /* value */
                        index,
-                       len ? gspca_dev->usb_buf : NULL, len,
+                       gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
                pr_err("reg_r err %d\n", ret);
@@ -727,7 +731,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                case MegaImageVI:
                        reg_w_riv(gspca_dev, 0xf0, 0, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
-                       reg_r(gspca_dev, 0xf0, 4, 0);
+                       reg_w_riv(gspca_dev, 0xf0, 4, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
                        break;
                default:
index cec841a..3e535be 100644 (file)
@@ -929,7 +929,6 @@ static int hackrf_s_fmt_sdr(struct file *file, void *priv,
        if (vb2_is_busy(q))
                return -EBUSY;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
                        dev->pixelformat = formats[i].pixelformat;
@@ -955,7 +954,6 @@ static int hackrf_g_fmt_sdr(struct file *file, void *priv,
        dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&dev->pixelformat);
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        f->fmt.sdr.pixelformat = dev->pixelformat;
        f->fmt.sdr.buffersize = dev->buffersize;
 
@@ -971,7 +969,6 @@ static int hackrf_try_fmt_sdr(struct file *file, void *priv,
        dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
                        (char *)&f->fmt.sdr.pixelformat);
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < NUM_FORMATS; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        f->fmt.sdr.buffersize = formats[i].buffersize;
index 63882a5..71de6b4 100644 (file)
@@ -912,7 +912,6 @@ static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv,
 
        f->fmt.sdr.pixelformat = dev->pixelformat;
        f->fmt.sdr.buffersize = dev->buffersize;
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 
        return 0;
 }
@@ -930,7 +929,6 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv,
        if (vb2_is_busy(q))
                return -EBUSY;
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < dev->num_formats; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        dev->pixelformat = formats[i].pixelformat;
@@ -957,7 +955,6 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv,
        dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
                (char *)&f->fmt.sdr.pixelformat);
 
-       memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
        for (i = 0; i < dev->num_formats; i++) {
                if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
                        f->fmt.sdr.buffersize = formats[i].buffersize;
index f4a7279..d38dee1 100644 (file)
@@ -2676,9 +2676,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                pvr2_stream_destroy(hdw->vid_stream);
                hdw->vid_stream = NULL;
        }
-       pvr2_i2c_core_done(hdw);
        v4l2_device_unregister(&hdw->v4l2_dev);
-       pvr2_hdw_remove_usb_stuff(hdw);
+       pvr2_hdw_disconnect(hdw);
        mutex_lock(&pvr2_unit_mtx);
        do {
                if ((hdw->unit_number >= 0) &&
@@ -2705,6 +2704,7 @@ void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
 {
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
        LOCK_TAKE(hdw->big_lock);
+       pvr2_i2c_core_done(hdw);
        LOCK_TAKE(hdw->ctl_lock);
        pvr2_hdw_remove_usb_stuff(hdw);
        LOCK_GIVE(hdw->ctl_lock);
index 4af55e2..3b0e4ed 100644 (file)
@@ -767,8 +767,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        if (fmt == NULL)
                return -EINVAL;
 
-       field = f->fmt.pix.field;
-
        dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
                __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
        if (is_ntsc) {
index a852ee5..bfda46a 100644 (file)
@@ -324,10 +324,10 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (!b)
                return -ENOMEM;
 
-       if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
-               kfree(b);
+       result = mutex_lock_interruptible(&dec->usb_mutex);
+       if (result) {
                printk("%s: Failed to lock usb mutex.\n", __func__);
-               return result;
+               goto err;
        }
 
        b[0] = 0xaa;
@@ -349,9 +349,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (result) {
                printk("%s: command bulk message failed: error %d\n",
                       __func__, result);
-               mutex_unlock(&dec->usb_mutex);
-               kfree(b);
-               return result;
+               goto err;
        }
 
        result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
@@ -360,9 +358,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (result) {
                printk("%s: result bulk message failed: error %d\n",
                       __func__, result);
-               mutex_unlock(&dec->usb_mutex);
-               kfree(b);
-               return result;
+               goto err;
        } else {
                if (debug) {
                        printk(KERN_DEBUG "%s: result: %*ph\n",
@@ -373,12 +369,13 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
                        *result_length = b[3];
                if (cmd_result && b[3] > 0)
                        memcpy(cmd_result, &b[4], b[3]);
+       }
 
-               mutex_unlock(&dec->usb_mutex);
+err:
+       mutex_unlock(&dec->usb_mutex);
 
-               kfree(b);
-               return 0;
-       }
+       kfree(b);
+       return result;
 }
 
 static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
index a777b38..e164646 100644 (file)
@@ -127,10 +127,37 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
 static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
        struct uvc_streaming_control *ctrl)
 {
+       static const struct usb_device_id elgato_cam_link_4k = {
+               USB_DEVICE(0x0fd9, 0x0066)
+       };
        struct uvc_format *format = NULL;
        struct uvc_frame *frame = NULL;
        unsigned int i;
 
+       /*
+        * The response of the Elgato Cam Link 4K is incorrect: The second byte
+        * contains bFormatIndex (instead of being the second byte of bmHint).
+        * The first byte is always zero. The third byte is always 1.
+        *
+        * The UVC 1.5 class specification defines the first five bits in the
+        * bmHint bitfield. The remaining bits are reserved and should be zero.
+        * Therefore a valid bmHint will be less than 32.
+        *
+        * Latest Elgato Cam Link 4K firmware as of 2021-03-23 needs this fix.
+        * MCU: 20.02.19, FPGA: 67
+        */
+       if (usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k) &&
+           ctrl->bmHint > 255) {
+               u8 corrected_format_index = ctrl->bmHint >> 8;
+
+               uvc_dbg(stream->dev, VIDEO,
+                       "Correct USB video probe response from {bmHint: 0x%04x, bFormatIndex: %u} to {bmHint: 0x%04x, bFormatIndex: %u}\n",
+                       ctrl->bmHint, ctrl->bFormatIndex,
+                       1, corrected_format_index);
+               ctrl->bmHint = 1;
+               ctrl->bFormatIndex = corrected_format_index;
+       }
+
        for (i = 0; i < stream->nformats; ++i) {
                if (stream->format[i].index == ctrl->bFormatIndex) {
                        format = &stream->format[i];
index 1ef611e..538a330 100644 (file)
@@ -1032,6 +1032,7 @@ static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
        DBG("submitting URB %p\n", pipe_info->stream_urb);
        retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
        if (retval) {
+               usb_free_urb(pipe_info->stream_urb);
                printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
                return retval;
        }
index bf49f83..02dc178 100644 (file)
@@ -62,6 +62,7 @@ config V4L2_FLASH_LED_CLASS
        tristate "V4L2 flash API for LED flash class devices"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        depends on LEDS_CLASS_FLASH
+       select V4L2_ASYNC
        help
          Say Y here to enable V4L2 flash API support for LED flash
          class drivers.
@@ -70,6 +71,10 @@ config V4L2_FLASH_LED_CLASS
 
 config V4L2_FWNODE
        tristate
+       select V4L2_ASYNC
+
+config V4L2_ASYNC
+       tristate
 
 # Used by drivers that need Videobuf modules
 config VIDEOBUF_GEN
index e4cd589..66a78c5 100644 (file)
@@ -6,16 +6,18 @@
 tuner-objs     :=      tuner-core.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
-                       v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \
-                       v4l2-async.o v4l2-common.o
+                       v4l2-event.o v4l2-subdev.o v4l2-common.o \
+                       v4l2-ctrls-core.o v4l2-ctrls-api.o \
+                       v4l2-ctrls-request.o v4l2-ctrls-defs.o
 videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o
 videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o
 videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
 videodev-$(CONFIG_SPI) += v4l2-spi.o
 videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
 
-obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
 obj-$(CONFIG_VIDEO_V4L2) += videodev.o
+obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
+obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
 obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
index e638aa8..cd9e78c 100644 (file)
@@ -854,8 +854,27 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(pending_subdevs);
 
-void v4l2_async_debug_init(struct dentry *debugfs_dir)
+static struct dentry *v4l2_async_debugfs_dir;
+
+static int __init v4l2_async_init(void)
 {
-       debugfs_create_file("pending_async_subdevices", 0444, debugfs_dir, NULL,
+       v4l2_async_debugfs_dir = debugfs_create_dir("v4l2-async", NULL);
+       debugfs_create_file("pending_async_subdevices", 0444,
+                           v4l2_async_debugfs_dir, NULL,
                            &pending_subdevs_fops);
+
+       return 0;
+}
+
+static void __exit v4l2_async_exit(void)
+{
+       debugfs_remove_recursive(v4l2_async_debugfs_dir);
 }
+
+subsys_initcall(v4l2_async_init);
+module_exit(v4l2_async_exit);
+
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_LICENSE("GPL");
index 0ca75f6..47aff3b 100644 (file)
@@ -1244,6 +1244,9 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        if (!file->f_op->unlocked_ioctl)
                return ret;
 
+       if (!video_is_registered(vdev))
+               return -ENODEV;
+
        if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
                ret = file->f_op->unlocked_ioctl(file, cmd,
                                        (unsigned long)compat_ptr(arg));
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
new file mode 100644 (file)
index 0000000..db9baa0
--- /dev/null
@@ -0,0 +1,1225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework uAPI implementation:
+ *
+ * Copyright (C) 2010-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#define pr_fmt(fmt) "v4l2-ctrls: " fmt
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "v4l2-ctrls-priv.h"
+
+/* Internal temporary helper struct, one for each v4l2_ext_control */
+struct v4l2_ctrl_helper {
+       /* Pointer to the control reference of the master control */
+       struct v4l2_ctrl_ref *mref;
+       /* The control ref corresponding to the v4l2_ext_control ID field. */
+       struct v4l2_ctrl_ref *ref;
+       /*
+        * v4l2_ext_control index of the next control belonging to the
+        * same cluster, or 0 if there isn't any.
+        */
+       u32 next;
+};
+
+/*
+ * Helper functions to copy control payload data from kernel space to
+ * user space and vice versa.
+ */
+
+/* Helper function: copy the given control value back to the caller */
+static int ptr_to_user(struct v4l2_ext_control *c,
+                      struct v4l2_ctrl *ctrl,
+                      union v4l2_ctrl_ptr ptr)
+{
+       u32 len;
+
+       if (ctrl->is_ptr && !ctrl->is_string)
+               return copy_to_user(c->ptr, ptr.p_const, c->size) ?
+                      -EFAULT : 0;
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_STRING:
+               len = strlen(ptr.p_char);
+               if (c->size < len + 1) {
+                       c->size = ctrl->elem_size;
+                       return -ENOSPC;
+               }
+               return copy_to_user(c->string, ptr.p_char, len + 1) ?
+                      -EFAULT : 0;
+       case V4L2_CTRL_TYPE_INTEGER64:
+               c->value64 = *ptr.p_s64;
+               break;
+       default:
+               c->value = *ptr.p_s32;
+               break;
+       }
+       return 0;
+}
+
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+       return ptr_to_user(c, ctrl, ctrl->p_cur);
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+                      struct v4l2_ctrl *ctrl)
+{
+       return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the request value back to the caller */
+static int req_to_user(struct v4l2_ext_control *c,
+                      struct v4l2_ctrl_ref *ref)
+{
+       return ptr_to_user(c, ref->ctrl, ref->p_req);
+}
+
+/* Helper function: copy the initial control value back to the caller */
+static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+       int idx;
+
+       for (idx = 0; idx < ctrl->elems; idx++)
+               ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+
+       return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the caller-provider value to the given control value */
+static int user_to_ptr(struct v4l2_ext_control *c,
+                      struct v4l2_ctrl *ctrl,
+                      union v4l2_ctrl_ptr ptr)
+{
+       int ret;
+       u32 size;
+
+       ctrl->is_new = 1;
+       if (ctrl->is_ptr && !ctrl->is_string) {
+               unsigned int idx;
+
+               ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
+               if (ret || !ctrl->is_array)
+                       return ret;
+               for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
+                       ctrl->type_ops->init(ctrl, idx, ptr);
+               return 0;
+       }
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER64:
+               *ptr.p_s64 = c->value64;
+               break;
+       case V4L2_CTRL_TYPE_STRING:
+               size = c->size;
+               if (size == 0)
+                       return -ERANGE;
+               if (size > ctrl->maximum + 1)
+                       size = ctrl->maximum + 1;
+               ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
+               if (!ret) {
+                       char last = ptr.p_char[size - 1];
+
+                       ptr.p_char[size - 1] = 0;
+                       /*
+                        * If the string was longer than ctrl->maximum,
+                        * then return an error.
+                        */
+                       if (strlen(ptr.p_char) == ctrl->maximum && last)
+                               return -ERANGE;
+               }
+               return ret;
+       default:
+               *ptr.p_s32 = c->value;
+               break;
+       }
+       return 0;
+}
+
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+       return user_to_ptr(c, ctrl, ctrl->p_new);
+}
+
+/*
+ * VIDIOC_G/TRY/S_EXT_CTRLS implementation
+ */
+
+/*
+ * Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
+ *
+ * It is not a fully atomic operation, just best-effort only. After all, if
+ * multiple controls have to be set through multiple i2c writes (for example)
+ * then some initial writes may succeed while others fail. Thus leaving the
+ * system in an inconsistent state. The question is how much effort you are
+ * willing to spend on trying to make something atomic that really isn't.
+ *
+ * From the point of view of an application the main requirement is that
+ * when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
+ * error should be returned without actually affecting any controls.
+ *
+ * If all the values are correct, then it is acceptable to just give up
+ * in case of low-level errors.
+ *
+ * It is important though that the application can tell when only a partial
+ * configuration was done. The way we do that is through the error_idx field
+ * of struct v4l2_ext_controls: if that is equal to the count field then no
+ * controls were affected. Otherwise all controls before that index were
+ * successful in performing their 'get' or 'set' operation, the control at
+ * the given index failed, and you don't know what happened with the controls
+ * after the failed one. Since if they were part of a control cluster they
+ * could have been successfully processed (if a cluster member was encountered
+ * at index < error_idx), they could have failed (if a cluster member was at
+ * error_idx), or they may not have been processed yet (if the first cluster
+ * member appeared after error_idx).
+ *
+ * It is all fairly theoretical, though. In practice all you can do is to
+ * bail out. If error_idx == count, then it is an application bug. If
+ * error_idx < count then it is only an application bug if the error code was
+ * EBUSY. That usually means that something started streaming just when you
+ * tried to set the controls. In all other cases it is a driver/hardware
+ * problem and all you can do is to retry or bail out.
+ *
+ * Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
+ * never modifies controls the error_idx is just set to whatever control
+ * has an invalid value.
+ */
+
+/*
+ * Prepare for the extended g/s/try functions.
+ * Find the controls in the control array and do some basic checks.
+ */
+static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+                            struct v4l2_ext_controls *cs,
+                            struct v4l2_ctrl_helper *helpers,
+                            struct video_device *vdev,
+                            bool get)
+{
+       struct v4l2_ctrl_helper *h;
+       bool have_clusters = false;
+       u32 i;
+
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
+               struct v4l2_ext_control *c = &cs->controls[i];
+               struct v4l2_ctrl_ref *ref;
+               struct v4l2_ctrl *ctrl;
+               u32 id = c->id & V4L2_CTRL_ID_MASK;
+
+               cs->error_idx = i;
+
+               if (cs->which &&
+                   cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
+                   cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
+                   V4L2_CTRL_ID2WHICH(id) != cs->which) {
+                       dprintk(vdev,
+                               "invalid which 0x%x or control id 0x%x\n",
+                               cs->which, id);
+                       return -EINVAL;
+               }
+
+               /*
+                * Old-style private controls are not allowed for
+                * extended controls.
+                */
+               if (id >= V4L2_CID_PRIVATE_BASE) {
+                       dprintk(vdev,
+                               "old-style private controls not allowed\n");
+                       return -EINVAL;
+               }
+               ref = find_ref_lock(hdl, id);
+               if (!ref) {
+                       dprintk(vdev, "cannot find control id 0x%x\n", id);
+                       return -EINVAL;
+               }
+               h->ref = ref;
+               ctrl = ref->ctrl;
+               if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
+                       dprintk(vdev, "control id 0x%x is disabled\n", id);
+                       return -EINVAL;
+               }
+
+               if (ctrl->cluster[0]->ncontrols > 1)
+                       have_clusters = true;
+               if (ctrl->cluster[0] != ctrl)
+                       ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
+               if (ctrl->is_ptr && !ctrl->is_string) {
+                       unsigned int tot_size = ctrl->elems * ctrl->elem_size;
+
+                       if (c->size < tot_size) {
+                               /*
+                                * In the get case the application first
+                                * queries to obtain the size of the control.
+                                */
+                               if (get) {
+                                       c->size = tot_size;
+                                       return -ENOSPC;
+                               }
+                               dprintk(vdev,
+                                       "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n",
+                                       id, c->size, tot_size);
+                               return -EFAULT;
+                       }
+                       c->size = tot_size;
+               }
+               /* Store the ref to the master control of the cluster */
+               h->mref = ref;
+               /*
+                * Initially set next to 0, meaning that there is no other
+                * control in this helper array belonging to the same
+                * cluster.
+                */
+               h->next = 0;
+       }
+
+       /*
+        * We are done if there were no controls that belong to a multi-
+        * control cluster.
+        */
+       if (!have_clusters)
+               return 0;
+
+       /*
+        * The code below figures out in O(n) time which controls in the list
+        * belong to the same cluster.
+        */
+
+       /* This has to be done with the handler lock taken. */
+       mutex_lock(hdl->lock);
+
+       /* First zero the helper field in the master control references */
+       for (i = 0; i < cs->count; i++)
+               helpers[i].mref->helper = NULL;
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
+               struct v4l2_ctrl_ref *mref = h->mref;
+
+               /*
+                * If the mref->helper is set, then it points to an earlier
+                * helper that belongs to the same cluster.
+                */
+               if (mref->helper) {
+                       /*
+                        * Set the next field of mref->helper to the current
+                        * index: this means that the earlier helper now
+                        * points to the next helper in the same cluster.
+                        */
+                       mref->helper->next = i;
+                       /*
+                        * mref should be set only for the first helper in the
+                        * cluster, clear the others.
+                        */
+                       h->mref = NULL;
+               }
+               /* Point the mref helper to the current helper struct. */
+               mref->helper = h;
+       }
+       mutex_unlock(hdl->lock);
+       return 0;
+}
+
+/*
+ * Handles the corner case where cs->count == 0. It checks whether the
+ * specified control class exists. If that class ID is 0, then it checks
+ * whether there are any controls at all.
+ */
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
+{
+       if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
+           which == V4L2_CTRL_WHICH_REQUEST_VAL)
+               return 0;
+       return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
+}
+
+/*
+ * Get extended controls. Allocates the helpers array if needed.
+ *
+ * Note that v4l2_g_ext_ctrls_common() with 'which' set to
+ * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
+ * completed, and in that case valid_p_req is true for all controls.
+ */
+int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
+                           struct v4l2_ext_controls *cs,
+                           struct video_device *vdev)
+{
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
+       int ret;
+       int i, j;
+       bool is_default, is_request;
+
+       is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
+       is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
+
+       cs->error_idx = cs->count;
+       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
+
+       if (!hdl)
+               return -EINVAL;
+
+       if (cs->count == 0)
+               return class_check(hdl, cs->which);
+
+       if (cs->count > ARRAY_SIZE(helper)) {
+               helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
+                                        GFP_KERNEL);
+               if (!helpers)
+                       return -ENOMEM;
+       }
+
+       ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true);
+       cs->error_idx = cs->count;
+
+       for (i = 0; !ret && i < cs->count; i++)
+               if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+                       ret = -EACCES;
+
+       for (i = 0; !ret && i < cs->count; i++) {
+               struct v4l2_ctrl *master;
+               bool is_volatile = false;
+               u32 idx = i;
+
+               if (!helpers[i].mref)
+                       continue;
+
+               master = helpers[i].mref->ctrl;
+               cs->error_idx = i;
+
+               v4l2_ctrl_lock(master);
+
+               /*
+                * g_volatile_ctrl will update the new control values.
+                * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
+                * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
+                * it is v4l2_ctrl_request_complete() that copies the
+                * volatile controls at the time of request completion
+                * to the request, so you don't want to do that again.
+                */
+               if (!is_default && !is_request &&
+                   ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+                   (master->has_volatiles && !is_cur_manual(master)))) {
+                       for (j = 0; j < master->ncontrols; j++)
+                               cur_to_new(master->cluster[j]);
+                       ret = call_op(master, g_volatile_ctrl);
+                       is_volatile = true;
+               }
+
+               if (ret) {
+                       v4l2_ctrl_unlock(master);
+                       break;
+               }
+
+               /*
+                * Copy the default value (if is_default is true), the
+                * request value (if is_request is true and p_req is valid),
+                * the new volatile value (if is_volatile is true) or the
+                * current value.
+                */
+               do {
+                       struct v4l2_ctrl_ref *ref = helpers[idx].ref;
+
+                       if (is_default)
+                               ret = def_to_user(cs->controls + idx, ref->ctrl);
+                       else if (is_request && ref->valid_p_req)
+                               ret = req_to_user(cs->controls + idx, ref);
+                       else if (is_volatile)
+                               ret = new_to_user(cs->controls + idx, ref->ctrl);
+                       else
+                               ret = cur_to_user(cs->controls + idx, ref->ctrl);
+                       idx = helpers[idx].next;
+               } while (!ret && idx);
+
+               v4l2_ctrl_unlock(master);
+       }
+
+       if (cs->count > ARRAY_SIZE(helper))
+               kvfree(helpers);
+       return ret;
+}
+
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+                    struct media_device *mdev, struct v4l2_ext_controls *cs)
+{
+       if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
+               return v4l2_g_ext_ctrls_request(hdl, vdev, mdev, cs);
+
+       return v4l2_g_ext_ctrls_common(hdl, cs, vdev);
+}
+EXPORT_SYMBOL(v4l2_g_ext_ctrls);
+
+/* Validate controls. */
+static int validate_ctrls(struct v4l2_ext_controls *cs,
+                         struct v4l2_ctrl_helper *helpers,
+                         struct video_device *vdev,
+                         bool set)
+{
+       unsigned int i;
+       int ret = 0;
+
+       cs->error_idx = cs->count;
+       for (i = 0; i < cs->count; i++) {
+               struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
+               union v4l2_ctrl_ptr p_new;
+
+               cs->error_idx = i;
+
+               if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) {
+                       dprintk(vdev,
+                               "control id 0x%x is read-only\n",
+                               ctrl->id);
+                       return -EACCES;
+               }
+               /*
+                * This test is also done in try_set_control_cluster() which
+                * is called in atomic context, so that has the final say,
+                * but it makes sense to do an up-front check as well. Once
+                * an error occurs in try_set_control_cluster() some other
+                * controls may have been set already and we want to do a
+                * best-effort to avoid that.
+                */
+               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) {
+                       dprintk(vdev,
+                               "control id 0x%x is grabbed, cannot set\n",
+                               ctrl->id);
+                       return -EBUSY;
+               }
+               /*
+                * Skip validation for now if the payload needs to be copied
+                * from userspace into kernelspace. We'll validate those later.
+                */
+               if (ctrl->is_ptr)
+                       continue;
+               if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+                       p_new.p_s64 = &cs->controls[i].value64;
+               else
+                       p_new.p_s32 = &cs->controls[i].value;
+               ret = validate_new(ctrl, p_new);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/* Try or try-and-set controls */
+int try_set_ext_ctrls_common(struct v4l2_fh *fh,
+                            struct v4l2_ctrl_handler *hdl,
+                            struct v4l2_ext_controls *cs,
+                            struct video_device *vdev, bool set)
+{
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
+       unsigned int i, j;
+       int ret;
+
+       cs->error_idx = cs->count;
+
+       /* Default value cannot be changed */
+       if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
+               dprintk(vdev, "%s: cannot change default value\n",
+                       video_device_node_name(vdev));
+               return -EINVAL;
+       }
+
+       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
+
+       if (!hdl) {
+               dprintk(vdev, "%s: invalid null control handler\n",
+                       video_device_node_name(vdev));
+               return -EINVAL;
+       }
+
+       if (cs->count == 0)
+               return class_check(hdl, cs->which);
+
+       if (cs->count > ARRAY_SIZE(helper)) {
+               helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
+                                        GFP_KERNEL);
+               if (!helpers)
+                       return -ENOMEM;
+       }
+       ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false);
+       if (!ret)
+               ret = validate_ctrls(cs, helpers, vdev, set);
+       if (ret && set)
+               cs->error_idx = cs->count;
+       for (i = 0; !ret && i < cs->count; i++) {
+               struct v4l2_ctrl *master;
+               u32 idx = i;
+
+               if (!helpers[i].mref)
+                       continue;
+
+               cs->error_idx = i;
+               master = helpers[i].mref->ctrl;
+               v4l2_ctrl_lock(master);
+
+               /* Reset the 'is_new' flags of the cluster */
+               for (j = 0; j < master->ncontrols; j++)
+                       if (master->cluster[j])
+                               master->cluster[j]->is_new = 0;
+
+               /*
+                * For volatile autoclusters that are currently in auto mode
+                * we need to discover if it will be set to manual mode.
+                * If so, then we have to copy the current volatile values
+                * first since those will become the new manual values (which
+                * may be overwritten by explicit new values from this set
+                * of controls).
+                */
+               if (master->is_auto && master->has_volatiles &&
+                   !is_cur_manual(master)) {
+                       /* Pick an initial non-manual value */
+                       s32 new_auto_val = master->manual_mode_value + 1;
+                       u32 tmp_idx = idx;
+
+                       do {
+                               /*
+                                * Check if the auto control is part of the
+                                * list, and remember the new value.
+                                */
+                               if (helpers[tmp_idx].ref->ctrl == master)
+                                       new_auto_val = cs->controls[tmp_idx].value;
+                               tmp_idx = helpers[tmp_idx].next;
+                       } while (tmp_idx);
+                       /*
+                        * If the new value == the manual value, then copy
+                        * the current volatile values.
+                        */
+                       if (new_auto_val == master->manual_mode_value)
+                               update_from_auto_cluster(master);
+               }
+
+               /*
+                * Copy the new caller-supplied control values.
+                * user_to_new() sets 'is_new' to 1.
+                */
+               do {
+                       struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
+
+                       ret = user_to_new(cs->controls + idx, ctrl);
+                       if (!ret && ctrl->is_ptr) {
+                               ret = validate_new(ctrl, ctrl->p_new);
+                               if (ret)
+                                       dprintk(vdev,
+                                               "failed to validate control %s (%d)\n",
+                                               v4l2_ctrl_get_name(ctrl->id), ret);
+                       }
+                       idx = helpers[idx].next;
+               } while (!ret && idx);
+
+               if (!ret)
+                       ret = try_or_set_cluster(fh, master,
+                                                !hdl->req_obj.req && set, 0);
+               if (!ret && hdl->req_obj.req && set) {
+                       for (j = 0; j < master->ncontrols; j++) {
+                               struct v4l2_ctrl_ref *ref =
+                                       find_ref(hdl, master->cluster[j]->id);
+
+                               new_to_req(ref);
+                       }
+               }
+
+               /* Copy the new values back to userspace. */
+               if (!ret) {
+                       idx = i;
+                       do {
+                               ret = new_to_user(cs->controls + idx,
+                                                 helpers[idx].ref->ctrl);
+                               idx = helpers[idx].next;
+                       } while (!ret && idx);
+               }
+               v4l2_ctrl_unlock(master);
+       }
+
+       if (cs->count > ARRAY_SIZE(helper))
+               kvfree(helpers);
+       return ret;
+}
+
+static int try_set_ext_ctrls(struct v4l2_fh *fh,
+                            struct v4l2_ctrl_handler *hdl,
+                            struct video_device *vdev,
+                            struct media_device *mdev,
+                            struct v4l2_ext_controls *cs, bool set)
+{
+       int ret;
+
+       if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
+               return try_set_ext_ctrls_request(fh, hdl, vdev, mdev, cs, set);
+
+       ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
+       if (ret)
+               dprintk(vdev,
+                       "%s: try_set_ext_ctrls_common failed (%d)\n",
+                       video_device_node_name(vdev), ret);
+
+       return ret;
+}
+
+int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+                      struct video_device *vdev,
+                      struct media_device *mdev,
+                      struct v4l2_ext_controls *cs)
+{
+       return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false);
+}
+EXPORT_SYMBOL(v4l2_try_ext_ctrls);
+
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
+                    struct v4l2_ctrl_handler *hdl,
+                    struct video_device *vdev,
+                    struct media_device *mdev,
+                    struct v4l2_ext_controls *cs)
+{
+       return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true);
+}
+EXPORT_SYMBOL(v4l2_s_ext_ctrls);
+
+/*
+ * VIDIOC_G/S_CTRL implementation
+ */
+
+/* Helper function to get a single control */
+static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
+{
+       struct v4l2_ctrl *master = ctrl->cluster[0];
+       int ret = 0;
+       int i;
+
+       /* Compound controls are not supported. The new_to_user() and
+        * cur_to_user() calls below would need to be modified not to access
+        * userspace memory when called from get_ctrl().
+        */
+       if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64)
+               return -EINVAL;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+               return -EACCES;
+
+       v4l2_ctrl_lock(master);
+       /* g_volatile_ctrl will update the current control values */
+       if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+               for (i = 0; i < master->ncontrols; i++)
+                       cur_to_new(master->cluster[i]);
+               ret = call_op(master, g_volatile_ctrl);
+               new_to_user(c, ctrl);
+       } else {
+               cur_to_user(c, ctrl);
+       }
+       v4l2_ctrl_unlock(master);
+       return ret;
+}
+
+int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+       struct v4l2_ext_control c;
+       int ret;
+
+       if (!ctrl || !ctrl->is_int)
+               return -EINVAL;
+       ret = get_ctrl(ctrl, &c);
+       control->value = c.value;
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_g_ctrl);
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+{
+       struct v4l2_ctrl *master = ctrl->cluster[0];
+       int ret;
+       int i;
+
+       /* Reset the 'is_new' flags of the cluster */
+       for (i = 0; i < master->ncontrols; i++)
+               if (master->cluster[i])
+                       master->cluster[i]->is_new = 0;
+
+       ret = validate_new(ctrl, ctrl->p_new);
+       if (ret)
+               return ret;
+
+       /*
+        * For autoclusters with volatiles that are switched from auto to
+        * manual mode we have to update the current volatile values since
+        * those will become the initial manual values after such a switch.
+        */
+       if (master->is_auto && master->has_volatiles && ctrl == master &&
+           !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
+               update_from_auto_cluster(master);
+
+       ctrl->is_new = 1;
+       return try_or_set_cluster(fh, master, true, ch_flags);
+}
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+                        struct v4l2_ext_control *c)
+{
+       int ret;
+
+       v4l2_ctrl_lock(ctrl);
+       user_to_new(c, ctrl);
+       ret = set_ctrl(fh, ctrl, 0);
+       if (!ret)
+               cur_to_user(c, ctrl);
+       v4l2_ctrl_unlock(ctrl);
+       return ret;
+}
+
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+               struct v4l2_control *control)
+{
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+       struct v4l2_ext_control c = { control->id };
+       int ret;
+
+       if (!ctrl || !ctrl->is_int)
+               return -EINVAL;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+               return -EACCES;
+
+       c.value = control->value;
+       ret = set_ctrl_lock(fh, ctrl, &c);
+       control->value = c.value;
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_s_ctrl);
+
+/*
+ * Helper functions for drivers to get/set controls.
+ */
+
+s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ext_control c;
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(!ctrl->is_int))
+               return 0;
+       c.value = 0;
+       get_ctrl(ctrl, &c);
+       return c.value;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
+
+s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ext_control c;
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
+               return 0;
+       c.value64 = 0;
+       get_ctrl(ctrl, &c);
+       return c.value64;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
+
+int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
+{
+       lockdep_assert_held(ctrl->handler->lock);
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(!ctrl->is_int))
+               return -EINVAL;
+       ctrl->val = val;
+       return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
+
+int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
+{
+       lockdep_assert_held(ctrl->handler->lock);
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
+               return -EINVAL;
+       *ctrl->p_new.p_s64 = val;
+       return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
+
+int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
+{
+       lockdep_assert_held(ctrl->handler->lock);
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING))
+               return -EINVAL;
+       strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
+       return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
+
+int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
+                               enum v4l2_ctrl_type type, const void *p)
+{
+       lockdep_assert_held(ctrl->handler->lock);
+
+       /* It's a driver bug if this happens. */
+       if (WARN_ON(ctrl->type != type))
+               return -EINVAL;
+       memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
+       return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound);
+
+/*
+ * Modify the range of a control.
+ */
+int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
+                            s64 min, s64 max, u64 step, s64 def)
+{
+       bool value_changed;
+       bool range_changed = false;
+       int ret;
+
+       lockdep_assert_held(ctrl->handler->lock);
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_INTEGER64:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+       case V4L2_CTRL_TYPE_BITMASK:
+       case V4L2_CTRL_TYPE_U8:
+       case V4L2_CTRL_TYPE_U16:
+       case V4L2_CTRL_TYPE_U32:
+               if (ctrl->is_array)
+                       return -EINVAL;
+               ret = check_range(ctrl->type, min, max, step, def);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (ctrl->minimum != min || ctrl->maximum != max ||
+           ctrl->step != step || ctrl->default_value != def) {
+               range_changed = true;
+               ctrl->minimum = min;
+               ctrl->maximum = max;
+               ctrl->step = step;
+               ctrl->default_value = def;
+       }
+       cur_to_new(ctrl);
+       if (validate_new(ctrl, ctrl->p_new)) {
+               if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+                       *ctrl->p_new.p_s64 = def;
+               else
+                       *ctrl->p_new.p_s32 = def;
+       }
+
+       if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+               value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
+       else
+               value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
+       if (value_changed)
+               ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+       else if (range_changed)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+       return ret;
+}
+EXPORT_SYMBOL(__v4l2_ctrl_modify_range);
+
+/* Implement VIDIOC_QUERY_EXT_CTRL */
+int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
+{
+       const unsigned int next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
+       u32 id = qc->id & V4L2_CTRL_ID_MASK;
+       struct v4l2_ctrl_ref *ref;
+       struct v4l2_ctrl *ctrl;
+
+       if (!hdl)
+               return -EINVAL;
+
+       mutex_lock(hdl->lock);
+
+       /* Try to find it */
+       ref = find_ref(hdl, id);
+
+       if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
+               bool is_compound;
+               /* Match any control that is not hidden */
+               unsigned int mask = 1;
+               bool match = false;
+
+               if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
+                       /* Match any hidden control */
+                       match = true;
+               } else if ((qc->id & next_flags) == next_flags) {
+                       /* Match any control, compound or not */
+                       mask = 0;
+               }
+
+               /* Find the next control with ID > qc->id */
+
+               /* Did we reach the end of the control list? */
+               if (id >= node2id(hdl->ctrl_refs.prev)) {
+                       ref = NULL; /* Yes, so there is no next control */
+               } else if (ref) {
+                       /*
+                        * We found a control with the given ID, so just get
+                        * the next valid one in the list.
+                        */
+                       list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
+                               is_compound = ref->ctrl->is_array ||
+                                       ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+                               if (id < ref->ctrl->id &&
+                                   (is_compound & mask) == match)
+                                       break;
+                       }
+                       if (&ref->node == &hdl->ctrl_refs)
+                               ref = NULL;
+               } else {
+                       /*
+                        * No control with the given ID exists, so start
+                        * searching for the next largest ID. We know there
+                        * is one, otherwise the first 'if' above would have
+                        * been true.
+                        */
+                       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+                               is_compound = ref->ctrl->is_array ||
+                                       ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+                               if (id < ref->ctrl->id &&
+                                   (is_compound & mask) == match)
+                                       break;
+                       }
+                       if (&ref->node == &hdl->ctrl_refs)
+                               ref = NULL;
+               }
+       }
+       mutex_unlock(hdl->lock);
+
+       if (!ref)
+               return -EINVAL;
+
+       ctrl = ref->ctrl;
+       memset(qc, 0, sizeof(*qc));
+       if (id >= V4L2_CID_PRIVATE_BASE)
+               qc->id = id;
+       else
+               qc->id = ctrl->id;
+       strscpy(qc->name, ctrl->name, sizeof(qc->name));
+       qc->flags = user_flags(ctrl);
+       qc->type = ctrl->type;
+       qc->elem_size = ctrl->elem_size;
+       qc->elems = ctrl->elems;
+       qc->nr_of_dims = ctrl->nr_of_dims;
+       memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
+       qc->minimum = ctrl->minimum;
+       qc->maximum = ctrl->maximum;
+       qc->default_value = ctrl->default_value;
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU ||
+           ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
+               qc->step = 1;
+       else
+               qc->step = ctrl->step;
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_query_ext_ctrl);
+
+/* Implement VIDIOC_QUERYCTRL */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+{
+       struct v4l2_query_ext_ctrl qec = { qc->id };
+       int rc;
+
+       rc = v4l2_query_ext_ctrl(hdl, &qec);
+       if (rc)
+               return rc;
+
+       qc->id = qec.id;
+       qc->type = qec.type;
+       qc->flags = qec.flags;
+       strscpy(qc->name, qec.name, sizeof(qc->name));
+       switch (qc->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+       case V4L2_CTRL_TYPE_STRING:
+       case V4L2_CTRL_TYPE_BITMASK:
+               qc->minimum = qec.minimum;
+               qc->maximum = qec.maximum;
+               qc->step = qec.step;
+               qc->default_value = qec.default_value;
+               break;
+       default:
+               qc->minimum = 0;
+               qc->maximum = 0;
+               qc->step = 0;
+               qc->default_value = 0;
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_queryctrl);
+
+/* Implement VIDIOC_QUERYMENU */
+int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
+{
+       struct v4l2_ctrl *ctrl;
+       u32 i = qm->index;
+
+       ctrl = v4l2_ctrl_find(hdl, qm->id);
+       if (!ctrl)
+               return -EINVAL;
+
+       qm->reserved = 0;
+       /* Sanity checks */
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_MENU:
+               if (!ctrl->qmenu)
+                       return -EINVAL;
+               break;
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               if (!ctrl->qmenu_int)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (i < ctrl->minimum || i > ctrl->maximum)
+               return -EINVAL;
+
+       /* Use mask to see if this menu item should be skipped */
+       if (ctrl->menu_skip_mask & (1ULL << i))
+               return -EINVAL;
+       /* Empty menu items should also be skipped */
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+               if (!ctrl->qmenu[i] || ctrl->qmenu[i][0] == '\0')
+                       return -EINVAL;
+               strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+       } else {
+               qm->value = ctrl->qmenu_int[i];
+       }
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_querymenu);
+
+/*
+ * VIDIOC_LOG_STATUS helpers
+ */
+
+int v4l2_ctrl_log_status(struct file *file, void *fh)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_fh *vfh = file->private_data;
+
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
+               v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
+                                            vfd->v4l2_dev->name);
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_log_status);
+
+int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
+{
+       v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
+
+/*
+ * VIDIOC_(UN)SUBSCRIBE_EVENT implementation
+ */
+
+static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev,
+                              unsigned int elems)
+{
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+       if (!ctrl)
+               return -EINVAL;
+
+       v4l2_ctrl_lock(ctrl);
+       list_add_tail(&sev->node, &ctrl->ev_subs);
+       if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+           (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL))
+               send_initial_event(sev->fh, ctrl);
+       v4l2_ctrl_unlock(ctrl);
+       return 0;
+}
+
+static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
+{
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+       if (!ctrl)
+               return;
+
+       v4l2_ctrl_lock(ctrl);
+       list_del(&sev->node);
+       v4l2_ctrl_unlock(ctrl);
+}
+
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+       u32 old_changes = old->u.ctrl.changes;
+
+       old->u.ctrl = new->u.ctrl;
+       old->u.ctrl.changes |= old_changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_replace);
+
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
+{
+       new->u.ctrl.changes |= old->u.ctrl.changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_merge);
+
+const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
+       .add = v4l2_ctrl_add_event,
+       .del = v4l2_ctrl_del_event,
+       .replace = v4l2_ctrl_replace,
+       .merge = v4l2_ctrl_merge,
+};
+EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
+
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+                             const struct v4l2_event_subscription *sub)
+{
+       if (sub->type == V4L2_EVENT_CTRL)
+               return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+
+int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                                    struct v4l2_event_subscription *sub)
+{
+       if (!sd->ctrl_handler)
+               return -EINVAL;
+       return v4l2_ctrl_subscribe_event(fh, sub);
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
+
+/*
+ * poll helper
+ */
+__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       poll_wait(file, &fh->wait, wait);
+       if (v4l2_event_pending(fh))
+               return EPOLLPRI;
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_poll);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
new file mode 100644 (file)
index 0000000..c4b5082
--- /dev/null
@@ -0,0 +1,1946 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework core implementation.
+ *
+ * Copyright (C) 2010-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+
+#include "v4l2-ctrls-priv.h"
+
+static const union v4l2_ctrl_ptr ptr_null;
+
+static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl,
+                      u32 changes)
+{
+       memset(ev, 0, sizeof(*ev));
+       ev->type = V4L2_EVENT_CTRL;
+       ev->id = ctrl->id;
+       ev->u.ctrl.changes = changes;
+       ev->u.ctrl.type = ctrl->type;
+       ev->u.ctrl.flags = user_flags(ctrl);
+       if (ctrl->is_ptr)
+               ev->u.ctrl.value64 = 0;
+       else
+               ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
+       ev->u.ctrl.minimum = ctrl->minimum;
+       ev->u.ctrl.maximum = ctrl->maximum;
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU
+           || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
+               ev->u.ctrl.step = 1;
+       else
+               ev->u.ctrl.step = ctrl->step;
+       ev->u.ctrl.default_value = ctrl->default_value;
+}
+
+void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_event ev;
+       u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+
+       if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
+               changes |= V4L2_EVENT_CTRL_CH_VALUE;
+       fill_event(&ev, ctrl, changes);
+       v4l2_event_queue_fh(fh, &ev);
+}
+
+void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
+{
+       struct v4l2_event ev;
+       struct v4l2_subscribed_event *sev;
+
+       if (list_empty(&ctrl->ev_subs))
+               return;
+       fill_event(&ev, ctrl, changes);
+
+       list_for_each_entry(sev, &ctrl->ev_subs, node)
+               if (sev->fh != fh ||
+                   (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
+                       v4l2_event_queue_fh(sev->fh, &ev);
+}
+
+static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
+                     union v4l2_ctrl_ptr ptr1,
+                     union v4l2_ctrl_ptr ptr2)
+{
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_BUTTON:
+               return false;
+       case V4L2_CTRL_TYPE_STRING:
+               idx *= ctrl->elem_size;
+               /* strings are always 0-terminated */
+               return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
+       case V4L2_CTRL_TYPE_INTEGER64:
+               return ptr1.p_s64[idx] == ptr2.p_s64[idx];
+       case V4L2_CTRL_TYPE_U8:
+               return ptr1.p_u8[idx] == ptr2.p_u8[idx];
+       case V4L2_CTRL_TYPE_U16:
+               return ptr1.p_u16[idx] == ptr2.p_u16[idx];
+       case V4L2_CTRL_TYPE_U32:
+               return ptr1.p_u32[idx] == ptr2.p_u32[idx];
+       default:
+               if (ctrl->is_int)
+                       return ptr1.p_s32[idx] == ptr2.p_s32[idx];
+               idx *= ctrl->elem_size;
+               return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx,
+                              ctrl->elem_size);
+       }
+}
+
+/* Default intra MPEG-2 quantisation coefficients, from the specification. */
+static const u8 mpeg2_intra_quant_matrix[64] = {
+       8,  16, 16, 19, 16, 19, 22, 22,
+       22, 22, 22, 22, 26, 24, 26, 27,
+       27, 27, 26, 26, 26, 26, 27, 27,
+       27, 29, 29, 29, 34, 34, 34, 29,
+       29, 29, 27, 27, 29, 29, 32, 32,
+       34, 34, 37, 38, 37, 35, 35, 34,
+       35, 38, 38, 40, 40, 40, 48, 48,
+       46, 46, 56, 56, 58, 69, 69, 83
+};
+
+static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+                             union v4l2_ctrl_ptr ptr)
+{
+       struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
+       struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
+       struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant;
+       struct v4l2_ctrl_vp8_frame *p_vp8_frame;
+       struct v4l2_ctrl_fwht_params *p_fwht_params;
+       void *p = ptr.p + idx * ctrl->elem_size;
+
+       if (ctrl->p_def.p_const)
+               memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
+       else
+               memset(p, 0, ctrl->elem_size);
+
+       switch ((u32)ctrl->type) {
+       case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+               p_mpeg2_sequence = p;
+
+               /* 4:2:0 */
+               p_mpeg2_sequence->chroma_format = 1;
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+               p_mpeg2_picture = p;
+
+               /* interlaced top field */
+               p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD;
+               p_mpeg2_picture->picture_coding_type =
+                                       V4L2_MPEG2_PIC_CODING_TYPE_I;
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+               p_mpeg2_quant = p;
+
+               memcpy(p_mpeg2_quant->intra_quantiser_matrix,
+                      mpeg2_intra_quant_matrix,
+                      ARRAY_SIZE(mpeg2_intra_quant_matrix));
+               /*
+                * The default non-intra MPEG-2 quantisation
+                * coefficients are all 16, as per the specification.
+                */
+               memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16,
+                      sizeof(p_mpeg2_quant->non_intra_quantiser_matrix));
+               break;
+       case V4L2_CTRL_TYPE_VP8_FRAME:
+               p_vp8_frame = p;
+               p_vp8_frame->num_dct_parts = 1;
+               break;
+       case V4L2_CTRL_TYPE_FWHT_PARAMS:
+               p_fwht_params = p;
+               p_fwht_params->version = V4L2_FWHT_VERSION;
+               p_fwht_params->width = 1280;
+               p_fwht_params->height = 720;
+               p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV |
+                       (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
+               break;
+       }
+}
+
+static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
+                    union v4l2_ctrl_ptr ptr)
+{
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_STRING:
+               idx *= ctrl->elem_size;
+               memset(ptr.p_char + idx, ' ', ctrl->minimum);
+               ptr.p_char[idx + ctrl->minimum] = '\0';
+               break;
+       case V4L2_CTRL_TYPE_INTEGER64:
+               ptr.p_s64[idx] = ctrl->default_value;
+               break;
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_BITMASK:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+               ptr.p_s32[idx] = ctrl->default_value;
+               break;
+       case V4L2_CTRL_TYPE_BUTTON:
+       case V4L2_CTRL_TYPE_CTRL_CLASS:
+               ptr.p_s32[idx] = 0;
+               break;
+       case V4L2_CTRL_TYPE_U8:
+               ptr.p_u8[idx] = ctrl->default_value;
+               break;
+       case V4L2_CTRL_TYPE_U16:
+               ptr.p_u16[idx] = ctrl->default_value;
+               break;
+       case V4L2_CTRL_TYPE_U32:
+               ptr.p_u32[idx] = ctrl->default_value;
+               break;
+       default:
+               std_init_compound(ctrl, idx, ptr);
+               break;
+       }
+}
+
+static void std_log(const struct v4l2_ctrl *ctrl)
+{
+       union v4l2_ctrl_ptr ptr = ctrl->p_cur;
+
+       if (ctrl->is_array) {
+               unsigned i;
+
+               for (i = 0; i < ctrl->nr_of_dims; i++)
+                       pr_cont("[%u]", ctrl->dims[i]);
+               pr_cont(" ");
+       }
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+               pr_cont("%d", *ptr.p_s32);
+               break;
+       case V4L2_CTRL_TYPE_BOOLEAN:
+               pr_cont("%s", *ptr.p_s32 ? "true" : "false");
+               break;
+       case V4L2_CTRL_TYPE_MENU:
+               pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
+               break;
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
+               break;
+       case V4L2_CTRL_TYPE_BITMASK:
+               pr_cont("0x%08x", *ptr.p_s32);
+               break;
+       case V4L2_CTRL_TYPE_INTEGER64:
+               pr_cont("%lld", *ptr.p_s64);
+               break;
+       case V4L2_CTRL_TYPE_STRING:
+               pr_cont("%s", ptr.p_char);
+               break;
+       case V4L2_CTRL_TYPE_U8:
+               pr_cont("%u", (unsigned)*ptr.p_u8);
+               break;
+       case V4L2_CTRL_TYPE_U16:
+               pr_cont("%u", (unsigned)*ptr.p_u16);
+               break;
+       case V4L2_CTRL_TYPE_U32:
+               pr_cont("%u", (unsigned)*ptr.p_u32);
+               break;
+       case V4L2_CTRL_TYPE_H264_SPS:
+               pr_cont("H264_SPS");
+               break;
+       case V4L2_CTRL_TYPE_H264_PPS:
+               pr_cont("H264_PPS");
+               break;
+       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+               pr_cont("H264_SCALING_MATRIX");
+               break;
+       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+               pr_cont("H264_SLICE_PARAMS");
+               break;
+       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+               pr_cont("H264_DECODE_PARAMS");
+               break;
+       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+               pr_cont("H264_PRED_WEIGHTS");
+               break;
+       case V4L2_CTRL_TYPE_FWHT_PARAMS:
+               pr_cont("FWHT_PARAMS");
+               break;
+       case V4L2_CTRL_TYPE_VP8_FRAME:
+               pr_cont("VP8_FRAME");
+               break;
+       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+               pr_cont("HDR10_CLL_INFO");
+               break;
+       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+               pr_cont("HDR10_MASTERING_DISPLAY");
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+               pr_cont("MPEG2_QUANTISATION");
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+               pr_cont("MPEG2_SEQUENCE");
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+               pr_cont("MPEG2_PICTURE");
+               break;
+       default:
+               pr_cont("unknown type %d", ctrl->type);
+               break;
+       }
+}
+
+/*
+ * Round towards the closest legal value. Be careful when we are
+ * close to the maximum range of the control type to prevent
+ * wrap-arounds.
+ */
+#define ROUND_TO_RANGE(val, offset_type, ctrl)                 \
+({                                                             \
+       offset_type offset;                                     \
+       if ((ctrl)->maximum >= 0 &&                             \
+           val >= (ctrl)->maximum - (s32)((ctrl)->step / 2))   \
+               val = (ctrl)->maximum;                          \
+       else                                                    \
+               val += (s32)((ctrl)->step / 2);                 \
+       val = clamp_t(typeof(val), val,                         \
+                     (ctrl)->minimum, (ctrl)->maximum);        \
+       offset = (val) - (ctrl)->minimum;                       \
+       offset = (ctrl)->step * (offset / (u32)(ctrl)->step);   \
+       val = (ctrl)->minimum + offset;                         \
+       0;                                                      \
+})
+
+/* Validate a new control */
+
+#define zero_padding(s) \
+       memset(&(s).padding, 0, sizeof((s).padding))
+#define zero_reserved(s) \
+       memset(&(s).reserved, 0, sizeof((s).reserved))
+
+/*
+ * Compound controls validation requires setting unused fields/flags to zero
+ * in order to properly detect unchanged controls with std_equal's memcmp.
+ */
+static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+                                union v4l2_ctrl_ptr ptr)
+{
+       struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
+       struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
+       struct v4l2_ctrl_vp8_frame *p_vp8_frame;
+       struct v4l2_ctrl_fwht_params *p_fwht_params;
+       struct v4l2_ctrl_h264_sps *p_h264_sps;
+       struct v4l2_ctrl_h264_pps *p_h264_pps;
+       struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
+       struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
+       struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
+       struct v4l2_ctrl_hevc_sps *p_hevc_sps;
+       struct v4l2_ctrl_hevc_pps *p_hevc_pps;
+       struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
+       struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
+       struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
+       struct v4l2_area *area;
+       void *p = ptr.p + idx * ctrl->elem_size;
+       unsigned int i;
+
+       switch ((u32)ctrl->type) {
+       case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+               p_mpeg2_sequence = p;
+
+               switch (p_mpeg2_sequence->chroma_format) {
+               case 1: /* 4:2:0 */
+               case 2: /* 4:2:2 */
+               case 3: /* 4:4:4 */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+               p_mpeg2_picture = p;
+
+               switch (p_mpeg2_picture->intra_dc_precision) {
+               case 0: /* 8 bits */
+               case 1: /* 9 bits */
+               case 2: /* 10 bits */
+               case 3: /* 11 bits */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (p_mpeg2_picture->picture_structure) {
+               case V4L2_MPEG2_PIC_TOP_FIELD:
+               case V4L2_MPEG2_PIC_BOTTOM_FIELD:
+               case V4L2_MPEG2_PIC_FRAME:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (p_mpeg2_picture->picture_coding_type) {
+               case V4L2_MPEG2_PIC_CODING_TYPE_I:
+               case V4L2_MPEG2_PIC_CODING_TYPE_P:
+               case V4L2_MPEG2_PIC_CODING_TYPE_B:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               zero_reserved(*p_mpeg2_picture);
+               break;
+
+       case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+               break;
+
+       case V4L2_CTRL_TYPE_FWHT_PARAMS:
+               p_fwht_params = p;
+               if (p_fwht_params->version < V4L2_FWHT_VERSION)
+                       return -EINVAL;
+               if (!p_fwht_params->width || !p_fwht_params->height)
+                       return -EINVAL;
+               break;
+
+       case V4L2_CTRL_TYPE_H264_SPS:
+               p_h264_sps = p;
+
+               /* Some syntax elements are only conditionally valid */
+               if (p_h264_sps->pic_order_cnt_type != 0) {
+                       p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
+               } else if (p_h264_sps->pic_order_cnt_type != 1) {
+                       p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0;
+                       p_h264_sps->offset_for_non_ref_pic = 0;
+                       p_h264_sps->offset_for_top_to_bottom_field = 0;
+                       memset(&p_h264_sps->offset_for_ref_frame, 0,
+                              sizeof(p_h264_sps->offset_for_ref_frame));
+               }
+
+               if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) {
+                       p_h264_sps->chroma_format_idc = 1;
+                       p_h264_sps->bit_depth_luma_minus8 = 0;
+                       p_h264_sps->bit_depth_chroma_minus8 = 0;
+
+                       p_h264_sps->flags &=
+                               ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
+
+                       if (p_h264_sps->chroma_format_idc < 3)
+                               p_h264_sps->flags &=
+                                       ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
+               }
+
+               if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
+                       p_h264_sps->flags &=
+                               ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
+
+               /*
+                * Chroma 4:2:2 format require at least High 4:2:2 profile.
+                *
+                * The H264 specification and well-known parser implementations
+                * use profile-idc values directly, as that is clearer and
+                * less ambiguous. We do the same here.
+                */
+               if (p_h264_sps->profile_idc < 122 &&
+                   p_h264_sps->chroma_format_idc > 1)
+                       return -EINVAL;
+               /* Chroma 4:4:4 format require at least High 4:2:2 profile */
+               if (p_h264_sps->profile_idc < 244 &&
+                   p_h264_sps->chroma_format_idc > 2)
+                       return -EINVAL;
+               if (p_h264_sps->chroma_format_idc > 3)
+                       return -EINVAL;
+
+               if (p_h264_sps->bit_depth_luma_minus8 > 6)
+                       return -EINVAL;
+               if (p_h264_sps->bit_depth_chroma_minus8 > 6)
+                       return -EINVAL;
+               if (p_h264_sps->log2_max_frame_num_minus4 > 12)
+                       return -EINVAL;
+               if (p_h264_sps->pic_order_cnt_type > 2)
+                       return -EINVAL;
+               if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
+                       return -EINVAL;
+               if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN)
+                       return -EINVAL;
+               break;
+
+       case V4L2_CTRL_TYPE_H264_PPS:
+               p_h264_pps = p;
+
+               if (p_h264_pps->num_slice_groups_minus1 > 7)
+                       return -EINVAL;
+               if (p_h264_pps->num_ref_idx_l0_default_active_minus1 >
+                   (V4L2_H264_REF_LIST_LEN - 1))
+                       return -EINVAL;
+               if (p_h264_pps->num_ref_idx_l1_default_active_minus1 >
+                   (V4L2_H264_REF_LIST_LEN - 1))
+                       return -EINVAL;
+               if (p_h264_pps->weighted_bipred_idc > 2)
+                       return -EINVAL;
+               /*
+                * pic_init_qp_minus26 shall be in the range of
+                * -(26 + QpBdOffset_y) to +25, inclusive,
+                *  where QpBdOffset_y is 6 * bit_depth_luma_minus8
+                */
+               if (p_h264_pps->pic_init_qp_minus26 < -62 ||
+                   p_h264_pps->pic_init_qp_minus26 > 25)
+                       return -EINVAL;
+               if (p_h264_pps->pic_init_qs_minus26 < -26 ||
+                   p_h264_pps->pic_init_qs_minus26 > 25)
+                       return -EINVAL;
+               if (p_h264_pps->chroma_qp_index_offset < -12 ||
+                   p_h264_pps->chroma_qp_index_offset > 12)
+                       return -EINVAL;
+               if (p_h264_pps->second_chroma_qp_index_offset < -12 ||
+                   p_h264_pps->second_chroma_qp_index_offset > 12)
+                       return -EINVAL;
+               break;
+
+       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+               break;
+
+       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+               p_h264_pred_weights = p;
+
+               if (p_h264_pred_weights->luma_log2_weight_denom > 7)
+                       return -EINVAL;
+               if (p_h264_pred_weights->chroma_log2_weight_denom > 7)
+                       return -EINVAL;
+               break;
+
+       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+               p_h264_slice_params = p;
+
+               if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
+                       p_h264_slice_params->flags &=
+                               ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED;
+
+               if (p_h264_slice_params->colour_plane_id > 2)
+                       return -EINVAL;
+               if (p_h264_slice_params->cabac_init_idc > 2)
+                       return -EINVAL;
+               if (p_h264_slice_params->disable_deblocking_filter_idc > 2)
+                       return -EINVAL;
+               if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 ||
+                   p_h264_slice_params->slice_alpha_c0_offset_div2 > 6)
+                       return -EINVAL;
+               if (p_h264_slice_params->slice_beta_offset_div2 < -6 ||
+                   p_h264_slice_params->slice_beta_offset_div2 > 6)
+                       return -EINVAL;
+
+               if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I ||
+                   p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI)
+                       p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0;
+               if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
+                       p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0;
+
+               if (p_h264_slice_params->num_ref_idx_l0_active_minus1 >
+                   (V4L2_H264_REF_LIST_LEN - 1))
+                       return -EINVAL;
+               if (p_h264_slice_params->num_ref_idx_l1_active_minus1 >
+                   (V4L2_H264_REF_LIST_LEN - 1))
+                       return -EINVAL;
+               zero_reserved(*p_h264_slice_params);
+               break;
+
+       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+               p_h264_dec_params = p;
+
+               if (p_h264_dec_params->nal_ref_idc > 3)
+                       return -EINVAL;
+               for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
+                       struct v4l2_h264_dpb_entry *dpb_entry =
+                               &p_h264_dec_params->dpb[i];
+
+                       zero_reserved(*dpb_entry);
+               }
+               zero_reserved(*p_h264_dec_params);
+               break;
+
+       case V4L2_CTRL_TYPE_VP8_FRAME:
+               p_vp8_frame = p;
+
+               switch (p_vp8_frame->num_dct_parts) {
+               case 1:
+               case 2:
+               case 4:
+               case 8:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               zero_padding(p_vp8_frame->segment);
+               zero_padding(p_vp8_frame->lf);
+               zero_padding(p_vp8_frame->quant);
+               zero_padding(p_vp8_frame->entropy);
+               zero_padding(p_vp8_frame->coder_state);
+               break;
+
+       case V4L2_CTRL_TYPE_HEVC_SPS:
+               p_hevc_sps = p;
+
+               if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) {
+                       p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0;
+                       p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0;
+                       p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0;
+                       p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0;
+               }
+
+               if (!(p_hevc_sps->flags &
+                     V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT))
+                       p_hevc_sps->num_long_term_ref_pics_sps = 0;
+               break;
+
+       case V4L2_CTRL_TYPE_HEVC_PPS:
+               p_hevc_pps = p;
+
+               if (!(p_hevc_pps->flags &
+                     V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
+                       p_hevc_pps->diff_cu_qp_delta_depth = 0;
+
+               if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
+                       p_hevc_pps->num_tile_columns_minus1 = 0;
+                       p_hevc_pps->num_tile_rows_minus1 = 0;
+                       memset(&p_hevc_pps->column_width_minus1, 0,
+                              sizeof(p_hevc_pps->column_width_minus1));
+                       memset(&p_hevc_pps->row_height_minus1, 0,
+                              sizeof(p_hevc_pps->row_height_minus1));
+
+                       p_hevc_pps->flags &=
+                               ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+               }
+
+               if (p_hevc_pps->flags &
+                   V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) {
+                       p_hevc_pps->pps_beta_offset_div2 = 0;
+                       p_hevc_pps->pps_tc_offset_div2 = 0;
+               }
+
+               zero_padding(*p_hevc_pps);
+               break;
+
+       case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+               p_hevc_decode_params = p;
+
+               if (p_hevc_decode_params->num_active_dpb_entries >
+                   V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+                       return -EINVAL;
+
+               for (i = 0; i < p_hevc_decode_params->num_active_dpb_entries;
+                    i++) {
+                       struct v4l2_hevc_dpb_entry *dpb_entry =
+                               &p_hevc_decode_params->dpb[i];
+
+                       zero_padding(*dpb_entry);
+               }
+               break;
+
+       case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+               p_hevc_slice_params = p;
+
+               zero_padding(p_hevc_slice_params->pred_weight_table);
+               zero_padding(*p_hevc_slice_params);
+               break;
+
+       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+               break;
+
+       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+               p_hdr10_mastering = p;
+
+               for (i = 0; i < 3; ++i) {
+                       if (p_hdr10_mastering->display_primaries_x[i] <
+                               V4L2_HDR10_MASTERING_PRIMARIES_X_LOW ||
+                           p_hdr10_mastering->display_primaries_x[i] >
+                               V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH ||
+                           p_hdr10_mastering->display_primaries_y[i] <
+                               V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW ||
+                           p_hdr10_mastering->display_primaries_y[i] >
+                               V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH)
+                               return -EINVAL;
+               }
+
+               if (p_hdr10_mastering->white_point_x <
+                       V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW ||
+                   p_hdr10_mastering->white_point_x >
+                       V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH ||
+                   p_hdr10_mastering->white_point_y <
+                       V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW ||
+                   p_hdr10_mastering->white_point_y >
+                       V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH)
+                       return -EINVAL;
+
+               if (p_hdr10_mastering->max_display_mastering_luminance <
+                       V4L2_HDR10_MASTERING_MAX_LUMA_LOW ||
+                   p_hdr10_mastering->max_display_mastering_luminance >
+                       V4L2_HDR10_MASTERING_MAX_LUMA_HIGH ||
+                   p_hdr10_mastering->min_display_mastering_luminance <
+                       V4L2_HDR10_MASTERING_MIN_LUMA_LOW ||
+                   p_hdr10_mastering->min_display_mastering_luminance >
+                       V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
+                       return -EINVAL;
+
+               /* The following restriction comes from ITU-T Rec. H.265 spec */
+               if (p_hdr10_mastering->max_display_mastering_luminance ==
+                       V4L2_HDR10_MASTERING_MAX_LUMA_LOW &&
+                   p_hdr10_mastering->min_display_mastering_luminance ==
+                       V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
+                       return -EINVAL;
+
+               break;
+
+       case V4L2_CTRL_TYPE_AREA:
+               area = p;
+               if (!area->width || !area->height)
+                       return -EINVAL;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
+                       union v4l2_ctrl_ptr ptr)
+{
+       size_t len;
+       u64 offset;
+       s64 val;
+
+       switch ((u32)ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+               return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
+       case V4L2_CTRL_TYPE_INTEGER64:
+               /*
+                * We can't use the ROUND_TO_RANGE define here due to
+                * the u64 divide that needs special care.
+                */
+               val = ptr.p_s64[idx];
+               if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2))
+                       val = ctrl->maximum;
+               else
+                       val += (s64)(ctrl->step / 2);
+               val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
+               offset = val - ctrl->minimum;
+               do_div(offset, ctrl->step);
+               ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step;
+               return 0;
+       case V4L2_CTRL_TYPE_U8:
+               return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
+       case V4L2_CTRL_TYPE_U16:
+               return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
+       case V4L2_CTRL_TYPE_U32:
+               return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl);
+
+       case V4L2_CTRL_TYPE_BOOLEAN:
+               ptr.p_s32[idx] = !!ptr.p_s32[idx];
+               return 0;
+
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
+                       return -ERANGE;
+               if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
+                   (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
+                       return -EINVAL;
+               if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+                   ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
+                       return -EINVAL;
+               return 0;
+
+       case V4L2_CTRL_TYPE_BITMASK:
+               ptr.p_s32[idx] &= ctrl->maximum;
+               return 0;
+
+       case V4L2_CTRL_TYPE_BUTTON:
+       case V4L2_CTRL_TYPE_CTRL_CLASS:
+               ptr.p_s32[idx] = 0;
+               return 0;
+
+       case V4L2_CTRL_TYPE_STRING:
+               idx *= ctrl->elem_size;
+               len = strlen(ptr.p_char + idx);
+               if (len < ctrl->minimum)
+                       return -ERANGE;
+               if ((len - (u32)ctrl->minimum) % (u32)ctrl->step)
+                       return -ERANGE;
+               return 0;
+
+       default:
+               return std_validate_compound(ctrl, idx, ptr);
+       }
+}
+
+static const struct v4l2_ctrl_type_ops std_type_ops = {
+       .equal = std_equal,
+       .init = std_init,
+       .log = std_log,
+       .validate = std_validate,
+};
+
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
+{
+       if (!ctrl)
+               return;
+       if (!notify) {
+               ctrl->call_notify = 0;
+               return;
+       }
+       if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
+               return;
+       ctrl->handler->notify = notify;
+       ctrl->handler->notify_priv = priv;
+       ctrl->call_notify = 1;
+}
+EXPORT_SYMBOL(v4l2_ctrl_notify);
+
+/* Copy the one value to another. */
+static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
+                      union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
+{
+       if (ctrl == NULL)
+               return;
+       memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
+}
+
+/* Copy the new value to the current value. */
+void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+{
+       bool changed;
+
+       if (ctrl == NULL)
+               return;
+
+       /* has_changed is set by cluster_changed */
+       changed = ctrl->has_changed;
+       if (changed)
+               ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
+
+       if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
+               /* Note: CH_FLAGS is only set for auto clusters. */
+               ctrl->flags &=
+                       ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
+               if (!is_cur_manual(ctrl->cluster[0])) {
+                       ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+                       if (ctrl->cluster[0]->has_volatiles)
+                               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+               }
+               fh = NULL;
+       }
+       if (changed || ch_flags) {
+               /* If a control was changed that was not one of the controls
+                  modified by the application, then send the event to all. */
+               if (!ctrl->is_new)
+                       fh = NULL;
+               send_event(fh, ctrl,
+                       (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
+               if (ctrl->call_notify && changed && ctrl->handler->notify)
+                       ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
+       }
+}
+
+/* Copy the current value to the new value */
+void cur_to_new(struct v4l2_ctrl *ctrl)
+{
+       if (ctrl == NULL)
+               return;
+       ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
+}
+
+/* Copy the new value to the request value */
+void new_to_req(struct v4l2_ctrl_ref *ref)
+{
+       if (!ref)
+               return;
+       ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
+       ref->valid_p_req = true;
+}
+
+/* Copy the current value to the request value */
+void cur_to_req(struct v4l2_ctrl_ref *ref)
+{
+       if (!ref)
+               return;
+       ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
+       ref->valid_p_req = true;
+}
+
+/* Copy the request value to the new value */
+void req_to_new(struct v4l2_ctrl_ref *ref)
+{
+       if (!ref)
+               return;
+       if (ref->valid_p_req)
+               ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
+       else
+               ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
+}
+
+/* Control range checking */
+int check_range(enum v4l2_ctrl_type type,
+               s64 min, s64 max, u64 step, s64 def)
+{
+       switch (type) {
+       case V4L2_CTRL_TYPE_BOOLEAN:
+               if (step != 1 || max > 1 || min < 0)
+                       return -ERANGE;
+               fallthrough;
+       case V4L2_CTRL_TYPE_U8:
+       case V4L2_CTRL_TYPE_U16:
+       case V4L2_CTRL_TYPE_U32:
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_INTEGER64:
+               if (step == 0 || min > max || def < min || def > max)
+                       return -ERANGE;
+               return 0;
+       case V4L2_CTRL_TYPE_BITMASK:
+               if (step || min || !max || (def & ~max))
+                       return -ERANGE;
+               return 0;
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               if (min > max || def < min || def > max)
+                       return -ERANGE;
+               /* Note: step == menu_skip_mask for menu controls.
+                  So here we check if the default value is masked out. */
+               if (step && ((1 << def) & step))
+                       return -EINVAL;
+               return 0;
+       case V4L2_CTRL_TYPE_STRING:
+               if (min > max || min < 0 || step < 1 || def)
+                       return -ERANGE;
+               return 0;
+       default:
+               return 0;
+       }
+}
+
+/* Validate a new control */
+int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
+{
+       unsigned idx;
+       int err = 0;
+
+       for (idx = 0; !err && idx < ctrl->elems; idx++)
+               err = ctrl->type_ops->validate(ctrl, idx, p_new);
+       return err;
+}
+
+/* Set the handler's error code if it wasn't set earlier already */
+static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
+{
+       if (hdl->error == 0)
+               hdl->error = err;
+       return err;
+}
+
+/* Initialize the handler */
+int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
+                                unsigned nr_of_controls_hint,
+                                struct lock_class_key *key, const char *name)
+{
+       mutex_init(&hdl->_lock);
+       hdl->lock = &hdl->_lock;
+       lockdep_set_class_and_name(hdl->lock, key, name);
+       INIT_LIST_HEAD(&hdl->ctrls);
+       INIT_LIST_HEAD(&hdl->ctrl_refs);
+       hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
+       hdl->buckets = kvmalloc_array(hdl->nr_of_buckets,
+                                     sizeof(hdl->buckets[0]),
+                                     GFP_KERNEL | __GFP_ZERO);
+       hdl->error = hdl->buckets ? 0 : -ENOMEM;
+       v4l2_ctrl_handler_init_request(hdl);
+       return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
+
+/* Free all controls and control refs */
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
+{
+       struct v4l2_ctrl_ref *ref, *next_ref;
+       struct v4l2_ctrl *ctrl, *next_ctrl;
+       struct v4l2_subscribed_event *sev, *next_sev;
+
+       if (hdl == NULL || hdl->buckets == NULL)
+               return;
+
+       v4l2_ctrl_handler_free_request(hdl);
+
+       mutex_lock(hdl->lock);
+       /* Free all nodes */
+       list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
+               list_del(&ref->node);
+               kfree(ref);
+       }
+       /* Free all controls owned by the handler */
+       list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
+               list_del(&ctrl->node);
+               list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
+                       list_del(&sev->node);
+               kvfree(ctrl);
+       }
+       kvfree(hdl->buckets);
+       hdl->buckets = NULL;
+       hdl->cached = NULL;
+       hdl->error = 0;
+       mutex_unlock(hdl->lock);
+       mutex_destroy(&hdl->_lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_free);
+
+/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
+   be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
+   with applications that do not use the NEXT_CTRL flag.
+
+   We just find the n-th private user control. It's O(N), but that should not
+   be an issue in this particular case. */
+static struct v4l2_ctrl_ref *find_private_ref(
+               struct v4l2_ctrl_handler *hdl, u32 id)
+{
+       struct v4l2_ctrl_ref *ref;
+
+       id -= V4L2_CID_PRIVATE_BASE;
+       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+               /* Search for private user controls that are compatible with
+                  VIDIOC_G/S_CTRL. */
+               if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+                   V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
+                       if (!ref->ctrl->is_int)
+                               continue;
+                       if (id == 0)
+                               return ref;
+                       id--;
+               }
+       }
+       return NULL;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+       struct v4l2_ctrl_ref *ref;
+       int bucket;
+
+       id &= V4L2_CTRL_ID_MASK;
+
+       /* Old-style private controls need special handling */
+       if (id >= V4L2_CID_PRIVATE_BASE)
+               return find_private_ref(hdl, id);
+       bucket = id % hdl->nr_of_buckets;
+
+       /* Simple optimization: cache the last control found */
+       if (hdl->cached && hdl->cached->ctrl->id == id)
+               return hdl->cached;
+
+       /* Not in cache, search the hash */
+       ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
+       while (ref && ref->ctrl->id != id)
+               ref = ref->next;
+
+       if (ref)
+               hdl->cached = ref; /* cache it! */
+       return ref;
+}
+
+/* Find a control with the given ID. Take the handler's lock first. */
+struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+       struct v4l2_ctrl_ref *ref = NULL;
+
+       if (hdl) {
+               mutex_lock(hdl->lock);
+               ref = find_ref(hdl, id);
+               mutex_unlock(hdl->lock);
+       }
+       return ref;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+       struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+       return ref ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_find);
+
+/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
+int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+                   struct v4l2_ctrl *ctrl,
+                   struct v4l2_ctrl_ref **ctrl_ref,
+                   bool from_other_dev, bool allocate_req)
+{
+       struct v4l2_ctrl_ref *ref;
+       struct v4l2_ctrl_ref *new_ref;
+       u32 id = ctrl->id;
+       u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
+       int bucket = id % hdl->nr_of_buckets;   /* which bucket to use */
+       unsigned int size_extra_req = 0;
+
+       if (ctrl_ref)
+               *ctrl_ref = NULL;
+
+       /*
+        * Automatically add the control class if it is not yet present and
+        * the new control is not a compound control.
+        */
+       if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
+           id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
+               if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
+                       return hdl->error;
+
+       if (hdl->error)
+               return hdl->error;
+
+       if (allocate_req)
+               size_extra_req = ctrl->elems * ctrl->elem_size;
+       new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
+       if (!new_ref)
+               return handler_set_err(hdl, -ENOMEM);
+       new_ref->ctrl = ctrl;
+       new_ref->from_other_dev = from_other_dev;
+       if (size_extra_req)
+               new_ref->p_req.p = &new_ref[1];
+
+       INIT_LIST_HEAD(&new_ref->node);
+
+       mutex_lock(hdl->lock);
+
+       /* Add immediately at the end of the list if the list is empty, or if
+          the last element in the list has a lower ID.
+          This ensures that when elements are added in ascending order the
+          insertion is an O(1) operation. */
+       if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
+               list_add_tail(&new_ref->node, &hdl->ctrl_refs);
+               goto insert_in_hash;
+       }
+
+       /* Find insert position in sorted list */
+       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+               if (ref->ctrl->id < id)
+                       continue;
+               /* Don't add duplicates */
+               if (ref->ctrl->id == id) {
+                       kfree(new_ref);
+                       goto unlock;
+               }
+               list_add(&new_ref->node, ref->node.prev);
+               break;
+       }
+
+insert_in_hash:
+       /* Insert the control node in the hash */
+       new_ref->next = hdl->buckets[bucket];
+       hdl->buckets[bucket] = new_ref;
+       if (ctrl_ref)
+               *ctrl_ref = new_ref;
+       if (ctrl->handler == hdl) {
+               /* By default each control starts in a cluster of its own.
+                * new_ref->ctrl is basically a cluster array with one
+                * element, so that's perfect to use as the cluster pointer.
+                * But only do this for the handler that owns the control.
+                */
+               ctrl->cluster = &new_ref->ctrl;
+               ctrl->ncontrols = 1;
+       }
+
+unlock:
+       mutex_unlock(hdl->lock);
+       return 0;
+}
+
+/* Add a new control */
+static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops,
+                       const struct v4l2_ctrl_type_ops *type_ops,
+                       u32 id, const char *name, enum v4l2_ctrl_type type,
+                       s64 min, s64 max, u64 step, s64 def,
+                       const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
+                       u32 flags, const char * const *qmenu,
+                       const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
+                       void *priv)
+{
+       struct v4l2_ctrl *ctrl;
+       unsigned sz_extra;
+       unsigned nr_of_dims = 0;
+       unsigned elems = 1;
+       bool is_array;
+       unsigned tot_ctrl_size;
+       unsigned idx;
+       void *data;
+       int err;
+
+       if (hdl->error)
+               return NULL;
+
+       while (dims && dims[nr_of_dims]) {
+               elems *= dims[nr_of_dims];
+               nr_of_dims++;
+               if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
+                       break;
+       }
+       is_array = nr_of_dims > 0;
+
+       /* Prefill elem_size for all types handled by std_type_ops */
+       switch ((u32)type) {
+       case V4L2_CTRL_TYPE_INTEGER64:
+               elem_size = sizeof(s64);
+               break;
+       case V4L2_CTRL_TYPE_STRING:
+               elem_size = max + 1;
+               break;
+       case V4L2_CTRL_TYPE_U8:
+               elem_size = sizeof(u8);
+               break;
+       case V4L2_CTRL_TYPE_U16:
+               elem_size = sizeof(u16);
+               break;
+       case V4L2_CTRL_TYPE_U32:
+               elem_size = sizeof(u32);
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+               elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence);
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+               elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture);
+               break;
+       case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+               elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation);
+               break;
+       case V4L2_CTRL_TYPE_FWHT_PARAMS:
+               elem_size = sizeof(struct v4l2_ctrl_fwht_params);
+               break;
+       case V4L2_CTRL_TYPE_H264_SPS:
+               elem_size = sizeof(struct v4l2_ctrl_h264_sps);
+               break;
+       case V4L2_CTRL_TYPE_H264_PPS:
+               elem_size = sizeof(struct v4l2_ctrl_h264_pps);
+               break;
+       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+               elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix);
+               break;
+       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+               elem_size = sizeof(struct v4l2_ctrl_h264_slice_params);
+               break;
+       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+               elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
+               break;
+       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+               elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
+               break;
+       case V4L2_CTRL_TYPE_VP8_FRAME:
+               elem_size = sizeof(struct v4l2_ctrl_vp8_frame);
+               break;
+       case V4L2_CTRL_TYPE_HEVC_SPS:
+               elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
+               break;
+       case V4L2_CTRL_TYPE_HEVC_PPS:
+               elem_size = sizeof(struct v4l2_ctrl_hevc_pps);
+               break;
+       case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+               elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
+               break;
+       case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+               elem_size = sizeof(struct v4l2_ctrl_hevc_decode_params);
+               break;
+       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+               elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info);
+               break;
+       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+               elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display);
+               break;
+       case V4L2_CTRL_TYPE_AREA:
+               elem_size = sizeof(struct v4l2_area);
+               break;
+       default:
+               if (type < V4L2_CTRL_COMPOUND_TYPES)
+                       elem_size = sizeof(s32);
+               break;
+       }
+       tot_ctrl_size = elem_size * elems;
+
+       /* Sanity checks */
+       if (id == 0 || name == NULL || !elem_size ||
+           id >= V4L2_CID_PRIVATE_BASE ||
+           (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+           (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
+               handler_set_err(hdl, -ERANGE);
+               return NULL;
+       }
+       err = check_range(type, min, max, step, def);
+       if (err) {
+               handler_set_err(hdl, err);
+               return NULL;
+       }
+       if (is_array &&
+           (type == V4L2_CTRL_TYPE_BUTTON ||
+            type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+
+       sz_extra = 0;
+       if (type == V4L2_CTRL_TYPE_BUTTON)
+               flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+                       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+       else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
+               flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
+                type == V4L2_CTRL_TYPE_STRING ||
+                type >= V4L2_CTRL_COMPOUND_TYPES ||
+                is_array)
+               sz_extra += 2 * tot_ctrl_size;
+
+       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
+               sz_extra += elem_size;
+
+       ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
+       if (ctrl == NULL) {
+               handler_set_err(hdl, -ENOMEM);
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&ctrl->node);
+       INIT_LIST_HEAD(&ctrl->ev_subs);
+       ctrl->handler = hdl;
+       ctrl->ops = ops;
+       ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
+       ctrl->id = id;
+       ctrl->name = name;
+       ctrl->type = type;
+       ctrl->flags = flags;
+       ctrl->minimum = min;
+       ctrl->maximum = max;
+       ctrl->step = step;
+       ctrl->default_value = def;
+       ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
+       ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
+       ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+       ctrl->is_array = is_array;
+       ctrl->elems = elems;
+       ctrl->nr_of_dims = nr_of_dims;
+       if (nr_of_dims)
+               memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
+       ctrl->elem_size = elem_size;
+       if (type == V4L2_CTRL_TYPE_MENU)
+               ctrl->qmenu = qmenu;
+       else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+               ctrl->qmenu_int = qmenu_int;
+       ctrl->priv = priv;
+       ctrl->cur.val = ctrl->val = def;
+       data = &ctrl[1];
+
+       if (!ctrl->is_int) {
+               ctrl->p_new.p = data;
+               ctrl->p_cur.p = data + tot_ctrl_size;
+       } else {
+               ctrl->p_new.p = &ctrl->val;
+               ctrl->p_cur.p = &ctrl->cur.val;
+       }
+
+       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
+               ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
+               memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
+       }
+
+       for (idx = 0; idx < elems; idx++) {
+               ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
+               ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+       }
+
+       if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
+               kvfree(ctrl);
+               return NULL;
+       }
+       mutex_lock(hdl->lock);
+       list_add_tail(&ctrl->node, &hdl->ctrls);
+       mutex_unlock(hdl->lock);
+       return ctrl;
+}
+
+struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_config *cfg, void *priv)
+{
+       bool is_menu;
+       struct v4l2_ctrl *ctrl;
+       const char *name = cfg->name;
+       const char * const *qmenu = cfg->qmenu;
+       const s64 *qmenu_int = cfg->qmenu_int;
+       enum v4l2_ctrl_type type = cfg->type;
+       u32 flags = cfg->flags;
+       s64 min = cfg->min;
+       s64 max = cfg->max;
+       u64 step = cfg->step;
+       s64 def = cfg->def;
+
+       if (name == NULL)
+               v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
+                                                               &def, &flags);
+
+       is_menu = (type == V4L2_CTRL_TYPE_MENU ||
+                  type == V4L2_CTRL_TYPE_INTEGER_MENU);
+       if (is_menu)
+               WARN_ON(step);
+       else
+               WARN_ON(cfg->menu_skip_mask);
+       if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
+               qmenu = v4l2_ctrl_get_menu(cfg->id);
+       } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+
+       ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
+                       type, min, max,
+                       is_menu ? cfg->menu_skip_mask : step, def,
+                       cfg->dims, cfg->elem_size,
+                       flags, qmenu, qmenu_int, cfg->p_def, priv);
+       if (ctrl)
+               ctrl->is_private = cfg->is_private;
+       return ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_custom);
+
+/* Helper function for standard non-menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops,
+                       u32 id, s64 min, s64 max, u64 step, s64 def)
+{
+       const char *name;
+       enum v4l2_ctrl_type type;
+       u32 flags;
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+       if (type == V4L2_CTRL_TYPE_MENU ||
+           type == V4L2_CTRL_TYPE_INTEGER_MENU ||
+           type >= V4L2_CTRL_COMPOUND_TYPES) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+                            min, max, step, def, NULL, 0,
+                            flags, NULL, NULL, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std);
+
+/* Helper function for standard menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops,
+                       u32 id, u8 _max, u64 mask, u8 _def)
+{
+       const char * const *qmenu = NULL;
+       const s64 *qmenu_int = NULL;
+       unsigned int qmenu_int_len = 0;
+       const char *name;
+       enum v4l2_ctrl_type type;
+       s64 min;
+       s64 max = _max;
+       s64 def = _def;
+       u64 step;
+       u32 flags;
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+
+       if (type == V4L2_CTRL_TYPE_MENU)
+               qmenu = v4l2_ctrl_get_menu(id);
+       else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+               qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
+
+       if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+                            0, max, mask, def, NULL, 0,
+                            flags, qmenu, qmenu_int, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
+
+/* Helper function for standard menu controls with driver defined menu */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
+                       u64 mask, u8 _def, const char * const *qmenu)
+{
+       enum v4l2_ctrl_type type;
+       const char *name;
+       u32 flags;
+       u64 step;
+       s64 min;
+       s64 max = _max;
+       s64 def = _def;
+
+       /* v4l2_ctrl_new_std_menu_items() should only be called for
+        * standard controls without a standard menu.
+        */
+       if (v4l2_ctrl_get_menu(id)) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+       if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+                            0, max, mask, def, NULL, 0,
+                            flags, qmenu, NULL, ptr_null, NULL);
+
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
+
+/* Helper function for standard compound controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
+                               const struct v4l2_ctrl_ops *ops, u32 id,
+                               const union v4l2_ctrl_ptr p_def)
+{
+       const char *name;
+       enum v4l2_ctrl_type type;
+       u32 flags;
+       s64 min, max, step, def;
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+       if (type < V4L2_CTRL_COMPOUND_TYPES) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+                            min, max, step, def, NULL, 0,
+                            flags, NULL, NULL, p_def, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
+
+/* Helper function for standard integer menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops,
+                       u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
+{
+       const char *name;
+       enum v4l2_ctrl_type type;
+       s64 min;
+       u64 step;
+       s64 max = _max;
+       s64 def = _def;
+       u32 flags;
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+       if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+                            0, max, 0, def, NULL, 0,
+                            flags, NULL, qmenu_int, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
+
+/* Add the controls from another handler to our own. */
+int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
+                         struct v4l2_ctrl_handler *add,
+                         bool (*filter)(const struct v4l2_ctrl *ctrl),
+                         bool from_other_dev)
+{
+       struct v4l2_ctrl_ref *ref;
+       int ret = 0;
+
+       /* Do nothing if either handler is NULL or if they are the same */
+       if (!hdl || !add || hdl == add)
+               return 0;
+       if (hdl->error)
+               return hdl->error;
+       mutex_lock(add->lock);
+       list_for_each_entry(ref, &add->ctrl_refs, node) {
+               struct v4l2_ctrl *ctrl = ref->ctrl;
+
+               /* Skip handler-private controls. */
+               if (ctrl->is_private)
+                       continue;
+               /* And control classes */
+               if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+                       continue;
+               /* Filter any unwanted controls */
+               if (filter && !filter(ctrl))
+                       continue;
+               ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
+               if (ret)
+                       break;
+       }
+       mutex_unlock(add->lock);
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_handler);
+
+bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
+{
+       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
+               return true;
+       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
+               return true;
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+       case V4L2_CID_AUDIO_LOUDNESS:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
+
+/* Cluster controls */
+void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
+{
+       bool has_volatiles = false;
+       int i;
+
+       /* The first control is the master control and it must not be NULL */
+       if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
+               return;
+
+       for (i = 0; i < ncontrols; i++) {
+               if (controls[i]) {
+                       controls[i]->cluster = controls;
+                       controls[i]->ncontrols = ncontrols;
+                       if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
+                               has_volatiles = true;
+               }
+       }
+       controls[0]->has_volatiles = has_volatiles;
+}
+EXPORT_SYMBOL(v4l2_ctrl_cluster);
+
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                           u8 manual_val, bool set_volatile)
+{
+       struct v4l2_ctrl *master = controls[0];
+       u32 flag = 0;
+       int i;
+
+       v4l2_ctrl_cluster(ncontrols, controls);
+       WARN_ON(ncontrols <= 1);
+       WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
+       WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
+       master->is_auto = true;
+       master->has_volatiles = set_volatile;
+       master->manual_mode_value = manual_val;
+       master->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+       if (!is_cur_manual(master))
+               flag = V4L2_CTRL_FLAG_INACTIVE |
+                       (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
+
+       for (i = 1; i < ncontrols; i++)
+               if (controls[i])
+                       controls[i]->flags |= flag;
+}
+EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
+
+/*
+ * Obtain the current volatile values of an autocluster and mark them
+ * as new.
+ */
+void update_from_auto_cluster(struct v4l2_ctrl *master)
+{
+       int i;
+
+       for (i = 1; i < master->ncontrols; i++)
+               cur_to_new(master->cluster[i]);
+       if (!call_op(master, g_volatile_ctrl))
+               for (i = 1; i < master->ncontrols; i++)
+                       if (master->cluster[i])
+                               master->cluster[i]->is_new = 1;
+}
+
+/*
+ * Return non-zero if one or more of the controls in the cluster has a new
+ * value that differs from the current value.
+ */
+static int cluster_changed(struct v4l2_ctrl *master)
+{
+       bool changed = false;
+       unsigned int idx;
+       int i;
+
+       for (i = 0; i < master->ncontrols; i++) {
+               struct v4l2_ctrl *ctrl = master->cluster[i];
+               bool ctrl_changed = false;
+
+               if (!ctrl)
+                       continue;
+
+               if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) {
+                       changed = true;
+                       ctrl_changed = true;
+               }
+
+               /*
+                * Set has_changed to false to avoid generating
+                * the event V4L2_EVENT_CTRL_CH_VALUE
+                */
+               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+                       ctrl->has_changed = false;
+                       continue;
+               }
+
+               for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
+                       ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
+                               ctrl->p_cur, ctrl->p_new);
+               ctrl->has_changed = ctrl_changed;
+               changed |= ctrl->has_changed;
+       }
+       return changed;
+}
+
+/*
+ * Core function that calls try/s_ctrl and ensures that the new value is
+ * copied to the current value on a set.
+ * Must be called with ctrl->handler->lock held.
+ */
+int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
+                      bool set, u32 ch_flags)
+{
+       bool update_flag;
+       int ret;
+       int i;
+
+       /*
+        * Go through the cluster and either validate the new value or
+        * (if no new value was set), copy the current value to the new
+        * value, ensuring a consistent view for the control ops when
+        * called.
+        */
+       for (i = 0; i < master->ncontrols; i++) {
+               struct v4l2_ctrl *ctrl = master->cluster[i];
+
+               if (!ctrl)
+                       continue;
+
+               if (!ctrl->is_new) {
+                       cur_to_new(ctrl);
+                       continue;
+               }
+               /*
+                * Check again: it may have changed since the
+                * previous check in try_or_set_ext_ctrls().
+                */
+               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+                       return -EBUSY;
+       }
+
+       ret = call_op(master, try_ctrl);
+
+       /* Don't set if there is no change */
+       if (ret || !set || !cluster_changed(master))
+               return ret;
+       ret = call_op(master, s_ctrl);
+       if (ret)
+               return ret;
+
+       /* If OK, then make the new values permanent. */
+       update_flag = is_cur_manual(master) != is_new_manual(master);
+
+       for (i = 0; i < master->ncontrols; i++) {
+               /*
+                * If we switch from auto to manual mode, and this cluster
+                * contains volatile controls, then all non-master controls
+                * have to be marked as changed. The 'new' value contains
+                * the volatile value (obtained by update_from_auto_cluster),
+                * which now has to become the current value.
+                */
+               if (i && update_flag && is_new_manual(master) &&
+                   master->has_volatiles && master->cluster[i])
+                       master->cluster[i]->has_changed = true;
+
+               new_to_cur(fh, master->cluster[i], ch_flags |
+                       ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+       }
+       return 0;
+}
+
+/* Activate/deactivate a control. */
+void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
+{
+       /* invert since the actual flag is called 'inactive' */
+       bool inactive = !active;
+       bool old;
+
+       if (ctrl == NULL)
+               return;
+
+       if (inactive)
+               /* set V4L2_CTRL_FLAG_INACTIVE */
+               old = test_and_set_bit(4, &ctrl->flags);
+       else
+               /* clear V4L2_CTRL_FLAG_INACTIVE */
+               old = test_and_clear_bit(4, &ctrl->flags);
+       if (old != inactive)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+}
+EXPORT_SYMBOL(v4l2_ctrl_activate);
+
+void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
+{
+       bool old;
+
+       if (ctrl == NULL)
+               return;
+
+       lockdep_assert_held(ctrl->handler->lock);
+
+       if (grabbed)
+               /* set V4L2_CTRL_FLAG_GRABBED */
+               old = test_and_set_bit(1, &ctrl->flags);
+       else
+               /* clear V4L2_CTRL_FLAG_GRABBED */
+               old = test_and_clear_bit(1, &ctrl->flags);
+       if (old != grabbed)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_grab);
+
+/* Call s_ctrl for all controls owned by the handler */
+int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+       struct v4l2_ctrl *ctrl;
+       int ret = 0;
+
+       if (hdl == NULL)
+               return 0;
+
+       lockdep_assert_held(hdl->lock);
+
+       list_for_each_entry(ctrl, &hdl->ctrls, node)
+               ctrl->done = false;
+
+       list_for_each_entry(ctrl, &hdl->ctrls, node) {
+               struct v4l2_ctrl *master = ctrl->cluster[0];
+               int i;
+
+               /* Skip if this control was already handled by a cluster. */
+               /* Skip button controls and read-only controls. */
+               if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+                       continue;
+
+               for (i = 0; i < master->ncontrols; i++) {
+                       if (master->cluster[i]) {
+                               cur_to_new(master->cluster[i]);
+                               master->cluster[i]->is_new = 1;
+                               master->cluster[i]->done = true;
+                       }
+               }
+               ret = call_op(master, s_ctrl);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup);
+
+int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+       int ret;
+
+       if (hdl == NULL)
+               return 0;
+
+       mutex_lock(hdl->lock);
+       ret = __v4l2_ctrl_handler_setup(hdl);
+       mutex_unlock(hdl->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
+
+/* Log the control name and value */
+static void log_ctrl(const struct v4l2_ctrl *ctrl,
+                    const char *prefix, const char *colon)
+{
+       if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
+               return;
+       if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+               return;
+
+       pr_info("%s%s%s: ", prefix, colon, ctrl->name);
+
+       ctrl->type_ops->log(ctrl);
+
+       if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
+                          V4L2_CTRL_FLAG_GRABBED |
+                          V4L2_CTRL_FLAG_VOLATILE)) {
+               if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+                       pr_cont(" inactive");
+               if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+                       pr_cont(" grabbed");
+               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
+                       pr_cont(" volatile");
+       }
+       pr_cont("\n");
+}
+
+/* Log all controls owned by the handler */
+void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
+                                 const char *prefix)
+{
+       struct v4l2_ctrl *ctrl;
+       const char *colon = "";
+       int len;
+
+       if (!hdl)
+               return;
+       if (!prefix)
+               prefix = "";
+       len = strlen(prefix);
+       if (len && prefix[len - 1] != ' ')
+               colon = ": ";
+       mutex_lock(hdl->lock);
+       list_for_each_entry(ctrl, &hdl->ctrls, node)
+               if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
+                       log_ctrl(ctrl, prefix, colon);
+       mutex_unlock(hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
+
+int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
+                                   const struct v4l2_ctrl_ops *ctrl_ops,
+                                   const struct v4l2_fwnode_device_properties *p)
+{
+       if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
+               u32 orientation_ctrl;
+
+               switch (p->orientation) {
+               case V4L2_FWNODE_ORIENTATION_FRONT:
+                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT;
+                       break;
+               case V4L2_FWNODE_ORIENTATION_BACK:
+                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK;
+                       break;
+               case V4L2_FWNODE_ORIENTATION_EXTERNAL:
+                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops,
+                                           V4L2_CID_CAMERA_ORIENTATION,
+                                           V4L2_CAMERA_ORIENTATION_EXTERNAL, 0,
+                                           orientation_ctrl))
+                       return hdl->error;
+       }
+
+       if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
+               if (!v4l2_ctrl_new_std(hdl, ctrl_ops,
+                                      V4L2_CID_CAMERA_SENSOR_ROTATION,
+                                      p->rotation, p->rotation, 1,
+                                      p->rotation))
+                       return hdl->error;
+       }
+
+       return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
new file mode 100644 (file)
index 0000000..b6344bb
--- /dev/null
@@ -0,0 +1,1579 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework control definitions.
+ *
+ * Copyright (C) 2010-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#include <linux/export.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * Returns NULL or a character pointer array containing the menu for
+ * the given control ID. The pointer array ends with a NULL pointer.
+ * An empty string signifies a menu entry that is invalid. This allows
+ * drivers to disable certain options if it is not supported.
+ */
+const char * const *v4l2_ctrl_get_menu(u32 id)
+{
+       static const char * const mpeg_audio_sampling_freq[] = {
+               "44.1 kHz",
+               "48 kHz",
+               "32 kHz",
+               NULL
+       };
+       static const char * const mpeg_audio_encoding[] = {
+               "MPEG-1/2 Layer I",
+               "MPEG-1/2 Layer II",
+               "MPEG-1/2 Layer III",
+               "MPEG-2/4 AAC",
+               "AC-3",
+               NULL
+       };
+       static const char * const mpeg_audio_l1_bitrate[] = {
+               "32 kbps",
+               "64 kbps",
+               "96 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "288 kbps",
+               "320 kbps",
+               "352 kbps",
+               "384 kbps",
+               "416 kbps",
+               "448 kbps",
+               NULL
+       };
+       static const char * const mpeg_audio_l2_bitrate[] = {
+               "32 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               "384 kbps",
+               NULL
+       };
+       static const char * const mpeg_audio_l3_bitrate[] = {
+               "32 kbps",
+               "40 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               NULL
+       };
+       static const char * const mpeg_audio_ac3_bitrate[] = {
+               "32 kbps",
+               "40 kbps",
+               "48 kbps",
+               "56 kbps",
+               "64 kbps",
+               "80 kbps",
+               "96 kbps",
+               "112 kbps",
+               "128 kbps",
+               "160 kbps",
+               "192 kbps",
+               "224 kbps",
+               "256 kbps",
+               "320 kbps",
+               "384 kbps",
+               "448 kbps",
+               "512 kbps",
+               "576 kbps",
+               "640 kbps",
+               NULL
+       };
+       static const char * const mpeg_audio_mode[] = {
+               "Stereo",
+               "Joint Stereo",
+               "Dual",
+               "Mono",
+               NULL
+       };
+       static const char * const mpeg_audio_mode_extension[] = {
+               "Bound 4",
+               "Bound 8",
+               "Bound 12",
+               "Bound 16",
+               NULL
+       };
+       static const char * const mpeg_audio_emphasis[] = {
+               "No Emphasis",
+               "50/15 us",
+               "CCITT J17",
+               NULL
+       };
+       static const char * const mpeg_audio_crc[] = {
+               "No CRC",
+               "16-bit CRC",
+               NULL
+       };
+       static const char * const mpeg_audio_dec_playback[] = {
+               "Auto",
+               "Stereo",
+               "Left",
+               "Right",
+               "Mono",
+               "Swapped Stereo",
+               NULL
+       };
+       static const char * const mpeg_video_encoding[] = {
+               "MPEG-1",
+               "MPEG-2",
+               "MPEG-4 AVC",
+               NULL
+       };
+       static const char * const mpeg_video_aspect[] = {
+               "1x1",
+               "4x3",
+               "16x9",
+               "2.21x1",
+               NULL
+       };
+       static const char * const mpeg_video_bitrate_mode[] = {
+               "Variable Bitrate",
+               "Constant Bitrate",
+               "Constant Quality",
+               NULL
+       };
+       static const char * const mpeg_stream_type[] = {
+               "MPEG-2 Program Stream",
+               "MPEG-2 Transport Stream",
+               "MPEG-1 System Stream",
+               "MPEG-2 DVD-compatible Stream",
+               "MPEG-1 VCD-compatible Stream",
+               "MPEG-2 SVCD-compatible Stream",
+               NULL
+       };
+       static const char * const mpeg_stream_vbi_fmt[] = {
+               "No VBI",
+               "Private Packet, IVTV Format",
+               NULL
+       };
+       static const char * const camera_power_line_frequency[] = {
+               "Disabled",
+               "50 Hz",
+               "60 Hz",
+               "Auto",
+               NULL
+       };
+       static const char * const camera_exposure_auto[] = {
+               "Auto Mode",
+               "Manual Mode",
+               "Shutter Priority Mode",
+               "Aperture Priority Mode",
+               NULL
+       };
+       static const char * const camera_exposure_metering[] = {
+               "Average",
+               "Center Weighted",
+               "Spot",
+               "Matrix",
+               NULL
+       };
+       static const char * const camera_auto_focus_range[] = {
+               "Auto",
+               "Normal",
+               "Macro",
+               "Infinity",
+               NULL
+       };
+       static const char * const colorfx[] = {
+               "None",
+               "Black & White",
+               "Sepia",
+               "Negative",
+               "Emboss",
+               "Sketch",
+               "Sky Blue",
+               "Grass Green",
+               "Skin Whiten",
+               "Vivid",
+               "Aqua",
+               "Art Freeze",
+               "Silhouette",
+               "Solarization",
+               "Antique",
+               "Set Cb/Cr",
+               NULL
+       };
+       static const char * const auto_n_preset_white_balance[] = {
+               "Manual",
+               "Auto",
+               "Incandescent",
+               "Fluorescent",
+               "Fluorescent H",
+               "Horizon",
+               "Daylight",
+               "Flash",
+               "Cloudy",
+               "Shade",
+               NULL,
+       };
+       static const char * const camera_iso_sensitivity_auto[] = {
+               "Manual",
+               "Auto",
+               NULL
+       };
+       static const char * const scene_mode[] = {
+               "None",
+               "Backlight",
+               "Beach/Snow",
+               "Candle Light",
+               "Dusk/Dawn",
+               "Fall Colors",
+               "Fireworks",
+               "Landscape",
+               "Night",
+               "Party/Indoor",
+               "Portrait",
+               "Sports",
+               "Sunset",
+               "Text",
+               NULL
+       };
+       static const char * const tune_emphasis[] = {
+               "None",
+               "50 Microseconds",
+               "75 Microseconds",
+               NULL,
+       };
+       static const char * const header_mode[] = {
+               "Separate Buffer",
+               "Joined With 1st Frame",
+               NULL,
+       };
+       static const char * const multi_slice[] = {
+               "Single",
+               "Max Macroblocks",
+               "Max Bytes",
+               NULL,
+       };
+       static const char * const entropy_mode[] = {
+               "CAVLC",
+               "CABAC",
+               NULL,
+       };
+       static const char * const mpeg_h264_level[] = {
+               "1",
+               "1b",
+               "1.1",
+               "1.2",
+               "1.3",
+               "2",
+               "2.1",
+               "2.2",
+               "3",
+               "3.1",
+               "3.2",
+               "4",
+               "4.1",
+               "4.2",
+               "5",
+               "5.1",
+               "5.2",
+               "6.0",
+               "6.1",
+               "6.2",
+               NULL,
+       };
+       static const char * const h264_loop_filter[] = {
+               "Enabled",
+               "Disabled",
+               "Disabled at Slice Boundary",
+               NULL,
+       };
+       static const char * const h264_profile[] = {
+               "Baseline",
+               "Constrained Baseline",
+               "Main",
+               "Extended",
+               "High",
+               "High 10",
+               "High 422",
+               "High 444 Predictive",
+               "High 10 Intra",
+               "High 422 Intra",
+               "High 444 Intra",
+               "CAVLC 444 Intra",
+               "Scalable Baseline",
+               "Scalable High",
+               "Scalable High Intra",
+               "Stereo High",
+               "Multiview High",
+               "Constrained High",
+               NULL,
+       };
+       static const char * const vui_sar_idc[] = {
+               "Unspecified",
+               "1:1",
+               "12:11",
+               "10:11",
+               "16:11",
+               "40:33",
+               "24:11",
+               "20:11",
+               "32:11",
+               "80:33",
+               "18:11",
+               "15:11",
+               "64:33",
+               "160:99",
+               "4:3",
+               "3:2",
+               "2:1",
+               "Extended SAR",
+               NULL,
+       };
+       static const char * const h264_fp_arrangement_type[] = {
+               "Checkerboard",
+               "Column",
+               "Row",
+               "Side by Side",
+               "Top Bottom",
+               "Temporal",
+               NULL,
+       };
+       static const char * const h264_fmo_map_type[] = {
+               "Interleaved Slices",
+               "Scattered Slices",
+               "Foreground with Leftover",
+               "Box Out",
+               "Raster Scan",
+               "Wipe Scan",
+               "Explicit",
+               NULL,
+       };
+       static const char * const h264_decode_mode[] = {
+               "Slice-Based",
+               "Frame-Based",
+               NULL,
+       };
+       static const char * const h264_start_code[] = {
+               "No Start Code",
+               "Annex B Start Code",
+               NULL,
+       };
+       static const char * const h264_hierarchical_coding_type[] = {
+               "Hier Coding B",
+               "Hier Coding P",
+               NULL,
+       };
+       static const char * const mpeg_mpeg2_level[] = {
+               "Low",
+               "Main",
+               "High 1440",
+               "High",
+               NULL,
+       };
+       static const char * const mpeg2_profile[] = {
+               "Simple",
+               "Main",
+               "SNR Scalable",
+               "Spatially Scalable",
+               "High",
+               NULL,
+       };
+       static const char * const mpeg_mpeg4_level[] = {
+               "0",
+               "0b",
+               "1",
+               "2",
+               "3",
+               "3b",
+               "4",
+               "5",
+               NULL,
+       };
+       static const char * const mpeg4_profile[] = {
+               "Simple",
+               "Advanced Simple",
+               "Core",
+               "Simple Scalable",
+               "Advanced Coding Efficiency",
+               NULL,
+       };
+
+       static const char * const vpx_golden_frame_sel[] = {
+               "Use Previous Frame",
+               "Use Previous Specific Frame",
+               NULL,
+       };
+       static const char * const vp8_profile[] = {
+               "0",
+               "1",
+               "2",
+               "3",
+               NULL,
+       };
+       static const char * const vp9_profile[] = {
+               "0",
+               "1",
+               "2",
+               "3",
+               NULL,
+       };
+       static const char * const vp9_level[] = {
+               "1",
+               "1.1",
+               "2",
+               "2.1",
+               "3",
+               "3.1",
+               "4",
+               "4.1",
+               "5",
+               "5.1",
+               "5.2",
+               "6",
+               "6.1",
+               "6.2",
+               NULL,
+       };
+
+       static const char * const flash_led_mode[] = {
+               "Off",
+               "Flash",
+               "Torch",
+               NULL,
+       };
+       static const char * const flash_strobe_source[] = {
+               "Software",
+               "External",
+               NULL,
+       };
+
+       static const char * const jpeg_chroma_subsampling[] = {
+               "4:4:4",
+               "4:2:2",
+               "4:2:0",
+               "4:1:1",
+               "4:1:0",
+               "Gray",
+               NULL,
+       };
+       static const char * const dv_tx_mode[] = {
+               "DVI-D",
+               "HDMI",
+               NULL,
+       };
+       static const char * const dv_rgb_range[] = {
+               "Automatic",
+               "RGB Limited Range (16-235)",
+               "RGB Full Range (0-255)",
+               NULL,
+       };
+       static const char * const dv_it_content_type[] = {
+               "Graphics",
+               "Photo",
+               "Cinema",
+               "Game",
+               "No IT Content",
+               NULL,
+       };
+       static const char * const detect_md_mode[] = {
+               "Disabled",
+               "Global",
+               "Threshold Grid",
+               "Region Grid",
+               NULL,
+       };
+
+       static const char * const hevc_profile[] = {
+               "Main",
+               "Main Still Picture",
+               "Main 10",
+               NULL,
+       };
+       static const char * const hevc_level[] = {
+               "1",
+               "2",
+               "2.1",
+               "3",
+               "3.1",
+               "4",
+               "4.1",
+               "5",
+               "5.1",
+               "5.2",
+               "6",
+               "6.1",
+               "6.2",
+               NULL,
+       };
+       static const char * const hevc_hierarchial_coding_type[] = {
+               "B",
+               "P",
+               NULL,
+       };
+       static const char * const hevc_refresh_type[] = {
+               "None",
+               "CRA",
+               "IDR",
+               NULL,
+       };
+       static const char * const hevc_size_of_length_field[] = {
+               "0",
+               "1",
+               "2",
+               "4",
+               NULL,
+       };
+       static const char * const hevc_tier[] = {
+               "Main",
+               "High",
+               NULL,
+       };
+       static const char * const hevc_loop_filter_mode[] = {
+               "Disabled",
+               "Enabled",
+               "Disabled at slice boundary",
+               "NULL",
+       };
+       static const char * const hevc_decode_mode[] = {
+               "Slice-Based",
+               "Frame-Based",
+               NULL,
+       };
+       static const char * const hevc_start_code[] = {
+               "No Start Code",
+               "Annex B Start Code",
+               NULL,
+       };
+       static const char * const camera_orientation[] = {
+               "Front",
+               "Back",
+               "External",
+               NULL,
+       };
+       static const char * const mpeg_video_frame_skip[] = {
+               "Disabled",
+               "Level Limit",
+               "VBV/CPB Limit",
+               NULL,
+       };
+
+       switch (id) {
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               return mpeg_audio_sampling_freq;
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return mpeg_audio_encoding;
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+               return mpeg_audio_l1_bitrate;
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               return mpeg_audio_l2_bitrate;
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+               return mpeg_audio_l3_bitrate;
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+               return mpeg_audio_ac3_bitrate;
+       case V4L2_CID_MPEG_AUDIO_MODE:
+               return mpeg_audio_mode;
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+               return mpeg_audio_mode_extension;
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+               return mpeg_audio_emphasis;
+       case V4L2_CID_MPEG_AUDIO_CRC:
+               return mpeg_audio_crc;
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+               return mpeg_audio_dec_playback;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return mpeg_video_encoding;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return mpeg_video_aspect;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return mpeg_video_bitrate_mode;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return mpeg_stream_type;
+       case V4L2_CID_MPEG_STREAM_VBI_FMT:
+               return mpeg_stream_vbi_fmt;
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               return camera_power_line_frequency;
+       case V4L2_CID_EXPOSURE_AUTO:
+               return camera_exposure_auto;
+       case V4L2_CID_EXPOSURE_METERING:
+               return camera_exposure_metering;
+       case V4L2_CID_AUTO_FOCUS_RANGE:
+               return camera_auto_focus_range;
+       case V4L2_CID_COLORFX:
+               return colorfx;
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+               return auto_n_preset_white_balance;
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:
+               return camera_iso_sensitivity_auto;
+       case V4L2_CID_SCENE_MODE:
+               return scene_mode;
+       case V4L2_CID_TUNE_PREEMPHASIS:
+               return tune_emphasis;
+       case V4L2_CID_TUNE_DEEMPHASIS:
+               return tune_emphasis;
+       case V4L2_CID_FLASH_LED_MODE:
+               return flash_led_mode;
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+               return flash_strobe_source;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               return header_mode;
+       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+               return mpeg_video_frame_skip;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               return multi_slice;
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+               return entropy_mode;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               return mpeg_h264_level;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               return h264_loop_filter;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               return h264_profile;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+               return vui_sar_idc;
+       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+               return h264_fp_arrangement_type;
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+               return h264_fmo_map_type;
+       case V4L2_CID_STATELESS_H264_DECODE_MODE:
+               return h264_decode_mode;
+       case V4L2_CID_STATELESS_H264_START_CODE:
+               return h264_start_code;
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+               return h264_hierarchical_coding_type;
+       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
+               return mpeg_mpeg2_level;
+       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
+               return mpeg2_profile;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+               return mpeg_mpeg4_level;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+               return mpeg4_profile;
+       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
+               return vpx_golden_frame_sel;
+       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+               return vp8_profile;
+       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+               return vp9_profile;
+       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+               return vp9_level;
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+               return jpeg_chroma_subsampling;
+       case V4L2_CID_DV_TX_MODE:
+               return dv_tx_mode;
+       case V4L2_CID_DV_TX_RGB_RANGE:
+       case V4L2_CID_DV_RX_RGB_RANGE:
+               return dv_rgb_range;
+       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
+       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+               return dv_it_content_type;
+       case V4L2_CID_DETECT_MD_MODE:
+               return detect_md_mode;
+       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+               return hevc_profile;
+       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+               return hevc_level;
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+               return hevc_hierarchial_coding_type;
+       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+               return hevc_refresh_type;
+       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+               return hevc_size_of_length_field;
+       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+               return hevc_tier;
+       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+               return hevc_loop_filter_mode;
+       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
+               return hevc_decode_mode;
+       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+               return hevc_start_code;
+       case V4L2_CID_CAMERA_ORIENTATION:
+               return camera_orientation;
+       default:
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+
+#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); (arr); })
+/*
+ * Returns NULL or an s64 type array containing the menu for given
+ * control ID. The total number of the menu items is returned in @len.
+ */
+const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
+{
+       static const s64 qmenu_int_vpx_num_partitions[] = {
+               1, 2, 4, 8,
+       };
+
+       static const s64 qmenu_int_vpx_num_ref_frames[] = {
+               1, 2, 3,
+       };
+
+       switch (id) {
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
+               return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len);
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
+               return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len);
+       default:
+               *len = 0;
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_int_menu);
+
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
+{
+       switch (id) {
+       /* USER controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_USER_CLASS:               return "User Controls";
+       case V4L2_CID_BRIGHTNESS:               return "Brightness";
+       case V4L2_CID_CONTRAST:                 return "Contrast";
+       case V4L2_CID_SATURATION:               return "Saturation";
+       case V4L2_CID_HUE:                      return "Hue";
+       case V4L2_CID_AUDIO_VOLUME:             return "Volume";
+       case V4L2_CID_AUDIO_BALANCE:            return "Balance";
+       case V4L2_CID_AUDIO_BASS:               return "Bass";
+       case V4L2_CID_AUDIO_TREBLE:             return "Treble";
+       case V4L2_CID_AUDIO_MUTE:               return "Mute";
+       case V4L2_CID_AUDIO_LOUDNESS:           return "Loudness";
+       case V4L2_CID_BLACK_LEVEL:              return "Black Level";
+       case V4L2_CID_AUTO_WHITE_BALANCE:       return "White Balance, Automatic";
+       case V4L2_CID_DO_WHITE_BALANCE:         return "Do White Balance";
+       case V4L2_CID_RED_BALANCE:              return "Red Balance";
+       case V4L2_CID_BLUE_BALANCE:             return "Blue Balance";
+       case V4L2_CID_GAMMA:                    return "Gamma";
+       case V4L2_CID_EXPOSURE:                 return "Exposure";
+       case V4L2_CID_AUTOGAIN:                 return "Gain, Automatic";
+       case V4L2_CID_GAIN:                     return "Gain";
+       case V4L2_CID_HFLIP:                    return "Horizontal Flip";
+       case V4L2_CID_VFLIP:                    return "Vertical Flip";
+       case V4L2_CID_POWER_LINE_FREQUENCY:     return "Power Line Frequency";
+       case V4L2_CID_HUE_AUTO:                 return "Hue, Automatic";
+       case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
+       case V4L2_CID_SHARPNESS:                return "Sharpness";
+       case V4L2_CID_BACKLIGHT_COMPENSATION:   return "Backlight Compensation";
+       case V4L2_CID_CHROMA_AGC:               return "Chroma AGC";
+       case V4L2_CID_COLOR_KILLER:             return "Color Killer";
+       case V4L2_CID_COLORFX:                  return "Color Effects";
+       case V4L2_CID_AUTOBRIGHTNESS:           return "Brightness, Automatic";
+       case V4L2_CID_BAND_STOP_FILTER:         return "Band-Stop Filter";
+       case V4L2_CID_ROTATE:                   return "Rotate";
+       case V4L2_CID_BG_COLOR:                 return "Background Color";
+       case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
+       case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
+       case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Min Number of Capture Buffers";
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Min Number of Output Buffers";
+       case V4L2_CID_ALPHA_COMPONENT:          return "Alpha Component";
+       case V4L2_CID_COLORFX_CBCR:             return "Color Effects, CbCr";
+
+       /*
+        * Codec controls
+        *
+        * The MPEG controls are applicable to all codec controls
+        * and the 'MPEG' part of the define is historical.
+        *
+        * Keep the order of the 'case's the same as in videodev2.h!
+        */
+       case V4L2_CID_CODEC_CLASS:              return "Codec Controls";
+       case V4L2_CID_MPEG_STREAM_TYPE:         return "Stream Type";
+       case V4L2_CID_MPEG_STREAM_PID_PMT:      return "Stream PMT Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:    return "Stream Audio Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:    return "Stream Video Program ID";
+       case V4L2_CID_MPEG_STREAM_PID_PCR:      return "Stream PCR Program ID";
+       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+       case V4L2_CID_MPEG_STREAM_VBI_FMT:      return "Stream VBI Format";
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+       case V4L2_CID_MPEG_AUDIO_ENCODING:      return "Audio Encoding";
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:    return "Audio Layer I Bitrate";
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:    return "Audio Layer II Bitrate";
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:    return "Audio Layer III Bitrate";
+       case V4L2_CID_MPEG_AUDIO_MODE:          return "Audio Stereo Mode";
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:      return "Audio Emphasis";
+       case V4L2_CID_MPEG_AUDIO_CRC:           return "Audio CRC";
+       case V4L2_CID_MPEG_AUDIO_MUTE:          return "Audio Mute";
+       case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:   return "Audio AAC Bitrate";
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:   return "Audio AC-3 Bitrate";
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:  return "Audio Playback";
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
+       case V4L2_CID_MPEG_VIDEO_ENCODING:      return "Video Encoding";
+       case V4L2_CID_MPEG_VIDEO_ASPECT:        return "Video Aspect";
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:      return "Video B Frames";
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:      return "Video GOP Size";
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:   return "Video GOP Closure";
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:      return "Video Pulldown";
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:  return "Video Bitrate Mode";
+       case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY:      return "Constant Quality";
+       case V4L2_CID_MPEG_VIDEO_BITRATE:       return "Video Bitrate";
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:  return "Video Peak Bitrate";
+       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+       case V4L2_CID_MPEG_VIDEO_MUTE:          return "Video Mute";
+       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:       return "Decoder Slice Interface";
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:  return "MPEG4 Loop Filter Enable";
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "Number of Intra Refresh MBs";
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:               return "Frame Level Rate Control Enable";
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:                  return "H264 MB Level Rate Control";
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:                   return "Sequence Header Mode";
+       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "Max Number of Reference Pics";
+       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:               return "Frame Skip Mode";
+       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:             return "Display Delay";
+       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:      return "Display Delay Enable";
+       case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:                  return "Generate Access Unit Delimiters";
+       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:               return "H263 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:                   return "H263 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:                   return "H263 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:               return "H264 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:                   return "H264 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:                   return "H264 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:            return "H264 8x8 Transform Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:                 return "H264 CPB Buffer Size";
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entropy Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I-Frame Period";
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:                    return "H264 Level";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:        return "H264 Loop Filter Alpha Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:         return "H264 Loop Filter Beta Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:         return "H264 Loop Filter Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:                  return "H264 Profile";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:       return "Vertical Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:        return "Horizontal Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:           return "Aspect Ratio VUI Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:              return "VUI Aspect Ratio IDC";
+       case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:        return "H264 Enable Frame Packing SEI";
+       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0:   return "H264 Set Curr. Frame as Frame0";
+       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:  return "H264 FP Arrangement Type";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO:                      return "H264 Flexible MB Ordering";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:             return "H264 Map Type for FMO";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP:          return "H264 FMO Number of Slice Groups";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION:     return "H264 FMO Direction of Change";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE:          return "H264 FMO Size of 1st Slice Grp";
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH:           return "H264 FMO No. of Consecutive MBs";
+       case V4L2_CID_MPEG_VIDEO_H264_ASO:                      return "H264 Arbitrary Slice Ordering";
+       case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER:          return "H264 ASO Slice Order";
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:      return "Enable H264 Hierarchical Coding";
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type";
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers";
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
+                                                               return "H264 Set QP Value for HC Layers";
+       case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
+                                                               return "H264 Constrained Intra Pred";
+       case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:   return "H264 Chroma QP Index Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP:           return "H264 I-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP:           return "H264 I-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP:           return "H264 P-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP:           return "H264 P-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP:           return "H264 B-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP:           return "H264 B-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR:        return "H264 Hierarchical Lay 0 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR:        return "H264 Hierarchical Lay 1 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR:        return "H264 Hierarchical Lay 2 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR:        return "H264 Hierarchical Lay 3 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR:        return "H264 Hierarchical Lay 4 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR:        return "H264 Hierarchical Lay 5 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR:        return "H264 Hierarchical Lay 6 Bitrate";
+       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:                   return "MPEG2 Level";
+       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:                 return "MPEG2 Profile";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:              return "MPEG4 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:                  return "MPEG4 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:                  return "MPEG4 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:                   return "MPEG4 Level";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:                 return "MPEG4 Profile";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:                    return "Quarter Pixel Search Enable";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "Maximum Bytes in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "Number of MBs in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "Slice Partitioning Method";
+       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
+       case V4L2_CID_MPEG_VIDEO_DEC_PTS:                       return "Video Decoder PTS";
+       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:                     return "Video Decoder Frame Count";
+       case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:             return "Video Decoder Conceal Color";
+       case V4L2_CID_MPEG_VIDEO_VBV_DELAY:                     return "Initial Delay for VBV Control";
+       case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:             return "Horizontal MV Search Range";
+       case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:             return "Vertical MV Search Range";
+       case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:             return "Repeat Sequence Header";
+       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:               return "Force Key Frame";
+       case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID:         return "Base Layer Priority ID";
+       case V4L2_CID_MPEG_VIDEO_LTR_COUNT:                     return "LTR Count";
+       case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:               return "Frame LTR Index";
+       case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:                return "Use LTR Frames";
+       case V4L2_CID_FWHT_I_FRAME_QP:                          return "FWHT I-Frame QP Value";
+       case V4L2_CID_FWHT_P_FRAME_QP:                          return "FWHT P-Frame QP Value";
+
+       /* VPX controls */
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:            return "VPX Number of Partitions";
+       case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4:           return "VPX Intra Mode Decision Disable";
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:            return "VPX No. of Refs for P Frame";
+       case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL:              return "VPX Loop Filter Level Range";
+       case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS:          return "VPX Deblocking Effect Control";
+       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD:   return "VPX Golden Frame Refresh Period";
+       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:          return "VPX Golden Frame Indicator";
+       case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:                    return "VPX Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:                    return "VPX Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP:                return "VPX I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP:                return "VPX P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:                   return "VP8 Profile";
+       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:                   return "VP9 Profile";
+       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:                     return "VP9 Level";
+
+       /* HEVC controls */
+       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:               return "HEVC I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:               return "HEVC P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:               return "HEVC B-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:                   return "HEVC Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:                   return "HEVC Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP:           return "HEVC I-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP:           return "HEVC I-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP:           return "HEVC P-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP:           return "HEVC P-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP:           return "HEVC B-Frame Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP:           return "HEVC B-Frame Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:                  return "HEVC Profile";
+       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:                    return "HEVC Level";
+       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:                     return "HEVC Tier";
+       case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION:    return "HEVC Frame Rate Resolution";
+       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH:      return "HEVC Maximum Coding Unit Depth";
+       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:             return "HEVC Refresh Type";
+       case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:         return "HEVC Constant Intra Prediction";
+       case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU:              return "HEVC Lossless Encoding";
+       case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT:                return "HEVC Wavefront";
+       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:         return "HEVC Loop Filter";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP:                  return "HEVC QP Values";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:         return "HEVC Hierarchical Coding Type";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER:        return "HEVC Hierarchical Coding Layer";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP:        return "HEVC Hierarchical Layer 0 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP:        return "HEVC Hierarchical Layer 1 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP:        return "HEVC Hierarchical Layer 2 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP:        return "HEVC Hierarchical Layer 3 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP:        return "HEVC Hierarchical Layer 4 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP:        return "HEVC Hierarchical Layer 5 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP:        return "HEVC Hierarchical Layer 6 QP";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR:        return "HEVC Hierarchical Lay 0 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR:        return "HEVC Hierarchical Lay 1 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR:        return "HEVC Hierarchical Lay 2 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR:        return "HEVC Hierarchical Lay 3 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR:        return "HEVC Hierarchical Lay 4 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR:        return "HEVC Hierarchical Lay 5 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR:        return "HEVC Hierarchical Lay 6 BitRate";
+       case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB:               return "HEVC General PB";
+       case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID:              return "HEVC Temporal ID";
+       case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:         return "HEVC Strong Intra Smoothing";
+       case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT:           return "HEVC Intra PU Split";
+       case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:           return "HEVC TMV Prediction";
+       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:  return "HEVC Max Num of Candidate MVs";
+       case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE:        return "HEVC ENC Without Startcode";
+       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:           return "HEVC Num of I-Frame b/w 2 IDR";
+       case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:      return "HEVC Loop Filter Beta Offset";
+       case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:        return "HEVC Loop Filter TC Offset";
+       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:     return "HEVC Size of Length Field";
+       case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES:        return "Reference Frames for a P-Frame";
+       case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:         return "Prepend SPS and PPS to IDR";
+       case V4L2_CID_MPEG_VIDEO_HEVC_SPS:                      return "HEVC Sequence Parameter Set";
+       case V4L2_CID_MPEG_VIDEO_HEVC_PPS:                      return "HEVC Picture Parameter Set";
+       case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:             return "HEVC Slice Parameters";
+       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS:            return "HEVC Decode Parameters";
+       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:              return "HEVC Decode Mode";
+       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:               return "HEVC Start Code";
+
+       /* CAMERA controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_CAMERA_CLASS:             return "Camera Controls";
+       case V4L2_CID_EXPOSURE_AUTO:            return "Auto Exposure";
+       case V4L2_CID_EXPOSURE_ABSOLUTE:        return "Exposure Time, Absolute";
+       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:   return "Exposure, Dynamic Framerate";
+       case V4L2_CID_PAN_RELATIVE:             return "Pan, Relative";
+       case V4L2_CID_TILT_RELATIVE:            return "Tilt, Relative";
+       case V4L2_CID_PAN_RESET:                return "Pan, Reset";
+       case V4L2_CID_TILT_RESET:               return "Tilt, Reset";
+       case V4L2_CID_PAN_ABSOLUTE:             return "Pan, Absolute";
+       case V4L2_CID_TILT_ABSOLUTE:            return "Tilt, Absolute";
+       case V4L2_CID_FOCUS_ABSOLUTE:           return "Focus, Absolute";
+       case V4L2_CID_FOCUS_RELATIVE:           return "Focus, Relative";
+       case V4L2_CID_FOCUS_AUTO:               return "Focus, Automatic Continuous";
+       case V4L2_CID_ZOOM_ABSOLUTE:            return "Zoom, Absolute";
+       case V4L2_CID_ZOOM_RELATIVE:            return "Zoom, Relative";
+       case V4L2_CID_ZOOM_CONTINUOUS:          return "Zoom, Continuous";
+       case V4L2_CID_PRIVACY:                  return "Privacy";
+       case V4L2_CID_IRIS_ABSOLUTE:            return "Iris, Absolute";
+       case V4L2_CID_IRIS_RELATIVE:            return "Iris, Relative";
+       case V4L2_CID_AUTO_EXPOSURE_BIAS:       return "Auto Exposure, Bias";
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
+       case V4L2_CID_WIDE_DYNAMIC_RANGE:       return "Wide Dynamic Range";
+       case V4L2_CID_IMAGE_STABILIZATION:      return "Image Stabilization";
+       case V4L2_CID_ISO_SENSITIVITY:          return "ISO Sensitivity";
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:     return "ISO Sensitivity, Auto";
+       case V4L2_CID_EXPOSURE_METERING:        return "Exposure, Metering Mode";
+       case V4L2_CID_SCENE_MODE:               return "Scene Mode";
+       case V4L2_CID_3A_LOCK:                  return "3A Lock";
+       case V4L2_CID_AUTO_FOCUS_START:         return "Auto Focus, Start";
+       case V4L2_CID_AUTO_FOCUS_STOP:          return "Auto Focus, Stop";
+       case V4L2_CID_AUTO_FOCUS_STATUS:        return "Auto Focus, Status";
+       case V4L2_CID_AUTO_FOCUS_RANGE:         return "Auto Focus, Range";
+       case V4L2_CID_PAN_SPEED:                return "Pan, Speed";
+       case V4L2_CID_TILT_SPEED:               return "Tilt, Speed";
+       case V4L2_CID_UNIT_CELL_SIZE:           return "Unit Cell Size";
+       case V4L2_CID_CAMERA_ORIENTATION:       return "Camera Orientation";
+       case V4L2_CID_CAMERA_SENSOR_ROTATION:   return "Camera Sensor Rotation";
+
+       /* FM Radio Modulator controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_FM_TX_CLASS:              return "FM Radio Modulator Controls";
+       case V4L2_CID_RDS_TX_DEVIATION:         return "RDS Signal Deviation";
+       case V4L2_CID_RDS_TX_PI:                return "RDS Program ID";
+       case V4L2_CID_RDS_TX_PTY:               return "RDS Program Type";
+       case V4L2_CID_RDS_TX_PS_NAME:           return "RDS PS Name";
+       case V4L2_CID_RDS_TX_RADIO_TEXT:        return "RDS Radio Text";
+       case V4L2_CID_RDS_TX_MONO_STEREO:       return "RDS Stereo";
+       case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:   return "RDS Artificial Head";
+       case V4L2_CID_RDS_TX_COMPRESSED:        return "RDS Compressed";
+       case V4L2_CID_RDS_TX_DYNAMIC_PTY:       return "RDS Dynamic PTY";
+       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:   return "RDS Traffic Program";
+       case V4L2_CID_RDS_TX_MUSIC_SPEECH:      return "RDS Music";
+       case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:  return "RDS Enable Alt Frequencies";
+       case V4L2_CID_RDS_TX_ALT_FREQS:         return "RDS Alternate Frequencies";
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:    return "Audio Limiter Feature Enabled";
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:  return "Audio Limiter Deviation";
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:   return "Audio Compression Gain";
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+       case V4L2_CID_PILOT_TONE_ENABLED:       return "Pilot Tone Feature Enabled";
+       case V4L2_CID_PILOT_TONE_DEVIATION:     return "Pilot Tone Deviation";
+       case V4L2_CID_PILOT_TONE_FREQUENCY:     return "Pilot Tone Frequency";
+       case V4L2_CID_TUNE_PREEMPHASIS:         return "Pre-Emphasis";
+       case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
+
+       /* Flash controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_FLASH_CLASS:              return "Flash Controls";
+       case V4L2_CID_FLASH_LED_MODE:           return "LED Mode";
+       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe Source";
+       case V4L2_CID_FLASH_STROBE:             return "Strobe";
+       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop Strobe";
+       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe Status";
+       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe Timeout";
+       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, Flash Mode";
+       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, Torch Mode";
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
+       case V4L2_CID_FLASH_FAULT:              return "Faults";
+       case V4L2_CID_FLASH_CHARGE:             return "Charge";
+       case V4L2_CID_FLASH_READY:              return "Ready to Strobe";
+
+       /* JPEG encoder controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_JPEG_CLASS:               return "JPEG Compression Controls";
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:  return "Chroma Subsampling";
+       case V4L2_CID_JPEG_RESTART_INTERVAL:    return "Restart Interval";
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
+       case V4L2_CID_JPEG_ACTIVE_MARKER:       return "Active Markers";
+
+       /* Image source controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_IMAGE_SOURCE_CLASS:       return "Image Source Controls";
+       case V4L2_CID_VBLANK:                   return "Vertical Blanking";
+       case V4L2_CID_HBLANK:                   return "Horizontal Blanking";
+       case V4L2_CID_ANALOGUE_GAIN:            return "Analogue Gain";
+       case V4L2_CID_TEST_PATTERN_RED:         return "Red Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENR:      return "Green (Red) Pixel Value";
+       case V4L2_CID_TEST_PATTERN_BLUE:        return "Blue Pixel Value";
+       case V4L2_CID_TEST_PATTERN_GREENB:      return "Green (Blue) Pixel Value";
+
+       /* Image processing controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_IMAGE_PROC_CLASS:         return "Image Processing Controls";
+       case V4L2_CID_LINK_FREQ:                return "Link Frequency";
+       case V4L2_CID_PIXEL_RATE:               return "Pixel Rate";
+       case V4L2_CID_TEST_PATTERN:             return "Test Pattern";
+       case V4L2_CID_DEINTERLACING_MODE:       return "Deinterlacing Mode";
+       case V4L2_CID_DIGITAL_GAIN:             return "Digital Gain";
+
+       /* DV controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_DV_CLASS:                 return "Digital Video Controls";
+       case V4L2_CID_DV_TX_HOTPLUG:            return "Hotplug Present";
+       case V4L2_CID_DV_TX_RXSENSE:            return "RxSense Present";
+       case V4L2_CID_DV_TX_EDID_PRESENT:       return "EDID Present";
+       case V4L2_CID_DV_TX_MODE:               return "Transmit Mode";
+       case V4L2_CID_DV_TX_RGB_RANGE:          return "Tx RGB Quantization Range";
+       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:    return "Tx IT Content Type";
+       case V4L2_CID_DV_RX_POWER_PRESENT:      return "Power Present";
+       case V4L2_CID_DV_RX_RGB_RANGE:          return "Rx RGB Quantization Range";
+       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:    return "Rx IT Content Type";
+
+       case V4L2_CID_FM_RX_CLASS:              return "FM Radio Receiver Controls";
+       case V4L2_CID_TUNE_DEEMPHASIS:          return "De-Emphasis";
+       case V4L2_CID_RDS_RECEPTION:            return "RDS Reception";
+       case V4L2_CID_RF_TUNER_CLASS:           return "RF Tuner Controls";
+       case V4L2_CID_RF_TUNER_RF_GAIN:         return "RF Gain";
+       case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:   return "LNA Gain, Auto";
+       case V4L2_CID_RF_TUNER_LNA_GAIN:        return "LNA Gain";
+       case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto";
+       case V4L2_CID_RF_TUNER_MIXER_GAIN:      return "Mixer Gain";
+       case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:    return "IF Gain, Auto";
+       case V4L2_CID_RF_TUNER_IF_GAIN:         return "IF Gain";
+       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:  return "Bandwidth, Auto";
+       case V4L2_CID_RF_TUNER_BANDWIDTH:       return "Bandwidth";
+       case V4L2_CID_RF_TUNER_PLL_LOCK:        return "PLL Lock";
+       case V4L2_CID_RDS_RX_PTY:               return "RDS Program Type";
+       case V4L2_CID_RDS_RX_PS_NAME:           return "RDS PS Name";
+       case V4L2_CID_RDS_RX_RADIO_TEXT:        return "RDS Radio Text";
+       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:   return "RDS Traffic Program";
+       case V4L2_CID_RDS_RX_MUSIC_SPEECH:      return "RDS Music";
+
+       /* Detection controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_DETECT_CLASS:             return "Detection Controls";
+       case V4L2_CID_DETECT_MD_MODE:           return "Motion Detection Mode";
+       case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold";
+       case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid";
+       case V4L2_CID_DETECT_MD_REGION_GRID:    return "MD Region Grid";
+
+       /* Stateless Codec controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_CODEC_STATELESS_CLASS:    return "Stateless Codec Controls";
+       case V4L2_CID_STATELESS_H264_DECODE_MODE:               return "H264 Decode Mode";
+       case V4L2_CID_STATELESS_H264_START_CODE:                return "H264 Start Code";
+       case V4L2_CID_STATELESS_H264_SPS:                       return "H264 Sequence Parameter Set";
+       case V4L2_CID_STATELESS_H264_PPS:                       return "H264 Picture Parameter Set";
+       case V4L2_CID_STATELESS_H264_SCALING_MATRIX:            return "H264 Scaling Matrix";
+       case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:              return "H264 Prediction Weight Table";
+       case V4L2_CID_STATELESS_H264_SLICE_PARAMS:              return "H264 Slice Parameters";
+       case V4L2_CID_STATELESS_H264_DECODE_PARAMS:             return "H264 Decode Parameters";
+       case V4L2_CID_STATELESS_FWHT_PARAMS:                    return "FWHT Stateless Parameters";
+       case V4L2_CID_STATELESS_VP8_FRAME:                      return "VP8 Frame Parameters";
+       case V4L2_CID_STATELESS_MPEG2_SEQUENCE:                 return "MPEG-2 Sequence Header";
+       case V4L2_CID_STATELESS_MPEG2_PICTURE:                  return "MPEG-2 Picture Header";
+       case V4L2_CID_STATELESS_MPEG2_QUANTISATION:             return "MPEG-2 Quantisation Matrices";
+
+       /* Colorimetry controls */
+       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+       case V4L2_CID_COLORIMETRY_CLASS:        return "Colorimetry Controls";
+       case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:               return "HDR10 Content Light Info";
+       case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:      return "HDR10 Mastering Display";
+       default:
+               return NULL;
+       }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+                   s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
+{
+       *name = v4l2_ctrl_get_name(id);
+       *flags = 0;
+
+       switch (id) {
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_LOUDNESS:
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+       case V4L2_CID_AUTOGAIN:
+       case V4L2_CID_HFLIP:
+       case V4L2_CID_VFLIP:
+       case V4L2_CID_HUE_AUTO:
+       case V4L2_CID_CHROMA_AGC:
+       case V4L2_CID_COLOR_KILLER:
+       case V4L2_CID_AUTOBRIGHTNESS:
+       case V4L2_CID_MPEG_AUDIO_MUTE:
+       case V4L2_CID_MPEG_VIDEO_MUTE:
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+       case V4L2_CID_FOCUS_AUTO:
+       case V4L2_CID_PRIVACY:
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+       case V4L2_CID_PILOT_TONE_ENABLED:
+       case V4L2_CID_ILLUMINATORS_1:
+       case V4L2_CID_ILLUMINATORS_2:
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_FLASH_CHARGE:
+       case V4L2_CID_FLASH_READY:
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+       case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
+       case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
+       case V4L2_CID_WIDE_DYNAMIC_RANGE:
+       case V4L2_CID_IMAGE_STABILIZATION:
+       case V4L2_CID_RDS_RECEPTION:
+       case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+       case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+       case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+       case V4L2_CID_RF_TUNER_PLL_LOCK:
+       case V4L2_CID_RDS_TX_MONO_STEREO:
+       case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
+       case V4L2_CID_RDS_TX_COMPRESSED:
+       case V4L2_CID_RDS_TX_DYNAMIC_PTY:
+       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+       case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+       case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:
+       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+       case V4L2_CID_RDS_RX_MUSIC_SPEECH:
+               *type = V4L2_CTRL_TYPE_BOOLEAN;
+               *min = 0;
+               *max = *step = 1;
+               break;
+       case V4L2_CID_ROTATE:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
+       case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
+       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               break;
+       case V4L2_CID_MPEG_VIDEO_LTR_COUNT:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+               break;
+       case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:
+               *type = V4L2_CTRL_TYPE_BITMASK;
+               *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+       case V4L2_CID_PAN_RESET:
+       case V4L2_CID_TILT_RESET:
+       case V4L2_CID_FLASH_STROBE:
+       case V4L2_CID_FLASH_STROBE_STOP:
+       case V4L2_CID_AUTO_FOCUS_START:
+       case V4L2_CID_AUTO_FOCUS_STOP:
+       case V4L2_CID_DO_WHITE_BALANCE:
+               *type = V4L2_CTRL_TYPE_BUTTON;
+               *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+                         V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+               *min = *max = *step = *def = 0;
+               break;
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+       case V4L2_CID_MPEG_AUDIO_MODE:
+       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+       case V4L2_CID_MPEG_AUDIO_CRC:
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+       case V4L2_CID_MPEG_STREAM_TYPE:
+       case V4L2_CID_MPEG_STREAM_VBI_FMT:
+       case V4L2_CID_EXPOSURE_AUTO:
+       case V4L2_CID_AUTO_FOCUS_RANGE:
+       case V4L2_CID_COLORFX:
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+       case V4L2_CID_TUNE_PREEMPHASIS:
+       case V4L2_CID_FLASH_LED_MODE:
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:
+       case V4L2_CID_EXPOSURE_METERING:
+       case V4L2_CID_SCENE_MODE:
+       case V4L2_CID_DV_TX_MODE:
+       case V4L2_CID_DV_TX_RGB_RANGE:
+       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
+       case V4L2_CID_DV_RX_RGB_RANGE:
+       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+       case V4L2_CID_TEST_PATTERN:
+       case V4L2_CID_DEINTERLACING_MODE:
+       case V4L2_CID_TUNE_DEEMPHASIS:
+       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
+       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+       case V4L2_CID_DETECT_MD_MODE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
+       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+       case V4L2_CID_STATELESS_H264_DECODE_MODE:
+       case V4L2_CID_STATELESS_H264_START_CODE:
+       case V4L2_CID_CAMERA_ORIENTATION:
+               *type = V4L2_CTRL_TYPE_MENU;
+               break;
+       case V4L2_CID_LINK_FREQ:
+               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+               break;
+       case V4L2_CID_RDS_TX_PS_NAME:
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+       case V4L2_CID_RDS_RX_PS_NAME:
+       case V4L2_CID_RDS_RX_RADIO_TEXT:
+               *type = V4L2_CTRL_TYPE_STRING;
+               break;
+       case V4L2_CID_ISO_SENSITIVITY:
+       case V4L2_CID_AUTO_EXPOSURE_BIAS:
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
+       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
+               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+               break;
+       case V4L2_CID_USER_CLASS:
+       case V4L2_CID_CAMERA_CLASS:
+       case V4L2_CID_CODEC_CLASS:
+       case V4L2_CID_FM_TX_CLASS:
+       case V4L2_CID_FLASH_CLASS:
+       case V4L2_CID_JPEG_CLASS:
+       case V4L2_CID_IMAGE_SOURCE_CLASS:
+       case V4L2_CID_IMAGE_PROC_CLASS:
+       case V4L2_CID_DV_CLASS:
+       case V4L2_CID_FM_RX_CLASS:
+       case V4L2_CID_RF_TUNER_CLASS:
+       case V4L2_CID_DETECT_CLASS:
+       case V4L2_CID_CODEC_STATELESS_CLASS:
+       case V4L2_CID_COLORIMETRY_CLASS:
+               *type = V4L2_CTRL_TYPE_CTRL_CLASS;
+               /* You can neither read nor write these */
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
+               *min = *max = *step = *def = 0;
+               break;
+       case V4L2_CID_BG_COLOR:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *step = 1;
+               *min = 0;
+               /* Max is calculated as RGB888 that is 2^24 */
+               *max = 0xFFFFFF;
+               break;
+       case V4L2_CID_FLASH_FAULT:
+       case V4L2_CID_JPEG_ACTIVE_MARKER:
+       case V4L2_CID_3A_LOCK:
+       case V4L2_CID_AUTO_FOCUS_STATUS:
+       case V4L2_CID_DV_TX_HOTPLUG:
+       case V4L2_CID_DV_TX_RXSENSE:
+       case V4L2_CID_DV_TX_EDID_PRESENT:
+       case V4L2_CID_DV_RX_POWER_PRESENT:
+               *type = V4L2_CTRL_TYPE_BITMASK;
+               break;
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+               *type = V4L2_CTRL_TYPE_INTEGER64;
+               *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+               *min = *def = 0;
+               *max = 0x1ffffffffLL;
+               *step = 1;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+               *type = V4L2_CTRL_TYPE_INTEGER64;
+               *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+               *min = *def = 0;
+               *max = 0x7fffffffffffffffLL;
+               *step = 1;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:
+               *type = V4L2_CTRL_TYPE_INTEGER64;
+               *min = 0;
+               /* default for 8 bit black, luma is 16, chroma is 128 */
+               *def = 0x8000800010LL;
+               *max = 0xffffffffffffLL;
+               *step = 1;
+               break;
+       case V4L2_CID_PIXEL_RATE:
+               *type = V4L2_CTRL_TYPE_INTEGER64;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
+       case V4L2_CID_DETECT_MD_REGION_GRID:
+               *type = V4L2_CTRL_TYPE_U8;
+               break;
+       case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+               *type = V4L2_CTRL_TYPE_U16;
+               break;
+       case V4L2_CID_RDS_TX_ALT_FREQS:
+               *type = V4L2_CTRL_TYPE_U32;
+               break;
+       case V4L2_CID_STATELESS_MPEG2_SEQUENCE:
+               *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE;
+               break;
+       case V4L2_CID_STATELESS_MPEG2_PICTURE:
+               *type = V4L2_CTRL_TYPE_MPEG2_PICTURE;
+               break;
+       case V4L2_CID_STATELESS_MPEG2_QUANTISATION:
+               *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION;
+               break;
+       case V4L2_CID_STATELESS_FWHT_PARAMS:
+               *type = V4L2_CTRL_TYPE_FWHT_PARAMS;
+               break;
+       case V4L2_CID_STATELESS_H264_SPS:
+               *type = V4L2_CTRL_TYPE_H264_SPS;
+               break;
+       case V4L2_CID_STATELESS_H264_PPS:
+               *type = V4L2_CTRL_TYPE_H264_PPS;
+               break;
+       case V4L2_CID_STATELESS_H264_SCALING_MATRIX:
+               *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX;
+               break;
+       case V4L2_CID_STATELESS_H264_SLICE_PARAMS:
+               *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS;
+               break;
+       case V4L2_CID_STATELESS_H264_DECODE_PARAMS:
+               *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
+               break;
+       case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:
+               *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
+               break;
+       case V4L2_CID_STATELESS_VP8_FRAME:
+               *type = V4L2_CTRL_TYPE_VP8_FRAME;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
+               *type = V4L2_CTRL_TYPE_HEVC_SPS;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEVC_PPS:
+               *type = V4L2_CTRL_TYPE_HEVC_PPS;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
+               *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS:
+               *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS;
+               break;
+       case V4L2_CID_UNIT_CELL_SIZE:
+               *type = V4L2_CTRL_TYPE_AREA;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
+       case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:
+               *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO;
+               break;
+       case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
+               *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY;
+               break;
+       default:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               break;
+       }
+       switch (id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+       case V4L2_CID_MPEG_AUDIO_MODE:
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               *flags |= V4L2_CTRL_FLAG_UPDATE;
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case V4L2_CID_GAMMA:
+       case V4L2_CID_SHARPNESS:
+       case V4L2_CID_CHROMA_GAIN:
+       case V4L2_CID_RDS_TX_DEVIATION:
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+       case V4L2_CID_PILOT_TONE_DEVIATION:
+       case V4L2_CID_PILOT_TONE_FREQUENCY:
+       case V4L2_CID_TUNE_POWER_LEVEL:
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+       case V4L2_CID_RF_TUNER_RF_GAIN:
+       case V4L2_CID_RF_TUNER_LNA_GAIN:
+       case V4L2_CID_RF_TUNER_MIXER_GAIN:
+       case V4L2_CID_RF_TUNER_IF_GAIN:
+       case V4L2_CID_RF_TUNER_BANDWIDTH:
+       case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
+               *flags |= V4L2_CTRL_FLAG_SLIDER;
+               break;
+       case V4L2_CID_PAN_RELATIVE:
+       case V4L2_CID_TILT_RELATIVE:
+       case V4L2_CID_FOCUS_RELATIVE:
+       case V4L2_CID_IRIS_RELATIVE:
+       case V4L2_CID_ZOOM_RELATIVE:
+               *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+                         V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+               break;
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_AUTO_FOCUS_STATUS:
+       case V4L2_CID_FLASH_READY:
+       case V4L2_CID_DV_TX_HOTPLUG:
+       case V4L2_CID_DV_TX_RXSENSE:
+       case V4L2_CID_DV_TX_EDID_PRESENT:
+       case V4L2_CID_DV_RX_POWER_PRESENT:
+       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+       case V4L2_CID_RDS_RX_PTY:
+       case V4L2_CID_RDS_RX_PS_NAME:
+       case V4L2_CID_RDS_RX_RADIO_TEXT:
+       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+       case V4L2_CID_RDS_RX_MUSIC_SPEECH:
+       case V4L2_CID_CAMERA_ORIENTATION:
+       case V4L2_CID_CAMERA_SENSOR_ROTATION:
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
+       case V4L2_CID_RF_TUNER_PLL_LOCK:
+               *flags |= V4L2_CTRL_FLAG_VOLATILE;
+               break;
+       }
+}
+EXPORT_SYMBOL(v4l2_ctrl_fill);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
new file mode 100644 (file)
index 0000000..d4bf2c7
--- /dev/null
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * V4L2 controls framework private header.
+ *
+ * Copyright (C) 2010-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#ifndef _V4L2_CTRLS_PRIV_H_
+#define _V4L2_CTRLS_PRIV_H_
+
+#define dprintk(vdev, fmt, arg...) do {                                        \
+       if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \
+               printk(KERN_DEBUG pr_fmt("%s: %s: " fmt),               \
+                      __func__, video_device_node_name(vdev), ##arg);  \
+} while (0)
+
+#define has_op(master, op) \
+       ((master)->ops && (master)->ops->op)
+#define call_op(master, op) \
+       (has_op(master, op) ? (master)->ops->op(master) : 0)
+
+static inline u32 node2id(struct list_head *node)
+{
+       return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
+}
+
+/*
+ * Small helper function to determine if the autocluster is set to manual
+ * mode.
+ */
+static inline bool is_cur_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->cur.val == master->manual_mode_value;
+}
+
+/*
+ * Small helper function to determine if the autocluster will be set to manual
+ * mode.
+ */
+static inline bool is_new_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->val == master->manual_mode_value;
+}
+
+static inline u32 user_flags(const struct v4l2_ctrl *ctrl)
+{
+       u32 flags = ctrl->flags;
+
+       if (ctrl->is_ptr)
+               flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+
+       return flags;
+}
+
+/* v4l2-ctrls-core.c */
+void cur_to_new(struct v4l2_ctrl *ctrl);
+void cur_to_req(struct v4l2_ctrl_ref *ref);
+void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags);
+void new_to_req(struct v4l2_ctrl_ref *ref);
+void req_to_new(struct v4l2_ctrl_ref *ref);
+void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl);
+void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes);
+int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new);
+int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+                   struct v4l2_ctrl *ctrl,
+                   struct v4l2_ctrl_ref **ctrl_ref,
+                   bool from_other_dev, bool allocate_req);
+struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id);
+struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id);
+int check_range(enum v4l2_ctrl_type type,
+               s64 min, s64 max, u64 step, s64 def);
+void update_from_auto_cluster(struct v4l2_ctrl *master);
+int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
+                      bool set, u32 ch_flags);
+
+/* v4l2-ctrls-api.c */
+int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
+                           struct v4l2_ext_controls *cs,
+                           struct video_device *vdev);
+int try_set_ext_ctrls_common(struct v4l2_fh *fh,
+                            struct v4l2_ctrl_handler *hdl,
+                            struct v4l2_ext_controls *cs,
+                            struct video_device *vdev, bool set);
+
+/* v4l2-ctrls-request.c */
+void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl);
+void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl);
+int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+                            struct media_device *mdev, struct v4l2_ext_controls *cs);
+int try_set_ext_ctrls_request(struct v4l2_fh *fh,
+                             struct v4l2_ctrl_handler *hdl,
+                             struct video_device *vdev,
+                             struct media_device *mdev,
+                             struct v4l2_ext_controls *cs, bool set);
+
+#endif
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c
new file mode 100644 (file)
index 0000000..7d098f2
--- /dev/null
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework Request API implementation.
+ *
+ * Copyright (C) 2018-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#define pr_fmt(fmt) "v4l2-ctrls: " fmt
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+#include "v4l2-ctrls-priv.h"
+
+/* Initialize the request-related fields in a control handler */
+void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl)
+{
+       INIT_LIST_HEAD(&hdl->requests);
+       INIT_LIST_HEAD(&hdl->requests_queued);
+       hdl->request_is_queued = false;
+       media_request_object_init(&hdl->req_obj);
+}
+
+/* Free the request-related fields in a control handler */
+void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl)
+{
+       struct v4l2_ctrl_handler *req, *next_req;
+
+       /*
+        * Do nothing if this isn't the main handler or the main
+        * handler is not used in any request.
+        *
+        * The main handler can be identified by having a NULL ops pointer in
+        * the request object.
+        */
+       if (hdl->req_obj.ops || list_empty(&hdl->requests))
+               return;
+
+       /*
+        * If the main handler is freed and it is used by handler objects in
+        * outstanding requests, then unbind and put those objects before
+        * freeing the main handler.
+        */
+       list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
+               media_request_object_unbind(&req->req_obj);
+               media_request_object_put(&req->req_obj);
+       }
+}
+
+static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
+                                  const struct v4l2_ctrl_handler *from)
+{
+       struct v4l2_ctrl_ref *ref;
+       int err = 0;
+
+       if (WARN_ON(!hdl || hdl == from))
+               return -EINVAL;
+
+       if (hdl->error)
+               return hdl->error;
+
+       WARN_ON(hdl->lock != &hdl->_lock);
+
+       mutex_lock(from->lock);
+       list_for_each_entry(ref, &from->ctrl_refs, node) {
+               struct v4l2_ctrl *ctrl = ref->ctrl;
+               struct v4l2_ctrl_ref *new_ref;
+
+               /* Skip refs inherited from other devices */
+               if (ref->from_other_dev)
+                       continue;
+               err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
+               if (err)
+                       break;
+       }
+       mutex_unlock(from->lock);
+       return err;
+}
+
+static void v4l2_ctrl_request_queue(struct media_request_object *obj)
+{
+       struct v4l2_ctrl_handler *hdl =
+               container_of(obj, struct v4l2_ctrl_handler, req_obj);
+       struct v4l2_ctrl_handler *main_hdl = obj->priv;
+
+       mutex_lock(main_hdl->lock);
+       list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
+       hdl->request_is_queued = true;
+       mutex_unlock(main_hdl->lock);
+}
+
+static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
+{
+       struct v4l2_ctrl_handler *hdl =
+               container_of(obj, struct v4l2_ctrl_handler, req_obj);
+       struct v4l2_ctrl_handler *main_hdl = obj->priv;
+
+       mutex_lock(main_hdl->lock);
+       list_del_init(&hdl->requests);
+       if (hdl->request_is_queued) {
+               list_del_init(&hdl->requests_queued);
+               hdl->request_is_queued = false;
+       }
+       mutex_unlock(main_hdl->lock);
+}
+
+static void v4l2_ctrl_request_release(struct media_request_object *obj)
+{
+       struct v4l2_ctrl_handler *hdl =
+               container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+       v4l2_ctrl_handler_free(hdl);
+       kfree(hdl);
+}
+
+static const struct media_request_object_ops req_ops = {
+       .queue = v4l2_ctrl_request_queue,
+       .unbind = v4l2_ctrl_request_unbind,
+       .release = v4l2_ctrl_request_release,
+};
+
+struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
+                                                    struct v4l2_ctrl_handler *parent)
+{
+       struct media_request_object *obj;
+
+       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
+                   req->state != MEDIA_REQUEST_STATE_QUEUED))
+               return NULL;
+
+       obj = media_request_object_find(req, &req_ops, parent);
+       if (obj)
+               return container_of(obj, struct v4l2_ctrl_handler, req_obj);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
+
+struct v4l2_ctrl *
+v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+       struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+       return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
+
+static int v4l2_ctrl_request_bind(struct media_request *req,
+                                 struct v4l2_ctrl_handler *hdl,
+                                 struct v4l2_ctrl_handler *from)
+{
+       int ret;
+
+       ret = v4l2_ctrl_request_clone(hdl, from);
+
+       if (!ret) {
+               ret = media_request_object_bind(req, &req_ops,
+                                               from, false, &hdl->req_obj);
+               if (!ret) {
+                       mutex_lock(from->lock);
+                       list_add_tail(&hdl->requests, &from->requests);
+                       mutex_unlock(from->lock);
+               }
+       }
+       return ret;
+}
+
+static struct media_request_object *
+v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
+                       struct media_request *req, bool set)
+{
+       struct media_request_object *obj;
+       struct v4l2_ctrl_handler *new_hdl;
+       int ret;
+
+       if (IS_ERR(req))
+               return ERR_CAST(req);
+
+       if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+               return ERR_PTR(-EBUSY);
+
+       obj = media_request_object_find(req, &req_ops, hdl);
+       if (obj)
+               return obj;
+       /*
+        * If there are no controls in this completed request,
+        * then that can only happen if:
+        *
+        * 1) no controls were present in the queued request, and
+        * 2) v4l2_ctrl_request_complete() could not allocate a
+        *    control handler object to store the completed state in.
+        *
+        * So return ENOMEM to indicate that there was an out-of-memory
+        * error.
+        */
+       if (!set)
+               return ERR_PTR(-ENOMEM);
+
+       new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
+       if (!new_hdl)
+               return ERR_PTR(-ENOMEM);
+
+       obj = &new_hdl->req_obj;
+       ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
+       if (!ret)
+               ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
+       if (ret) {
+               v4l2_ctrl_handler_free(new_hdl);
+               kfree(new_hdl);
+               return ERR_PTR(ret);
+       }
+
+       media_request_object_get(obj);
+       return obj;
+}
+
+int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+                            struct media_device *mdev, struct v4l2_ext_controls *cs)
+{
+       struct media_request_object *obj = NULL;
+       struct media_request *req = NULL;
+       int ret;
+
+       if (!mdev || cs->request_fd < 0)
+               return -EINVAL;
+
+       req = media_request_get_by_fd(mdev, cs->request_fd);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
+               media_request_put(req);
+               return -EACCES;
+       }
+
+       ret = media_request_lock_for_access(req);
+       if (ret) {
+               media_request_put(req);
+               return ret;
+       }
+
+       obj = v4l2_ctrls_find_req_obj(hdl, req, false);
+       if (IS_ERR(obj)) {
+               media_request_unlock_for_access(req);
+               media_request_put(req);
+               return PTR_ERR(obj);
+       }
+
+       hdl = container_of(obj, struct v4l2_ctrl_handler,
+                          req_obj);
+       ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
+
+       media_request_unlock_for_access(req);
+       media_request_object_put(obj);
+       media_request_put(req);
+       return ret;
+}
+
+int try_set_ext_ctrls_request(struct v4l2_fh *fh,
+                             struct v4l2_ctrl_handler *hdl,
+                             struct video_device *vdev,
+                             struct media_device *mdev,
+                             struct v4l2_ext_controls *cs, bool set)
+{
+       struct media_request_object *obj = NULL;
+       struct media_request *req = NULL;
+       int ret;
+
+       if (!mdev) {
+               dprintk(vdev, "%s: missing media device\n",
+                       video_device_node_name(vdev));
+               return -EINVAL;
+       }
+
+       if (cs->request_fd < 0) {
+               dprintk(vdev, "%s: invalid request fd %d\n",
+                       video_device_node_name(vdev), cs->request_fd);
+               return -EINVAL;
+       }
+
+       req = media_request_get_by_fd(mdev, cs->request_fd);
+       if (IS_ERR(req)) {
+               dprintk(vdev, "%s: cannot find request fd %d\n",
+                       video_device_node_name(vdev), cs->request_fd);
+               return PTR_ERR(req);
+       }
+
+       ret = media_request_lock_for_update(req);
+       if (ret) {
+               dprintk(vdev, "%s: cannot lock request fd %d\n",
+                       video_device_node_name(vdev), cs->request_fd);
+               media_request_put(req);
+               return ret;
+       }
+
+       obj = v4l2_ctrls_find_req_obj(hdl, req, set);
+       if (IS_ERR(obj)) {
+               dprintk(vdev,
+                       "%s: cannot find request object for request fd %d\n",
+                       video_device_node_name(vdev),
+                       cs->request_fd);
+               media_request_unlock_for_update(req);
+               media_request_put(req);
+               return PTR_ERR(obj);
+       }
+
+       hdl = container_of(obj, struct v4l2_ctrl_handler,
+                          req_obj);
+       ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
+       if (ret)
+               dprintk(vdev,
+                       "%s: try_set_ext_ctrls_common failed (%d)\n",
+                       video_device_node_name(vdev), ret);
+
+       media_request_unlock_for_update(req);
+       media_request_object_put(obj);
+       media_request_put(req);
+
+       return ret;
+}
+
+void v4l2_ctrl_request_complete(struct media_request *req,
+                               struct v4l2_ctrl_handler *main_hdl)
+{
+       struct media_request_object *obj;
+       struct v4l2_ctrl_handler *hdl;
+       struct v4l2_ctrl_ref *ref;
+
+       if (!req || !main_hdl)
+               return;
+
+       /*
+        * Note that it is valid if nothing was found. It means
+        * that this request doesn't have any controls and so just
+        * wants to leave the controls unchanged.
+        */
+       obj = media_request_object_find(req, &req_ops, main_hdl);
+       if (!obj) {
+               int ret;
+
+               /* Create a new request so the driver can return controls */
+               hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
+               if (!hdl)
+                       return;
+
+               ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
+               if (!ret)
+                       ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
+               if (ret) {
+                       v4l2_ctrl_handler_free(hdl);
+                       kfree(hdl);
+                       return;
+               }
+               hdl->request_is_queued = true;
+               obj = media_request_object_find(req, &req_ops, main_hdl);
+       }
+       hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+               struct v4l2_ctrl *ctrl = ref->ctrl;
+               struct v4l2_ctrl *master = ctrl->cluster[0];
+               unsigned int i;
+
+               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+                       v4l2_ctrl_lock(master);
+                       /* g_volatile_ctrl will update the current control values */
+                       for (i = 0; i < master->ncontrols; i++)
+                               cur_to_new(master->cluster[i]);
+                       call_op(master, g_volatile_ctrl);
+                       new_to_req(ref);
+                       v4l2_ctrl_unlock(master);
+                       continue;
+               }
+               if (ref->valid_p_req)
+                       continue;
+
+               /* Copy the current control value into the request */
+               v4l2_ctrl_lock(ctrl);
+               cur_to_req(ref);
+               v4l2_ctrl_unlock(ctrl);
+       }
+
+       mutex_lock(main_hdl->lock);
+       WARN_ON(!hdl->request_is_queued);
+       list_del_init(&hdl->requests_queued);
+       hdl->request_is_queued = false;
+       mutex_unlock(main_hdl->lock);
+       media_request_object_complete(obj);
+       media_request_object_put(obj);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_complete);
+
+int v4l2_ctrl_request_setup(struct media_request *req,
+                           struct v4l2_ctrl_handler *main_hdl)
+{
+       struct media_request_object *obj;
+       struct v4l2_ctrl_handler *hdl;
+       struct v4l2_ctrl_ref *ref;
+       int ret = 0;
+
+       if (!req || !main_hdl)
+               return 0;
+
+       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+               return -EBUSY;
+
+       /*
+        * Note that it is valid if nothing was found. It means
+        * that this request doesn't have any controls and so just
+        * wants to leave the controls unchanged.
+        */
+       obj = media_request_object_find(req, &req_ops, main_hdl);
+       if (!obj)
+               return 0;
+       if (obj->completed) {
+               media_request_object_put(obj);
+               return -EBUSY;
+       }
+       hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+       list_for_each_entry(ref, &hdl->ctrl_refs, node)
+               ref->req_done = false;
+
+       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+               struct v4l2_ctrl *ctrl = ref->ctrl;
+               struct v4l2_ctrl *master = ctrl->cluster[0];
+               bool have_new_data = false;
+               int i;
+
+               /*
+                * Skip if this control was already handled by a cluster.
+                * Skip button controls and read-only controls.
+                */
+               if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+                       continue;
+
+               v4l2_ctrl_lock(master);
+               for (i = 0; i < master->ncontrols; i++) {
+                       if (master->cluster[i]) {
+                               struct v4l2_ctrl_ref *r =
+                                       find_ref(hdl, master->cluster[i]->id);
+
+                               if (r->valid_p_req) {
+                                       have_new_data = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!have_new_data) {
+                       v4l2_ctrl_unlock(master);
+                       continue;
+               }
+
+               for (i = 0; i < master->ncontrols; i++) {
+                       if (master->cluster[i]) {
+                               struct v4l2_ctrl_ref *r =
+                                       find_ref(hdl, master->cluster[i]->id);
+
+                               req_to_new(r);
+                               master->cluster[i]->is_new = 1;
+                               r->req_done = true;
+                       }
+               }
+               /*
+                * For volatile autoclusters that are currently in auto mode
+                * we need to discover if it will be set to manual mode.
+                * If so, then we have to copy the current volatile values
+                * first since those will become the new manual values (which
+                * may be overwritten by explicit new values from this set
+                * of controls).
+                */
+               if (master->is_auto && master->has_volatiles &&
+                   !is_cur_manual(master)) {
+                       s32 new_auto_val = *master->p_new.p_s32;
+
+                       /*
+                        * If the new value == the manual value, then copy
+                        * the current volatile values.
+                        */
+                       if (new_auto_val == master->manual_mode_value)
+                               update_from_auto_cluster(master);
+               }
+
+               ret = try_or_set_cluster(NULL, master, true, 0);
+               v4l2_ctrl_unlock(master);
+
+               if (ret)
+                       break;
+       }
+
+       media_request_object_put(obj);
+       return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_setup);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
deleted file mode 100644 (file)
index 0d7fe1b..0000000
+++ /dev/null
@@ -1,5035 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-    V4L2 controls framework implementation.
-
-    Copyright (C) 2010  Hans Verkuil <hverkuil@xs4all.nl>
-
- */
-
-#define pr_fmt(fmt) "v4l2-ctrls: " fmt
-
-#include <linux/ctype.h>
-#include <linux/export.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-fwnode.h>
-#include <media/v4l2-ioctl.h>
-
-#define dprintk(vdev, fmt, arg...) do {                                        \
-       if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \
-               printk(KERN_DEBUG pr_fmt("%s: %s: " fmt),               \
-                      __func__, video_device_node_name(vdev), ##arg);  \
-} while (0)
-
-#define has_op(master, op) \
-       (master->ops && master->ops->op)
-#define call_op(master, op) \
-       (has_op(master, op) ? master->ops->op(master) : 0)
-
-static const union v4l2_ctrl_ptr ptr_null;
-
-/* Internal temporary helper struct, one for each v4l2_ext_control */
-struct v4l2_ctrl_helper {
-       /* Pointer to the control reference of the master control */
-       struct v4l2_ctrl_ref *mref;
-       /* The control ref corresponding to the v4l2_ext_control ID field. */
-       struct v4l2_ctrl_ref *ref;
-       /* v4l2_ext_control index of the next control belonging to the
-          same cluster, or 0 if there isn't any. */
-       u32 next;
-};
-
-/* Small helper function to determine if the autocluster is set to manual
-   mode. */
-static bool is_cur_manual(const struct v4l2_ctrl *master)
-{
-       return master->is_auto && master->cur.val == master->manual_mode_value;
-}
-
-/* Same as above, but this checks the against the new value instead of the
-   current value. */
-static bool is_new_manual(const struct v4l2_ctrl *master)
-{
-       return master->is_auto && master->val == master->manual_mode_value;
-}
-
-/* Returns NULL or a character pointer array containing the menu for
-   the given control ID. The pointer array ends with a NULL pointer.
-   An empty string signifies a menu entry that is invalid. This allows
-   drivers to disable certain options if it is not supported. */
-const char * const *v4l2_ctrl_get_menu(u32 id)
-{
-       static const char * const mpeg_audio_sampling_freq[] = {
-               "44.1 kHz",
-               "48 kHz",
-               "32 kHz",
-               NULL
-       };
-       static const char * const mpeg_audio_encoding[] = {
-               "MPEG-1/2 Layer I",
-               "MPEG-1/2 Layer II",
-               "MPEG-1/2 Layer III",
-               "MPEG-2/4 AAC",
-               "AC-3",
-               NULL
-       };
-       static const char * const mpeg_audio_l1_bitrate[] = {
-               "32 kbps",
-               "64 kbps",
-               "96 kbps",
-               "128 kbps",
-               "160 kbps",
-               "192 kbps",
-               "224 kbps",
-               "256 kbps",
-               "288 kbps",
-               "320 kbps",
-               "352 kbps",
-               "384 kbps",
-               "416 kbps",
-               "448 kbps",
-               NULL
-       };
-       static const char * const mpeg_audio_l2_bitrate[] = {
-               "32 kbps",
-               "48 kbps",
-               "56 kbps",
-               "64 kbps",
-               "80 kbps",
-               "96 kbps",
-               "112 kbps",
-               "128 kbps",
-               "160 kbps",
-               "192 kbps",
-               "224 kbps",
-               "256 kbps",
-               "320 kbps",
-               "384 kbps",
-               NULL
-       };
-       static const char * const mpeg_audio_l3_bitrate[] = {
-               "32 kbps",
-               "40 kbps",
-               "48 kbps",
-               "56 kbps",
-               "64 kbps",
-               "80 kbps",
-               "96 kbps",
-               "112 kbps",
-               "128 kbps",
-               "160 kbps",
-               "192 kbps",
-               "224 kbps",
-               "256 kbps",
-               "320 kbps",
-               NULL
-       };
-       static const char * const mpeg_audio_ac3_bitrate[] = {
-               "32 kbps",
-               "40 kbps",
-               "48 kbps",
-               "56 kbps",
-               "64 kbps",
-               "80 kbps",
-               "96 kbps",
-               "112 kbps",
-               "128 kbps",
-               "160 kbps",
-               "192 kbps",
-               "224 kbps",
-               "256 kbps",
-               "320 kbps",
-               "384 kbps",
-               "448 kbps",
-               "512 kbps",
-               "576 kbps",
-               "640 kbps",
-               NULL
-       };
-       static const char * const mpeg_audio_mode[] = {
-               "Stereo",
-               "Joint Stereo",
-               "Dual",
-               "Mono",
-               NULL
-       };
-       static const char * const mpeg_audio_mode_extension[] = {
-               "Bound 4",
-               "Bound 8",
-               "Bound 12",
-               "Bound 16",
-               NULL
-       };
-       static const char * const mpeg_audio_emphasis[] = {
-               "No Emphasis",
-               "50/15 us",
-               "CCITT J17",
-               NULL
-       };
-       static const char * const mpeg_audio_crc[] = {
-               "No CRC",
-               "16-bit CRC",
-               NULL
-       };
-       static const char * const mpeg_audio_dec_playback[] = {
-               "Auto",
-               "Stereo",
-               "Left",
-               "Right",
-               "Mono",
-               "Swapped Stereo",
-               NULL
-       };
-       static const char * const mpeg_video_encoding[] = {
-               "MPEG-1",
-               "MPEG-2",
-               "MPEG-4 AVC",
-               NULL
-       };
-       static const char * const mpeg_video_aspect[] = {
-               "1x1",
-               "4x3",
-               "16x9",
-               "2.21x1",
-               NULL
-       };
-       static const char * const mpeg_video_bitrate_mode[] = {
-               "Variable Bitrate",
-               "Constant Bitrate",
-               "Constant Quality",
-               NULL
-       };
-       static const char * const mpeg_stream_type[] = {
-               "MPEG-2 Program Stream",
-               "MPEG-2 Transport Stream",
-               "MPEG-1 System Stream",
-               "MPEG-2 DVD-compatible Stream",
-               "MPEG-1 VCD-compatible Stream",
-               "MPEG-2 SVCD-compatible Stream",
-               NULL
-       };
-       static const char * const mpeg_stream_vbi_fmt[] = {
-               "No VBI",
-               "Private Packet, IVTV Format",
-               NULL
-       };
-       static const char * const camera_power_line_frequency[] = {
-               "Disabled",
-               "50 Hz",
-               "60 Hz",
-               "Auto",
-               NULL
-       };
-       static const char * const camera_exposure_auto[] = {
-               "Auto Mode",
-               "Manual Mode",
-               "Shutter Priority Mode",
-               "Aperture Priority Mode",
-               NULL
-       };
-       static const char * const camera_exposure_metering[] = {
-               "Average",
-               "Center Weighted",
-               "Spot",
-               "Matrix",
-               NULL
-       };
-       static const char * const camera_auto_focus_range[] = {
-               "Auto",
-               "Normal",
-               "Macro",
-               "Infinity",
-               NULL
-       };
-       static const char * const colorfx[] = {
-               "None",
-               "Black & White",
-               "Sepia",
-               "Negative",
-               "Emboss",
-               "Sketch",
-               "Sky Blue",
-               "Grass Green",
-               "Skin Whiten",
-               "Vivid",
-               "Aqua",
-               "Art Freeze",
-               "Silhouette",
-               "Solarization",
-               "Antique",
-               "Set Cb/Cr",
-               NULL
-       };
-       static const char * const auto_n_preset_white_balance[] = {
-               "Manual",
-               "Auto",
-               "Incandescent",
-               "Fluorescent",
-               "Fluorescent H",
-               "Horizon",
-               "Daylight",
-               "Flash",
-               "Cloudy",
-               "Shade",
-               NULL,
-       };
-       static const char * const camera_iso_sensitivity_auto[] = {
-               "Manual",
-               "Auto",
-               NULL
-       };
-       static const char * const scene_mode[] = {
-               "None",
-               "Backlight",
-               "Beach/Snow",
-               "Candle Light",
-               "Dusk/Dawn",
-               "Fall Colors",
-               "Fireworks",
-               "Landscape",
-               "Night",
-               "Party/Indoor",
-               "Portrait",
-               "Sports",
-               "Sunset",
-               "Text",
-               NULL
-       };
-       static const char * const tune_emphasis[] = {
-               "None",
-               "50 Microseconds",
-               "75 Microseconds",
-               NULL,
-       };
-       static const char * const header_mode[] = {
-               "Separate Buffer",
-               "Joined With 1st Frame",
-               NULL,
-       };
-       static const char * const multi_slice[] = {
-               "Single",
-               "Max Macroblocks",
-               "Max Bytes",
-               NULL,
-       };
-       static const char * const entropy_mode[] = {
-               "CAVLC",
-               "CABAC",
-               NULL,
-       };
-       static const char * const mpeg_h264_level[] = {
-               "1",
-               "1b",
-               "1.1",
-               "1.2",
-               "1.3",
-               "2",
-               "2.1",
-               "2.2",
-               "3",
-               "3.1",
-               "3.2",
-               "4",
-               "4.1",
-               "4.2",
-               "5",
-               "5.1",
-               "5.2",
-               "6.0",
-               "6.1",
-               "6.2",
-               NULL,
-       };
-       static const char * const h264_loop_filter[] = {
-               "Enabled",
-               "Disabled",
-               "Disabled at Slice Boundary",
-               NULL,
-       };
-       static const char * const h264_profile[] = {
-               "Baseline",
-               "Constrained Baseline",
-               "Main",
-               "Extended",
-               "High",
-               "High 10",
-               "High 422",
-               "High 444 Predictive",
-               "High 10 Intra",
-               "High 422 Intra",
-               "High 444 Intra",
-               "CAVLC 444 Intra",
-               "Scalable Baseline",
-               "Scalable High",
-               "Scalable High Intra",
-               "Stereo High",
-               "Multiview High",
-               "Constrained High",
-               NULL,
-       };
-       static const char * const vui_sar_idc[] = {
-               "Unspecified",
-               "1:1",
-               "12:11",
-               "10:11",
-               "16:11",
-               "40:33",
-               "24:11",
-               "20:11",
-               "32:11",
-               "80:33",
-               "18:11",
-               "15:11",
-               "64:33",
-               "160:99",
-               "4:3",
-               "3:2",
-               "2:1",
-               "Extended SAR",
-               NULL,
-       };
-       static const char * const h264_fp_arrangement_type[] = {
-               "Checkerboard",
-               "Column",
-               "Row",
-               "Side by Side",
-               "Top Bottom",
-               "Temporal",
-               NULL,
-       };
-       static const char * const h264_fmo_map_type[] = {
-               "Interleaved Slices",
-               "Scattered Slices",
-               "Foreground with Leftover",
-               "Box Out",
-               "Raster Scan",
-               "Wipe Scan",
-               "Explicit",
-               NULL,
-       };
-       static const char * const h264_decode_mode[] = {
-               "Slice-Based",
-               "Frame-Based",
-               NULL,
-       };
-       static const char * const h264_start_code[] = {
-               "No Start Code",
-               "Annex B Start Code",
-               NULL,
-       };
-       static const char * const h264_hierarchical_coding_type[] = {
-               "Hier Coding B",
-               "Hier Coding P",
-               NULL,
-       };
-       static const char * const mpeg_mpeg2_level[] = {
-               "Low",
-               "Main",
-               "High 1440",
-               "High",
-               NULL,
-       };
-       static const char * const mpeg2_profile[] = {
-               "Simple",
-               "Main",
-               "SNR Scalable",
-               "Spatially Scalable",
-               "High",
-               NULL,
-       };
-       static const char * const mpeg_mpeg4_level[] = {
-               "0",
-               "0b",
-               "1",
-               "2",
-               "3",
-               "3b",
-               "4",
-               "5",
-               NULL,
-       };
-       static const char * const mpeg4_profile[] = {
-               "Simple",
-               "Advanced Simple",
-               "Core",
-               "Simple Scalable",
-               "Advanced Coding Efficiency",
-               NULL,
-       };
-
-       static const char * const vpx_golden_frame_sel[] = {
-               "Use Previous Frame",
-               "Use Previous Specific Frame",
-               NULL,
-       };
-       static const char * const vp8_profile[] = {
-               "0",
-               "1",
-               "2",
-               "3",
-               NULL,
-       };
-       static const char * const vp9_profile[] = {
-               "0",
-               "1",
-               "2",
-               "3",
-               NULL,
-       };
-       static const char * const vp9_level[] = {
-               "1",
-               "1.1",
-               "2",
-               "2.1",
-               "3",
-               "3.1",
-               "4",
-               "4.1",
-               "5",
-               "5.1",
-               "5.2",
-               "6",
-               "6.1",
-               "6.2",
-               NULL,
-       };
-
-       static const char * const flash_led_mode[] = {
-               "Off",
-               "Flash",
-               "Torch",
-               NULL,
-       };
-       static const char * const flash_strobe_source[] = {
-               "Software",
-               "External",
-               NULL,
-       };
-
-       static const char * const jpeg_chroma_subsampling[] = {
-               "4:4:4",
-               "4:2:2",
-               "4:2:0",
-               "4:1:1",
-               "4:1:0",
-               "Gray",
-               NULL,
-       };
-       static const char * const dv_tx_mode[] = {
-               "DVI-D",
-               "HDMI",
-               NULL,
-       };
-       static const char * const dv_rgb_range[] = {
-               "Automatic",
-               "RGB Limited Range (16-235)",
-               "RGB Full Range (0-255)",
-               NULL,
-       };
-       static const char * const dv_it_content_type[] = {
-               "Graphics",
-               "Photo",
-               "Cinema",
-               "Game",
-               "No IT Content",
-               NULL,
-       };
-       static const char * const detect_md_mode[] = {
-               "Disabled",
-               "Global",
-               "Threshold Grid",
-               "Region Grid",
-               NULL,
-       };
-
-       static const char * const hevc_profile[] = {
-               "Main",
-               "Main Still Picture",
-               "Main 10",
-               NULL,
-       };
-       static const char * const hevc_level[] = {
-               "1",
-               "2",
-               "2.1",
-               "3",
-               "3.1",
-               "4",
-               "4.1",
-               "5",
-               "5.1",
-               "5.2",
-               "6",
-               "6.1",
-               "6.2",
-               NULL,
-       };
-       static const char * const hevc_hierarchial_coding_type[] = {
-               "B",
-               "P",
-               NULL,
-       };
-       static const char * const hevc_refresh_type[] = {
-               "None",
-               "CRA",
-               "IDR",
-               NULL,
-       };
-       static const char * const hevc_size_of_length_field[] = {
-               "0",
-               "1",
-               "2",
-               "4",
-               NULL,
-       };
-       static const char * const hevc_tier[] = {
-               "Main",
-               "High",
-               NULL,
-       };
-       static const char * const hevc_loop_filter_mode[] = {
-               "Disabled",
-               "Enabled",
-               "Disabled at slice boundary",
-               "NULL",
-       };
-       static const char * const hevc_decode_mode[] = {
-               "Slice-Based",
-               "Frame-Based",
-               NULL,
-       };
-       static const char * const hevc_start_code[] = {
-               "No Start Code",
-               "Annex B Start Code",
-               NULL,
-       };
-       static const char * const camera_orientation[] = {
-               "Front",
-               "Back",
-               "External",
-               NULL,
-       };
-       static const char * const mpeg_video_frame_skip[] = {
-               "Disabled",
-               "Level Limit",
-               "VBV/CPB Limit",
-               NULL,
-       };
-
-       switch (id) {
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-               return mpeg_audio_sampling_freq;
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-               return mpeg_audio_encoding;
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
-               return mpeg_audio_l1_bitrate;
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-               return mpeg_audio_l2_bitrate;
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
-               return mpeg_audio_l3_bitrate;
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-               return mpeg_audio_ac3_bitrate;
-       case V4L2_CID_MPEG_AUDIO_MODE:
-               return mpeg_audio_mode;
-       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
-               return mpeg_audio_mode_extension;
-       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
-               return mpeg_audio_emphasis;
-       case V4L2_CID_MPEG_AUDIO_CRC:
-               return mpeg_audio_crc;
-       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
-       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
-               return mpeg_audio_dec_playback;
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               return mpeg_video_encoding;
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               return mpeg_video_aspect;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               return mpeg_video_bitrate_mode;
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               return mpeg_stream_type;
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:
-               return mpeg_stream_vbi_fmt;
-       case V4L2_CID_POWER_LINE_FREQUENCY:
-               return camera_power_line_frequency;
-       case V4L2_CID_EXPOSURE_AUTO:
-               return camera_exposure_auto;
-       case V4L2_CID_EXPOSURE_METERING:
-               return camera_exposure_metering;
-       case V4L2_CID_AUTO_FOCUS_RANGE:
-               return camera_auto_focus_range;
-       case V4L2_CID_COLORFX:
-               return colorfx;
-       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
-               return auto_n_preset_white_balance;
-       case V4L2_CID_ISO_SENSITIVITY_AUTO:
-               return camera_iso_sensitivity_auto;
-       case V4L2_CID_SCENE_MODE:
-               return scene_mode;
-       case V4L2_CID_TUNE_PREEMPHASIS:
-               return tune_emphasis;
-       case V4L2_CID_TUNE_DEEMPHASIS:
-               return tune_emphasis;
-       case V4L2_CID_FLASH_LED_MODE:
-               return flash_led_mode;
-       case V4L2_CID_FLASH_STROBE_SOURCE:
-               return flash_strobe_source;
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-               return header_mode;
-       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
-               return mpeg_video_frame_skip;
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
-               return multi_slice;
-       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
-               return entropy_mode;
-       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-               return mpeg_h264_level;
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-               return h264_loop_filter;
-       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-               return h264_profile;
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
-               return vui_sar_idc;
-       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
-               return h264_fp_arrangement_type;
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
-               return h264_fmo_map_type;
-       case V4L2_CID_STATELESS_H264_DECODE_MODE:
-               return h264_decode_mode;
-       case V4L2_CID_STATELESS_H264_START_CODE:
-               return h264_start_code;
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
-               return h264_hierarchical_coding_type;
-       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
-               return mpeg_mpeg2_level;
-       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
-               return mpeg2_profile;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
-               return mpeg_mpeg4_level;
-       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
-               return mpeg4_profile;
-       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
-               return vpx_golden_frame_sel;
-       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
-               return vp8_profile;
-       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
-               return vp9_profile;
-       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
-               return vp9_level;
-       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
-               return jpeg_chroma_subsampling;
-       case V4L2_CID_DV_TX_MODE:
-               return dv_tx_mode;
-       case V4L2_CID_DV_TX_RGB_RANGE:
-       case V4L2_CID_DV_RX_RGB_RANGE:
-               return dv_rgb_range;
-       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
-       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
-               return dv_it_content_type;
-       case V4L2_CID_DETECT_MD_MODE:
-               return detect_md_mode;
-       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
-               return hevc_profile;
-       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
-               return hevc_level;
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
-               return hevc_hierarchial_coding_type;
-       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
-               return hevc_refresh_type;
-       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
-               return hevc_size_of_length_field;
-       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
-               return hevc_tier;
-       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
-               return hevc_loop_filter_mode;
-       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
-               return hevc_decode_mode;
-       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
-               return hevc_start_code;
-       case V4L2_CID_CAMERA_ORIENTATION:
-               return camera_orientation;
-       default:
-               return NULL;
-       }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-
-#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); arr; })
-/*
- * Returns NULL or an s64 type array containing the menu for given
- * control ID. The total number of the menu items is returned in @len.
- */
-const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
-{
-       static const s64 qmenu_int_vpx_num_partitions[] = {
-               1, 2, 4, 8,
-       };
-
-       static const s64 qmenu_int_vpx_num_ref_frames[] = {
-               1, 2, 3,
-       };
-
-       switch (id) {
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
-               return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len);
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
-               return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len);
-       default:
-               *len = 0;
-               return NULL;
-       }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_int_menu);
-
-/* Return the control name. */
-const char *v4l2_ctrl_get_name(u32 id)
-{
-       switch (id) {
-       /* USER controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_USER_CLASS:               return "User Controls";
-       case V4L2_CID_BRIGHTNESS:               return "Brightness";
-       case V4L2_CID_CONTRAST:                 return "Contrast";
-       case V4L2_CID_SATURATION:               return "Saturation";
-       case V4L2_CID_HUE:                      return "Hue";
-       case V4L2_CID_AUDIO_VOLUME:             return "Volume";
-       case V4L2_CID_AUDIO_BALANCE:            return "Balance";
-       case V4L2_CID_AUDIO_BASS:               return "Bass";
-       case V4L2_CID_AUDIO_TREBLE:             return "Treble";
-       case V4L2_CID_AUDIO_MUTE:               return "Mute";
-       case V4L2_CID_AUDIO_LOUDNESS:           return "Loudness";
-       case V4L2_CID_BLACK_LEVEL:              return "Black Level";
-       case V4L2_CID_AUTO_WHITE_BALANCE:       return "White Balance, Automatic";
-       case V4L2_CID_DO_WHITE_BALANCE:         return "Do White Balance";
-       case V4L2_CID_RED_BALANCE:              return "Red Balance";
-       case V4L2_CID_BLUE_BALANCE:             return "Blue Balance";
-       case V4L2_CID_GAMMA:                    return "Gamma";
-       case V4L2_CID_EXPOSURE:                 return "Exposure";
-       case V4L2_CID_AUTOGAIN:                 return "Gain, Automatic";
-       case V4L2_CID_GAIN:                     return "Gain";
-       case V4L2_CID_HFLIP:                    return "Horizontal Flip";
-       case V4L2_CID_VFLIP:                    return "Vertical Flip";
-       case V4L2_CID_POWER_LINE_FREQUENCY:     return "Power Line Frequency";
-       case V4L2_CID_HUE_AUTO:                 return "Hue, Automatic";
-       case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
-       case V4L2_CID_SHARPNESS:                return "Sharpness";
-       case V4L2_CID_BACKLIGHT_COMPENSATION:   return "Backlight Compensation";
-       case V4L2_CID_CHROMA_AGC:               return "Chroma AGC";
-       case V4L2_CID_COLOR_KILLER:             return "Color Killer";
-       case V4L2_CID_COLORFX:                  return "Color Effects";
-       case V4L2_CID_AUTOBRIGHTNESS:           return "Brightness, Automatic";
-       case V4L2_CID_BAND_STOP_FILTER:         return "Band-Stop Filter";
-       case V4L2_CID_ROTATE:                   return "Rotate";
-       case V4L2_CID_BG_COLOR:                 return "Background Color";
-       case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
-       case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
-       case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
-       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Min Number of Capture Buffers";
-       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Min Number of Output Buffers";
-       case V4L2_CID_ALPHA_COMPONENT:          return "Alpha Component";
-       case V4L2_CID_COLORFX_CBCR:             return "Color Effects, CbCr";
-
-       /* Codec controls */
-       /* The MPEG controls are applicable to all codec controls
-        * and the 'MPEG' part of the define is historical */
-       /* Keep the order of the 'case's the same as in videodev2.h! */
-       case V4L2_CID_CODEC_CLASS:              return "Codec Controls";
-       case V4L2_CID_MPEG_STREAM_TYPE:         return "Stream Type";
-       case V4L2_CID_MPEG_STREAM_PID_PMT:      return "Stream PMT Program ID";
-       case V4L2_CID_MPEG_STREAM_PID_AUDIO:    return "Stream Audio Program ID";
-       case V4L2_CID_MPEG_STREAM_PID_VIDEO:    return "Stream Video Program ID";
-       case V4L2_CID_MPEG_STREAM_PID_PCR:      return "Stream PCR Program ID";
-       case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
-       case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:      return "Stream VBI Format";
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
-       case V4L2_CID_MPEG_AUDIO_ENCODING:      return "Audio Encoding";
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:    return "Audio Layer I Bitrate";
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:    return "Audio Layer II Bitrate";
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:    return "Audio Layer III Bitrate";
-       case V4L2_CID_MPEG_AUDIO_MODE:          return "Audio Stereo Mode";
-       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
-       case V4L2_CID_MPEG_AUDIO_EMPHASIS:      return "Audio Emphasis";
-       case V4L2_CID_MPEG_AUDIO_CRC:           return "Audio CRC";
-       case V4L2_CID_MPEG_AUDIO_MUTE:          return "Audio Mute";
-       case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:   return "Audio AAC Bitrate";
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:   return "Audio AC-3 Bitrate";
-       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:  return "Audio Playback";
-       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
-       case V4L2_CID_MPEG_VIDEO_ENCODING:      return "Video Encoding";
-       case V4L2_CID_MPEG_VIDEO_ASPECT:        return "Video Aspect";
-       case V4L2_CID_MPEG_VIDEO_B_FRAMES:      return "Video B Frames";
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:      return "Video GOP Size";
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:   return "Video GOP Closure";
-       case V4L2_CID_MPEG_VIDEO_PULLDOWN:      return "Video Pulldown";
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:  return "Video Bitrate Mode";
-       case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY:      return "Constant Quality";
-       case V4L2_CID_MPEG_VIDEO_BITRATE:       return "Video Bitrate";
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:  return "Video Peak Bitrate";
-       case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
-       case V4L2_CID_MPEG_VIDEO_MUTE:          return "Video Mute";
-       case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
-       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:       return "Decoder Slice Interface";
-       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:  return "MPEG4 Loop Filter Enable";
-       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "Number of Intra Refresh MBs";
-       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:               return "Frame Level Rate Control Enable";
-       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:                  return "H264 MB Level Rate Control";
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:                   return "Sequence Header Mode";
-       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "Max Number of Reference Pics";
-       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:               return "Frame Skip Mode";
-       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:             return "Display Delay";
-       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:      return "Display Delay Enable";
-       case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:                  return "Generate Access Unit Delimiters";
-       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:               return "H263 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:                   return "H263 Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:                   return "H263 Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:               return "H264 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:                   return "H264 Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:                   return "H264 Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:            return "H264 8x8 Transform Enable";
-       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:                 return "H264 CPB Buffer Size";
-       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entropy Mode";
-       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I-Frame Period";
-       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:                    return "H264 Level";
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:        return "H264 Loop Filter Alpha Offset";
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:         return "H264 Loop Filter Beta Offset";
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:         return "H264 Loop Filter Mode";
-       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:                  return "H264 Profile";
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:       return "Vertical Size of SAR";
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:        return "Horizontal Size of SAR";
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:           return "Aspect Ratio VUI Enable";
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:              return "VUI Aspect Ratio IDC";
-       case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:        return "H264 Enable Frame Packing SEI";
-       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0:   return "H264 Set Curr. Frame as Frame0";
-       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:  return "H264 FP Arrangement Type";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO:                      return "H264 Flexible MB Ordering";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:             return "H264 Map Type for FMO";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP:          return "H264 FMO Number of Slice Groups";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION:     return "H264 FMO Direction of Change";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE:          return "H264 FMO Size of 1st Slice Grp";
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH:           return "H264 FMO No. of Consecutive MBs";
-       case V4L2_CID_MPEG_VIDEO_H264_ASO:                      return "H264 Arbitrary Slice Ordering";
-       case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER:          return "H264 ASO Slice Order";
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:      return "Enable H264 Hierarchical Coding";
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type";
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers";
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
-                                                               return "H264 Set QP Value for HC Layers";
-       case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
-                                                               return "H264 Constrained Intra Pred";
-       case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:   return "H264 Chroma QP Index Offset";
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP:           return "H264 I-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP:           return "H264 I-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP:           return "H264 P-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP:           return "H264 P-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP:           return "H264 B-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP:           return "H264 B-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR:        return "H264 Hierarchical Lay 0 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR:        return "H264 Hierarchical Lay 1 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR:        return "H264 Hierarchical Lay 2 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR:        return "H264 Hierarchical Lay 3 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR:        return "H264 Hierarchical Lay 4 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR:        return "H264 Hierarchical Lay 5 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR:        return "H264 Hierarchical Lay 6 Bitrate";
-       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:                   return "MPEG2 Level";
-       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:                 return "MPEG2 Profile";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:              return "MPEG4 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:                  return "MPEG4 Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:                  return "MPEG4 Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:                   return "MPEG4 Level";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:                 return "MPEG4 Profile";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:                    return "Quarter Pixel Search Enable";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "Maximum Bytes in a Slice";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "Number of MBs in a Slice";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "Slice Partitioning Method";
-       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
-       case V4L2_CID_MPEG_VIDEO_DEC_PTS:                       return "Video Decoder PTS";
-       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:                     return "Video Decoder Frame Count";
-       case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:             return "Video Decoder Conceal Color";
-       case V4L2_CID_MPEG_VIDEO_VBV_DELAY:                     return "Initial Delay for VBV Control";
-       case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:             return "Horizontal MV Search Range";
-       case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:             return "Vertical MV Search Range";
-       case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:             return "Repeat Sequence Header";
-       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:               return "Force Key Frame";
-       case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID:         return "Base Layer Priority ID";
-       case V4L2_CID_MPEG_VIDEO_LTR_COUNT:                     return "LTR Count";
-       case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:               return "Frame LTR Index";
-       case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:                return "Use LTR Frames";
-       case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS:            return "MPEG-2 Slice Parameters";
-       case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION:            return "MPEG-2 Quantization Matrices";
-       case V4L2_CID_FWHT_I_FRAME_QP:                          return "FWHT I-Frame QP Value";
-       case V4L2_CID_FWHT_P_FRAME_QP:                          return "FWHT P-Frame QP Value";
-
-       /* VPX controls */
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:            return "VPX Number of Partitions";
-       case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4:           return "VPX Intra Mode Decision Disable";
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:            return "VPX No. of Refs for P Frame";
-       case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL:              return "VPX Loop Filter Level Range";
-       case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS:          return "VPX Deblocking Effect Control";
-       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD:   return "VPX Golden Frame Refresh Period";
-       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:          return "VPX Golden Frame Indicator";
-       case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:                    return "VPX Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:                    return "VPX Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP:                return "VPX I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP:                return "VPX P-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:                   return "VP8 Profile";
-       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:                   return "VP9 Profile";
-       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:                     return "VP9 Level";
-
-       /* HEVC controls */
-       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:               return "HEVC I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:               return "HEVC P-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:               return "HEVC B-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:                   return "HEVC Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:                   return "HEVC Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP:           return "HEVC I-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP:           return "HEVC I-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP:           return "HEVC P-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP:           return "HEVC P-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP:           return "HEVC B-Frame Minimum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP:           return "HEVC B-Frame Maximum QP Value";
-       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:                  return "HEVC Profile";
-       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:                    return "HEVC Level";
-       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:                     return "HEVC Tier";
-       case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION:    return "HEVC Frame Rate Resolution";
-       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH:      return "HEVC Maximum Coding Unit Depth";
-       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:             return "HEVC Refresh Type";
-       case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:         return "HEVC Constant Intra Prediction";
-       case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU:              return "HEVC Lossless Encoding";
-       case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT:                return "HEVC Wavefront";
-       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:         return "HEVC Loop Filter";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP:                  return "HEVC QP Values";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:         return "HEVC Hierarchical Coding Type";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER:        return "HEVC Hierarchical Coding Layer";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP:        return "HEVC Hierarchical Layer 0 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP:        return "HEVC Hierarchical Layer 1 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP:        return "HEVC Hierarchical Layer 2 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP:        return "HEVC Hierarchical Layer 3 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP:        return "HEVC Hierarchical Layer 4 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP:        return "HEVC Hierarchical Layer 5 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP:        return "HEVC Hierarchical Layer 6 QP";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR:        return "HEVC Hierarchical Lay 0 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR:        return "HEVC Hierarchical Lay 1 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR:        return "HEVC Hierarchical Lay 2 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR:        return "HEVC Hierarchical Lay 3 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR:        return "HEVC Hierarchical Lay 4 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR:        return "HEVC Hierarchical Lay 5 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR:        return "HEVC Hierarchical Lay 6 BitRate";
-       case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB:               return "HEVC General PB";
-       case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID:              return "HEVC Temporal ID";
-       case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:         return "HEVC Strong Intra Smoothing";
-       case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT:           return "HEVC Intra PU Split";
-       case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:           return "HEVC TMV Prediction";
-       case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:  return "HEVC Max Num of Candidate MVs";
-       case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE:        return "HEVC ENC Without Startcode";
-       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:           return "HEVC Num of I-Frame b/w 2 IDR";
-       case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:      return "HEVC Loop Filter Beta Offset";
-       case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:        return "HEVC Loop Filter TC Offset";
-       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:     return "HEVC Size of Length Field";
-       case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES:        return "Reference Frames for a P-Frame";
-       case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:         return "Prepend SPS and PPS to IDR";
-       case V4L2_CID_MPEG_VIDEO_HEVC_SPS:                      return "HEVC Sequence Parameter Set";
-       case V4L2_CID_MPEG_VIDEO_HEVC_PPS:                      return "HEVC Picture Parameter Set";
-       case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:             return "HEVC Slice Parameters";
-       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:              return "HEVC Decode Mode";
-       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:               return "HEVC Start Code";
-
-       /* CAMERA controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_CAMERA_CLASS:             return "Camera Controls";
-       case V4L2_CID_EXPOSURE_AUTO:            return "Auto Exposure";
-       case V4L2_CID_EXPOSURE_ABSOLUTE:        return "Exposure Time, Absolute";
-       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:   return "Exposure, Dynamic Framerate";
-       case V4L2_CID_PAN_RELATIVE:             return "Pan, Relative";
-       case V4L2_CID_TILT_RELATIVE:            return "Tilt, Relative";
-       case V4L2_CID_PAN_RESET:                return "Pan, Reset";
-       case V4L2_CID_TILT_RESET:               return "Tilt, Reset";
-       case V4L2_CID_PAN_ABSOLUTE:             return "Pan, Absolute";
-       case V4L2_CID_TILT_ABSOLUTE:            return "Tilt, Absolute";
-       case V4L2_CID_FOCUS_ABSOLUTE:           return "Focus, Absolute";
-       case V4L2_CID_FOCUS_RELATIVE:           return "Focus, Relative";
-       case V4L2_CID_FOCUS_AUTO:               return "Focus, Automatic Continuous";
-       case V4L2_CID_ZOOM_ABSOLUTE:            return "Zoom, Absolute";
-       case V4L2_CID_ZOOM_RELATIVE:            return "Zoom, Relative";
-       case V4L2_CID_ZOOM_CONTINUOUS:          return "Zoom, Continuous";
-       case V4L2_CID_PRIVACY:                  return "Privacy";
-       case V4L2_CID_IRIS_ABSOLUTE:            return "Iris, Absolute";
-       case V4L2_CID_IRIS_RELATIVE:            return "Iris, Relative";
-       case V4L2_CID_AUTO_EXPOSURE_BIAS:       return "Auto Exposure, Bias";
-       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
-       case V4L2_CID_WIDE_DYNAMIC_RANGE:       return "Wide Dynamic Range";
-       case V4L2_CID_IMAGE_STABILIZATION:      return "Image Stabilization";
-       case V4L2_CID_ISO_SENSITIVITY:          return "ISO Sensitivity";
-       case V4L2_CID_ISO_SENSITIVITY_AUTO:     return "ISO Sensitivity, Auto";
-       case V4L2_CID_EXPOSURE_METERING:        return "Exposure, Metering Mode";
-       case V4L2_CID_SCENE_MODE:               return "Scene Mode";
-       case V4L2_CID_3A_LOCK:                  return "3A Lock";
-       case V4L2_CID_AUTO_FOCUS_START:         return "Auto Focus, Start";
-       case V4L2_CID_AUTO_FOCUS_STOP:          return "Auto Focus, Stop";
-       case V4L2_CID_AUTO_FOCUS_STATUS:        return "Auto Focus, Status";
-       case V4L2_CID_AUTO_FOCUS_RANGE:         return "Auto Focus, Range";
-       case V4L2_CID_PAN_SPEED:                return "Pan, Speed";
-       case V4L2_CID_TILT_SPEED:               return "Tilt, Speed";
-       case V4L2_CID_UNIT_CELL_SIZE:           return "Unit Cell Size";
-       case V4L2_CID_CAMERA_ORIENTATION:       return "Camera Orientation";
-       case V4L2_CID_CAMERA_SENSOR_ROTATION:   return "Camera Sensor Rotation";
-
-       /* FM Radio Modulator controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_FM_TX_CLASS:              return "FM Radio Modulator Controls";
-       case V4L2_CID_RDS_TX_DEVIATION:         return "RDS Signal Deviation";
-       case V4L2_CID_RDS_TX_PI:                return "RDS Program ID";
-       case V4L2_CID_RDS_TX_PTY:               return "RDS Program Type";
-       case V4L2_CID_RDS_TX_PS_NAME:           return "RDS PS Name";
-       case V4L2_CID_RDS_TX_RADIO_TEXT:        return "RDS Radio Text";
-       case V4L2_CID_RDS_TX_MONO_STEREO:       return "RDS Stereo";
-       case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:   return "RDS Artificial Head";
-       case V4L2_CID_RDS_TX_COMPRESSED:        return "RDS Compressed";
-       case V4L2_CID_RDS_TX_DYNAMIC_PTY:       return "RDS Dynamic PTY";
-       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
-       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:   return "RDS Traffic Program";
-       case V4L2_CID_RDS_TX_MUSIC_SPEECH:      return "RDS Music";
-       case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:  return "RDS Enable Alt Frequencies";
-       case V4L2_CID_RDS_TX_ALT_FREQS:         return "RDS Alternate Frequencies";
-       case V4L2_CID_AUDIO_LIMITER_ENABLED:    return "Audio Limiter Feature Enabled";
-       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
-       case V4L2_CID_AUDIO_LIMITER_DEVIATION:  return "Audio Limiter Deviation";
-       case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
-       case V4L2_CID_AUDIO_COMPRESSION_GAIN:   return "Audio Compression Gain";
-       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
-       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
-       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
-       case V4L2_CID_PILOT_TONE_ENABLED:       return "Pilot Tone Feature Enabled";
-       case V4L2_CID_PILOT_TONE_DEVIATION:     return "Pilot Tone Deviation";
-       case V4L2_CID_PILOT_TONE_FREQUENCY:     return "Pilot Tone Frequency";
-       case V4L2_CID_TUNE_PREEMPHASIS:         return "Pre-Emphasis";
-       case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
-       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
-
-       /* Flash controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_FLASH_CLASS:              return "Flash Controls";
-       case V4L2_CID_FLASH_LED_MODE:           return "LED Mode";
-       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe Source";
-       case V4L2_CID_FLASH_STROBE:             return "Strobe";
-       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop Strobe";
-       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe Status";
-       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe Timeout";
-       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, Flash Mode";
-       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, Torch Mode";
-       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
-       case V4L2_CID_FLASH_FAULT:              return "Faults";
-       case V4L2_CID_FLASH_CHARGE:             return "Charge";
-       case V4L2_CID_FLASH_READY:              return "Ready to Strobe";
-
-       /* JPEG encoder controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_JPEG_CLASS:               return "JPEG Compression Controls";
-       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:  return "Chroma Subsampling";
-       case V4L2_CID_JPEG_RESTART_INTERVAL:    return "Restart Interval";
-       case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
-       case V4L2_CID_JPEG_ACTIVE_MARKER:       return "Active Markers";
-
-       /* Image source controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_IMAGE_SOURCE_CLASS:       return "Image Source Controls";
-       case V4L2_CID_VBLANK:                   return "Vertical Blanking";
-       case V4L2_CID_HBLANK:                   return "Horizontal Blanking";
-       case V4L2_CID_ANALOGUE_GAIN:            return "Analogue Gain";
-       case V4L2_CID_TEST_PATTERN_RED:         return "Red Pixel Value";
-       case V4L2_CID_TEST_PATTERN_GREENR:      return "Green (Red) Pixel Value";
-       case V4L2_CID_TEST_PATTERN_BLUE:        return "Blue Pixel Value";
-       case V4L2_CID_TEST_PATTERN_GREENB:      return "Green (Blue) Pixel Value";
-
-       /* Image processing controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_IMAGE_PROC_CLASS:         return "Image Processing Controls";
-       case V4L2_CID_LINK_FREQ:                return "Link Frequency";
-       case V4L2_CID_PIXEL_RATE:               return "Pixel Rate";
-       case V4L2_CID_TEST_PATTERN:             return "Test Pattern";
-       case V4L2_CID_DEINTERLACING_MODE:       return "Deinterlacing Mode";
-       case V4L2_CID_DIGITAL_GAIN:             return "Digital Gain";
-
-       /* DV controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_DV_CLASS:                 return "Digital Video Controls";
-       case V4L2_CID_DV_TX_HOTPLUG:            return "Hotplug Present";
-       case V4L2_CID_DV_TX_RXSENSE:            return "RxSense Present";
-       case V4L2_CID_DV_TX_EDID_PRESENT:       return "EDID Present";
-       case V4L2_CID_DV_TX_MODE:               return "Transmit Mode";
-       case V4L2_CID_DV_TX_RGB_RANGE:          return "Tx RGB Quantization Range";
-       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:    return "Tx IT Content Type";
-       case V4L2_CID_DV_RX_POWER_PRESENT:      return "Power Present";
-       case V4L2_CID_DV_RX_RGB_RANGE:          return "Rx RGB Quantization Range";
-       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:    return "Rx IT Content Type";
-
-       case V4L2_CID_FM_RX_CLASS:              return "FM Radio Receiver Controls";
-       case V4L2_CID_TUNE_DEEMPHASIS:          return "De-Emphasis";
-       case V4L2_CID_RDS_RECEPTION:            return "RDS Reception";
-       case V4L2_CID_RF_TUNER_CLASS:           return "RF Tuner Controls";
-       case V4L2_CID_RF_TUNER_RF_GAIN:         return "RF Gain";
-       case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:   return "LNA Gain, Auto";
-       case V4L2_CID_RF_TUNER_LNA_GAIN:        return "LNA Gain";
-       case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto";
-       case V4L2_CID_RF_TUNER_MIXER_GAIN:      return "Mixer Gain";
-       case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:    return "IF Gain, Auto";
-       case V4L2_CID_RF_TUNER_IF_GAIN:         return "IF Gain";
-       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:  return "Bandwidth, Auto";
-       case V4L2_CID_RF_TUNER_BANDWIDTH:       return "Bandwidth";
-       case V4L2_CID_RF_TUNER_PLL_LOCK:        return "PLL Lock";
-       case V4L2_CID_RDS_RX_PTY:               return "RDS Program Type";
-       case V4L2_CID_RDS_RX_PS_NAME:           return "RDS PS Name";
-       case V4L2_CID_RDS_RX_RADIO_TEXT:        return "RDS Radio Text";
-       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
-       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:   return "RDS Traffic Program";
-       case V4L2_CID_RDS_RX_MUSIC_SPEECH:      return "RDS Music";
-
-       /* Detection controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_DETECT_CLASS:             return "Detection Controls";
-       case V4L2_CID_DETECT_MD_MODE:           return "Motion Detection Mode";
-       case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold";
-       case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid";
-       case V4L2_CID_DETECT_MD_REGION_GRID:    return "MD Region Grid";
-
-       /* Stateless Codec controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_CODEC_STATELESS_CLASS:    return "Stateless Codec Controls";
-       case V4L2_CID_STATELESS_H264_DECODE_MODE:               return "H264 Decode Mode";
-       case V4L2_CID_STATELESS_H264_START_CODE:                return "H264 Start Code";
-       case V4L2_CID_STATELESS_H264_SPS:                       return "H264 Sequence Parameter Set";
-       case V4L2_CID_STATELESS_H264_PPS:                       return "H264 Picture Parameter Set";
-       case V4L2_CID_STATELESS_H264_SCALING_MATRIX:            return "H264 Scaling Matrix";
-       case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:              return "H264 Prediction Weight Table";
-       case V4L2_CID_STATELESS_H264_SLICE_PARAMS:              return "H264 Slice Parameters";
-       case V4L2_CID_STATELESS_H264_DECODE_PARAMS:             return "H264 Decode Parameters";
-       case V4L2_CID_STATELESS_FWHT_PARAMS:                    return "FWHT Stateless Parameters";
-       case V4L2_CID_STATELESS_VP8_FRAME:                      return "VP8 Frame Parameters";
-
-       /* Colorimetry controls */
-       /* Keep the order of the 'case's the same as in v4l2-controls.h! */
-       case V4L2_CID_COLORIMETRY_CLASS:        return "Colorimetry Controls";
-       case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:               return "HDR10 Content Light Info";
-       case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:      return "HDR10 Mastering Display";
-       default:
-               return NULL;
-       }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_name);
-
-void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
-                   s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
-{
-       *name = v4l2_ctrl_get_name(id);
-       *flags = 0;
-
-       switch (id) {
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-       case V4L2_CID_AUTOGAIN:
-       case V4L2_CID_HFLIP:
-       case V4L2_CID_VFLIP:
-       case V4L2_CID_HUE_AUTO:
-       case V4L2_CID_CHROMA_AGC:
-       case V4L2_CID_COLOR_KILLER:
-       case V4L2_CID_AUTOBRIGHTNESS:
-       case V4L2_CID_MPEG_AUDIO_MUTE:
-       case V4L2_CID_MPEG_VIDEO_MUTE:
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
-       case V4L2_CID_MPEG_VIDEO_PULLDOWN:
-       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
-       case V4L2_CID_FOCUS_AUTO:
-       case V4L2_CID_PRIVACY:
-       case V4L2_CID_AUDIO_LIMITER_ENABLED:
-       case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
-       case V4L2_CID_PILOT_TONE_ENABLED:
-       case V4L2_CID_ILLUMINATORS_1:
-       case V4L2_CID_ILLUMINATORS_2:
-       case V4L2_CID_FLASH_STROBE_STATUS:
-       case V4L2_CID_FLASH_CHARGE:
-       case V4L2_CID_FLASH_READY:
-       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
-       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
-       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
-       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
-       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
-       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
-       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
-       case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
-       case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
-       case V4L2_CID_WIDE_DYNAMIC_RANGE:
-       case V4L2_CID_IMAGE_STABILIZATION:
-       case V4L2_CID_RDS_RECEPTION:
-       case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
-       case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
-       case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
-       case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
-       case V4L2_CID_RF_TUNER_PLL_LOCK:
-       case V4L2_CID_RDS_TX_MONO_STEREO:
-       case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
-       case V4L2_CID_RDS_TX_COMPRESSED:
-       case V4L2_CID_RDS_TX_DYNAMIC_PTY:
-       case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
-       case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
-       case V4L2_CID_RDS_TX_MUSIC_SPEECH:
-       case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:
-       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
-       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
-       case V4L2_CID_RDS_RX_MUSIC_SPEECH:
-               *type = V4L2_CTRL_TYPE_BOOLEAN;
-               *min = 0;
-               *max = *step = 1;
-               break;
-       case V4L2_CID_ROTATE:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
-       case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
-       case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               break;
-       case V4L2_CID_MPEG_VIDEO_LTR_COUNT:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               break;
-       case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
-               break;
-       case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:
-               *type = V4L2_CTRL_TYPE_BITMASK;
-               *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
-               break;
-       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
-       case V4L2_CID_PAN_RESET:
-       case V4L2_CID_TILT_RESET:
-       case V4L2_CID_FLASH_STROBE:
-       case V4L2_CID_FLASH_STROBE_STOP:
-       case V4L2_CID_AUTO_FOCUS_START:
-       case V4L2_CID_AUTO_FOCUS_STOP:
-       case V4L2_CID_DO_WHITE_BALANCE:
-               *type = V4L2_CTRL_TYPE_BUTTON;
-               *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
-                         V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
-               *min = *max = *step = *def = 0;
-               break;
-       case V4L2_CID_POWER_LINE_FREQUENCY:
-       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-       case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
-       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
-       case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
-       case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
-       case V4L2_CID_MPEG_AUDIO_MODE:
-       case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
-       case V4L2_CID_MPEG_AUDIO_EMPHASIS:
-       case V4L2_CID_MPEG_AUDIO_CRC:
-       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
-       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-       case V4L2_CID_MPEG_STREAM_TYPE:
-       case V4L2_CID_MPEG_STREAM_VBI_FMT:
-       case V4L2_CID_EXPOSURE_AUTO:
-       case V4L2_CID_AUTO_FOCUS_RANGE:
-       case V4L2_CID_COLORFX:
-       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
-       case V4L2_CID_TUNE_PREEMPHASIS:
-       case V4L2_CID_FLASH_LED_MODE:
-       case V4L2_CID_FLASH_STROBE_SOURCE:
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-       case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
-       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
-       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
-       case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
-       case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
-       case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
-       case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL:
-       case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE:
-       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
-       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
-       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
-       case V4L2_CID_ISO_SENSITIVITY_AUTO:
-       case V4L2_CID_EXPOSURE_METERING:
-       case V4L2_CID_SCENE_MODE:
-       case V4L2_CID_DV_TX_MODE:
-       case V4L2_CID_DV_TX_RGB_RANGE:
-       case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
-       case V4L2_CID_DV_RX_RGB_RANGE:
-       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
-       case V4L2_CID_TEST_PATTERN:
-       case V4L2_CID_DEINTERLACING_MODE:
-       case V4L2_CID_TUNE_DEEMPHASIS:
-       case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
-       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
-       case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
-       case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
-       case V4L2_CID_DETECT_MD_MODE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
-       case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
-       case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
-       case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
-       case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
-       case V4L2_CID_STATELESS_H264_DECODE_MODE:
-       case V4L2_CID_STATELESS_H264_START_CODE:
-       case V4L2_CID_CAMERA_ORIENTATION:
-               *type = V4L2_CTRL_TYPE_MENU;
-               break;
-       case V4L2_CID_LINK_FREQ:
-               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
-               break;
-       case V4L2_CID_RDS_TX_PS_NAME:
-       case V4L2_CID_RDS_TX_RADIO_TEXT:
-       case V4L2_CID_RDS_RX_PS_NAME:
-       case V4L2_CID_RDS_RX_RADIO_TEXT:
-               *type = V4L2_CTRL_TYPE_STRING;
-               break;
-       case V4L2_CID_ISO_SENSITIVITY:
-       case V4L2_CID_AUTO_EXPOSURE_BIAS:
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
-       case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
-               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
-               break;
-       case V4L2_CID_USER_CLASS:
-       case V4L2_CID_CAMERA_CLASS:
-       case V4L2_CID_CODEC_CLASS:
-       case V4L2_CID_FM_TX_CLASS:
-       case V4L2_CID_FLASH_CLASS:
-       case V4L2_CID_JPEG_CLASS:
-       case V4L2_CID_IMAGE_SOURCE_CLASS:
-       case V4L2_CID_IMAGE_PROC_CLASS:
-       case V4L2_CID_DV_CLASS:
-       case V4L2_CID_FM_RX_CLASS:
-       case V4L2_CID_RF_TUNER_CLASS:
-       case V4L2_CID_DETECT_CLASS:
-       case V4L2_CID_CODEC_STATELESS_CLASS:
-       case V4L2_CID_COLORIMETRY_CLASS:
-               *type = V4L2_CTRL_TYPE_CTRL_CLASS;
-               /* You can neither read nor write these */
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
-               *min = *max = *step = *def = 0;
-               break;
-       case V4L2_CID_BG_COLOR:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               *step = 1;
-               *min = 0;
-               /* Max is calculated as RGB888 that is 2^24 */
-               *max = 0xFFFFFF;
-               break;
-       case V4L2_CID_FLASH_FAULT:
-       case V4L2_CID_JPEG_ACTIVE_MARKER:
-       case V4L2_CID_3A_LOCK:
-       case V4L2_CID_AUTO_FOCUS_STATUS:
-       case V4L2_CID_DV_TX_HOTPLUG:
-       case V4L2_CID_DV_TX_RXSENSE:
-       case V4L2_CID_DV_TX_EDID_PRESENT:
-       case V4L2_CID_DV_RX_POWER_PRESENT:
-               *type = V4L2_CTRL_TYPE_BITMASK;
-               break;
-       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
-       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
-               break;
-       case V4L2_CID_MPEG_VIDEO_DEC_PTS:
-               *type = V4L2_CTRL_TYPE_INTEGER64;
-               *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
-               *min = *def = 0;
-               *max = 0x1ffffffffLL;
-               *step = 1;
-               break;
-       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
-               *type = V4L2_CTRL_TYPE_INTEGER64;
-               *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
-               *min = *def = 0;
-               *max = 0x7fffffffffffffffLL;
-               *step = 1;
-               break;
-       case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:
-               *type = V4L2_CTRL_TYPE_INTEGER64;
-               *min = 0;
-               /* default for 8 bit black, luma is 16, chroma is 128 */
-               *def = 0x8000800010LL;
-               *max = 0xffffffffffffLL;
-               *step = 1;
-               break;
-       case V4L2_CID_PIXEL_RATE:
-               *type = V4L2_CTRL_TYPE_INTEGER64;
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
-               break;
-       case V4L2_CID_DETECT_MD_REGION_GRID:
-               *type = V4L2_CTRL_TYPE_U8;
-               break;
-       case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
-               *type = V4L2_CTRL_TYPE_U16;
-               break;
-       case V4L2_CID_RDS_TX_ALT_FREQS:
-               *type = V4L2_CTRL_TYPE_U32;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS:
-               *type = V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION:
-               *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION;
-               break;
-       case V4L2_CID_STATELESS_FWHT_PARAMS:
-               *type = V4L2_CTRL_TYPE_FWHT_PARAMS;
-               break;
-       case V4L2_CID_STATELESS_H264_SPS:
-               *type = V4L2_CTRL_TYPE_H264_SPS;
-               break;
-       case V4L2_CID_STATELESS_H264_PPS:
-               *type = V4L2_CTRL_TYPE_H264_PPS;
-               break;
-       case V4L2_CID_STATELESS_H264_SCALING_MATRIX:
-               *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX;
-               break;
-       case V4L2_CID_STATELESS_H264_SLICE_PARAMS:
-               *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS;
-               break;
-       case V4L2_CID_STATELESS_H264_DECODE_PARAMS:
-               *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
-               break;
-       case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:
-               *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
-               break;
-       case V4L2_CID_STATELESS_VP8_FRAME:
-               *type = V4L2_CTRL_TYPE_VP8_FRAME;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
-               *type = V4L2_CTRL_TYPE_HEVC_SPS;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEVC_PPS:
-               *type = V4L2_CTRL_TYPE_HEVC_PPS;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
-               *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
-               break;
-       case V4L2_CID_UNIT_CELL_SIZE:
-               *type = V4L2_CTRL_TYPE_AREA;
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
-               break;
-       case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:
-               *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO;
-               break;
-       case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
-               *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY;
-               break;
-       default:
-               *type = V4L2_CTRL_TYPE_INTEGER;
-               break;
-       }
-       switch (id) {
-       case V4L2_CID_MPEG_AUDIO_ENCODING:
-       case V4L2_CID_MPEG_AUDIO_MODE:
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               *flags |= V4L2_CTRL_FLAG_UPDATE;
-               break;
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_HUE:
-       case V4L2_CID_RED_BALANCE:
-       case V4L2_CID_BLUE_BALANCE:
-       case V4L2_CID_GAMMA:
-       case V4L2_CID_SHARPNESS:
-       case V4L2_CID_CHROMA_GAIN:
-       case V4L2_CID_RDS_TX_DEVIATION:
-       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
-       case V4L2_CID_AUDIO_LIMITER_DEVIATION:
-       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
-       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
-       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
-       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
-       case V4L2_CID_PILOT_TONE_DEVIATION:
-       case V4L2_CID_PILOT_TONE_FREQUENCY:
-       case V4L2_CID_TUNE_POWER_LEVEL:
-       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-       case V4L2_CID_RF_TUNER_RF_GAIN:
-       case V4L2_CID_RF_TUNER_LNA_GAIN:
-       case V4L2_CID_RF_TUNER_MIXER_GAIN:
-       case V4L2_CID_RF_TUNER_IF_GAIN:
-       case V4L2_CID_RF_TUNER_BANDWIDTH:
-       case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
-               *flags |= V4L2_CTRL_FLAG_SLIDER;
-               break;
-       case V4L2_CID_PAN_RELATIVE:
-       case V4L2_CID_TILT_RELATIVE:
-       case V4L2_CID_FOCUS_RELATIVE:
-       case V4L2_CID_IRIS_RELATIVE:
-       case V4L2_CID_ZOOM_RELATIVE:
-               *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
-                         V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
-               break;
-       case V4L2_CID_FLASH_STROBE_STATUS:
-       case V4L2_CID_AUTO_FOCUS_STATUS:
-       case V4L2_CID_FLASH_READY:
-       case V4L2_CID_DV_TX_HOTPLUG:
-       case V4L2_CID_DV_TX_RXSENSE:
-       case V4L2_CID_DV_TX_EDID_PRESENT:
-       case V4L2_CID_DV_RX_POWER_PRESENT:
-       case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
-       case V4L2_CID_RDS_RX_PTY:
-       case V4L2_CID_RDS_RX_PS_NAME:
-       case V4L2_CID_RDS_RX_RADIO_TEXT:
-       case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
-       case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
-       case V4L2_CID_RDS_RX_MUSIC_SPEECH:
-       case V4L2_CID_CAMERA_ORIENTATION:
-       case V4L2_CID_CAMERA_SENSOR_ROTATION:
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
-               break;
-       case V4L2_CID_RF_TUNER_PLL_LOCK:
-               *flags |= V4L2_CTRL_FLAG_VOLATILE;
-               break;
-       }
-}
-EXPORT_SYMBOL(v4l2_ctrl_fill);
-
-static u32 user_flags(const struct v4l2_ctrl *ctrl)
-{
-       u32 flags = ctrl->flags;
-
-       if (ctrl->is_ptr)
-               flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
-
-       return flags;
-}
-
-static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
-{
-       memset(ev, 0, sizeof(*ev));
-       ev->type = V4L2_EVENT_CTRL;
-       ev->id = ctrl->id;
-       ev->u.ctrl.changes = changes;
-       ev->u.ctrl.type = ctrl->type;
-       ev->u.ctrl.flags = user_flags(ctrl);
-       if (ctrl->is_ptr)
-               ev->u.ctrl.value64 = 0;
-       else
-               ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
-       ev->u.ctrl.minimum = ctrl->minimum;
-       ev->u.ctrl.maximum = ctrl->maximum;
-       if (ctrl->type == V4L2_CTRL_TYPE_MENU
-           || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
-               ev->u.ctrl.step = 1;
-       else
-               ev->u.ctrl.step = ctrl->step;
-       ev->u.ctrl.default_value = ctrl->default_value;
-}
-
-static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
-{
-       struct v4l2_event ev;
-       struct v4l2_subscribed_event *sev;
-
-       if (list_empty(&ctrl->ev_subs))
-               return;
-       fill_event(&ev, ctrl, changes);
-
-       list_for_each_entry(sev, &ctrl->ev_subs, node)
-               if (sev->fh != fh ||
-                   (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
-                       v4l2_event_queue_fh(sev->fh, &ev);
-}
-
-static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
-                     union v4l2_ctrl_ptr ptr1,
-                     union v4l2_ctrl_ptr ptr2)
-{
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_BUTTON:
-               return false;
-       case V4L2_CTRL_TYPE_STRING:
-               idx *= ctrl->elem_size;
-               /* strings are always 0-terminated */
-               return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
-       case V4L2_CTRL_TYPE_INTEGER64:
-               return ptr1.p_s64[idx] == ptr2.p_s64[idx];
-       case V4L2_CTRL_TYPE_U8:
-               return ptr1.p_u8[idx] == ptr2.p_u8[idx];
-       case V4L2_CTRL_TYPE_U16:
-               return ptr1.p_u16[idx] == ptr2.p_u16[idx];
-       case V4L2_CTRL_TYPE_U32:
-               return ptr1.p_u32[idx] == ptr2.p_u32[idx];
-       default:
-               if (ctrl->is_int)
-                       return ptr1.p_s32[idx] == ptr2.p_s32[idx];
-               idx *= ctrl->elem_size;
-               return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx,
-                              ctrl->elem_size);
-       }
-}
-
-static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
-                             union v4l2_ctrl_ptr ptr)
-{
-       struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
-       struct v4l2_ctrl_vp8_frame *p_vp8_frame;
-       struct v4l2_ctrl_fwht_params *p_fwht_params;
-       void *p = ptr.p + idx * ctrl->elem_size;
-
-       if (ctrl->p_def.p_const)
-               memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
-       else
-               memset(p, 0, ctrl->elem_size);
-
-       /*
-        * The cast is needed to get rid of a gcc warning complaining that
-        * V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS is not part of the
-        * v4l2_ctrl_type enum.
-        */
-       switch ((u32)ctrl->type) {
-       case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
-               p_mpeg2_slice_params = p;
-               /* 4:2:0 */
-               p_mpeg2_slice_params->sequence.chroma_format = 1;
-               /* interlaced top field */
-               p_mpeg2_slice_params->picture.picture_structure = 1;
-               p_mpeg2_slice_params->picture.picture_coding_type =
-                                       V4L2_MPEG2_PICTURE_CODING_TYPE_I;
-               break;
-       case V4L2_CTRL_TYPE_VP8_FRAME:
-               p_vp8_frame = p;
-               p_vp8_frame->num_dct_parts = 1;
-               break;
-       case V4L2_CTRL_TYPE_FWHT_PARAMS:
-               p_fwht_params = p;
-               p_fwht_params->version = V4L2_FWHT_VERSION;
-               p_fwht_params->width = 1280;
-               p_fwht_params->height = 720;
-               p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV |
-                       (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
-               break;
-       }
-}
-
-static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
-                    union v4l2_ctrl_ptr ptr)
-{
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_STRING:
-               idx *= ctrl->elem_size;
-               memset(ptr.p_char + idx, ' ', ctrl->minimum);
-               ptr.p_char[idx + ctrl->minimum] = '\0';
-               break;
-       case V4L2_CTRL_TYPE_INTEGER64:
-               ptr.p_s64[idx] = ctrl->default_value;
-               break;
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_BITMASK:
-       case V4L2_CTRL_TYPE_BOOLEAN:
-               ptr.p_s32[idx] = ctrl->default_value;
-               break;
-       case V4L2_CTRL_TYPE_BUTTON:
-       case V4L2_CTRL_TYPE_CTRL_CLASS:
-               ptr.p_s32[idx] = 0;
-               break;
-       case V4L2_CTRL_TYPE_U8:
-               ptr.p_u8[idx] = ctrl->default_value;
-               break;
-       case V4L2_CTRL_TYPE_U16:
-               ptr.p_u16[idx] = ctrl->default_value;
-               break;
-       case V4L2_CTRL_TYPE_U32:
-               ptr.p_u32[idx] = ctrl->default_value;
-               break;
-       default:
-               std_init_compound(ctrl, idx, ptr);
-               break;
-       }
-}
-
-static void std_log(const struct v4l2_ctrl *ctrl)
-{
-       union v4l2_ctrl_ptr ptr = ctrl->p_cur;
-
-       if (ctrl->is_array) {
-               unsigned i;
-
-               for (i = 0; i < ctrl->nr_of_dims; i++)
-                       pr_cont("[%u]", ctrl->dims[i]);
-               pr_cont(" ");
-       }
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-               pr_cont("%d", *ptr.p_s32);
-               break;
-       case V4L2_CTRL_TYPE_BOOLEAN:
-               pr_cont("%s", *ptr.p_s32 ? "true" : "false");
-               break;
-       case V4L2_CTRL_TYPE_MENU:
-               pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
-               break;
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-               pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
-               break;
-       case V4L2_CTRL_TYPE_BITMASK:
-               pr_cont("0x%08x", *ptr.p_s32);
-               break;
-       case V4L2_CTRL_TYPE_INTEGER64:
-               pr_cont("%lld", *ptr.p_s64);
-               break;
-       case V4L2_CTRL_TYPE_STRING:
-               pr_cont("%s", ptr.p_char);
-               break;
-       case V4L2_CTRL_TYPE_U8:
-               pr_cont("%u", (unsigned)*ptr.p_u8);
-               break;
-       case V4L2_CTRL_TYPE_U16:
-               pr_cont("%u", (unsigned)*ptr.p_u16);
-               break;
-       case V4L2_CTRL_TYPE_U32:
-               pr_cont("%u", (unsigned)*ptr.p_u32);
-               break;
-       case V4L2_CTRL_TYPE_H264_SPS:
-               pr_cont("H264_SPS");
-               break;
-       case V4L2_CTRL_TYPE_H264_PPS:
-               pr_cont("H264_PPS");
-               break;
-       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
-               pr_cont("H264_SCALING_MATRIX");
-               break;
-       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
-               pr_cont("H264_SLICE_PARAMS");
-               break;
-       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
-               pr_cont("H264_DECODE_PARAMS");
-               break;
-       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
-               pr_cont("H264_PRED_WEIGHTS");
-               break;
-       case V4L2_CTRL_TYPE_FWHT_PARAMS:
-               pr_cont("FWHT_PARAMS");
-               break;
-       case V4L2_CTRL_TYPE_VP8_FRAME:
-               pr_cont("VP8_FRAME");
-               break;
-       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
-               pr_cont("HDR10_CLL_INFO");
-               break;
-       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
-               pr_cont("HDR10_MASTERING_DISPLAY");
-               break;
-       default:
-               pr_cont("unknown type %d", ctrl->type);
-               break;
-       }
-}
-
-/*
- * Round towards the closest legal value. Be careful when we are
- * close to the maximum range of the control type to prevent
- * wrap-arounds.
- */
-#define ROUND_TO_RANGE(val, offset_type, ctrl)                 \
-({                                                             \
-       offset_type offset;                                     \
-       if ((ctrl)->maximum >= 0 &&                             \
-           val >= (ctrl)->maximum - (s32)((ctrl)->step / 2))   \
-               val = (ctrl)->maximum;                          \
-       else                                                    \
-               val += (s32)((ctrl)->step / 2);                 \
-       val = clamp_t(typeof(val), val,                         \
-                     (ctrl)->minimum, (ctrl)->maximum);        \
-       offset = (val) - (ctrl)->minimum;                       \
-       offset = (ctrl)->step * (offset / (u32)(ctrl)->step);   \
-       val = (ctrl)->minimum + offset;                         \
-       0;                                                      \
-})
-
-/* Validate a new control */
-
-#define zero_padding(s) \
-       memset(&(s).padding, 0, sizeof((s).padding))
-#define zero_reserved(s) \
-       memset(&(s).reserved, 0, sizeof((s).reserved))
-
-/*
- * Compound controls validation requires setting unused fields/flags to zero
- * in order to properly detect unchanged controls with std_equal's memcmp.
- */
-static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
-                                union v4l2_ctrl_ptr ptr)
-{
-       struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
-       struct v4l2_ctrl_vp8_frame *p_vp8_frame;
-       struct v4l2_ctrl_fwht_params *p_fwht_params;
-       struct v4l2_ctrl_h264_sps *p_h264_sps;
-       struct v4l2_ctrl_h264_pps *p_h264_pps;
-       struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
-       struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
-       struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
-       struct v4l2_ctrl_hevc_sps *p_hevc_sps;
-       struct v4l2_ctrl_hevc_pps *p_hevc_pps;
-       struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
-       struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
-       struct v4l2_area *area;
-       void *p = ptr.p + idx * ctrl->elem_size;
-       unsigned int i;
-
-       switch ((u32)ctrl->type) {
-       case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
-               p_mpeg2_slice_params = p;
-
-               switch (p_mpeg2_slice_params->sequence.chroma_format) {
-               case 1: /* 4:2:0 */
-               case 2: /* 4:2:2 */
-               case 3: /* 4:4:4 */
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               switch (p_mpeg2_slice_params->picture.intra_dc_precision) {
-               case 0: /* 8 bits */
-               case 1: /* 9 bits */
-               case 2: /* 10 bits */
-               case 3: /* 11 bits */
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               switch (p_mpeg2_slice_params->picture.picture_structure) {
-               case 1: /* interlaced top field */
-               case 2: /* interlaced bottom field */
-               case 3: /* progressive */
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               switch (p_mpeg2_slice_params->picture.picture_coding_type) {
-               case V4L2_MPEG2_PICTURE_CODING_TYPE_I:
-               case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
-               case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-
-               break;
-
-       case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
-               break;
-
-       case V4L2_CTRL_TYPE_FWHT_PARAMS:
-               p_fwht_params = p;
-               if (p_fwht_params->version < V4L2_FWHT_VERSION)
-                       return -EINVAL;
-               if (!p_fwht_params->width || !p_fwht_params->height)
-                       return -EINVAL;
-               break;
-
-       case V4L2_CTRL_TYPE_H264_SPS:
-               p_h264_sps = p;
-
-               /* Some syntax elements are only conditionally valid */
-               if (p_h264_sps->pic_order_cnt_type != 0) {
-                       p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
-               } else if (p_h264_sps->pic_order_cnt_type != 1) {
-                       p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0;
-                       p_h264_sps->offset_for_non_ref_pic = 0;
-                       p_h264_sps->offset_for_top_to_bottom_field = 0;
-                       memset(&p_h264_sps->offset_for_ref_frame, 0,
-                              sizeof(p_h264_sps->offset_for_ref_frame));
-               }
-
-               if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) {
-                       p_h264_sps->chroma_format_idc = 1;
-                       p_h264_sps->bit_depth_luma_minus8 = 0;
-                       p_h264_sps->bit_depth_chroma_minus8 = 0;
-
-                       p_h264_sps->flags &=
-                               ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
-
-                       if (p_h264_sps->chroma_format_idc < 3)
-                               p_h264_sps->flags &=
-                                       ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
-               }
-
-               if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
-                       p_h264_sps->flags &=
-                               ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
-
-               /*
-                * Chroma 4:2:2 format require at least High 4:2:2 profile.
-                *
-                * The H264 specification and well-known parser implementations
-                * use profile-idc values directly, as that is clearer and
-                * less ambiguous. We do the same here.
-                */
-               if (p_h264_sps->profile_idc < 122 &&
-                   p_h264_sps->chroma_format_idc > 1)
-                       return -EINVAL;
-               /* Chroma 4:4:4 format require at least High 4:2:2 profile */
-               if (p_h264_sps->profile_idc < 244 &&
-                   p_h264_sps->chroma_format_idc > 2)
-                       return -EINVAL;
-               if (p_h264_sps->chroma_format_idc > 3)
-                       return -EINVAL;
-
-               if (p_h264_sps->bit_depth_luma_minus8 > 6)
-                       return -EINVAL;
-               if (p_h264_sps->bit_depth_chroma_minus8 > 6)
-                       return -EINVAL;
-               if (p_h264_sps->log2_max_frame_num_minus4 > 12)
-                       return -EINVAL;
-               if (p_h264_sps->pic_order_cnt_type > 2)
-                       return -EINVAL;
-               if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
-                       return -EINVAL;
-               if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN)
-                       return -EINVAL;
-               break;
-
-       case V4L2_CTRL_TYPE_H264_PPS:
-               p_h264_pps = p;
-
-               if (p_h264_pps->num_slice_groups_minus1 > 7)
-                       return -EINVAL;
-               if (p_h264_pps->num_ref_idx_l0_default_active_minus1 >
-                   (V4L2_H264_REF_LIST_LEN - 1))
-                       return -EINVAL;
-               if (p_h264_pps->num_ref_idx_l1_default_active_minus1 >
-                   (V4L2_H264_REF_LIST_LEN - 1))
-                       return -EINVAL;
-               if (p_h264_pps->weighted_bipred_idc > 2)
-                       return -EINVAL;
-               /*
-                * pic_init_qp_minus26 shall be in the range of
-                * -(26 + QpBdOffset_y) to +25, inclusive,
-                *  where QpBdOffset_y is 6 * bit_depth_luma_minus8
-                */
-               if (p_h264_pps->pic_init_qp_minus26 < -62 ||
-                   p_h264_pps->pic_init_qp_minus26 > 25)
-                       return -EINVAL;
-               if (p_h264_pps->pic_init_qs_minus26 < -26 ||
-                   p_h264_pps->pic_init_qs_minus26 > 25)
-                       return -EINVAL;
-               if (p_h264_pps->chroma_qp_index_offset < -12 ||
-                   p_h264_pps->chroma_qp_index_offset > 12)
-                       return -EINVAL;
-               if (p_h264_pps->second_chroma_qp_index_offset < -12 ||
-                   p_h264_pps->second_chroma_qp_index_offset > 12)
-                       return -EINVAL;
-               break;
-
-       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
-               break;
-
-       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
-               p_h264_pred_weights = p;
-
-               if (p_h264_pred_weights->luma_log2_weight_denom > 7)
-                       return -EINVAL;
-               if (p_h264_pred_weights->chroma_log2_weight_denom > 7)
-                       return -EINVAL;
-               break;
-
-       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
-               p_h264_slice_params = p;
-
-               if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
-                       p_h264_slice_params->flags &=
-                               ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED;
-
-               if (p_h264_slice_params->colour_plane_id > 2)
-                       return -EINVAL;
-               if (p_h264_slice_params->cabac_init_idc > 2)
-                       return -EINVAL;
-               if (p_h264_slice_params->disable_deblocking_filter_idc > 2)
-                       return -EINVAL;
-               if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 ||
-                   p_h264_slice_params->slice_alpha_c0_offset_div2 > 6)
-                       return -EINVAL;
-               if (p_h264_slice_params->slice_beta_offset_div2 < -6 ||
-                   p_h264_slice_params->slice_beta_offset_div2 > 6)
-                       return -EINVAL;
-
-               if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I ||
-                   p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI)
-                       p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0;
-               if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
-                       p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0;
-
-               if (p_h264_slice_params->num_ref_idx_l0_active_minus1 >
-                   (V4L2_H264_REF_LIST_LEN - 1))
-                       return -EINVAL;
-               if (p_h264_slice_params->num_ref_idx_l1_active_minus1 >
-                   (V4L2_H264_REF_LIST_LEN - 1))
-                       return -EINVAL;
-               zero_reserved(*p_h264_slice_params);
-               break;
-
-       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
-               p_h264_dec_params = p;
-
-               if (p_h264_dec_params->nal_ref_idc > 3)
-                       return -EINVAL;
-               for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
-                       struct v4l2_h264_dpb_entry *dpb_entry =
-                               &p_h264_dec_params->dpb[i];
-
-                       zero_reserved(*dpb_entry);
-               }
-               zero_reserved(*p_h264_dec_params);
-               break;
-
-       case V4L2_CTRL_TYPE_VP8_FRAME:
-               p_vp8_frame = p;
-
-               switch (p_vp8_frame->num_dct_parts) {
-               case 1:
-               case 2:
-               case 4:
-               case 8:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               zero_padding(p_vp8_frame->segment);
-               zero_padding(p_vp8_frame->lf);
-               zero_padding(p_vp8_frame->quant);
-               zero_padding(p_vp8_frame->entropy);
-               zero_padding(p_vp8_frame->coder_state);
-               break;
-
-       case V4L2_CTRL_TYPE_HEVC_SPS:
-               p_hevc_sps = p;
-
-               if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) {
-                       p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0;
-                       p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0;
-                       p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0;
-                       p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0;
-               }
-
-               if (!(p_hevc_sps->flags &
-                     V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT))
-                       p_hevc_sps->num_long_term_ref_pics_sps = 0;
-               break;
-
-       case V4L2_CTRL_TYPE_HEVC_PPS:
-               p_hevc_pps = p;
-
-               if (!(p_hevc_pps->flags &
-                     V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
-                       p_hevc_pps->diff_cu_qp_delta_depth = 0;
-
-               if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
-                       p_hevc_pps->num_tile_columns_minus1 = 0;
-                       p_hevc_pps->num_tile_rows_minus1 = 0;
-                       memset(&p_hevc_pps->column_width_minus1, 0,
-                              sizeof(p_hevc_pps->column_width_minus1));
-                       memset(&p_hevc_pps->row_height_minus1, 0,
-                              sizeof(p_hevc_pps->row_height_minus1));
-
-                       p_hevc_pps->flags &=
-                               ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
-               }
-
-               if (p_hevc_pps->flags &
-                   V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) {
-                       p_hevc_pps->pps_beta_offset_div2 = 0;
-                       p_hevc_pps->pps_tc_offset_div2 = 0;
-               }
-
-               zero_padding(*p_hevc_pps);
-               break;
-
-       case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
-               p_hevc_slice_params = p;
-
-               if (p_hevc_slice_params->num_active_dpb_entries >
-                   V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
-                       return -EINVAL;
-
-               zero_padding(p_hevc_slice_params->pred_weight_table);
-
-               for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries;
-                    i++) {
-                       struct v4l2_hevc_dpb_entry *dpb_entry =
-                               &p_hevc_slice_params->dpb[i];
-
-                       zero_padding(*dpb_entry);
-               }
-
-               zero_padding(*p_hevc_slice_params);
-               break;
-
-       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
-               break;
-
-       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
-               p_hdr10_mastering = p;
-
-               for (i = 0; i < 3; ++i) {
-                       if (p_hdr10_mastering->display_primaries_x[i] <
-                               V4L2_HDR10_MASTERING_PRIMARIES_X_LOW ||
-                           p_hdr10_mastering->display_primaries_x[i] >
-                               V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH ||
-                           p_hdr10_mastering->display_primaries_y[i] <
-                               V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW ||
-                           p_hdr10_mastering->display_primaries_y[i] >
-                               V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH)
-                               return -EINVAL;
-               }
-
-               if (p_hdr10_mastering->white_point_x <
-                       V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW ||
-                   p_hdr10_mastering->white_point_x >
-                       V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH ||
-                   p_hdr10_mastering->white_point_y <
-                       V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW ||
-                   p_hdr10_mastering->white_point_y >
-                       V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH)
-                       return -EINVAL;
-
-               if (p_hdr10_mastering->max_display_mastering_luminance <
-                       V4L2_HDR10_MASTERING_MAX_LUMA_LOW ||
-                   p_hdr10_mastering->max_display_mastering_luminance >
-                       V4L2_HDR10_MASTERING_MAX_LUMA_HIGH ||
-                   p_hdr10_mastering->min_display_mastering_luminance <
-                       V4L2_HDR10_MASTERING_MIN_LUMA_LOW ||
-                   p_hdr10_mastering->min_display_mastering_luminance >
-                       V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
-                       return -EINVAL;
-
-               /* The following restriction comes from ITU-T Rec. H.265 spec */
-               if (p_hdr10_mastering->max_display_mastering_luminance ==
-                       V4L2_HDR10_MASTERING_MAX_LUMA_LOW &&
-                   p_hdr10_mastering->min_display_mastering_luminance ==
-                       V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
-                       return -EINVAL;
-
-               break;
-
-       case V4L2_CTRL_TYPE_AREA:
-               area = p;
-               if (!area->width || !area->height)
-                       return -EINVAL;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
-                       union v4l2_ctrl_ptr ptr)
-{
-       size_t len;
-       u64 offset;
-       s64 val;
-
-       switch ((u32)ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-               return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
-       case V4L2_CTRL_TYPE_INTEGER64:
-               /*
-                * We can't use the ROUND_TO_RANGE define here due to
-                * the u64 divide that needs special care.
-                */
-               val = ptr.p_s64[idx];
-               if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2))
-                       val = ctrl->maximum;
-               else
-                       val += (s64)(ctrl->step / 2);
-               val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
-               offset = val - ctrl->minimum;
-               do_div(offset, ctrl->step);
-               ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step;
-               return 0;
-       case V4L2_CTRL_TYPE_U8:
-               return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
-       case V4L2_CTRL_TYPE_U16:
-               return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
-       case V4L2_CTRL_TYPE_U32:
-               return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl);
-
-       case V4L2_CTRL_TYPE_BOOLEAN:
-               ptr.p_s32[idx] = !!ptr.p_s32[idx];
-               return 0;
-
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-               if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
-                       return -ERANGE;
-               if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
-                   (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
-                       return -EINVAL;
-               if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
-                   ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
-                       return -EINVAL;
-               return 0;
-
-       case V4L2_CTRL_TYPE_BITMASK:
-               ptr.p_s32[idx] &= ctrl->maximum;
-               return 0;
-
-       case V4L2_CTRL_TYPE_BUTTON:
-       case V4L2_CTRL_TYPE_CTRL_CLASS:
-               ptr.p_s32[idx] = 0;
-               return 0;
-
-       case V4L2_CTRL_TYPE_STRING:
-               idx *= ctrl->elem_size;
-               len = strlen(ptr.p_char + idx);
-               if (len < ctrl->minimum)
-                       return -ERANGE;
-               if ((len - (u32)ctrl->minimum) % (u32)ctrl->step)
-                       return -ERANGE;
-               return 0;
-
-       default:
-               return std_validate_compound(ctrl, idx, ptr);
-       }
-}
-
-static const struct v4l2_ctrl_type_ops std_type_ops = {
-       .equal = std_equal,
-       .init = std_init,
-       .log = std_log,
-       .validate = std_validate,
-};
-
-/* Helper function: copy the given control value back to the caller */
-static int ptr_to_user(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl *ctrl,
-                      union v4l2_ctrl_ptr ptr)
-{
-       u32 len;
-
-       if (ctrl->is_ptr && !ctrl->is_string)
-               return copy_to_user(c->ptr, ptr.p_const, c->size) ?
-                      -EFAULT : 0;
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_STRING:
-               len = strlen(ptr.p_char);
-               if (c->size < len + 1) {
-                       c->size = ctrl->elem_size;
-                       return -ENOSPC;
-               }
-               return copy_to_user(c->string, ptr.p_char, len + 1) ?
-                      -EFAULT : 0;
-       case V4L2_CTRL_TYPE_INTEGER64:
-               c->value64 = *ptr.p_s64;
-               break;
-       default:
-               c->value = *ptr.p_s32;
-               break;
-       }
-       return 0;
-}
-
-/* Helper function: copy the current control value back to the caller */
-static int cur_to_user(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl *ctrl)
-{
-       return ptr_to_user(c, ctrl, ctrl->p_cur);
-}
-
-/* Helper function: copy the new control value back to the caller */
-static int new_to_user(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl *ctrl)
-{
-       return ptr_to_user(c, ctrl, ctrl->p_new);
-}
-
-/* Helper function: copy the request value back to the caller */
-static int req_to_user(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl_ref *ref)
-{
-       return ptr_to_user(c, ref->ctrl, ref->p_req);
-}
-
-/* Helper function: copy the initial control value back to the caller */
-static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
-{
-       int idx;
-
-       for (idx = 0; idx < ctrl->elems; idx++)
-               ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
-
-       return ptr_to_user(c, ctrl, ctrl->p_new);
-}
-
-/* Helper function: copy the caller-provider value to the given control value */
-static int user_to_ptr(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl *ctrl,
-                      union v4l2_ctrl_ptr ptr)
-{
-       int ret;
-       u32 size;
-
-       ctrl->is_new = 1;
-       if (ctrl->is_ptr && !ctrl->is_string) {
-               unsigned idx;
-
-               ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
-               if (ret || !ctrl->is_array)
-                       return ret;
-               for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
-                       ctrl->type_ops->init(ctrl, idx, ptr);
-               return 0;
-       }
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER64:
-               *ptr.p_s64 = c->value64;
-               break;
-       case V4L2_CTRL_TYPE_STRING:
-               size = c->size;
-               if (size == 0)
-                       return -ERANGE;
-               if (size > ctrl->maximum + 1)
-                       size = ctrl->maximum + 1;
-               ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
-               if (!ret) {
-                       char last = ptr.p_char[size - 1];
-
-                       ptr.p_char[size - 1] = 0;
-                       /* If the string was longer than ctrl->maximum,
-                          then return an error. */
-                       if (strlen(ptr.p_char) == ctrl->maximum && last)
-                               return -ERANGE;
-               }
-               return ret;
-       default:
-               *ptr.p_s32 = c->value;
-               break;
-       }
-       return 0;
-}
-
-/* Helper function: copy the caller-provider value as the new control value */
-static int user_to_new(struct v4l2_ext_control *c,
-                      struct v4l2_ctrl *ctrl)
-{
-       return user_to_ptr(c, ctrl, ctrl->p_new);
-}
-
-/* Copy the one value to another. */
-static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
-                      union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
-{
-       if (ctrl == NULL)
-               return;
-       memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
-}
-
-/* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
-{
-       bool changed;
-
-       if (ctrl == NULL)
-               return;
-
-       /* has_changed is set by cluster_changed */
-       changed = ctrl->has_changed;
-       if (changed)
-               ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
-
-       if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
-               /* Note: CH_FLAGS is only set for auto clusters. */
-               ctrl->flags &=
-                       ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
-               if (!is_cur_manual(ctrl->cluster[0])) {
-                       ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-                       if (ctrl->cluster[0]->has_volatiles)
-                               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
-               }
-               fh = NULL;
-       }
-       if (changed || ch_flags) {
-               /* If a control was changed that was not one of the controls
-                  modified by the application, then send the event to all. */
-               if (!ctrl->is_new)
-                       fh = NULL;
-               send_event(fh, ctrl,
-                       (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
-               if (ctrl->call_notify && changed && ctrl->handler->notify)
-                       ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
-       }
-}
-
-/* Copy the current value to the new value */
-static void cur_to_new(struct v4l2_ctrl *ctrl)
-{
-       if (ctrl == NULL)
-               return;
-       ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
-}
-
-/* Copy the new value to the request value */
-static void new_to_req(struct v4l2_ctrl_ref *ref)
-{
-       if (!ref)
-               return;
-       ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
-       ref->valid_p_req = true;
-}
-
-/* Copy the current value to the request value */
-static void cur_to_req(struct v4l2_ctrl_ref *ref)
-{
-       if (!ref)
-               return;
-       ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
-       ref->valid_p_req = true;
-}
-
-/* Copy the request value to the new value */
-static void req_to_new(struct v4l2_ctrl_ref *ref)
-{
-       if (!ref)
-               return;
-       if (ref->valid_p_req)
-               ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
-       else
-               ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
-}
-
-/* Return non-zero if one or more of the controls in the cluster has a new
-   value that differs from the current value. */
-static int cluster_changed(struct v4l2_ctrl *master)
-{
-       bool changed = false;
-       unsigned idx;
-       int i;
-
-       for (i = 0; i < master->ncontrols; i++) {
-               struct v4l2_ctrl *ctrl = master->cluster[i];
-               bool ctrl_changed = false;
-
-               if (ctrl == NULL)
-                       continue;
-
-               if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE)
-                       changed = ctrl_changed = true;
-
-               /*
-                * Set has_changed to false to avoid generating
-                * the event V4L2_EVENT_CTRL_CH_VALUE
-                */
-               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
-                       ctrl->has_changed = false;
-                       continue;
-               }
-
-               for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
-                       ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
-                               ctrl->p_cur, ctrl->p_new);
-               ctrl->has_changed = ctrl_changed;
-               changed |= ctrl->has_changed;
-       }
-       return changed;
-}
-
-/* Control range checking */
-static int check_range(enum v4l2_ctrl_type type,
-               s64 min, s64 max, u64 step, s64 def)
-{
-       switch (type) {
-       case V4L2_CTRL_TYPE_BOOLEAN:
-               if (step != 1 || max > 1 || min < 0)
-                       return -ERANGE;
-               fallthrough;
-       case V4L2_CTRL_TYPE_U8:
-       case V4L2_CTRL_TYPE_U16:
-       case V4L2_CTRL_TYPE_U32:
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_INTEGER64:
-               if (step == 0 || min > max || def < min || def > max)
-                       return -ERANGE;
-               return 0;
-       case V4L2_CTRL_TYPE_BITMASK:
-               if (step || min || !max || (def & ~max))
-                       return -ERANGE;
-               return 0;
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-               if (min > max || def < min || def > max)
-                       return -ERANGE;
-               /* Note: step == menu_skip_mask for menu controls.
-                  So here we check if the default value is masked out. */
-               if (step && ((1 << def) & step))
-                       return -EINVAL;
-               return 0;
-       case V4L2_CTRL_TYPE_STRING:
-               if (min > max || min < 0 || step < 1 || def)
-                       return -ERANGE;
-               return 0;
-       default:
-               return 0;
-       }
-}
-
-/* Validate a new control */
-static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
-{
-       unsigned idx;
-       int err = 0;
-
-       for (idx = 0; !err && idx < ctrl->elems; idx++)
-               err = ctrl->type_ops->validate(ctrl, idx, p_new);
-       return err;
-}
-
-static inline u32 node2id(struct list_head *node)
-{
-       return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
-}
-
-/* Set the handler's error code if it wasn't set earlier already */
-static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
-{
-       if (hdl->error == 0)
-               hdl->error = err;
-       return err;
-}
-
-/* Initialize the handler */
-int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
-                                unsigned nr_of_controls_hint,
-                                struct lock_class_key *key, const char *name)
-{
-       mutex_init(&hdl->_lock);
-       hdl->lock = &hdl->_lock;
-       lockdep_set_class_and_name(hdl->lock, key, name);
-       INIT_LIST_HEAD(&hdl->ctrls);
-       INIT_LIST_HEAD(&hdl->ctrl_refs);
-       INIT_LIST_HEAD(&hdl->requests);
-       INIT_LIST_HEAD(&hdl->requests_queued);
-       hdl->request_is_queued = false;
-       hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
-       hdl->buckets = kvmalloc_array(hdl->nr_of_buckets,
-                                     sizeof(hdl->buckets[0]),
-                                     GFP_KERNEL | __GFP_ZERO);
-       hdl->error = hdl->buckets ? 0 : -ENOMEM;
-       media_request_object_init(&hdl->req_obj);
-       return hdl->error;
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
-
-/* Free all controls and control refs */
-void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
-{
-       struct v4l2_ctrl_ref *ref, *next_ref;
-       struct v4l2_ctrl *ctrl, *next_ctrl;
-       struct v4l2_subscribed_event *sev, *next_sev;
-
-       if (hdl == NULL || hdl->buckets == NULL)
-               return;
-
-       /*
-        * If the main handler is freed and it is used by handler objects in
-        * outstanding requests, then unbind and put those objects before
-        * freeing the main handler.
-        *
-        * The main handler can be identified by having a NULL ops pointer in
-        * the request object.
-        */
-       if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) {
-               struct v4l2_ctrl_handler *req, *next_req;
-
-               list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
-                       media_request_object_unbind(&req->req_obj);
-                       media_request_object_put(&req->req_obj);
-               }
-       }
-       mutex_lock(hdl->lock);
-       /* Free all nodes */
-       list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
-               list_del(&ref->node);
-               kfree(ref);
-       }
-       /* Free all controls owned by the handler */
-       list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
-               list_del(&ctrl->node);
-               list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
-                       list_del(&sev->node);
-               kvfree(ctrl);
-       }
-       kvfree(hdl->buckets);
-       hdl->buckets = NULL;
-       hdl->cached = NULL;
-       hdl->error = 0;
-       mutex_unlock(hdl->lock);
-       mutex_destroy(&hdl->_lock);
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_free);
-
-/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
-   be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
-   with applications that do not use the NEXT_CTRL flag.
-
-   We just find the n-th private user control. It's O(N), but that should not
-   be an issue in this particular case. */
-static struct v4l2_ctrl_ref *find_private_ref(
-               struct v4l2_ctrl_handler *hdl, u32 id)
-{
-       struct v4l2_ctrl_ref *ref;
-
-       id -= V4L2_CID_PRIVATE_BASE;
-       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
-               /* Search for private user controls that are compatible with
-                  VIDIOC_G/S_CTRL. */
-               if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
-                   V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
-                       if (!ref->ctrl->is_int)
-                               continue;
-                       if (id == 0)
-                               return ref;
-                       id--;
-               }
-       }
-       return NULL;
-}
-
-/* Find a control with the given ID. */
-static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
-{
-       struct v4l2_ctrl_ref *ref;
-       int bucket;
-
-       id &= V4L2_CTRL_ID_MASK;
-
-       /* Old-style private controls need special handling */
-       if (id >= V4L2_CID_PRIVATE_BASE)
-               return find_private_ref(hdl, id);
-       bucket = id % hdl->nr_of_buckets;
-
-       /* Simple optimization: cache the last control found */
-       if (hdl->cached && hdl->cached->ctrl->id == id)
-               return hdl->cached;
-
-       /* Not in cache, search the hash */
-       ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
-       while (ref && ref->ctrl->id != id)
-               ref = ref->next;
-
-       if (ref)
-               hdl->cached = ref; /* cache it! */
-       return ref;
-}
-
-/* Find a control with the given ID. Take the handler's lock first. */
-static struct v4l2_ctrl_ref *find_ref_lock(
-               struct v4l2_ctrl_handler *hdl, u32 id)
-{
-       struct v4l2_ctrl_ref *ref = NULL;
-
-       if (hdl) {
-               mutex_lock(hdl->lock);
-               ref = find_ref(hdl, id);
-               mutex_unlock(hdl->lock);
-       }
-       return ref;
-}
-
-/* Find a control with the given ID. */
-struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
-{
-       struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
-
-       return ref ? ref->ctrl : NULL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_find);
-
-/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
-static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
-                          struct v4l2_ctrl *ctrl,
-                          struct v4l2_ctrl_ref **ctrl_ref,
-                          bool from_other_dev, bool allocate_req)
-{
-       struct v4l2_ctrl_ref *ref;
-       struct v4l2_ctrl_ref *new_ref;
-       u32 id = ctrl->id;
-       u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
-       int bucket = id % hdl->nr_of_buckets;   /* which bucket to use */
-       unsigned int size_extra_req = 0;
-
-       if (ctrl_ref)
-               *ctrl_ref = NULL;
-
-       /*
-        * Automatically add the control class if it is not yet present and
-        * the new control is not a compound control.
-        */
-       if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
-           id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
-               if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
-                       return hdl->error;
-
-       if (hdl->error)
-               return hdl->error;
-
-       if (allocate_req)
-               size_extra_req = ctrl->elems * ctrl->elem_size;
-       new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
-       if (!new_ref)
-               return handler_set_err(hdl, -ENOMEM);
-       new_ref->ctrl = ctrl;
-       new_ref->from_other_dev = from_other_dev;
-       if (size_extra_req)
-               new_ref->p_req.p = &new_ref[1];
-
-       INIT_LIST_HEAD(&new_ref->node);
-
-       mutex_lock(hdl->lock);
-
-       /* Add immediately at the end of the list if the list is empty, or if
-          the last element in the list has a lower ID.
-          This ensures that when elements are added in ascending order the
-          insertion is an O(1) operation. */
-       if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
-               list_add_tail(&new_ref->node, &hdl->ctrl_refs);
-               goto insert_in_hash;
-       }
-
-       /* Find insert position in sorted list */
-       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
-               if (ref->ctrl->id < id)
-                       continue;
-               /* Don't add duplicates */
-               if (ref->ctrl->id == id) {
-                       kfree(new_ref);
-                       goto unlock;
-               }
-               list_add(&new_ref->node, ref->node.prev);
-               break;
-       }
-
-insert_in_hash:
-       /* Insert the control node in the hash */
-       new_ref->next = hdl->buckets[bucket];
-       hdl->buckets[bucket] = new_ref;
-       if (ctrl_ref)
-               *ctrl_ref = new_ref;
-       if (ctrl->handler == hdl) {
-               /* By default each control starts in a cluster of its own.
-                * new_ref->ctrl is basically a cluster array with one
-                * element, so that's perfect to use as the cluster pointer.
-                * But only do this for the handler that owns the control.
-                */
-               ctrl->cluster = &new_ref->ctrl;
-               ctrl->ncontrols = 1;
-       }
-
-unlock:
-       mutex_unlock(hdl->lock);
-       return 0;
-}
-
-/* Add a new control */
-static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_ops *ops,
-                       const struct v4l2_ctrl_type_ops *type_ops,
-                       u32 id, const char *name, enum v4l2_ctrl_type type,
-                       s64 min, s64 max, u64 step, s64 def,
-                       const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
-                       u32 flags, const char * const *qmenu,
-                       const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
-                       void *priv)
-{
-       struct v4l2_ctrl *ctrl;
-       unsigned sz_extra;
-       unsigned nr_of_dims = 0;
-       unsigned elems = 1;
-       bool is_array;
-       unsigned tot_ctrl_size;
-       unsigned idx;
-       void *data;
-       int err;
-
-       if (hdl->error)
-               return NULL;
-
-       while (dims && dims[nr_of_dims]) {
-               elems *= dims[nr_of_dims];
-               nr_of_dims++;
-               if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
-                       break;
-       }
-       is_array = nr_of_dims > 0;
-
-       /* Prefill elem_size for all types handled by std_type_ops */
-       switch ((u32)type) {
-       case V4L2_CTRL_TYPE_INTEGER64:
-               elem_size = sizeof(s64);
-               break;
-       case V4L2_CTRL_TYPE_STRING:
-               elem_size = max + 1;
-               break;
-       case V4L2_CTRL_TYPE_U8:
-               elem_size = sizeof(u8);
-               break;
-       case V4L2_CTRL_TYPE_U16:
-               elem_size = sizeof(u16);
-               break;
-       case V4L2_CTRL_TYPE_U32:
-               elem_size = sizeof(u32);
-               break;
-       case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
-               elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params);
-               break;
-       case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
-               elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization);
-               break;
-       case V4L2_CTRL_TYPE_FWHT_PARAMS:
-               elem_size = sizeof(struct v4l2_ctrl_fwht_params);
-               break;
-       case V4L2_CTRL_TYPE_H264_SPS:
-               elem_size = sizeof(struct v4l2_ctrl_h264_sps);
-               break;
-       case V4L2_CTRL_TYPE_H264_PPS:
-               elem_size = sizeof(struct v4l2_ctrl_h264_pps);
-               break;
-       case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
-               elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix);
-               break;
-       case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
-               elem_size = sizeof(struct v4l2_ctrl_h264_slice_params);
-               break;
-       case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
-               elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
-               break;
-       case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
-               elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
-               break;
-       case V4L2_CTRL_TYPE_VP8_FRAME:
-               elem_size = sizeof(struct v4l2_ctrl_vp8_frame);
-               break;
-       case V4L2_CTRL_TYPE_HEVC_SPS:
-               elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
-               break;
-       case V4L2_CTRL_TYPE_HEVC_PPS:
-               elem_size = sizeof(struct v4l2_ctrl_hevc_pps);
-               break;
-       case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
-               elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
-               break;
-       case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
-               elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info);
-               break;
-       case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
-               elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display);
-               break;
-       case V4L2_CTRL_TYPE_AREA:
-               elem_size = sizeof(struct v4l2_area);
-               break;
-       default:
-               if (type < V4L2_CTRL_COMPOUND_TYPES)
-                       elem_size = sizeof(s32);
-               break;
-       }
-       tot_ctrl_size = elem_size * elems;
-
-       /* Sanity checks */
-       if (id == 0 || name == NULL || !elem_size ||
-           id >= V4L2_CID_PRIVATE_BASE ||
-           (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
-           (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
-               handler_set_err(hdl, -ERANGE);
-               return NULL;
-       }
-       err = check_range(type, min, max, step, def);
-       if (err) {
-               handler_set_err(hdl, err);
-               return NULL;
-       }
-       if (is_array &&
-           (type == V4L2_CTRL_TYPE_BUTTON ||
-            type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-
-       sz_extra = 0;
-       if (type == V4L2_CTRL_TYPE_BUTTON)
-               flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
-                       V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
-       else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
-               flags |= V4L2_CTRL_FLAG_READ_ONLY;
-       else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
-                type == V4L2_CTRL_TYPE_STRING ||
-                type >= V4L2_CTRL_COMPOUND_TYPES ||
-                is_array)
-               sz_extra += 2 * tot_ctrl_size;
-
-       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
-               sz_extra += elem_size;
-
-       ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
-       if (ctrl == NULL) {
-               handler_set_err(hdl, -ENOMEM);
-               return NULL;
-       }
-
-       INIT_LIST_HEAD(&ctrl->node);
-       INIT_LIST_HEAD(&ctrl->ev_subs);
-       ctrl->handler = hdl;
-       ctrl->ops = ops;
-       ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
-       ctrl->id = id;
-       ctrl->name = name;
-       ctrl->type = type;
-       ctrl->flags = flags;
-       ctrl->minimum = min;
-       ctrl->maximum = max;
-       ctrl->step = step;
-       ctrl->default_value = def;
-       ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
-       ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
-       ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
-       ctrl->is_array = is_array;
-       ctrl->elems = elems;
-       ctrl->nr_of_dims = nr_of_dims;
-       if (nr_of_dims)
-               memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
-       ctrl->elem_size = elem_size;
-       if (type == V4L2_CTRL_TYPE_MENU)
-               ctrl->qmenu = qmenu;
-       else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
-               ctrl->qmenu_int = qmenu_int;
-       ctrl->priv = priv;
-       ctrl->cur.val = ctrl->val = def;
-       data = &ctrl[1];
-
-       if (!ctrl->is_int) {
-               ctrl->p_new.p = data;
-               ctrl->p_cur.p = data + tot_ctrl_size;
-       } else {
-               ctrl->p_new.p = &ctrl->val;
-               ctrl->p_cur.p = &ctrl->cur.val;
-       }
-
-       if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
-               ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
-               memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
-       }
-
-       for (idx = 0; idx < elems; idx++) {
-               ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
-               ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
-       }
-
-       if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
-               kvfree(ctrl);
-               return NULL;
-       }
-       mutex_lock(hdl->lock);
-       list_add_tail(&ctrl->node, &hdl->ctrls);
-       mutex_unlock(hdl->lock);
-       return ctrl;
-}
-
-struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_config *cfg, void *priv)
-{
-       bool is_menu;
-       struct v4l2_ctrl *ctrl;
-       const char *name = cfg->name;
-       const char * const *qmenu = cfg->qmenu;
-       const s64 *qmenu_int = cfg->qmenu_int;
-       enum v4l2_ctrl_type type = cfg->type;
-       u32 flags = cfg->flags;
-       s64 min = cfg->min;
-       s64 max = cfg->max;
-       u64 step = cfg->step;
-       s64 def = cfg->def;
-
-       if (name == NULL)
-               v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
-                                                               &def, &flags);
-
-       is_menu = (type == V4L2_CTRL_TYPE_MENU ||
-                  type == V4L2_CTRL_TYPE_INTEGER_MENU);
-       if (is_menu)
-               WARN_ON(step);
-       else
-               WARN_ON(cfg->menu_skip_mask);
-       if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
-               qmenu = v4l2_ctrl_get_menu(cfg->id);
-       } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-
-       ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
-                       type, min, max,
-                       is_menu ? cfg->menu_skip_mask : step, def,
-                       cfg->dims, cfg->elem_size,
-                       flags, qmenu, qmenu_int, cfg->p_def, priv);
-       if (ctrl)
-               ctrl->is_private = cfg->is_private;
-       return ctrl;
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_custom);
-
-/* Helper function for standard non-menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_ops *ops,
-                       u32 id, s64 min, s64 max, u64 step, s64 def)
-{
-       const char *name;
-       enum v4l2_ctrl_type type;
-       u32 flags;
-
-       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-       if (type == V4L2_CTRL_TYPE_MENU ||
-           type == V4L2_CTRL_TYPE_INTEGER_MENU ||
-           type >= V4L2_CTRL_COMPOUND_TYPES) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-                            min, max, step, def, NULL, 0,
-                            flags, NULL, NULL, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std);
-
-/* Helper function for standard menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_ops *ops,
-                       u32 id, u8 _max, u64 mask, u8 _def)
-{
-       const char * const *qmenu = NULL;
-       const s64 *qmenu_int = NULL;
-       unsigned int qmenu_int_len = 0;
-       const char *name;
-       enum v4l2_ctrl_type type;
-       s64 min;
-       s64 max = _max;
-       s64 def = _def;
-       u64 step;
-       u32 flags;
-
-       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-
-       if (type == V4L2_CTRL_TYPE_MENU)
-               qmenu = v4l2_ctrl_get_menu(id);
-       else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
-               qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
-
-       if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-                            0, max, mask, def, NULL, 0,
-                            flags, qmenu, qmenu_int, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
-
-/* Helper function for standard menu controls with driver defined menu */
-struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
-                       u64 mask, u8 _def, const char * const *qmenu)
-{
-       enum v4l2_ctrl_type type;
-       const char *name;
-       u32 flags;
-       u64 step;
-       s64 min;
-       s64 max = _max;
-       s64 def = _def;
-
-       /* v4l2_ctrl_new_std_menu_items() should only be called for
-        * standard controls without a standard menu.
-        */
-       if (v4l2_ctrl_get_menu(id)) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-
-       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-       if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-                            0, max, mask, def, NULL, 0,
-                            flags, qmenu, NULL, ptr_null, NULL);
-
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
-
-/* Helper function for standard compound controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
-                               const struct v4l2_ctrl_ops *ops, u32 id,
-                               const union v4l2_ctrl_ptr p_def)
-{
-       const char *name;
-       enum v4l2_ctrl_type type;
-       u32 flags;
-       s64 min, max, step, def;
-
-       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-       if (type < V4L2_CTRL_COMPOUND_TYPES) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-                            min, max, step, def, NULL, 0,
-                            flags, NULL, NULL, p_def, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
-
-/* Helper function for standard integer menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
-                       const struct v4l2_ctrl_ops *ops,
-                       u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
-{
-       const char *name;
-       enum v4l2_ctrl_type type;
-       s64 min;
-       u64 step;
-       s64 max = _max;
-       s64 def = _def;
-       u32 flags;
-
-       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-       if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
-               handler_set_err(hdl, -EINVAL);
-               return NULL;
-       }
-       return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
-                            0, max, 0, def, NULL, 0,
-                            flags, NULL, qmenu_int, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
-
-/* Add the controls from another handler to our own. */
-int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
-                         struct v4l2_ctrl_handler *add,
-                         bool (*filter)(const struct v4l2_ctrl *ctrl),
-                         bool from_other_dev)
-{
-       struct v4l2_ctrl_ref *ref;
-       int ret = 0;
-
-       /* Do nothing if either handler is NULL or if they are the same */
-       if (!hdl || !add || hdl == add)
-               return 0;
-       if (hdl->error)
-               return hdl->error;
-       mutex_lock(add->lock);
-       list_for_each_entry(ref, &add->ctrl_refs, node) {
-               struct v4l2_ctrl *ctrl = ref->ctrl;
-
-               /* Skip handler-private controls. */
-               if (ctrl->is_private)
-                       continue;
-               /* And control classes */
-               if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
-                       continue;
-               /* Filter any unwanted controls */
-               if (filter && !filter(ctrl))
-                       continue;
-               ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
-               if (ret)
-                       break;
-       }
-       mutex_unlock(add->lock);
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_add_handler);
-
-bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
-{
-       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
-               return true;
-       if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
-               return true;
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
-
-/* Cluster controls */
-void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
-{
-       bool has_volatiles = false;
-       int i;
-
-       /* The first control is the master control and it must not be NULL */
-       if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
-               return;
-
-       for (i = 0; i < ncontrols; i++) {
-               if (controls[i]) {
-                       controls[i]->cluster = controls;
-                       controls[i]->ncontrols = ncontrols;
-                       if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
-                               has_volatiles = true;
-               }
-       }
-       controls[0]->has_volatiles = has_volatiles;
-}
-EXPORT_SYMBOL(v4l2_ctrl_cluster);
-
-void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
-                           u8 manual_val, bool set_volatile)
-{
-       struct v4l2_ctrl *master = controls[0];
-       u32 flag = 0;
-       int i;
-
-       v4l2_ctrl_cluster(ncontrols, controls);
-       WARN_ON(ncontrols <= 1);
-       WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
-       WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
-       master->is_auto = true;
-       master->has_volatiles = set_volatile;
-       master->manual_mode_value = manual_val;
-       master->flags |= V4L2_CTRL_FLAG_UPDATE;
-
-       if (!is_cur_manual(master))
-               flag = V4L2_CTRL_FLAG_INACTIVE |
-                       (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
-
-       for (i = 1; i < ncontrols; i++)
-               if (controls[i])
-                       controls[i]->flags |= flag;
-}
-EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
-
-/* Activate/deactivate a control. */
-void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
-{
-       /* invert since the actual flag is called 'inactive' */
-       bool inactive = !active;
-       bool old;
-
-       if (ctrl == NULL)
-               return;
-
-       if (inactive)
-               /* set V4L2_CTRL_FLAG_INACTIVE */
-               old = test_and_set_bit(4, &ctrl->flags);
-       else
-               /* clear V4L2_CTRL_FLAG_INACTIVE */
-               old = test_and_clear_bit(4, &ctrl->flags);
-       if (old != inactive)
-               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
-}
-EXPORT_SYMBOL(v4l2_ctrl_activate);
-
-void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
-{
-       bool old;
-
-       if (ctrl == NULL)
-               return;
-
-       lockdep_assert_held(ctrl->handler->lock);
-
-       if (grabbed)
-               /* set V4L2_CTRL_FLAG_GRABBED */
-               old = test_and_set_bit(1, &ctrl->flags);
-       else
-               /* clear V4L2_CTRL_FLAG_GRABBED */
-               old = test_and_clear_bit(1, &ctrl->flags);
-       if (old != grabbed)
-               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_grab);
-
-/* Log the control name and value */
-static void log_ctrl(const struct v4l2_ctrl *ctrl,
-                    const char *prefix, const char *colon)
-{
-       if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
-               return;
-       if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
-               return;
-
-       pr_info("%s%s%s: ", prefix, colon, ctrl->name);
-
-       ctrl->type_ops->log(ctrl);
-
-       if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
-                          V4L2_CTRL_FLAG_GRABBED |
-                          V4L2_CTRL_FLAG_VOLATILE)) {
-               if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
-                       pr_cont(" inactive");
-               if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
-                       pr_cont(" grabbed");
-               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
-                       pr_cont(" volatile");
-       }
-       pr_cont("\n");
-}
-
-/* Log all controls owned by the handler */
-void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
-                                 const char *prefix)
-{
-       struct v4l2_ctrl *ctrl;
-       const char *colon = "";
-       int len;
-
-       if (hdl == NULL)
-               return;
-       if (prefix == NULL)
-               prefix = "";
-       len = strlen(prefix);
-       if (len && prefix[len - 1] != ' ')
-               colon = ": ";
-       mutex_lock(hdl->lock);
-       list_for_each_entry(ctrl, &hdl->ctrls, node)
-               if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
-                       log_ctrl(ctrl, prefix, colon);
-       mutex_unlock(hdl->lock);
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
-
-int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
-{
-       v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
-
-/* Call s_ctrl for all controls owned by the handler */
-int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
-{
-       struct v4l2_ctrl *ctrl;
-       int ret = 0;
-
-       if (hdl == NULL)
-               return 0;
-
-       lockdep_assert_held(hdl->lock);
-
-       list_for_each_entry(ctrl, &hdl->ctrls, node)
-               ctrl->done = false;
-
-       list_for_each_entry(ctrl, &hdl->ctrls, node) {
-               struct v4l2_ctrl *master = ctrl->cluster[0];
-               int i;
-
-               /* Skip if this control was already handled by a cluster. */
-               /* Skip button controls and read-only controls. */
-               if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
-                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
-                       continue;
-
-               for (i = 0; i < master->ncontrols; i++) {
-                       if (master->cluster[i]) {
-                               cur_to_new(master->cluster[i]);
-                               master->cluster[i]->is_new = 1;
-                               master->cluster[i]->done = true;
-                       }
-               }
-               ret = call_op(master, s_ctrl);
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup);
-
-int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
-{
-       int ret;
-
-       if (hdl == NULL)
-               return 0;
-
-       mutex_lock(hdl->lock);
-       ret = __v4l2_ctrl_handler_setup(hdl);
-       mutex_unlock(hdl->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
-
-/* Implement VIDIOC_QUERY_EXT_CTRL */
-int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
-{
-       const unsigned next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
-       u32 id = qc->id & V4L2_CTRL_ID_MASK;
-       struct v4l2_ctrl_ref *ref;
-       struct v4l2_ctrl *ctrl;
-
-       if (hdl == NULL)
-               return -EINVAL;
-
-       mutex_lock(hdl->lock);
-
-       /* Try to find it */
-       ref = find_ref(hdl, id);
-
-       if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
-               bool is_compound;
-               /* Match any control that is not hidden */
-               unsigned mask = 1;
-               bool match = false;
-
-               if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
-                       /* Match any hidden control */
-                       match = true;
-               } else if ((qc->id & next_flags) == next_flags) {
-                       /* Match any control, compound or not */
-                       mask = 0;
-               }
-
-               /* Find the next control with ID > qc->id */
-
-               /* Did we reach the end of the control list? */
-               if (id >= node2id(hdl->ctrl_refs.prev)) {
-                       ref = NULL; /* Yes, so there is no next control */
-               } else if (ref) {
-                       /* We found a control with the given ID, so just get
-                          the next valid one in the list. */
-                       list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
-                               is_compound = ref->ctrl->is_array ||
-                                       ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
-                               if (id < ref->ctrl->id &&
-                                   (is_compound & mask) == match)
-                                       break;
-                       }
-                       if (&ref->node == &hdl->ctrl_refs)
-                               ref = NULL;
-               } else {
-                       /* No control with the given ID exists, so start
-                          searching for the next largest ID. We know there
-                          is one, otherwise the first 'if' above would have
-                          been true. */
-                       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
-                               is_compound = ref->ctrl->is_array ||
-                                       ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
-                               if (id < ref->ctrl->id &&
-                                   (is_compound & mask) == match)
-                                       break;
-                       }
-                       if (&ref->node == &hdl->ctrl_refs)
-                               ref = NULL;
-               }
-       }
-       mutex_unlock(hdl->lock);
-
-       if (!ref)
-               return -EINVAL;
-
-       ctrl = ref->ctrl;
-       memset(qc, 0, sizeof(*qc));
-       if (id >= V4L2_CID_PRIVATE_BASE)
-               qc->id = id;
-       else
-               qc->id = ctrl->id;
-       strscpy(qc->name, ctrl->name, sizeof(qc->name));
-       qc->flags = user_flags(ctrl);
-       qc->type = ctrl->type;
-       qc->elem_size = ctrl->elem_size;
-       qc->elems = ctrl->elems;
-       qc->nr_of_dims = ctrl->nr_of_dims;
-       memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
-       qc->minimum = ctrl->minimum;
-       qc->maximum = ctrl->maximum;
-       qc->default_value = ctrl->default_value;
-       if (ctrl->type == V4L2_CTRL_TYPE_MENU
-           || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
-               qc->step = 1;
-       else
-               qc->step = ctrl->step;
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_query_ext_ctrl);
-
-/* Implement VIDIOC_QUERYCTRL */
-int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
-{
-       struct v4l2_query_ext_ctrl qec = { qc->id };
-       int rc;
-
-       rc = v4l2_query_ext_ctrl(hdl, &qec);
-       if (rc)
-               return rc;
-
-       qc->id = qec.id;
-       qc->type = qec.type;
-       qc->flags = qec.flags;
-       strscpy(qc->name, qec.name, sizeof(qc->name));
-       switch (qc->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-       case V4L2_CTRL_TYPE_STRING:
-       case V4L2_CTRL_TYPE_BITMASK:
-               qc->minimum = qec.minimum;
-               qc->maximum = qec.maximum;
-               qc->step = qec.step;
-               qc->default_value = qec.default_value;
-               break;
-       default:
-               qc->minimum = 0;
-               qc->maximum = 0;
-               qc->step = 0;
-               qc->default_value = 0;
-               break;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_queryctrl);
-
-/* Implement VIDIOC_QUERYMENU */
-int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
-{
-       struct v4l2_ctrl *ctrl;
-       u32 i = qm->index;
-
-       ctrl = v4l2_ctrl_find(hdl, qm->id);
-       if (!ctrl)
-               return -EINVAL;
-
-       qm->reserved = 0;
-       /* Sanity checks */
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_MENU:
-               if (ctrl->qmenu == NULL)
-                       return -EINVAL;
-               break;
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-               if (ctrl->qmenu_int == NULL)
-                       return -EINVAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (i < ctrl->minimum || i > ctrl->maximum)
-               return -EINVAL;
-
-       /* Use mask to see if this menu item should be skipped */
-       if (ctrl->menu_skip_mask & (1ULL << i))
-               return -EINVAL;
-       /* Empty menu items should also be skipped */
-       if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
-               if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
-                       return -EINVAL;
-               strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
-       } else {
-               qm->value = ctrl->qmenu_int[i];
-       }
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_querymenu);
-
-static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
-                                  const struct v4l2_ctrl_handler *from)
-{
-       struct v4l2_ctrl_ref *ref;
-       int err = 0;
-
-       if (WARN_ON(!hdl || hdl == from))
-               return -EINVAL;
-
-       if (hdl->error)
-               return hdl->error;
-
-       WARN_ON(hdl->lock != &hdl->_lock);
-
-       mutex_lock(from->lock);
-       list_for_each_entry(ref, &from->ctrl_refs, node) {
-               struct v4l2_ctrl *ctrl = ref->ctrl;
-               struct v4l2_ctrl_ref *new_ref;
-
-               /* Skip refs inherited from other devices */
-               if (ref->from_other_dev)
-                       continue;
-               err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
-               if (err)
-                       break;
-       }
-       mutex_unlock(from->lock);
-       return err;
-}
-
-static void v4l2_ctrl_request_queue(struct media_request_object *obj)
-{
-       struct v4l2_ctrl_handler *hdl =
-               container_of(obj, struct v4l2_ctrl_handler, req_obj);
-       struct v4l2_ctrl_handler *main_hdl = obj->priv;
-
-       mutex_lock(main_hdl->lock);
-       list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
-       hdl->request_is_queued = true;
-       mutex_unlock(main_hdl->lock);
-}
-
-static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
-{
-       struct v4l2_ctrl_handler *hdl =
-               container_of(obj, struct v4l2_ctrl_handler, req_obj);
-       struct v4l2_ctrl_handler *main_hdl = obj->priv;
-
-       mutex_lock(main_hdl->lock);
-       list_del_init(&hdl->requests);
-       if (hdl->request_is_queued) {
-               list_del_init(&hdl->requests_queued);
-               hdl->request_is_queued = false;
-       }
-       mutex_unlock(main_hdl->lock);
-}
-
-static void v4l2_ctrl_request_release(struct media_request_object *obj)
-{
-       struct v4l2_ctrl_handler *hdl =
-               container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
-       v4l2_ctrl_handler_free(hdl);
-       kfree(hdl);
-}
-
-static const struct media_request_object_ops req_ops = {
-       .queue = v4l2_ctrl_request_queue,
-       .unbind = v4l2_ctrl_request_unbind,
-       .release = v4l2_ctrl_request_release,
-};
-
-struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
-                                       struct v4l2_ctrl_handler *parent)
-{
-       struct media_request_object *obj;
-
-       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
-                   req->state != MEDIA_REQUEST_STATE_QUEUED))
-               return NULL;
-
-       obj = media_request_object_find(req, &req_ops, parent);
-       if (obj)
-               return container_of(obj, struct v4l2_ctrl_handler, req_obj);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
-
-struct v4l2_ctrl *
-v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
-{
-       struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
-
-       return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
-
-static int v4l2_ctrl_request_bind(struct media_request *req,
-                          struct v4l2_ctrl_handler *hdl,
-                          struct v4l2_ctrl_handler *from)
-{
-       int ret;
-
-       ret = v4l2_ctrl_request_clone(hdl, from);
-
-       if (!ret) {
-               ret = media_request_object_bind(req, &req_ops,
-                                               from, false, &hdl->req_obj);
-               if (!ret) {
-                       mutex_lock(from->lock);
-                       list_add_tail(&hdl->requests, &from->requests);
-                       mutex_unlock(from->lock);
-               }
-       }
-       return ret;
-}
-
-/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
-
-   It is not a fully atomic operation, just best-effort only. After all, if
-   multiple controls have to be set through multiple i2c writes (for example)
-   then some initial writes may succeed while others fail. Thus leaving the
-   system in an inconsistent state. The question is how much effort you are
-   willing to spend on trying to make something atomic that really isn't.
-
-   From the point of view of an application the main requirement is that
-   when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
-   error should be returned without actually affecting any controls.
-
-   If all the values are correct, then it is acceptable to just give up
-   in case of low-level errors.
-
-   It is important though that the application can tell when only a partial
-   configuration was done. The way we do that is through the error_idx field
-   of struct v4l2_ext_controls: if that is equal to the count field then no
-   controls were affected. Otherwise all controls before that index were
-   successful in performing their 'get' or 'set' operation, the control at
-   the given index failed, and you don't know what happened with the controls
-   after the failed one. Since if they were part of a control cluster they
-   could have been successfully processed (if a cluster member was encountered
-   at index < error_idx), they could have failed (if a cluster member was at
-   error_idx), or they may not have been processed yet (if the first cluster
-   member appeared after error_idx).
-
-   It is all fairly theoretical, though. In practice all you can do is to
-   bail out. If error_idx == count, then it is an application bug. If
-   error_idx < count then it is only an application bug if the error code was
-   EBUSY. That usually means that something started streaming just when you
-   tried to set the controls. In all other cases it is a driver/hardware
-   problem and all you can do is to retry or bail out.
-
-   Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
-   never modifies controls the error_idx is just set to whatever control
-   has an invalid value.
- */
-
-/* Prepare for the extended g/s/try functions.
-   Find the controls in the control array and do some basic checks. */
-static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
-                            struct v4l2_ext_controls *cs,
-                            struct v4l2_ctrl_helper *helpers,
-                            struct video_device *vdev,
-                            bool get)
-{
-       struct v4l2_ctrl_helper *h;
-       bool have_clusters = false;
-       u32 i;
-
-       for (i = 0, h = helpers; i < cs->count; i++, h++) {
-               struct v4l2_ext_control *c = &cs->controls[i];
-               struct v4l2_ctrl_ref *ref;
-               struct v4l2_ctrl *ctrl;
-               u32 id = c->id & V4L2_CTRL_ID_MASK;
-
-               cs->error_idx = i;
-
-               if (cs->which &&
-                   cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
-                   cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
-                   V4L2_CTRL_ID2WHICH(id) != cs->which) {
-                       dprintk(vdev,
-                               "invalid which 0x%x or control id 0x%x\n",
-                               cs->which, id);
-                       return -EINVAL;
-               }
-
-               /* Old-style private controls are not allowed for
-                  extended controls */
-               if (id >= V4L2_CID_PRIVATE_BASE) {
-                       dprintk(vdev,
-                               "old-style private controls not allowed\n");
-                       return -EINVAL;
-               }
-               ref = find_ref_lock(hdl, id);
-               if (ref == NULL) {
-                       dprintk(vdev, "cannot find control id 0x%x\n", id);
-                       return -EINVAL;
-               }
-               h->ref = ref;
-               ctrl = ref->ctrl;
-               if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
-                       dprintk(vdev, "control id 0x%x is disabled\n", id);
-                       return -EINVAL;
-               }
-
-               if (ctrl->cluster[0]->ncontrols > 1)
-                       have_clusters = true;
-               if (ctrl->cluster[0] != ctrl)
-                       ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
-               if (ctrl->is_ptr && !ctrl->is_string) {
-                       unsigned tot_size = ctrl->elems * ctrl->elem_size;
-
-                       if (c->size < tot_size) {
-                               /*
-                                * In the get case the application first
-                                * queries to obtain the size of the control.
-                                */
-                               if (get) {
-                                       c->size = tot_size;
-                                       return -ENOSPC;
-                               }
-                               dprintk(vdev,
-                                       "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n",
-                                       id, c->size, tot_size);
-                               return -EFAULT;
-                       }
-                       c->size = tot_size;
-               }
-               /* Store the ref to the master control of the cluster */
-               h->mref = ref;
-               /* Initially set next to 0, meaning that there is no other
-                  control in this helper array belonging to the same
-                  cluster */
-               h->next = 0;
-       }
-
-       /* We are done if there were no controls that belong to a multi-
-          control cluster. */
-       if (!have_clusters)
-               return 0;
-
-       /* The code below figures out in O(n) time which controls in the list
-          belong to the same cluster. */
-
-       /* This has to be done with the handler lock taken. */
-       mutex_lock(hdl->lock);
-
-       /* First zero the helper field in the master control references */
-       for (i = 0; i < cs->count; i++)
-               helpers[i].mref->helper = NULL;
-       for (i = 0, h = helpers; i < cs->count; i++, h++) {
-               struct v4l2_ctrl_ref *mref = h->mref;
-
-               /* If the mref->helper is set, then it points to an earlier
-                  helper that belongs to the same cluster. */
-               if (mref->helper) {
-                       /* Set the next field of mref->helper to the current
-                          index: this means that that earlier helper now
-                          points to the next helper in the same cluster. */
-                       mref->helper->next = i;
-                       /* mref should be set only for the first helper in the
-                          cluster, clear the others. */
-                       h->mref = NULL;
-               }
-               /* Point the mref helper to the current helper struct. */
-               mref->helper = h;
-       }
-       mutex_unlock(hdl->lock);
-       return 0;
-}
-
-/* Handles the corner case where cs->count == 0. It checks whether the
-   specified control class exists. If that class ID is 0, then it checks
-   whether there are any controls at all. */
-static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
-{
-       if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
-           which == V4L2_CTRL_WHICH_REQUEST_VAL)
-               return 0;
-       return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
-}
-
-/*
- * Get extended controls. Allocates the helpers array if needed.
- *
- * Note that v4l2_g_ext_ctrls_common() with 'which' set to
- * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
- * completed, and in that case valid_p_req is true for all controls.
- */
-static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
-                                  struct v4l2_ext_controls *cs,
-                                  struct video_device *vdev)
-{
-       struct v4l2_ctrl_helper helper[4];
-       struct v4l2_ctrl_helper *helpers = helper;
-       int ret;
-       int i, j;
-       bool is_default, is_request;
-
-       is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
-       is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
-
-       cs->error_idx = cs->count;
-       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
-
-       if (hdl == NULL)
-               return -EINVAL;
-
-       if (cs->count == 0)
-               return class_check(hdl, cs->which);
-
-       if (cs->count > ARRAY_SIZE(helper)) {
-               helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
-                                        GFP_KERNEL);
-               if (helpers == NULL)
-                       return -ENOMEM;
-       }
-
-       ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true);
-       cs->error_idx = cs->count;
-
-       for (i = 0; !ret && i < cs->count; i++)
-               if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
-                       ret = -EACCES;
-
-       for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *master;
-               bool is_volatile = false;
-               u32 idx = i;
-
-               if (helpers[i].mref == NULL)
-                       continue;
-
-               master = helpers[i].mref->ctrl;
-               cs->error_idx = i;
-
-               v4l2_ctrl_lock(master);
-
-               /*
-                * g_volatile_ctrl will update the new control values.
-                * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
-                * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
-                * it is v4l2_ctrl_request_complete() that copies the
-                * volatile controls at the time of request completion
-                * to the request, so you don't want to do that again.
-                */
-               if (!is_default && !is_request &&
-                   ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
-                   (master->has_volatiles && !is_cur_manual(master)))) {
-                       for (j = 0; j < master->ncontrols; j++)
-                               cur_to_new(master->cluster[j]);
-                       ret = call_op(master, g_volatile_ctrl);
-                       is_volatile = true;
-               }
-
-               if (ret) {
-                       v4l2_ctrl_unlock(master);
-                       break;
-               }
-
-               /*
-                * Copy the default value (if is_default is true), the
-                * request value (if is_request is true and p_req is valid),
-                * the new volatile value (if is_volatile is true) or the
-                * current value.
-                */
-               do {
-                       struct v4l2_ctrl_ref *ref = helpers[idx].ref;
-
-                       if (is_default)
-                               ret = def_to_user(cs->controls + idx, ref->ctrl);
-                       else if (is_request && ref->valid_p_req)
-                               ret = req_to_user(cs->controls + idx, ref);
-                       else if (is_volatile)
-                               ret = new_to_user(cs->controls + idx, ref->ctrl);
-                       else
-                               ret = cur_to_user(cs->controls + idx, ref->ctrl);
-                       idx = helpers[idx].next;
-               } while (!ret && idx);
-
-               v4l2_ctrl_unlock(master);
-       }
-
-       if (cs->count > ARRAY_SIZE(helper))
-               kvfree(helpers);
-       return ret;
-}
-
-static struct media_request_object *
-v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
-                       struct media_request *req, bool set)
-{
-       struct media_request_object *obj;
-       struct v4l2_ctrl_handler *new_hdl;
-       int ret;
-
-       if (IS_ERR(req))
-               return ERR_CAST(req);
-
-       if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
-               return ERR_PTR(-EBUSY);
-
-       obj = media_request_object_find(req, &req_ops, hdl);
-       if (obj)
-               return obj;
-       if (!set)
-               return ERR_PTR(-ENOENT);
-
-       new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
-       if (!new_hdl)
-               return ERR_PTR(-ENOMEM);
-
-       obj = &new_hdl->req_obj;
-       ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
-       if (!ret)
-               ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
-       if (ret) {
-               kfree(new_hdl);
-
-               return ERR_PTR(ret);
-       }
-
-       media_request_object_get(obj);
-       return obj;
-}
-
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
-                    struct media_device *mdev, struct v4l2_ext_controls *cs)
-{
-       struct media_request_object *obj = NULL;
-       struct media_request *req = NULL;
-       int ret;
-
-       if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) {
-               if (!mdev || cs->request_fd < 0)
-                       return -EINVAL;
-
-               req = media_request_get_by_fd(mdev, cs->request_fd);
-               if (IS_ERR(req))
-                       return PTR_ERR(req);
-
-               if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
-                       media_request_put(req);
-                       return -EACCES;
-               }
-
-               ret = media_request_lock_for_access(req);
-               if (ret) {
-                       media_request_put(req);
-                       return ret;
-               }
-
-               obj = v4l2_ctrls_find_req_obj(hdl, req, false);
-               if (IS_ERR(obj)) {
-                       media_request_unlock_for_access(req);
-                       media_request_put(req);
-                       return PTR_ERR(obj);
-               }
-
-               hdl = container_of(obj, struct v4l2_ctrl_handler,
-                                  req_obj);
-       }
-
-       ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
-
-       if (obj) {
-               media_request_unlock_for_access(req);
-               media_request_object_put(obj);
-               media_request_put(req);
-       }
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_g_ext_ctrls);
-
-/* Helper function to get a single control */
-static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
-{
-       struct v4l2_ctrl *master = ctrl->cluster[0];
-       int ret = 0;
-       int i;
-
-       /* Compound controls are not supported. The new_to_user() and
-        * cur_to_user() calls below would need to be modified not to access
-        * userspace memory when called from get_ctrl().
-        */
-       if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64)
-               return -EINVAL;
-
-       if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
-               return -EACCES;
-
-       v4l2_ctrl_lock(master);
-       /* g_volatile_ctrl will update the current control values */
-       if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
-               for (i = 0; i < master->ncontrols; i++)
-                       cur_to_new(master->cluster[i]);
-               ret = call_op(master, g_volatile_ctrl);
-               new_to_user(c, ctrl);
-       } else {
-               cur_to_user(c, ctrl);
-       }
-       v4l2_ctrl_unlock(master);
-       return ret;
-}
-
-int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
-{
-       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
-       struct v4l2_ext_control c;
-       int ret;
-
-       if (ctrl == NULL || !ctrl->is_int)
-               return -EINVAL;
-       ret = get_ctrl(ctrl, &c);
-       control->value = c.value;
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_g_ctrl);
-
-s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct v4l2_ext_control c;
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(!ctrl->is_int))
-               return 0;
-       c.value = 0;
-       get_ctrl(ctrl, &c);
-       return c.value;
-}
-EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
-
-s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
-{
-       struct v4l2_ext_control c;
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
-               return 0;
-       c.value64 = 0;
-       get_ctrl(ctrl, &c);
-       return c.value64;
-}
-EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
-
-
-/* Core function that calls try/s_ctrl and ensures that the new value is
-   copied to the current value on a set.
-   Must be called with ctrl->handler->lock held. */
-static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
-                             bool set, u32 ch_flags)
-{
-       bool update_flag;
-       int ret;
-       int i;
-
-       /* Go through the cluster and either validate the new value or
-          (if no new value was set), copy the current value to the new
-          value, ensuring a consistent view for the control ops when
-          called. */
-       for (i = 0; i < master->ncontrols; i++) {
-               struct v4l2_ctrl *ctrl = master->cluster[i];
-
-               if (ctrl == NULL)
-                       continue;
-
-               if (!ctrl->is_new) {
-                       cur_to_new(ctrl);
-                       continue;
-               }
-               /* Check again: it may have changed since the
-                  previous check in try_or_set_ext_ctrls(). */
-               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
-                       return -EBUSY;
-       }
-
-       ret = call_op(master, try_ctrl);
-
-       /* Don't set if there is no change */
-       if (ret || !set || !cluster_changed(master))
-               return ret;
-       ret = call_op(master, s_ctrl);
-       if (ret)
-               return ret;
-
-       /* If OK, then make the new values permanent. */
-       update_flag = is_cur_manual(master) != is_new_manual(master);
-
-       for (i = 0; i < master->ncontrols; i++) {
-               /*
-                * If we switch from auto to manual mode, and this cluster
-                * contains volatile controls, then all non-master controls
-                * have to be marked as changed. The 'new' value contains
-                * the volatile value (obtained by update_from_auto_cluster),
-                * which now has to become the current value.
-                */
-               if (i && update_flag && is_new_manual(master) &&
-                   master->has_volatiles && master->cluster[i])
-                       master->cluster[i]->has_changed = true;
-
-               new_to_cur(fh, master->cluster[i], ch_flags |
-                       ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
-       }
-       return 0;
-}
-
-/* Validate controls. */
-static int validate_ctrls(struct v4l2_ext_controls *cs,
-                         struct v4l2_ctrl_helper *helpers,
-                         struct video_device *vdev,
-                         bool set)
-{
-       unsigned i;
-       int ret = 0;
-
-       cs->error_idx = cs->count;
-       for (i = 0; i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
-               union v4l2_ctrl_ptr p_new;
-
-               cs->error_idx = i;
-
-               if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) {
-                       dprintk(vdev,
-                               "control id 0x%x is read-only\n",
-                               ctrl->id);
-                       return -EACCES;
-               }
-               /* This test is also done in try_set_control_cluster() which
-                  is called in atomic context, so that has the final say,
-                  but it makes sense to do an up-front check as well. Once
-                  an error occurs in try_set_control_cluster() some other
-                  controls may have been set already and we want to do a
-                  best-effort to avoid that. */
-               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) {
-                       dprintk(vdev,
-                               "control id 0x%x is grabbed, cannot set\n",
-                               ctrl->id);
-                       return -EBUSY;
-               }
-               /*
-                * Skip validation for now if the payload needs to be copied
-                * from userspace into kernelspace. We'll validate those later.
-                */
-               if (ctrl->is_ptr)
-                       continue;
-               if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
-                       p_new.p_s64 = &cs->controls[i].value64;
-               else
-                       p_new.p_s32 = &cs->controls[i].value;
-               ret = validate_new(ctrl, p_new);
-               if (ret)
-                       return ret;
-       }
-       return 0;
-}
-
-/* Obtain the current volatile values of an autocluster and mark them
-   as new. */
-static void update_from_auto_cluster(struct v4l2_ctrl *master)
-{
-       int i;
-
-       for (i = 1; i < master->ncontrols; i++)
-               cur_to_new(master->cluster[i]);
-       if (!call_op(master, g_volatile_ctrl))
-               for (i = 1; i < master->ncontrols; i++)
-                       if (master->cluster[i])
-                               master->cluster[i]->is_new = 1;
-}
-
-/* Try or try-and-set controls */
-static int try_set_ext_ctrls_common(struct v4l2_fh *fh,
-                                   struct v4l2_ctrl_handler *hdl,
-                                   struct v4l2_ext_controls *cs,
-                                   struct video_device *vdev, bool set)
-{
-       struct v4l2_ctrl_helper helper[4];
-       struct v4l2_ctrl_helper *helpers = helper;
-       unsigned i, j;
-       int ret;
-
-       cs->error_idx = cs->count;
-
-       /* Default value cannot be changed */
-       if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
-               dprintk(vdev, "%s: cannot change default value\n",
-                       video_device_node_name(vdev));
-               return -EINVAL;
-       }
-
-       cs->which = V4L2_CTRL_ID2WHICH(cs->which);
-
-       if (hdl == NULL) {
-               dprintk(vdev, "%s: invalid null control handler\n",
-                       video_device_node_name(vdev));
-               return -EINVAL;
-       }
-
-       if (cs->count == 0)
-               return class_check(hdl, cs->which);
-
-       if (cs->count > ARRAY_SIZE(helper)) {
-               helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
-                                        GFP_KERNEL);
-               if (!helpers)
-                       return -ENOMEM;
-       }
-       ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false);
-       if (!ret)
-               ret = validate_ctrls(cs, helpers, vdev, set);
-       if (ret && set)
-               cs->error_idx = cs->count;
-       for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *master;
-               u32 idx = i;
-
-               if (helpers[i].mref == NULL)
-                       continue;
-
-               cs->error_idx = i;
-               master = helpers[i].mref->ctrl;
-               v4l2_ctrl_lock(master);
-
-               /* Reset the 'is_new' flags of the cluster */
-               for (j = 0; j < master->ncontrols; j++)
-                       if (master->cluster[j])
-                               master->cluster[j]->is_new = 0;
-
-               /* For volatile autoclusters that are currently in auto mode
-                  we need to discover if it will be set to manual mode.
-                  If so, then we have to copy the current volatile values
-                  first since those will become the new manual values (which
-                  may be overwritten by explicit new values from this set
-                  of controls). */
-               if (master->is_auto && master->has_volatiles &&
-                                               !is_cur_manual(master)) {
-                       /* Pick an initial non-manual value */
-                       s32 new_auto_val = master->manual_mode_value + 1;
-                       u32 tmp_idx = idx;
-
-                       do {
-                               /* Check if the auto control is part of the
-                                  list, and remember the new value. */
-                               if (helpers[tmp_idx].ref->ctrl == master)
-                                       new_auto_val = cs->controls[tmp_idx].value;
-                               tmp_idx = helpers[tmp_idx].next;
-                       } while (tmp_idx);
-                       /* If the new value == the manual value, then copy
-                          the current volatile values. */
-                       if (new_auto_val == master->manual_mode_value)
-                               update_from_auto_cluster(master);
-               }
-
-               /* Copy the new caller-supplied control values.
-                  user_to_new() sets 'is_new' to 1. */
-               do {
-                       struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
-
-                       ret = user_to_new(cs->controls + idx, ctrl);
-                       if (!ret && ctrl->is_ptr) {
-                               ret = validate_new(ctrl, ctrl->p_new);
-                               if (ret)
-                                       dprintk(vdev,
-                                               "failed to validate control %s (%d)\n",
-                                               v4l2_ctrl_get_name(ctrl->id), ret);
-                       }
-                       idx = helpers[idx].next;
-               } while (!ret && idx);
-
-               if (!ret)
-                       ret = try_or_set_cluster(fh, master,
-                                                !hdl->req_obj.req && set, 0);
-               if (!ret && hdl->req_obj.req && set) {
-                       for (j = 0; j < master->ncontrols; j++) {
-                               struct v4l2_ctrl_ref *ref =
-                                       find_ref(hdl, master->cluster[j]->id);
-
-                               new_to_req(ref);
-                       }
-               }
-
-               /* Copy the new values back to userspace. */
-               if (!ret) {
-                       idx = i;
-                       do {
-                               ret = new_to_user(cs->controls + idx,
-                                               helpers[idx].ref->ctrl);
-                               idx = helpers[idx].next;
-                       } while (!ret && idx);
-               }
-               v4l2_ctrl_unlock(master);
-       }
-
-       if (cs->count > ARRAY_SIZE(helper))
-               kvfree(helpers);
-       return ret;
-}
-
-static int try_set_ext_ctrls(struct v4l2_fh *fh,
-                            struct v4l2_ctrl_handler *hdl,
-                            struct video_device *vdev,
-                            struct media_device *mdev,
-                            struct v4l2_ext_controls *cs, bool set)
-{
-       struct media_request_object *obj = NULL;
-       struct media_request *req = NULL;
-       int ret;
-
-       if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) {
-               if (!mdev) {
-                       dprintk(vdev, "%s: missing media device\n",
-                               video_device_node_name(vdev));
-                       return -EINVAL;
-               }
-
-               if (cs->request_fd < 0) {
-                       dprintk(vdev, "%s: invalid request fd %d\n",
-                               video_device_node_name(vdev), cs->request_fd);
-                       return -EINVAL;
-               }
-
-               req = media_request_get_by_fd(mdev, cs->request_fd);
-               if (IS_ERR(req)) {
-                       dprintk(vdev, "%s: cannot find request fd %d\n",
-                               video_device_node_name(vdev), cs->request_fd);
-                       return PTR_ERR(req);
-               }
-
-               ret = media_request_lock_for_update(req);
-               if (ret) {
-                       dprintk(vdev, "%s: cannot lock request fd %d\n",
-                               video_device_node_name(vdev), cs->request_fd);
-                       media_request_put(req);
-                       return ret;
-               }
-
-               obj = v4l2_ctrls_find_req_obj(hdl, req, set);
-               if (IS_ERR(obj)) {
-                       dprintk(vdev,
-                               "%s: cannot find request object for request fd %d\n",
-                               video_device_node_name(vdev),
-                               cs->request_fd);
-                       media_request_unlock_for_update(req);
-                       media_request_put(req);
-                       return PTR_ERR(obj);
-               }
-               hdl = container_of(obj, struct v4l2_ctrl_handler,
-                                  req_obj);
-       }
-
-       ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
-       if (ret)
-               dprintk(vdev,
-                       "%s: try_set_ext_ctrls_common failed (%d)\n",
-                       video_device_node_name(vdev), ret);
-
-       if (obj) {
-               media_request_unlock_for_update(req);
-               media_request_object_put(obj);
-               media_request_put(req);
-       }
-
-       return ret;
-}
-
-int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
-                      struct video_device *vdev,
-                      struct media_device *mdev,
-                      struct v4l2_ext_controls *cs)
-{
-       return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false);
-}
-EXPORT_SYMBOL(v4l2_try_ext_ctrls);
-
-int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
-                    struct v4l2_ctrl_handler *hdl,
-                    struct video_device *vdev,
-                    struct media_device *mdev,
-                    struct v4l2_ext_controls *cs)
-{
-       return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true);
-}
-EXPORT_SYMBOL(v4l2_s_ext_ctrls);
-
-/* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
-{
-       struct v4l2_ctrl *master = ctrl->cluster[0];
-       int ret;
-       int i;
-
-       /* Reset the 'is_new' flags of the cluster */
-       for (i = 0; i < master->ncontrols; i++)
-               if (master->cluster[i])
-                       master->cluster[i]->is_new = 0;
-
-       ret = validate_new(ctrl, ctrl->p_new);
-       if (ret)
-               return ret;
-
-       /* For autoclusters with volatiles that are switched from auto to
-          manual mode we have to update the current volatile values since
-          those will become the initial manual values after such a switch. */
-       if (master->is_auto && master->has_volatiles && ctrl == master &&
-           !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
-               update_from_auto_cluster(master);
-
-       ctrl->is_new = 1;
-       return try_or_set_cluster(fh, master, true, ch_flags);
-}
-
-/* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
-                        struct v4l2_ext_control *c)
-{
-       int ret;
-
-       v4l2_ctrl_lock(ctrl);
-       user_to_new(c, ctrl);
-       ret = set_ctrl(fh, ctrl, 0);
-       if (!ret)
-               cur_to_user(c, ctrl);
-       v4l2_ctrl_unlock(ctrl);
-       return ret;
-}
-
-int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
-                                       struct v4l2_control *control)
-{
-       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
-       struct v4l2_ext_control c = { control->id };
-       int ret;
-
-       if (ctrl == NULL || !ctrl->is_int)
-               return -EINVAL;
-
-       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
-               return -EACCES;
-
-       c.value = control->value;
-       ret = set_ctrl_lock(fh, ctrl, &c);
-       control->value = c.value;
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_s_ctrl);
-
-int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
-{
-       lockdep_assert_held(ctrl->handler->lock);
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(!ctrl->is_int))
-               return -EINVAL;
-       ctrl->val = val;
-       return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
-
-int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
-{
-       lockdep_assert_held(ctrl->handler->lock);
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
-               return -EINVAL;
-       *ctrl->p_new.p_s64 = val;
-       return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
-
-int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
-{
-       lockdep_assert_held(ctrl->handler->lock);
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING))
-               return -EINVAL;
-       strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
-       return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
-
-int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
-                               enum v4l2_ctrl_type type, const void *p)
-{
-       lockdep_assert_held(ctrl->handler->lock);
-
-       /* It's a driver bug if this happens. */
-       if (WARN_ON(ctrl->type != type))
-               return -EINVAL;
-       memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
-       return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound);
-
-void v4l2_ctrl_request_complete(struct media_request *req,
-                               struct v4l2_ctrl_handler *main_hdl)
-{
-       struct media_request_object *obj;
-       struct v4l2_ctrl_handler *hdl;
-       struct v4l2_ctrl_ref *ref;
-
-       if (!req || !main_hdl)
-               return;
-
-       /*
-        * Note that it is valid if nothing was found. It means
-        * that this request doesn't have any controls and so just
-        * wants to leave the controls unchanged.
-        */
-       obj = media_request_object_find(req, &req_ops, main_hdl);
-       if (!obj)
-               return;
-       hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
-       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
-               struct v4l2_ctrl *ctrl = ref->ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
-               unsigned int i;
-
-               if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
-                       v4l2_ctrl_lock(master);
-                       /* g_volatile_ctrl will update the current control values */
-                       for (i = 0; i < master->ncontrols; i++)
-                               cur_to_new(master->cluster[i]);
-                       call_op(master, g_volatile_ctrl);
-                       new_to_req(ref);
-                       v4l2_ctrl_unlock(master);
-                       continue;
-               }
-               if (ref->valid_p_req)
-                       continue;
-
-               /* Copy the current control value into the request */
-               v4l2_ctrl_lock(ctrl);
-               cur_to_req(ref);
-               v4l2_ctrl_unlock(ctrl);
-       }
-
-       mutex_lock(main_hdl->lock);
-       WARN_ON(!hdl->request_is_queued);
-       list_del_init(&hdl->requests_queued);
-       hdl->request_is_queued = false;
-       mutex_unlock(main_hdl->lock);
-       media_request_object_complete(obj);
-       media_request_object_put(obj);
-}
-EXPORT_SYMBOL(v4l2_ctrl_request_complete);
-
-int v4l2_ctrl_request_setup(struct media_request *req,
-                            struct v4l2_ctrl_handler *main_hdl)
-{
-       struct media_request_object *obj;
-       struct v4l2_ctrl_handler *hdl;
-       struct v4l2_ctrl_ref *ref;
-       int ret = 0;
-
-       if (!req || !main_hdl)
-               return 0;
-
-       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
-               return -EBUSY;
-
-       /*
-        * Note that it is valid if nothing was found. It means
-        * that this request doesn't have any controls and so just
-        * wants to leave the controls unchanged.
-        */
-       obj = media_request_object_find(req, &req_ops, main_hdl);
-       if (!obj)
-               return 0;
-       if (obj->completed) {
-               media_request_object_put(obj);
-               return -EBUSY;
-       }
-       hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
-       list_for_each_entry(ref, &hdl->ctrl_refs, node)
-               ref->req_done = false;
-
-       list_for_each_entry(ref, &hdl->ctrl_refs, node) {
-               struct v4l2_ctrl *ctrl = ref->ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
-               bool have_new_data = false;
-               int i;
-
-               /*
-                * Skip if this control was already handled by a cluster.
-                * Skip button controls and read-only controls.
-                */
-               if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
-                       continue;
-
-               v4l2_ctrl_lock(master);
-               for (i = 0; i < master->ncontrols; i++) {
-                       if (master->cluster[i]) {
-                               struct v4l2_ctrl_ref *r =
-                                       find_ref(hdl, master->cluster[i]->id);
-
-                               if (r->valid_p_req) {
-                                       have_new_data = true;
-                                       break;
-                               }
-                       }
-               }
-               if (!have_new_data) {
-                       v4l2_ctrl_unlock(master);
-                       continue;
-               }
-
-               for (i = 0; i < master->ncontrols; i++) {
-                       if (master->cluster[i]) {
-                               struct v4l2_ctrl_ref *r =
-                                       find_ref(hdl, master->cluster[i]->id);
-
-                               req_to_new(r);
-                               master->cluster[i]->is_new = 1;
-                               r->req_done = true;
-                       }
-               }
-               /*
-                * For volatile autoclusters that are currently in auto mode
-                * we need to discover if it will be set to manual mode.
-                * If so, then we have to copy the current volatile values
-                * first since those will become the new manual values (which
-                * may be overwritten by explicit new values from this set
-                * of controls).
-                */
-               if (master->is_auto && master->has_volatiles &&
-                   !is_cur_manual(master)) {
-                       s32 new_auto_val = *master->p_new.p_s32;
-
-                       /*
-                        * If the new value == the manual value, then copy
-                        * the current volatile values.
-                        */
-                       if (new_auto_val == master->manual_mode_value)
-                               update_from_auto_cluster(master);
-               }
-
-               ret = try_or_set_cluster(NULL, master, true, 0);
-               v4l2_ctrl_unlock(master);
-
-               if (ret)
-                       break;
-       }
-
-       media_request_object_put(obj);
-       return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_request_setup);
-
-void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
-{
-       if (ctrl == NULL)
-               return;
-       if (notify == NULL) {
-               ctrl->call_notify = 0;
-               return;
-       }
-       if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
-               return;
-       ctrl->handler->notify = notify;
-       ctrl->handler->notify_priv = priv;
-       ctrl->call_notify = 1;
-}
-EXPORT_SYMBOL(v4l2_ctrl_notify);
-
-int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
-                       s64 min, s64 max, u64 step, s64 def)
-{
-       bool value_changed;
-       bool range_changed = false;
-       int ret;
-
-       lockdep_assert_held(ctrl->handler->lock);
-
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_INTEGER:
-       case V4L2_CTRL_TYPE_INTEGER64:
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER_MENU:
-       case V4L2_CTRL_TYPE_BITMASK:
-       case V4L2_CTRL_TYPE_U8:
-       case V4L2_CTRL_TYPE_U16:
-       case V4L2_CTRL_TYPE_U32:
-               if (ctrl->is_array)
-                       return -EINVAL;
-               ret = check_range(ctrl->type, min, max, step, def);
-               if (ret)
-                       return ret;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if ((ctrl->minimum != min) || (ctrl->maximum != max) ||
-               (ctrl->step != step) || ctrl->default_value != def) {
-               range_changed = true;
-               ctrl->minimum = min;
-               ctrl->maximum = max;
-               ctrl->step = step;
-               ctrl->default_value = def;
-       }
-       cur_to_new(ctrl);
-       if (validate_new(ctrl, ctrl->p_new)) {
-               if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
-                       *ctrl->p_new.p_s64 = def;
-               else
-                       *ctrl->p_new.p_s32 = def;
-       }
-
-       if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
-               value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
-       else
-               value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
-       if (value_changed)
-               ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
-       else if (range_changed)
-               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
-       return ret;
-}
-EXPORT_SYMBOL(__v4l2_ctrl_modify_range);
-
-static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
-{
-       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
-
-       if (ctrl == NULL)
-               return -EINVAL;
-
-       v4l2_ctrl_lock(ctrl);
-       list_add_tail(&sev->node, &ctrl->ev_subs);
-       if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
-           (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
-               struct v4l2_event ev;
-               u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
-
-               if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
-                       changes |= V4L2_EVENT_CTRL_CH_VALUE;
-               fill_event(&ev, ctrl, changes);
-               /* Mark the queue as active, allowing this initial
-                  event to be accepted. */
-               sev->elems = elems;
-               v4l2_event_queue_fh(sev->fh, &ev);
-       }
-       v4l2_ctrl_unlock(ctrl);
-       return 0;
-}
-
-static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
-{
-       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
-
-       if (ctrl == NULL)
-               return;
-
-       v4l2_ctrl_lock(ctrl);
-       list_del(&sev->node);
-       v4l2_ctrl_unlock(ctrl);
-}
-
-void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
-{
-       u32 old_changes = old->u.ctrl.changes;
-
-       old->u.ctrl = new->u.ctrl;
-       old->u.ctrl.changes |= old_changes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_replace);
-
-void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
-{
-       new->u.ctrl.changes |= old->u.ctrl.changes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_merge);
-
-const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
-       .add = v4l2_ctrl_add_event,
-       .del = v4l2_ctrl_del_event,
-       .replace = v4l2_ctrl_replace,
-       .merge = v4l2_ctrl_merge,
-};
-EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
-
-int v4l2_ctrl_log_status(struct file *file, void *fh)
-{
-       struct video_device *vfd = video_devdata(file);
-       struct v4l2_fh *vfh = file->private_data;
-
-       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
-               v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
-                       vfd->v4l2_dev->name);
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_log_status);
-
-int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
-                               const struct v4l2_event_subscription *sub)
-{
-       if (sub->type == V4L2_EVENT_CTRL)
-               return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
-       return -EINVAL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
-
-int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
-                                    struct v4l2_event_subscription *sub)
-{
-       if (!sd->ctrl_handler)
-               return -EINVAL;
-       return v4l2_ctrl_subscribe_event(fh, sub);
-}
-EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
-
-__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct v4l2_fh *fh = file->private_data;
-
-       poll_wait(file, &fh->wait, wait);
-       if (v4l2_event_pending(fh))
-               return EPOLLPRI;
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_poll);
-
-int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
-                                   const struct v4l2_ctrl_ops *ctrl_ops,
-                                   const struct v4l2_fwnode_device_properties *p)
-{
-       if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
-               u32 orientation_ctrl;
-
-               switch (p->orientation) {
-               case V4L2_FWNODE_ORIENTATION_FRONT:
-                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT;
-                       break;
-               case V4L2_FWNODE_ORIENTATION_BACK:
-                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK;
-                       break;
-               case V4L2_FWNODE_ORIENTATION_EXTERNAL:
-                       orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops,
-                                           V4L2_CID_CAMERA_ORIENTATION,
-                                           V4L2_CAMERA_ORIENTATION_EXTERNAL, 0,
-                                           orientation_ctrl))
-                       return hdl->error;
-       }
-
-       if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
-               if (!v4l2_ctrl_new_std(hdl, ctrl_ops,
-                                      V4L2_CID_CAMERA_SENSOR_ROTATION,
-                                      p->rotation, p->rotation, 1,
-                                      p->rotation))
-                       return hdl->error;
-       }
-
-       return hdl->error;
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
index 7d0edf3..d03ace3 100644 (file)
@@ -39,8 +39,6 @@
                       __func__, ##arg);                                \
 } while (0)
 
-static struct dentry *v4l2_debugfs_dir;
-
 /*
  *     sysfs stuff
  */
@@ -520,9 +518,8 @@ static int get_index(struct video_device *vdev)
        return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
 }
 
-#define SET_VALID_IOCTL(ops, cmd, op)                  \
-       if (ops->op)                                    \
-               set_bit(_IOC_NR(cmd), valid_ioctls)
+#define SET_VALID_IOCTL(ops, cmd, op) \
+       do { if ((ops)->op) set_bit(_IOC_NR(cmd), valid_ioctls); } while (0)
 
 /* This determines which ioctls are actually implemented in the driver.
    It's a one-time thing which simplifies video_ioctl2 as it can just do
@@ -1121,8 +1118,6 @@ static int __init videodev_init(void)
                return -EIO;
        }
 
-       v4l2_debugfs_dir = debugfs_create_dir("video4linux", NULL);
-       v4l2_async_debug_init(v4l2_debugfs_dir);
        return 0;
 }
 
@@ -1130,7 +1125,6 @@ static void __exit videodev_exit(void)
 {
        dev_t dev = MKDEV(VIDEO_MAJOR, 0);
 
-       debugfs_remove_recursive(v4l2_debugfs_dir);
        class_unregister(&video_class);
        unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
index caad58b..c5ce9f1 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
-static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
+static unsigned int sev_pos(const struct v4l2_subscribed_event *sev, unsigned int idx)
 {
        idx += sev->first;
        return idx >= sev->elems ? idx - sev->elems : idx;
@@ -221,12 +221,12 @@ static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
 }
 
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-                        const struct v4l2_event_subscription *sub, unsigned elems,
+                        const struct v4l2_event_subscription *sub, unsigned int elems,
                         const struct v4l2_subscribed_event_ops *ops)
 {
        struct v4l2_subscribed_event *sev, *found_ev;
        unsigned long flags;
-       unsigned i;
+       unsigned int i;
        int ret = 0;
 
        if (sub->type == V4L2_EVENT_ALL)
index 684574f..90eec79 100644 (file)
@@ -96,6 +96,7 @@ int v4l2_fh_release(struct file *filp)
                v4l2_fh_del(fh);
                v4l2_fh_exit(fh);
                kfree(fh);
+               filp->private_data = NULL;
        }
        return 0;
 }
index 2673f51..05d5db3 100644 (file)
@@ -3072,8 +3072,8 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 
 static unsigned int video_translate_cmd(unsigned int cmd)
 {
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
        switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
        case VIDIOC_DQEVENT_TIME32:
                return VIDIOC_DQEVENT;
        case VIDIOC_QUERYBUF_TIME32:
@@ -3084,8 +3084,8 @@ static unsigned int video_translate_cmd(unsigned int cmd)
                return VIDIOC_DQBUF;
        case VIDIOC_PREPARE_BUF_TIME32:
                return VIDIOC_PREPARE_BUF;
-#endif
        }
+#endif
        if (in_compat_syscall())
                return v4l2_compat_translate_cmd(cmd);
 
@@ -3124,10 +3124,12 @@ static int video_get_user(void __user *arg, void *parg,
                if (copy_from_user(parg, (void __user *)arg, n))
                        err = -EFAULT;
        } else if (in_compat_syscall()) {
+               memset(parg, 0, n);
                err = v4l2_compat_get_user(arg, parg, cmd);
        } else {
+               memset(parg, 0, n);
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
                switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
                case VIDIOC_QUERYBUF_TIME32:
                case VIDIOC_QBUF_TIME32:
                case VIDIOC_DQBUF_TIME32:
@@ -3140,23 +3142,23 @@ static int video_get_user(void __user *arg, void *parg,
 
                        *vb = (struct v4l2_buffer) {
                                .index          = vb32.index,
-                                       .type           = vb32.type,
-                                       .bytesused      = vb32.bytesused,
-                                       .flags          = vb32.flags,
-                                       .field          = vb32.field,
-                                       .timestamp.tv_sec       = vb32.timestamp.tv_sec,
-                                       .timestamp.tv_usec      = vb32.timestamp.tv_usec,
-                                       .timecode       = vb32.timecode,
-                                       .sequence       = vb32.sequence,
-                                       .memory         = vb32.memory,
-                                       .m.userptr      = vb32.m.userptr,
-                                       .length         = vb32.length,
-                                       .request_fd     = vb32.request_fd,
+                               .type           = vb32.type,
+                               .bytesused      = vb32.bytesused,
+                               .flags          = vb32.flags,
+                               .field          = vb32.field,
+                               .timestamp.tv_sec       = vb32.timestamp.tv_sec,
+                               .timestamp.tv_usec      = vb32.timestamp.tv_usec,
+                               .timecode       = vb32.timecode,
+                               .sequence       = vb32.sequence,
+                               .memory         = vb32.memory,
+                               .m.userptr      = vb32.m.userptr,
+                               .length         = vb32.length,
+                               .request_fd     = vb32.request_fd,
                        };
                        break;
                }
-#endif
                }
+#endif
        }
 
        /* zero out anything we don't copy from userspace */
@@ -3181,8 +3183,8 @@ static int video_put_user(void __user *arg, void *parg,
        if (in_compat_syscall())
                return v4l2_compat_put_user(arg, parg, cmd);
 
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
        switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
        case VIDIOC_DQEVENT_TIME32: {
                struct v4l2_event *ev = parg;
                struct v4l2_event_time32 ev32;
@@ -3230,8 +3232,8 @@ static int video_put_user(void __user *arg, void *parg,
                        return -EFAULT;
                break;
        }
-#endif
        }
+#endif
 
        return 0;
 }
index 956dafa..5d27a27 100644 (file)
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
-       if (sd->entity.num_pads) {
-               fh->pad = v4l2_subdev_alloc_pad_config(sd);
-               if (fh->pad == NULL)
-                       return -ENOMEM;
-       }
+       struct v4l2_subdev_state *state;
+
+       state = v4l2_subdev_alloc_state(sd);
+       if (IS_ERR(state))
+               return PTR_ERR(state);
+
+       fh->state = state;
 
        return 0;
 }
 
 static void subdev_fh_free(struct v4l2_subdev_fh *fh)
 {
-       v4l2_subdev_free_pad_config(fh->pad);
-       fh->pad = NULL;
+       v4l2_subdev_free_state(fh->state);
+       fh->state = NULL;
 }
 
 static int subdev_open(struct file *file)
@@ -146,63 +148,63 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
        return 0;
 }
 
-static int check_cfg(u32 which, struct v4l2_subdev_pad_config *cfg)
+static int check_state_pads(u32 which, struct v4l2_subdev_state *state)
 {
-       if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
+       if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads))
                return -EINVAL;
 
        return 0;
 }
 
 static inline int check_format(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *state,
                               struct v4l2_subdev_format *format)
 {
        if (!format)
                return -EINVAL;
 
        return check_which(format->which) ? : check_pad(sd, format->pad) ? :
-              check_cfg(format->which, cfg);
+              check_state_pads(format->which, state);
 }
 
 static int call_get_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *state,
                        struct v4l2_subdev_format *format)
 {
-       return check_format(sd, cfg, format) ? :
-              sd->ops->pad->get_fmt(sd, cfg, format);
+       return check_format(sd, state, format) ? :
+              sd->ops->pad->get_fmt(sd, state, format);
 }
 
 static int call_set_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *state,
                        struct v4l2_subdev_format *format)
 {
-       return check_format(sd, cfg, format) ? :
-              sd->ops->pad->set_fmt(sd, cfg, format);
+       return check_format(sd, state, format) ? :
+              sd->ops->pad->set_fmt(sd, state, format);
 }
 
 static int call_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        if (!code)
                return -EINVAL;
 
        return check_which(code->which) ? : check_pad(sd, code->pad) ? :
-              check_cfg(code->which, cfg) ? :
-              sd->ops->pad->enum_mbus_code(sd, cfg, code);
+              check_state_pads(code->which, state) ? :
+              sd->ops->pad->enum_mbus_code(sd, state, code);
 }
 
 static int call_enum_frame_size(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        if (!fse)
                return -EINVAL;
 
        return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
-              check_cfg(fse->which, cfg) ? :
-              sd->ops->pad->enum_frame_size(sd, cfg, fse);
+              check_state_pads(fse->which, state) ? :
+              sd->ops->pad->enum_frame_size(sd, state, fse);
 }
 
 static inline int check_frame_interval(struct v4l2_subdev *sd,
@@ -229,42 +231,42 @@ static int call_s_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int call_enum_frame_interval(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *state,
                                    struct v4l2_subdev_frame_interval_enum *fie)
 {
        if (!fie)
                return -EINVAL;
 
        return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
-              check_cfg(fie->which, cfg) ? :
-              sd->ops->pad->enum_frame_interval(sd, cfg, fie);
+              check_state_pads(fie->which, state) ? :
+              sd->ops->pad->enum_frame_interval(sd, state, fie);
 }
 
 static inline int check_selection(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *state,
                                  struct v4l2_subdev_selection *sel)
 {
        if (!sel)
                return -EINVAL;
 
        return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
-              check_cfg(sel->which, cfg);
+              check_state_pads(sel->which, state);
 }
 
 static int call_get_selection(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *state,
                              struct v4l2_subdev_selection *sel)
 {
-       return check_selection(sd, cfg, sel) ? :
-              sd->ops->pad->get_selection(sd, cfg, sel);
+       return check_selection(sd, state, sel) ? :
+              sd->ops->pad->get_selection(sd, state, sel);
 }
 
 static int call_set_selection(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *state,
                              struct v4l2_subdev_selection *sel)
 {
-       return check_selection(sd, cfg, sel) ? :
-              sd->ops->pad->set_selection(sd, cfg, sel);
+       return check_selection(sd, state, sel) ? :
+              sd->ops->pad->set_selection(sd, state, sel);
 }
 
 static inline int check_edid(struct v4l2_subdev *sd,
@@ -428,30 +430,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
 
-       case VIDIOC_DQEVENT_TIME32: {
-               struct v4l2_event_time32 *ev32 = arg;
-               struct v4l2_event ev = { };
-
-               if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
-                       return -ENOIOCTLCMD;
-
-               rval = v4l2_event_dequeue(vfh, &ev, file->f_flags & O_NONBLOCK);
-
-               *ev32 = (struct v4l2_event_time32) {
-                       .type           = ev.type,
-                       .pending        = ev.pending,
-                       .sequence       = ev.sequence,
-                       .timestamp.tv_sec  = ev.timestamp.tv_sec,
-                       .timestamp.tv_nsec = ev.timestamp.tv_nsec,
-                       .id             = ev.id,
-               };
-
-               memcpy(&ev32->u, &ev.u, sizeof(ev.u));
-               memcpy(&ev32->reserved, &ev.reserved, sizeof(ev.reserved));
-
-               return rval;
-       }
-
        case VIDIOC_SUBSCRIBE_EVENT:
                return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
 
@@ -506,7 +484,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(format->reserved, 0, sizeof(format->reserved));
                memset(format->format.reserved, 0, sizeof(format->format.reserved));
-               return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
+               return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->state, format);
        }
 
        case VIDIOC_SUBDEV_S_FMT: {
@@ -517,7 +495,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(format->reserved, 0, sizeof(format->reserved));
                memset(format->format.reserved, 0, sizeof(format->format.reserved));
-               return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
+               return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->state, format);
        }
 
        case VIDIOC_SUBDEV_G_CROP: {
@@ -531,7 +509,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                sel.target = V4L2_SEL_TGT_CROP;
 
                rval = v4l2_subdev_call(
-                       sd, pad, get_selection, subdev_fh->pad, &sel);
+                       sd, pad, get_selection, subdev_fh->state, &sel);
 
                crop->rect = sel.r;
 
@@ -553,7 +531,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                sel.r = crop->rect;
 
                rval = v4l2_subdev_call(
-                       sd, pad, set_selection, subdev_fh->pad, &sel);
+                       sd, pad, set_selection, subdev_fh->state, &sel);
 
                crop->rect = sel.r;
 
@@ -564,7 +542,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_subdev_mbus_code_enum *code = arg;
 
                memset(code->reserved, 0, sizeof(code->reserved));
-               return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
+               return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->state,
                                        code);
        }
 
@@ -572,7 +550,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_subdev_frame_size_enum *fse = arg;
 
                memset(fse->reserved, 0, sizeof(fse->reserved));
-               return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
+               return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->state,
                                        fse);
        }
 
@@ -597,7 +575,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_subdev_frame_interval_enum *fie = arg;
 
                memset(fie->reserved, 0, sizeof(fie->reserved));
-               return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
+               return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->state,
                                        fie);
        }
 
@@ -606,7 +584,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(sel->reserved, 0, sizeof(sel->reserved));
                return v4l2_subdev_call(
-                       sd, pad, get_selection, subdev_fh->pad, sel);
+                       sd, pad, get_selection, subdev_fh->state, sel);
        }
 
        case VIDIOC_SUBDEV_S_SELECTION: {
@@ -617,7 +595,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(sel->reserved, 0, sizeof(sel->reserved));
                return v4l2_subdev_call(
-                       sd, pad, set_selection, subdev_fh->pad, sel);
+                       sd, pad, set_selection, subdev_fh->state, sel);
        }
 
        case VIDIOC_G_EDID: {
@@ -892,35 +870,51 @@ int v4l2_subdev_link_validate(struct media_link *link)
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
 
-struct v4l2_subdev_pad_config *
-v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
+struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd)
 {
-       struct v4l2_subdev_pad_config *cfg;
+       struct v4l2_subdev_state *state;
        int ret;
 
-       if (!sd->entity.num_pads)
-               return NULL;
-
-       cfg = kvmalloc_array(sd->entity.num_pads, sizeof(*cfg),
-                            GFP_KERNEL | __GFP_ZERO);
-       if (!cfg)
-               return NULL;
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
 
-       ret = v4l2_subdev_call(sd, pad, init_cfg, cfg);
-       if (ret < 0 && ret != -ENOIOCTLCMD) {
-               kvfree(cfg);
-               return NULL;
+       if (sd->entity.num_pads) {
+               state->pads = kvmalloc_array(sd->entity.num_pads,
+                                            sizeof(*state->pads),
+                                            GFP_KERNEL | __GFP_ZERO);
+               if (!state->pads) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
        }
 
-       return cfg;
+       ret = v4l2_subdev_call(sd, pad, init_cfg, state);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
+               goto err;
+
+       return state;
+
+err:
+       if (state && state->pads)
+               kvfree(state->pads);
+
+       kfree(state);
+
+       return ERR_PTR(ret);
 }
-EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
+EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_state);
 
-void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
+void v4l2_subdev_free_state(struct v4l2_subdev_state *state)
 {
-       kvfree(cfg);
+       if (!state)
+               return;
+
+       kvfree(state->pads);
+       kfree(state);
 }
-EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config);
+EXPORT_SYMBOL_GPL(v4l2_subdev_free_state);
+
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
index 8dd0562..f75e5ee 100644 (file)
@@ -423,7 +423,6 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
                videobuf_queue_unlock(q);
                kfree(map);
        }
-       return;
 }
 
 /*
index 8004dd6..d971acd 100644 (file)
@@ -129,7 +129,7 @@ static int msb_sg_compare_to_buffer(struct scatterlist *sg,
  * Each zone consists of 512 eraseblocks, out of which in first
  * zone 494 are used and 496 are for all following zones.
  * Therefore zone #0 hosts blocks 0-493, zone #1 blocks 494-988, etc...
-*/
+ */
 static int msb_get_zone_from_lba(int lba)
 {
        if (lba < 494)
@@ -348,8 +348,9 @@ again:
        switch (msb->state) {
        case MSB_RP_SEND_BLOCK_ADDRESS:
                /* msb_write_regs sometimes "fails" because it needs to update
-                       the reg window, and thus it returns request for that.
-                       Then we stay in this state and retry */
+                * the reg window, and thus it returns request for that.
+                * Then we stay in this state and retry
+                */
                if (!msb_write_regs(msb,
                        offsetof(struct ms_register, param),
                        sizeof(struct ms_param_register),
@@ -368,7 +369,8 @@ again:
        case MSB_RP_SEND_INT_REQ:
                msb->state = MSB_RP_RECEIVE_INT_REQ_RESULT;
                /* If dont actually need to send the int read request (only in
-                       serial mode), then just fall through */
+                * serial mode), then just fall through
+                */
                if (msb_read_int_reg(msb, -1))
                        return 0;
                fallthrough;
@@ -702,7 +704,8 @@ static int h_msb_parallel_switch(struct memstick_dev *card,
 
        case MSB_PS_SWICH_HOST:
                 /* Set parallel interface on our side + send a dummy request
-                       to see if card responds */
+                 * to see if card responds
+                 */
                host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);
                memstick_init_req(mrq, MS_TPC_GET_INT, NULL, 1);
                msb->state = MSB_PS_CONFIRM;
@@ -821,6 +824,7 @@ static int msb_mark_page_bad(struct msb_data *msb, int pba, int page)
 static int msb_erase_block(struct msb_data *msb, u16 pba)
 {
        int error, try;
+
        if (msb->read_only)
                return -EROFS;
 
@@ -997,6 +1001,7 @@ static int msb_write_block(struct msb_data *msb,
                        u16 pba, u32 lba, struct scatterlist *sg, int offset)
 {
        int error, current_try = 1;
+
        BUG_ON(sg->length < msb->page_size);
 
        if (msb->read_only)
@@ -1045,11 +1050,12 @@ static int msb_write_block(struct msb_data *msb,
                error = msb_run_state_machine(msb, h_msb_write_block);
 
                /* Sector we just wrote to is assumed erased since its pba
-                       was erased. If it wasn't erased, write will succeed
-                       and will just clear the bits that were set in the block
-                       thus test that what we have written,
-                       matches what we expect.
-                       We do trust the blocks that we erased */
+                * was erased. If it wasn't erased, write will succeed
+                * and will just clear the bits that were set in the block
+                * thus test that what we have written,
+                * matches what we expect.
+                * We do trust the blocks that we erased
+                */
                if (!error && (verify_writes ||
                                !test_bit(pba, msb->erased_blocks_bitmap)))
                        error = msb_verify_block(msb, pba, sg, offset);
@@ -1493,6 +1499,7 @@ static int msb_ftl_scan(struct msb_data *msb)
 static void msb_cache_flush_timer(struct timer_list *t)
 {
        struct msb_data *msb = from_timer(msb, t, cache_flush_timer);
+
        msb->need_flush_cache = true;
        queue_work(msb->io_queue, &msb->io_work);
 }
@@ -1673,7 +1680,8 @@ static int msb_cache_read(struct msb_data *msb, int lba,
  * This table content isn't that importaint,
  * One could put here different values, providing that they still
  * cover whole disk.
- * 64 MB entry is what windows reports for my 64M memstick */
+ * 64 MB entry is what windows reports for my 64M memstick
+ */
 
 static const struct chs_entry chs_table[] = {
 /*        size sectors cylynders  heads */
@@ -1706,8 +1714,9 @@ static int msb_init_card(struct memstick_dev *card)
                return error;
 
        /* Due to a bug in Jmicron driver written by Alex Dubov,
-        its serial mode barely works,
-        so we switch to parallel mode right away */
+        * its serial mode barely works,
+        * so we switch to parallel mode right away
+        */
        if (host->caps & MEMSTICK_CAP_PAR4)
                msb_switch_to_parallel(msb);
 
@@ -2033,6 +2042,7 @@ static blk_status_t msb_queue_rq(struct blk_mq_hw_ctx *hctx,
 static int msb_check_card(struct memstick_dev *card)
 {
        struct msb_data *msb = memstick_get_drvdata(card);
+
        return (msb->card_dead == 0);
 }
 
@@ -2333,6 +2343,7 @@ static struct memstick_driver msb_driver = {
 static int __init msb_init(void)
 {
        int rc = memstick_register_driver(&msb_driver);
+
        if (rc)
                pr_err("failed to register memstick driver (error %d)\n", rc);
 
index 102dbb8..29271ad 100644 (file)
@@ -799,9 +799,9 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
 
        return 0;
 err_out:
-       memstick_free_host(msh);
        pm_runtime_disable(ms_dev(host));
        pm_runtime_put_noidle(ms_dev(host));
+       memstick_free_host(msh);
        return err;
 }
 
@@ -828,9 +828,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
        }
        mutex_unlock(&host->host_mutex);
 
-       memstick_remove_host(msh);
-       memstick_free_host(msh);
-
        /* Balance possible unbalanced usage count
         * e.g. unconditional module removal
         */
@@ -838,10 +835,11 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
                pm_runtime_put(ms_dev(host));
 
        pm_runtime_disable(ms_dev(host));
-       platform_set_drvdata(pdev, NULL);
-
+       memstick_remove_host(msh);
        dev_dbg(ms_dev(host),
                ": Realtek USB Memstick controller has been removed\n");
+       memstick_free_host(msh);
+       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index c73ec78..99b9c11 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index db734f2..83f3ffb 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/interrupt.h>
 #include <linux/mfd/mt6358/core.h>
 #include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6359/core.h>
+#include <linux/mfd/mt6359/registers.h>
 #include <linux/mfd/mt6397/core.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -13,7 +15,9 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
-static struct irq_top_t mt6358_ints[] = {
+#define MTK_PMIC_REG_WIDTH 16
+
+static const struct irq_top_t mt6358_ints[] = {
        MT6358_TOP_GEN(BUCK),
        MT6358_TOP_GEN(LDO),
        MT6358_TOP_GEN(PSC),
@@ -24,6 +28,31 @@ static struct irq_top_t mt6358_ints[] = {
        MT6358_TOP_GEN(MISC),
 };
 
+static const struct irq_top_t mt6359_ints[] = {
+       MT6359_TOP_GEN(BUCK),
+       MT6359_TOP_GEN(LDO),
+       MT6359_TOP_GEN(PSC),
+       MT6359_TOP_GEN(SCK),
+       MT6359_TOP_GEN(BM),
+       MT6359_TOP_GEN(HK),
+       MT6359_TOP_GEN(AUD),
+       MT6359_TOP_GEN(MISC),
+};
+
+static struct pmic_irq_data mt6358_irqd = {
+       .num_top = ARRAY_SIZE(mt6358_ints),
+       .num_pmic_irqs = MT6358_IRQ_NR,
+       .top_int_status_reg = MT6358_TOP_INT_STATUS0,
+       .pmic_ints = mt6358_ints,
+};
+
+static struct pmic_irq_data mt6359_irqd = {
+       .num_top = ARRAY_SIZE(mt6359_ints),
+       .num_pmic_irqs = MT6359_IRQ_NR,
+       .top_int_status_reg = MT6359_TOP_INT_STATUS0,
+       .pmic_ints = mt6359_ints,
+};
+
 static void pmic_irq_enable(struct irq_data *data)
 {
        unsigned int hwirq = irqd_to_hwirq(data);
@@ -62,15 +91,15 @@ static void pmic_irq_sync_unlock(struct irq_data *data)
                /* Find out the IRQ group */
                top_gp = 0;
                while ((top_gp + 1) < irqd->num_top &&
-                      i >= mt6358_ints[top_gp + 1].hwirq_base)
+                      i >= irqd->pmic_ints[top_gp + 1].hwirq_base)
                        top_gp++;
 
                /* Find the IRQ registers */
-               gp_offset = i - mt6358_ints[top_gp].hwirq_base;
-               int_regs = gp_offset / MT6358_REG_WIDTH;
-               shift = gp_offset % MT6358_REG_WIDTH;
-               en_reg = mt6358_ints[top_gp].en_reg +
-                        (mt6358_ints[top_gp].en_reg_shift * int_regs);
+               gp_offset = i - irqd->pmic_ints[top_gp].hwirq_base;
+               int_regs = gp_offset / MTK_PMIC_REG_WIDTH;
+               shift = gp_offset % MTK_PMIC_REG_WIDTH;
+               en_reg = irqd->pmic_ints[top_gp].en_reg +
+                        (irqd->pmic_ints[top_gp].en_reg_shift * int_regs);
 
                regmap_update_bits(chip->regmap, en_reg, BIT(shift),
                                   irqd->enable_hwirq[i] << shift);
@@ -95,10 +124,11 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
        unsigned int irq_status, sta_reg, status;
        unsigned int hwirq, virq;
        int i, j, ret;
+       struct pmic_irq_data *irqd = chip->irq_data;
 
-       for (i = 0; i < mt6358_ints[top_gp].num_int_regs; i++) {
-               sta_reg = mt6358_ints[top_gp].sta_reg +
-                       mt6358_ints[top_gp].sta_reg_shift * i;
+       for (i = 0; i < irqd->pmic_ints[top_gp].num_int_regs; i++) {
+               sta_reg = irqd->pmic_ints[top_gp].sta_reg +
+                       irqd->pmic_ints[top_gp].sta_reg_shift * i;
 
                ret = regmap_read(chip->regmap, sta_reg, &irq_status);
                if (ret) {
@@ -114,8 +144,8 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
                do {
                        j = __ffs(status);
 
-                       hwirq = mt6358_ints[top_gp].hwirq_base +
-                               MT6358_REG_WIDTH * i + j;
+                       hwirq = irqd->pmic_ints[top_gp].hwirq_base +
+                               MTK_PMIC_REG_WIDTH * i + j;
 
                        virq = irq_find_mapping(chip->irq_domain, hwirq);
                        if (virq)
@@ -131,12 +161,12 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
 static irqreturn_t mt6358_irq_handler(int irq, void *data)
 {
        struct mt6397_chip *chip = data;
-       struct pmic_irq_data *mt6358_irq_data = chip->irq_data;
+       struct pmic_irq_data *irqd = chip->irq_data;
        unsigned int bit, i, top_irq_status = 0;
        int ret;
 
        ret = regmap_read(chip->regmap,
-                         mt6358_irq_data->top_int_status_reg,
+                         irqd->top_int_status_reg,
                          &top_irq_status);
        if (ret) {
                dev_err(chip->dev,
@@ -144,8 +174,8 @@ static irqreturn_t mt6358_irq_handler(int irq, void *data)
                return IRQ_NONE;
        }
 
-       for (i = 0; i < mt6358_irq_data->num_top; i++) {
-               bit = BIT(mt6358_ints[i].top_offset);
+       for (i = 0; i < irqd->num_top; i++) {
+               bit = BIT(irqd->pmic_ints[i].top_offset);
                if (top_irq_status & bit) {
                        mt6358_irq_sp_handler(chip, i);
                        top_irq_status &= ~bit;
@@ -180,17 +210,22 @@ int mt6358_irq_init(struct mt6397_chip *chip)
        int i, j, ret;
        struct pmic_irq_data *irqd;
 
-       irqd = devm_kzalloc(chip->dev, sizeof(*irqd), GFP_KERNEL);
-       if (!irqd)
-               return -ENOMEM;
+       switch (chip->chip_id) {
+       case MT6358_CHIP_ID:
+               chip->irq_data = &mt6358_irqd;
+               break;
 
-       chip->irq_data = irqd;
+       case MT6359_CHIP_ID:
+               chip->irq_data = &mt6359_irqd;
+               break;
 
-       mutex_init(&chip->irqlock);
-       irqd->top_int_status_reg = MT6358_TOP_INT_STATUS0;
-       irqd->num_pmic_irqs = MT6358_IRQ_NR;
-       irqd->num_top = ARRAY_SIZE(mt6358_ints);
+       default:
+               dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
+               return -ENODEV;
+       }
 
+       mutex_init(&chip->irqlock);
+       irqd = chip->irq_data;
        irqd->enable_hwirq = devm_kcalloc(chip->dev,
                                          irqd->num_pmic_irqs,
                                          sizeof(*irqd->enable_hwirq),
@@ -207,10 +242,10 @@ int mt6358_irq_init(struct mt6397_chip *chip)
 
        /* Disable all interrupts for initializing */
        for (i = 0; i < irqd->num_top; i++) {
-               for (j = 0; j < mt6358_ints[i].num_int_regs; j++)
+               for (j = 0; j < irqd->pmic_ints[i].num_int_regs; j++)
                        regmap_write(chip->regmap,
-                                    mt6358_ints[i].en_reg +
-                                    mt6358_ints[i].en_reg_shift * j, 0);
+                                    irqd->pmic_ints[i].en_reg +
+                                    irqd->pmic_ints[i].en_reg_shift * j, 0);
        }
 
        chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
index 7518d74..9a615f7 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/mt6323/core.h>
 #include <linux/mfd/mt6358/core.h>
+#include <linux/mfd/mt6359/core.h>
 #include <linux/mfd/mt6397/core.h>
 #include <linux/mfd/mt6323/registers.h>
 #include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6359/registers.h>
 #include <linux/mfd/mt6397/registers.h>
 
 #define MT6323_RTC_BASE                0x8000
@@ -99,6 +101,17 @@ static const struct mfd_cell mt6358_devs[] = {
        },
 };
 
+static const struct mfd_cell mt6359_devs[] = {
+       { .name = "mt6359-regulator", },
+       {
+               .name = "mt6359-rtc",
+               .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
+               .resources = mt6358_rtc_resources,
+               .of_compatible = "mediatek,mt6358-rtc",
+       },
+       { .name = "mt6359-sound", },
+};
+
 static const struct mfd_cell mt6397_devs[] = {
        {
                .name = "mt6397-rtc",
@@ -149,6 +162,14 @@ static const struct chip_data mt6358_core = {
        .irq_init = mt6358_irq_init,
 };
 
+static const struct chip_data mt6359_core = {
+       .cid_addr = MT6359_SWCID,
+       .cid_shift = 8,
+       .cells = mt6359_devs,
+       .cell_size = ARRAY_SIZE(mt6359_devs),
+       .irq_init = mt6358_irq_init,
+};
+
 static const struct chip_data mt6397_core = {
        .cid_addr = MT6397_CID,
        .cid_shift = 0,
@@ -219,6 +240,9 @@ static const struct of_device_id mt6397_of_match[] = {
                .compatible = "mediatek,mt6358",
                .data = &mt6358_core,
        }, {
+               .compatible = "mediatek,mt6359",
+               .data = &mt6359_core,
+       }, {
                .compatible = "mediatek,mt6397",
                .data = &mt6397_core,
        }, {
index 0e8254d..a164896 100644 (file)
@@ -463,7 +463,7 @@ void lkdtm_DOUBLE_FAULT(void)
 #ifdef CONFIG_ARM64
 static noinline void change_pac_parameters(void)
 {
-       if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH)) {
+       if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {
                /* Reset the keys of current task */
                ptrauth_thread_init_kernel(current);
                ptrauth_thread_switch_kernel(current);
@@ -477,8 +477,8 @@ noinline void lkdtm_CORRUPT_PAC(void)
 #define CORRUPT_PAC_ITERATE    10
        int i;
 
-       if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH))
-               pr_err("FAIL: kernel not built with CONFIG_ARM64_PTR_AUTH\n");
+       if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL))
+               pr_err("FAIL: kernel not built with CONFIG_ARM64_PTR_AUTH_KERNEL\n");
 
        if (!system_supports_address_auth()) {
                pr_err("FAIL: CPU lacks pointer authentication feature\n");
index 689eb9a..88f4c21 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Block driver for media (i.e., flash cards)
  *
@@ -1004,6 +1005,12 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
 
        switch (mq_rq->drv_op) {
        case MMC_DRV_OP_IOCTL:
+               if (card->ext_csd.cmdq_en) {
+                       ret = mmc_cmdq_disable(card);
+                       if (ret)
+                               break;
+               }
+               fallthrough;
        case MMC_DRV_OP_IOCTL_RPMB:
                idata = mq_rq->drv_op_data;
                for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
@@ -1014,6 +1021,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
                /* Always switch back to main area after RPMB access */
                if (rpmb_ioctl)
                        mmc_blk_part_switch(card, 0);
+               else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
+                       mmc_cmdq_enable(card);
                break;
        case MMC_DRV_OP_BOOT_WP:
                ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1159,7 +1168,7 @@ static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
        struct mmc_card *card = md->queue.card;
        int ret = 0;
 
-       ret = mmc_flush_cache(card);
+       ret = mmc_flush_cache(card->host);
        blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
 }
 
index f194940..b039dcf 100644 (file)
@@ -1582,7 +1582,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 {
        struct mmc_command cmd = {};
        unsigned int qty = 0, busy_timeout = 0;
-       bool use_r1b_resp = false;
+       bool use_r1b_resp;
        int err;
 
        mmc_retune_hold(card->host);
@@ -1650,23 +1650,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
        busy_timeout = mmc_erase_timeout(card, arg, qty);
-       /*
-        * If the host controller supports busy signalling and the timeout for
-        * the erase operation does not exceed the max_busy_timeout, we should
-        * use R1B response. Or we need to prevent the host from doing hw busy
-        * detection, which is done by converting to a R1 response instead.
-        * Note, some hosts requires R1B, which also means they are on their own
-        * when it comes to deal with the busy timeout.
-        */
-       if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
-           card->host->max_busy_timeout &&
-           busy_timeout > card->host->max_busy_timeout) {
-               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-       } else {
-               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-               cmd.busy_timeout = busy_timeout;
-               use_r1b_resp = true;
-       }
+       use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout);
 
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
@@ -1687,7 +1671,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                goto out;
 
        /* Let's poll to find out when the erase operation completes. */
-       err = mmc_poll_for_busy(card, busy_timeout, MMC_BUSY_ERASE);
+       err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE);
 
 out:
        mmc_retune_release(card->host);
index db3c9c6..0c4de20 100644 (file)
@@ -30,6 +30,7 @@ struct mmc_bus_ops {
        int (*hw_reset)(struct mmc_host *);
        int (*sw_reset)(struct mmc_host *);
        bool (*cache_enabled)(struct mmc_host *);
+       int (*flush_cache)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -172,4 +173,12 @@ static inline bool mmc_cache_enabled(struct mmc_host *host)
        return false;
 }
 
+static inline int mmc_flush_cache(struct mmc_host *host)
+{
+       if (host->bus_ops->flush_cache)
+               return host->bus_ops->flush_cache(host);
+
+       return 0;
+}
+
 #endif
index 9ec84c8..3fdbc80 100644 (file)
@@ -26,6 +26,7 @@
 static DECLARE_FAULT_ATTR(fail_default_attr);
 static char *fail_request;
 module_param(fail_request, charp, 0);
+MODULE_PARM_DESC(fail_request, "default fault injection attributes");
 
 #endif /* CONFIG_FAIL_MMC_REQUEST */
 
index 0b05779..eda4a18 100644 (file)
@@ -388,6 +388,9 @@ int mmc_of_parse(struct mmc_host *host)
                host->caps2 |= MMC_CAP2_NO_SD;
        if (device_property_read_bool(dev, "no-mmc"))
                host->caps2 |= MMC_CAP2_NO_MMC;
+       if (device_property_read_bool(dev, "no-mmc-hs400"))
+               host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
+                                MMC_CAP2_HS400_ES);
 
        /* Must be after "non-removable" check */
        if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
index 8674c3e..838726b 100644 (file)
@@ -28,6 +28,7 @@
 
 #define DEFAULT_CMD6_TIMEOUT_MS        500
 #define MIN_CACHE_EN_TIMEOUT_MS 1600
+#define CACHE_FLUSH_TIMEOUT_MS 30000 /* 30s */
 
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
@@ -1905,11 +1906,20 @@ static int mmc_can_sleep(struct mmc_card *card)
        return card->ext_csd.rev >= 3;
 }
 
+static int mmc_sleep_busy_cb(void *cb_data, bool *busy)
+{
+       struct mmc_host *host = cb_data;
+
+       *busy = host->ops->card_busy(host);
+       return 0;
+}
+
 static int mmc_sleep(struct mmc_host *host)
 {
        struct mmc_command cmd = {};
        struct mmc_card *card = host->card;
        unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
+       bool use_r1b_resp;
        int err;
 
        /* Re-tuning can't be done once the card is deselected */
@@ -1922,35 +1932,27 @@ static int mmc_sleep(struct mmc_host *host)
        cmd.opcode = MMC_SLEEP_AWAKE;
        cmd.arg = card->rca << 16;
        cmd.arg |= 1 << 15;
-
-       /*
-        * If the max_busy_timeout of the host is specified, validate it against
-        * the sleep cmd timeout. A failure means we need to prevent the host
-        * from doing hw busy detection, which is done by converting to a R1
-        * response instead of a R1B. Note, some hosts requires R1B, which also
-        * means they are on their own when it comes to deal with the busy
-        * timeout.
-        */
-       if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
-           (timeout_ms > host->max_busy_timeout)) {
-               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-       } else {
-               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-               cmd.busy_timeout = timeout_ms;
-       }
+       use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
 
        err = mmc_wait_for_cmd(host, &cmd, 0);
        if (err)
                goto out_release;
 
        /*
-        * If the host does not wait while the card signals busy, then we will
-        * will have to wait the sleep/awake timeout.  Note, we cannot use the
-        * SEND_STATUS command to poll the status because that command (and most
-        * others) is invalid while the card sleeps.
+        * If the host does not wait while the card signals busy, then we can
+        * try to poll, but only if the host supports HW polling, as the
+        * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need
+        * to wait the sleep/awake timeout.
         */
-       if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+       if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+               goto out_release;
+
+       if (!host->ops->card_busy) {
                mmc_delay(timeout_ms);
+               goto out_release;
+       }
+
+       err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host);
 
 out_release:
        mmc_retune_release(host);
@@ -2035,6 +2037,25 @@ static bool _mmc_cache_enabled(struct mmc_host *host)
               host->card->ext_csd.cache_ctrl & 1;
 }
 
+/*
+ * Flush the internal cache of the eMMC to non-volatile storage.
+ */
+static int _mmc_flush_cache(struct mmc_host *host)
+{
+       int err = 0;
+
+       if (_mmc_cache_enabled(host)) {
+               err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_FLUSH_CACHE, 1,
+                                CACHE_FLUSH_TIMEOUT_MS);
+               if (err)
+                       pr_err("%s: cache flush error %d\n",
+                              mmc_hostname(host), err);
+       }
+
+       return err;
+}
+
 static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
        int err = 0;
@@ -2046,7 +2067,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
        if (mmc_card_suspended(host->card))
                goto out;
 
-       err = mmc_flush_cache(host->card);
+       err = _mmc_flush_cache(host);
        if (err)
                goto out;
 
@@ -2187,7 +2208,7 @@ static int _mmc_hw_reset(struct mmc_host *host)
         * In the case of recovery, we can't expect flushing the cache to work
         * always, but we have a go and ignore errors.
         */
-       mmc_flush_cache(host->card);
+       _mmc_flush_cache(host);
 
        if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
             mmc_can_reset(card)) {
@@ -2215,6 +2236,7 @@ static const struct mmc_bus_ops mmc_ops = {
        .shutdown = mmc_shutdown,
        .hw_reset = _mmc_hw_reset,
        .cache_enabled = _mmc_cache_enabled,
+       .flush_cache = _mmc_flush_cache,
 };
 
 /*
index 5756781..973756e 100644 (file)
@@ -20,7 +20,6 @@
 #include "mmc_ops.h"
 
 #define MMC_BKOPS_TIMEOUT_MS           (120 * 1000) /* 120s */
-#define MMC_CACHE_FLUSH_TIMEOUT_MS     (30 * 1000) /* 30s */
 #define MMC_SANITIZE_TIMEOUT_MS                (240 * 1000) /* 240s */
 
 static const u8 tuning_blk_pattern_4bit[] = {
@@ -53,6 +52,12 @@ static const u8 tuning_blk_pattern_8bit[] = {
        0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
 };
 
+struct mmc_busy_data {
+       struct mmc_card *card;
+       bool retry_crc_err;
+       enum mmc_busy_cmd busy_cmd;
+};
+
 int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
 {
        int err;
@@ -246,9 +251,8 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
  * NOTE: void *buf, caller for the buf is required to use DMA-capable
  * buffer or on-stack buffer (with some overhead in callee).
  */
-static int
-mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
-               u32 opcode, void *buf, unsigned len)
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+                      u32 args, void *buf, unsigned len)
 {
        struct mmc_request mrq = {};
        struct mmc_command cmd = {};
@@ -259,7 +263,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
        mrq.data = &data;
 
        cmd.opcode = opcode;
-       cmd.arg = 0;
+       cmd.arg = args;
 
        /* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
         * rely on callers to never use this with "native" calls for reading
@@ -305,7 +309,7 @@ static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
        if (!cxd_tmp)
                return -ENOMEM;
 
-       ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
+       ret = mmc_send_adtc_data(NULL, host, opcode, 0, cxd_tmp, 16);
        if (ret)
                goto err;
 
@@ -353,7 +357,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
        if (!ext_csd)
                return -ENOMEM;
 
-       err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
+       err = mmc_send_adtc_data(card, card->host, MMC_SEND_EXT_CSD, 0, ext_csd,
                                512);
        if (err)
                kfree(ext_csd);
@@ -424,10 +428,10 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
        return mmc_switch_status_error(card->host, status);
 }
 
-static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
-                          enum mmc_busy_cmd busy_cmd, bool *busy)
+static int mmc_busy_cb(void *cb_data, bool *busy)
 {
-       struct mmc_host *host = card->host;
+       struct mmc_busy_data *data = cb_data;
+       struct mmc_host *host = data->card->host;
        u32 status = 0;
        int err;
 
@@ -436,22 +440,23 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
                return 0;
        }
 
-       err = mmc_send_status(card, &status);
-       if (retry_crc_err && err == -EILSEQ) {
+       err = mmc_send_status(data->card, &status);
+       if (data->retry_crc_err && err == -EILSEQ) {
                *busy = true;
                return 0;
        }
        if (err)
                return err;
 
-       switch (busy_cmd) {
+       switch (data->busy_cmd) {
        case MMC_BUSY_CMD6:
-               err = mmc_switch_status_error(card->host, status);
+               err = mmc_switch_status_error(host, status);
                break;
        case MMC_BUSY_ERASE:
                err = R1_STATUS(status) ? -EIO : 0;
                break;
        case MMC_BUSY_HPI:
+       case MMC_BUSY_EXTR_SINGLE:
                break;
        default:
                err = -EINVAL;
@@ -464,9 +469,9 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
        return 0;
 }
 
-static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-                              bool send_status, bool retry_crc_err,
-                              enum mmc_busy_cmd busy_cmd)
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+                       int (*busy_cb)(void *cb_data, bool *busy),
+                       void *cb_data)
 {
        struct mmc_host *host = card->host;
        int err;
@@ -475,16 +480,6 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
        bool expired = false;
        bool busy = false;
 
-       /*
-        * In cases when not allowed to poll by using CMD13 or because we aren't
-        * capable of polling by using ->card_busy(), then rely on waiting the
-        * stated timeout to be sufficient.
-        */
-       if (!send_status && !host->ops->card_busy) {
-               mmc_delay(timeout_ms);
-               return 0;
-       }
-
        timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
        do {
                /*
@@ -493,7 +488,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
                 */
                expired = time_after(jiffies, timeout);
 
-               err = mmc_busy_status(card, retry_crc_err, busy_cmd, &busy);
+               err = (*busy_cb)(cb_data, &busy);
                if (err)
                        return err;
 
@@ -516,9 +511,36 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 }
 
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-                     enum mmc_busy_cmd busy_cmd)
+                     bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
+{
+       struct mmc_busy_data cb_data;
+
+       cb_data.card = card;
+       cb_data.retry_crc_err = retry_crc_err;
+       cb_data.busy_cmd = busy_cmd;
+
+       return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data);
+}
+
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+                         unsigned int timeout_ms)
 {
-       return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
+       /*
+        * If the max_busy_timeout of the host is specified, make sure it's
+        * enough to fit the used timeout_ms. In case it's not, let's instruct
+        * the host to avoid HW busy detection, by converting to a R1 response
+        * instead of a R1B. Note, some hosts requires R1B, which also means
+        * they are on their own when it comes to deal with the busy timeout.
+        */
+       if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+           (timeout_ms > host->max_busy_timeout)) {
+               cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1 | MMC_RSP_R1;
+               return false;
+       }
+
+       cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+       cmd->busy_timeout = timeout_ms;
+       return true;
 }
 
 /**
@@ -543,7 +565,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
        struct mmc_host *host = card->host;
        int err;
        struct mmc_command cmd = {};
-       bool use_r1b_resp = true;
+       bool use_r1b_resp;
        unsigned char old_timing = host->ios.timing;
 
        mmc_retune_hold(host);
@@ -554,29 +576,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                timeout_ms = card->ext_csd.generic_cmd6_time;
        }
 
-       /*
-        * If the max_busy_timeout of the host is specified, make sure it's
-        * enough to fit the used timeout_ms. In case it's not, let's instruct
-        * the host to avoid HW busy detection, by converting to a R1 response
-        * instead of a R1B. Note, some hosts requires R1B, which also means
-        * they are on their own when it comes to deal with the busy timeout.
-        */
-       if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
-           (timeout_ms > host->max_busy_timeout))
-               use_r1b_resp = false;
-
        cmd.opcode = MMC_SWITCH;
        cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
                  (index << 16) |
                  (value << 8) |
                  set;
-       cmd.flags = MMC_CMD_AC;
-       if (use_r1b_resp) {
-               cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
-               cmd.busy_timeout = timeout_ms;
-       } else {
-               cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
-       }
+       use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
 
        err = mmc_wait_for_cmd(host, &cmd, retries);
        if (err)
@@ -587,9 +592,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                mmc_host_is_spi(host))
                goto out_tim;
 
+       /*
+        * If the host doesn't support HW polling via the ->card_busy() ops and
+        * when it's not allowed to poll by using CMD13, then we need to rely on
+        * waiting the stated timeout to be sufficient.
+        */
+       if (!send_status && !host->ops->card_busy) {
+               mmc_delay(timeout_ms);
+               goto out_tim;
+       }
+
        /* Let's try to poll to find out when the command is completed. */
-       err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
-                                 MMC_BUSY_CMD6);
+       err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6);
        if (err)
                goto out;
 
@@ -686,7 +700,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(mmc_send_tuning);
 
-int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
+int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode)
 {
        struct mmc_command cmd = {};
 
@@ -709,7 +723,7 @@ int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
 
        return mmc_wait_for_cmd(host, &cmd, 0);
 }
-EXPORT_SYMBOL_GPL(mmc_abort_tuning);
+EXPORT_SYMBOL_GPL(mmc_send_abort_tuning);
 
 static int
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
@@ -813,28 +827,17 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
 {
        unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time;
        struct mmc_host *host = card->host;
-       bool use_r1b_resp = true;
+       bool use_r1b_resp = false;
        struct mmc_command cmd = {};
        int err;
 
        cmd.opcode = card->ext_csd.hpi_cmd;
        cmd.arg = card->rca << 16 | 1;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
-       /*
-        * Make sure the host's max_busy_timeout fit the needed timeout for HPI.
-        * In case it doesn't, let's instruct the host to avoid HW busy
-        * detection, by using a R1 response instead of R1B.
-        */
-       if (host->max_busy_timeout && busy_timeout_ms > host->max_busy_timeout)
-               use_r1b_resp = false;
-
-       if (cmd.opcode == MMC_STOP_TRANSMISSION && use_r1b_resp) {
-               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-               cmd.busy_timeout = busy_timeout_ms;
-       } else {
-               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-               use_r1b_resp = false;
-       }
+       if (cmd.opcode == MMC_STOP_TRANSMISSION)
+               use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd,
+                                                   busy_timeout_ms);
 
        err = mmc_wait_for_cmd(host, &cmd, 0);
        if (err) {
@@ -848,7 +851,7 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
                return 0;
 
        /* Let's poll to find out when the HPI request completes. */
-       return mmc_poll_for_busy(card, busy_timeout_ms, MMC_BUSY_HPI);
+       return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI);
 }
 
 /**
@@ -961,26 +964,6 @@ void mmc_run_bkops(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_run_bkops);
 
-/*
- * Flush the cache to the non-volatile storage.
- */
-int mmc_flush_cache(struct mmc_card *card)
-{
-       int err = 0;
-
-       if (mmc_cache_enabled(card->host)) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_FLUSH_CACHE, 1,
-                                MMC_CACHE_FLUSH_TIMEOUT_MS);
-               if (err)
-                       pr_err("%s: cache flush error %d\n",
-                                       mmc_hostname(card->host), err);
-       }
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_flush_cache);
-
 static int mmc_cmdq_switch(struct mmc_card *card, bool enable)
 {
        u8 val = enable ? EXT_CSD_CMDQ_MODE_ENABLED : 0;
index 7bc1cfb..41ab4f5 100644 (file)
@@ -14,10 +14,12 @@ enum mmc_busy_cmd {
        MMC_BUSY_CMD6,
        MMC_BUSY_ERASE,
        MMC_BUSY_HPI,
+       MMC_BUSY_EXTR_SINGLE,
 };
 
 struct mmc_host;
 struct mmc_card;
+struct mmc_command;
 
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
@@ -25,6 +27,8 @@ int mmc_set_dsr(struct mmc_host *host);
 int mmc_go_idle(struct mmc_host *host);
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+                      u32 args, void *buf, unsigned len);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
 int mmc_send_status(struct mmc_card *card, u32 *status);
@@ -35,15 +39,19 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_can_ext_csd(struct mmc_card *card);
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+                         unsigned int timeout_ms);
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+                       int (*busy_cb)(void *cb_data, bool *busy),
+                       void *cb_data);
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-                     enum mmc_busy_cmd busy_cmd);
+                     bool retry_crc_err, enum mmc_busy_cmd busy_cmd);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms, unsigned char timing,
                bool send_status, bool retry_crc_err, unsigned int retries);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms);
 void mmc_run_bkops(struct mmc_card *card);
-int mmc_flush_cache(struct mmc_card *card);
 int mmc_cmdq_enable(struct mmc_card *card);
 int mmc_cmdq_disable(struct mmc_card *card);
 int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms);
index 2c48d65..4646b7a 100644 (file)
@@ -66,6 +66,14 @@ static const unsigned int sd_au_size[] = {
                __res & __mask;                                         \
        })
 
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+#define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
+
+struct sd_busy_data {
+       struct mmc_card *card;
+       u8 *reg_buf;
+};
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -222,7 +230,9 @@ static int mmc_decode_scr(struct mmc_card *card)
        else
                card->erased_byte = 0x0;
 
-       if (scr->sda_spec3)
+       if (scr->sda_spec4)
+               scr->cmds = UNSTUFF_BITS(resp, 32, 4);
+       else if (scr->sda_spec3)
                scr->cmds = UNSTUFF_BITS(resp, 32, 2);
 
        /* SD Spec says: any SD Card shall set at least bits 0 and 2 */
@@ -847,11 +857,13 @@ try_again:
                return err;
 
        /*
-        * In case CCS and S18A in the response is set, start Signal Voltage
-        * Switch procedure. SPI mode doesn't support CMD11.
+        * In case the S18A bit is set in the response, let's start the signal
+        * voltage switch procedure. SPI mode doesn't support CMD11.
+        * Note that, according to the spec, the S18A bit is not valid unless
+        * the CCS bit is set as well. We deliberately deviate from the spec in
+        * regards to this, which allows UHS-I to be supported for SDSC cards.
         */
-       if (!mmc_host_is_spi(host) && rocr &&
-          ((*rocr & 0x41000000) == 0x41000000)) {
+       if (!mmc_host_is_spi(host) && rocr && (*rocr & 0x01000000)) {
                err = mmc_set_uhs_voltage(host, pocr);
                if (err == -EAGAIN) {
                        retries--;
@@ -994,6 +1006,380 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
               (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
 }
 
+static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+                           u8 reg_data)
+{
+       struct mmc_host *host = card->host;
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
+       struct scatterlist sg;
+       u8 *reg_buf;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       mrq.cmd = &cmd;
+       mrq.data = &data;
+
+       /*
+        * Arguments of CMD49:
+        * [31:31] MIO (0 = memory).
+        * [30:27] FNO (function number).
+        * [26:26] MW - mask write mode (0 = disable).
+        * [25:18] page number.
+        * [17:9] offset address.
+        * [8:0] length (0 = 1 byte).
+        */
+       cmd.arg = fno << 27 | page << 18 | offset << 9;
+
+       /* The first byte in the buffer is the data to be written. */
+       reg_buf[0] = reg_data;
+
+       data.flags = MMC_DATA_WRITE;
+       data.blksz = 512;
+       data.blocks = 1;
+       data.sg = &sg;
+       data.sg_len = 1;
+       sg_init_one(&sg, reg_buf, 512);
+
+       cmd.opcode = SD_WRITE_EXTR_SINGLE;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+       mmc_set_data_timeout(&data, card);
+       mmc_wait_for_req(host, &mrq);
+
+       kfree(reg_buf);
+
+       /*
+        * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
+        * after the CMD49. Although, let's leave this to be managed by the
+        * caller.
+        */
+
+       if (cmd.error)
+               return cmd.error;
+       if (data.error)
+               return data.error;
+
+       return 0;
+}
+
+static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+                          u16 offset, u16 len, u8 *reg_buf)
+{
+       u32 cmd_args;
+
+       /*
+        * Command arguments of CMD48:
+        * [31:31] MIO (0 = memory).
+        * [30:27] FNO (function number).
+        * [26:26] reserved (0).
+        * [25:18] page number.
+        * [17:9] offset address.
+        * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
+        */
+       cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
+
+       return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
+                                 cmd_args, reg_buf, 512);
+}
+
+static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
+                                 u16 offset)
+{
+       int err;
+       u8 *reg_buf;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       /* Read the extension register for power management function. */
+       err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+       if (err) {
+               pr_warn("%s: error %d reading PM func of ext reg\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       /* PM revision consists of 4 bits. */
+       card->ext_power.rev = reg_buf[0] & 0xf;
+
+       /* Power Off Notification support at bit 4. */
+       if (reg_buf[1] & BIT(4))
+               card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
+
+       /* Power Sustenance support at bit 5. */
+       if (reg_buf[1] & BIT(5))
+               card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
+
+       /* Power Down Mode support at bit 6. */
+       if (reg_buf[1] & BIT(6))
+               card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
+
+       card->ext_power.fno = fno;
+       card->ext_power.page = page;
+       card->ext_power.offset = offset;
+
+out:
+       kfree(reg_buf);
+       return err;
+}
+
+static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
+                                u16 offset)
+{
+       int err;
+       u8 *reg_buf;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+       if (err) {
+               pr_warn("%s: error %d reading PERF func of ext reg\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       /* PERF revision. */
+       card->ext_perf.rev = reg_buf[0];
+
+       /* FX_EVENT support at bit 0. */
+       if (reg_buf[1] & BIT(0))
+               card->ext_perf.feature_support |= SD_EXT_PERF_FX_EVENT;
+
+       /* Card initiated self-maintenance support at bit 0. */
+       if (reg_buf[2] & BIT(0))
+               card->ext_perf.feature_support |= SD_EXT_PERF_CARD_MAINT;
+
+       /* Host initiated self-maintenance support at bit 1. */
+       if (reg_buf[2] & BIT(1))
+               card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT;
+
+       /* Cache support at bit 0. */
+       if (reg_buf[4] & BIT(0))
+               card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
+
+       /* Command queue support indicated via queue depth bits (0 to 4). */
+       if (reg_buf[6] & 0x1f)
+               card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE;
+
+       card->ext_perf.fno = fno;
+       card->ext_perf.page = page;
+       card->ext_perf.offset = offset;
+
+out:
+       kfree(reg_buf);
+       return err;
+}
+
+static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
+                           u16 *next_ext_addr)
+{
+       u8 num_regs, fno, page;
+       u16 sfc, offset, ext = *next_ext_addr;
+       u32 reg_addr;
+
+       /*
+        * Parse only one register set per extension, as that is sufficient to
+        * support the standard functions. This means another 48 bytes in the
+        * buffer must be available.
+        */
+       if (ext + 48 > 512)
+               return -EFAULT;
+
+       /* Standard Function Code */
+       memcpy(&sfc, &gen_info_buf[ext], 2);
+
+       /* Address to the next extension. */
+       memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
+
+       /* Number of registers for this extension. */
+       num_regs = gen_info_buf[ext + 42];
+
+       /* We support only one register per extension. */
+       if (num_regs != 1)
+               return 0;
+
+       /* Extension register address. */
+       memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
+
+       /* 9 bits (0 to 8) contains the offset address. */
+       offset = reg_addr & 0x1ff;
+
+       /* 8 bits (9 to 16) contains the page number. */
+       page = reg_addr >> 9 & 0xff ;
+
+       /* 4 bits (18 to 21) contains the function number. */
+       fno = reg_addr >> 18 & 0xf;
+
+       /* Standard Function Code for power management. */
+       if (sfc == 0x1)
+               return sd_parse_ext_reg_power(card, fno, page, offset);
+
+       /* Standard Function Code for performance enhancement. */
+       if (sfc == 0x2)
+               return sd_parse_ext_reg_perf(card, fno, page, offset);
+
+       return 0;
+}
+
+static int sd_read_ext_regs(struct mmc_card *card)
+{
+       int err, i;
+       u8 num_ext, *gen_info_buf;
+       u16 rev, len, next_ext_addr;
+
+       if (mmc_host_is_spi(card->host))
+               return 0;
+
+       if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
+               return 0;
+
+       gen_info_buf = kzalloc(512, GFP_KERNEL);
+       if (!gen_info_buf)
+               return -ENOMEM;
+
+       /*
+        * Read 512 bytes of general info, which is found at function number 0,
+        * at page 0 and with no offset.
+        */
+       err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
+       if (err) {
+               pr_warn("%s: error %d reading general info of SD ext reg\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       /* General info structure revision. */
+       memcpy(&rev, &gen_info_buf[0], 2);
+
+       /* Length of general info in bytes. */
+       memcpy(&len, &gen_info_buf[2], 2);
+
+       /* Number of extensions to be find. */
+       num_ext = gen_info_buf[4];
+
+       /* We support revision 0, but limit it to 512 bytes for simplicity. */
+       if (rev != 0 || len > 512) {
+               pr_warn("%s: non-supported SD ext reg layout\n",
+                       mmc_hostname(card->host));
+               goto out;
+       }
+
+       /*
+        * Parse the extension registers. The first extension should start
+        * immediately after the general info header (16 bytes).
+        */
+       next_ext_addr = 16;
+       for (i = 0; i < num_ext; i++) {
+               err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
+               if (err) {
+                       pr_warn("%s: error %d parsing SD ext reg\n",
+                               mmc_hostname(card->host), err);
+                       goto out;
+               }
+       }
+
+out:
+       kfree(gen_info_buf);
+       return err;
+}
+
+static bool sd_cache_enabled(struct mmc_host *host)
+{
+       return host->card->ext_perf.feature_enabled & SD_EXT_PERF_CACHE;
+}
+
+static int sd_flush_cache(struct mmc_host *host)
+{
+       struct mmc_card *card = host->card;
+       u8 *reg_buf, fno, page;
+       u16 offset;
+       int err;
+
+       if (!sd_cache_enabled(host))
+               return 0;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       /*
+        * Set Flush Cache at bit 0 in the performance enhancement register at
+        * 261 bytes offset.
+        */
+       fno = card->ext_perf.fno;
+       page = card->ext_perf.page;
+       offset = card->ext_perf.offset + 261;
+
+       err = sd_write_ext_reg(card, fno, page, offset, BIT(0));
+       if (err) {
+               pr_warn("%s: error %d writing Cache Flush bit\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+
+       err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+                               MMC_BUSY_EXTR_SINGLE);
+       if (err)
+               goto out;
+
+       /*
+        * Read the Flush Cache bit. The card shall reset it, to confirm that
+        * it's has completed the flushing of the cache.
+        */
+       err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
+       if (err) {
+               pr_warn("%s: error %d reading Cache Flush bit\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+
+       if (reg_buf[0] & BIT(0))
+               err = -ETIMEDOUT;
+out:
+       kfree(reg_buf);
+       return err;
+}
+
+static int sd_enable_cache(struct mmc_card *card)
+{
+       u8 *reg_buf;
+       int err;
+
+       card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       /*
+        * Set Cache Enable at bit 0 in the performance enhancement register at
+        * 260 bytes offset.
+        */
+       err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+                              card->ext_perf.offset + 260, BIT(0));
+       if (err) {
+               pr_warn("%s: error %d writing Cache Enable bit\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+                               MMC_BUSY_EXTR_SINGLE);
+       if (!err)
+               card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE;
+
+out:
+       kfree(reg_buf);
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -1142,6 +1528,20 @@ retry:
                }
        }
 
+       if (!oldcard) {
+               /* Read/parse the extension registers. */
+               err = sd_read_ext_regs(card);
+               if (err)
+                       goto free_card;
+       }
+
+       /* Enable internal SD cache if supported. */
+       if (card->ext_perf.feature_support & SD_EXT_PERF_CACHE) {
+               err = sd_enable_cache(card);
+               if (err)
+                       goto free_card;
+       }
+
        if (host->cqe_ops && !host->cqe_enabled) {
                err = host->cqe_ops->cqe_enable(host, card);
                if (!err) {
@@ -1213,21 +1613,84 @@ static void mmc_sd_detect(struct mmc_host *host)
        }
 }
 
+static int sd_can_poweroff_notify(struct mmc_card *card)
+{
+       return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
+}
+
+static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
+{
+       struct sd_busy_data *data = cb_data;
+       struct mmc_card *card = data->card;
+       int err;
+
+       /*
+        * Read the status register for the power management function. It's at
+        * one byte offset and is one byte long. The Power Off Notification
+        * Ready is bit 0.
+        */
+       err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+                             card->ext_power.offset + 1, 1, data->reg_buf);
+       if (err) {
+               pr_warn("%s: error %d reading status reg of PM func\n",
+                       mmc_hostname(card->host), err);
+               return err;
+       }
+
+       *busy = !(data->reg_buf[0] & BIT(0));
+       return 0;
+}
+
+static int sd_poweroff_notify(struct mmc_card *card)
+{
+       struct sd_busy_data cb_data;
+       u8 *reg_buf;
+       int err;
+
+       reg_buf = kzalloc(512, GFP_KERNEL);
+       if (!reg_buf)
+               return -ENOMEM;
+
+       /*
+        * Set the Power Off Notification bit in the power management settings
+        * register at 2 bytes offset.
+        */
+       err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+                              card->ext_power.offset + 2, BIT(0));
+       if (err) {
+               pr_warn("%s: error %d writing Power Off Notify bit\n",
+                       mmc_hostname(card->host), err);
+               goto out;
+       }
+
+       cb_data.card = card;
+       cb_data.reg_buf = reg_buf;
+       err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+                                 &sd_busy_poweroff_notify_cb, &cb_data);
+
+out:
+       kfree(reg_buf);
+       return err;
+}
+
 static int _mmc_sd_suspend(struct mmc_host *host)
 {
+       struct mmc_card *card = host->card;
        int err = 0;
 
        mmc_claim_host(host);
 
-       if (mmc_card_suspended(host->card))
+       if (mmc_card_suspended(card))
                goto out;
 
-       if (!mmc_host_is_spi(host))
+       if (sd_can_poweroff_notify(card))
+               err = sd_poweroff_notify(card);
+       else if (!mmc_host_is_spi(host))
                err = mmc_deselect_cards(host);
 
        if (!err) {
                mmc_power_off(host);
-               mmc_card_set_suspended(host->card);
+               mmc_card_set_suspended(card);
        }
 
 out:
@@ -1331,6 +1794,8 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .alive = mmc_sd_alive,
        .shutdown = mmc_sd_suspend,
        .hw_reset = mmc_sd_hw_reset,
+       .cache_enabled = sd_cache_enabled,
+       .flush_cache = sd_flush_cache,
 };
 
 /*
index d61ff81..ef8d1dc 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "core.h"
 #include "sd_ops.h"
+#include "mmc_ops.h"
 
 int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 {
@@ -309,43 +310,18 @@ int mmc_app_send_scr(struct mmc_card *card)
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        u8 value, u8 *resp)
 {
-       struct mmc_request mrq = {};
-       struct mmc_command cmd = {};
-       struct mmc_data data = {};
-       struct scatterlist sg;
+       u32 cmd_args;
 
        /* NOTE: caller guarantees resp is heap-allocated */
 
        mode = !!mode;
        value &= 0xF;
+       cmd_args = mode << 31 | 0x00FFFFFF;
+       cmd_args &= ~(0xF << (group * 4));
+       cmd_args |= value << (group * 4);
 
-       mrq.cmd = &cmd;
-       mrq.data = &data;
-
-       cmd.opcode = SD_SWITCH;
-       cmd.arg = mode << 31 | 0x00FFFFFF;
-       cmd.arg &= ~(0xF << (group * 4));
-       cmd.arg |= value << (group * 4);
-       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
-       data.blksz = 64;
-       data.blocks = 1;
-       data.flags = MMC_DATA_READ;
-       data.sg = &sg;
-       data.sg_len = 1;
-
-       sg_init_one(&sg, resp, 64);
-
-       mmc_set_data_timeout(&data, card);
-
-       mmc_wait_for_req(card->host, &mrq);
-
-       if (cmd.error)
-               return cmd.error;
-       if (data.error)
-               return data.error;
-
-       return 0;
+       return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
+                                 64);
 }
 
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
index 3eb94ac..68edf7a 100644 (file)
@@ -937,11 +937,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
 
        /* Make sure card is powered before detecting it */
        if (host->caps & MMC_CAP_POWER_OFF_CARD) {
-               err = pm_runtime_get_sync(&host->card->dev);
-               if (err < 0) {
-                       pm_runtime_put_noidle(&host->card->dev);
+               err = pm_runtime_resume_and_get(&host->card->dev);
+               if (err < 0)
                        goto out;
-               }
        }
 
        mmc_claim_host(host);
index a4d4c75..561184f 100644 (file)
@@ -412,7 +412,7 @@ config MMC_SDHCI_MILBEAUT
 
 config MMC_SDHCI_IPROC
        tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
-       depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
+       depends on ARCH_BCM2835 || ARCH_BCM_IPROC || ARCH_BRCMSTB || COMPILE_TEST
        depends on MMC_SDHCI_PLTFM
        depends on OF || ACPI
        default ARCH_BCM_IPROC
index 93b0432..38559a9 100644 (file)
@@ -45,17 +45,23 @@ static inline u8 *get_link_desc(struct cqhci_host *cq_host, u8 tag)
        return desc + cq_host->task_desc_len;
 }
 
+static inline size_t get_trans_desc_offset(struct cqhci_host *cq_host, u8 tag)
+{
+       return cq_host->trans_desc_len * cq_host->mmc->max_segs * tag;
+}
+
 static inline dma_addr_t get_trans_desc_dma(struct cqhci_host *cq_host, u8 tag)
 {
-       return cq_host->trans_desc_dma_base +
-               (cq_host->mmc->max_segs * tag *
-                cq_host->trans_desc_len);
+       size_t offset = get_trans_desc_offset(cq_host, tag);
+
+       return cq_host->trans_desc_dma_base + offset;
 }
 
 static inline u8 *get_trans_desc(struct cqhci_host *cq_host, u8 tag)
 {
-       return cq_host->trans_desc_base +
-               (cq_host->trans_desc_len * cq_host->mmc->max_segs * tag);
+       size_t offset = get_trans_desc_offset(cq_host, tag);
+
+       return cq_host->trans_desc_base + offset;
 }
 
 static void setup_trans_desc(struct cqhci_host *cq_host, u8 tag)
@@ -146,7 +152,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host)
 }
 
 /*
- * The allocated descriptor table for task, link & transfer descritors
+ * The allocated descriptor table for task, link & transfer descriptors
  * looks like:
  * |----------|
  * |task desc |  |->|----------|
@@ -194,8 +200,7 @@ static int cqhci_host_alloc_tdl(struct cqhci_host *cq_host)
 
        cq_host->desc_size = cq_host->slot_sz * cq_host->num_slots;
 
-       cq_host->data_size = cq_host->trans_desc_len * cq_host->mmc->max_segs *
-               cq_host->mmc->cqe_qdepth;
+       cq_host->data_size = get_trans_desc_offset(cq_host, cq_host->mmc->cqe_qdepth);
 
        pr_debug("%s: cqhci: desc_size: %zu data_sz: %zu slot-sz: %d\n",
                 mmc_hostname(cq_host->mmc), cq_host->desc_size, cq_host->data_size,
index 73731cd..9901208 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/of.h>
-#include <linux/clk.h>
 
 #include "dw_mmc.h"
 #include "dw_mmc-pltfm.h"
index b3c636e..0db17bc 100644 (file)
@@ -674,7 +674,7 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
                        cmdat |= JZ_MMC_CMDAT_WRITE;
                if (host->use_dma) {
                        /*
-                        * The 4780's MMC controller has integrated DMA ability
+                        * The JZ4780's MMC controller has integrated DMA ability
                         * in addition to being able to use the external DMA
                         * controller. It moves DMA control bits to a separate
                         * register. The DMA_SEL bit chooses the external
@@ -866,7 +866,7 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
        writew(div, host->base + JZ_REG_MMC_CLKRT);
 
        if (real_rate > 25000000) {
-               if (host->version >= JZ_MMC_X1000) {
+               if (host->version >= JZ_MMC_JZ4780) {
                        writel(JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY |
                                   JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY |
                                   JZ_MMC_LPM_LOW_POWER_MODE_EN,
@@ -959,6 +959,7 @@ static const struct of_device_id jz4740_mmc_of_match[] = {
        { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },
        { .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B },
        { .compatible = "ingenic,jz4760-mmc", .data = (void *) JZ_MMC_JZ4760 },
+       { .compatible = "ingenic,jz4775-mmc", .data = (void *) JZ_MMC_JZ4780 },
        { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
        { .compatible = "ingenic,x1000-mmc", .data = (void *) JZ_MMC_X1000 },
        {},
@@ -1013,7 +1014,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        host->base = devm_ioremap_resource(&pdev->dev, host->mem_res);
        if (IS_ERR(host->base)) {
                ret = PTR_ERR(host->base);
-               dev_err(&pdev->dev, "Failed to ioremap base memory\n");
                goto err_free_host;
        }
 
index 016a610..3f28eb4 100644 (file)
@@ -165,6 +165,7 @@ struct meson_host {
 
        unsigned int bounce_buf_size;
        void *bounce_buf;
+       void __iomem *bounce_iomem_buf;
        dma_addr_t bounce_dma_addr;
        struct sd_emmc_desc *descs;
        dma_addr_t descs_dma_addr;
@@ -745,6 +746,47 @@ static void meson_mmc_desc_chain_transfer(struct mmc_host *mmc, u32 cmd_cfg)
        writel(start, host->regs + SD_EMMC_START);
 }
 
+/* local sg copy to buffer version with _to/fromio usage for dram_access_quirk */
+static void meson_mmc_copy_buffer(struct meson_host *host, struct mmc_data *data,
+                                 size_t buflen, bool to_buffer)
+{
+       unsigned int sg_flags = SG_MITER_ATOMIC;
+       struct scatterlist *sgl = data->sg;
+       unsigned int nents = data->sg_len;
+       struct sg_mapping_iter miter;
+       unsigned int offset = 0;
+
+       if (to_buffer)
+               sg_flags |= SG_MITER_FROM_SG;
+       else
+               sg_flags |= SG_MITER_TO_SG;
+
+       sg_miter_start(&miter, sgl, nents, sg_flags);
+
+       while ((offset < buflen) && sg_miter_next(&miter)) {
+               unsigned int len;
+
+               len = min(miter.length, buflen - offset);
+
+               /* When dram_access_quirk, the bounce buffer is a iomem mapping */
+               if (host->dram_access_quirk) {
+                       if (to_buffer)
+                               memcpy_toio(host->bounce_iomem_buf + offset, miter.addr, len);
+                       else
+                               memcpy_fromio(miter.addr, host->bounce_iomem_buf + offset, len);
+               } else {
+                       if (to_buffer)
+                               memcpy(host->bounce_buf + offset, miter.addr, len);
+                       else
+                               memcpy(miter.addr, host->bounce_buf + offset, len);
+               }
+
+               offset += len;
+       }
+
+       sg_miter_stop(&miter);
+}
+
 static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct meson_host *host = mmc_priv(mmc);
@@ -788,8 +830,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
                if (data->flags & MMC_DATA_WRITE) {
                        cmd_cfg |= CMD_CFG_DATA_WR;
                        WARN_ON(xfer_bytes > host->bounce_buf_size);
-                       sg_copy_to_buffer(data->sg, data->sg_len,
-                                         host->bounce_buf, xfer_bytes);
+                       meson_mmc_copy_buffer(host, data, xfer_bytes, true);
                        dma_wmb();
                }
 
@@ -958,8 +999,7 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
        if (meson_mmc_bounce_buf_read(data)) {
                xfer_bytes = data->blksz * data->blocks;
                WARN_ON(xfer_bytes > host->bounce_buf_size);
-               sg_copy_from_buffer(data->sg, data->sg_len,
-                                   host->bounce_buf, xfer_bytes);
+               meson_mmc_copy_buffer(host, data, xfer_bytes, false);
        }
 
        next_cmd = meson_mmc_get_next_command(cmd);
@@ -1179,7 +1219,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
                 * instead of the DDR memory
                 */
                host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
-               host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
+               host->bounce_iomem_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
                host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
        } else {
                /* data bounce buffer */
index 9776a03..65c65bb 100644 (file)
@@ -504,7 +504,7 @@ mmc_spi_command_send(struct mmc_spi_host *host,
                /* else:  R1 (most commands) */
        }
 
-       dev_dbg(&host->spi->dev, "  mmc_spi: CMD%d, resp %s\n",
+       dev_dbg(&host->spi->dev, "  CMD%d, resp %s\n",
                cmd->opcode, maptype(cmd));
 
        /* send command, leaving chipselect active */
@@ -928,8 +928,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                while (length) {
                        t->len = min(length, blk_size);
 
-                       dev_dbg(&host->spi->dev,
-                               "    mmc_spi: %s block, %d bytes\n",
+                       dev_dbg(&host->spi->dev, "    %s block, %d bytes\n",
                                (direction == DMA_TO_DEVICE) ? "write" : "read",
                                t->len);
 
@@ -974,7 +973,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                int             tmp;
                const unsigned  statlen = sizeof(scratch->status);
 
-               dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
+               dev_dbg(&spi->dev, "    STOP_TRAN\n");
 
                /* Tweak the per-block message we set up earlier by morphing
                 * it to hold single buffer with the token followed by some
@@ -1175,7 +1174,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
                canpower = host->pdata && host->pdata->setpower;
 
-               dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+               dev_dbg(&host->spi->dev, "power %s (%d)%s\n",
                                mmc_powerstring(ios->power_mode),
                                ios->vdd,
                                canpower ? ", can switch" : "");
@@ -1248,8 +1247,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
                host->spi->max_speed_hz = ios->clock;
                status = spi_setup(host->spi);
-               dev_dbg(&host->spi->dev,
-                       "mmc_spi:  clock to %d Hz, %d\n",
+               dev_dbg(&host->spi->dev, "  clock to %d Hz, %d\n",
                        host->spi->max_speed_hz, status);
        }
 }
index 898ed1b..4dfc246 100644 (file)
@@ -724,10 +724,8 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
        writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA);
 }
 
-static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
+static void msdc_prepare_data(struct msdc_host *host, struct mmc_data *data)
 {
-       struct mmc_data *data = mrq->data;
-
        if (!(data->host_cookie & MSDC_PREPARE_FLAG)) {
                data->host_cookie |= MSDC_PREPARE_FLAG;
                data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len,
@@ -735,10 +733,8 @@ static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
        }
 }
 
-static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
+static void msdc_unprepare_data(struct msdc_host *host, struct mmc_data *data)
 {
-       struct mmc_data *data = mrq->data;
-
        if (data->host_cookie & MSDC_ASYNC_FLAG)
                return;
 
@@ -1140,7 +1136,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
 
        msdc_track_cmd_data(host, mrq->cmd, mrq->data);
        if (mrq->data)
-               msdc_unprepare_data(host, mrq);
+               msdc_unprepare_data(host, mrq->data);
        if (host->error)
                msdc_reset_hw(host);
        mmc_request_done(mmc_from_priv(host), mrq);
@@ -1311,7 +1307,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
        host->mrq = mrq;
 
        if (mrq->data)
-               msdc_prepare_data(host, mrq);
+               msdc_prepare_data(host, mrq->data);
 
        /* if SBC is required, we have HW option and SW option.
         * if HW option is enabled, and SBC does not have "special" flags,
@@ -1332,7 +1328,7 @@ static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
        if (!data)
                return;
 
-       msdc_prepare_data(host, mrq);
+       msdc_prepare_data(host, data);
        data->host_cookie |= MSDC_ASYNC_FLAG;
 }
 
@@ -1340,19 +1336,18 @@ static void msdc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
                int err)
 {
        struct msdc_host *host = mmc_priv(mmc);
-       struct mmc_data *data;
+       struct mmc_data *data = mrq->data;
 
-       data = mrq->data;
        if (!data)
                return;
+
        if (data->host_cookie) {
                data->host_cookie &= ~MSDC_ASYNC_FLAG;
-               msdc_unprepare_data(host, mrq);
+               msdc_unprepare_data(host, data);
        }
 }
 
-static void msdc_data_xfer_next(struct msdc_host *host,
-                               struct mmc_request *mrq, struct mmc_data *data)
+static void msdc_data_xfer_next(struct msdc_host *host, struct mmc_request *mrq)
 {
        if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error &&
            !mrq->sbc)
@@ -1411,7 +1406,7 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
                                (int)data->error, data->bytes_xfered);
                }
 
-               msdc_data_xfer_next(host, mrq, data);
+               msdc_data_xfer_next(host, mrq);
                done = true;
        }
        return done;
index 9d480a0..3629550 100644 (file)
@@ -22,8 +22,8 @@
 MODULE_LICENSE("GPL");
 
 struct of_mmc_spi {
-       int detect_irq;
        struct mmc_spi_platform_data pdata;
+       int detect_irq;
 };
 
 static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
index baab4c2..e49ca0f 100644 (file)
@@ -704,7 +704,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
                        set_bit(i, priv->smpcmp);
 
                if (cmd_error)
-                       mmc_abort_tuning(mmc, opcode);
+                       mmc_send_abort_tuning(mmc, opcode);
        }
 
        ret = renesas_sdhi_select_tuning(host);
index 0ca6f6d..8d5929a 100644 (file)
@@ -1578,17 +1578,12 @@ static int s3cmci_probe(struct platform_device *pdev)
                goto probe_iounmap;
        }
 
-       if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
+       if (request_irq(host->irq, s3cmci_irq, IRQF_NO_AUTOEN, DRIVER_NAME, host)) {
                dev_err(&pdev->dev, "failed to request mci interrupt.\n");
                ret = -ENOENT;
                goto probe_iounmap;
        }
 
-       /* We get spurious interrupts even when we have set the IMSK
-        * register to ignore everything, so use disable_irq() to make
-        * ensure we don't lock the system with un-serviceable requests. */
-
-       disable_irq(host->irq);
        host->irq_state = false;
 
        /* Depending on the dma state, get a DMA channel to use. */
index c3fbf8c..8fe65f1 100644 (file)
@@ -822,6 +822,17 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
                },
                .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
        },
+       {
+               /*
+                * The Toshiba WT8-B's microSD slot always reports the card being
+                * write-protected.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TOSHIBA ENCORE 2 WT8-B"),
+               },
+               .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
+       },
        {} /* Terminating entry */
 };
 
index b991cf0..72c0bf0 100644 (file)
@@ -324,11 +324,6 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
        return data->socdata == &esdhc_imx53_data;
 }
 
-static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
-{
-       return data->socdata == &usdhc_imx6q_data;
-}
-
 static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
 {
        return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
@@ -427,9 +422,6 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
                                        | FIELD_PREP(SDHCI_RETUNING_MODE_MASK,
                                                     SDHCI_TUNING_MODE_3);
 
-                       if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
-                               val |= SDHCI_SUPPORT_HS400;
-
                        /*
                         * Do not advertise faster UHS modes if there are no
                         * pinctrl states for 100MHz/200MHz.
@@ -1591,7 +1583,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
                host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
        if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
-               host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
+               host->mmc->caps2 |= MMC_CAP2_HS400;
 
        if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
                host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
@@ -1628,6 +1620,14 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (err)
                goto disable_ahb_clk;
 
+       /*
+        * Setup the wakeup capability here, let user to decide
+        * whether need to enable this wakeup through sysfs interface.
+        */
+       if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) &&
+                       (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ))
+               device_set_wakeup_capable(&pdev->dev, true);
+
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_use_autosuspend(&pdev->dev);
index ddeaf8e..cce390f 100644 (file)
@@ -286,11 +286,35 @@ static const struct sdhci_iproc_data bcm2711_data = {
        .mmc_caps = MMC_CAP_3_3V_DDR,
 };
 
+static const struct sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = {
+       .quirks = SDHCI_QUIRK_MISSING_CAPS |
+               SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+               SDHCI_QUIRK_BROKEN_DMA |
+               SDHCI_QUIRK_BROKEN_ADMA,
+       .ops = &sdhci_iproc_ops,
+};
+
+#define BCM7211A0_BASE_CLK_MHZ 100
+static const struct sdhci_iproc_data bcm7211a0_data = {
+       .pdata = &sdhci_bcm7211a0_pltfm_data,
+       .caps = ((BCM7211A0_BASE_CLK_MHZ / 2) << SDHCI_TIMEOUT_CLK_SHIFT) |
+               (BCM7211A0_BASE_CLK_MHZ << SDHCI_CLOCK_BASE_SHIFT) |
+               ((0x2 << SDHCI_MAX_BLOCK_SHIFT)
+                       & SDHCI_MAX_BLOCK_MASK) |
+               SDHCI_CAN_VDD_330 |
+               SDHCI_CAN_VDD_180 |
+               SDHCI_CAN_DO_SUSPEND |
+               SDHCI_CAN_DO_HISPD,
+       .caps1 = SDHCI_DRIVER_TYPE_C |
+                SDHCI_DRIVER_TYPE_D,
+};
+
 static const struct of_device_id sdhci_iproc_of_match[] = {
        { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
        { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2711_data },
        { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
        { .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
+       { .compatible = "brcm,bcm7211a0-sdhci", .data = &bcm7211a0_data },
        { }
 };
 MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
@@ -384,6 +408,11 @@ err:
        return ret;
 }
 
+static void sdhci_iproc_shutdown(struct platform_device *pdev)
+{
+       sdhci_pltfm_suspend(&pdev->dev);
+}
+
 static struct platform_driver sdhci_iproc_driver = {
        .driver = {
                .name = "sdhci-iproc",
@@ -394,6 +423,7 @@ static struct platform_driver sdhci_iproc_driver = {
        },
        .probe = sdhci_iproc_probe,
        .remove = sdhci_pltfm_unregister,
+       .shutdown = sdhci_iproc_shutdown,
 };
 module_platform_driver(sdhci_iproc_driver);
 
index d001c51..6e4e132 100644 (file)
 #define   ASPEED_SDC_S0_PHASE_OUT_EN   GENMASK(1, 0)
 #define   ASPEED_SDC_PHASE_MAX         31
 
+/* SDIO{10,20} */
+#define ASPEED_SDC_CAP1_1_8V           (0 * 32 + 26)
+/* SDIO{14,24} */
+#define ASPEED_SDC_CAP2_SDR104         (1 * 32 + 1)
+
 struct aspeed_sdc {
        struct clk *clk;
        struct resource *res;
@@ -72,6 +77,37 @@ struct aspeed_sdhci {
        const struct aspeed_sdhci_phase_desc *phase_desc;
 };
 
+/*
+ * The function sets the mirror register for updating
+ * capbilities of the current slot.
+ *
+ *   slot | capability  | caps_reg | mirror_reg
+ *   -----|-------------|----------|------------
+ *     0  | CAP1_1_8V   | SDIO140  |   SDIO10
+ *     0  | CAP2_SDR104 | SDIO144  |   SDIO14
+ *     1  | CAP1_1_8V   | SDIO240  |   SDIO20
+ *     1  | CAP2_SDR104 | SDIO244  |   SDIO24
+ */
+static void aspeed_sdc_set_slot_capability(struct sdhci_host *host, struct aspeed_sdc *sdc,
+                                          int capability, bool enable, u8 slot)
+{
+       u32 mirror_reg_offset;
+       u32 cap_val;
+       u8 cap_reg;
+
+       if (slot > 1)
+               return;
+
+       cap_reg = capability / 32;
+       cap_val = sdhci_readl(host, 0x40 + (cap_reg * 4));
+       if (enable)
+               cap_val |= BIT(capability % 32);
+       else
+               cap_val &= ~BIT(capability % 32);
+       mirror_reg_offset = ((slot + 1) * 0x10) + (cap_reg * 4);
+       writel(cap_val, sdc->regs + mirror_reg_offset);
+}
+
 static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc,
                                           struct aspeed_sdhci *sdhci,
                                           bool bus8)
@@ -150,7 +186,7 @@ static int aspeed_sdhci_phase_to_tap(struct device *dev, unsigned long rate_hz,
 
        tap = div_u64(phase_period_ps, prop_delay_ps);
        if (tap > ASPEED_SDHCI_NR_TAPS) {
-               dev_warn(dev,
+               dev_dbg(dev,
                         "Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n",
                         tap, phase_deg, rate_hz, ASPEED_SDHCI_NR_TAPS);
                tap = ASPEED_SDHCI_NR_TAPS;
@@ -328,6 +364,7 @@ static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
 static int aspeed_sdhci_probe(struct platform_device *pdev)
 {
        const struct aspeed_sdhci_pdata *aspeed_pdata;
+       struct device_node *np = pdev->dev.of_node;
        struct sdhci_pltfm_host *pltfm_host;
        struct aspeed_sdhci *dev;
        struct sdhci_host *host;
@@ -372,6 +409,17 @@ static int aspeed_sdhci_probe(struct platform_device *pdev)
 
        sdhci_get_of_property(pdev);
 
+       if (of_property_read_bool(np, "mmc-hs200-1_8v") ||
+           of_property_read_bool(np, "sd-uhs-sdr104")) {
+               aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V,
+                                              true, slot);
+       }
+
+       if (of_property_read_bool(np, "sd-uhs-sdr104")) {
+               aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104,
+                                              true, slot);
+       }
+
        pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pltfm_host->clk))
                return PTR_ERR(pltfm_host->clk);
index 7893fd3..8f4d1f0 100644 (file)
@@ -1173,10 +1173,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
         * as part of pm_runtime_get_sync.
         */
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret) {
                dev_err(dev, "pm_runtime_get_sync failed\n");
-               pm_runtime_put_noidle(dev);
                goto err_rpm_disable;
        }
 
index 061618a..4fd99c1 100644 (file)
@@ -94,7 +94,7 @@
 
 #define PCIE_GLI_9763E_CFG2      0x8A4
 #define   GLI_9763E_CFG2_L1DLY     GENMASK(28, 19)
-#define   GLI_9763E_CFG2_L1DLY_MID 0x50
+#define   GLI_9763E_CFG2_L1DLY_MID 0x54
 
 #define PCIE_GLI_9763E_MMC_CTRL  0x960
 #define   GLI_9763E_HS400_SLOW     BIT(3)
@@ -847,7 +847,7 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
 
        pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, &value);
        value &= ~GLI_9763E_CFG2_L1DLY;
-       /* set ASPM L1 entry delay to 20us */
+       /* set ASPM L1 entry delay to 21us */
        value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID);
        pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value);
 
index 5dc36ef..11e3755 100644 (file)
@@ -393,6 +393,7 @@ static void sdhci_sprd_request_done(struct sdhci_host *host,
 static struct sdhci_ops sdhci_sprd_ops = {
        .read_l = sdhci_sprd_readl,
        .write_l = sdhci_sprd_writel,
+       .write_w = sdhci_sprd_writew,
        .write_b = sdhci_sprd_writeb,
        .set_clock = sdhci_sprd_set_clock,
        .get_max_clock = sdhci_sprd_get_max_clock,
index bf238ad..6aaf5c3 100644 (file)
@@ -2680,7 +2680,7 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
 
        sdhci_end_tuning(host);
 
-       mmc_abort_tuning(host->mmc, opcode);
+       mmc_send_abort_tuning(host->mmc, opcode);
 }
 EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
 
index 0770c03..c35ed4b 100644 (file)
 
 #define SDHCI_CAPABILITIES     0x40
 #define  SDHCI_TIMEOUT_CLK_MASK                GENMASK(5, 0)
+#define  SDHCI_TIMEOUT_CLK_SHIFT 0
 #define  SDHCI_TIMEOUT_CLK_UNIT        0x00000080
 #define  SDHCI_CLOCK_BASE_MASK         GENMASK(13, 8)
+#define  SDHCI_CLOCK_BASE_SHIFT        8
 #define  SDHCI_CLOCK_V3_BASE_MASK      GENMASK(15, 8)
 #define  SDHCI_MAX_BLOCK_MASK  0x00030000
 #define  SDHCI_MAX_BLOCK_SHIFT  16
index 1fad6e4..f654afb 100644 (file)
@@ -809,11 +809,9 @@ static int sdhci_am654_probe(struct platform_device *pdev)
 
        /* Clocks are enabled using pm_runtime */
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(dev);
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret)
                goto pm_runtime_disable;
-       }
 
        base = devm_platform_ioremap_resource(pdev, 1);
        if (IS_ERR(base)) {
index 615f3d0..b9b79b1 100644 (file)
@@ -1801,6 +1801,7 @@ static int usdhi6_probe(struct platform_device *pdev)
 
        version = usdhi6_read(host, USDHI6_VERSION);
        if ((version & 0xfff) != 0xa0d) {
+               ret = -EPERM;
                dev_err(dev, "Version not recognized %x\n", version);
                goto e_clk_off;
        }
index a1d0985..c32df55 100644 (file)
@@ -857,6 +857,9 @@ static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask)
 {
        BUG_ON(intmask == 0);
 
+       if (!host->data)
+               return;
+
        if (intmask & VIA_CRDR_SDSTS_DT)
                host->data->error = -ETIMEDOUT;
        else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC))
index 739cf63..4950d10 100644 (file)
@@ -2279,7 +2279,7 @@ static int vub300_probe(struct usb_interface *interface,
        if (retval < 0)
                goto error5;
        retval =
-               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
                                SET_ROM_WAIT_STATES,
                                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
index a3ae877..e13d42c 100644 (file)
@@ -423,13 +423,13 @@ static void mtdpstore_notify_add(struct mtd_info *mtd)
        longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize));
        cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);
 
-       cxt->dev.total_size = mtd->size;
        /* just support dmesg right now */
        cxt->dev.flags = PSTORE_FLAGS_DMESG;
-       cxt->dev.read = mtdpstore_read;
-       cxt->dev.write = mtdpstore_write;
-       cxt->dev.erase = mtdpstore_erase;
-       cxt->dev.panic_write = mtdpstore_panic_write;
+       cxt->dev.zone.read = mtdpstore_read;
+       cxt->dev.zone.write = mtdpstore_write;
+       cxt->dev.zone.erase = mtdpstore_erase;
+       cxt->dev.zone.panic_write = mtdpstore_panic_write;
+       cxt->dev.zone.total_size = mtd->size;
 
        ret = register_pstore_device(&cxt->dev);
        if (ret) {
index 17f63f9..3131fae 100644 (file)
@@ -473,20 +473,26 @@ static int spinand_erase_op(struct spinand_device *spinand,
        return spi_mem_exec_op(spinand->spimem, &op);
 }
 
-static int spinand_wait(struct spinand_device *spinand, u8 *s)
+static int spinand_wait(struct spinand_device *spinand,
+                       unsigned long initial_delay_us,
+                       unsigned long poll_delay_us,
+                       u8 *s)
 {
-       unsigned long timeo =  jiffies + msecs_to_jiffies(400);
+       struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS,
+                                                     spinand->scratchbuf);
        u8 status;
        int ret;
 
-       do {
-               ret = spinand_read_status(spinand, &status);
-               if (ret)
-                       return ret;
+       ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0,
+                                 initial_delay_us,
+                                 poll_delay_us,
+                                 SPINAND_WAITRDY_TIMEOUT_MS);
+       if (ret)
+               return ret;
 
-               if (!(status & STATUS_BUSY))
-                       goto out;
-       } while (time_before(jiffies, timeo));
+       status = *spinand->scratchbuf;
+       if (!(status & STATUS_BUSY))
+               goto out;
 
        /*
         * Extra read, just in case the STATUS_READY bit has changed
@@ -526,7 +532,10 @@ static int spinand_reset_op(struct spinand_device *spinand)
        if (ret)
                return ret;
 
-       return spinand_wait(spinand, NULL);
+       return spinand_wait(spinand,
+                           SPINAND_RESET_INITIAL_DELAY_US,
+                           SPINAND_RESET_POLL_DELAY_US,
+                           NULL);
 }
 
 static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
@@ -549,7 +558,10 @@ static int spinand_read_page(struct spinand_device *spinand,
        if (ret)
                return ret;
 
-       ret = spinand_wait(spinand, &status);
+       ret = spinand_wait(spinand,
+                          SPINAND_READ_INITIAL_DELAY_US,
+                          SPINAND_READ_POLL_DELAY_US,
+                          &status);
        if (ret < 0)
                return ret;
 
@@ -585,7 +597,10 @@ static int spinand_write_page(struct spinand_device *spinand,
        if (ret)
                return ret;
 
-       ret = spinand_wait(spinand, &status);
+       ret = spinand_wait(spinand,
+                          SPINAND_WRITE_INITIAL_DELAY_US,
+                          SPINAND_WRITE_POLL_DELAY_US,
+                          &status);
        if (!ret && (status & STATUS_PROG_FAILED))
                return -EIO;
 
@@ -768,7 +783,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
        if (ret)
                return ret;
 
-       ret = spinand_wait(spinand, &status);
+       ret = spinand_wait(spinand,
+                          SPINAND_ERASE_INITIAL_DELAY_US,
+                          SPINAND_ERASE_POLL_DELAY_US,
+                          &status);
+
        if (!ret && (status & STATUS_ERASE_FAILED))
                ret = -EIO;
 
index d174823..4ffbfd5 100644 (file)
@@ -350,6 +350,7 @@ static int ldisc_open(struct tty_struct *tty)
        rtnl_lock();
        result = register_netdevice(dev);
        if (result) {
+               tty_kref_put(tty);
                rtnl_unlock();
                free_netdev(dev);
                return -ENODEV;
index 029e77d..a45865b 100644 (file)
@@ -82,6 +82,8 @@ struct mcba_priv {
        bool can_ka_first_pass;
        bool can_speed_check;
        atomic_t free_ctx_cnt;
+       void *rxbuf[MCBA_MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
 };
 
 /* CAN frame */
@@ -633,6 +635,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
        for (i = 0; i < MCBA_MAX_RX_URBS; i++) {
                struct urb *urb = NULL;
                u8 *buf;
+               dma_addr_t buf_dma;
 
                /* create a URB, and a buffer for it */
                urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -642,7 +645,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
                }
 
                buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
-                                        GFP_KERNEL, &urb->transfer_dma);
+                                        GFP_KERNEL, &buf_dma);
                if (!buf) {
                        netdev_err(netdev, "No memory left for USB buffer\n");
                        usb_free_urb(urb);
@@ -661,11 +664,14 @@ static int mcba_usb_start(struct mcba_priv *priv)
                if (err) {
                        usb_unanchor_urb(urb);
                        usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
-                                         buf, urb->transfer_dma);
+                                         buf, buf_dma);
                        usb_free_urb(urb);
                        break;
                }
 
+               priv->rxbuf[i] = buf;
+               priv->rxbuf_dma[i] = buf_dma;
+
                /* Drop reference, USB core will take care of freeing it */
                usb_free_urb(urb);
        }
@@ -708,7 +714,14 @@ static int mcba_usb_open(struct net_device *netdev)
 
 static void mcba_urb_unlink(struct mcba_priv *priv)
 {
+       int i;
+
        usb_kill_anchored_urbs(&priv->rx_submitted);
+
+       for (i = 0; i < MCBA_MAX_RX_URBS; ++i)
+               usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
+                                 priv->rxbuf[i], priv->rxbuf_dma[i]);
+
        usb_kill_anchored_urbs(&priv->tx_submitted);
 }
 
index 881f887..5257148 100644 (file)
@@ -236,36 +236,48 @@ static int ena_xdp_io_poll(struct napi_struct *napi, int budget)
 static int ena_xdp_tx_map_frame(struct ena_ring *xdp_ring,
                                struct ena_tx_buffer *tx_info,
                                struct xdp_frame *xdpf,
-                               void **push_hdr,
-                               u32 *push_len)
+                               struct ena_com_tx_ctx *ena_tx_ctx)
 {
        struct ena_adapter *adapter = xdp_ring->adapter;
        struct ena_com_buf *ena_buf;
-       dma_addr_t dma = 0;
+       int push_len = 0;
+       dma_addr_t dma;
+       void *data;
        u32 size;
 
        tx_info->xdpf = xdpf;
+       data = tx_info->xdpf->data;
        size = tx_info->xdpf->len;
-       ena_buf = tx_info->bufs;
 
-       /* llq push buffer */
-       *push_len = min_t(u32, size, xdp_ring->tx_max_header_size);
-       *push_hdr = tx_info->xdpf->data;
+       if (xdp_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+               /* Designate part of the packet for LLQ */
+               push_len = min_t(u32, size, xdp_ring->tx_max_header_size);
+
+               ena_tx_ctx->push_header = data;
+
+               size -= push_len;
+               data += push_len;
+       }
+
+       ena_tx_ctx->header_len = push_len;
 
-       if (size - *push_len > 0) {
+       if (size > 0) {
                dma = dma_map_single(xdp_ring->dev,
-                                    *push_hdr + *push_len,
-                                    size - *push_len,
+                                    data,
+                                    size,
                                     DMA_TO_DEVICE);
                if (unlikely(dma_mapping_error(xdp_ring->dev, dma)))
                        goto error_report_dma_error;
 
-               tx_info->map_linear_data = 1;
-               tx_info->num_of_bufs = 1;
-       }
+               tx_info->map_linear_data = 0;
 
-       ena_buf->paddr = dma;
-       ena_buf->len = size;
+               ena_buf = tx_info->bufs;
+               ena_buf->paddr = dma;
+               ena_buf->len = size;
+
+               ena_tx_ctx->ena_bufs = ena_buf;
+               ena_tx_ctx->num_bufs = tx_info->num_of_bufs = 1;
+       }
 
        return 0;
 
@@ -274,10 +286,6 @@ error_report_dma_error:
                          &xdp_ring->syncp);
        netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map xdp buff\n");
 
-       xdp_return_frame_rx_napi(tx_info->xdpf);
-       tx_info->xdpf = NULL;
-       tx_info->num_of_bufs = 0;
-
        return -EINVAL;
 }
 
@@ -289,8 +297,6 @@ static int ena_xdp_xmit_frame(struct ena_ring *xdp_ring,
        struct ena_com_tx_ctx ena_tx_ctx = {};
        struct ena_tx_buffer *tx_info;
        u16 next_to_use, req_id;
-       void *push_hdr;
-       u32 push_len;
        int rc;
 
        next_to_use = xdp_ring->next_to_use;
@@ -298,15 +304,11 @@ static int ena_xdp_xmit_frame(struct ena_ring *xdp_ring,
        tx_info = &xdp_ring->tx_buffer_info[req_id];
        tx_info->num_of_bufs = 0;
 
-       rc = ena_xdp_tx_map_frame(xdp_ring, tx_info, xdpf, &push_hdr, &push_len);
+       rc = ena_xdp_tx_map_frame(xdp_ring, tx_info, xdpf, &ena_tx_ctx);
        if (unlikely(rc))
                return rc;
 
-       ena_tx_ctx.ena_bufs = tx_info->bufs;
-       ena_tx_ctx.push_header = push_hdr;
-       ena_tx_ctx.num_bufs = tx_info->num_of_bufs;
        ena_tx_ctx.req_id = req_id;
-       ena_tx_ctx.header_len = push_len;
 
        rc = ena_xmit_common(dev,
                             xdp_ring,
index b3d7433..7748b27 100644 (file)
@@ -1849,6 +1849,7 @@ out_free_netdev:
        free_netdev(netdev);
 out_pci_release:
        pci_release_mem_regions(pdev);
+       pci_disable_pcie_error_reporting(pdev);
 out_pci_disable:
        pci_disable_device(pdev);
        return err;
index fcc729d..598e5e6 100644 (file)
@@ -2184,6 +2184,7 @@ static int bnxt_hwrm_handler(struct bnxt *bp, struct tx_cmp *txcmp)
        case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
                bnxt_async_event_process(bp,
                                         (struct hwrm_async_event_cmpl *)txcmp);
+               break;
 
        default:
                break;
@@ -7308,7 +7309,7 @@ skip_rdma:
        entries_sp = ctx->vnic_max_vnic_entries + ctx->qp_max_l2_entries +
                     2 * (extra_qps + ctx->qp_min_qp1_entries) + min;
        entries_sp = roundup(entries_sp, ctx->tqm_entries_multiple);
-       entries = ctx->qp_max_l2_entries + extra_qps + ctx->qp_min_qp1_entries;
+       entries = ctx->qp_max_l2_entries + 2 * (extra_qps + ctx->qp_min_qp1_entries);
        entries = roundup(entries, ctx->tqm_entries_multiple);
        entries = clamp_t(u32, entries, min, ctx->tqm_max_entries_per_ring);
        for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) {
@@ -11750,6 +11751,8 @@ static void bnxt_fw_init_one_p3(struct bnxt *bp)
        bnxt_hwrm_coal_params_qcaps(bp);
 }
 
+static int bnxt_probe_phy(struct bnxt *bp, bool fw_dflt);
+
 static int bnxt_fw_init_one(struct bnxt *bp)
 {
        int rc;
@@ -11764,6 +11767,9 @@ static int bnxt_fw_init_one(struct bnxt *bp)
                netdev_err(bp->dev, "Firmware init phase 2 failed\n");
                return rc;
        }
+       rc = bnxt_probe_phy(bp, false);
+       if (rc)
+               return rc;
        rc = bnxt_approve_mac(bp, bp->dev->dev_addr, false);
        if (rc)
                return rc;
@@ -13155,6 +13161,7 @@ init_err_pci_clean:
        bnxt_hwrm_func_drv_unrgtr(bp);
        bnxt_free_hwrm_short_cmd_req(bp);
        bnxt_free_hwrm_resources(bp);
+       bnxt_ethtool_free(bp);
        kfree(bp->fw_health);
        bp->fw_health = NULL;
        bnxt_cleanup_pci(bp);
index 61ea3ec..83ed10a 100644 (file)
@@ -1337,13 +1337,27 @@ static int cxgb4_ethtool_flash_phy(struct net_device *netdev,
                return ret;
        }
 
-       spin_lock_bh(&adap->win0_lock);
+       /* We have to RESET the chip/firmware because we need the
+        * chip in uninitialized state for loading new PHY image.
+        * Otherwise, the running firmware will only store the PHY
+        * image in local RAM which will be lost after next reset.
+        */
+       ret = t4_fw_reset(adap, adap->mbox, PIORSTMODE_F | PIORST_F);
+       if (ret < 0) {
+               dev_err(adap->pdev_dev,
+                       "Set FW to RESET for flashing PHY FW failed. ret: %d\n",
+                       ret);
+               return ret;
+       }
+
        ret = t4_load_phy_fw(adap, MEMWIN_NIC, NULL, data, size);
-       spin_unlock_bh(&adap->win0_lock);
-       if (ret)
-               dev_err(adap->pdev_dev, "Failed to load PHY FW\n");
+       if (ret < 0) {
+               dev_err(adap->pdev_dev, "Failed to load PHY FW. ret: %d\n",
+                       ret);
+               return ret;
+       }
 
-       return ret;
+       return 0;
 }
 
 static int cxgb4_ethtool_flash_fw(struct net_device *netdev,
@@ -1610,16 +1624,14 @@ static struct filter_entry *cxgb4_get_filter_entry(struct adapter *adap,
                                                   u32 ftid)
 {
        struct tid_info *t = &adap->tids;
-       struct filter_entry *f;
 
-       if (ftid < t->nhpftids)
-               f = &adap->tids.hpftid_tab[ftid];
-       else if (ftid < t->nftids)
-               f = &adap->tids.ftid_tab[ftid - t->nhpftids];
-       else
-               f = lookup_tid(&adap->tids, ftid);
+       if (ftid >= t->hpftid_base && ftid < t->hpftid_base + t->nhpftids)
+               return &t->hpftid_tab[ftid - t->hpftid_base];
 
-       return f;
+       if (ftid >= t->ftid_base && ftid < t->ftid_base + t->nftids)
+               return &t->ftid_tab[ftid - t->ftid_base];
+
+       return lookup_tid(t, ftid);
 }
 
 static void cxgb4_fill_filter_rule(struct ethtool_rx_flow_spec *fs,
@@ -1826,6 +1838,11 @@ static int cxgb4_ntuple_del_filter(struct net_device *dev,
        filter_id = filter_info->loc_array[cmd->fs.location];
        f = cxgb4_get_filter_entry(adapter, filter_id);
 
+       if (f->fs.prio)
+               filter_id -= adapter->tids.hpftid_base;
+       else if (!f->fs.hash)
+               filter_id -= (adapter->tids.ftid_base - adapter->tids.nhpftids);
+
        ret = cxgb4_flow_rule_destroy(dev, f->fs.tc_prio, &f->fs, filter_id);
        if (ret)
                goto err;
@@ -1885,6 +1902,11 @@ static int cxgb4_ntuple_set_filter(struct net_device *netdev,
 
        filter_info = &adapter->ethtool_filters->port[pi->port_id];
 
+       if (fs.prio)
+               tid += adapter->tids.hpftid_base;
+       else if (!fs.hash)
+               tid += (adapter->tids.ftid_base - adapter->tids.nhpftids);
+
        filter_info->loc_array[cmd->fs.location] = tid;
        set_bit(cmd->fs.location, filter_info->bmap);
        filter_info->in_use++;
index 22c9ac9..6260b3b 100644 (file)
@@ -198,7 +198,7 @@ static void set_nat_params(struct adapter *adap, struct filter_entry *f,
                                      WORD_MASK, f->fs.nat_lip[3] |
                                      f->fs.nat_lip[2] << 8 |
                                      f->fs.nat_lip[1] << 16 |
-                                     (u64)f->fs.nat_lip[0] << 25, 1);
+                                     (u64)f->fs.nat_lip[0] << 24, 1);
                }
        }
 
index 1f601de..762113a 100644 (file)
@@ -4424,10 +4424,8 @@ static int adap_init0_phy(struct adapter *adap)
 
        /* Load PHY Firmware onto adapter.
         */
-       spin_lock_bh(&adap->win0_lock);
        ret = t4_load_phy_fw(adap, MEMWIN_NIC, phy_info->phy_fw_version,
                             (u8 *)phyf->data, phyf->size);
-       spin_unlock_bh(&adap->win0_lock);
        if (ret < 0)
                dev_err(adap->pdev_dev, "PHY Firmware transfer error %d\n",
                        -ret);
index 9428ef1..a0555f4 100644 (file)
@@ -3060,16 +3060,19 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr,
  *     @addr: the start address to write
  *     @n: length of data to write in bytes
  *     @data: the data to write
+ *     @byte_oriented: whether to store data as bytes or as words
  *
  *     Writes up to a page of data (256 bytes) to the serial flash starting
  *     at the given address.  All the data must be written to the same page.
+ *     If @byte_oriented is set the write data is stored as byte stream
+ *     (i.e. matches what on disk), otherwise in big-endian.
  */
 static int t4_write_flash(struct adapter *adapter, unsigned int addr,
-                         unsigned int n, const u8 *data)
+                         unsigned int n, const u8 *data, bool byte_oriented)
 {
-       int ret;
-       u32 buf[64];
        unsigned int i, c, left, val, offset = addr & 0xff;
+       u32 buf[64];
+       int ret;
 
        if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
                return -EINVAL;
@@ -3080,10 +3083,14 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
            (ret = sf1_write(adapter, 4, 1, 1, val)) != 0)
                goto unlock;
 
-       for (left = n; left; left -= c) {
+       for (left = n; left; left -= c, data += c) {
                c = min(left, 4U);
-               for (val = 0, i = 0; i < c; ++i)
-                       val = (val << 8) + *data++;
+               for (val = 0, i = 0; i < c; ++i) {
+                       if (byte_oriented)
+                               val = (val << 8) + data[i];
+                       else
+                               val = (val << 8) + data[c - i - 1];
+               }
 
                ret = sf1_write(adapter, c, c != left, 1, val);
                if (ret)
@@ -3096,7 +3103,8 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
        t4_write_reg(adapter, SF_OP_A, 0);    /* unlock SF */
 
        /* Read the page to verify the write succeeded */
-       ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+       ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
+                           byte_oriented);
        if (ret)
                return ret;
 
@@ -3692,7 +3700,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
         */
        memcpy(first_page, fw_data, SF_PAGE_SIZE);
        ((struct fw_hdr *)first_page)->fw_ver = cpu_to_be32(0xffffffff);
-       ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page);
+       ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, true);
        if (ret)
                goto out;
 
@@ -3700,14 +3708,14 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
        for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
                addr += SF_PAGE_SIZE;
                fw_data += SF_PAGE_SIZE;
-               ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data);
+               ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, true);
                if (ret)
                        goto out;
        }
 
-       ret = t4_write_flash(adap,
-                            fw_start + offsetof(struct fw_hdr, fw_ver),
-                            sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver);
+       ret = t4_write_flash(adap, fw_start + offsetof(struct fw_hdr, fw_ver),
+                            sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver,
+                            true);
 out:
        if (ret)
                dev_err(adap->pdev_dev, "firmware download failed, error %d\n",
@@ -3812,9 +3820,11 @@ int t4_load_phy_fw(struct adapter *adap, int win,
        /* Copy the supplied PHY Firmware image to the adapter memory location
         * allocated by the adapter firmware.
         */
+       spin_lock_bh(&adap->win0_lock);
        ret = t4_memory_rw(adap, win, mtype, maddr,
                           phy_fw_size, (__be32 *)phy_fw_data,
                           T4_MEMORY_WRITE);
+       spin_unlock_bh(&adap->win0_lock);
        if (ret)
                return ret;
 
@@ -10208,7 +10218,7 @@ int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
                        n = size - i;
                else
                        n = SF_PAGE_SIZE;
-               ret = t4_write_flash(adap, addr, n, cfg_data);
+               ret = t4_write_flash(adap, addr, n, cfg_data, true);
                if (ret)
                        goto out;
 
@@ -10677,13 +10687,14 @@ int t4_load_boot(struct adapter *adap, u8 *boot_data,
        for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
                addr += SF_PAGE_SIZE;
                boot_data += SF_PAGE_SIZE;
-               ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data);
+               ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data,
+                                    false);
                if (ret)
                        goto out;
        }
 
        ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE,
-                            (const u8 *)header);
+                            (const u8 *)header, false);
 
 out:
        if (ret)
@@ -10758,7 +10769,7 @@ int t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
        for (i = 0; i < size; i += SF_PAGE_SIZE) {
                n = min_t(u32, size - i, SF_PAGE_SIZE);
 
-               ret = t4_write_flash(adap, addr, n, cfg_data);
+               ret = t4_write_flash(adap, addr, n, cfg_data, false);
                if (ret)
                        goto out;
 
@@ -10770,7 +10781,8 @@ int t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
        for (i = 0; i < npad; i++) {
                u8 data = 0;
 
-               ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data);
+               ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data,
+                                    false);
                if (ret)
                        goto out;
        }
index 46b0dba..7c99217 100644 (file)
@@ -576,10 +576,12 @@ static void ec_bhf_remove(struct pci_dev *dev)
        struct ec_bhf_priv *priv = netdev_priv(net_dev);
 
        unregister_netdev(net_dev);
-       free_netdev(net_dev);
 
        pci_iounmap(dev, priv->dma_io);
        pci_iounmap(dev, priv->io);
+
+       free_netdev(net_dev);
+
        pci_release_regions(dev);
        pci_clear_master(dev);
        pci_disable_device(dev);
index b6eba29..7968568 100644 (file)
@@ -5897,6 +5897,7 @@ drv_cleanup:
 unmap_bars:
        be_unmap_pci_bars(adapter);
 free_netdev:
+       pci_disable_pcie_error_reporting(pdev);
        free_netdev(netdev);
 rel_reg:
        pci_release_regions(pdev);
index 1753807..d71eac7 100644 (file)
@@ -215,15 +215,13 @@ static u64 fec_ptp_read(const struct cyclecounter *cc)
 {
        struct fec_enet_private *fep =
                container_of(cc, struct fec_enet_private, cc);
-       const struct platform_device_id *id_entry =
-               platform_get_device_id(fep->pdev);
        u32 tempval;
 
        tempval = readl(fep->hwp + FEC_ATIME_CTRL);
        tempval |= FEC_T_CTRL_CAPTURE;
        writel(tempval, fep->hwp + FEC_ATIME_CTRL);
 
-       if (id_entry->driver_data & FEC_QUIRK_BUG_CAPTURE)
+       if (fep->quirks & FEC_QUIRK_BUG_CAPTURE)
                udelay(1);
 
        return readl(fep->hwp + FEC_ATIME);
@@ -604,6 +602,10 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
        fep->ptp_caps.enable = fec_ptp_enable;
 
        fep->cycle_speed = clk_get_rate(fep->clk_ptp);
+       if (!fep->cycle_speed) {
+               fep->cycle_speed = NSEC_PER_SEC;
+               dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n");
+       }
        fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
 
        spin_lock_init(&fep->tmreg_lock);
index d70ee57..27f9dac 100644 (file)
@@ -1717,12 +1717,13 @@ setup_rings:
  * ice_vsi_cfg_txqs - Configure the VSI for Tx
  * @vsi: the VSI being configured
  * @rings: Tx ring array to be configured
+ * @count: number of Tx ring array elements
  *
  * Return 0 on success and a negative value on error
  * Configure the Tx VSI for operation.
  */
 static int
-ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings)
+ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, u16 count)
 {
        struct ice_aqc_add_tx_qgrp *qg_buf;
        u16 q_idx = 0;
@@ -1734,7 +1735,7 @@ ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings)
 
        qg_buf->num_txqs = 1;
 
-       for (q_idx = 0; q_idx < vsi->num_txq; q_idx++) {
+       for (q_idx = 0; q_idx < count; q_idx++) {
                err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf);
                if (err)
                        goto err_cfg_txqs;
@@ -1754,7 +1755,7 @@ err_cfg_txqs:
  */
 int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi)
 {
-       return ice_vsi_cfg_txqs(vsi, vsi->tx_rings);
+       return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, vsi->num_txq);
 }
 
 /**
@@ -1769,7 +1770,7 @@ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi)
        int ret;
        int i;
 
-       ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings);
+       ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings, vsi->num_xdp_txq);
        if (ret)
                return ret;
 
@@ -2009,17 +2010,18 @@ int ice_vsi_stop_all_rx_rings(struct ice_vsi *vsi)
  * @rst_src: reset source
  * @rel_vmvf_num: Relative ID of VF/VM
  * @rings: Tx ring array to be stopped
+ * @count: number of Tx ring array elements
  */
 static int
 ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
-                     u16 rel_vmvf_num, struct ice_ring **rings)
+                     u16 rel_vmvf_num, struct ice_ring **rings, u16 count)
 {
        u16 q_idx;
 
        if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS)
                return -EINVAL;
 
-       for (q_idx = 0; q_idx < vsi->num_txq; q_idx++) {
+       for (q_idx = 0; q_idx < count; q_idx++) {
                struct ice_txq_meta txq_meta = { };
                int status;
 
@@ -2047,7 +2049,7 @@ int
 ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
                          u16 rel_vmvf_num)
 {
-       return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings);
+       return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings, vsi->num_txq);
 }
 
 /**
@@ -2056,7 +2058,7 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
  */
 int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi)
 {
-       return ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0, vsi->xdp_rings);
+       return ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0, vsi->xdp_rings, vsi->num_xdp_txq);
 }
 
 /**
index 4ee85a2..0eb2307 100644 (file)
@@ -2556,6 +2556,20 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
 }
 
 /**
+ * ice_xdp_safe_mode - XDP handler for safe mode
+ * @dev: netdevice
+ * @xdp: XDP command
+ */
+static int ice_xdp_safe_mode(struct net_device __always_unused *dev,
+                            struct netdev_bpf *xdp)
+{
+       NL_SET_ERR_MSG_MOD(xdp->extack,
+                          "Please provide working DDP firmware package in order to use XDP\n"
+                          "Refer to Documentation/networking/device_drivers/ethernet/intel/ice.rst");
+       return -EOPNOTSUPP;
+}
+
+/**
  * ice_xdp - implements XDP handler
  * @dev: netdevice
  * @xdp: XDP command
@@ -6937,6 +6951,7 @@ static const struct net_device_ops ice_netdev_safe_mode_ops = {
        .ndo_change_mtu = ice_change_mtu,
        .ndo_get_stats64 = ice_get_stats64,
        .ndo_tx_timeout = ice_tx_timeout,
+       .ndo_bpf = ice_xdp_safe_mode,
 };
 
 static const struct net_device_ops ice_netdev_ops = {
index 36dc3e5..21ef2f1 100644 (file)
@@ -154,6 +154,7 @@ static int xrx200_close(struct net_device *net_dev)
 
 static int xrx200_alloc_skb(struct xrx200_chan *ch)
 {
+       struct sk_buff *skb = ch->skb[ch->dma.desc];
        dma_addr_t mapping;
        int ret = 0;
 
@@ -168,6 +169,7 @@ static int xrx200_alloc_skb(struct xrx200_chan *ch)
                                 XRX200_DMA_DATA_LEN, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(ch->priv->dev, mapping))) {
                dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+               ch->skb[ch->dma.desc] = skb;
                ret = -ENOMEM;
                goto skip;
        }
@@ -198,7 +200,6 @@ static int xrx200_hw_receive(struct xrx200_chan *ch)
        ch->dma.desc %= LTQ_DESC_NUM;
 
        if (ret) {
-               ch->skb[ch->dma.desc] = skb;
                net_dev->stats.rx_dropped++;
                netdev_err(net_dev, "failed to allocate new rx buffer\n");
                return ret;
@@ -352,8 +353,8 @@ static irqreturn_t xrx200_dma_irq(int irq, void *ptr)
        struct xrx200_chan *ch = ptr;
 
        if (napi_schedule_prep(&ch->napi)) {
-               __napi_schedule(&ch->napi);
                ltq_dma_disable_irq(&ch->dma);
+               __napi_schedule(&ch->napi);
        }
 
        ltq_dma_ack_irq(&ch->dma);
index a9166cd..ceebfc2 100644 (file)
@@ -303,6 +303,7 @@ int mlx5_attach_device(struct mlx5_core_dev *dev)
        int ret = 0, i;
 
        mutex_lock(&mlx5_intf_mutex);
+       priv->flags &= ~MLX5_PRIV_FLAGS_DETACH;
        for (i = 0; i < ARRAY_SIZE(mlx5_adev_devices); i++) {
                if (!priv->adev[i]) {
                        bool is_supported = false;
@@ -320,6 +321,16 @@ int mlx5_attach_device(struct mlx5_core_dev *dev)
                        }
                } else {
                        adev = &priv->adev[i]->adev;
+
+                       /* Pay attention that this is not PCI driver that
+                        * mlx5_core_dev is connected, but auxiliary driver.
+                        *
+                        * Here we can race of module unload with devlink
+                        * reload, but we don't need to take extra lock because
+                        * we are holding global mlx5_intf_mutex.
+                        */
+                       if (!adev->dev.driver)
+                               continue;
                        adrv = to_auxiliary_drv(adev->dev.driver);
 
                        if (adrv->resume)
@@ -350,6 +361,10 @@ void mlx5_detach_device(struct mlx5_core_dev *dev)
                        continue;
 
                adev = &priv->adev[i]->adev;
+               /* Auxiliary driver was unbind manually through sysfs */
+               if (!adev->dev.driver)
+                       goto skip_suspend;
+
                adrv = to_auxiliary_drv(adev->dev.driver);
 
                if (adrv->suspend) {
@@ -357,9 +372,11 @@ void mlx5_detach_device(struct mlx5_core_dev *dev)
                        continue;
                }
 
+skip_suspend:
                del_adev(&priv->adev[i]->adev);
                priv->adev[i] = NULL;
        }
+       priv->flags |= MLX5_PRIV_FLAGS_DETACH;
        mutex_unlock(&mlx5_intf_mutex);
 }
 
@@ -448,6 +465,8 @@ int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev)
        struct mlx5_priv *priv = &dev->priv;
 
        lockdep_assert_held(&mlx5_intf_mutex);
+       if (priv->flags & MLX5_PRIV_FLAGS_DETACH)
+               return 0;
 
        delete_drivers(dev);
        if (priv->flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
index 0dd7615..bc33eaa 100644 (file)
@@ -64,6 +64,8 @@ struct devlink_port *mlx5e_get_devlink_port(struct net_device *dev)
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct devlink_port *port;
 
+       if (!netif_device_present(dev))
+               return NULL;
        port = mlx5e_devlink_get_dl_port(priv);
        if (port->registered)
                return port;
index d907c1a..778e229 100644 (file)
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 // Copyright (c) 2020 Mellanox Technologies
 
-#include <linux/ptp_classify.h>
 #include "en/ptp.h"
 #include "en/txrx.h"
 #include "en/params.h"
index ab935cc..c96668b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "en.h"
 #include "en_stats.h"
+#include <linux/ptp_classify.h>
 
 struct mlx5e_ptpsq {
        struct mlx5e_txqsq       txqsq;
@@ -43,6 +44,27 @@ struct mlx5e_ptp {
        DECLARE_BITMAP(state, MLX5E_PTP_STATE_NUM_STATES);
 };
 
+static inline bool mlx5e_use_ptpsq(struct sk_buff *skb)
+{
+       struct flow_keys fk;
+
+       if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+               return false;
+
+       if (!skb_flow_dissect_flow_keys(skb, &fk, 0))
+               return false;
+
+       if (fk.basic.n_proto == htons(ETH_P_1588))
+               return true;
+
+       if (fk.basic.n_proto != htons(ETH_P_IP) &&
+           fk.basic.n_proto != htons(ETH_P_IPV6))
+               return false;
+
+       return (fk.basic.ip_proto == IPPROTO_UDP &&
+               fk.ports.dst == htons(PTP_EV_PORT));
+}
+
 int mlx5e_ptp_open(struct mlx5e_priv *priv, struct mlx5e_params *params,
                   u8 lag_port, struct mlx5e_ptp **cp);
 void mlx5e_ptp_close(struct mlx5e_ptp *c);
index be0ee03..2e9bee4 100644 (file)
@@ -129,10 +129,9 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
                                                             work);
        struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
        struct neighbour *n = update_work->n;
+       struct mlx5e_encap_entry *e = NULL;
        bool neigh_connected, same_dev;
-       struct mlx5e_encap_entry *e;
        unsigned char ha[ETH_ALEN];
-       struct mlx5e_priv *priv;
        u8 nud_state, dead;
 
        rtnl_lock();
@@ -156,14 +155,12 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
        if (!same_dev)
                goto out;
 
-       list_for_each_entry(e, &nhe->encap_list, encap_list) {
-               if (!mlx5e_encap_take(e))
-                       continue;
+       /* mlx5e_get_next_init_encap() releases previous encap before returning
+        * the next one.
+        */
+       while ((e = mlx5e_get_next_init_encap(nhe, e)) != NULL)
+               mlx5e_rep_update_flows(netdev_priv(e->out_dev), e, neigh_connected, ha);
 
-               priv = netdev_priv(e->out_dev);
-               mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
-               mlx5e_encap_put(priv, e);
-       }
 out:
        rtnl_unlock();
        mlx5e_release_neigh_update_work(update_work);
index 3113822..85eaadc 100644 (file)
@@ -94,13 +94,9 @@ void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
 
        ASSERT_RTNL();
 
-       /* wait for encap to be fully initialized */
-       wait_for_completion(&e->res_ready);
-
        mutex_lock(&esw->offloads.encap_tbl_lock);
        encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
-       if (e->compl_result < 0 || (encap_connected == neigh_connected &&
-                                   ether_addr_equal(e->h_dest, ha)))
+       if (encap_connected == neigh_connected && ether_addr_equal(e->h_dest, ha))
                goto unlock;
 
        mlx5e_take_all_encap_flows(e, &flow_list);
index f1fb116..490131e 100644 (file)
@@ -251,9 +251,12 @@ static void mlx5e_take_all_route_decap_flows(struct mlx5e_route_entry *r,
                mlx5e_take_tmp_flow(flow, flow_list, 0);
 }
 
+typedef bool (match_cb)(struct mlx5e_encap_entry *);
+
 static struct mlx5e_encap_entry *
-mlx5e_get_next_valid_encap(struct mlx5e_neigh_hash_entry *nhe,
-                          struct mlx5e_encap_entry *e)
+mlx5e_get_next_matching_encap(struct mlx5e_neigh_hash_entry *nhe,
+                             struct mlx5e_encap_entry *e,
+                             match_cb match)
 {
        struct mlx5e_encap_entry *next = NULL;
 
@@ -288,7 +291,7 @@ retry:
        /* wait for encap to be fully initialized */
        wait_for_completion(&next->res_ready);
        /* continue searching if encap entry is not in valid state after completion */
-       if (!(next->flags & MLX5_ENCAP_ENTRY_VALID)) {
+       if (!match(next)) {
                e = next;
                goto retry;
        }
@@ -296,6 +299,30 @@ retry:
        return next;
 }
 
+static bool mlx5e_encap_valid(struct mlx5e_encap_entry *e)
+{
+       return e->flags & MLX5_ENCAP_ENTRY_VALID;
+}
+
+static struct mlx5e_encap_entry *
+mlx5e_get_next_valid_encap(struct mlx5e_neigh_hash_entry *nhe,
+                          struct mlx5e_encap_entry *e)
+{
+       return mlx5e_get_next_matching_encap(nhe, e, mlx5e_encap_valid);
+}
+
+static bool mlx5e_encap_initialized(struct mlx5e_encap_entry *e)
+{
+       return e->compl_result >= 0;
+}
+
+struct mlx5e_encap_entry *
+mlx5e_get_next_init_encap(struct mlx5e_neigh_hash_entry *nhe,
+                         struct mlx5e_encap_entry *e)
+{
+       return mlx5e_get_next_matching_encap(nhe, e, mlx5e_encap_initialized);
+}
+
 void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
 {
        struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
index 3d45341..26f7fab 100644 (file)
@@ -532,9 +532,6 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv)
        struct mlx5_core_dev *mdev = priv->mdev;
        struct net_device *netdev = priv->netdev;
 
-       if (!priv->ipsec)
-               return;
-
        if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_CAP_ESP) ||
            !MLX5_CAP_ETH(mdev, swp)) {
                mlx5_core_dbg(mdev, "mlx5e: ESP and SWP offload not supported\n");
index 5cd466e..25403af 100644 (file)
@@ -356,7 +356,7 @@ err:
 
 int mlx5e_arfs_create_tables(struct mlx5e_priv *priv)
 {
-       int err = 0;
+       int err = -ENOMEM;
        int i;
 
        if (!(priv->netdev->hw_features & NETIF_F_NTUPLE))
index ec6bafe..d26b8ed 100644 (file)
@@ -2705,8 +2705,6 @@ static int mlx5e_update_netdev_queues(struct mlx5e_priv *priv)
        nch = priv->channels.params.num_channels;
        ntc = priv->channels.params.num_tc;
        num_rxqs = nch * priv->profile->rq_groups;
-       if (priv->channels.params.ptp_rx)
-               num_rxqs++;
 
        mlx5e_netdev_set_tcs(netdev, nch, ntc);
 
@@ -4824,22 +4822,15 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
        }
 
        if (mlx5_vxlan_allowed(mdev->vxlan) || mlx5_geneve_tx_allowed(mdev)) {
-               netdev->hw_features     |= NETIF_F_GSO_UDP_TUNNEL |
-                                          NETIF_F_GSO_UDP_TUNNEL_CSUM;
-               netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL |
-                                          NETIF_F_GSO_UDP_TUNNEL_CSUM;
-               netdev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
-               netdev->vlan_features |= NETIF_F_GSO_UDP_TUNNEL |
-                                        NETIF_F_GSO_UDP_TUNNEL_CSUM;
+               netdev->hw_features     |= NETIF_F_GSO_UDP_TUNNEL;
+               netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
+               netdev->vlan_features |= NETIF_F_GSO_UDP_TUNNEL;
        }
 
        if (mlx5e_tunnel_proto_supported_tx(mdev, IPPROTO_GRE)) {
-               netdev->hw_features     |= NETIF_F_GSO_GRE |
-                                          NETIF_F_GSO_GRE_CSUM;
-               netdev->hw_enc_features |= NETIF_F_GSO_GRE |
-                                          NETIF_F_GSO_GRE_CSUM;
-               netdev->gso_partial_features |= NETIF_F_GSO_GRE |
-                                               NETIF_F_GSO_GRE_CSUM;
+               netdev->hw_features     |= NETIF_F_GSO_GRE;
+               netdev->hw_enc_features |= NETIF_F_GSO_GRE;
+               netdev->gso_partial_features |= NETIF_F_GSO_GRE;
        }
 
        if (mlx5e_tunnel_proto_supported_tx(mdev, IPPROTO_IPIP)) {
index dd64878..d4b0f27 100644 (file)
@@ -4765,7 +4765,7 @@ static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
        list_for_each_entry_safe(hpe, tmp, &init_wait_list, dead_peer_wait_list) {
                wait_for_completion(&hpe->res_ready);
                if (!IS_ERR_OR_NULL(hpe->hp) && hpe->peer_vhca_id == peer_vhca_id)
-                       hpe->hp->pair->peer_gone = true;
+                       mlx5_core_hairpin_clear_dead_peer(hpe->hp->pair);
 
                mlx5e_hairpin_put(priv, hpe);
        }
index 25c0917..1702753 100644 (file)
@@ -178,6 +178,9 @@ void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *f
 void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list);
 
 struct mlx5e_neigh_hash_entry;
+struct mlx5e_encap_entry *
+mlx5e_get_next_init_encap(struct mlx5e_neigh_hash_entry *nhe,
+                         struct mlx5e_encap_entry *e);
 void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe);
 
 void mlx5e_tc_reoffload_flows_work(struct work_struct *work);
index 8ba6267..320fe0c 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <linux/tcp.h>
 #include <linux/if_vlan.h>
-#include <linux/ptp_classify.h>
 #include <net/geneve.h>
 #include <net/dsfield.h>
 #include "en.h"
@@ -67,24 +66,6 @@ static inline int mlx5e_get_dscp_up(struct mlx5e_priv *priv, struct sk_buff *skb
 }
 #endif
 
-static bool mlx5e_use_ptpsq(struct sk_buff *skb)
-{
-       struct flow_keys fk;
-
-       if (!skb_flow_dissect_flow_keys(skb, &fk, 0))
-               return false;
-
-       if (fk.basic.n_proto == htons(ETH_P_1588))
-               return true;
-
-       if (fk.basic.n_proto != htons(ETH_P_IP) &&
-           fk.basic.n_proto != htons(ETH_P_IPV6))
-               return false;
-
-       return (fk.basic.ip_proto == IPPROTO_UDP &&
-               fk.ports.dst == htons(PTP_EV_PORT));
-}
-
 static u16 mlx5e_select_ptpsq(struct net_device *dev, struct sk_buff *skb)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
@@ -145,9 +126,9 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
                }
 
                ptp_channel = READ_ONCE(priv->channels.ptp);
-               if (unlikely(ptp_channel) &&
-                   test_bit(MLX5E_PTP_STATE_TX, ptp_channel->state) &&
-                   mlx5e_use_ptpsq(skb))
+               if (unlikely(ptp_channel &&
+                            test_bit(MLX5E_PTP_STATE_TX, ptp_channel->state) &&
+                            mlx5e_use_ptpsq(skb)))
                        return mlx5e_select_ptpsq(dev, skb);
 
                txq_ix = netdev_pick_tx(dev, skb, NULL);
index 77c0ca6..9403334 100644 (file)
@@ -136,7 +136,7 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
 
        eqe = next_eqe_sw(eq);
        if (!eqe)
-               return 0;
+               goto out;
 
        do {
                struct mlx5_core_cq *cq;
@@ -161,6 +161,8 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
                ++eq->cons_index;
 
        } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
+
+out:
        eq_update_ci(eq, 1);
 
        if (cqn != -1)
@@ -248,9 +250,9 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
                ++eq->cons_index;
 
        } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
-       eq_update_ci(eq, 1);
 
 out:
+       eq_update_ci(eq, 1);
        mlx5_eq_async_int_unlock(eq_async, recovery, &flags);
 
        return unlikely(recovery) ? num_eqes : 0;
index b88705a..97e6cb6 100644 (file)
@@ -1054,6 +1054,12 @@ int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
                        goto err_vhca_mapping;
        }
 
+       /* External controller host PF has factory programmed MAC.
+        * Read it from the device.
+        */
+       if (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF)
+               mlx5_query_nic_vport_mac_address(esw->dev, vport_num, true, vport->info.mac);
+
        esw_vport_change_handle_locked(vport);
 
        esw->enabled_vports++;
index a1d67bd..0d0f63a 100644 (file)
@@ -1161,7 +1161,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)
        err = mlx5_core_set_hca_defaults(dev);
        if (err) {
                mlx5_core_err(dev, "Failed to set hca defaults\n");
-               goto err_sriov;
+               goto err_set_hca;
        }
 
        mlx5_vhca_event_start(dev);
@@ -1194,6 +1194,7 @@ err_ec:
        mlx5_sf_hw_table_destroy(dev);
 err_vhca:
        mlx5_vhca_event_stop(dev);
+err_set_hca:
        mlx5_cleanup_fs(dev);
 err_fs:
        mlx5_accel_tls_cleanup(dev);
index 50af84e..174f71e 100644 (file)
@@ -54,7 +54,7 @@ int mlx5_core_create_mkey(struct mlx5_core_dev *dev,
        mkey_index = MLX5_GET(create_mkey_out, lout, mkey_index);
        mkey->iova = MLX5_GET64(mkc, mkc, start_addr);
        mkey->size = MLX5_GET64(mkc, mkc, len);
-       mkey->key |= mlx5_idx_to_mkey(mkey_index);
+       mkey->key = (u32)mlx5_mkey_variant(mkey->key) | mlx5_idx_to_mkey(mkey_index);
        mkey->pd = MLX5_GET(mkc, mkc, pd);
        init_waitqueue_head(&mkey->wait);
 
index 441b545..540cf05 100644 (file)
@@ -156,6 +156,9 @@ void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
 {
        int err;
 
+       if (!MLX5_CAP_GEN(dev, roce))
+               return;
+
        err = mlx5_nic_vport_enable_roce(dev);
        if (err) {
                mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err);
index 6a0c6f9..fa0288a 100644 (file)
@@ -163,6 +163,7 @@ mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_
        sf_index = event->function_id - base_id;
        sf_dev = xa_load(&table->devices, sf_index);
        switch (event->new_vhca_state) {
+       case MLX5_VHCA_STATE_INVALID:
        case MLX5_VHCA_STATE_ALLOCATED:
                if (sf_dev)
                        mlx5_sf_dev_del(table->dev, sf_dev, sf_index);
index 054c2e2..7466f01 100644 (file)
@@ -694,7 +694,11 @@ static int dr_ste_v1_set_action_decap_l3_list(void *data,
        if (hw_action_sz / DR_STE_ACTION_DOUBLE_SZ < DR_STE_DECAP_L3_ACTION_NUM)
                return -EINVAL;
 
-       memcpy(padded_data, data, data_sz);
+       inline_data_sz =
+               MLX5_FLD_SZ_BYTES(ste_double_action_insert_with_inline_v1, inline_data);
+
+       /* Add an alignment padding  */
+       memcpy(padded_data + data_sz % inline_data_sz, data, data_sz);
 
        /* Remove L2L3 outer headers */
        MLX5_SET(ste_single_action_remove_header_v1, hw_action, action_id,
@@ -706,32 +710,34 @@ static int dr_ste_v1_set_action_decap_l3_list(void *data,
        hw_action += DR_STE_ACTION_DOUBLE_SZ;
        used_actions++; /* Remove and NOP are a single double action */
 
-       inline_data_sz =
-               MLX5_FLD_SZ_BYTES(ste_double_action_insert_with_inline_v1, inline_data);
+       /* Point to the last dword of the header */
+       data_ptr += (data_sz / inline_data_sz) * inline_data_sz;
 
-       /* Add the new header inline + 2 extra bytes */
+       /* Add the new header using inline action 4Byte at a time, the header
+        * is added in reversed order to the beginning of the packet to avoid
+        * incorrect parsing by the HW. Since header is 14B or 18B an extra
+        * two bytes are padded and later removed.
+        */
        for (i = 0; i < data_sz / inline_data_sz + 1; i++) {
                void *addr_inline;
 
                MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, action_id,
                         DR_STE_V1_ACTION_ID_INSERT_INLINE);
                /* The hardware expects here offset to words (2 bytes) */
-               MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, start_offset,
-                        i * 2);
+               MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, start_offset, 0);
 
                /* Copy bytes one by one to avoid endianness problem */
                addr_inline = MLX5_ADDR_OF(ste_double_action_insert_with_inline_v1,
                                           hw_action, inline_data);
-               memcpy(addr_inline, data_ptr, inline_data_sz);
+               memcpy(addr_inline, data_ptr - i * inline_data_sz, inline_data_sz);
                hw_action += DR_STE_ACTION_DOUBLE_SZ;
-               data_ptr += inline_data_sz;
                used_actions++;
        }
 
-       /* Remove 2 extra bytes */
+       /* Remove first 2 extra bytes */
        MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, action_id,
                 DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE);
-       MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, start_offset, data_sz / 2);
+       MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, start_offset, 0);
        /* The hardware expects here size in words (2 bytes) */
        MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, remove_size, 1);
        used_actions++;
index 612b0ac..9737565 100644 (file)
@@ -124,10 +124,11 @@ int mlx5dr_action_destroy(struct mlx5dr_action *action);
 static inline bool
 mlx5dr_is_supported(struct mlx5_core_dev *dev)
 {
-       return MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner) ||
-              (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner_v2) &&
-               (MLX5_CAP_GEN(dev, steering_format_version) <=
-                MLX5_STEERING_FORMAT_CONNECTX_6DX));
+       return MLX5_CAP_GEN(dev, roce) &&
+              (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner) ||
+               (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner_v2) &&
+                (MLX5_CAP_GEN(dev, steering_format_version) <=
+                 MLX5_STEERING_FORMAT_CONNECTX_6DX)));
 }
 
 /* buddy functions & structure */
index 01cc00a..b6931bb 100644 (file)
@@ -424,6 +424,15 @@ err_modify_sq:
        return err;
 }
 
+static void mlx5_hairpin_unpair_peer_sq(struct mlx5_hairpin *hp)
+{
+       int i;
+
+       for (i = 0; i < hp->num_channels; i++)
+               mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
+                                      MLX5_SQC_STATE_RST, 0, 0);
+}
+
 static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
 {
        int i;
@@ -432,13 +441,9 @@ static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
        for (i = 0; i < hp->num_channels; i++)
                mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn[i], MLX5_RQC_STATE_RDY,
                                       MLX5_RQC_STATE_RST, 0, 0);
-
        /* unset peer SQs */
-       if (hp->peer_gone)
-               return;
-       for (i = 0; i < hp->num_channels; i++)
-               mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
-                                      MLX5_SQC_STATE_RST, 0, 0);
+       if (!hp->peer_gone)
+               mlx5_hairpin_unpair_peer_sq(hp);
 }
 
 struct mlx5_hairpin *
@@ -485,3 +490,16 @@ void mlx5_core_hairpin_destroy(struct mlx5_hairpin *hp)
        mlx5_hairpin_destroy_queues(hp);
        kfree(hp);
 }
+
+void mlx5_core_hairpin_clear_dead_peer(struct mlx5_hairpin *hp)
+{
+       int i;
+
+       mlx5_hairpin_unpair_peer_sq(hp);
+
+       /* destroy peer SQ */
+       for (i = 0; i < hp->num_channels; i++)
+               mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
+
+       hp->peer_gone = true;
+}
index 457ad42..4c1440a 100644 (file)
@@ -465,8 +465,6 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev,
        void *in;
        int err;
 
-       if (!vport)
-               return -EINVAL;
        if (!MLX5_CAP_GEN(mdev, vport_group_manager))
                return -EACCES;
 
index dfea143..85f0ce2 100644 (file)
@@ -693,7 +693,8 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
                                                        MLXSW_THERMAL_TRIP_MASK,
                                                        module_tz,
                                                        &mlxsw_thermal_module_ops,
-                                                       NULL, 0, 0);
+                                                       NULL, 0,
+                                                       module_tz->parent->polling_delay);
        if (IS_ERR(module_tz->tzdev)) {
                err = PTR_ERR(module_tz->tzdev);
                return err;
@@ -815,7 +816,8 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
                                                MLXSW_THERMAL_TRIP_MASK,
                                                gearbox_tz,
                                                &mlxsw_thermal_gearbox_ops,
-                                               NULL, 0, 0);
+                                               NULL, 0,
+                                               gearbox_tz->parent->polling_delay);
        if (IS_ERR(gearbox_tz->tzdev))
                return PTR_ERR(gearbox_tz->tzdev);
 
index 900b4bf..2bc5a90 100644 (file)
@@ -3907,7 +3907,7 @@ MLXSW_ITEM32(reg, qeec, max_shaper_bs, 0x1C, 0, 6);
 #define MLXSW_REG_QEEC_HIGHEST_SHAPER_BS       25
 #define MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1    5
 #define MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2    11
-#define MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3    5
+#define MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3    11
 
 static inline void mlxsw_reg_qeec_pack(char *payload, u8 local_port,
                                       enum mlxsw_reg_qeec_hr hr, u8 index,
index 04672eb..9958d50 100644 (file)
@@ -1332,6 +1332,7 @@ __mlxsw_sp_qdisc_ets_graft(struct mlxsw_sp_port *mlxsw_sp_port,
                           u8 band, u32 child_handle)
 {
        struct mlxsw_sp_qdisc *old_qdisc;
+       u32 parent;
 
        if (band < mlxsw_sp_qdisc->num_classes &&
            mlxsw_sp_qdisc->qdiscs[band].handle == child_handle)
@@ -1352,7 +1353,9 @@ __mlxsw_sp_qdisc_ets_graft(struct mlxsw_sp_port *mlxsw_sp_port,
        if (old_qdisc)
                mlxsw_sp_qdisc_destroy(mlxsw_sp_port, old_qdisc);
 
-       mlxsw_sp_qdisc = mlxsw_sp_qdisc->ops->find_class(mlxsw_sp_qdisc, band);
+       parent = TC_H_MAKE(mlxsw_sp_qdisc->handle, band + 1);
+       mlxsw_sp_qdisc = mlxsw_sp_qdisc->ops->find_class(mlxsw_sp_qdisc,
+                                                        parent);
        if (!WARN_ON(!mlxsw_sp_qdisc))
                mlxsw_sp_qdisc_destroy(mlxsw_sp_port, mlxsw_sp_qdisc);
 
index 0c42833..adfb978 100644 (file)
@@ -379,6 +379,7 @@ static u32 ocelot_read_eq_avail(struct ocelot *ocelot, int port)
 
 int ocelot_port_flush(struct ocelot *ocelot, int port)
 {
+       unsigned int pause_ena;
        int err, val;
 
        /* Disable dequeuing from the egress queues */
@@ -387,6 +388,7 @@ int ocelot_port_flush(struct ocelot *ocelot, int port)
                       QSYS_PORT_MODE, port);
 
        /* Disable flow control */
+       ocelot_fields_read(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, &pause_ena);
        ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, 0);
 
        /* Disable priority flow control */
@@ -422,6 +424,9 @@ int ocelot_port_flush(struct ocelot *ocelot, int port)
        /* Clear flushing again. */
        ocelot_rmw_gix(ocelot, 0, REW_PORT_CFG_FLUSH_ENA, REW_PORT_CFG, port);
 
+       /* Re-enable flow control */
+       ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, pause_ena);
+
        return err;
 }
 EXPORT_SYMBOL(ocelot_port_flush);
index 5162b93..b47d747 100644 (file)
@@ -3784,6 +3784,7 @@ vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1,
                        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN |
                        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(
                        itable[j]);
+               return;
        default:
                return;
        }
index b3cabc2..3b8e675 100644 (file)
@@ -103,6 +103,7 @@ nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
        case NFP_PORT_PF_PORT:
        case NFP_PORT_VF_PORT:
                nfp_repr_vnic_get_stats64(repr->port, stats);
+               break;
        default:
                break;
        }
index 08f9477..35ec9aa 100644 (file)
@@ -1685,6 +1685,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
                        break;
                case NETXEN_NIC_RESPONSE_DESC:
                        netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
+                       goto skip;
                default:
                        goto skip;
                }
index 7e6bac8..344ea11 100644 (file)
@@ -1602,6 +1602,8 @@ err_out_free_netdev:
        free_netdev(netdev);
 
 err_out_free_res:
+       if (NX_IS_REVISION_P3(pdev->revision))
+               pci_disable_pcie_error_reporting(pdev);
        pci_release_regions(pdev);
 
 err_out_disable_pdev:
index 17d5b64..e81dd34 100644 (file)
@@ -1266,9 +1266,11 @@ int qed_dcbx_get_config_params(struct qed_hwfn *p_hwfn,
                p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_STATIC;
 
        p_hwfn->p_dcbx_info->set.enabled = dcbx_info->operational.enabled;
+       BUILD_BUG_ON(sizeof(dcbx_info->operational.params) !=
+                    sizeof(p_hwfn->p_dcbx_info->set.config.params));
        memcpy(&p_hwfn->p_dcbx_info->set.config.params,
               &dcbx_info->operational.params,
-              sizeof(struct qed_dcbx_admin_params));
+              sizeof(p_hwfn->p_dcbx_info->set.config.params));
        p_hwfn->p_dcbx_info->set.config.valid = true;
 
        memcpy(params, &p_hwfn->p_dcbx_info->set, sizeof(struct qed_dcbx_set));
index bdf15d2..af4c516 100644 (file)
@@ -1390,6 +1390,7 @@ static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int ma
                        break;
                case QLCNIC_RESPONSE_DESC:
                        qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+                       goto skip;
                default:
                        goto skip;
                }
index 96b947f..918220a 100644 (file)
@@ -2690,6 +2690,7 @@ err_out_free_hw_res:
        kfree(ahw);
 
 err_out_free_res:
+       pci_disable_pcie_error_reporting(pdev);
        pci_release_regions(pdev);
 
 err_out_disable_pdev:
@@ -3455,6 +3456,7 @@ wait_npar:
                        adapter->fw_wait_cnt = 0;
                        return;
                }
+               break;
        case QLCNIC_DEV_FAILED:
                break;
        default:
index ab9b025..0a6b811 100644 (file)
@@ -653,8 +653,7 @@ qcaspi_intr_handler(int irq, void *data)
        struct qcaspi *qca = data;
 
        qca->intr_req++;
-       if (qca->spi_thread &&
-           qca->spi_thread->state != TASK_RUNNING)
+       if (qca->spi_thread)
                wake_up_process(qca->spi_thread);
 
        return IRQ_HANDLED;
@@ -777,8 +776,7 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
 
        netif_trans_update(dev);
 
-       if (qca->spi_thread &&
-           qca->spi_thread->state != TASK_RUNNING)
+       if (qca->spi_thread)
                wake_up_process(qca->spi_thread);
 
        return NETDEV_TX_OK;
index 41fbd2c..ab1e0fc 100644 (file)
@@ -126,24 +126,24 @@ static void rmnet_get_stats64(struct net_device *dev,
                              struct rtnl_link_stats64 *s)
 {
        struct rmnet_priv *priv = netdev_priv(dev);
-       struct rmnet_vnd_stats total_stats;
+       struct rmnet_vnd_stats total_stats = { };
        struct rmnet_pcpu_stats *pcpu_ptr;
+       struct rmnet_vnd_stats snapshot;
        unsigned int cpu, start;
 
-       memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats));
-
        for_each_possible_cpu(cpu) {
                pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu);
 
                do {
                        start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp);
-                       total_stats.rx_pkts += pcpu_ptr->stats.rx_pkts;
-                       total_stats.rx_bytes += pcpu_ptr->stats.rx_bytes;
-                       total_stats.tx_pkts += pcpu_ptr->stats.tx_pkts;
-                       total_stats.tx_bytes += pcpu_ptr->stats.tx_bytes;
+                       snapshot = pcpu_ptr->stats;     /* struct assignment */
                } while (u64_stats_fetch_retry_irq(&pcpu_ptr->syncp, start));
 
-               total_stats.tx_drops += pcpu_ptr->stats.tx_drops;
+               total_stats.rx_pkts += snapshot.rx_pkts;
+               total_stats.rx_bytes += snapshot.rx_bytes;
+               total_stats.tx_pkts += snapshot.tx_pkts;
+               total_stats.tx_bytes += snapshot.tx_bytes;
+               total_stats.tx_drops += snapshot.tx_drops;
        }
 
        s->rx_packets = total_stats.rx_pkts;
@@ -354,4 +354,4 @@ int rmnet_vnd_update_dev_mtu(struct rmnet_port *port,
        }
 
        return 0;
-}
\ No newline at end of file
+}
index 2c89cde..2ee72dc 100644 (file)
@@ -1671,7 +1671,7 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        switch(stringset) {
        case ETH_SS_STATS:
-               memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
+               memcpy(data, rtl8169_gstrings, sizeof(rtl8169_gstrings));
                break;
        }
 }
index c5b1548..713d362 100644 (file)
@@ -2287,7 +2287,7 @@ static void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
 {
        switch (stringset) {
        case ETH_SS_STATS:
-               memcpy(data, *sh_eth_gstrings_stats,
+               memcpy(data, sh_eth_gstrings_stats,
                       sizeof(sh_eth_gstrings_stats));
                break;
        }
index b70d44a..3c73453 100644 (file)
@@ -76,10 +76,10 @@ enum power_event {
 #define LPI_CTRL_STATUS_TLPIEN 0x00000001      /* Transmit LPI Entry */
 
 /* GMAC HW ADDR regs */
-#define GMAC_ADDR_HIGH(reg)    (((reg > 15) ? 0x00000800 : 0x00000040) + \
-                               (reg * 8))
-#define GMAC_ADDR_LOW(reg)     (((reg > 15) ? 0x00000804 : 0x00000044) + \
-                               (reg * 8))
+#define GMAC_ADDR_HIGH(reg)    ((reg > 15) ? 0x00000800 + (reg - 16) * 8 : \
+                                0x00000040 + (reg * 8))
+#define GMAC_ADDR_LOW(reg)     ((reg > 15) ? 0x00000804 + (reg - 16) * 8 : \
+                                0x00000044 + (reg * 8))
 #define GMAC_MAX_PERFECT_ADDRESSES     1
 
 #define GMAC_PCS_BASE          0x000000c0      /* PCS register base */
index 1e17a23..a696ada 100644 (file)
@@ -622,6 +622,8 @@ error_pclk_get:
 void stmmac_remove_config_dt(struct platform_device *pdev,
                             struct plat_stmmacenet_data *plat)
 {
+       clk_disable_unprepare(plat->stmmac_clk);
+       clk_disable_unprepare(plat->pclk);
        of_node_put(plat->phy_node);
        of_node_put(plat->mdio_node);
 }
index a1f5f07..9a13953 100644 (file)
@@ -774,12 +774,15 @@ static void temac_start_xmit_done(struct net_device *ndev)
        stat = be32_to_cpu(cur_p->app0);
 
        while (stat & STS_CTRL_APP0_CMPLT) {
+               /* Make sure that the other fields are read after bd is
+                * released by dma
+                */
+               rmb();
                dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
                                 be32_to_cpu(cur_p->len), DMA_TO_DEVICE);
                skb = (struct sk_buff *)ptr_from_txbd(cur_p);
                if (skb)
                        dev_consume_skb_irq(skb);
-               cur_p->app0 = 0;
                cur_p->app1 = 0;
                cur_p->app2 = 0;
                cur_p->app3 = 0;
@@ -788,6 +791,12 @@ static void temac_start_xmit_done(struct net_device *ndev)
                ndev->stats.tx_packets++;
                ndev->stats.tx_bytes += be32_to_cpu(cur_p->len);
 
+               /* app0 must be visible last, as it is used to flag
+                * availability of the bd
+                */
+               smp_mb();
+               cur_p->app0 = 0;
+
                lp->tx_bd_ci++;
                if (lp->tx_bd_ci >= lp->tx_bd_num)
                        lp->tx_bd_ci = 0;
@@ -814,6 +823,9 @@ static inline int temac_check_tx_bd_space(struct temac_local *lp, int num_frag)
                if (cur_p->app0)
                        return NETDEV_TX_BUSY;
 
+               /* Make sure to read next bd app0 after this one */
+               rmb();
+
                tail++;
                if (tail >= lp->tx_bd_num)
                        tail = 0;
@@ -849,7 +861,7 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                smp_mb();
 
                /* Space might have just been freed - check again */
-               if (temac_check_tx_bd_space(lp, num_frag))
+               if (temac_check_tx_bd_space(lp, num_frag + 1))
                        return NETDEV_TX_BUSY;
 
                netif_wake_queue(ndev);
@@ -876,7 +888,6 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_OK;
        }
        cur_p->phys = cpu_to_be32(skb_dma_addr);
-       ptr_to_txbd((void *)skb, cur_p);
 
        for (ii = 0; ii < num_frag; ii++) {
                if (++lp->tx_bd_tail >= lp->tx_bd_num)
@@ -915,6 +926,11 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        cur_p->app0 |= cpu_to_be32(STS_CTRL_APP0_EOP);
 
+       /* Mark last fragment with skb address, so it can be consumed
+        * in temac_start_xmit_done()
+        */
+       ptr_to_txbd((void *)skb, cur_p);
+
        tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
        lp->tx_bd_tail++;
        if (lp->tx_bd_tail >= lp->tx_bd_num)
@@ -926,6 +942,11 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        wmb();
        lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
+       if (temac_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) {
+               netdev_info(ndev, "%s -> netif_stop_queue\n", __func__);
+               netif_stop_queue(ndev);
+       }
+
        return NETDEV_TX_OK;
 }
 
index 6515422..7685a17 100644 (file)
@@ -799,6 +799,7 @@ static void mkiss_close(struct tty_struct *tty)
        ax->tty = NULL;
 
        unregister_netdev(ax->dev);
+       free_netdev(ax->dev);
 }
 
 /* Perform I/O control on an active ax25 channel. */
index 442c520..b11aa68 100644 (file)
@@ -895,9 +895,16 @@ static inline u32 netvsc_rqstor_size(unsigned long ringbytes)
                ringbytes / NETVSC_MIN_IN_MSG_SIZE;
 }
 
+/* XFER PAGE packets can specify a maximum of 375 ranges for NDIS >= 6.0
+ * and a maximum of 64 ranges for NDIS < 6.0 with no RSC; with RSC, this
+ * limit is raised to 562 (= NVSP_RSC_MAX).
+ */
+#define NETVSC_MAX_XFER_PAGE_RANGES NVSP_RSC_MAX
 #define NETVSC_XFER_HEADER_SIZE(rng_cnt) \
                (offsetof(struct vmtransfer_page_packet_header, ranges) + \
                (rng_cnt) * sizeof(struct vmtransfer_page_range))
+#define NETVSC_MAX_PKT_SIZE (NETVSC_XFER_HEADER_SIZE(NETVSC_MAX_XFER_PAGE_RANGES) + \
+               sizeof(struct nvsp_message) + (sizeof(u32) * VRSS_SEND_TAB_SIZE))
 
 struct multi_send_data {
        struct sk_buff *skb; /* skb containing the pkt */
index 9d07c9c..7bd9354 100644 (file)
@@ -757,7 +757,7 @@ static void netvsc_send_tx_complete(struct net_device *ndev,
        int queue_sends;
        u64 cmd_rqst;
 
-       cmd_rqst = vmbus_request_addr(&channel->requestor, (u64)desc->trans_id);
+       cmd_rqst = channel->request_addr_callback(channel, (u64)desc->trans_id);
        if (cmd_rqst == VMBUS_RQST_ERROR) {
                netdev_err(ndev, "Incorrect transaction id\n");
                return;
@@ -817,8 +817,8 @@ static void netvsc_send_completion(struct net_device *ndev,
 
        /* First check if this is a VMBUS completion without data payload */
        if (!msglen) {
-               cmd_rqst = vmbus_request_addr(&incoming_channel->requestor,
-                                             (u64)desc->trans_id);
+               cmd_rqst = incoming_channel->request_addr_callback(incoming_channel,
+                                                                  (u64)desc->trans_id);
                if (cmd_rqst == VMBUS_RQST_ERROR) {
                        netdev_err(ndev, "Invalid transaction id\n");
                        return;
@@ -1649,7 +1649,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
                       netvsc_poll, NAPI_POLL_WEIGHT);
 
        /* Open the channel */
+       device->channel->next_request_id_callback = vmbus_next_request_id;
+       device->channel->request_addr_callback = vmbus_request_addr;
        device->channel->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes);
+       device->channel->max_pkt_size = NETVSC_MAX_PKT_SIZE;
+
        ret = vmbus_open(device->channel, netvsc_ring_bytes,
                         netvsc_ring_bytes,  NULL, 0,
                         netvsc_channel_cb, net_device->chan_table);
index c0e89e1..983bf36 100644 (file)
@@ -1259,7 +1259,11 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
        /* Set the channel before opening.*/
        nvchan->channel = new_sc;
 
+       new_sc->next_request_id_callback = vmbus_next_request_id;
+       new_sc->request_addr_callback = vmbus_request_addr;
        new_sc->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes);
+       new_sc->max_pkt_size = NETVSC_MAX_PKT_SIZE;
+
        ret = vmbus_open(new_sc, netvsc_ring_bytes,
                         netvsc_ring_bytes, NULL, 0,
                         netvsc_channel_cb, nvchan);
index 0d8293a..b806f2f 100644 (file)
@@ -49,7 +49,7 @@ static int mhi_ndo_stop(struct net_device *ndev)
        return 0;
 }
 
-static int mhi_ndo_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t mhi_ndo_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        struct mhi_net_dev *mhi_netdev = netdev_priv(ndev);
        const struct mhi_net_proto *proto = mhi_netdev->proto;
index 9bd9a5c..6bbc81a 100644 (file)
@@ -826,16 +826,12 @@ static int dp83867_phy_reset(struct phy_device *phydev)
 {
        int err;
 
-       err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
+       err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESTART);
        if (err < 0)
                return err;
 
        usleep_range(10, 20);
 
-       /* After reset FORCE_LINK_GOOD bit is set. Although the
-        * default value should be unset. Disable FORCE_LINK_GOOD
-        * for the phy to work properly.
-        */
        return phy_modify(phydev, MII_DP83867_PHYCTRL,
                         DP83867_PHYCR_FORCE_LINK_GOOD, 0);
 }
index 2e60bc1..359ea0d 100644 (file)
@@ -123,10 +123,10 @@ static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
        }
 
        skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
+       dev_kfree_skb_any(skb);
        if (!skb2)
                return NULL;
 
-       dev_kfree_skb_any(skb);
        skb = skb2;
 
 done:
index b04055f..df0d183 100644 (file)
@@ -1880,7 +1880,7 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
 static const struct driver_info cdc_ncm_info = {
        .description = "CDC NCM",
        .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-                       | FLAG_LINK_INTR,
+                       | FLAG_LINK_INTR | FLAG_ETHER,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .manage_power = usbnet_manage_power,
index 6700f19..bc55ec7 100644 (file)
@@ -575,7 +575,7 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 
        if (info->flags & QMI_WWAN_FLAG_PASS_THROUGH) {
                skb->protocol = htons(ETH_P_MAP);
-               return (netif_rx(skb) == NET_RX_SUCCESS);
+               return 1;
        }
 
        switch (skb->data[0] & 0xf0) {
index f6abb2f..e25bfb7 100644 (file)
@@ -8678,7 +8678,7 @@ static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
        switch (stringset) {
        case ETH_SS_STATS:
-               memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
+               memcpy(data, rtl8152_gstrings, sizeof(rtl8152_gstrings));
                break;
        }
 }
index b286993..13141db 100644 (file)
@@ -1483,7 +1483,7 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
        ret = smsc75xx_wait_ready(dev, 0);
        if (ret < 0) {
                netdev_warn(dev->net, "device not ready in smsc75xx_bind\n");
-               goto err;
+               goto free_pdata;
        }
 
        smsc75xx_init_mac_address(dev);
@@ -1492,7 +1492,7 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
        ret = smsc75xx_reset(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
-               goto err;
+               goto cancel_work;
        }
 
        dev->net->netdev_ops = &smsc75xx_netdev_ops;
@@ -1503,8 +1503,11 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->net->max_mtu = MAX_SINGLE_PACKET_SIZE;
        return 0;
 
-err:
+cancel_work:
+       cancel_work_sync(&pdata->set_multicast);
+free_pdata:
        kfree(pdata);
+       dev->data[0] = 0;
        return ret;
 }
 
@@ -1515,7 +1518,6 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
                cancel_work_sync(&pdata->set_multicast);
                netif_dbg(dev, ifdown, dev->net, "free pdata\n");
                kfree(pdata);
-               pdata = NULL;
                dev->data[0] = 0;
        }
 }
index 503e2fd..28a6c4c 100644 (file)
@@ -1183,9 +1183,6 @@ static int vrf_dev_init(struct net_device *dev)
 
        dev->flags = IFF_MASTER | IFF_NOARP;
 
-       /* MTU is irrelevant for VRF device; set to 64k similar to lo */
-       dev->mtu = 64 * 1024;
-
        /* similarly, oper state is irrelevant; set to up to avoid confusion */
        dev->operstate = IF_OPER_UP;
        netdev_lockdep_set_classes(dev);
@@ -1685,7 +1682,8 @@ static void vrf_setup(struct net_device *dev)
         * which breaks networking.
         */
        dev->min_mtu = IPV6_MIN_MTU;
-       dev->max_mtu = ETH_MAX_MTU;
+       dev->max_mtu = IP6_MAX_MTU;
+       dev->mtu = dev->max_mtu;
 }
 
 static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],
index 51ce767..7a6fd46 100644 (file)
@@ -1693,8 +1693,13 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)
 static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 {
        struct mac80211_hwsim_data *data = hw->priv;
+
        data->started = false;
        hrtimer_cancel(&data->beacon_timer);
+
+       while (!skb_queue_empty(&data->pending))
+               ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
+
        wiphy_dbg(hw->wiphy, "%s\n", __func__);
 }
 
index e366218..b335c07 100644 (file)
@@ -893,6 +893,16 @@ static int _set_required_opps(struct device *dev,
        if (!required_opp_tables)
                return 0;
 
+       /*
+        * We only support genpd's OPPs in the "required-opps" for now, as we
+        * don't know much about other use cases. Error out if the required OPP
+        * doesn't belong to a genpd.
+        */
+       if (unlikely(!required_opp_tables[0]->is_genpd)) {
+               dev_err(dev, "required-opps don't belong to a genpd\n");
+               return -ENOENT;
+       }
+
        /* required-opps not fully initialized yet */
        if (lazy_linking_pending(opp_table))
                return -EBUSY;
index c582a9c..d298e38 100644 (file)
@@ -197,21 +197,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
                required_opp_tables[i] = _find_table_of_opp_np(required_np);
                of_node_put(required_np);
 
-               if (IS_ERR(required_opp_tables[i])) {
+               if (IS_ERR(required_opp_tables[i]))
                        lazy = true;
-                       continue;
-               }
-
-               /*
-                * We only support genpd's OPPs in the "required-opps" for now,
-                * as we don't know how much about other cases. Error out if the
-                * required OPP doesn't belong to a genpd.
-                */
-               if (!required_opp_tables[i]->is_genpd) {
-                       dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
-                               required_np);
-                       goto free_required_tables;
-               }
        }
 
        /* Let's do the linking later on */
@@ -379,13 +366,6 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)
        struct dev_pm_opp *opp;
        int i, ret;
 
-       /*
-        * We only support genpd's OPPs in the "required-opps" for now,
-        * as we don't know much about other cases.
-        */
-       if (!new_table->is_genpd)
-               return;
-
        mutex_lock(&opp_table_lock);
 
        list_for_each_entry_safe(opp_table, temp, &lazy_opp_tables, lazy) {
@@ -433,8 +413,7 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)
 
                /* All required opp-tables found, remove from lazy list */
                if (!lazy) {
-                       list_del(&opp_table->lazy);
-                       INIT_LIST_HEAD(&opp_table->lazy);
+                       list_del_init(&opp_table->lazy);
 
                        list_for_each_entry(opp, &opp_table->opp_list, node)
                                _required_opps_available(opp, opp_table->required_opp_count);
@@ -874,7 +853,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
                return ERR_PTR(-ENOMEM);
 
        ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
-       if (ret < 0 && !opp_table->is_genpd) {
+       if (ret < 0) {
                dev_err(dev, "%s: opp key field not found\n", __func__);
                goto free_opp;
        }
index eca805c..9e6ce0d 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
+obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
 obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
 
@@ -38,6 +39,6 @@ ifdef CONFIG_ACPI
 ifdef CONFIG_PCI_QUIRKS
 obj-$(CONFIG_ARM64) += pcie-al.o
 obj-$(CONFIG_ARM64) += pcie-hisi.o
-obj-$(CONFIG_ARM64) += pcie-tegra194.o
+obj-$(CONFIG_ARM64) += pcie-tegra194-acpi.o
 endif
 endif
diff --git a/drivers/pci/controller/dwc/pcie-tegra194-acpi.c b/drivers/pci/controller/dwc/pcie-tegra194-acpi.c
new file mode 100644 (file)
index 0000000..c2de6ed
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ACPI quirks for Tegra194 PCIe host controller
+ *
+ * Copyright (C) 2021 NVIDIA Corporation.
+ *
+ * Author: Vidya Sagar <vidyas@nvidia.com>
+ */
+
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
+
+#include "pcie-designware.h"
+
+struct tegra194_pcie_ecam  {
+       void __iomem *config_base;
+       void __iomem *iatu_base;
+       void __iomem *dbi_base;
+};
+
+static int tegra194_acpi_init(struct pci_config_window *cfg)
+{
+       struct device *dev = cfg->parent;
+       struct tegra194_pcie_ecam *pcie_ecam;
+
+       pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
+       if (!pcie_ecam)
+               return -ENOMEM;
+
+       pcie_ecam->config_base = cfg->win;
+       pcie_ecam->iatu_base = cfg->win + SZ_256K;
+       pcie_ecam->dbi_base = cfg->win + SZ_512K;
+       cfg->priv = pcie_ecam;
+
+       return 0;
+}
+
+static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
+                         u32 val, u32 reg)
+{
+       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+       writel(val, pcie_ecam->iatu_base + offset + reg);
+}
+
+static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
+                                int index, int type, u64 cpu_addr,
+                                u64 pci_addr, u64 size)
+{
+       atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
+                     PCIE_ATU_LOWER_BASE);
+       atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
+                     PCIE_ATU_UPPER_BASE);
+       atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
+                     PCIE_ATU_LOWER_TARGET);
+       atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
+                     PCIE_ATU_LIMIT);
+       atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
+                     PCIE_ATU_UPPER_TARGET);
+       atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1);
+       atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+}
+
+static void __iomem *tegra194_map_bus(struct pci_bus *bus,
+                                     unsigned int devfn, int where)
+{
+       struct pci_config_window *cfg = bus->sysdata;
+       struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
+       u32 busdev;
+       int type;
+
+       if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
+               return NULL;
+
+       if (bus->number == cfg->busr.start) {
+               if (PCI_SLOT(devfn) == 0)
+                       return pcie_ecam->dbi_base + where;
+               else
+                       return NULL;
+       }
+
+       busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
+                PCIE_ATU_FUNC(PCI_FUNC(devfn));
+
+       if (bus->parent->number == cfg->busr.start) {
+               if (PCI_SLOT(devfn) == 0)
+                       type = PCIE_ATU_TYPE_CFG0;
+               else
+                       return NULL;
+       } else {
+               type = PCIE_ATU_TYPE_CFG1;
+       }
+
+       program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
+                            SZ_256K);
+
+       return pcie_ecam->config_base + where;
+}
+
+const struct pci_ecam_ops tegra194_pcie_ops = {
+       .init           = tegra194_acpi_init,
+       .pci_ops        = {
+               .map_bus        = tegra194_map_bus,
+               .read           = pci_generic_config_read,
+               .write          = pci_generic_config_write,
+       }
+};
index bafd2c6..504669e 100644 (file)
@@ -22,8 +22,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_pci.h>
 #include <linux/pci.h>
-#include <linux/pci-acpi.h>
-#include <linux/pci-ecam.h>
 #include <linux/phy/phy.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
@@ -247,24 +245,6 @@ static const unsigned int pcie_gen_freq[] = {
        GEN4_CORE_CLK_FREQ
 };
 
-static const u32 event_cntr_ctrl_offset[] = {
-       0x1d8,
-       0x1a8,
-       0x1a8,
-       0x1a8,
-       0x1c4,
-       0x1d8
-};
-
-static const u32 event_cntr_data_offset[] = {
-       0x1dc,
-       0x1ac,
-       0x1ac,
-       0x1ac,
-       0x1c8,
-       0x1dc
-};
-
 struct tegra_pcie_dw {
        struct device *dev;
        struct resource *appl_res;
@@ -313,104 +293,6 @@ struct tegra_pcie_dw_of_data {
        enum dw_pcie_device_mode mode;
 };
 
-#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
-struct tegra194_pcie_ecam  {
-       void __iomem *config_base;
-       void __iomem *iatu_base;
-       void __iomem *dbi_base;
-};
-
-static int tegra194_acpi_init(struct pci_config_window *cfg)
-{
-       struct device *dev = cfg->parent;
-       struct tegra194_pcie_ecam *pcie_ecam;
-
-       pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
-       if (!pcie_ecam)
-               return -ENOMEM;
-
-       pcie_ecam->config_base = cfg->win;
-       pcie_ecam->iatu_base = cfg->win + SZ_256K;
-       pcie_ecam->dbi_base = cfg->win + SZ_512K;
-       cfg->priv = pcie_ecam;
-
-       return 0;
-}
-
-static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
-                         u32 val, u32 reg)
-{
-       u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-
-       writel(val, pcie_ecam->iatu_base + offset + reg);
-}
-
-static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
-                                int index, int type, u64 cpu_addr,
-                                u64 pci_addr, u64 size)
-{
-       atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
-                     PCIE_ATU_LOWER_BASE);
-       atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
-                     PCIE_ATU_UPPER_BASE);
-       atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
-                     PCIE_ATU_LOWER_TARGET);
-       atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
-                     PCIE_ATU_LIMIT);
-       atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
-                     PCIE_ATU_UPPER_TARGET);
-       atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1);
-       atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
-}
-
-static void __iomem *tegra194_map_bus(struct pci_bus *bus,
-                                     unsigned int devfn, int where)
-{
-       struct pci_config_window *cfg = bus->sysdata;
-       struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
-       u32 busdev;
-       int type;
-
-       if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
-               return NULL;
-
-       if (bus->number == cfg->busr.start) {
-               if (PCI_SLOT(devfn) == 0)
-                       return pcie_ecam->dbi_base + where;
-               else
-                       return NULL;
-       }
-
-       busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
-                PCIE_ATU_FUNC(PCI_FUNC(devfn));
-
-       if (bus->parent->number == cfg->busr.start) {
-               if (PCI_SLOT(devfn) == 0)
-                       type = PCIE_ATU_TYPE_CFG0;
-               else
-                       return NULL;
-       } else {
-               type = PCIE_ATU_TYPE_CFG1;
-       }
-
-       program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
-                            SZ_256K);
-
-       return pcie_ecam->config_base + where;
-}
-
-const struct pci_ecam_ops tegra194_pcie_ops = {
-       .init           = tegra194_acpi_init,
-       .pci_ops        = {
-               .map_bus        = tegra194_map_bus,
-               .read           = pci_generic_config_read,
-               .write          = pci_generic_config_write,
-       }
-};
-#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
-
-#ifdef CONFIG_PCIE_TEGRA194
-
 static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
 {
        return container_of(pci, struct tegra_pcie_dw, pci);
@@ -694,6 +576,24 @@ static struct pci_ops tegra_pci_ops = {
 };
 
 #if defined(CONFIG_PCIEASPM)
+static const u32 event_cntr_ctrl_offset[] = {
+       0x1d8,
+       0x1a8,
+       0x1a8,
+       0x1a8,
+       0x1c4,
+       0x1d8
+};
+
+static const u32 event_cntr_data_offset[] = {
+       0x1dc,
+       0x1ac,
+       0x1ac,
+       0x1ac,
+       0x1c8,
+       0x1dc
+};
+
 static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
 {
        u32 val;
@@ -2411,5 +2311,3 @@ MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);
 MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
 MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
 MODULE_LICENSE("GPL v2");
-
-#endif /* CONFIG_PCIE_TEGRA194 */
index 051b48b..e3f5e7a 100644 (file)
@@ -514,7 +514,7 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
                udelay(PIO_RETRY_DELAY);
        }
 
-       dev_err(dev, "config read/write timed out\n");
+       dev_err(dev, "PIO read/write transfer time out\n");
        return -ETIMEDOUT;
 }
 
@@ -657,6 +657,35 @@ static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
        return true;
 }
 
+static bool advk_pcie_pio_is_running(struct advk_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+
+       /*
+        * Trying to start a new PIO transfer when previous has not completed
+        * cause External Abort on CPU which results in kernel panic:
+        *
+        *     SError Interrupt on CPU0, code 0xbf000002 -- SError
+        *     Kernel panic - not syncing: Asynchronous SError Interrupt
+        *
+        * Functions advk_pcie_rd_conf() and advk_pcie_wr_conf() are protected
+        * by raw_spin_lock_irqsave() at pci_lock_config() level to prevent
+        * concurrent calls at the same time. But because PIO transfer may take
+        * about 1.5s when link is down or card is disconnected, it means that
+        * advk_pcie_wait_pio() does not always have to wait for completion.
+        *
+        * Some versions of ARM Trusted Firmware handles this External Abort at
+        * EL3 level and mask it to prevent kernel panic. Relevant TF-A commit:
+        * https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=3c7dcdac5c50
+        */
+       if (advk_readl(pcie, PIO_START)) {
+               dev_err(dev, "Previous PIO read/write transfer is still running\n");
+               return true;
+       }
+
+       return false;
+}
+
 static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
                             int where, int size, u32 *val)
 {
@@ -673,9 +702,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
                return pci_bridge_emul_conf_read(&pcie->bridge, where,
                                                 size, val);
 
-       /* Start PIO */
-       advk_writel(pcie, 0, PIO_START);
-       advk_writel(pcie, 1, PIO_ISR);
+       if (advk_pcie_pio_is_running(pcie)) {
+               *val = 0xffffffff;
+               return PCIBIOS_SET_FAILED;
+       }
 
        /* Program the control register */
        reg = advk_readl(pcie, PIO_CTRL);
@@ -694,7 +724,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
        /* Program the data strobe */
        advk_writel(pcie, 0xf, PIO_WR_DATA_STRB);
 
-       /* Start the transfer */
+       /* Clear PIO DONE ISR and start the transfer */
+       advk_writel(pcie, 1, PIO_ISR);
        advk_writel(pcie, 1, PIO_START);
 
        ret = advk_pcie_wait_pio(pcie);
@@ -734,9 +765,8 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
        if (where % size)
                return PCIBIOS_SET_FAILED;
 
-       /* Start PIO */
-       advk_writel(pcie, 0, PIO_START);
-       advk_writel(pcie, 1, PIO_ISR);
+       if (advk_pcie_pio_is_running(pcie))
+               return PCIBIOS_SET_FAILED;
 
        /* Program the control register */
        reg = advk_readl(pcie, PIO_CTRL);
@@ -763,7 +793,8 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
        /* Program the data strobe */
        advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB);
 
-       /* Start the transfer */
+       /* Clear PIO DONE ISR and start the transfer */
+       advk_writel(pcie, 1, PIO_ISR);
        advk_writel(pcie, 1, PIO_START);
 
        ret = advk_pcie_wait_pio(pcie);
index 6511648..bebe3ee 100644 (file)
@@ -3476,6 +3476,9 @@ static void __exit exit_hv_pci_drv(void)
 
 static int __init init_hv_pci_drv(void)
 {
+       if (!hv_is_hyperv_initialized())
+               return -ENODEV;
+
        /* Set the invalid domain number's bit, so it will not be used */
        set_bit(HVPCI_DOM_INVALID, hvpci_dom_map);
 
index 85dcb70..a143b02 100644 (file)
@@ -353,6 +353,8 @@ static int devm_of_pci_get_host_bridge_resources(struct device *dev,
                                dev_warn(dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
                                         dev_node);
                        *io_base = range.cpu_addr;
+               } else if (resource_type(res) == IORESOURCE_MEM) {
+                       res->flags &= ~IORESOURCE_MEM_64;
                }
 
                pci_add_resource_offset(resources, res, res->start - range.pci_addr);
index b717680..8d4ebe0 100644 (file)
@@ -1900,11 +1900,21 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
        int err;
        int i, bars = 0;
 
-       if (atomic_inc_return(&dev->enable_cnt) > 1) {
-               pci_update_current_state(dev, dev->current_state);
-               return 0;               /* already enabled */
+       /*
+        * Power state could be unknown at this point, either due to a fresh
+        * boot or a device removal call.  So get the current power state
+        * so that things like MSI message writing will behave as expected
+        * (e.g. if the device really is in D0 at enable time).
+        */
+       if (dev->pm_cap) {
+               u16 pmcsr;
+               pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+               dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
        }
 
+       if (atomic_inc_return(&dev->enable_cnt) > 1)
+               return 0;               /* already enabled */
+
        bridge = pci_upstream_bridge(dev);
        if (bridge)
                pci_enable_bridge(bridge);
index dcb229d..22b2bb1 100644 (file)
@@ -3547,6 +3547,18 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
 }
 
 /*
+ * Some NVIDIA GPU devices do not work with bus reset, SBR needs to be
+ * prevented for those affected devices.
+ */
+static void quirk_nvidia_no_bus_reset(struct pci_dev *dev)
+{
+       if ((dev->device & 0xffc0) == 0x2340)
+               quirk_no_bus_reset(dev);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+                        quirk_nvidia_no_bus_reset);
+
+/*
  * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
  * The device will throw a Link Down error on AER-capable systems and
  * regardless of AER, config space of the device is never accessible again
@@ -3566,6 +3578,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
 
+/*
+ * Some TI KeyStone C667X devices do not support bus/hot reset.  The PCIESS
+ * automatically disables LTSSM when Secondary Bus Reset is received and
+ * the device stops working.  Prevent bus reset for these devices.  With
+ * this change, the device can be assigned to VMs with VFIO, but it will
+ * leak state between VMs.  Reference
+ * https://e2e.ti.com/support/processors/f/791/t/954382
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0xb005, quirk_no_bus_reset);
+
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
        /*
@@ -3901,6 +3923,69 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
        return 0;
 }
 
+#define PCI_DEVICE_ID_HINIC_VF      0x375E
+#define HINIC_VF_FLR_TYPE           0x1000
+#define HINIC_VF_FLR_CAP_BIT        (1UL << 30)
+#define HINIC_VF_OP                 0xE80
+#define HINIC_VF_FLR_PROC_BIT       (1UL << 18)
+#define HINIC_OPERATION_TIMEOUT     15000      /* 15 seconds */
+
+/* Device-specific reset method for Huawei Intelligent NIC virtual functions */
+static int reset_hinic_vf_dev(struct pci_dev *pdev, int probe)
+{
+       unsigned long timeout;
+       void __iomem *bar;
+       u32 val;
+
+       if (probe)
+               return 0;
+
+       bar = pci_iomap(pdev, 0, 0);
+       if (!bar)
+               return -ENOTTY;
+
+       /* Get and check firmware capabilities */
+       val = ioread32be(bar + HINIC_VF_FLR_TYPE);
+       if (!(val & HINIC_VF_FLR_CAP_BIT)) {
+               pci_iounmap(pdev, bar);
+               return -ENOTTY;
+       }
+
+       /* Set HINIC_VF_FLR_PROC_BIT for the start of FLR */
+       val = ioread32be(bar + HINIC_VF_OP);
+       val = val | HINIC_VF_FLR_PROC_BIT;
+       iowrite32be(val, bar + HINIC_VF_OP);
+
+       pcie_flr(pdev);
+
+       /*
+        * The device must recapture its Bus and Device Numbers after FLR
+        * in order generate Completions.  Issue a config write to let the
+        * device capture this information.
+        */
+       pci_write_config_word(pdev, PCI_VENDOR_ID, 0);
+
+       /* Firmware clears HINIC_VF_FLR_PROC_BIT when reset is complete */
+       timeout = jiffies + msecs_to_jiffies(HINIC_OPERATION_TIMEOUT);
+       do {
+               val = ioread32be(bar + HINIC_VF_OP);
+               if (!(val & HINIC_VF_FLR_PROC_BIT))
+                       goto reset_complete;
+               msleep(20);
+       } while (time_before(jiffies, timeout));
+
+       val = ioread32be(bar + HINIC_VF_OP);
+       if (!(val & HINIC_VF_FLR_PROC_BIT))
+               goto reset_complete;
+
+       pci_warn(pdev, "Reset dev timeout, FLR ack reg: %#010x\n", val);
+
+reset_complete:
+       pci_iounmap(pdev, bar);
+
+       return 0;
+}
+
 static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
                 reset_intel_82599_sfp_virtfn },
@@ -3913,6 +3998,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
        { PCI_VENDOR_ID_INTEL, 0x0a54, delay_250ms_after_flr },
        { PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
                reset_chelsio_generic_dev },
+       { PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
+               reset_hinic_vf_dev },
        { 0 }
 };
 
@@ -4753,6 +4840,8 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
        { PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
        { PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
+       /* Broadcom multi-function device */
+       { PCI_VENDOR_ID_BROADCOM, 0x16D7, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
        /* Amazon Annapurna Labs */
        { PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs },
@@ -5154,7 +5243,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags);
 static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
 {
        if ((pdev->device == 0x7312 && pdev->revision != 0x00) ||
-           (pdev->device == 0x7340 && pdev->revision != 0xc5))
+           (pdev->device == 0x7340 && pdev->revision != 0xc5) ||
+           (pdev->device == 0x7341 && pdev->revision != 0x00))
                return;
 
        if (pdev->device == 0x15d8) {
@@ -5181,6 +5271,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
 /* AMD Navi14 dGPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7341, quirk_amd_harvest_no_ats);
 /* AMD Raven platform iGPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
 #endif /* CONFIG_PCI_ATS */
index 666d8a9..54aca3a 100644 (file)
@@ -37,7 +37,7 @@
 
 #define CCI_PMU_CNTR_SIZE(model)       ((model)->cntr_size)
 #define CCI_PMU_CNTR_BASE(model, idx)  ((idx) * CCI_PMU_CNTR_SIZE(model))
-#define CCI_PMU_CNTR_MASK              ((1ULL << 32) -1)
+#define CCI_PMU_CNTR_MASK              ((1ULL << 32) - 1)
 #define CCI_PMU_CNTR_LAST(cci_pmu)     (cci_pmu->num_cntrs - 1)
 
 #define CCI_PMU_MAX_HW_CNTRS(model) \
@@ -806,7 +806,7 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
                return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
 
        /* Generic code to find an unused idx from the mask */
-       for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
+       for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
                if (!test_and_set_bit(idx, hw->used_mask))
                        return idx;
 
index 96d47cb..a96c316 100644 (file)
@@ -1211,7 +1211,7 @@ static int arm_ccn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
        perf_pmu_migrate_context(&dt->pmu, cpu, target);
        dt->cpu = target;
        if (ccn->irq)
-               WARN_ON(irq_set_affinity_hint(ccn->irq, cpumask_of(dt->cpu)));
+               WARN_ON(irq_set_affinity(ccn->irq, cpumask_of(dt->cpu)));
        return 0;
 }
 
@@ -1291,7 +1291,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
 
        /* Also make sure that the overflow interrupt is handled by this CPU */
        if (ccn->irq) {
-               err = irq_set_affinity_hint(ccn->irq, cpumask_of(ccn->dt.cpu));
+               err = irq_set_affinity(ccn->irq, cpumask_of(ccn->dt.cpu));
                if (err) {
                        dev_err(ccn->dev, "Failed to set interrupt affinity!\n");
                        goto error_set_affinity;
@@ -1325,8 +1325,6 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
 
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE,
                                            &ccn->dt.node);
-       if (ccn->irq)
-               irq_set_affinity_hint(ccn->irq, NULL);
        for (i = 0; i < ccn->num_xps; i++)
                writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
        writel(0, ccn->dt.base + CCN_DT_PMCR);
index 56a5c35..bc3cba5 100644 (file)
@@ -31,7 +31,7 @@
 #define CMN_CI_CHILD_COUNT             GENMASK_ULL(15, 0)
 #define CMN_CI_CHILD_PTR_OFFSET                GENMASK_ULL(31, 16)
 
-#define CMN_CHILD_NODE_ADDR            GENMASK(27,0)
+#define CMN_CHILD_NODE_ADDR            GENMASK(27, 0)
 #define CMN_CHILD_NODE_EXTERNAL                BIT(31)
 
 #define CMN_ADDR_NODE_PTR              GENMASK(27, 14)
@@ -1162,7 +1162,7 @@ static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
 
        perf_pmu_migrate_context(&cmn->pmu, cpu, target);
        for (i = 0; i < cmn->num_dtcs; i++)
-               irq_set_affinity_hint(cmn->dtc[i].irq, cpumask_of(target));
+               irq_set_affinity(cmn->dtc[i].irq, cpumask_of(target));
        cmn->cpu = target;
        return 0;
 }
@@ -1212,7 +1212,7 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
                irq = cmn->dtc[i].irq;
                for (j = i; j--; ) {
                        if (cmn->dtc[j].irq == irq) {
-                               cmn->dtc[j].irq_friend = j - i;
+                               cmn->dtc[j].irq_friend = i - j;
                                goto next;
                        }
                }
@@ -1222,7 +1222,7 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
                if (err)
                        return err;
 
-               err = irq_set_affinity_hint(irq, cpumask_of(cmn->cpu));
+               err = irq_set_affinity(irq, cpumask_of(cmn->cpu));
                if (err)
                        return err;
        next:
@@ -1568,16 +1568,11 @@ static int arm_cmn_probe(struct platform_device *pdev)
 static int arm_cmn_remove(struct platform_device *pdev)
 {
        struct arm_cmn *cmn = platform_get_drvdata(pdev);
-       int i;
 
        writel_relaxed(0, cmn->dtc[0].base + CMN_DT_DTC_CTL);
 
        perf_pmu_unregister(&cmn->pmu);
        cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
-
-       for (i = 0; i < cmn->num_dtcs; i++)
-               irq_set_affinity_hint(cmn->dtc[i].irq, NULL);
-
        return 0;
 }
 
index b6c2511..280a6ae 100644 (file)
@@ -421,7 +421,7 @@ static struct dmc620_pmu_irq *__dmc620_pmu_get_irq(int irq_num)
        if (ret)
                goto out_free_aff;
 
-       ret = irq_set_affinity_hint(irq_num, cpumask_of(irq->cpu));
+       ret = irq_set_affinity(irq_num, cpumask_of(irq->cpu));
        if (ret)
                goto out_free_irq;
 
@@ -475,7 +475,6 @@ static void dmc620_pmu_put_irq(struct dmc620_pmu *dmc620_pmu)
        list_del(&irq->irqs_node);
        mutex_unlock(&dmc620_pmu_irqs_lock);
 
-       WARN_ON(irq_set_affinity_hint(irq->irq_num, NULL));
        free_irq(irq->irq_num, irq);
        cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &irq->node);
        kfree(irq);
@@ -622,7 +621,7 @@ static int dmc620_pmu_cpu_teardown(unsigned int cpu,
                perf_pmu_migrate_context(&dmc620_pmu->pmu, irq->cpu, target);
        mutex_unlock(&dmc620_pmu_irqs_lock);
 
-       WARN_ON(irq_set_affinity_hint(irq->irq_num, cpumask_of(target)));
+       WARN_ON(irq_set_affinity(irq->irq_num, cpumask_of(target)));
        irq->cpu = target;
 
        return 0;
index 196faea..a36698a 100644 (file)
@@ -687,7 +687,7 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
 static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
 {
        cpumask_set_cpu(cpu, &dsu_pmu->active_cpu);
-       if (irq_set_affinity_hint(dsu_pmu->irq, &dsu_pmu->active_cpu))
+       if (irq_set_affinity(dsu_pmu->irq, &dsu_pmu->active_cpu))
                pr_warn("Failed to set irq affinity to %d\n", cpu);
 }
 
@@ -769,7 +769,6 @@ static int dsu_pmu_device_probe(struct platform_device *pdev)
        if (rc) {
                cpuhp_state_remove_instance(dsu_pmu_cpuhp_state,
                                                 &dsu_pmu->cpuhp_node);
-               irq_set_affinity_hint(dsu_pmu->irq, NULL);
        }
 
        return rc;
@@ -781,7 +780,6 @@ static int dsu_pmu_device_remove(struct platform_device *pdev)
 
        perf_pmu_unregister(&dsu_pmu->pmu);
        cpuhp_state_remove_instance(dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node);
-       irq_set_affinity_hint(dsu_pmu->irq, NULL);
 
        return 0;
 }
@@ -840,10 +838,8 @@ static int dsu_pmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
 
        dst = dsu_pmu_get_online_cpu_any_but(dsu_pmu, cpu);
        /* If there are no active CPUs in the DSU, leave IRQ disabled */
-       if (dst >= nr_cpu_ids) {
-               irq_set_affinity_hint(dsu_pmu->irq, NULL);
+       if (dst >= nr_cpu_ids)
                return 0;
-       }
 
        perf_pmu_migrate_context(&dsu_pmu->pmu, cpu, dst);
        dsu_pmu_set_active_cpu(dst, dsu_pmu);
index d4f7f1f..3cbc3ba 100644 (file)
@@ -563,14 +563,14 @@ static int armpmu_filter_match(struct perf_event *event)
        return ret;
 }
 
-static ssize_t armpmu_cpumask_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t cpus_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct arm_pmu *armpmu = to_arm_pmu(dev_get_drvdata(dev));
        return cpumap_print_to_pagebuf(true, buf, &armpmu->supported_cpus);
 }
 
-static DEVICE_ATTR(cpus, S_IRUGO, armpmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpus);
 
 static struct attribute *armpmu_common_attrs[] = {
        &dev_attr_cpus.attr,
@@ -644,11 +644,9 @@ int armpmu_request_irq(int irq, int cpu)
                }
 
                irq_flags = IRQF_PERCPU |
-                           IRQF_NOBALANCING |
+                           IRQF_NOBALANCING | IRQF_NO_AUTOEN |
                            IRQF_NO_THREAD;
 
-               irq_set_status_flags(irq, IRQ_NOAUTOEN);
-
                err = request_nmi(irq, handler, irq_flags, "arm-pmu",
                                  per_cpu_ptr(&cpu_armpmu, cpu));
 
@@ -670,7 +668,7 @@ int armpmu_request_irq(int irq, int cpu)
                                                 &cpu_armpmu);
                        irq_ops = &percpu_pmuirq_ops;
                } else {
-                       has_nmi= true;
+                       has_nmi = true;
                        irq_ops = &percpu_pmunmi_ops;
                }
        } else {
@@ -869,10 +867,8 @@ static struct arm_pmu *__armpmu_alloc(gfp_t flags)
        int cpu;
 
        pmu = kzalloc(sizeof(*pmu), flags);
-       if (!pmu) {
-               pr_info("failed to allocate PMU device!\n");
+       if (!pmu)
                goto out;
-       }
 
        pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
        if (!pmu->hw_events) {
index ff6fab4..2263488 100644 (file)
@@ -277,7 +277,7 @@ static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
                                       struct perf_event *event, int idx)
 {
        u32 span, sid;
-       unsigned int num_ctrs = smmu_pmu->num_counters;
+       unsigned int cur_idx, num_ctrs = smmu_pmu->num_counters;
        bool filter_en = !!get_filter_enable(event);
 
        span = filter_en ? get_filter_span(event) :
@@ -285,17 +285,19 @@ static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
        sid = filter_en ? get_filter_stream_id(event) :
                           SMMU_PMCG_DEFAULT_FILTER_SID;
 
-       /* Support individual filter settings */
-       if (!smmu_pmu->global_filter) {
+       cur_idx = find_first_bit(smmu_pmu->used_counters, num_ctrs);
+       /*
+        * Per-counter filtering, or scheduling the first globally-filtered
+        * event into an empty PMU so idx == 0 and it works out equivalent.
+        */
+       if (!smmu_pmu->global_filter || cur_idx == num_ctrs) {
                smmu_pmu_set_event_filter(event, idx, span, sid);
                return 0;
        }
 
-       /* Requested settings same as current global settings*/
-       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);
+       /* Otherwise, must match whatever's currently scheduled */
+       if (smmu_pmu_check_global_filter(smmu_pmu->events[cur_idx], event)) {
+               smmu_pmu_set_evtyper(smmu_pmu, idx, get_event(event));
                return 0;
        }
 
@@ -509,11 +511,8 @@ static ssize_t smmu_pmu_event_show(struct device *dev,
        return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
 }
 
-#define SMMU_EVENT_ATTR(name, config)                                  \
-       (&((struct perf_pmu_events_attr) {                              \
-               .attr = __ATTR(name, 0444, smmu_pmu_event_show, NULL),  \
-               .id = config,                                           \
-       }).attr.attr)
+#define SMMU_EVENT_ATTR(name, config)                  \
+       PMU_EVENT_ATTR_ID(name, smmu_pmu_event_show, config)
 
 static struct attribute *smmu_pmu_events[] = {
        SMMU_EVENT_ATTR(cycles, 0),
@@ -628,7 +627,7 @@ static int smmu_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
 
        perf_pmu_migrate_context(&smmu_pmu->pmu, cpu, target);
        smmu_pmu->on_cpu = target;
-       WARN_ON(irq_set_affinity_hint(smmu_pmu->irq, cpumask_of(target)));
+       WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(target)));
 
        return 0;
 }
@@ -839,15 +838,14 @@ static int smmu_pmu_probe(struct platform_device *pdev)
 
        /* Pick one CPU to be the preferred one to use */
        smmu_pmu->on_cpu = raw_smp_processor_id();
-       WARN_ON(irq_set_affinity_hint(smmu_pmu->irq,
-                                     cpumask_of(smmu_pmu->on_cpu)));
+       WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(smmu_pmu->on_cpu)));
 
        err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
                                               &smmu_pmu->node);
        if (err) {
                dev_err(dev, "Error %d registering hotplug, PMU @%pa\n",
                        err, &res_0->start);
-               goto out_clear_affinity;
+               return err;
        }
 
        err = perf_pmu_register(&smmu_pmu->pmu, name, -1);
@@ -866,8 +864,6 @@ static int smmu_pmu_probe(struct platform_device *pdev)
 
 out_unregister:
        cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &smmu_pmu->node);
-out_clear_affinity:
-       irq_set_affinity_hint(smmu_pmu->irq, NULL);
        return err;
 }
 
@@ -877,7 +873,6 @@ static int smmu_pmu_remove(struct platform_device *pdev)
 
        perf_pmu_unregister(&smmu_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &smmu_pmu->node);
-       irq_set_affinity_hint(smmu_pmu->irq, NULL);
 
        return 0;
 }
index 8a1e86a..d44bcc2 100644 (file)
@@ -231,15 +231,14 @@ static const struct attribute_group arm_spe_pmu_format_group = {
        .attrs  = arm_spe_pmu_formats_attr,
 };
 
-static ssize_t arm_spe_pmu_get_attr_cpumask(struct device *dev,
-                                           struct device_attribute *attr,
-                                           char *buf)
+static ssize_t cpumask_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
 
        return cpumap_print_to_pagebuf(true, buf, &spe_pmu->supported_cpus);
 }
-static DEVICE_ATTR(cpumask, S_IRUGO, arm_spe_pmu_get_attr_cpumask, NULL);
+static DEVICE_ATTR_RO(cpumask);
 
 static struct attribute *arm_spe_pmu_attrs[] = {
        &dev_attr_cpumask.attr,
@@ -1044,7 +1043,6 @@ static void __arm_spe_pmu_dev_probe(void *info)
                 spe_pmu->max_record_sz, spe_pmu->align, spe_pmu->features);
 
        spe_pmu->features |= SPE_PMU_FEAT_DEV_PROBED;
-       return;
 }
 
 static void __arm_spe_pmu_reset_local(void)
@@ -1190,10 +1188,8 @@ static int arm_spe_pmu_device_probe(struct platform_device *pdev)
        }
 
        spe_pmu = devm_kzalloc(dev, sizeof(*spe_pmu), GFP_KERNEL);
-       if (!spe_pmu) {
-               dev_err(dev, "failed to allocate spe_pmu\n");
+       if (!spe_pmu)
                return -ENOMEM;
-       }
 
        spe_pmu->handle = alloc_percpu(typeof(*spe_pmu->handle));
        if (!spe_pmu->handle)
index 2bbb931..94ebc1e 100644 (file)
@@ -222,11 +222,8 @@ ddr_pmu_event_show(struct device *dev, struct device_attribute *attr,
        return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
 }
 
-#define IMX8_DDR_PMU_EVENT_ATTR(_name, _id)                            \
-       (&((struct perf_pmu_events_attr[]) {                            \
-               { .attr = __ATTR(_name, 0444, ddr_pmu_event_show, NULL),\
-                 .id = _id, }                                          \
-       })[0].attr.attr)
+#define IMX8_DDR_PMU_EVENT_ATTR(_name, _id)            \
+       PMU_EVENT_ATTR_ID(_name, ddr_pmu_event_show, _id)
 
 static struct attribute *ddr_perf_events_attrs[] = {
        IMX8_DDR_PMU_EVENT_ATTR(cycles, EVENT_CYCLES_ID),
@@ -674,7 +671,7 @@ static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
        perf_pmu_migrate_context(&pmu->pmu, cpu, target);
        pmu->cpu = target;
 
-       WARN_ON(irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu)));
+       WARN_ON(irq_set_affinity(pmu->irq, cpumask_of(pmu->cpu)));
 
        return 0;
 }
@@ -705,8 +702,10 @@ static int ddr_perf_probe(struct platform_device *pdev)
 
        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d",
                              num);
-       if (!name)
-               return -ENOMEM;
+       if (!name) {
+               ret = -ENOMEM;
+               goto cpuhp_state_err;
+       }
 
        pmu->devtype_data = of_device_get_match_data(&pdev->dev);
 
@@ -749,7 +748,7 @@ static int ddr_perf_probe(struct platform_device *pdev)
        }
 
        pmu->irq = irq;
-       ret = irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu));
+       ret = irq_set_affinity(pmu->irq, cpumask_of(pmu->cpu));
        if (ret) {
                dev_err(pmu->dev, "Failed to set interrupt affinity!\n");
                goto ddr_perf_err;
@@ -777,7 +776,6 @@ static int ddr_perf_remove(struct platform_device *pdev)
 
        cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
        cpuhp_remove_multi_state(pmu->cpuhp_state);
-       irq_set_affinity_hint(pmu->irq, NULL);
 
        perf_pmu_unregister(&pmu->pmu);
 
index 7c8a4bc..62299ab 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SoC DDRC uncore Hardware event counters support
  *
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
  * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
  *         Anurup M <anurup.m@huawei.com>
  *
@@ -537,7 +537,6 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
                dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
                cpuhp_state_remove_instance_nocalls(
                        CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
-               irq_set_affinity_hint(ddrc_pmu->irq, NULL);
        }
 
        return ret;
@@ -550,8 +549,6 @@ static int hisi_ddrc_pmu_remove(struct platform_device *pdev)
        perf_pmu_unregister(&ddrc_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
                                            &ddrc_pmu->node);
-       irq_set_affinity_hint(ddrc_pmu->irq, NULL);
-
        return 0;
 }
 
index 0316fab..3935131 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SoC HHA uncore Hardware event counters support
  *
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
  * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
  *         Anurup M <anurup.m@huawei.com>
  *
@@ -90,7 +90,7 @@ static void hisi_hha_pmu_config_ds(struct perf_event *event)
 
                val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
                val |= HHA_DATSRC_SKT_EN;
-               writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+               writel(val, hha_pmu->base + HHA_DATSRC_CTRL);
        }
 }
 
@@ -104,7 +104,7 @@ static void hisi_hha_pmu_clear_ds(struct perf_event *event)
 
                val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
                val &= ~HHA_DATSRC_SKT_EN;
-               writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+               writel(val, hha_pmu->base + HHA_DATSRC_CTRL);
        }
 }
 
@@ -540,7 +540,6 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
                dev_err(hha_pmu->dev, "HHA PMU register failed!\n");
                cpuhp_state_remove_instance_nocalls(
                        CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node);
-               irq_set_affinity_hint(hha_pmu->irq, NULL);
        }
 
        return ret;
@@ -553,8 +552,6 @@ static int hisi_hha_pmu_remove(struct platform_device *pdev)
        perf_pmu_unregister(&hha_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
                                            &hha_pmu->node);
-       irq_set_affinity_hint(hha_pmu->irq, NULL);
-
        return 0;
 }
 
index bf9f777..560ab96 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SoC L3C uncore Hardware event counters support
  *
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
  * Author: Anurup M <anurup.m@huawei.com>
  *         Shaokun Zhang <zhangshaokun@hisilicon.com>
  *
@@ -578,7 +578,6 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
                dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");
                cpuhp_state_remove_instance_nocalls(
                        CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node);
-               irq_set_affinity_hint(l3c_pmu->irq, NULL);
        }
 
        return ret;
@@ -591,8 +590,6 @@ static int hisi_l3c_pmu_remove(struct platform_device *pdev)
        perf_pmu_unregister(&l3c_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
                                            &l3c_pmu->node);
-       irq_set_affinity_hint(l3c_pmu->irq, NULL);
-
        return 0;
 }
 
index 14f23eb..83264ec 100644 (file)
@@ -333,7 +333,7 @@ static struct attribute *hisi_pa_pmu_identifier_attrs[] = {
        NULL
 };
 
-static struct attribute_group hisi_pa_pmu_identifier_group = {
+static const struct attribute_group hisi_pa_pmu_identifier_group = {
        .attrs = hisi_pa_pmu_identifier_attrs,
 };
 
@@ -436,7 +436,6 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
                dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
                cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
                                            &pa_pmu->node);
-               irq_set_affinity_hint(pa_pmu->irq, NULL);
                return ret;
        }
 
@@ -451,8 +450,6 @@ static int hisi_pa_pmu_remove(struct platform_device *pdev)
        perf_pmu_unregister(&pa_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
                                            &pa_pmu->node);
-       irq_set_affinity_hint(pa_pmu->irq, NULL);
-
        return 0;
 }
 
index 13c68b5..a738aea 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SoC Hardware event counters support
  *
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
  * Author: Anurup M <anurup.m@huawei.com>
  *         Shaokun Zhang <zhangshaokun@hisilicon.com>
  *
@@ -488,7 +488,7 @@ int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
        hisi_pmu->on_cpu = cpu;
 
        /* Overflow interrupt also should use the same CPU */
-       WARN_ON(irq_set_affinity_hint(hisi_pmu->irq, cpumask_of(cpu)));
+       WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(cpu)));
 
        return 0;
 }
@@ -521,7 +521,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
        perf_pmu_migrate_context(&hisi_pmu->pmu, cpu, target);
        /* Use this CPU for event counting */
        hisi_pmu->on_cpu = target;
-       WARN_ON(irq_set_affinity_hint(hisi_pmu->irq, cpumask_of(target)));
+       WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(target)));
 
        return 0;
 }
index ea9d89b..7f5841d 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SoC Hardware event counters support
  *
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
  * Author: Anurup M <anurup.m@huawei.com>
  *         Shaokun Zhang <zhangshaokun@hisilicon.com>
  *
index 46be312..6aedc30 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * HiSilicon SLLC uncore Hardware event counters support
  *
- * Copyright (C) 2020 Hisilicon Limited
+ * Copyright (C) 2020 HiSilicon Limited
  * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
  *
  * This code is based on the uncore PMUs like arm-cci and arm-ccn.
@@ -366,7 +366,7 @@ static struct attribute *hisi_sllc_pmu_identifier_attrs[] = {
        NULL
 };
 
-static struct attribute_group hisi_sllc_pmu_identifier_group = {
+static const struct attribute_group hisi_sllc_pmu_identifier_group = {
        .attrs = hisi_sllc_pmu_identifier_attrs,
 };
 
@@ -465,7 +465,6 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
                dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
                cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
                                            &sllc_pmu->node);
-               irq_set_affinity_hint(sllc_pmu->irq, NULL);
                return ret;
        }
 
@@ -481,8 +480,6 @@ static int hisi_sllc_pmu_remove(struct platform_device *pdev)
        perf_pmu_unregister(&sllc_pmu->pmu);
        cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
                                            &sllc_pmu->node);
-       irq_set_affinity_hint(sllc_pmu->irq, NULL);
-
        return 0;
 }
 
index fc54a80..5b093ba 100644 (file)
@@ -679,11 +679,8 @@ static ssize_t l2cache_pmu_event_show(struct device *dev,
        return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
 }
 
-#define L2CACHE_EVENT_ATTR(_name, _id)                                      \
-       (&((struct perf_pmu_events_attr[]) {                                 \
-               { .attr = __ATTR(_name, 0444, l2cache_pmu_event_show, NULL), \
-                 .id = _id, }                                               \
-       })[0].attr.attr)
+#define L2CACHE_EVENT_ATTR(_name, _id)                     \
+       PMU_EVENT_ATTR_ID(_name, l2cache_pmu_event_show, _id)
 
 static struct attribute *l2_cache_pmu_events[] = {
        L2CACHE_EVENT_ATTR(cycles, L2_EVENT_CYCLES),
@@ -869,14 +866,14 @@ static int l2_cache_pmu_probe_cluster(struct device *dev, void *data)
        irq = platform_get_irq(sdev, 0);
        if (irq < 0)
                return irq;
-       irq_set_status_flags(irq, IRQ_NOAUTOEN);
        cluster->irq = irq;
 
        cluster->l2cache_pmu = l2cache_pmu;
        cluster->on_cpu = -1;
 
        err = devm_request_irq(&pdev->dev, irq, l2_cache_handle_irq,
-                              IRQF_NOBALANCING | IRQF_NO_THREAD,
+                              IRQF_NOBALANCING | IRQF_NO_THREAD |
+                              IRQF_NO_AUTOEN,
                               "l2-cache-pmu", cluster);
        if (err) {
                dev_err(&pdev->dev,
index bba0780..1ff2ff6 100644 (file)
@@ -647,10 +647,7 @@ static ssize_t l3cache_pmu_event_show(struct device *dev,
 }
 
 #define L3CACHE_EVENT_ATTR(_name, _id)                                      \
-       (&((struct perf_pmu_events_attr[]) {                                 \
-               { .attr = __ATTR(_name, 0444, l3cache_pmu_event_show, NULL), \
-                 .id = _id, }                                               \
-       })[0].attr.attr)
+       PMU_EVENT_ATTR_ID(_name, l3cache_pmu_event_show, _id)
 
 static struct attribute *qcom_l3_cache_pmu_events[] = {
        L3CACHE_EVENT_ATTR(cycles, L3_EVENT_CYCLES),
@@ -670,15 +667,15 @@ static const struct attribute_group qcom_l3_cache_pmu_events_group = {
 
 /* cpumask */
 
-static ssize_t qcom_l3_cache_pmu_cpumask_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
+static ssize_t cpumask_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct l3cache_pmu *l3pmu = to_l3cache_pmu(dev_get_drvdata(dev));
 
        return cpumap_print_to_pagebuf(true, buf, &l3pmu->cpumask);
 }
 
-static DEVICE_ATTR(cpumask, 0444, qcom_l3_cache_pmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpumask);
 
 static struct attribute *qcom_l3_cache_pmu_cpumask_attrs[] = {
        &dev_attr_cpumask.attr,
@@ -767,10 +764,8 @@ static int qcom_l3_cache_pmu_probe(struct platform_device *pdev)
 
        memrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        l3pmu->regs = devm_ioremap_resource(&pdev->dev, memrc);
-       if (IS_ERR(l3pmu->regs)) {
-               dev_err(&pdev->dev, "Can't map PMU @%pa\n", &memrc->start);
+       if (IS_ERR(l3pmu->regs))
                return PTR_ERR(l3pmu->regs);
-       }
 
        qcom_l3_cache__init(l3pmu);
 
index 06a6d56..fc1a376 100644 (file)
@@ -817,10 +817,8 @@ static struct tx2_uncore_pmu *tx2_uncore_pmu_init_dev(struct device *dev,
        }
 
        base = devm_ioremap_resource(dev, &res);
-       if (IS_ERR(base)) {
-               dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+       if (IS_ERR(base))
                return NULL;
-       }
 
        tx2_pmu = devm_kzalloc(dev, sizeof(*tx2_pmu), GFP_KERNEL);
        if (!tx2_pmu)
index ffe3bde..2b6d476 100644 (file)
@@ -278,17 +278,14 @@ static const struct attribute_group mc_pmu_v3_format_attr_group = {
 static ssize_t xgene_pmu_event_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct dev_ext_attribute *eattr;
+       struct perf_pmu_events_attr *pmu_attr =
+               container_of(attr, struct perf_pmu_events_attr, attr);
 
-       eattr = container_of(attr, struct dev_ext_attribute, attr);
-       return sysfs_emit(buf, "config=0x%lx\n", (unsigned long) eattr->var);
+       return sysfs_emit(buf, "config=0x%llx\n", pmu_attr->id);
 }
 
 #define XGENE_PMU_EVENT_ATTR(_name, _config)           \
-       (&((struct dev_ext_attribute[]) {               \
-               { .attr = __ATTR(_name, S_IRUGO, xgene_pmu_event_show, NULL), \
-                 .var = (void *) _config, }            \
-        })[0].attr.attr)
+       PMU_EVENT_ATTR_ID(_name, xgene_pmu_event_show, _config)
 
 static struct attribute *l3c_pmu_events_attrs[] = {
        XGENE_PMU_EVENT_ATTR(cycle-count,                       0x00),
@@ -604,15 +601,15 @@ static const struct attribute_group mc_pmu_v3_events_attr_group = {
 /*
  * sysfs cpumask attributes
  */
-static ssize_t xgene_pmu_cpumask_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
+static ssize_t cpumask_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct xgene_pmu_dev *pmu_dev = to_pmu_dev(dev_get_drvdata(dev));
 
        return cpumap_print_to_pagebuf(true, buf, &pmu_dev->parent->cpu);
 }
 
-static DEVICE_ATTR(cpumask, S_IRUGO, xgene_pmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpumask);
 
 static struct attribute *xgene_pmu_cpumask_attrs[] = {
        &dev_attr_cpumask.attr,
index c12fa57..165cb7a 100644 (file)
@@ -845,8 +845,10 @@ static int microchip_sgpio_probe(struct platform_device *pdev)
        i = 0;
        device_for_each_child_node(dev, fwnode) {
                ret = microchip_sgpio_register_bank(dev, priv, fwnode, i++);
-               if (ret)
+               if (ret) {
+                       fwnode_handle_put(fwnode);
                        return ret;
+               }
        }
 
        if (priv->in.gpio.ngpio != priv->out.gpio.ngpio) {
index ad9eb5e..c14d12d 100644 (file)
@@ -1224,7 +1224,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
        struct device *dev = pctl->dev;
        struct resource res;
        int npins = STM32_GPIO_PINS_PER_BANK;
-       int bank_nr, err;
+       int bank_nr, err, i = 0;
 
        if (!IS_ERR(bank->rstc))
                reset_control_deassert(bank->rstc);
@@ -1246,9 +1246,14 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
 
        of_property_read_string(np, "st,bank-name", &bank->gpio_chip.label);
 
-       if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args)) {
+       if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, i, &args)) {
                bank_nr = args.args[1] / STM32_GPIO_PINS_PER_BANK;
                bank->gpio_chip.base = args.args[1];
+
+               npins = args.args[2];
+               while (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+                                                        ++i, &args))
+                       npins += args.args[2];
        } else {
                bank_nr = pctl->nbanks;
                bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK;
index 03a246e..21c4c34 100644 (file)
@@ -63,7 +63,7 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
        spin_unlock_irqrestore(&queue->lock, flags);
 }
 
-s32 scaled_ppm_to_ppb(long ppm)
+long scaled_ppm_to_ppb(long ppm)
 {
        /*
         * The 'freq' field in the 'struct timex' is in parts per
@@ -80,7 +80,7 @@ s32 scaled_ppm_to_ppb(long ppm)
        s64 ppb = 1 + ppm;
        ppb *= 125;
        ppb >>= 13;
-       return (s32) ppb;
+       return (long) ppb;
 }
 EXPORT_SYMBOL(scaled_ppm_to_ppb);
 
@@ -138,7 +138,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
                delta = ktime_to_ns(kt);
                err = ops->adjtime(ops, delta);
        } else if (tx->modes & ADJ_FREQUENCY) {
-               s32 ppb = scaled_ppm_to_ppb(tx->freq);
+               long ppb = scaled_ppm_to_ppb(tx->freq);
                if (ppb > ops->max_adj || ppb < -ops->max_adj)
                        return -ERANGE;
                if (ops->adjfine)
index 3e7a385..24ce9a1 100644 (file)
@@ -193,20 +193,10 @@ config REGULATOR_BCM590XX
          BCM590xx PMUs. This will enable support for the software
          controllable LDO/Switching regulators.
 
-config REGULATOR_BD70528
-       tristate "ROHM BD70528 Power Regulator"
-       depends on MFD_ROHM_BD70528
-       help
-         This driver supports voltage regulators on ROHM BD70528 PMIC.
-         This will enable support for the software controllable buck
-         and LDO regulators.
-
-         This driver can also be built as a module. If so, the module
-         will be called bd70528-regulator.
-
 config REGULATOR_BD71815
        tristate "ROHM BD71815 Power Regulator"
        depends on MFD_ROHM_BD71828
+       select REGULATOR_ROHM
        help
          This driver supports voltage regulators on ROHM BD71815 PMIC.
          This will enable support for the software controllable buck
@@ -588,6 +578,14 @@ config REGULATOR_MAX8660
          This driver controls a Maxim 8660/8661 voltage output
          regulator via I2C bus.
 
+config REGULATOR_MAX8893
+       tristate "Maxim 8893 voltage regulator"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This driver controls a Maxim 8893 voltage output
+         regulator via I2C bus.
+
 config REGULATOR_MAX8907
        tristate "Maxim 8907 voltage regulator"
        depends on MFD_MAX8907 || COMPILE_TEST
@@ -779,6 +777,15 @@ config REGULATOR_MT6358
          This driver supports the control of different power rails of device
          through regulator interface.
 
+config REGULATOR_MT6359
+       tristate "MediaTek MT6359 PMIC"
+       depends on MFD_MT6397
+       help
+         Say y here to select this option to enable the power regulator of
+         MediaTek MT6359 PMIC.
+         This driver supports the control of different power rails of device
+         through regulator interface.
+
 config REGULATOR_MT6360
        tristate "MT6360 SubPMIC Regulator"
        depends on MFD_MT6360
@@ -1030,6 +1037,26 @@ config REGULATOR_RT5033
          RT5033 PMIC. The device supports multiple regulators like
          current source, LDO and Buck.
 
+config REGULATOR_RT6160
+       tristate "Richtek RT6160 BuckBoost voltage regulator"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This adds support for voltage regulator in Richtek RT6160.
+         This device automatically change voltage output mode from
+         Buck or Boost. The mode transistion depend on the input source voltage.
+         The wide output range is from 2025mV to 5200mV and can be used on most
+         common application scenario.
+
+config REGULATOR_RT6245
+       tristate "Richtek RT6245 voltage regulator"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This adds supprot for Richtek RT6245 voltage regulator.
+         It can support up to 14A output current and adjustable output voltage
+         from 0.4375V to 1.3875V, per step 12.5mV.
+
 config REGULATOR_RTMV20
        tristate "Richtek RTMV20 Laser Diode Regulator"
        depends on I2C
@@ -1150,6 +1177,12 @@ config REGULATOR_STW481X_VMMC
          This driver supports the internal VMMC regulator in the STw481x
          PMIC chips.
 
+config REGULATOR_SY7636A
+       tristate "Silergy SY7636A voltage regulator"
+       depends on MFD_SY7636A
+       help
+         This driver supports Silergy SY3686A voltage regulator.
+
 config REGULATOR_SY8106A
        tristate "Silergy SY8106A regulator"
        depends on I2C && (OF || COMPILE_TEST)
index 580b015..8c2f822 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
@@ -29,7 +29,6 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
-obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
 obj-$(CONFIG_REGULATOR_BD71815)        += bd71815-regulator.o
 obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
 obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
@@ -72,6 +71,7 @@ obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
 obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8649)        += max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8893) += max8893.o
 obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
 obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
+obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
 obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
@@ -124,6 +125,8 @@ obj-$(CONFIG_REGULATOR_ROHM)        += rohm-regulator.o
 obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o
 obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o
 obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
+obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o
+obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o
 obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o
 obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
@@ -136,6 +139,7 @@ obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 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_SY7636A) += sy7636a-regulator.o
 obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
 obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o
 obj-$(CONFIG_REGULATOR_SY8827N) += sy8827n.o
diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c
deleted file mode 100644 (file)
index 1f5f948..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 ROHM Semiconductors
-// bd70528-regulator.c ROHM BD70528MWV regulator driver
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/rohm-bd70528.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/of_regulator.h>
-#include <linux/slab.h>
-
-#define BUCK_RAMPRATE_250MV 0
-#define BUCK_RAMPRATE_125MV 1
-#define BUCK_RAMP_MAX 250
-
-static const struct linear_range bd70528_buck1_volts[] = {
-       REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 600000),
-       REGULATOR_LINEAR_RANGE(2750000, 0x2, 0xf, 50000),
-};
-static const struct linear_range bd70528_buck2_volts[] = {
-       REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 300000),
-       REGULATOR_LINEAR_RANGE(1550000, 0x2, 0xd, 50000),
-       REGULATOR_LINEAR_RANGE(3000000, 0xe, 0xf, 300000),
-};
-static const struct linear_range bd70528_buck3_volts[] = {
-       REGULATOR_LINEAR_RANGE(800000, 0x00, 0xd, 50000),
-       REGULATOR_LINEAR_RANGE(1800000, 0xe, 0xf, 0),
-};
-
-/* All LDOs have same voltage ranges */
-static const struct linear_range bd70528_ldo_volts[] = {
-       REGULATOR_LINEAR_RANGE(1650000, 0x0, 0x07, 50000),
-       REGULATOR_LINEAR_RANGE(2100000, 0x8, 0x0f, 100000),
-       REGULATOR_LINEAR_RANGE(2850000, 0x10, 0x19, 50000),
-       REGULATOR_LINEAR_RANGE(3300000, 0x19, 0x1f, 0),
-};
-
-/* Also both LEDs support same voltages */
-static const unsigned int led_volts[] = {
-       20000, 30000
-};
-
-static int bd70528_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       if (ramp_delay > 0 && ramp_delay <= BUCK_RAMP_MAX) {
-               unsigned int ramp_value = BUCK_RAMPRATE_250MV;
-
-               if (ramp_delay <= 125)
-                       ramp_value = BUCK_RAMPRATE_125MV;
-
-               return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
-                                 BD70528_MASK_BUCK_RAMP,
-                                 ramp_value << BD70528_SIFT_BUCK_RAMP);
-       }
-       dev_err(&rdev->dev, "%s: ramp_delay: %d not supported\n",
-               rdev->desc->name, ramp_delay);
-       return -EINVAL;
-}
-
-static int bd70528_led_set_voltage_sel(struct regulator_dev *rdev,
-                                      unsigned int sel)
-{
-       int ret;
-
-       ret = regulator_is_enabled_regmap(rdev);
-       if (ret < 0)
-               return ret;
-
-       if (ret == 0)
-               return regulator_set_voltage_sel_regmap(rdev, sel);
-
-       dev_err(&rdev->dev,
-               "LED voltage change not allowed when led is enabled\n");
-
-       return -EBUSY;
-}
-
-static const struct regulator_ops bd70528_buck_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_linear_range,
-       .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,
-       .set_ramp_delay = bd70528_set_ramp_delay,
-};
-
-static const struct regulator_ops bd70528_ldo_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_linear_range,
-       .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,
-};
-
-static const struct regulator_ops bd70528_led_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
-       .list_voltage = regulator_list_voltage_table,
-       .set_voltage_sel = bd70528_led_set_voltage_sel,
-       .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static const struct regulator_desc bd70528_desc[] = {
-       {
-               .name = "buck1",
-               .of_match = of_match_ptr("BUCK1"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_BUCK1,
-               .ops = &bd70528_buck_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_buck1_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_buck1_volts),
-               .n_voltages = BD70528_BUCK_VOLTS,
-               .enable_reg = BD70528_REG_BUCK1_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_BUCK1_VOLT,
-               .vsel_mask = BD70528_MASK_BUCK_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck2",
-               .of_match = of_match_ptr("BUCK2"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_BUCK2,
-               .ops = &bd70528_buck_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_buck2_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_buck2_volts),
-               .n_voltages = BD70528_BUCK_VOLTS,
-               .enable_reg = BD70528_REG_BUCK2_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_BUCK2_VOLT,
-               .vsel_mask = BD70528_MASK_BUCK_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "buck3",
-               .of_match = of_match_ptr("BUCK3"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_BUCK3,
-               .ops = &bd70528_buck_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_buck3_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_buck3_volts),
-               .n_voltages = BD70528_BUCK_VOLTS,
-               .enable_reg = BD70528_REG_BUCK3_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_BUCK3_VOLT,
-               .vsel_mask = BD70528_MASK_BUCK_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo1",
-               .of_match = of_match_ptr("LDO1"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_LDO1,
-               .ops = &bd70528_ldo_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_ldo_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
-               .n_voltages = BD70528_LDO_VOLTS,
-               .enable_reg = BD70528_REG_LDO1_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_LDO1_VOLT,
-               .vsel_mask = BD70528_MASK_LDO_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo2",
-               .of_match = of_match_ptr("LDO2"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_LDO2,
-               .ops = &bd70528_ldo_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_ldo_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
-               .n_voltages = BD70528_LDO_VOLTS,
-               .enable_reg = BD70528_REG_LDO2_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_LDO2_VOLT,
-               .vsel_mask = BD70528_MASK_LDO_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo3",
-               .of_match = of_match_ptr("LDO3"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_LDO3,
-               .ops = &bd70528_ldo_ops,
-               .type = REGULATOR_VOLTAGE,
-               .linear_ranges = bd70528_ldo_volts,
-               .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
-               .n_voltages = BD70528_LDO_VOLTS,
-               .enable_reg = BD70528_REG_LDO3_EN,
-               .enable_mask = BD70528_MASK_RUN_EN,
-               .vsel_reg = BD70528_REG_LDO3_VOLT,
-               .vsel_mask = BD70528_MASK_LDO_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo_led1",
-               .of_match = of_match_ptr("LDO_LED1"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_LED1,
-               .ops = &bd70528_led_ops,
-               .type = REGULATOR_VOLTAGE,
-               .volt_table = &led_volts[0],
-               .n_voltages = ARRAY_SIZE(led_volts),
-               .enable_reg = BD70528_REG_LED_EN,
-               .enable_mask = BD70528_MASK_LED1_EN,
-               .vsel_reg = BD70528_REG_LED_VOLT,
-               .vsel_mask = BD70528_MASK_LED1_VOLT,
-               .owner = THIS_MODULE,
-       },
-       {
-               .name = "ldo_led2",
-               .of_match = of_match_ptr("LDO_LED2"),
-               .regulators_node = of_match_ptr("regulators"),
-               .id = BD70528_LED2,
-               .ops = &bd70528_led_ops,
-               .type = REGULATOR_VOLTAGE,
-               .volt_table = &led_volts[0],
-               .n_voltages = ARRAY_SIZE(led_volts),
-               .enable_reg = BD70528_REG_LED_EN,
-               .enable_mask = BD70528_MASK_LED2_EN,
-               .vsel_reg = BD70528_REG_LED_VOLT,
-               .vsel_mask = BD70528_MASK_LED2_VOLT,
-               .owner = THIS_MODULE,
-       },
-
-};
-
-static int bd70528_probe(struct platform_device *pdev)
-{
-       int i;
-       struct regulator_config config = {
-               .dev = pdev->dev.parent,
-       };
-
-       config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
-       if (!config.regmap)
-               return -ENODEV;
-
-       for (i = 0; i < ARRAY_SIZE(bd70528_desc); i++) {
-               struct regulator_dev *rdev;
-
-               rdev = devm_regulator_register(&pdev->dev, &bd70528_desc[i],
-                                              &config);
-               if (IS_ERR(rdev)) {
-                       dev_err(&pdev->dev,
-                               "failed to register %s regulator\n",
-                               bd70528_desc[i].name);
-                       return PTR_ERR(rdev);
-               }
-       }
-       return 0;
-}
-
-static struct platform_driver bd70528_regulator = {
-       .driver = {
-               .name = "bd70528-pmic"
-       },
-       .probe = bd70528_probe,
-};
-
-module_platform_driver(bd70528_regulator);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD70528 voltage regulator driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bd70528-pmic");
index a4e8d5e..16edd90 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/driver.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -26,14 +28,6 @@ struct bd71815_regulator {
        const struct rohm_dvs_config *dvs;
 };
 
-struct bd71815_pmic {
-       struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
-       struct regmap *regmap;
-       struct device *dev;
-       struct gpio_descs *gps;
-       struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
-};
-
 static const int bd7181x_wled_currents[] = {
        10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
        5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000,
@@ -300,14 +294,13 @@ static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
 
 static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
 {
-       struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
        int rid = rdev_get_id(rdev);
        int ret, regh, regl, val;
 
        regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2;
        regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2;
 
-       ret = regmap_read(pmic->regmap, regh, &val);
+       ret = regmap_read(rdev->regmap, regh, &val);
        if (ret)
                return ret;
 
@@ -319,7 +312,7 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
         * by BD71815_BUCK_DVSSEL bit
         */
        if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL)))
-               ret = regmap_read(pmic->regmap, regl, &val);
+               ret = regmap_read(rdev->regmap, regl, &val);
 
        if (ret)
                return ret;
@@ -333,14 +326,13 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
 static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
                                          unsigned int sel)
 {
-       struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
        int rid = rdev_get_id(rdev);
        int ret, val, reg, regh, regl;
 
        regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2;
        regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2;
 
-       ret = regmap_read(pmic->regmap, regh, &val);
+       ret = regmap_read(rdev->regmap, regh, &val);
        if (ret)
                return ret;
 
@@ -350,7 +342,7 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
         * voltages at runtime is not supported by this driver.
         */
        if (((val & BD71815_BUCK_STBY_DVS))) {
-               return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK,
+               return regmap_update_bits(rdev->regmap, regh, BD71815_VOLT_MASK,
                                          sel);
        }
        /* Update new voltage to the register which is not selected now */
@@ -359,12 +351,13 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
        else
                reg = regh;
 
-       ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel);
+       ret = regmap_update_bits(rdev->regmap, reg, BD71815_VOLT_MASK, sel);
        if (ret)
                return ret;
 
        /* Select the other DVS register to be used */
-       return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val);
+       return regmap_update_bits(rdev->regmap, regh, BD71815_BUCK_DVSSEL,
+                                 ~val);
 }
 
 static const struct regulator_ops bd7181x_ldo_regulator_ops = {
@@ -522,7 +515,7 @@ static const struct regulator_ops bd7181x_led_regulator_ops = {
                .dvs = (_dvs),                                          \
        }
 
-static struct bd71815_regulator bd71815_regulators[] = {
+static const struct bd71815_regulator bd71815_regulators[] = {
        BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H,
                           BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000,
                           &buck1_dvs),
@@ -568,24 +561,16 @@ static struct bd71815_regulator bd71815_regulators[] = {
 
 static int bd7181x_probe(struct platform_device *pdev)
 {
-       struct bd71815_pmic *pmic;
        struct regulator_config config = {};
        int i, ret;
        struct gpio_desc *ldo4_en;
+       struct regmap *regmap;
 
-       pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
-       if (!pmic)
-               return -ENOMEM;
-
-       memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs));
-
-       pmic->dev = &pdev->dev;
-       pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
-       if (!pmic->regmap) {
-               dev_err(pmic->dev, "No parent regmap\n");
+       regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!regmap) {
+               dev_err(&pdev->dev, "No parent regmap\n");
                return -ENODEV;
        }
-       platform_set_drvdata(pdev, pmic);
        ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev,
                                              pdev->dev.parent->of_node,
                                                 "rohm,vsel-gpios", 0,
@@ -599,23 +584,23 @@ static int bd7181x_probe(struct platform_device *pdev)
        }
 
        /* Disable to go to ship-mode */
-       ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL,
-                                RESTARTEN, 0);
+       ret = regmap_update_bits(regmap, BD71815_REG_PWRCTRL, RESTARTEN, 0);
        if (ret)
                return ret;
 
        config.dev = pdev->dev.parent;
-       config.regmap = pmic->regmap;
+       config.regmap = regmap;
 
        for (i = 0; i < BD71815_REGULATOR_CNT; i++) {
-               struct regulator_desc *desc;
+               const struct regulator_desc *desc;
                struct regulator_dev *rdev;
 
-               desc = &pmic->descs[i].desc;
+               desc = &bd71815_regulators[i].desc;
+
                if (i == BD71815_LDO4)
                        config.ena_gpiod = ldo4_en;
-
-               config.driver_data = pmic;
+               else
+                       config.ena_gpiod = NULL;
 
                rdev = devm_regulator_register(&pdev->dev, desc, &config);
                if (IS_ERR(rdev)) {
@@ -624,8 +609,6 @@ static int bd7181x_probe(struct platform_device *pdev)
                                desc->name);
                        return PTR_ERR(rdev);
                }
-               config.ena_gpiod = NULL;
-               pmic->rdev[i] = rdev;
        }
        return 0;
 }
@@ -639,7 +622,6 @@ MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id);
 static struct platform_driver bd7181x_regulator = {
        .driver = {
                .name = "bd7181x-pmic",
-               .owner = THIS_MODULE,
        },
        .probe = bd7181x_probe,
        .id_table = bd7181x_pmic_id,
index 204a2da..e16c372 100644 (file)
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/mfd/rohm-bd957x.h>
 #include <linux/mfd/rohm-generic.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
 
 #define BD957X_VOUTS1_VOLT     3300000
 #define BD957X_VOUTS4_BASE_VOLT        1030000
 #define BD957X_VOUTS34_NUM_VOLT        32
 
-static int vout1_volt_table[] = {5000000, 4900000, 4800000, 4700000, 4600000,
-                                4500000, 4500000, 4500000, 5000000, 5100000,
-                                5200000, 5300000, 5400000, 5500000, 5500000,
-                                5500000};
+#define BD9576_THERM_IRQ_MASK_TW       BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1     BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
 
-static int vout2_volt_table[] = {1800000, 1780000, 1760000, 1740000, 1720000,
-                                1700000, 1680000, 1660000, 1800000, 1820000,
-                                1840000, 1860000, 1880000, 1900000, 1920000,
-                                1940000};
+static const unsigned int vout1_volt_table[] = {
+       5000000, 4900000, 4800000, 4700000, 4600000,
+       4500000, 4500000, 4500000, 5000000, 5100000,
+       5200000, 5300000, 5400000, 5500000, 5500000,
+       5500000
+};
+
+static const unsigned int vout2_volt_table[] = {
+       1800000, 1780000, 1760000, 1740000, 1720000,
+       1700000, 1680000, 1660000, 1800000, 1820000,
+       1840000, 1860000, 1880000, 1900000, 1920000,
+       1940000
+};
+
+static const unsigned int voutl1_volt_table[] = {
+       2500000, 2540000, 2580000, 2620000, 2660000,
+       2700000, 2740000, 2780000, 2500000, 2460000,
+       2420000, 2380000, 2340000, 2300000, 2260000,
+       2220000
+};
+
+static const struct linear_range vout1_xvd_ranges[] = {
+       REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+       REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+       REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+       REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+       REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+       REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+       REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+       REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+       REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+       REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0),
+       REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000),
+       REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+       REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0),
+       REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000),
+       REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+       REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0),
+       REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000),
+       REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0),
+};
 
-static int voutl1_volt_table[] = {2500000, 2540000, 2580000, 2620000, 2660000,
-                                 2700000, 2740000, 2780000, 2500000, 2460000,
-                                 2420000, 2380000, 2340000, 2300000, 2260000,
-                                 2220000};
+static struct linear_range voutS1_ocp_ranges[] = {
+       REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0),
+       REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000),
+       REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0),
+};
 
 struct bd957x_regulator_data {
        struct regulator_desc desc;
        int base_voltage;
+       struct regulator_dev *rdev;
+       int ovd_notif;
+       int uvd_notif;
+       int temp_notif;
+       int ovd_err;
+       int uvd_err;
+       int temp_err;
+       const struct linear_range *xvd_ranges;
+       int num_xvd_ranges;
+       bool oc_supported;
+       unsigned int ovd_reg;
+       unsigned int uvd_reg;
+       unsigned int xvd_mask;
+       unsigned int ocp_reg;
+       unsigned int ocp_mask;
+       unsigned int ocw_reg;
+       unsigned int ocw_mask;
+       unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+       struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+       struct regmap *regmap;
+       struct delayed_work therm_irq_suppress;
+       struct delayed_work ovd_irq_suppress;
+       struct delayed_work uvd_irq_suppress;
+       unsigned int therm_irq;
+       unsigned int ovd_irq;
+       unsigned int uvd_irq;
+       spinlock_t err_lock;
+       int regulator_global_err;
 };
 
 static int bd957x_vout34_list_voltage(struct regulator_dev *rdev,
@@ -72,151 +161,784 @@ static int bd957x_list_voltage(struct regulator_dev *rdev,
        return desc->volt_table[index];
 }
 
-static const struct regulator_ops bd957x_vout34_ops = {
+static void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data,
+                                 bool warn)
+{
+       if (warn) {
+               data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN;
+               data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN;
+       } else {
+               data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT;
+               data->ovd_err = REGULATOR_ERROR_REGULATION_OUT;
+       }
+}
+
+static void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data,
+                                 bool warn)
+{
+       if (warn) {
+               data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN;
+               data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN;
+       } else {
+               data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT;
+               data->uvd_err = REGULATOR_ERROR_OVER_CURRENT;
+       }
+}
+
+static void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data,
+                                 bool warn)
+{
+       if (warn) {
+               data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
+               data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN;
+       } else {
+               data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE;
+               data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE;
+       }
+}
+
+static void bd9576_fill_temp_flags(struct bd957x_regulator_data *data,
+                                  bool enable, bool warn)
+{
+       if (!enable) {
+               data->temp_notif = 0;
+               data->temp_err = 0;
+       } else if (warn) {
+               data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN;
+               data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN;
+       } else {
+               data->temp_notif = REGULATOR_EVENT_OVER_TEMP;
+               data->temp_err = REGULATOR_ERROR_OVER_TEMP;
+       }
+}
+
+static int bd9576_set_limit(const struct linear_range *r, int num_ranges,
+                           struct regmap *regmap, int reg, int mask, int lim)
+{
+       int ret;
+       bool found;
+       int sel = 0;
+
+       if (lim) {
+
+               ret = linear_range_get_selector_low_array(r, num_ranges,
+                                                         lim, &sel, &found);
+               if (ret)
+                       return ret;
+
+               if (!found)
+                       dev_warn(regmap_get_device(regmap),
+                                "limit %d out of range. Setting lower\n",
+                                lim);
+       }
+
+       return regmap_update_bits(regmap, reg, mask, sel);
+}
+
+static bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity,
+                                   struct bd957x_regulator_data *r)
+{
+       if ((severity == REGULATOR_SEVERITY_ERR &&
+           r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) ||
+           (severity == REGULATOR_SEVERITY_WARN &&
+           r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't support both OCP WARN and ERR\n");
+               /* Do not overwrite ERR config with WARN */
+               if (severity == REGULATOR_SEVERITY_WARN)
+                       return true;
+
+               bd9576_fill_ocp_flags(r, 0);
+       }
+
+       return false;
+}
+
+static bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity,
+                                   struct bd957x_regulator_data *r)
+{
+       if ((severity == REGULATOR_SEVERITY_ERR &&
+            r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) ||
+            (severity == REGULATOR_SEVERITY_WARN &&
+            r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't support both UVD WARN and ERR\n");
+               if (severity == REGULATOR_SEVERITY_WARN)
+                       return true;
+
+               bd9576_fill_uvd_flags(r, 0);
+       }
+
+       return false;
+}
+
+static bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity,
+                                   struct bd957x_regulator_data *r)
+{
+       if ((severity == REGULATOR_SEVERITY_ERR &&
+            r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) ||
+            (severity == REGULATOR_SEVERITY_WARN &&
+            r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't support both OVD WARN and ERR\n");
+               if (severity == REGULATOR_SEVERITY_WARN)
+                       return true;
+
+               bd9576_fill_ovd_flags(r, 0);
+       }
+
+       return false;
+}
+
+static bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity,
+                                   struct bd957x_regulator_data *r)
+{
+       if ((severity == REGULATOR_SEVERITY_ERR &&
+            r->ovd_notif != REGULATOR_EVENT_OVER_TEMP) ||
+            (severity == REGULATOR_SEVERITY_WARN &&
+            r->ovd_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't support both thermal WARN and ERR\n");
+               if (severity == REGULATOR_SEVERITY_WARN)
+                       return true;
+       }
+
+       return false;
+}
+
+static int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity,
+                         bool enable)
+{
+       struct bd957x_data *d;
+       struct bd957x_regulator_data *r;
+       int reg, mask;
+       int Vfet, rfet;
+       const struct linear_range *range;
+       int num_ranges;
+
+       if ((lim_uA && !enable) || (!lim_uA && enable))
+               return -EINVAL;
+
+       r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+       if (!r->oc_supported)
+               return -EINVAL;
+
+       d = rdev_get_drvdata(rdev);
+
+       if (severity == REGULATOR_SEVERITY_PROT) {
+               reg = r->ocp_reg;
+               mask = r->ocp_mask;
+               if (r->ocw_rfet) {
+                       range = voutS1_ocp_ranges;
+                       num_ranges = ARRAY_SIZE(voutS1_ocp_ranges);
+                       rfet = r->ocw_rfet / 1000;
+               } else {
+                       range = voutS1_ocp_ranges_internal;
+                       num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal);
+                       /* Internal values are already micro-amperes */
+                       rfet = 1000;
+               }
+       } else {
+               reg = r->ocw_reg;
+               mask = r->ocw_mask;
+
+               if (r->ocw_rfet) {
+                       range = voutS1_ocw_ranges;
+                       num_ranges = ARRAY_SIZE(voutS1_ocw_ranges);
+                       rfet = r->ocw_rfet / 1000;
+               } else {
+                       range = voutS1_ocw_ranges_internal;
+                       num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal);
+                       /* Internal values are already micro-amperes */
+                       rfet = 1000;
+               }
+
+               /* We abuse uvd fields for OCW on VoutS1 */
+               if (r->uvd_notif) {
+                       /*
+                        * If both warning and error are requested, prioritize
+                        * ERROR configuration
+                        */
+                       if (check_ocp_flag_mismatch(rdev, severity, r))
+                               return 0;
+               } else {
+                       bool warn = severity == REGULATOR_SEVERITY_WARN;
+
+                       bd9576_fill_ocp_flags(r, warn);
+               }
+       }
+
+       /*
+        * limits are given in uA, rfet is mOhm
+        * Divide lim_uA by 1000 to get Vfet in uV.
+        * (We expect both Rfet and limit uA to be magnitude of hundreds of
+        * milli Amperes & milli Ohms => we should still have decent accuracy)
+        */
+       Vfet = lim_uA/1000 * rfet;
+
+       return bd9576_set_limit(range, num_ranges, d->regmap,
+                               reg, mask, Vfet);
+}
+
+static int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity,
+                         bool enable)
+{
+       struct bd957x_data *d;
+       struct bd957x_regulator_data *r;
+       int mask, reg;
+
+       if (severity == REGULATOR_SEVERITY_PROT) {
+               if (!enable || lim_uV)
+                       return -EINVAL;
+               return 0;
+       }
+
+       /*
+        * BD9576 has enable control as a special value in limit reg. Can't
+        * set limit but keep feature disabled or enable W/O given limit.
+        */
+       if ((lim_uV && !enable) || (!lim_uV && enable))
+               return -EINVAL;
+
+       r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+       d = rdev_get_drvdata(rdev);
+
+       mask = r->xvd_mask;
+       reg = r->uvd_reg;
+       /*
+        * Check that there is no mismatch for what the detection IRQs are to
+        * be used.
+        */
+       if (r->uvd_notif) {
+               if (check_uvd_flag_mismatch(rdev, severity, r))
+                       return 0;
+       } else {
+               bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN);
+       }
+
+       return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
+                               reg, mask, lim_uV);
+}
+
+static int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity,
+                         bool enable)
+{
+       struct bd957x_data *d;
+       struct bd957x_regulator_data *r;
+       int mask, reg;
+
+       if (severity == REGULATOR_SEVERITY_PROT) {
+               if (!enable || lim_uV)
+                       return -EINVAL;
+               return 0;
+       }
+
+       /*
+        * BD9576 has enable control as a special value in limit reg. Can't
+        * set limit but keep feature disabled or enable W/O given limit.
+        */
+       if ((lim_uV && !enable) || (!lim_uV && enable))
+               return -EINVAL;
+
+       r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+       d = rdev_get_drvdata(rdev);
+
+       mask = r->xvd_mask;
+       reg = r->ovd_reg;
+       /*
+        * Check that there is no mismatch for what the detection IRQs are to
+        * be used.
+        */
+       if (r->ovd_notif) {
+               if (check_ovd_flag_mismatch(rdev, severity, r))
+                       return 0;
+       } else {
+               bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN);
+       }
+
+       return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
+                               reg, mask, lim_uV);
+}
+
+
+static int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity,
+                         bool enable)
+{
+       struct bd957x_data *d;
+       struct bd957x_regulator_data *r;
+       int i;
+
+       /*
+        * BD9576MUF has fixed temperature limits
+        * The detection can only be enabled/disabled
+        */
+       if (lim)
+               return -EINVAL;
+
+       /* Protection can't be disabled */
+       if (severity == REGULATOR_SEVERITY_PROT) {
+               if (!enable)
+                       return -EINVAL;
+               else
+                       return 0;
+       }
+
+       r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+       d = rdev_get_drvdata(rdev);
+
+       /*
+        * Check that there is no mismatch for what the detection IRQs are to
+        * be used.
+        */
+       if (r->temp_notif)
+               if (check_temp_flag_mismatch(rdev, severity, r))
+                       return 0;
+
+       bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN);
+
+       if (enable)
+               return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
+                                        BD9576_THERM_IRQ_MASK_TW, 0);
+
+       /*
+        * If any of the regulators is interested in thermal warning we keep IRQ
+        * enabled.
+        */
+       for (i = 0; i < BD9576_NUM_REGULATORS; i++)
+               if (d->regulator_data[i].temp_notif)
+                       return 0;
+
+       return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
+                                 BD9576_THERM_IRQ_MASK_TW,
+                                 BD9576_THERM_IRQ_MASK_TW);
+}
+
+static const struct regulator_ops bd9573_vout34_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .list_voltage = bd957x_vout34_list_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 };
 
-static const struct regulator_ops bd957X_vouts1_regulator_ops = {
+static const struct regulator_ops bd9576_vout34_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = bd957x_vout34_list_voltage,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_over_voltage_protection = bd9576_set_ovp,
+       .set_under_voltage_protection = bd9576_set_uvp,
+       .set_thermal_protection = bd9576_set_tw,
+};
+
+static const struct regulator_ops bd9573_vouts1_regulator_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops bd9576_vouts1_regulator_ops = {
        .is_enabled = regulator_is_enabled_regmap,
+       .set_over_current_protection = bd9576_set_ocp,
 };
 
-static const struct regulator_ops bd957x_ops = {
+static const struct regulator_ops bd9573_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .list_voltage = bd957x_list_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 };
 
-static struct bd957x_regulator_data bd9576_regulators[] = {
-       {
-               .desc = {
-                       .name = "VD50",
-                       .of_match = of_match_ptr("regulator-vd50"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VD50,
-                       .type = REGULATOR_VOLTAGE,
-                       .ops = &bd957x_ops,
-                       .volt_table = &vout1_volt_table[0],
-                       .n_voltages = ARRAY_SIZE(vout1_volt_table),
-                       .vsel_reg = BD957X_REG_VOUT1_TUNE,
-                       .vsel_mask = BD957X_MASK_VOUT1_TUNE,
-                       .enable_reg = BD957X_REG_POW_TRIGGER1,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+static const struct regulator_ops bd9576_ops = {
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = bd957x_list_voltage,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_over_voltage_protection = bd9576_set_ovp,
+       .set_under_voltage_protection = bd9576_set_uvp,
+       .set_thermal_protection = bd9576_set_tw,
+};
+
+static const struct regulator_ops  *bd9573_ops_arr[] = {
+       [BD957X_VD50]   = &bd9573_ops,
+       [BD957X_VD18]   = &bd9573_ops,
+       [BD957X_VDDDR]  = &bd9573_vout34_ops,
+       [BD957X_VD10]   = &bd9573_vout34_ops,
+       [BD957X_VOUTL1] = &bd9573_ops,
+       [BD957X_VOUTS1] = &bd9573_vouts1_regulator_ops,
+};
+
+static const struct regulator_ops  *bd9576_ops_arr[] = {
+       [BD957X_VD50]   = &bd9576_ops,
+       [BD957X_VD18]   = &bd9576_ops,
+       [BD957X_VDDDR]  = &bd9576_vout34_ops,
+       [BD957X_VD10]   = &bd9576_vout34_ops,
+       [BD957X_VOUTL1] = &bd9576_ops,
+       [BD957X_VOUTS1] = &bd9576_vouts1_regulator_ops,
+};
+
+static int vouts1_get_fet_res(struct device_node *np,
+                               const struct regulator_desc *desc,
+                               struct regulator_config *cfg)
+{
+       struct bd957x_regulator_data *data;
+       int ret;
+       u32 uohms;
+
+       data = container_of(desc, struct bd957x_regulator_data, desc);
+
+       ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms);
+       if (ret) {
+               if (ret != -EINVAL)
+                       return ret;
+
+               return 0;
+       }
+       data->ocw_rfet = uohms;
+       return 0;
+}
+
+static struct bd957x_data bd957x_regulators = {
+       .regulator_data = {
+               {
+                       .desc = {
+                               .name = "VD50",
+                               .of_match = of_match_ptr("regulator-vd50"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VD50,
+                               .type = REGULATOR_VOLTAGE,
+                               .volt_table = &vout1_volt_table[0],
+                               .n_voltages = ARRAY_SIZE(vout1_volt_table),
+                               .vsel_reg = BD957X_REG_VOUT1_TUNE,
+                               .vsel_mask = BD957X_MASK_VOUT1_TUNE,
+                               .enable_reg = BD957X_REG_POW_TRIGGER1,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                       },
+                       .xvd_ranges = vout1_xvd_ranges,
+                       .num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges),
+                       .ovd_reg = BD9576_REG_VOUT1_OVD,
+                       .uvd_reg = BD9576_REG_VOUT1_UVD,
+                       .xvd_mask = BD9576_MASK_XVD,
                },
-       },
-       {
-               .desc = {
-                       .name = "VD18",
-                       .of_match = of_match_ptr("regulator-vd18"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VD18,
-                       .type = REGULATOR_VOLTAGE,
-                       .ops = &bd957x_ops,
-                       .volt_table = &vout2_volt_table[0],
-                       .n_voltages = ARRAY_SIZE(vout2_volt_table),
-                       .vsel_reg = BD957X_REG_VOUT2_TUNE,
-                       .vsel_mask = BD957X_MASK_VOUT2_TUNE,
-                       .enable_reg = BD957X_REG_POW_TRIGGER2,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+               {
+                       .desc = {
+                               .name = "VD18",
+                               .of_match = of_match_ptr("regulator-vd18"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VD18,
+                               .type = REGULATOR_VOLTAGE,
+                               .volt_table = &vout2_volt_table[0],
+                               .n_voltages = ARRAY_SIZE(vout2_volt_table),
+                               .vsel_reg = BD957X_REG_VOUT2_TUNE,
+                               .vsel_mask = BD957X_MASK_VOUT2_TUNE,
+                               .enable_reg = BD957X_REG_POW_TRIGGER2,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                       },
+                       .xvd_ranges = vout234_xvd_ranges,
+                       .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
+                       .ovd_reg = BD9576_REG_VOUT2_OVD,
+                       .uvd_reg = BD9576_REG_VOUT2_UVD,
+                       .xvd_mask = BD9576_MASK_XVD,
                },
-       },
-       {
-               .desc = {
-                       .name = "VDDDR",
-                       .of_match = of_match_ptr("regulator-vdddr"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VDDDR,
-                       .ops = &bd957x_vout34_ops,
-                       .type = REGULATOR_VOLTAGE,
-                       .n_voltages = BD957X_VOUTS34_NUM_VOLT,
-                       .vsel_reg = BD957X_REG_VOUT3_TUNE,
-                       .vsel_mask = BD957X_MASK_VOUT3_TUNE,
-                       .enable_reg = BD957X_REG_POW_TRIGGER3,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+               {
+                       .desc = {
+                               .name = "VDDDR",
+                               .of_match = of_match_ptr("regulator-vdddr"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VDDDR,
+                               .type = REGULATOR_VOLTAGE,
+                               .n_voltages = BD957X_VOUTS34_NUM_VOLT,
+                               .vsel_reg = BD957X_REG_VOUT3_TUNE,
+                               .vsel_mask = BD957X_MASK_VOUT3_TUNE,
+                               .enable_reg = BD957X_REG_POW_TRIGGER3,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                       },
+                       .ovd_reg = BD9576_REG_VOUT3_OVD,
+                       .uvd_reg = BD9576_REG_VOUT3_UVD,
+                       .xvd_mask = BD9576_MASK_XVD,
+                       .xvd_ranges = vout234_xvd_ranges,
+                       .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
                },
-       },
-       {
-               .desc = {
-                       .name = "VD10",
-                       .of_match = of_match_ptr("regulator-vd10"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VD10,
-                       .ops = &bd957x_vout34_ops,
-                       .type = REGULATOR_VOLTAGE,
-                       .fixed_uV = BD957X_VOUTS4_BASE_VOLT,
-                       .n_voltages = BD957X_VOUTS34_NUM_VOLT,
-                       .vsel_reg = BD957X_REG_VOUT4_TUNE,
-                       .vsel_mask = BD957X_MASK_VOUT4_TUNE,
-                       .enable_reg = BD957X_REG_POW_TRIGGER4,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+               {
+                       .desc = {
+                               .name = "VD10",
+                               .of_match = of_match_ptr("regulator-vd10"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VD10,
+                               .type = REGULATOR_VOLTAGE,
+                               .fixed_uV = BD957X_VOUTS4_BASE_VOLT,
+                               .n_voltages = BD957X_VOUTS34_NUM_VOLT,
+                               .vsel_reg = BD957X_REG_VOUT4_TUNE,
+                               .vsel_mask = BD957X_MASK_VOUT4_TUNE,
+                               .enable_reg = BD957X_REG_POW_TRIGGER4,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                       },
+                       .xvd_ranges = vout234_xvd_ranges,
+                       .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
+                       .ovd_reg = BD9576_REG_VOUT4_OVD,
+                       .uvd_reg = BD9576_REG_VOUT4_UVD,
+                       .xvd_mask = BD9576_MASK_XVD,
                },
-       },
-       {
-               .desc = {
-                       .name = "VOUTL1",
-                       .of_match = of_match_ptr("regulator-voutl1"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VOUTL1,
-                       .ops = &bd957x_ops,
-                       .type = REGULATOR_VOLTAGE,
-                       .volt_table = &voutl1_volt_table[0],
-                       .n_voltages = ARRAY_SIZE(voutl1_volt_table),
-                       .vsel_reg = BD957X_REG_VOUTL1_TUNE,
-                       .vsel_mask = BD957X_MASK_VOUTL1_TUNE,
-                       .enable_reg = BD957X_REG_POW_TRIGGERL1,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+               {
+                       .desc = {
+                               .name = "VOUTL1",
+                               .of_match = of_match_ptr("regulator-voutl1"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VOUTL1,
+                               .type = REGULATOR_VOLTAGE,
+                               .volt_table = &voutl1_volt_table[0],
+                               .n_voltages = ARRAY_SIZE(voutl1_volt_table),
+                               .vsel_reg = BD957X_REG_VOUTL1_TUNE,
+                               .vsel_mask = BD957X_MASK_VOUTL1_TUNE,
+                               .enable_reg = BD957X_REG_POW_TRIGGERL1,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                       },
+                       .xvd_ranges = voutL1_xvd_ranges,
+                       .num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges),
+                       .ovd_reg = BD9576_REG_VOUTL1_OVD,
+                       .uvd_reg = BD9576_REG_VOUTL1_UVD,
+                       .xvd_mask = BD9576_MASK_XVD,
                },
-       },
-       {
-               .desc = {
-                       .name = "VOUTS1",
-                       .of_match = of_match_ptr("regulator-vouts1"),
-                       .regulators_node = of_match_ptr("regulators"),
-                       .id = BD957X_VOUTS1,
-                       .ops = &bd957X_vouts1_regulator_ops,
-                       .type = REGULATOR_VOLTAGE,
-                       .n_voltages = 1,
-                       .fixed_uV = BD957X_VOUTS1_VOLT,
-                       .enable_reg = BD957X_REG_POW_TRIGGERS1,
-                       .enable_mask = BD957X_REGULATOR_EN_MASK,
-                       .enable_val = BD957X_REGULATOR_DIS_VAL,
-                       .enable_is_inverted = true,
-                       .owner = THIS_MODULE,
+               {
+                       .desc = {
+                               .name = "VOUTS1",
+                               .of_match = of_match_ptr("regulator-vouts1"),
+                               .regulators_node = of_match_ptr("regulators"),
+                               .id = BD957X_VOUTS1,
+                               .type = REGULATOR_VOLTAGE,
+                               .n_voltages = 1,
+                               .fixed_uV = BD957X_VOUTS1_VOLT,
+                               .enable_reg = BD957X_REG_POW_TRIGGERS1,
+                               .enable_mask = BD957X_REGULATOR_EN_MASK,
+                               .enable_val = BD957X_REGULATOR_DIS_VAL,
+                               .enable_is_inverted = true,
+                               .owner = THIS_MODULE,
+                               .of_parse_cb = vouts1_get_fet_res,
+                       },
+                       .oc_supported = true,
+                       .ocw_reg = BD9576_REG_VOUT1S_OCW,
+                       .ocw_mask = BD9576_MASK_VOUT1S_OCW,
+                       .ocp_reg = BD9576_REG_VOUT1S_OCP,
+                       .ocp_mask = BD9576_MASK_VOUT1S_OCP,
                },
        },
 };
 
+static int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask)
+{
+       int val, ret;
+       struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+       ret = regmap_read(d->regmap, reg, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       if (rid->opaque && rid->opaque == (val & mask)) {
+               /*
+                * It seems we stil have same status. Ack and return
+                * information that we are still out of limits and core
+                * should not enable IRQ
+                */
+               regmap_write(d->regmap, reg, mask & val);
+               return REGULATOR_ERROR_ON;
+       }
+       rid->opaque = 0;
+       /*
+        * Status was changed. Either prolem was solved or we have new issues.
+        * Let's re-enable IRQs and be prepared to report problems again
+        */
+       return REGULATOR_ERROR_CLEARED;
+}
+
+static int bd9576_uvd_renable(struct regulator_irq_data *rid)
+{
+       return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK);
+}
+
+static int bd9576_ovd_renable(struct regulator_irq_data *rid)
+{
+       return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK);
+}
+
+static int bd9576_temp_renable(struct regulator_irq_data *rid)
+{
+       return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT,
+                             BD9576_THERM_IRQ_MASK_TW);
+}
+
+static int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid,
+                             unsigned long *dev_mask)
+{
+       int val, ret, i;
+       struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+       ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       *dev_mask = 0;
+
+       rid->opaque = val & UVD_IRQ_VALID_MASK;
+
+       /*
+        * Go through the set status bits and report either error or warning
+        * to the notifier depending on what was flagged in DT
+        */
+       *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
+       /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
+       *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
+       /*
+        * We (ab)use the uvd for OCW notification. DT parsing should
+        * have added correct OCW flag to uvd_notif and uvd_err for S1
+        */
+       *dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1);
+
+       for_each_set_bit(i, dev_mask, 6) {
+               struct bd957x_regulator_data *rdata;
+               struct regulator_err_state *stat;
+
+               rdata = &d->regulator_data[i];
+               stat  = &rid->states[i];
+
+               stat->notifs    = rdata->uvd_notif;
+               stat->errors    = rdata->uvd_err;
+       }
+
+       ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT,
+                          UVD_IRQ_VALID_MASK & val);
+
+       return 0;
+}
+
+static int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid,
+                             unsigned long *dev_mask)
+{
+       int val, ret, i;
+       struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+       ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       rid->opaque = val & OVD_IRQ_VALID_MASK;
+       *dev_mask = 0;
+
+       if (!(val & OVD_IRQ_VALID_MASK))
+               return 0;
+
+       *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
+       /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
+       *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
+
+       for_each_set_bit(i, dev_mask, 5) {
+               struct bd957x_regulator_data *rdata;
+               struct regulator_err_state *stat;
+
+               rdata = &d->regulator_data[i];
+               stat  = &rid->states[i];
+
+               stat->notifs    = rdata->ovd_notif;
+               stat->errors    = rdata->ovd_err;
+       }
+
+       /* Clear the sub-IRQ status */
+       regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT,
+                    OVD_IRQ_VALID_MASK & val);
+
+       return 0;
+}
+
+#define BD9576_DEV_MASK_ALL_REGULATORS 0x3F
+
+static int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid,
+                                 unsigned long *dev_mask)
+{
+       int val, ret, i;
+       struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+       ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val);
+       if (ret)
+               return REGULATOR_FAILED_RETRY;
+
+       if (!(val & BD9576_THERM_IRQ_MASK_TW)) {
+               *dev_mask = 0;
+               return 0;
+       }
+
+       *dev_mask = BD9576_DEV_MASK_ALL_REGULATORS;
+
+       for (i = 0; i < BD9576_NUM_REGULATORS; i++) {
+               struct bd957x_regulator_data *rdata;
+               struct regulator_err_state *stat;
+
+               rdata = &d->regulator_data[i];
+               stat  = &rid->states[i];
+
+               stat->notifs    = rdata->temp_notif;
+               stat->errors    = rdata->temp_err;
+       }
+
+       /* Clear the sub-IRQ status */
+       regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT,
+                    BD9576_THERM_IRQ_MASK_TW);
+
+       return 0;
+}
+
 static int bd957x_probe(struct platform_device *pdev)
 {
+       int i;
+       unsigned int num_reg_data;
+       bool vout_mode, ddr_sel, may_have_irqs = false;
        struct regmap *regmap;
+       struct bd957x_data *ic_data;
        struct regulator_config config = { 0 };
-       int i;
-       bool vout_mode, ddr_sel;
-       const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0];
-       unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators);
+       /* All regulators are related to UVD and thermal IRQs... */
+       struct regulator_dev *rdevs[BD9576_NUM_REGULATORS];
+       /* ...But VoutS1 is not flagged by OVD IRQ */
+       struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS];
+       static const struct regulator_irq_desc bd9576_notif_uvd = {
+               .name = "bd9576-uvd",
+               .irq_off_ms = 1000,
+               .map_event = bd9576_uvd_handler,
+               .renable = bd9576_uvd_renable,
+               .data = &bd957x_regulators,
+       };
+       static const struct regulator_irq_desc bd9576_notif_ovd = {
+               .name = "bd9576-ovd",
+               .irq_off_ms = 1000,
+               .map_event = bd9576_ovd_handler,
+               .renable = bd9576_ovd_renable,
+               .data = &bd957x_regulators,
+       };
+       static const struct regulator_irq_desc bd9576_notif_temp = {
+               .name = "bd9576-temp",
+               .irq_off_ms = 1000,
+               .map_event = bd9576_thermal_handler,
+               .renable = bd9576_temp_renable,
+               .data = &bd957x_regulators,
+       };
        enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
 
+       num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data);
+
+       ic_data = &bd957x_regulators;
+
        regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!regmap) {
                dev_err(&pdev->dev, "No regmap\n");
                return -EINVAL;
        }
+
+       ic_data->regmap = regmap;
        vout_mode = of_property_read_bool(pdev->dev.parent->of_node,
                                         "rohm,vout1-en-low");
        if (vout_mode) {
@@ -263,15 +985,17 @@ static int bd957x_probe(struct platform_device *pdev)
         * bytes and use bd9576_regulators directly for non-constant configs
         * like DDR voltage selection.
         */
+       platform_set_drvdata(pdev, ic_data);
        ddr_sel =  of_property_read_bool(pdev->dev.parent->of_node,
                                         "rohm,ddr-sel-low");
        if (ddr_sel)
-               bd9576_regulators[2].desc.fixed_uV = 1350000;
+               ic_data->regulator_data[2].desc.fixed_uV = 1350000;
        else
-               bd9576_regulators[2].desc.fixed_uV = 1500000;
+               ic_data->regulator_data[2].desc.fixed_uV = 1500000;
 
        switch (chip) {
        case ROHM_CHIP_TYPE_BD9576:
+               may_have_irqs = true;
                dev_dbg(&pdev->dev, "Found BD9576MUF\n");
                break;
        case ROHM_CHIP_TYPE_BD9573:
@@ -282,38 +1006,122 @@ static int bd957x_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       for (i = 0; i < num_reg_data; i++) {
+               struct regulator_desc *d;
+
+               d = &ic_data->regulator_data[i].desc;
+
+
+               if (may_have_irqs) {
+                       if (d->id >= ARRAY_SIZE(bd9576_ops_arr))
+                               return -EINVAL;
+
+                       d->ops = bd9576_ops_arr[d->id];
+               } else {
+                       if (d->id >= ARRAY_SIZE(bd9573_ops_arr))
+                               return -EINVAL;
+
+                       d->ops = bd9573_ops_arr[d->id];
+               }
+       }
+
        config.dev = pdev->dev.parent;
        config.regmap = regmap;
+       config.driver_data = ic_data;
 
        for (i = 0; i < num_reg_data; i++) {
 
-               const struct regulator_desc *desc;
-               struct regulator_dev *rdev;
-               const struct bd957x_regulator_data *r;
-
-               r = &reg_data[i];
-               desc = &r->desc;
+               struct bd957x_regulator_data *r = &ic_data->regulator_data[i];
+               const struct regulator_desc *desc = &r->desc;
 
-               rdev = devm_regulator_register(&pdev->dev, desc, &config);
-               if (IS_ERR(rdev)) {
+               r->rdev = devm_regulator_register(&pdev->dev, desc,
+                                                          &config);
+               if (IS_ERR(r->rdev)) {
                        dev_err(&pdev->dev,
                                "failed to register %s regulator\n",
                                desc->name);
-                       return PTR_ERR(rdev);
+                       return PTR_ERR(r->rdev);
                }
                /*
                 * Clear the VOUT1 GPIO setting - rest of the regulators do not
                 * support GPIO control
                 */
                config.ena_gpiod = NULL;
+
+               if (!may_have_irqs)
+                       continue;
+
+               rdevs[i] = r->rdev;
+               if (i < BD957X_VOUTS1)
+                       ovd_devs[i] = r->rdev;
        }
+       if (may_have_irqs) {
+               void *ret;
+               /*
+                * We can add both the possible error and warning flags here
+                * because the core uses these only for status clearing and
+                * if we use warnings - errors are always clear and the other
+                * way around. We can also add CURRENT flag for all regulators
+                * because it is never set if it is not supported. Same applies
+                * to setting UVD for VoutS1 - it is not accidentally cleared
+                * as it is never set.
+                */
+               int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE |
+                              REGULATOR_ERROR_UNDER_VOLTAGE_WARN |
+                              REGULATOR_ERROR_OVER_CURRENT |
+                              REGULATOR_ERROR_OVER_CURRENT_WARN;
+               int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN |
+                              REGULATOR_ERROR_REGULATION_OUT;
+               int temp_errs = REGULATOR_ERROR_OVER_TEMP |
+                               REGULATOR_ERROR_OVER_TEMP_WARN;
+               int irq;
+
+               irq = platform_get_irq_byname(pdev, "bd9576-uvd");
 
+               /* Register notifiers - can fail if IRQ is not given */
+               ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd,
+                                               irq, 0, uvd_errs, NULL,
+                                               &rdevs[0],
+                                               BD9576_NUM_REGULATORS);
+               if (IS_ERR(ret)) {
+                       if (PTR_ERR(ret) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+
+                       dev_warn(&pdev->dev, "UVD disabled %pe\n", ret);
+               }
+
+               irq = platform_get_irq_byname(pdev, "bd9576-ovd");
+
+               ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd,
+                                               irq, 0, ovd_errs, NULL,
+                                               &ovd_devs[0],
+                                               BD9576_NUM_OVD_REGULATORS);
+               if (IS_ERR(ret)) {
+                       if (PTR_ERR(ret) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+
+                       dev_warn(&pdev->dev, "OVD disabled %pe\n", ret);
+               }
+               irq = platform_get_irq_byname(pdev, "bd9576-temp");
+
+               ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp,
+                                               irq, 0, temp_errs, NULL,
+                                               &rdevs[0],
+                                               BD9576_NUM_REGULATORS);
+               if (IS_ERR(ret)) {
+                       if (PTR_ERR(ret) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+
+                       dev_warn(&pdev->dev, "Thermal warning disabled %pe\n",
+                                ret);
+               }
+       }
        return 0;
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-       { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-       { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+       { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+       { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
index e20e77e..ca6caba 100644 (file)
 #include "dummy.h"
 #include "internal.h"
 
-#define rdev_crit(rdev, fmt, ...)                                      \
-       pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_err(rdev, fmt, ...)                                       \
-       pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_warn(rdev, fmt, ...)                                      \
-       pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_info(rdev, fmt, ...)                                      \
-       pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_dbg(rdev, fmt, ...)                                       \
-       pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-
 static DEFINE_WW_CLASS(regulator_ww_class);
 static DEFINE_MUTEX(regulator_nesting_mutex);
 static DEFINE_MUTEX(regulator_list_mutex);
@@ -117,6 +106,7 @@ const char *rdev_get_name(struct regulator_dev *rdev)
        else
                return "";
 }
+EXPORT_SYMBOL_GPL(rdev_get_name);
 
 static bool have_full_constraints(void)
 {
@@ -591,8 +581,8 @@ regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t st
        return rstate;
 }
 
-static ssize_t regulator_uV_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t microvolts_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        int uV;
@@ -605,16 +595,16 @@ static ssize_t regulator_uV_show(struct device *dev,
                return uV;
        return sprintf(buf, "%d\n", uV);
 }
-static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
+static DEVICE_ATTR_RO(microvolts);
 
-static ssize_t regulator_uA_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t microamps_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
 }
-static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
+static DEVICE_ATTR_RO(microamps);
 
 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
@@ -645,14 +635,14 @@ static ssize_t regulator_print_opmode(char *buf, int mode)
        return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
 }
 
-static ssize_t regulator_opmode_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t opmode_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_opmode(buf, _regulator_get_mode(rdev));
 }
-static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL);
+static DEVICE_ATTR_RO(opmode);
 
 static ssize_t regulator_print_state(char *buf, int state)
 {
@@ -664,8 +654,8 @@ static ssize_t regulator_print_state(char *buf, int state)
                return sprintf(buf, "unknown\n");
 }
 
-static ssize_t regulator_state_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t state_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        ssize_t ret;
@@ -676,10 +666,10 @@ static ssize_t regulator_state_show(struct device *dev,
 
        return ret;
 }
-static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+static DEVICE_ATTR_RO(state);
 
-static ssize_t regulator_status_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t status_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        int status;
@@ -723,10 +713,10 @@ static ssize_t regulator_status_show(struct device *dev,
 
        return sprintf(buf, "%s\n", label);
 }
-static DEVICE_ATTR(status, 0444, regulator_status_show, NULL);
+static DEVICE_ATTR_RO(status);
 
-static ssize_t regulator_min_uA_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t min_microamps_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -735,10 +725,10 @@ static ssize_t regulator_min_uA_show(struct device *dev,
 
        return sprintf(buf, "%d\n", rdev->constraints->min_uA);
 }
-static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL);
+static DEVICE_ATTR_RO(min_microamps);
 
-static ssize_t regulator_max_uA_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t max_microamps_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -747,10 +737,10 @@ static ssize_t regulator_max_uA_show(struct device *dev,
 
        return sprintf(buf, "%d\n", rdev->constraints->max_uA);
 }
-static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL);
+static DEVICE_ATTR_RO(max_microamps);
 
-static ssize_t regulator_min_uV_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t min_microvolts_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -759,10 +749,10 @@ static ssize_t regulator_min_uV_show(struct device *dev,
 
        return sprintf(buf, "%d\n", rdev->constraints->min_uV);
 }
-static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL);
+static DEVICE_ATTR_RO(min_microvolts);
 
-static ssize_t regulator_max_uV_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
+static ssize_t max_microvolts_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -771,10 +761,10 @@ static ssize_t regulator_max_uV_show(struct device *dev,
 
        return sprintf(buf, "%d\n", rdev->constraints->max_uV);
 }
-static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL);
+static DEVICE_ATTR_RO(max_microvolts);
 
-static ssize_t regulator_total_uA_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
+static ssize_t requested_microamps_show(struct device *dev,
+                                       struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        struct regulator *regulator;
@@ -788,7 +778,7 @@ static ssize_t regulator_total_uA_show(struct device *dev,
        regulator_unlock(rdev);
        return sprintf(buf, "%d\n", uA);
 }
-static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
+static DEVICE_ATTR_RO(requested_microamps);
 
 static ssize_t num_users_show(struct device *dev, struct device_attribute *attr,
                              char *buf)
@@ -813,104 +803,95 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(type);
 
-static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_microvolts_show(struct device *dev,
+                                          struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV);
 }
-static DEVICE_ATTR(suspend_mem_microvolts, 0444,
-               regulator_suspend_mem_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_microvolts);
 
-static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_microvolts_show(struct device *dev,
+                                           struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV);
 }
-static DEVICE_ATTR(suspend_disk_microvolts, 0444,
-               regulator_suspend_disk_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_microvolts);
 
-static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_microvolts_show(struct device *dev,
+                                              struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV);
 }
-static DEVICE_ATTR(suspend_standby_microvolts, 0444,
-               regulator_suspend_standby_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_microvolts);
 
-static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_mode_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_opmode(buf,
                rdev->constraints->state_mem.mode);
 }
-static DEVICE_ATTR(suspend_mem_mode, 0444,
-               regulator_suspend_mem_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_mode);
 
-static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_mode_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_opmode(buf,
                rdev->constraints->state_disk.mode);
 }
-static DEVICE_ATTR(suspend_disk_mode, 0444,
-               regulator_suspend_disk_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_mode);
 
-static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_mode_show(struct device *dev,
+                                        struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_opmode(buf,
                rdev->constraints->state_standby.mode);
 }
-static DEVICE_ATTR(suspend_standby_mode, 0444,
-               regulator_suspend_standby_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_mode);
 
-static ssize_t regulator_suspend_mem_state_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_state_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_state(buf,
                        rdev->constraints->state_mem.enabled);
 }
-static DEVICE_ATTR(suspend_mem_state, 0444,
-               regulator_suspend_mem_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_state);
 
-static ssize_t regulator_suspend_disk_state_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_state_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_state(buf,
                        rdev->constraints->state_disk.enabled);
 }
-static DEVICE_ATTR(suspend_disk_state, 0444,
-               regulator_suspend_disk_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_state);
 
-static ssize_t regulator_suspend_standby_state_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_state_show(struct device *dev,
+                                         struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return regulator_print_state(buf,
                        rdev->constraints->state_standby.enabled);
 }
-static DEVICE_ATTR(suspend_standby_state, 0444,
-               regulator_suspend_standby_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_state);
 
-static ssize_t regulator_bypass_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
+static ssize_t bypass_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        const char *report;
@@ -928,8 +909,7 @@ static ssize_t regulator_bypass_show(struct device *dev,
 
        return sprintf(buf, "%s\n", report);
 }
-static DEVICE_ATTR(bypass, 0444,
-                  regulator_bypass_show, NULL);
+static DEVICE_ATTR_RO(bypass);
 
 /* Calculate the new optimum regulator operating mode based on the new total
  * consumer load. All locks held by caller
@@ -1315,6 +1295,52 @@ static int machine_constraints_current(struct regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+                          int (*set)(struct regulator_dev *, int, int, bool),
+                          int limit, int severity)
+{
+       bool enable;
+
+       if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+               enable = false;
+               limit = 0;
+       } else {
+               enable = true;
+       }
+
+       if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+               limit = 0;
+
+       return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+                       int (*set)(struct regulator_dev *, int, int, bool),
+                       struct notification_limit *limits)
+{
+       int ret = 0;
+
+       if (!set)
+               return -EOPNOTSUPP;
+
+       if (limits->prot)
+               ret = notif_set_limit(rdev, set, limits->prot,
+                                     REGULATOR_SEVERITY_PROT);
+       if (ret)
+               return ret;
+
+       if (limits->err)
+               ret = notif_set_limit(rdev, set, limits->err,
+                                     REGULATOR_SEVERITY_ERR);
+       if (ret)
+               return ret;
+
+       if (limits->warn)
+               ret = notif_set_limit(rdev, set, limits->warn,
+                                     REGULATOR_SEVERITY_WARN);
+
+       return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1400,9 +1426,27 @@ static int set_machine_constraints(struct regulator_dev *rdev)
                }
        }
 
+       /*
+        * Existing logic does not warn if over_current_protection is given as
+        * a constraint but driver does not support that. I think we should
+        * warn about this type of issues as it is possible someone changes
+        * PMIC on board to another type - and the another PMIC's driver does
+        * not support setting protection. Board composer may happily believe
+        * the DT limits are respected - especially if the new PMIC HW also
+        * supports protection but the driver does not. I won't change the logic
+        * without hearing more experienced opinion on this though.
+        *
+        * If warning is seen as a good idea then we can merge handling the
+        * over-curret protection and detection and get rid of this special
+        * handling.
+        */
        if (rdev->constraints->over_current_protection
                && ops->set_over_current_protection) {
-               ret = ops->set_over_current_protection(rdev);
+               int lim = rdev->constraints->over_curr_limits.prot;
+
+               ret = ops->set_over_current_protection(rdev, lim,
+                                                      REGULATOR_SEVERITY_PROT,
+                                                      true);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set over current protection: %pe\n",
                                 ERR_PTR(ret));
@@ -1410,6 +1454,62 @@ static int set_machine_constraints(struct regulator_dev *rdev)
                }
        }
 
+       if (rdev->constraints->over_current_detection)
+               ret = handle_notify_limits(rdev,
+                                          ops->set_over_current_protection,
+                                          &rdev->constraints->over_curr_limits);
+       if (ret) {
+               if (ret != -EOPNOTSUPP) {
+                       rdev_err(rdev, "failed to set over current limits: %pe\n",
+                                ERR_PTR(ret));
+                       return ret;
+               }
+               rdev_warn(rdev,
+                         "IC does not support requested over-current limits\n");
+       }
+
+       if (rdev->constraints->over_voltage_detection)
+               ret = handle_notify_limits(rdev,
+                                          ops->set_over_voltage_protection,
+                                          &rdev->constraints->over_voltage_limits);
+       if (ret) {
+               if (ret != -EOPNOTSUPP) {
+                       rdev_err(rdev, "failed to set over voltage limits %pe\n",
+                                ERR_PTR(ret));
+                       return ret;
+               }
+               rdev_warn(rdev,
+                         "IC does not support requested over voltage limits\n");
+       }
+
+       if (rdev->constraints->under_voltage_detection)
+               ret = handle_notify_limits(rdev,
+                                          ops->set_under_voltage_protection,
+                                          &rdev->constraints->under_voltage_limits);
+       if (ret) {
+               if (ret != -EOPNOTSUPP) {
+                       rdev_err(rdev, "failed to set under voltage limits %pe\n",
+                                ERR_PTR(ret));
+                       return ret;
+               }
+               rdev_warn(rdev,
+                         "IC does not support requested under voltage limits\n");
+       }
+
+       if (rdev->constraints->over_temp_detection)
+               ret = handle_notify_limits(rdev,
+                                          ops->set_thermal_protection,
+                                          &rdev->constraints->temp_limits);
+       if (ret) {
+               if (ret != -EOPNOTSUPP) {
+                       rdev_err(rdev, "failed to set temperature limits %pe\n",
+                                ERR_PTR(ret));
+                       return ret;
+               }
+               rdev_warn(rdev,
+                         "IC does not support requested temperature limits\n");
+       }
+
        if (rdev->constraints->active_discharge && ops->set_active_discharge) {
                bool ad_state = (rdev->constraints->active_discharge ==
                              REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
@@ -4111,6 +4211,29 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
 
+int regulator_sync_voltage_rdev(struct regulator_dev *rdev)
+{
+       int ret;
+
+       regulator_lock(rdev);
+
+       if (!rdev->desc->ops->set_voltage &&
+           !rdev->desc->ops->set_voltage_sel) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* balance only, if regulator is coupled */
+       if (rdev->coupling_desc.n_coupled > 1)
+               ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+       else
+               ret = -EOPNOTSUPP;
+
+out:
+       regulator_unlock(rdev);
+       return ret;
+}
+
 /**
  * regulator_sync_voltage - re-apply last regulator output voltage
  * @regulator: regulator source
@@ -4386,22 +4509,36 @@ unsigned int regulator_get_mode(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+       int ret = 0;
+
+       if (rdev->use_cached_err) {
+               spin_lock(&rdev->err_lock);
+               ret = rdev->cached_err;
+               spin_unlock(&rdev->err_lock);
+       }
+       return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
                                        unsigned int *flags)
 {
-       int ret;
+       int cached_flags, ret = 0;
 
        regulator_lock(rdev);
 
-       /* sanity check */
-       if (!rdev->desc->ops->get_error_flags) {
+       cached_flags = rdev_get_cached_err_flags(rdev);
+
+       if (rdev->desc->ops->get_error_flags)
+               ret = rdev->desc->ops->get_error_flags(rdev, flags);
+       else if (!rdev->use_cached_err)
                ret = -EINVAL;
-               goto out;
-       }
 
-       ret = rdev->desc->ops->get_error_flags(rdev, flags);
-out:
+       *flags |= cached_flags;
+
        regulator_unlock(rdev);
+
        return ret;
 }
 
@@ -5234,6 +5371,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
                goto rinse;
        }
        device_initialize(&rdev->dev);
+       spin_lock_init(&rdev->err_lock);
 
        /*
         * Duplicate the config so the driver could override it after
index e18d291..23fa429 100644 (file)
@@ -250,7 +250,8 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
        case DA9052_ID_BUCK3:
        case DA9052_ID_LDO2:
        case DA9052_ID_LDO3:
-               ret = (new_sel - old_sel) * info->step_uV / 6250;
+               ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,
+                                  6250);
                break;
        }
 
index 3091210..a8de0aa 100644 (file)
@@ -481,3 +481,55 @@ void devm_regulator_unregister_notifier(struct regulator *regulator,
                WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
+
+static void regulator_irq_helper_drop(void *res)
+{
+       regulator_irq_helper_cancel(&res);
+}
+
+/**
+ * devm_regulator_irq_helper - resource managed registration of IRQ based
+ * regulator event/error notifier
+ *
+ * @dev:               device to which lifetime the helper's lifetime is
+ *                     bound.
+ * @d:                 IRQ helper descriptor.
+ * @irq:               IRQ used to inform events/errors to be notified.
+ * @irq_flags:         Extra IRQ flags to be OR'ed with the default
+ *                     IRQF_ONESHOT when requesting the (threaded) irq.
+ * @common_errs:       Errors which can be flagged by this IRQ for all rdevs.
+ *                     When IRQ is re-enabled these errors will be cleared
+ *                     from all associated regulators
+ * @per_rdev_errs:     Optional error flag array describing errors specific
+ *                     for only some of the regulators. These errors will be
+ *                     or'ed with common errors. If this is given the array
+ *                     should contain rdev_amount flags. Can be set to NULL
+ *                     if there is no regulator specific error flags for this
+ *                     IRQ.
+ * @rdev:              Array of pointers to regulators associated with this
+ *                     IRQ.
+ * @rdev_amount:       Amount of regulators associated with this IRQ.
+ *
+ * Return: handle to irq_helper or an ERR_PTR() encoded error code.
+ */
+void *devm_regulator_irq_helper(struct device *dev,
+                               const struct regulator_irq_desc *d, int irq,
+                               int irq_flags, int common_errs,
+                               int *per_rdev_errs,
+                               struct regulator_dev **rdev, int rdev_amount)
+{
+       void *ptr;
+       int ret;
+
+       ptr = regulator_irq_helper(dev, d, irq, irq_flags, common_errs,
+                                   per_rdev_errs, rdev, rdev_amount);
+       if (IS_ERR(ptr))
+               return ptr;
+
+       ret = devm_add_action_or_reset(dev, regulator_irq_helper_drop, ptr);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return ptr;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_irq_helper);
index 26f06f6..dac1fb5 100644 (file)
@@ -56,7 +56,6 @@
 #define FAN53555_NVOLTAGES     64      /* Numbers of voltages */
 #define FAN53526_NVOLTAGES     128
 
-#define TCS_VSEL_NSEL_MASK     0x7f
 #define TCS_VSEL0_MODE         (1 << 7)
 #define TCS_VSEL1_MODE         (1 << 6)
 
@@ -67,7 +66,7 @@ enum fan53555_vendor {
        FAN53526_VENDOR_FAIRCHILD = 0,
        FAN53555_VENDOR_FAIRCHILD,
        FAN53555_VENDOR_SILERGY,
-       FAN53555_VENDOR_TCS,
+       FAN53526_VENDOR_TCS,
 };
 
 enum {
@@ -89,6 +88,14 @@ enum {
        FAN53555_CHIP_ID_08 = 8,
 };
 
+enum {
+       TCS4525_CHIP_ID_12 = 12,
+};
+
+enum {
+       TCS4526_CHIP_ID_00 = 0,
+};
+
 /* IC mask revision */
 enum {
        FAN53555_CHIP_REV_00 = 0x3,
@@ -123,7 +130,8 @@ struct fan53555_device_info {
        /* Slew rate */
        unsigned int slew_reg;
        unsigned int slew_mask;
-       unsigned int slew_shift;
+       const unsigned int *ramp_delay_table;
+       unsigned int n_ramp_values;
        unsigned int slew_rate;
 };
 
@@ -197,7 +205,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
                return REGULATOR_MODE_NORMAL;
 }
 
-static const int slew_rates[] = {
+static const unsigned int slew_rates[] = {
        64000,
        32000,
        16000,
@@ -208,51 +216,13 @@ static const int slew_rates[] = {
          500,
 };
 
-static const int tcs_slew_rates[] = {
+static const unsigned int tcs_slew_rates[] = {
        18700,
         9300,
         4600,
         2300,
 };
 
-static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
-{
-       struct fan53555_device_info *di = rdev_get_drvdata(rdev);
-       int regval = -1, i;
-       const int *slew_rate_t;
-       int slew_rate_n;
-
-       switch (di->vendor) {
-       case FAN53526_VENDOR_FAIRCHILD:
-       case FAN53555_VENDOR_FAIRCHILD:
-       case FAN53555_VENDOR_SILERGY:
-               slew_rate_t = slew_rates;
-               slew_rate_n = ARRAY_SIZE(slew_rates);
-               break;
-       case FAN53555_VENDOR_TCS:
-               slew_rate_t = tcs_slew_rates;
-               slew_rate_n = ARRAY_SIZE(tcs_slew_rates);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       for (i = 0; i < slew_rate_n; i++) {
-               if (ramp <= slew_rate_t[i])
-                       regval = i;
-               else
-                       break;
-       }
-
-       if (regval < 0) {
-               dev_err(di->dev, "unsupported ramp value %d\n", ramp);
-               return -EINVAL;
-       }
-
-       return regmap_update_bits(rdev->regmap, di->slew_reg,
-                                 di->slew_mask, regval << di->slew_shift);
-}
-
 static const struct regulator_ops fan53555_regulator_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -265,7 +235,7 @@ static const struct regulator_ops fan53555_regulator_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .set_mode = fan53555_set_mode,
        .get_mode = fan53555_get_mode,
-       .set_ramp_delay = fan53555_set_ramp,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
        .set_suspend_enable = fan53555_set_suspend_enable,
        .set_suspend_disable = fan53555_set_suspend_disable,
 };
@@ -293,6 +263,10 @@ static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
                return -EINVAL;
        }
 
+       di->slew_reg = FAN53555_CONTROL;
+       di->slew_mask = CTL_SLEW_MASK;
+       di->ramp_delay_table = slew_rates;
+       di->n_ramp_values = ARRAY_SIZE(slew_rates);
        di->vsel_count = FAN53526_NVOLTAGES;
 
        return 0;
@@ -337,7 +311,8 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
        }
        di->slew_reg = FAN53555_CONTROL;
        di->slew_mask = CTL_SLEW_MASK;
-       di->slew_shift = CTL_SLEW_SHIFT;
+       di->ramp_delay_table = slew_rates;
+       di->n_ramp_values = ARRAY_SIZE(slew_rates);
        di->vsel_count = FAN53555_NVOLTAGES;
 
        return 0;
@@ -358,24 +333,33 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
                return -EINVAL;
        }
        di->slew_reg = FAN53555_CONTROL;
-       di->slew_reg = FAN53555_CONTROL;
        di->slew_mask = CTL_SLEW_MASK;
-       di->slew_shift = CTL_SLEW_SHIFT;
+       di->ramp_delay_table = slew_rates;
+       di->n_ramp_values = ARRAY_SIZE(slew_rates);
        di->vsel_count = FAN53555_NVOLTAGES;
 
        return 0;
 }
 
-static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di)
+static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di)
 {
-       di->slew_reg = TCS4525_TIME;
-       di->slew_mask = TCS_SLEW_MASK;
-       di->slew_shift = TCS_SLEW_MASK;
-
-       /* Init voltage range and step */
-       di->vsel_min = 600000;
-       di->vsel_step = 6250;
-       di->vsel_count = FAN53526_NVOLTAGES;
+       switch (di->chip_id) {
+       case TCS4525_CHIP_ID_12:
+       case TCS4526_CHIP_ID_00:
+               di->slew_reg = TCS4525_TIME;
+               di->slew_mask = TCS_SLEW_MASK;
+               di->ramp_delay_table = tcs_slew_rates;
+               di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates);
+
+               /* Init voltage range and step */
+               di->vsel_min = 600000;
+               di->vsel_step = 6250;
+               di->vsel_count = FAN53526_NVOLTAGES;
+               break;
+       default:
+               dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id);
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -409,7 +393,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
                        return -EINVAL;
                }
                break;
-       case FAN53555_VENDOR_TCS:
+       case FAN53526_VENDOR_TCS:
                switch (pdata->sleep_vsel_id) {
                case FAN53555_VSEL_ID_0:
                        di->sleep_reg = TCS4525_VSEL0;
@@ -448,7 +432,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
                di->mode_reg = di->vol_reg;
                di->mode_mask = VSEL_MODE;
                break;
-       case FAN53555_VENDOR_TCS:
+       case FAN53526_VENDOR_TCS:
                di->mode_reg = TCS4525_COMMAND;
 
                switch (pdata->sleep_vsel_id) {
@@ -476,8 +460,8 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
        case FAN53555_VENDOR_SILERGY:
                ret = fan53555_voltages_setup_silergy(di);
                break;
-       case FAN53555_VENDOR_TCS:
-               ret = fan53555_voltages_setup_tcs(di);
+       case FAN53526_VENDOR_TCS:
+               ret = fan53526_voltages_setup_tcs(di);
                break;
        default:
                dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
@@ -504,6 +488,10 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
        rdesc->uV_step = di->vsel_step;
        rdesc->vsel_reg = di->vol_reg;
        rdesc->vsel_mask = di->vsel_count - 1;
+       rdesc->ramp_reg = di->slew_reg;
+       rdesc->ramp_mask = di->slew_mask;
+       rdesc->ramp_delay_table = di->ramp_delay_table;
+       rdesc->n_ramp_values = di->n_ramp_values;
        rdesc->owner = THIS_MODULE;
 
        rdev = devm_regulator_register(di->dev, &di->desc, config);
@@ -552,7 +540,10 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
                .data = (void *)FAN53555_VENDOR_SILERGY,
        }, {
                .compatible = "tcs,tcs4525",
-               .data = (void *)FAN53555_VENDOR_TCS
+               .data = (void *)FAN53526_VENDOR_TCS
+       }, {
+               .compatible = "tcs,tcs4526",
+               .data = (void *)FAN53526_VENDOR_TCS
        },
        { }
 };
@@ -660,7 +651,10 @@ static const struct i2c_device_id fan53555_id[] = {
                .driver_data = FAN53555_VENDOR_SILERGY
        }, {
                .name = "tcs4525",
-               .driver_data = FAN53555_VENDOR_TCS
+               .driver_data = FAN53526_VENDOR_TCS
+       }, {
+               .name = "tcs4526",
+               .driver_data = FAN53526_VENDOR_TCS
        },
        { },
 };
index 1684faf..8f25930 100644 (file)
@@ -79,7 +79,7 @@ static const struct regulator_desc fan53880_regulators[] = {
                .n_linear_ranges = 2,
                .n_voltages =      0xf8,
                .vsel_reg =        FAN53880_BUCKVOUT,
-               .vsel_mask =       0x7f,
+               .vsel_mask =       0xff,
                .enable_reg =      FAN53880_ENABLE,
                .enable_mask =     0x10,
                .enable_time =     480,
@@ -114,8 +114,7 @@ static const struct regmap_config fan53880_regmap = {
        .max_register = FAN53880_ENABLE_BOOST,
 };
 
-static int fan53880_i2c_probe(struct i2c_client *i2c,
-                            const struct i2c_device_id *id)
+static int fan53880_i2c_probe(struct i2c_client *i2c)
 {
        struct regulator_config config = { };
        struct regulator_dev *rdev;
@@ -177,7 +176,7 @@ static struct i2c_driver fan53880_regulator_driver = {
                .name = "fan53880",
                .of_match_table = of_match_ptr(fan53880_dt_ids),
        },
-       .probe = fan53880_i2c_probe,
+       .probe_new = fan53880_i2c_probe,
        .id_table = fan53880_i2c_id,
 };
 module_i2c_driver(fan53880_regulator_driver);
index 34e255c..3928461 100644 (file)
@@ -276,7 +276,8 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
         */
        cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
        if (IS_ERR(cfg.ena_gpiod))
-               return PTR_ERR(cfg.ena_gpiod);
+               return dev_err_probe(&pdev->dev, PTR_ERR(cfg.ena_gpiod),
+                                    "can't get GPIO\n");
 
        cfg.dev = &pdev->dev;
        cfg.init_data = config->init_data;
index dc631c1..bff8c51 100644 (file)
@@ -386,7 +386,7 @@ static int hi6421_regulator_enable(struct regulator_dev *rdev)
 static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
 {
        struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
-       u32 reg_val;
+       unsigned int reg_val;
 
        regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
        if (reg_val & info->mode_mask)
@@ -398,7 +398,7 @@ static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
 static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
 {
        struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
-       u32 reg_val;
+       unsigned int reg_val;
 
        regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
        if (reg_val & info->mode_mask)
@@ -411,7 +411,7 @@ static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
                                                unsigned int mode)
 {
        struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
-       u32 new_mode;
+       unsigned int new_mode;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -435,7 +435,7 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
                                                unsigned int mode)
 {
        struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
-       u32 new_mode;
+       unsigned int new_mode;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
index d6340bb..9b162c0 100644 (file)
 #include <linux/regulator/driver.h>
 #include <linux/spmi.h>
 
+struct hi6421_spmi_reg_priv {
+       /* Serialize regulator enable logic */
+       struct mutex enable_mutex;
+};
+
 struct hi6421_spmi_reg_info {
        struct regulator_desc   desc;
-       struct hi6421_spmi_pmic *pmic;
        u8                      eco_mode_mask;
        u32                     eco_uA;
-
-       /* Serialize regulator enable logic */
-       struct mutex enable_mutex;
 };
 
 static const unsigned int ldo3_voltages[] = {
@@ -97,41 +98,31 @@ static const unsigned int ldo34_voltages[] = {
 
 static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
 {
-       struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
-       struct hi6421_spmi_pmic *pmic = sreg->pmic;
+       struct hi6421_spmi_reg_priv *priv;
        int ret;
 
+       priv = dev_get_drvdata(rdev->dev.parent);
        /* cannot enable more than one regulator at one time */
-       mutex_lock(&sreg->enable_mutex);
+       mutex_lock(&priv->enable_mutex);
 
-       ret = regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+       ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                 rdev->desc->enable_mask,
                                 rdev->desc->enable_mask);
 
        /* Avoid powering up multiple devices at the same time */
        usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 60);
 
-       mutex_unlock(&sreg->enable_mutex);
+       mutex_unlock(&priv->enable_mutex);
 
        return ret;
 }
 
-static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
-{
-       struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
-       struct hi6421_spmi_pmic *pmic = sreg->pmic;
-
-       return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
-                                 rdev->desc->enable_mask, 0);
-}
-
 static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
 {
        struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
-       struct hi6421_spmi_pmic *pmic = sreg->pmic;
-       u32 reg_val;
+       unsigned int reg_val;
 
-       regmap_read(pmic->regmap, rdev->desc->enable_reg, &reg_val);
+       regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
 
        if (reg_val & sreg->eco_mode_mask)
                return REGULATOR_MODE_IDLE;
@@ -143,21 +134,23 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
                                          unsigned int mode)
 {
        struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
-       struct hi6421_spmi_pmic *pmic = sreg->pmic;
-       u32 val;
+       unsigned int val;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
                val = 0;
                break;
        case REGULATOR_MODE_IDLE:
-               val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
+               if (!sreg->eco_mode_mask)
+                       return -EINVAL;
+
+               val = sreg->eco_mode_mask;
                break;
        default:
                return -EINVAL;
        }
 
-       return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
                                  sreg->eco_mode_mask, val);
 }
 
@@ -177,9 +170,9 @@ hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
 static const struct regulator_ops hi6421_spmi_ldo_rops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = hi6421_spmi_regulator_enable,
-       .disable = hi6421_spmi_regulator_disable,
+       .disable = regulator_disable_regmap,
        .list_voltage = regulator_list_voltage_table,
-       .map_voltage = regulator_map_voltage_iterate,
+       .map_voltage = regulator_map_voltage_ascend,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_mode = hi6421_spmi_regulator_get_mode,
@@ -238,7 +231,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
 {
        struct device *pmic_dev = pdev->dev.parent;
        struct regulator_config config = { };
-       struct hi6421_spmi_reg_info *sreg;
+       struct hi6421_spmi_reg_priv *priv;
        struct hi6421_spmi_reg_info *info;
        struct device *dev = &pdev->dev;
        struct hi6421_spmi_pmic *pmic;
@@ -254,18 +247,18 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
        if (WARN_ON(!pmic))
                return -ENODEV;
 
-       sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
-       if (!sreg)
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
-       sreg->pmic = pmic;
-       mutex_init(&sreg->enable_mutex);
+       mutex_init(&priv->enable_mutex);
+       platform_set_drvdata(pdev, priv);
 
        for (i = 0; i < ARRAY_SIZE(regulator_info); i++) {
                info = &regulator_info[i];
 
                config.dev = pdev->dev.parent;
-               config.driver_data = sreg;
+               config.driver_data = info;
                config.regmap = pmic->regmap;
 
                rdev = devm_regulator_register(dev, &info->desc, &config);
index 68cdb17..556bb73 100644 (file)
@@ -72,7 +72,7 @@ enum hi655x_regulator_id {
 static int hi655x_is_enabled(struct regulator_dev *rdev)
 {
        unsigned int value = 0;
-       struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+       const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
 
        regmap_read(rdev->regmap, regulator->status_reg, &value);
        return (value & rdev->desc->enable_mask);
@@ -80,7 +80,7 @@ static int hi655x_is_enabled(struct regulator_dev *rdev)
 
 static int hi655x_disable(struct regulator_dev *rdev)
 {
-       struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+       const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
 
        return regmap_write(rdev->regmap, regulator->disable_reg,
                            rdev->desc->enable_mask);
@@ -169,7 +169,6 @@ static const struct hi655x_regulator regulators[] = {
 static int hi655x_regulator_probe(struct platform_device *pdev)
 {
        unsigned int i;
-       struct hi655x_regulator *regulator;
        struct hi655x_pmic *pmic;
        struct regulator_config config = { };
        struct regulator_dev *rdev;
@@ -180,22 +179,17 @@ static int hi655x_regulator_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
-       if (!regulator)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, regulator);
-
        config.dev = pdev->dev.parent;
        config.regmap = pmic->regmap;
-       config.driver_data = regulator;
        for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+               config.driver_data = (void *) &regulators[i];
+
                rdev = devm_regulator_register(&pdev->dev,
                                               &regulators[i].rdesc,
                                               &config);
                if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev, "failed to register regulator %s\n",
-                               regulator->rdesc.name);
+                               regulators[i].rdesc.name);
                        return PTR_ERR(rdev);
                }
        }
index 2391b56..1e9c716 100644 (file)
 
 #define REGULATOR_STATES_NUM   (PM_SUSPEND_MAX + 1)
 
+#define rdev_crit(rdev, fmt, ...)                                      \
+       pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_err(rdev, fmt, ...)                                       \
+       pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_warn(rdev, fmt, ...)                                      \
+       pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_info(rdev, fmt, ...)                                      \
+       pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_dbg(rdev, fmt, ...)                                       \
+       pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+
 struct regulator_voltage {
        int min_uV;
        int max_uV;
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
new file mode 100644 (file)
index 0000000..fabe2e5
--- /dev/null
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2021 ROHM Semiconductors
+// regulator IRQ based event notification helpers
+//
+// Logic has been partially adapted from qcom-labibb driver.
+//
+// Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regulator/driver.h>
+
+#include "internal.h"
+
+#define REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS 10000
+
+struct regulator_irq {
+       struct regulator_irq_data rdata;
+       struct regulator_irq_desc desc;
+       int irq;
+       int retry_cnt;
+       struct delayed_work isr_work;
+};
+
+/*
+ * Should only be called from threaded handler to prevent potential deadlock
+ */
+static void rdev_flag_err(struct regulator_dev *rdev, int err)
+{
+       spin_lock(&rdev->err_lock);
+       rdev->cached_err |= err;
+       spin_unlock(&rdev->err_lock);
+}
+
+static void rdev_clear_err(struct regulator_dev *rdev, int err)
+{
+       spin_lock(&rdev->err_lock);
+       rdev->cached_err &= ~err;
+       spin_unlock(&rdev->err_lock);
+}
+
+static void regulator_notifier_isr_work(struct work_struct *work)
+{
+       struct regulator_irq *h;
+       struct regulator_irq_desc *d;
+       struct regulator_irq_data *rid;
+       int ret = 0;
+       int tmo, i;
+       int num_rdevs;
+
+       h = container_of(work, struct regulator_irq,
+                           isr_work.work);
+       d = &h->desc;
+       rid = &h->rdata;
+       num_rdevs = rid->num_states;
+
+reread:
+       if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+               if (!d->die)
+                       return hw_protection_shutdown("Regulator HW failure? - no IC recovery",
+                                                     REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+               ret = d->die(rid);
+               /*
+                * If the 'last resort' IC recovery failed we will have
+                * nothing else left to do...
+                */
+               if (ret)
+                       return hw_protection_shutdown("Regulator HW failure. IC recovery failed",
+                                                     REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+
+               /*
+                * If h->die() was implemented we assume recovery has been
+                * attempted (probably regulator was shut down) and we
+                * just enable IRQ and bail-out.
+                */
+               goto enable_out;
+       }
+       if (d->renable) {
+               ret = d->renable(rid);
+
+               if (ret == REGULATOR_FAILED_RETRY) {
+                       /* Driver could not get current status */
+                       h->retry_cnt++;
+                       if (!d->reread_ms)
+                               goto reread;
+
+                       tmo = d->reread_ms;
+                       goto reschedule;
+               }
+
+               if (ret) {
+                       /*
+                        * IC status reading succeeded. update error info
+                        * just in case the renable changed it.
+                        */
+                       for (i = 0; i < num_rdevs; i++) {
+                               struct regulator_err_state *stat;
+                               struct regulator_dev *rdev;
+
+                               stat = &rid->states[i];
+                               rdev = stat->rdev;
+                               rdev_clear_err(rdev, (~stat->errors) &
+                                                     stat->possible_errs);
+                       }
+                       h->retry_cnt++;
+                       /*
+                        * The IC indicated problem is still ON - no point in
+                        * re-enabling the IRQ. Retry later.
+                        */
+                       tmo = d->irq_off_ms;
+                       goto reschedule;
+               }
+       }
+
+       /*
+        * Either IC reported problem cleared or no status checker was provided.
+        * If problems are gone - good. If not - then the IRQ will fire again
+        * and we'll have a new nice loop. In any case we should clear error
+        * flags here and re-enable IRQs.
+        */
+       for (i = 0; i < num_rdevs; i++) {
+               struct regulator_err_state *stat;
+               struct regulator_dev *rdev;
+
+               stat = &rid->states[i];
+               rdev = stat->rdev;
+               rdev_clear_err(rdev, stat->possible_errs);
+       }
+
+       /*
+        * Things have been seemingly successful => zero retry-counter.
+        */
+       h->retry_cnt = 0;
+
+enable_out:
+       enable_irq(h->irq);
+
+       return;
+
+reschedule:
+       if (!d->high_prio)
+               mod_delayed_work(system_wq, &h->isr_work,
+                                msecs_to_jiffies(tmo));
+       else
+               mod_delayed_work(system_highpri_wq, &h->isr_work,
+                                msecs_to_jiffies(tmo));
+}
+
+static irqreturn_t regulator_notifier_isr(int irq, void *data)
+{
+       struct regulator_irq *h = data;
+       struct regulator_irq_desc *d;
+       struct regulator_irq_data *rid;
+       unsigned long rdev_map = 0;
+       int num_rdevs;
+       int ret, i;
+
+       d = &h->desc;
+       rid = &h->rdata;
+       num_rdevs = rid->num_states;
+
+       if (d->fatal_cnt)
+               h->retry_cnt++;
+
+       /*
+        * we spare a few cycles by not clearing statuses prior to this call.
+        * The IC driver must initialize the status buffers for rdevs
+        * which it indicates having active events via rdev_map.
+        *
+        * Maybe we should just to be on a safer side(?)
+        */
+       ret = d->map_event(irq, rid, &rdev_map);
+
+       /*
+        * If status reading fails (which is unlikely) we don't ack/disable
+        * IRQ but just increase fail count and retry when IRQ fires again.
+        * If retry_count exceeds the given safety limit we call IC specific die
+        * handler which can try disabling regulator(s).
+        *
+        * If no die handler is given we will just bug() as a last resort.
+        *
+        * We could try disabling all associated rdevs - but we might shoot
+        * ourselves in the head and leave the problematic regulator enabled. So
+        * if IC has no die-handler populated we just assume the regulator
+        * can't be disabled.
+        */
+       if (unlikely(ret == REGULATOR_FAILED_RETRY))
+               goto fail_out;
+
+       h->retry_cnt = 0;
+       /*
+        * Let's not disable IRQ if there were no status bits for us. We'd
+        * better leave spurious IRQ handling to genirq
+        */
+       if (ret || !rdev_map)
+               return IRQ_NONE;
+
+       /*
+        * Some events are bogus if the regulator is disabled. Skip such events
+        * if all relevant regulators are disabled
+        */
+       if (d->skip_off) {
+               for_each_set_bit(i, &rdev_map, num_rdevs) {
+                       struct regulator_dev *rdev;
+                       const struct regulator_ops *ops;
+
+                       rdev = rid->states[i].rdev;
+                       ops = rdev->desc->ops;
+
+                       /*
+                        * If any of the flagged regulators is enabled we do
+                        * handle this
+                        */
+                       if (ops->is_enabled(rdev))
+                               break;
+               }
+               if (i == num_rdevs)
+                       return IRQ_NONE;
+       }
+
+       /* Disable IRQ if HW keeps line asserted */
+       if (d->irq_off_ms)
+               disable_irq_nosync(irq);
+
+       /*
+        * IRQ seems to be for us. Let's fire correct notifiers / store error
+        * flags
+        */
+       for_each_set_bit(i, &rdev_map, num_rdevs) {
+               struct regulator_err_state *stat;
+               struct regulator_dev *rdev;
+
+               stat = &rid->states[i];
+               rdev = stat->rdev;
+
+               rdev_dbg(rdev, "Sending regulator notification EVT 0x%lx\n",
+                        stat->notifs);
+
+               regulator_notifier_call_chain(rdev, stat->notifs, NULL);
+               rdev_flag_err(rdev, stat->errors);
+       }
+
+       if (d->irq_off_ms) {
+               if (!d->high_prio)
+                       schedule_delayed_work(&h->isr_work,
+                                             msecs_to_jiffies(d->irq_off_ms));
+               else
+                       mod_delayed_work(system_highpri_wq,
+                                        &h->isr_work,
+                                        msecs_to_jiffies(d->irq_off_ms));
+       }
+
+       return IRQ_HANDLED;
+
+fail_out:
+       if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+               /* If we have no recovery, just try shut down straight away */
+               if (!d->die) {
+                       hw_protection_shutdown("Regulator failure. Retry count exceeded",
+                                              REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+               } else {
+                       ret = d->die(rid);
+                       /* If die() failed shut down as a last attempt to save the HW */
+                       if (ret)
+                               hw_protection_shutdown("Regulator failure. Recovery failed",
+                                                      REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+               }
+       }
+
+       return IRQ_NONE;
+}
+
+static int init_rdev_state(struct device *dev, struct regulator_irq *h,
+                          struct regulator_dev **rdev, int common_err,
+                          int *rdev_err, int rdev_amount)
+{
+       int i;
+
+       h->rdata.states = devm_kzalloc(dev, sizeof(*h->rdata.states) *
+                                      rdev_amount, GFP_KERNEL);
+       if (!h->rdata.states)
+               return -ENOMEM;
+
+       h->rdata.num_states = rdev_amount;
+       h->rdata.data = h->desc.data;
+
+       for (i = 0; i < rdev_amount; i++) {
+               h->rdata.states[i].possible_errs = common_err;
+               if (rdev_err)
+                       h->rdata.states[i].possible_errs |= *rdev_err++;
+               h->rdata.states[i].rdev = *rdev++;
+       }
+
+       return 0;
+}
+
+static void init_rdev_errors(struct regulator_irq *h)
+{
+       int i;
+
+       for (i = 0; i < h->rdata.num_states; i++)
+               if (h->rdata.states[i].possible_errs)
+                       h->rdata.states[i].rdev->use_cached_err = true;
+}
+
+/**
+ * regulator_irq_helper - register IRQ based regulator event/error notifier
+ *
+ * @dev:               device providing the IRQs
+ * @d:                 IRQ helper descriptor.
+ * @irq:               IRQ used to inform events/errors to be notified.
+ * @irq_flags:         Extra IRQ flags to be OR'ed with the default
+ *                     IRQF_ONESHOT when requesting the (threaded) irq.
+ * @common_errs:       Errors which can be flagged by this IRQ for all rdevs.
+ *                     When IRQ is re-enabled these errors will be cleared
+ *                     from all associated regulators
+ * @per_rdev_errs:     Optional error flag array describing errors specific
+ *                     for only some of the regulators. These errors will be
+ *                     or'ed with common errors. If this is given the array
+ *                     should contain rdev_amount flags. Can be set to NULL
+ *                     if there is no regulator specific error flags for this
+ *                     IRQ.
+ * @rdev:              Array of pointers to regulators associated with this
+ *                     IRQ.
+ * @rdev_amount:       Amount of regulators associated with this IRQ.
+ *
+ * Return: handle to irq_helper or an ERR_PTR() encoded error code.
+ */
+void *regulator_irq_helper(struct device *dev,
+                          const struct regulator_irq_desc *d, int irq,
+                          int irq_flags, int common_errs, int *per_rdev_errs,
+                          struct regulator_dev **rdev, int rdev_amount)
+{
+       struct regulator_irq *h;
+       int ret;
+
+       if (!rdev_amount || !d || !d->map_event || !d->name)
+               return ERR_PTR(-EINVAL);
+
+       h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
+       if (!h)
+               return ERR_PTR(-ENOMEM);
+
+       h->irq = irq;
+       h->desc = *d;
+
+       ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs,
+                             rdev_amount);
+       if (ret)
+               return ERR_PTR(ret);
+
+       init_rdev_errors(h);
+
+       if (h->desc.irq_off_ms)
+               INIT_DELAYED_WORK(&h->isr_work, regulator_notifier_isr_work);
+
+       ret = request_threaded_irq(h->irq, NULL, regulator_notifier_isr,
+                                  IRQF_ONESHOT | irq_flags, h->desc.name, h);
+       if (ret) {
+               dev_err(dev, "Failed to request IRQ %d\n", irq);
+
+               return ERR_PTR(ret);
+       }
+
+       return h;
+}
+EXPORT_SYMBOL_GPL(regulator_irq_helper);
+
+/**
+ * regulator_irq_helper_cancel - drop IRQ based regulator event/error notifier
+ *
+ * @handle:            Pointer to handle returned by a successful call to
+ *                     regulator_irq_helper(). Will be NULLed upon return.
+ *
+ * The associated IRQ is released and work is cancelled when the function
+ * returns.
+ */
+void regulator_irq_helper_cancel(void **handle)
+{
+       if (handle && *handle) {
+               struct regulator_irq *h = *handle;
+
+               free_irq(h->irq, h);
+               if (h->desc.irq_off_ms)
+                       cancel_delayed_work_sync(&h->isr_work);
+
+               h = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel);
index 13c5357..321bec6 100644 (file)
@@ -136,52 +136,9 @@ err_i2c:
        return 0;
 }
 
-static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
-{
-       int ret;
-       unsigned int regval = 0x00;
-       enum lp8755_bucks id = rdev_get_id(rdev);
-
-       /* uV/us */
-       switch (ramp) {
-       case 0 ... 230:
-               regval = 0x07;
-               break;
-       case 231 ... 470:
-               regval = 0x06;
-               break;
-       case 471 ... 940:
-               regval = 0x05;
-               break;
-       case 941 ... 1900:
-               regval = 0x04;
-               break;
-       case 1901 ... 3800:
-               regval = 0x03;
-               break;
-       case 3801 ... 7500:
-               regval = 0x02;
-               break;
-       case 7501 ... 15000:
-               regval = 0x01;
-               break;
-       case 15001 ... 30000:
-               regval = 0x00;
-               break;
-       default:
-               dev_err(&rdev->dev,
-                       "Not supported ramp value %d %s\n", ramp, __func__);
-               return -EINVAL;
-       }
-
-       ret = regmap_update_bits(rdev->regmap, 0x07 + id, 0x07, regval);
-       if (ret < 0)
-               goto err_i2c;
-       return ret;
-err_i2c:
-       dev_err(&rdev->dev, "i2c access error %s\n", __func__);
-       return ret;
-}
+static const unsigned int lp8755_buck_ramp_table[] = {
+       30000, 15000, 7500, 3800, 1900, 940, 470, 230
+};
 
 static const struct regulator_ops lp8755_buck_ops = {
        .map_voltage = regulator_map_voltage_linear,
@@ -194,7 +151,7 @@ static const struct regulator_ops lp8755_buck_ops = {
        .enable_time = lp8755_buck_enable_time,
        .set_mode = lp8755_buck_set_mode,
        .get_mode = lp8755_buck_get_mode,
-       .set_ramp_delay = lp8755_buck_set_ramp,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 #define lp8755_rail(_id) "lp8755_buck"#_id
@@ -269,6 +226,10 @@ out_i2c_error:
        .enable_mask = LP8755_BUCK_EN_M,\
        .vsel_reg = LP8755_REG_BUCK##_id,\
        .vsel_mask = LP8755_BUCK_VOUT_M,\
+       .ramp_reg = (LP8755_BUCK##_id) + 0x7,\
+       .ramp_mask = 0x7,\
+       .ramp_delay_table = lp8755_buck_ramp_table,\
+       .n_ramp_values = ARRAY_SIZE(lp8755_buck_ramp_table),\
 }
 
 static const struct regulator_desc lp8755_regulators[] = {
index 38f7ccb..5e0b669 100644 (file)
 #define LTC3589_VCCR_SW3_GO            BIT(4)
 #define LTC3589_VCCR_LDO2_GO           BIT(6)
 
+#define LTC3589_VRRCR_SW1_RAMP_MASK    GENMASK(1, 0)
+#define LTC3589_VRRCR_SW2_RAMP_MASK    GENMASK(3, 2)
+#define LTC3589_VRRCR_SW3_RAMP_MASK    GENMASK(5, 4)
+#define LTC3589_VRRCR_LDO2_RAMP_MASK   GENMASK(7, 6)
+
 enum ltc3589_variant {
        LTC3589,
        LTC3589_1,
@@ -88,27 +93,9 @@ static const int ltc3589_12_ldo4[] = {
        1200000, 1800000, 2500000, 3200000,
 };
 
-static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
-       int sel, shift;
-
-       if (unlikely(ramp_delay <= 0))
-               return -EINVAL;
-
-       /* VRRCR slew rate offsets are the same as VCCR go bit offsets */
-       shift = ffs(rdev->desc->apply_bit) - 1;
-
-       /* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */
-       for (sel = 0; sel < 4; sel++) {
-               if ((880 << sel) >= ramp_delay) {
-                       return regmap_update_bits(ltc3589->regmap,
-                                                 LTC3589_VRRCR,
-                                                 0x3 << shift, sel << shift);
-               }
-       }
-       return -EINVAL;
-}
+static const unsigned int ltc3589_ramp_table[] = {
+       880, 1750, 3500, 7000
+};
 
 static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
@@ -149,7 +136,7 @@ static const struct regulator_ops ltc3589_linear_regulator_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_ramp_delay = ltc3589_set_ramp_delay,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
        .set_voltage_time_sel = regulator_set_voltage_time_sel,
        .set_suspend_voltage = ltc3589_set_suspend_voltage,
        .set_suspend_mode = ltc3589_set_suspend_mode,
@@ -218,16 +205,13 @@ static int ltc3589_of_parse_cb(struct device_node *np,
        return 0;
 }
 
-#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit)\
+#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask\
        [LTC3589_ ## _name] = {                                         \
                .name = #_name,                                         \
                .of_match = of_match_ptr(#_of_name),                    \
                .regulators_node = of_match_ptr("regulators"),          \
                .of_parse_cb = ltc3589_of_parse_cb,                     \
                .n_voltages = (dtv_mask) + 1,                           \
-               .min_uV = (go_bit) ? 362500 : 0,                        \
-               .uV_step = (go_bit) ? 12500 : 0,                        \
-               .ramp_delay = (go_bit) ? 1750 : 0,                      \
                .fixed_uV = (dtv_mask) ? 0 : 800000,                    \
                .ops = &ltc3589_ ## _ops ## _regulator_ops,             \
                .type = REGULATOR_VOLTAGE,                              \
@@ -235,30 +219,49 @@ static int ltc3589_of_parse_cb(struct device_node *np,
                .owner = THIS_MODULE,                                   \
                .vsel_reg = (dtv1_reg),                                 \
                .vsel_mask = (dtv_mask),                                \
-               .apply_reg = (go_bit) ? LTC3589_VCCR : 0,               \
-               .apply_bit = (go_bit),                                  \
                .enable_reg = (en_bit) ? LTC3589_OVEN : 0,              \
                .enable_mask = (en_bit),                                \
        }
 
 #define LTC3589_LINEAR_REG(_name, _of_name, _dtv1)                     \
-       LTC3589_REG(_name, _of_name, linear, LTC3589_OVEN_ ## _name,    \
-                   LTC3589_ ## _dtv1, 0x1f,                            \
-                   LTC3589_VCCR_ ## _name ## _GO)
+       [LTC3589_ ## _name] = {                                         \
+               .name = #_name,                                         \
+               .of_match = of_match_ptr(#_of_name),                    \
+               .regulators_node = of_match_ptr("regulators"),          \
+               .of_parse_cb = ltc3589_of_parse_cb,                     \
+               .n_voltages = 32,                                       \
+               .min_uV = 362500,                                       \
+               .uV_step = 12500,                                       \
+               .ramp_delay = 1750,                                     \
+               .ops = &ltc3589_linear_regulator_ops,                   \
+               .type = REGULATOR_VOLTAGE,                              \
+               .id = LTC3589_ ## _name,                                \
+               .owner = THIS_MODULE,                                   \
+               .vsel_reg = LTC3589_ ## _dtv1,                          \
+               .vsel_mask = 0x1f,                                      \
+               .apply_reg = LTC3589_VCCR,                              \
+               .apply_bit = LTC3589_VCCR_ ## _name ## _GO,             \
+               .enable_reg = LTC3589_OVEN,                             \
+               .enable_mask = (LTC3589_OVEN_ ## _name),                \
+               .ramp_reg = LTC3589_VRRCR,                              \
+               .ramp_mask = LTC3589_VRRCR_ ## _name ## _RAMP_MASK,     \
+               .ramp_delay_table = ltc3589_ramp_table,                 \
+               .n_ramp_values = ARRAY_SIZE(ltc3589_ramp_table),        \
+       }
+
 
 #define LTC3589_FIXED_REG(_name, _of_name)                             \
-       LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0)
+       LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0)
 
 static const struct regulator_desc ltc3589_regulators[] = {
        LTC3589_LINEAR_REG(SW1, sw1, B1DTV1),
        LTC3589_LINEAR_REG(SW2, sw2, B2DTV1),
        LTC3589_LINEAR_REG(SW3, sw3, B3DTV1),
        LTC3589_FIXED_REG(BB_OUT, bb-out),
-       LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0),
+       LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0),
        LTC3589_LINEAR_REG(LDO2, ldo2, L2DTV1),
        LTC3589_FIXED_REG(LDO3, ldo3),
-       LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2,
-                   0x60, 0),
+       LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60),
 };
 
 static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg)
index 9089ec6..55a07d3 100644 (file)
 #define MAX77686_REGULATORS    MAX77686_REG_MAX
 #define MAX77686_LDOS          26
 
-enum max77686_ramp_rate {
-       RAMP_RATE_13P75MV,
-       RAMP_RATE_27P5MV,
-       RAMP_RATE_55MV,
-       RAMP_RATE_NO_CTRL,      /* 100mV/us */
-};
-
 struct max77686_data {
        struct device *dev;
        DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
@@ -220,31 +213,6 @@ static int max77686_enable(struct regulator_dev *rdev)
                                  max77686->opmode[id] << shift);
 }
 
-static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       unsigned int ramp_value = RAMP_RATE_NO_CTRL;
-
-       switch (ramp_delay) {
-       case 1 ... 13750:
-               ramp_value = RAMP_RATE_13P75MV;
-               break;
-       case 13751 ... 27500:
-               ramp_value = RAMP_RATE_27P5MV;
-               break;
-       case 27501 ... 55000:
-               ramp_value = RAMP_RATE_55MV;
-               break;
-       case 55001 ... 100000:
-               break;
-       default:
-               pr_warn("%s: ramp_delay: %d not supported, setting 100000\n",
-                       rdev->desc->name, ramp_delay);
-       }
-
-       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
-                                 MAX77686_RAMP_RATE_MASK, ramp_value << 6);
-}
-
 static int max77686_of_parse_cb(struct device_node *np,
                const struct regulator_desc *desc,
                struct regulator_config *config)
@@ -284,6 +252,10 @@ static int max77686_of_parse_cb(struct device_node *np,
        return 0;
 }
 
+static const unsigned int max77686_buck_dvs_ramp_table[] = {
+       13750, 27500, 55000, 100000
+};
+
 static const struct regulator_ops max77686_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
@@ -330,7 +302,7 @@ static const struct regulator_ops max77686_buck_dvs_ops = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
-       .set_ramp_delay         = max77686_set_ramp_delay,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
        .set_suspend_disable    = max77686_set_suspend_disable,
 };
 
@@ -462,6 +434,10 @@ static const struct regulator_ops max77686_buck_dvs_ops = {
        .enable_reg     = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10,     \
        .enable_mask    = MAX77686_OPMODE_MASK                          \
                        << MAX77686_OPMODE_BUCK234_SHIFT,               \
+       .ramp_reg       = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10,     \
+       .ramp_mask      = MAX77686_RAMP_RATE_MASK,                      \
+       .ramp_delay_table = max77686_buck_dvs_ramp_table,               \
+       .n_ramp_values  = ARRAY_SIZE(max77686_buck_dvs_ramp_table),     \
 }
 
 static const struct regulator_desc regulators[] = {
index 7b8ec8c..21e0eb0 100644 (file)
 #define MAX77802_OFF_PWRREQ            0x1
 #define MAX77802_LP_PWRREQ             0x2
 
-/* MAX77802 has two register formats: 2-bit and 4-bit */
-static const unsigned int ramp_table_77802_2bit[] = {
+static const unsigned int max77802_buck234_ramp_table[] = {
        12500,
        25000,
        50000,
        100000,
 };
 
-static unsigned int ramp_table_77802_4bit[] = {
+static const unsigned int max77802_buck16_ramp_table[] = {
        1000,   2000,   3030,   4000,
        5000,   5880,   7140,   8330,
        9090,   10000,  11110,  12500,
@@ -221,58 +220,6 @@ static int max77802_enable(struct regulator_dev *rdev)
                                  max77802->opmode[id] << shift);
 }
 
-static int max77802_find_ramp_value(struct regulator_dev *rdev,
-                                   const unsigned int limits[], int size,
-                                   unsigned int ramp_delay)
-{
-       int i;
-
-       for (i = 0; i < size; i++) {
-               if (ramp_delay <= limits[i])
-                       return i;
-       }
-
-       /* Use maximum value for no ramp control */
-       dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n",
-                rdev->desc->name, ramp_delay);
-       return size - 1;
-}
-
-/* Used for BUCKs 2-4 */
-static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev,
-                                       int ramp_delay)
-{
-       int id = rdev_get_id(rdev);
-       unsigned int ramp_value;
-
-       if (id > MAX77802_BUCK4) {
-               dev_warn(&rdev->dev,
-                        "%s: regulator: ramp delay not supported\n",
-                        rdev->desc->name);
-               return -EINVAL;
-       }
-       ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit,
-                               ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay);
-
-       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
-                                 MAX77802_RAMP_RATE_MASK_2BIT,
-                                 ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT);
-}
-
-/* For BUCK1, 6 */
-static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
-                                           int ramp_delay)
-{
-       unsigned int ramp_value;
-
-       ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit,
-                               ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay);
-
-       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
-                                 MAX77802_RAMP_RATE_MASK_4BIT,
-                                 ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT);
-}
-
 /*
  * LDOs 2, 4-19, 22-35
  */
@@ -316,7 +263,7 @@ static const struct regulator_ops max77802_buck_16_dvs_ops = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
-       .set_ramp_delay         = max77802_set_ramp_delay_4bit,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
        .set_suspend_disable    = max77802_set_suspend_disable,
 };
 
@@ -330,7 +277,7 @@ static const struct regulator_ops max77802_buck_234_ops = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
-       .set_ramp_delay         = max77802_set_ramp_delay_2bit,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
        .set_suspend_disable    = max77802_set_suspend_disable,
        .set_suspend_mode       = max77802_set_suspend_mode,
 };
@@ -345,7 +292,6 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
-       .set_ramp_delay         = max77802_set_ramp_delay_2bit,
        .set_suspend_disable    = max77802_set_suspend_disable,
 };
 
@@ -409,6 +355,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
        .vsel_mask      = MAX77802_DVS_VSEL_MASK,                       \
        .enable_reg     = MAX77802_REG_BUCK ## num ## CTRL,             \
        .enable_mask    = MAX77802_OPMODE_MASK,                         \
+       .ramp_reg       = MAX77802_REG_BUCK ## num ## CTRL,             \
+       .ramp_mask      = MAX77802_RAMP_RATE_MASK_4BIT,                 \
+       .ramp_delay_table = max77802_buck16_ramp_table,                 \
+       .n_ramp_values  = ARRAY_SIZE(max77802_buck16_ramp_table),       \
        .of_map_mode    = max77802_map_mode,                            \
 }
 
@@ -431,6 +381,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
        .enable_reg     = MAX77802_REG_BUCK ## num ## CTRL1,            \
        .enable_mask    = MAX77802_OPMODE_MASK <<                       \
                                MAX77802_OPMODE_BUCK234_SHIFT,          \
+       .ramp_reg       = MAX77802_REG_BUCK ## num ## CTRL1,            \
+       .ramp_mask      = MAX77802_RAMP_RATE_MASK_2BIT,                 \
+       .ramp_delay_table = max77802_buck234_ramp_table,                \
+       .n_ramp_values  = ARRAY_SIZE(max77802_buck234_ramp_table),      \
        .of_map_mode    = max77802_map_mode,                            \
 }
 
diff --git a/drivers/regulator/max8893.c b/drivers/regulator/max8893.c
new file mode 100644 (file)
index 0000000..1519bf7
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+static const struct regulator_ops max8893_ops = {
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+};
+
+static const struct regulator_desc max8893_regulators[] = {
+       {
+               .name = "BUCK",
+               .supply_name = "in-buck",
+               .of_match = of_match_ptr("buck"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x11,
+               .id = 6,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 800000,
+               .uV_step = 100000,
+               .vsel_reg = 0x4,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(7),
+       },
+       {
+               .name = "LDO1",
+               .supply_name = "in-ldo1",
+               .of_match = of_match_ptr("ldo1"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x12,
+               .id = 1,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 1600000,
+               .uV_step = 100000,
+               .vsel_reg = 0x5,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(5),
+       },
+       {
+               .name = "LDO2",
+               .supply_name = "in-ldo2",
+               .of_match = of_match_ptr("ldo2"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x16,
+               .id = 2,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 1200000,
+               .uV_step = 100000,
+               .vsel_reg = 0x6,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(4),
+       },
+       {
+               .name = "LDO3",
+               .supply_name = "in-ldo3",
+               .of_match = of_match_ptr("ldo3"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x12,
+               .id = 3,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 1600000,
+               .uV_step = 100000,
+               .vsel_reg = 0x7,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(3),
+       },
+       {
+               .name = "LDO4",
+               .supply_name = "in-ldo4",
+               .of_match = of_match_ptr("ldo4"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x1a,
+               .id = 4,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 800000,
+               .uV_step = 100000,
+               .vsel_reg = 0x8,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(2),
+       },
+       {
+               .name = "LDO5",
+               .supply_name = "in-ldo5",
+               .of_match = of_match_ptr("ldo5"),
+               .regulators_node = of_match_ptr("regulators"),
+               .n_voltages = 0x1a,
+               .id = 5,
+               .ops = &max8893_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .min_uV = 800000,
+               .uV_step = 100000,
+               .vsel_reg = 0x9,
+               .vsel_mask = 0x1f,
+               .enable_reg = 0x0,
+               .enable_mask = BIT(1),
+       }
+};
+
+static const struct regmap_config max8893_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int max8893_probe_new(struct i2c_client *i2c)
+{
+       int id, ret;
+       struct regulator_config config = {.dev = &i2c->dev};
+       struct regmap *regmap = devm_regmap_init_i2c(i2c, &max8893_regmap);
+
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
+               return ret;
+       }
+
+       for (id = 0; id < ARRAY_SIZE(max8893_regulators); id++) {
+               struct regulator_dev *rdev;
+               rdev = devm_regulator_register(&i2c->dev,
+                                              &max8893_regulators[id],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       ret = PTR_ERR(rdev);
+                       dev_err(&i2c->dev, "failed to register %s: %d\n",
+                               max8893_regulators[id].name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max8893_dt_match[] = {
+       { .compatible = "maxim,max8893" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, max8893_dt_match);
+#endif
+
+static const struct i2c_device_id max8893_ids[] = {
+       { "max8893", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, max8893_ids);
+
+static struct i2c_driver max8893_driver = {
+       .probe_new      = max8893_probe_new,
+       .driver         = {
+               .name   = "max8893",
+               .of_match_table = of_match_ptr(max8893_dt_match),
+       },
+       .id_table       = max8893_ids,
+};
+
+module_i2c_driver(max8893_driver);
+
+MODULE_DESCRIPTION("Maxim MAX8893 PMIC driver");
+MODULE_AUTHOR("Sergey Larin <cerg2010cerg2010@mail.ru>");
+MODULE_LICENSE("GPL");
index 9aee144..8da8f9b 100644 (file)
@@ -265,33 +265,6 @@ static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev)
                REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 }
 
-static int max8973_set_ramp_delay(struct regulator_dev *rdev,
-               int ramp_delay)
-{
-       struct max8973_chip *max = rdev_get_drvdata(rdev);
-       unsigned int control;
-       int ret;
-
-       /* Set ramp delay */
-       if (ramp_delay <= 12000)
-               control = MAX8973_RAMP_12mV_PER_US;
-       else if (ramp_delay <= 25000)
-               control = MAX8973_RAMP_25mV_PER_US;
-       else if (ramp_delay <= 50000)
-               control = MAX8973_RAMP_50mV_PER_US;
-       else if (ramp_delay <= 200000)
-               control = MAX8973_RAMP_200mV_PER_US;
-       else
-               return -EINVAL;
-
-       ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1,
-                       MAX8973_RAMP_MASK, control);
-       if (ret < 0)
-               dev_err(max->dev, "register %d update failed, %d",
-                               MAX8973_CONTROL1, ret);
-       return ret;
-}
-
 static int max8973_set_current_limit(struct regulator_dev *rdev,
                int min_ua, int max_ua)
 {
@@ -341,6 +314,10 @@ static int max8973_get_current_limit(struct regulator_dev *rdev)
        return 9000000;
 }
 
+static const unsigned int max8973_buck_ramp_table[] = {
+       12000, 25000, 50000, 200000
+};
+
 static const struct regulator_ops max8973_dcdc_ops = {
        .get_voltage_sel        = max8973_dcdc_get_voltage_sel,
        .set_voltage_sel        = max8973_dcdc_set_voltage_sel,
@@ -348,7 +325,7 @@ static const struct regulator_ops max8973_dcdc_ops = {
        .set_mode               = max8973_dcdc_set_mode,
        .get_mode               = max8973_dcdc_get_mode,
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
-       .set_ramp_delay         = max8973_set_ramp_delay,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
 };
 
 static int max8973_init_dcdc(struct max8973_chip *max,
@@ -694,6 +671,10 @@ static int max8973_probe(struct i2c_client *client,
        max->desc.min_uV = MAX8973_MIN_VOLATGE;
        max->desc.uV_step = MAX8973_VOLATGE_STEP;
        max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE;
+       max->desc.ramp_reg = MAX8973_CONTROL1;
+       max->desc.ramp_mask = MAX8973_RAMP_MASK;
+       max->desc.ramp_delay_table = max8973_buck_ramp_table;
+       max->desc.n_ramp_values = ARRAY_SIZE(max8973_buck_ramp_table);
 
        max->dvs_gpio = (pdata->dvs_gpio) ? pdata->dvs_gpio : -EINVAL;
        max->enable_external_control = pdata->enable_ext_control;
index 88c6bd5..0426683 100644 (file)
@@ -90,10 +90,14 @@ enum mcp16502_reg {
 };
 
 /* Ramp delay (uV/us) for buck1, ldo1, ldo2. */
-static const int mcp16502_ramp_b1l12[] = { 6250, 3125, 2083, 1563 };
+static const unsigned int mcp16502_ramp_b1l12[] = {
+       6250, 3125, 2083, 1563
+};
 
 /* Ramp delay (uV/us) for buck2, buck3, buck4. */
-static const int mcp16502_ramp_b234[] = { 3125, 1563, 1042, 781 };
+static const unsigned int mcp16502_ramp_b234[] = {
+       3125, 1563, 1042, 781
+};
 
 static unsigned int mcp16502_of_map_mode(unsigned int mode)
 {
@@ -103,7 +107,7 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
        return REGULATOR_MODE_INVALID;
 }
 
-#define MCP16502_REGULATOR(_name, _id, _ranges, _ops)                  \
+#define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table)     \
        [_id] = {                                                       \
                .name                   = _name,                        \
                .regulators_node        = of_match_ptr("regulators"),   \
@@ -121,6 +125,10 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
                .vsel_mask              = MCP16502_VSEL,                \
                .enable_reg             = (((_id) + 1) << 4),           \
                .enable_mask            = MCP16502_EN,                  \
+               .ramp_reg               = MCP16502_REG_BASE(_id, CFG),  \
+               .ramp_mask              = MCP16502_DVSR,                \
+               .ramp_delay_table       = _ramp_table,                  \
+               .n_ramp_values          = ARRAY_SIZE(_ramp_table),      \
        }
 
 enum {
@@ -314,42 +322,6 @@ static int mcp16502_set_voltage_time_sel(struct regulator_dev *rdev,
        return ret;
 }
 
-static int mcp16502_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       const int *ramp;
-       int id = rdev_get_id(rdev);
-       unsigned int i, size;
-
-       switch (id) {
-       case BUCK1:
-       case LDO1:
-       case LDO2:
-               ramp = mcp16502_ramp_b1l12;
-               size = ARRAY_SIZE(mcp16502_ramp_b1l12);
-               break;
-
-       case BUCK2:
-       case BUCK3:
-       case BUCK4:
-               ramp = mcp16502_ramp_b234;
-               size = ARRAY_SIZE(mcp16502_ramp_b234);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       for (i = 0; i < size; i++) {
-               if (ramp[i] == ramp_delay)
-                       break;
-       }
-       if (i == size)
-               return -EINVAL;
-
-       return regmap_update_bits(rdev->regmap, MCP16502_REG_BASE(id, CFG),
-                                 MCP16502_DVSR, (i << 2));
-}
-
 #ifdef CONFIG_SUSPEND
 /*
  * mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC
@@ -445,7 +417,7 @@ static const struct regulator_ops mcp16502_buck_ops = {
        .is_enabled                     = regulator_is_enabled_regmap,
        .get_status                     = mcp16502_get_status,
        .set_voltage_time_sel           = mcp16502_set_voltage_time_sel,
-       .set_ramp_delay                 = mcp16502_set_ramp_delay,
+       .set_ramp_delay                 = regulator_set_ramp_delay_regmap,
 
        .set_mode                       = mcp16502_set_mode,
        .get_mode                       = mcp16502_get_mode,
@@ -471,7 +443,7 @@ static const struct regulator_ops mcp16502_ldo_ops = {
        .is_enabled                     = regulator_is_enabled_regmap,
        .get_status                     = mcp16502_get_status,
        .set_voltage_time_sel           = mcp16502_set_voltage_time_sel,
-       .set_ramp_delay                 = mcp16502_set_ramp_delay,
+       .set_ramp_delay                 = regulator_set_ramp_delay_regmap,
 
 #ifdef CONFIG_SUSPEND
        .set_suspend_voltage            = mcp16502_set_suspend_voltage,
@@ -495,13 +467,19 @@ static const struct linear_range b234_ranges[] = {
 };
 
 static const struct regulator_desc mcp16502_desc[] = {
-       /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */
-       MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops),
-       MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops),
-       MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops),
-       MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops),
-       MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops),
-       MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops)
+       /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops, ramp_table) */
+       MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops,
+                          mcp16502_ramp_b1l12),
+       MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops,
+                          mcp16502_ramp_b234),
+       MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops,
+                          mcp16502_ramp_b234),
+       MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops,
+                          mcp16502_ramp_b234),
+       MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops,
+                          mcp16502_ramp_b1l12),
+       MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops,
+                          mcp16502_ramp_b1l12)
 };
 
 static const struct regmap_range mcp16502_ranges[] = {
@@ -522,8 +500,7 @@ static const struct regmap_config mcp16502_regmap_config = {
        .wr_table       = &mcp16502_yes_reg_table,
 };
 
-static int mcp16502_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
+static int mcp16502_probe(struct i2c_client *client)
 {
        struct regulator_config config = { };
        struct regulator_dev *rdev;
@@ -606,7 +583,7 @@ static const struct i2c_device_id mcp16502_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id);
 
 static struct i2c_driver mcp16502_drv = {
-       .probe          = mcp16502_probe,
+       .probe_new      = mcp16502_probe,
        .driver         = {
                .name   = "mcp16502-regulator",
                .of_match_table = of_match_ptr(mcp16502_ids),
index 67ce1b5..39cebec 100644 (file)
                .vsel_mask = MP5416_MASK_VSET,                          \
                .enable_reg = MP5416_REG_BUCK ## _id,                   \
                .enable_mask = MP5416_REGULATOR_EN,                     \
+               .ramp_reg = MP5416_REG_CTL2,                            \
+               .ramp_mask = MP5416_MASK_DVS_SLEWRATE,                  \
+               .ramp_delay_table = mp5416_buck_ramp_table,             \
+               .n_ramp_values = ARRAY_SIZE(mp5416_buck_ramp_table),    \
                .active_discharge_on    = _dval,                        \
                .active_discharge_reg   = _dreg,                        \
                .active_discharge_mask  = _dval,                        \
@@ -123,7 +127,16 @@ static const unsigned int mp5416_I_limits2[] = {
        2200000, 3200000, 4200000, 5200000
 };
 
-static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay);
+/*
+ * DVS ramp rate BUCK1 to BUCK4
+ * 00: 32mV/us
+ * 01: 16mV/us
+ * 10: 8mV/us
+ * 11: 4mV/us
+ */
+static const unsigned int mp5416_buck_ramp_table[] = {
+       32000, 16000, 8000, 4000
+};
 
 static const struct regulator_ops mp5416_ldo_ops = {
        .enable                 = regulator_enable_regmap,
@@ -147,7 +160,7 @@ static const struct regulator_ops mp5416_buck_ops = {
        .set_active_discharge   = regulator_set_active_discharge_regmap,
        .get_current_limit      = regulator_get_current_limit_regmap,
        .set_current_limit      = regulator_set_current_limit_regmap,
-       .set_ramp_delay         = mp5416_set_ramp_delay,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
 };
 
 static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
@@ -161,33 +174,6 @@ static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
        MP5416LDO("ldo4", 4, BIT(1)),
 };
 
-/*
- * DVS ramp rate BUCK1 to BUCK4
- * 00: 32mV/us
- * 01: 16mV/us
- * 10: 8mV/us
- * 11: 4mV/us
- */
-static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       unsigned int ramp_val;
-
-       if (ramp_delay > 32000 || ramp_delay < 0)
-               return -EINVAL;
-
-       if (ramp_delay <= 4000)
-               ramp_val = 3;
-       else if (ramp_delay <= 8000)
-               ramp_val = 2;
-       else if (ramp_delay <= 16000)
-               ramp_val = 1;
-       else
-               ramp_val = 0;
-
-       return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2,
-                                 MP5416_MASK_DVS_SLEWRATE, ramp_val << 6);
-}
-
 static int mp5416_i2c_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
index a84fd74..8ad4722 100644 (file)
@@ -26,7 +26,7 @@
 
 struct mp886x_cfg_info {
        const struct regulator_ops *rops;
-       const int slew_rates[8];
+       const unsigned int slew_rates[8];
        const int switch_freq[4];
        const u8 fs_reg;
        const u8 fs_shift;
@@ -42,28 +42,6 @@ struct mp886x_device_info {
        unsigned int sel;
 };
 
-static int mp886x_set_ramp(struct regulator_dev *rdev, int ramp)
-{
-       struct mp886x_device_info *di = rdev_get_drvdata(rdev);
-       const struct mp886x_cfg_info *ci = di->ci;
-       int reg = -1, i;
-
-       for (i = 0; i < ARRAY_SIZE(ci->slew_rates); i++) {
-               if (ramp <= ci->slew_rates[i])
-                       reg = i;
-               else
-                       break;
-       }
-
-       if (reg < 0) {
-               dev_err(di->dev, "unsupported ramp value %d\n", ramp);
-               return -EINVAL;
-       }
-
-       return regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
-                                 MP886X_SLEW_MASK, reg << MP886X_SLEW_SHIFT);
-}
-
 static void mp886x_set_switch_freq(struct mp886x_device_info *di,
                                   struct regmap *regmap,
                                   u32 freq)
@@ -169,7 +147,7 @@ static const struct regulator_ops mp8869_regulator_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .set_mode = mp886x_set_mode,
        .get_mode = mp886x_get_mode,
-       .set_ramp_delay = mp886x_set_ramp,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct mp886x_cfg_info mp8869_ci = {
@@ -248,7 +226,7 @@ static const struct regulator_ops mp8867_regulator_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .set_mode = mp886x_set_mode,
        .get_mode = mp886x_get_mode,
-       .set_ramp_delay = mp886x_set_ramp,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct mp886x_cfg_info mp8867_ci = {
@@ -290,6 +268,10 @@ static int mp886x_regulator_register(struct mp886x_device_info *di,
        rdesc->uV_step = 10000;
        rdesc->vsel_reg = MP886X_VSEL;
        rdesc->vsel_mask = 0x3f;
+       rdesc->ramp_reg = MP886X_SYSCNTLREG1;
+       rdesc->ramp_mask = MP886X_SLEW_MASK;
+       rdesc->ramp_delay_table = di->ci->slew_rates;
+       rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates);
        rdesc->owner = THIS_MODULE;
 
        rdev = devm_regulator_register(di->dev, &di->desc, config);
index 6b8be52..284c229 100644 (file)
@@ -84,7 +84,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
        modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
        ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_4PHASE_ANA_CON42, &regval);
        if (ret != 0) {
-               dev_notice(&rdev->dev, "Failed to get mode: %d\n", ret);
+               dev_err(&rdev->dev, "Failed to get mode: %d\n", ret);
                return ret;
        }
 
@@ -93,7 +93,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
 
        ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_CON1, &regval);
        if (ret != 0) {
-               dev_notice(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+               dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
                return ret;
        }
 
@@ -147,12 +147,12 @@ static int mt6315_regulator_set_mode(struct regulator_dev *rdev,
                break;
        default:
                ret = -EINVAL;
-               dev_notice(&rdev->dev, "Unsupported mode: %d\n", mode);
+               dev_err(&rdev->dev, "Unsupported mode: %d\n", mode);
                break;
        }
 
        if (ret != 0) {
-               dev_notice(&rdev->dev, "Failed to set mode: %d\n", ret);
+               dev_err(&rdev->dev, "Failed to set mode: %d\n", ret);
                return ret;
        }
 
@@ -168,7 +168,7 @@ static int mt6315_get_status(struct regulator_dev *rdev)
        info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
        ret = regmap_read(rdev->regmap, info->status_reg, &regval);
        if (ret < 0) {
-               dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+               dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
                return ret;
        }
 
@@ -223,8 +223,8 @@ static int mt6315_regulator_probe(struct spmi_device *pdev)
        int i;
 
        regmap = devm_regmap_init_spmi_ext(pdev, &mt6315_regmap_config);
-       if (!regmap)
-               return -ENODEV;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
        chip = devm_kzalloc(dev, sizeof(struct mt6315_chip), GFP_KERNEL);
        if (!chip)
@@ -260,8 +260,9 @@ static int mt6315_regulator_probe(struct spmi_device *pdev)
                config.driver_data = init_data;
                rdev = devm_regulator_register(dev, &mt6315_regulators[i].desc, &config);
                if (IS_ERR(rdev)) {
-                       dev_notice(dev, "Failed to register %s\n", mt6315_regulators[i].desc.name);
-                       continue;
+                       dev_err(dev, "Failed to register %s\n",
+                               mt6315_regulators[i].desc.name);
+                       return PTR_ERR(rdev);
                }
        }
 
@@ -279,7 +280,7 @@ static void mt6315_regulator_shutdown(struct spmi_device *pdev)
        ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY, 0);
        ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY_H, 0);
        if (ret < 0)
-               dev_notice(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n",
+               dev_err(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n",
                           pdev->usid, ret);
 }
 
index 13cb6ac..0d35be4 100644 (file)
@@ -153,50 +153,50 @@ static const struct linear_range buck_volt_range4[] = {
        REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500),
 };
 
-static const u32 vdram2_voltages[] = {
+static const unsigned int vdram2_voltages[] = {
        600000, 1800000,
 };
 
-static const u32 vsim_voltages[] = {
+static const unsigned int vsim_voltages[] = {
        1700000, 1800000, 2700000, 3000000, 3100000,
 };
 
-static const u32 vibr_voltages[] = {
+static const unsigned int vibr_voltages[] = {
        1200000, 1300000, 1500000, 1800000,
        2000000, 2800000, 3000000, 3300000,
 };
 
-static const u32 vusb_voltages[] = {
+static const unsigned int vusb_voltages[] = {
        3000000, 3100000,
 };
 
-static const u32 vcamd_voltages[] = {
+static const unsigned int vcamd_voltages[] = {
        900000, 1000000, 1100000, 1200000,
        1300000, 1500000, 1800000,
 };
 
-static const u32 vefuse_voltages[] = {
+static const unsigned int vefuse_voltages[] = {
        1700000, 1800000, 1900000,
 };
 
-static const u32 vmch_vemc_voltages[] = {
+static const unsigned int vmch_vemc_voltages[] = {
        2900000, 3000000, 3300000,
 };
 
-static const u32 vcama_voltages[] = {
+static const unsigned int vcama_voltages[] = {
        1800000, 2500000, 2700000,
        2800000, 2900000, 3000000,
 };
 
-static const u32 vcn33_bt_wifi_voltages[] = {
+static const unsigned int vcn33_bt_wifi_voltages[] = {
        3300000, 3400000, 3500000,
 };
 
-static const u32 vmc_voltages[] = {
+static const unsigned int vmc_voltages[] = {
        1800000, 2900000, 3000000, 3300000,
 };
 
-static const u32 vldo28_voltages[] = {
+static const unsigned int vldo28_voltages[] = {
        2800000, 3000000,
 };
 
@@ -457,7 +457,7 @@ static struct mt6358_regulator_info mt6358_regulators[] = {
        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_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0xf, 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,
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
new file mode 100644 (file)
index 0000000..7ce0bd3
--- /dev/null
@@ -0,0 +1,997 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2021 MediaTek Inc.
+
+#include <linux/platform_device.h>
+#include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6359p/registers.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6359-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6359_BUCK_MODE_AUTO          0
+#define MT6359_BUCK_MODE_FORCE_PWM     1
+#define MT6359_BUCK_MODE_NORMAL                0
+#define MT6359_BUCK_MODE_LP            2
+
+/*
+ * MT6359 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @status_reg: for query status of regulators.
+ * @qi: Mask for query enable signal status of regulators.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @modeset_shift: SHIFT for operating modeset register.
+ */
+struct mt6359_regulator_info {
+       struct regulator_desc desc;
+       u32 status_reg;
+       u32 qi;
+       u32 modeset_reg;
+       u32 modeset_mask;
+       u32 modeset_shift;
+       u32 lp_mode_reg;
+       u32 lp_mode_mask;
+       u32 lp_mode_shift;
+};
+
+#define MT6359_BUCK(match, _name, min, max, step,              \
+       _enable_reg, _status_reg,                               \
+       _vsel_reg, _vsel_mask,                                  \
+       _lp_mode_reg, _lp_mode_shift,                           \
+       _modeset_reg, _modeset_shift)                           \
+[MT6359_ID_##_name] = {                                                \
+       .desc = {                                               \
+               .name = #_name,                                 \
+               .of_match = of_match_ptr(match),                \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .ops = &mt6359_volt_linear_ops,                 \
+               .type = REGULATOR_VOLTAGE,                      \
+               .id = MT6359_ID_##_name,                        \
+               .owner = THIS_MODULE,                           \
+               .uV_step = (step),                              \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .min_uV = (min),                                \
+               .vsel_reg = _vsel_reg,                          \
+               .vsel_mask = _vsel_mask,                        \
+               .enable_reg = _enable_reg,                      \
+               .enable_mask = BIT(0),                          \
+               .of_map_mode = mt6359_map_mode,                 \
+       },                                                      \
+       .status_reg = _status_reg,                              \
+       .qi = BIT(0),                                           \
+       .lp_mode_reg = _lp_mode_reg,                            \
+       .lp_mode_mask = BIT(_lp_mode_shift),                    \
+       .lp_mode_shift = _lp_mode_shift,                        \
+       .modeset_reg = _modeset_reg,                            \
+       .modeset_mask = BIT(_modeset_shift),                    \
+       .modeset_shift = _modeset_shift                         \
+}
+
+#define MT6359_LDO_LINEAR(match, _name, min, max, step,                \
+       _enable_reg, _status_reg, _vsel_reg, _vsel_mask)        \
+[MT6359_ID_##_name] = {                                                \
+       .desc = {                                               \
+               .name = #_name,                                 \
+               .of_match = of_match_ptr(match),                \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .ops = &mt6359_volt_linear_ops,                 \
+               .type = REGULATOR_VOLTAGE,                      \
+               .id = MT6359_ID_##_name,                        \
+               .owner = THIS_MODULE,                           \
+               .uV_step = (step),                              \
+               .n_voltages = ((max) - (min)) / (step) + 1,     \
+               .min_uV = (min),                                \
+               .vsel_reg = _vsel_reg,                          \
+               .vsel_mask = _vsel_mask,                        \
+               .enable_reg = _enable_reg,                      \
+               .enable_mask = BIT(0),                          \
+       },                                                      \
+       .status_reg = _status_reg,                              \
+       .qi = BIT(0),                                           \
+}
+
+#define MT6359_LDO(match, _name, _volt_table,                  \
+       _enable_reg, _enable_mask, _status_reg,                 \
+       _vsel_reg, _vsel_mask, _en_delay)                       \
+[MT6359_ID_##_name] = {                                                \
+       .desc = {                                               \
+               .name = #_name,                                 \
+               .of_match = of_match_ptr(match),                \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .ops = &mt6359_volt_table_ops,                  \
+               .type = REGULATOR_VOLTAGE,                      \
+               .id = MT6359_ID_##_name,                        \
+               .owner = THIS_MODULE,                           \
+               .n_voltages = ARRAY_SIZE(_volt_table),          \
+               .volt_table = _volt_table,                      \
+               .vsel_reg = _vsel_reg,                          \
+               .vsel_mask = _vsel_mask,                        \
+               .enable_reg = _enable_reg,                      \
+               .enable_mask = BIT(_enable_mask),               \
+               .enable_time = _en_delay,                       \
+       },                                                      \
+       .status_reg = _status_reg,                              \
+       .qi = BIT(0),                                           \
+}
+
+#define MT6359_REG_FIXED(match, _name, _enable_reg,    \
+       _status_reg, _fixed_volt)                       \
+[MT6359_ID_##_name] = {                                        \
+       .desc = {                                       \
+               .name = #_name,                         \
+               .of_match = of_match_ptr(match),        \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .ops = &mt6359_volt_fixed_ops,          \
+               .type = REGULATOR_VOLTAGE,              \
+               .id = MT6359_ID_##_name,                \
+               .owner = THIS_MODULE,                   \
+               .n_voltages = 1,                        \
+               .enable_reg = _enable_reg,              \
+               .enable_mask = BIT(0),                  \
+               .fixed_uV = (_fixed_volt),              \
+       },                                              \
+       .status_reg = _status_reg,                      \
+       .qi = BIT(0),                                   \
+}
+
+#define MT6359P_LDO1(match, _name, _ops, _volt_table,  \
+       _enable_reg, _enable_mask, _status_reg,         \
+       _vsel_reg, _vsel_mask)                          \
+[MT6359_ID_##_name] = {                                        \
+       .desc = {                                       \
+               .name = #_name,                         \
+               .of_match = of_match_ptr(match),        \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .ops = &_ops,                           \
+               .type = REGULATOR_VOLTAGE,              \
+               .id = MT6359_ID_##_name,                \
+               .owner = THIS_MODULE,                   \
+               .n_voltages = ARRAY_SIZE(_volt_table),  \
+               .volt_table = _volt_table,              \
+               .vsel_reg = _vsel_reg,                  \
+               .vsel_mask = _vsel_mask,                \
+               .enable_reg = _enable_reg,              \
+               .enable_mask = BIT(_enable_mask),       \
+       },                                              \
+       .status_reg = _status_reg,                      \
+       .qi = BIT(0),                                   \
+}
+
+static const unsigned int vsim1_voltages[] = {
+       0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000,
+};
+
+static const unsigned int vibr_voltages[] = {
+       1200000, 1300000, 1500000, 0, 1800000, 2000000, 0, 0, 2700000, 2800000,
+       0, 3000000, 0, 3300000,
+};
+
+static const unsigned int vrf12_voltages[] = {
+       0, 0, 1100000, 1200000, 1300000,
+};
+
+static const unsigned int volt18_voltages[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000,
+};
+
+static const unsigned int vcn13_voltages[] = {
+       900000, 1000000, 0, 1200000, 1300000,
+};
+
+static const unsigned int vcn33_voltages[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 0, 0, 0, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int vefuse_voltages[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000, 2000000,
+};
+
+static const unsigned int vxo22_voltages[] = {
+       1800000, 0, 0, 0, 2200000,
+};
+
+static const unsigned int vrfck_voltages[] = {
+       0, 0, 1500000, 0, 0, 0, 0, 1600000, 0, 0, 0, 0, 1700000,
+};
+
+static const unsigned int vrfck_voltages_1[] = {
+       1240000, 1600000,
+};
+
+static const unsigned int vio28_voltages[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 2900000, 3000000, 3100000, 3300000,
+};
+
+static const unsigned int vemc_voltages[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2900000, 3000000, 0, 3300000,
+};
+
+static const unsigned int vemc_voltages_1[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 2500000, 2800000, 2900000, 3000000, 3100000,
+       3300000,
+};
+
+static const unsigned int va12_voltages[] = {
+       0, 0, 0, 0, 0, 0, 1200000, 1300000,
+};
+
+static const unsigned int va09_voltages[] = {
+       0, 0, 800000, 900000, 0, 0, 1200000,
+};
+
+static const unsigned int vrf18_voltages[] = {
+       0, 0, 0, 0, 0, 1700000, 1800000, 1810000,
+};
+
+static const unsigned int vbbck_voltages[] = {
+       0, 0, 0, 0, 1100000, 0, 0, 0, 1150000, 0, 0, 0, 1200000,
+};
+
+static const unsigned int vsim2_voltages[] = {
+       0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000,
+};
+
+static inline unsigned int mt6359_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case MT6359_BUCK_MODE_NORMAL:
+               return REGULATOR_MODE_NORMAL;
+       case MT6359_BUCK_MODE_FORCE_PWM:
+               return REGULATOR_MODE_FAST;
+       case MT6359_BUCK_MODE_LP:
+               return REGULATOR_MODE_IDLE;
+       default:
+               return REGULATOR_MODE_INVALID;
+       }
+}
+
+static int mt6359_get_status(struct regulator_dev *rdev)
+{
+       int ret;
+       u32 regval;
+       struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+
+       ret = regmap_read(rdev->regmap, info->status_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+               return ret;
+       }
+
+       if (regval & info->qi)
+               return REGULATOR_STATUS_ON;
+       else
+               return REGULATOR_STATUS_OFF;
+}
+
+static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev)
+{
+       struct mt6359_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 mt6359 buck mode: %d\n", ret);
+               return ret;
+       }
+
+       if ((regval & info->modeset_mask) >> info->modeset_shift ==
+               MT6359_BUCK_MODE_FORCE_PWM)
+               return REGULATOR_MODE_FAST;
+
+       ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to get mt6359 buck lp mode: %d\n", ret);
+               return ret;
+       }
+
+       if (regval & info->lp_mode_mask)
+               return REGULATOR_MODE_IDLE;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6359_regulator_set_mode(struct regulator_dev *rdev,
+                                    unsigned int mode)
+{
+       struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret = 0, val;
+       int curr_mode;
+
+       curr_mode = mt6359_regulator_get_mode(rdev);
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               val = MT6359_BUCK_MODE_FORCE_PWM;
+               val <<= info->modeset_shift;
+               ret = regmap_update_bits(rdev->regmap,
+                                        info->modeset_reg,
+                                        info->modeset_mask,
+                                        val);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               if (curr_mode == REGULATOR_MODE_FAST) {
+                       val = MT6359_BUCK_MODE_AUTO;
+                       val <<= info->modeset_shift;
+                       ret = regmap_update_bits(rdev->regmap,
+                                                info->modeset_reg,
+                                                info->modeset_mask,
+                                                val);
+               } else if (curr_mode == REGULATOR_MODE_IDLE) {
+                       val = MT6359_BUCK_MODE_NORMAL;
+                       val <<= info->lp_mode_shift;
+                       ret = regmap_update_bits(rdev->regmap,
+                                                info->lp_mode_reg,
+                                                info->lp_mode_mask,
+                                                val);
+                       udelay(100);
+               }
+               break;
+       case REGULATOR_MODE_IDLE:
+               val = MT6359_BUCK_MODE_LP >> 1;
+               val <<= info->lp_mode_shift;
+               ret = regmap_update_bits(rdev->regmap,
+                                        info->lp_mode_reg,
+                                        info->lp_mode_mask,
+                                        val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ret != 0) {
+               dev_err(&rdev->dev,
+                       "Failed to set mt6359 buck mode: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev,
+                                       u32 sel)
+{
+       struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+       u32 val = 0;
+
+       sel <<= ffs(info->desc.vsel_mask) - 1;
+       ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, TMA_KEY);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val);
+       if (ret)
+               return ret;
+
+       switch (val) {
+       case 0:
+               /* If HW trapping is 0, use VEMC_VOSEL_0 */
+               ret = regmap_update_bits(rdev->regmap,
+                                        info->desc.vsel_reg,
+                                        info->desc.vsel_mask, sel);
+               break;
+       case 1:
+               /* If HW trapping is 1, use VEMC_VOSEL_1 */
+               ret = regmap_update_bits(rdev->regmap,
+                                        info->desc.vsel_reg + 0x2,
+                                        info->desc.vsel_mask, sel);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, 0);
+       return ret;
+}
+
+static int mt6359p_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+       u32 val = 0;
+
+       ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val);
+       if (ret)
+               return ret;
+       switch (val) {
+       case 0:
+               /* If HW trapping is 0, use VEMC_VOSEL_0 */
+               ret = regmap_read(rdev->regmap,
+                                 info->desc.vsel_reg, &val);
+               break;
+       case 1:
+               /* If HW trapping is 1, use VEMC_VOSEL_1 */
+               ret = regmap_read(rdev->regmap,
+                                 info->desc.vsel_reg + 0x2, &val);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (ret)
+               return ret;
+
+       val &= info->desc.vsel_mask;
+       val >>= ffs(info->desc.vsel_mask) - 1;
+
+       return val;
+}
+
+static const struct regulator_ops mt6359_volt_linear_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
+       .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,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6359_get_status,
+       .set_mode = mt6359_regulator_set_mode,
+       .get_mode = mt6359_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6359_volt_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .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,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6359_get_status,
+};
+
+static const struct regulator_ops mt6359_volt_fixed_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = mt6359_get_status,
+};
+
+static const struct regulator_ops mt6359p_vemc_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .set_voltage_sel = mt6359p_vemc_set_voltage_sel,
+       .get_voltage_sel = mt6359p_vemc_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 = mt6359_get_status,
+};
+
+/* The array is indexed by id(MT6359_ID_XXX) */
+static struct mt6359_regulator_info mt6359_regulators[] = {
+       MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+                   MT6359_RG_BUCK_VS1_EN_ADDR,
+                   MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VS1_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
+                   MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
+       MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VGPU11_EN_ADDR,
+                   MT6359_DA_VGPU11_EN_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VGPU11_LP_ADDR,
+                   MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+                   MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+       MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+                   MT6359_RG_BUCK_VMODEM_EN_ADDR,
+                   MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VMODEM_LP_ADDR,
+                   MT6359_RG_BUCK_VMODEM_LP_SHIFT,
+                   MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
+       MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPU_EN_ADDR,
+                   MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPU_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
+                   MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
+       MT6359_BUCK("buck_vcore", VCORE, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VCORE_EN_ADDR,
+                   MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+                   MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+       MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+                   MT6359_RG_BUCK_VS2_EN_ADDR,
+                   MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VS2_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
+                   MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
+       MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+                   MT6359_RG_BUCK_VPA_EN_ADDR,
+                   MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPA_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
+                   MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
+       MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPROC2_EN_ADDR,
+                   MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPROC2_LP_ADDR,
+                   MT6359_RG_BUCK_VPROC2_LP_SHIFT,
+                   MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
+       MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPROC1_EN_ADDR,
+                   MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPROC1_LP_ADDR,
+                   MT6359_RG_BUCK_VPROC1_LP_SHIFT,
+                   MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
+       MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR,
+                   MT6359_DA_VCORE_EN_ADDR,
+                   MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+                   MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+       MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359_RG_LDO_VAUD18_EN_ADDR,
+                        MT6359_DA_VAUD18_B_EN_ADDR, 1800000),
+       MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+                  MT6359_RG_LDO_VSIM1_EN_ADDR, MT6359_RG_LDO_VSIM1_EN_SHIFT,
+                  MT6359_DA_VSIM1_B_EN_ADDR, MT6359_RG_VSIM1_VOSEL_ADDR,
+                  MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+                  MT6359_RG_LDO_VIBR_EN_ADDR, MT6359_RG_LDO_VIBR_EN_SHIFT,
+                  MT6359_DA_VIBR_B_EN_ADDR, MT6359_RG_VIBR_VOSEL_ADDR,
+                  MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+                  MT6359_RG_LDO_VRF12_EN_ADDR, MT6359_RG_LDO_VRF12_EN_SHIFT,
+                  MT6359_DA_VRF12_B_EN_ADDR, MT6359_RG_VRF12_VOSEL_ADDR,
+                  MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
+                  120),
+       MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359_RG_LDO_VUSB_EN_0_ADDR,
+                        MT6359_DA_VUSB_B_EN_ADDR, 3000000),
+       MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+                         MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR,
+                         MT6359_DA_VSRAM_PROC2_B_EN_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+                  MT6359_RG_LDO_VIO18_EN_ADDR, MT6359_RG_LDO_VIO18_EN_SHIFT,
+                  MT6359_DA_VIO18_B_EN_ADDR, MT6359_RG_VIO18_VOSEL_ADDR,
+                  MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
+                  960),
+       MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+                  MT6359_RG_LDO_VCAMIO_EN_ADDR, MT6359_RG_LDO_VCAMIO_EN_SHIFT,
+                  MT6359_DA_VCAMIO_B_EN_ADDR, MT6359_RG_VCAMIO_VOSEL_ADDR,
+                  MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
+                  1290),
+       MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359_RG_LDO_VCN18_EN_ADDR,
+                        MT6359_DA_VCN18_B_EN_ADDR, 1800000),
+       MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359_RG_LDO_VFE28_EN_ADDR,
+                        MT6359_DA_VFE28_B_EN_ADDR, 2800000),
+       MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+                  MT6359_RG_LDO_VCN13_EN_ADDR, MT6359_RG_LDO_VCN13_EN_SHIFT,
+                  MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR,
+                  MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+                  MT6359_RG_LDO_VCN33_1_EN_0_ADDR,
+                  MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
+                  MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
+                  MT6359_RG_VCN33_1_VOSEL_MASK <<
+                  MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+                  MT6359_RG_LDO_VCN33_1_EN_1_ADDR,
+                  MT6359_RG_LDO_VCN33_1_EN_1_SHIFT,
+                  MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
+                  MT6359_RG_VCN33_1_VOSEL_MASK <<
+                  MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+       MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359_RG_LDO_VAUX18_EN_ADDR,
+                        MT6359_DA_VAUX18_B_EN_ADDR, 1800000),
+       MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+                         6250,
+                         MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR,
+                         MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+                  MT6359_RG_LDO_VEFUSE_EN_ADDR, MT6359_RG_LDO_VEFUSE_EN_SHIFT,
+                  MT6359_DA_VEFUSE_B_EN_ADDR, MT6359_RG_VEFUSE_VOSEL_ADDR,
+                  MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+                  MT6359_RG_LDO_VXO22_EN_ADDR, MT6359_RG_LDO_VXO22_EN_SHIFT,
+                  MT6359_DA_VXO22_B_EN_ADDR, MT6359_RG_VXO22_VOSEL_ADDR,
+                  MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
+                  120),
+       MT6359_LDO("ldo_vrfck", VRFCK, vrfck_voltages,
+                  MT6359_RG_LDO_VRFCK_EN_ADDR, MT6359_RG_LDO_VRFCK_EN_SHIFT,
+                  MT6359_DA_VRFCK_B_EN_ADDR, MT6359_RG_VRFCK_VOSEL_ADDR,
+                  MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
+                  480),
+       MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359_RG_LDO_VBIF28_EN_ADDR,
+                        MT6359_DA_VBIF28_B_EN_ADDR, 2800000),
+       MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+                  MT6359_RG_LDO_VIO28_EN_ADDR, MT6359_RG_LDO_VIO28_EN_SHIFT,
+                  MT6359_DA_VIO28_B_EN_ADDR, MT6359_RG_VIO28_VOSEL_ADDR,
+                  MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vemc", VEMC, vemc_voltages,
+                  MT6359_RG_LDO_VEMC_EN_ADDR, MT6359_RG_LDO_VEMC_EN_SHIFT,
+                  MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR,
+                  MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+                  MT6359_RG_LDO_VCN33_2_EN_0_ADDR,
+                  MT6359_RG_LDO_VCN33_2_EN_0_SHIFT,
+                  MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
+                  MT6359_RG_VCN33_2_VOSEL_MASK <<
+                  MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+                  MT6359_RG_LDO_VCN33_2_EN_1_ADDR,
+                  MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
+                  MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
+                  MT6359_RG_VCN33_2_VOSEL_MASK <<
+                  MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_va12", VA12, va12_voltages,
+                  MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT,
+                  MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR,
+                  MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_va09", VA09, va09_voltages,
+                  MT6359_RG_LDO_VA09_EN_ADDR, MT6359_RG_LDO_VA09_EN_SHIFT,
+                  MT6359_DA_VA09_B_EN_ADDR, MT6359_RG_VA09_VOSEL_ADDR,
+                  MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+                  MT6359_RG_LDO_VRF18_EN_ADDR, MT6359_RG_LDO_VRF18_EN_SHIFT,
+                  MT6359_DA_VRF18_B_EN_ADDR, MT6359_RG_VRF18_VOSEL_ADDR,
+                  MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
+                  120),
+       MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1100000, 6250,
+                         MT6359_RG_LDO_VSRAM_MD_EN_ADDR,
+                         MT6359_DA_VSRAM_MD_B_EN_ADDR,
+                         MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+                  MT6359_RG_LDO_VUFS_EN_ADDR, MT6359_RG_LDO_VUFS_EN_SHIFT,
+                  MT6359_DA_VUFS_B_EN_ADDR, MT6359_RG_VUFS_VOSEL_ADDR,
+                  MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
+                  1920),
+       MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+                  MT6359_RG_LDO_VM18_EN_ADDR, MT6359_RG_LDO_VM18_EN_SHIFT,
+                  MT6359_DA_VM18_B_EN_ADDR, MT6359_RG_VM18_VOSEL_ADDR,
+                  MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
+                  1920),
+       MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+                  MT6359_RG_LDO_VBBCK_EN_ADDR, MT6359_RG_LDO_VBBCK_EN_SHIFT,
+                  MT6359_DA_VBBCK_B_EN_ADDR, MT6359_RG_VBBCK_VOSEL_ADDR,
+                  MT6359_RG_VBBCK_VOSEL_MASK << MT6359_RG_VBBCK_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+                         MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR,
+                         MT6359_DA_VSRAM_PROC1_B_EN_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+                  MT6359_RG_LDO_VSIM2_EN_ADDR, MT6359_RG_LDO_VSIM2_EN_SHIFT,
+                  MT6359_DA_VSIM2_B_EN_ADDR, MT6359_RG_VSIM2_VOSEL_ADDR,
+                  MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+                         500000, 1293750, 6250,
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
+                         MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+};
+
+static struct mt6359_regulator_info mt6359p_regulators[] = {
+       MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+                   MT6359_RG_BUCK_VS1_EN_ADDR,
+                   MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VS1_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
+                   MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
+       MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VGPU11_EN_ADDR,
+                   MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VGPU11_LP_ADDR,
+                   MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+                   MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+       MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+                   MT6359_RG_BUCK_VMODEM_EN_ADDR,
+                   MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VMODEM_LP_ADDR,
+                   MT6359_RG_BUCK_VMODEM_LP_SHIFT,
+                   MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
+       MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPU_EN_ADDR,
+                   MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPU_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
+                   MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
+       MT6359_BUCK("buck_vcore", VCORE, 506250, 1300000, 6250,
+                   MT6359_RG_BUCK_VCORE_EN_ADDR,
+                   MT6359_DA_VCORE_EN_ADDR, MT6359P_RG_BUCK_VCORE_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+                   MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+       MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+                   MT6359_RG_BUCK_VS2_EN_ADDR,
+                   MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VS2_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
+                   MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
+       MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+                   MT6359_RG_BUCK_VPA_EN_ADDR,
+                   MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPA_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
+                   MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
+       MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPROC2_EN_ADDR,
+                   MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPROC2_LP_ADDR,
+                   MT6359_RG_BUCK_VPROC2_LP_SHIFT,
+                   MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
+       MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+                   MT6359_RG_BUCK_VPROC1_EN_ADDR,
+                   MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
+                   MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
+                   MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VPROC1_LP_ADDR,
+                   MT6359_RG_BUCK_VPROC1_LP_SHIFT,
+                   MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
+       MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, 400000, 1193750, 6250,
+                   MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR,
+                   MT6359_DA_VGPU11_EN_ADDR,
+                   MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR,
+                   MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_MASK <<
+                   MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_SHIFT,
+                   MT6359_RG_BUCK_VGPU11_LP_ADDR,
+                   MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+                   MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+       MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359P_RG_LDO_VAUD18_EN_ADDR,
+                        MT6359P_DA_VAUD18_B_EN_ADDR, 1800000),
+       MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+                  MT6359P_RG_LDO_VSIM1_EN_ADDR, MT6359P_RG_LDO_VSIM1_EN_SHIFT,
+                  MT6359P_DA_VSIM1_B_EN_ADDR, MT6359P_RG_VSIM1_VOSEL_ADDR,
+                  MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+                  MT6359P_RG_LDO_VIBR_EN_ADDR, MT6359P_RG_LDO_VIBR_EN_SHIFT,
+                  MT6359P_DA_VIBR_B_EN_ADDR, MT6359P_RG_VIBR_VOSEL_ADDR,
+                  MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+                  MT6359P_RG_LDO_VRF12_EN_ADDR, MT6359P_RG_LDO_VRF12_EN_SHIFT,
+                  MT6359P_DA_VRF12_B_EN_ADDR, MT6359P_RG_VRF12_VOSEL_ADDR,
+                  MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
+                  480),
+       MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359P_RG_LDO_VUSB_EN_0_ADDR,
+                        MT6359P_DA_VUSB_B_EN_ADDR, 3000000),
+       MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+                         MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR,
+                         MT6359P_DA_VSRAM_PROC2_B_EN_ADDR,
+                         MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+                  MT6359P_RG_LDO_VIO18_EN_ADDR, MT6359P_RG_LDO_VIO18_EN_SHIFT,
+                  MT6359P_DA_VIO18_B_EN_ADDR, MT6359P_RG_VIO18_VOSEL_ADDR,
+                  MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
+                  960),
+       MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+                  MT6359P_RG_LDO_VCAMIO_EN_ADDR,
+                  MT6359P_RG_LDO_VCAMIO_EN_SHIFT,
+                  MT6359P_DA_VCAMIO_B_EN_ADDR, MT6359P_RG_VCAMIO_VOSEL_ADDR,
+                  MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
+                  1290),
+       MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359P_RG_LDO_VCN18_EN_ADDR,
+                        MT6359P_DA_VCN18_B_EN_ADDR, 1800000),
+       MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359P_RG_LDO_VFE28_EN_ADDR,
+                        MT6359P_DA_VFE28_B_EN_ADDR, 2800000),
+       MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+                  MT6359P_RG_LDO_VCN13_EN_ADDR, MT6359P_RG_LDO_VCN13_EN_SHIFT,
+                  MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR,
+                  MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+                  MT6359P_RG_LDO_VCN33_1_EN_0_ADDR,
+                  MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
+                  MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
+                  MT6359_RG_VCN33_1_VOSEL_MASK <<
+                  MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+                  MT6359P_RG_LDO_VCN33_1_EN_1_ADDR,
+                  MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT,
+                  MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
+                  MT6359_RG_VCN33_1_VOSEL_MASK <<
+                  MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+       MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359P_RG_LDO_VAUX18_EN_ADDR,
+                        MT6359P_DA_VAUX18_B_EN_ADDR, 1800000),
+       MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+                         6250,
+                         MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR,
+                         MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
+                         MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+                  MT6359P_RG_LDO_VEFUSE_EN_ADDR,
+                  MT6359P_RG_LDO_VEFUSE_EN_SHIFT,
+                  MT6359P_DA_VEFUSE_B_EN_ADDR, MT6359P_RG_VEFUSE_VOSEL_ADDR,
+                  MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+                  MT6359P_RG_LDO_VXO22_EN_ADDR, MT6359P_RG_LDO_VXO22_EN_SHIFT,
+                  MT6359P_DA_VXO22_B_EN_ADDR, MT6359P_RG_VXO22_VOSEL_ADDR,
+                  MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO("ldo_vrfck_1", VRFCK, vrfck_voltages_1,
+                  MT6359P_RG_LDO_VRFCK_EN_ADDR, MT6359P_RG_LDO_VRFCK_EN_SHIFT,
+                  MT6359P_DA_VRFCK_B_EN_ADDR, MT6359P_RG_VRFCK_VOSEL_ADDR,
+                  MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
+                  480),
+       MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359P_RG_LDO_VBIF28_EN_ADDR,
+                        MT6359P_DA_VBIF28_B_EN_ADDR, 2800000),
+       MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+                  MT6359P_RG_LDO_VIO28_EN_ADDR, MT6359P_RG_LDO_VIO28_EN_SHIFT,
+                  MT6359P_DA_VIO28_B_EN_ADDR, MT6359P_RG_VIO28_VOSEL_ADDR,
+                  MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
+                  1920),
+       MT6359P_LDO1("ldo_vemc_1", VEMC, mt6359p_vemc_ops, vemc_voltages_1,
+                    MT6359P_RG_LDO_VEMC_EN_ADDR, MT6359P_RG_LDO_VEMC_EN_SHIFT,
+                    MT6359P_DA_VEMC_B_EN_ADDR,
+                    MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR,
+                    MT6359P_RG_LDO_VEMC_VOSEL_0_MASK <<
+                    MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT),
+       MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+                  MT6359P_RG_LDO_VCN33_2_EN_0_ADDR,
+                  MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT,
+                  MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
+                  MT6359_RG_VCN33_2_VOSEL_MASK <<
+                  MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+                  MT6359P_RG_LDO_VCN33_2_EN_1_ADDR,
+                  MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
+                  MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
+                  MT6359_RG_VCN33_2_VOSEL_MASK <<
+                  MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+       MT6359_LDO("ldo_va12", VA12, va12_voltages,
+                  MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT,
+                  MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR,
+                  MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
+                  960),
+       MT6359_LDO("ldo_va09", VA09, va09_voltages,
+                  MT6359P_RG_LDO_VA09_EN_ADDR, MT6359P_RG_LDO_VA09_EN_SHIFT,
+                  MT6359P_DA_VA09_B_EN_ADDR, MT6359P_RG_VA09_VOSEL_ADDR,
+                  MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
+                  960),
+       MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+                  MT6359P_RG_LDO_VRF18_EN_ADDR, MT6359P_RG_LDO_VRF18_EN_SHIFT,
+                  MT6359P_DA_VRF18_B_EN_ADDR, MT6359P_RG_VRF18_VOSEL_ADDR,
+                  MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
+                  240),
+       MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1293750, 6250,
+                         MT6359P_RG_LDO_VSRAM_MD_EN_ADDR,
+                         MT6359P_DA_VSRAM_MD_B_EN_ADDR,
+                         MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+                  MT6359P_RG_LDO_VUFS_EN_ADDR, MT6359P_RG_LDO_VUFS_EN_SHIFT,
+                  MT6359P_DA_VUFS_B_EN_ADDR, MT6359P_RG_VUFS_VOSEL_ADDR,
+                  MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
+                  1920),
+       MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+                  MT6359P_RG_LDO_VM18_EN_ADDR, MT6359P_RG_LDO_VM18_EN_SHIFT,
+                  MT6359P_DA_VM18_B_EN_ADDR, MT6359P_RG_VM18_VOSEL_ADDR,
+                  MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
+                  1920),
+       MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+                  MT6359P_RG_LDO_VBBCK_EN_ADDR, MT6359P_RG_LDO_VBBCK_EN_SHIFT,
+                  MT6359P_DA_VBBCK_B_EN_ADDR, MT6359P_RG_VBBCK_VOSEL_ADDR,
+                  MT6359P_RG_VBBCK_VOSEL_MASK << MT6359P_RG_VBBCK_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+                         MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR,
+                         MT6359P_DA_VSRAM_PROC1_B_EN_ADDR,
+                         MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
+       MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+                  MT6359P_RG_LDO_VSIM2_EN_ADDR, MT6359P_RG_LDO_VSIM2_EN_SHIFT,
+                  MT6359P_DA_VSIM2_B_EN_ADDR, MT6359P_RG_VSIM2_VOSEL_ADDR,
+                  MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
+                  480),
+       MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+                         500000, 1293750, 6250,
+                         MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
+                         MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
+                         MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
+                         MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+};
+
+static int mt6359_regulator_probe(struct platform_device *pdev)
+{
+       struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = {};
+       struct regulator_dev *rdev;
+       struct mt6359_regulator_info *mt6359_info;
+       int i, hw_ver;
+
+       regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver);
+       if (hw_ver >= MT6359P_CHIP_VER)
+               mt6359_info = mt6359p_regulators;
+       else
+               mt6359_info = mt6359_regulators;
+
+       config.dev = mt6397->dev;
+       config.regmap = mt6397->regmap;
+       for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) {
+               config.driver_data = mt6359_info;
+               rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name);
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id mt6359_platform_ids[] = {
+       {"mt6359-regulator", 0},
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6359_platform_ids);
+
+static struct platform_driver mt6359_regulator_driver = {
+       .driver = {
+               .name = "mt6359-regulator",
+       },
+       .probe = mt6359_regulator_probe,
+       .id_table = mt6359_platform_ids,
+};
+
+module_platform_driver(mt6359_regulator_driver);
+
+MODULE_AUTHOR("Wen Su <wen.su@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6359 PMIC");
+MODULE_LICENSE("GPL");
index 49f6c05..f54d4f1 100644 (file)
@@ -21,6 +21,62 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
        [PM_SUSPEND_MAX]        = "regulator-state-disk",
 };
 
+static void fill_limit(int *limit, int val)
+{
+       if (val)
+               if (val == 1)
+                       *limit = REGULATOR_NOTIF_LIMIT_ENABLE;
+               else
+                       *limit = val;
+       else
+               *limit = REGULATOR_NOTIF_LIMIT_DISABLE;
+}
+
+static void of_get_regulator_prot_limits(struct device_node *np,
+                               struct regulation_constraints *constraints)
+{
+       u32 pval;
+       int i;
+       static const char *const props[] = {
+               "regulator-oc-%s-microamp",
+               "regulator-ov-%s-microvolt",
+               "regulator-temp-%s-kelvin",
+               "regulator-uv-%s-microvolt",
+       };
+       struct notification_limit *limits[] = {
+               &constraints->over_curr_limits,
+               &constraints->over_voltage_limits,
+               &constraints->temp_limits,
+               &constraints->under_voltage_limits,
+       };
+       bool set[4] = {0};
+
+       /* Protection limits: */
+       for (i = 0; i < ARRAY_SIZE(props); i++) {
+               char prop[255];
+               bool found;
+               int j;
+               static const char *const lvl[] = {
+                       "protection", "error", "warn"
+               };
+               int *l[] = {
+                       &limits[i]->prot, &limits[i]->err, &limits[i]->warn,
+               };
+
+               for (j = 0; j < ARRAY_SIZE(lvl); j++) {
+                       snprintf(prop, 255, props[i], lvl[j]);
+                       found = !of_property_read_u32(np, prop, &pval);
+                       if (found)
+                               fill_limit(l[j], pval);
+                       set[i] |= found;
+               }
+       }
+       constraints->over_current_detection = set[0];
+       constraints->over_voltage_detection = set[1];
+       constraints->over_temp_detection = set[2];
+       constraints->under_voltage_detection = set[3];
+}
+
 static int of_get_regulation_constraints(struct device *dev,
                                        struct device_node *np,
                                        struct regulator_init_data **init_data,
@@ -188,6 +244,8 @@ static int of_get_regulation_constraints(struct device *dev,
        constraints->over_current_protection = of_property_read_bool(np,
                                        "regulator-over-current-protection");
 
+       of_get_regulator_prot_limits(np, constraints);
+
        for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
                switch (i) {
                case PM_SUSPEND_MEM:
index 2f7ee21..64e5f5f 100644 (file)
@@ -65,32 +65,9 @@ static const struct regmap_config pca9450_regmap_config = {
  * 10: 25mV/4usec
  * 11: 25mV/8usec
  */
-static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev,
-                                     int ramp_delay)
-{
-       int id = rdev_get_id(rdev);
-       unsigned int ramp_value;
-
-       switch (ramp_delay) {
-       case 1 ... 3125:
-               ramp_value = BUCK1_RAMP_3P125MV;
-               break;
-       case 3126 ... 6250:
-               ramp_value = BUCK1_RAMP_6P25MV;
-               break;
-       case 6251 ... 12500:
-               ramp_value = BUCK1_RAMP_12P5MV;
-               break;
-       case 12501 ... 25000:
-               ramp_value = BUCK1_RAMP_25MV;
-               break;
-       default:
-               ramp_value = BUCK1_RAMP_25MV;
-       }
-
-       return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3,
-                                 BUCK1_RAMP_MASK, ramp_value << 6);
-}
+static const unsigned int pca9450_dvs_buck_ramp_table[] = {
+       25000, 12500, 6250, 3125
+};
 
 static const struct regulator_ops pca9450_dvs_buck_regulator_ops = {
        .enable = regulator_enable_regmap,
@@ -100,7 +77,7 @@ static const struct regulator_ops pca9450_dvs_buck_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,
-       .set_ramp_delay = pca9450_dvs_set_ramp_delay,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct regulator_ops pca9450_buck_regulator_ops = {
@@ -251,6 +228,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
                        .vsel_mask = BUCK1OUT_DVS0_MASK,
                        .enable_reg = PCA9450_REG_BUCK1CTRL,
                        .enable_mask = BUCK1_ENMODE_MASK,
+                       .ramp_reg = PCA9450_REG_BUCK1CTRL,
+                       .ramp_mask = BUCK1_RAMP_MASK,
+                       .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+                       .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
                        .owner = THIS_MODULE,
                        .of_parse_cb = pca9450_set_dvs_levels,
                },
@@ -276,6 +257,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
                        .vsel_mask = BUCK2OUT_DVS0_MASK,
                        .enable_reg = PCA9450_REG_BUCK2CTRL,
                        .enable_mask = BUCK1_ENMODE_MASK,
+                       .ramp_reg = PCA9450_REG_BUCK2CTRL,
+                       .ramp_mask = BUCK2_RAMP_MASK,
+                       .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+                       .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
                        .owner = THIS_MODULE,
                        .of_parse_cb = pca9450_set_dvs_levels,
                },
@@ -301,6 +286,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
                        .vsel_mask = BUCK3OUT_DVS0_MASK,
                        .enable_reg = PCA9450_REG_BUCK3CTRL,
                        .enable_mask = BUCK3_ENMODE_MASK,
+                       .ramp_reg = PCA9450_REG_BUCK3CTRL,
+                       .ramp_mask = BUCK3_RAMP_MASK,
+                       .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+                       .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
                        .owner = THIS_MODULE,
                        .of_parse_cb = pca9450_set_dvs_levels,
                },
@@ -477,6 +466,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
                        .vsel_mask = BUCK1OUT_DVS0_MASK,
                        .enable_reg = PCA9450_REG_BUCK1CTRL,
                        .enable_mask = BUCK1_ENMODE_MASK,
+                       .ramp_reg = PCA9450_REG_BUCK1CTRL,
+                       .ramp_mask = BUCK1_RAMP_MASK,
+                       .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+                       .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
                        .owner = THIS_MODULE,
                        .of_parse_cb = pca9450_set_dvs_levels,
                },
@@ -502,6 +495,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
                        .vsel_mask = BUCK2OUT_DVS0_MASK,
                        .enable_reg = PCA9450_REG_BUCK2CTRL,
                        .enable_mask = BUCK1_ENMODE_MASK,
+                       .ramp_reg = PCA9450_REG_BUCK2CTRL,
+                       .ramp_mask = BUCK2_RAMP_MASK,
+                       .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+                       .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
                        .owner = THIS_MODULE,
                        .of_parse_cb = pca9450_set_dvs_levels,
                },
index de25e32..b3da0dc 100644 (file)
@@ -307,13 +307,21 @@ end:
        return IRQ_HANDLED;
 }
 
-static int qcom_labibb_set_ocp(struct regulator_dev *rdev)
+static int qcom_labibb_set_ocp(struct regulator_dev *rdev, int lim,
+                              int severity, bool enable)
 {
        struct labibb_regulator *vreg = rdev_get_drvdata(rdev);
        char *ocp_irq_name;
        u32 irq_flags = IRQF_ONESHOT;
        int irq_trig_low, ret;
 
+       /*
+        * labibb supports only protection - and does not support setting
+        * limit. Furthermore, we don't support disabling protection.
+        */
+       if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+               return -EINVAL;
+
        /* If there is no OCP interrupt, there's nothing to set */
        if (vreg->ocp_irq <= 0)
                return -EINVAL;
index 22fec37..6cca910 100644 (file)
@@ -811,12 +811,12 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
        RPMH_VREG("ldo28",  "ldo%s28", &pmic4_pldo,      "vdd-l16-l28"),
        RPMH_VREG("lvs1",   "vs%s1",   &pmic4_lvs,       "vin-lvs-1-2"),
        RPMH_VREG("lvs2",   "vs%s2",   &pmic4_lvs,       "vin-lvs-1-2"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
        RPMH_VREG("bob",    "bob%s1",  &pmic4_bob,       "vdd-bob"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
@@ -824,7 +824,7 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
        RPMH_VREG("smps2",  "smp%s2",  &pmic4_ftsmps426, "vdd-s2"),
        RPMH_VREG("smps3",  "smp%s3",  &pmic4_ftsmps426, "vdd-s3"),
        RPMH_VREG("smps4",  "smp%s4",  &pmic4_ftsmps426, "vdd-s4"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
@@ -856,7 +856,7 @@ static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
        RPMH_VREG("ldo16",  "ldo%s16", &pmic5_pldo,      "vdd-l13-l16-l17"),
        RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,      "vdd-l13-l16-l17"),
        RPMH_VREG("ldo18",  "ldo%s18", &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
@@ -880,7 +880,39 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
        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 pmm8155au_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_lv,   "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-l16-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-l16-l17"),
+       RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,      "vdd-l13-l16-l17"),
+       RPMH_VREG("ldo18",  "ldo%s18", &pmic5_nldo,      "vdd-l3-l4-l5-l18"),
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
@@ -906,7 +938,7 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
        RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_nldo,      "vdd-l8"),
        RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_nldo,      "vdd-l6-l9-l10"),
        RPMH_VREG("ldo10",  "ldo%s10", &pmic5_nldo,      "vdd-l6-l9-l10"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
@@ -934,7 +966,7 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
        RPMH_VREG("ldo12",  "ldo%s12", &pmic5_pldo_lv,   "vdd-l1-l12"),
        RPMH_VREG("ldo13",  "ldo%s13", &pmic5_pldo,      "vdd-l3-l4-l5-l7-l13"),
        RPMH_VREG("bob",    "bob%s1",  &pmic5_bob,       "vdd-bob"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
@@ -947,7 +979,7 @@ static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
        RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,      "vdd-l5-l6"),
        RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo,      "vdd-l5-l6"),
        RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo_lv,   "vdd-l7"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
@@ -960,7 +992,7 @@ static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
        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 const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
@@ -988,7 +1020,7 @@ static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
        RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,   "vdd-l5-l16-l17-l18-l19"),
        RPMH_VREG("ldo18",  "ldo%s18", &pmic5_pldo,   "vdd-l5-l16-l17-l18-l19"),
        RPMH_VREG("ldo19",  "ldo%s19", &pmic5_pldo,   "vdd-l5-l16-l17-l18-l19"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
@@ -1012,7 +1044,7 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
        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 pmx55_vreg_data[] = {
@@ -1039,7 +1071,7 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
        RPMH_VREG("ldo14",   "ldo%s14",   &pmic5_nldo,      "vdd-l14"),
        RPMH_VREG("ldo15",   "ldo%s15",   &pmic5_nldo,      "vdd-l15"),
        RPMH_VREG("ldo16",   "ldo%s16",   &pmic5_pldo,      "vdd-l16"),
-       {},
+       {}
 };
 
 static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
@@ -1070,6 +1102,7 @@ static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
        RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo_lv,   "vdd-l11-l17-l18-l19"),
        RPMH_VREG("ldo18",  "ldo%s18", &pmic5_pldo_lv,   "vdd-l11-l17-l18-l19"),
        RPMH_VREG("ldo19",  "ldo%s19", &pmic5_pldo_lv,   "vdd-l11-l17-l18-l19"),
+       {}
 };
 
 static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
@@ -1083,6 +1116,7 @@ static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
        RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_nldo,      "vdd-l5-l6"),
        RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_nldo,      "vdd-l5-l6"),
        RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo,      "vdd-l7-bob"),
+       {}
 };
 
 static int rpmh_regulator_probe(struct platform_device *pdev)
@@ -1176,6 +1210,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
                .data = pm8150l_vreg_data,
        },
        {
+               .compatible = "qcom,pmm8155au-rpmh-regulators",
+               .data = pmm8155au_vreg_data,
+       },
+       {
                .compatible = "qcom,pmx55-rpmh-regulators",
                .data = pmx55_vreg_data,
        },
index bb944ee..198fcc6 100644 (file)
@@ -251,6 +251,50 @@ static const struct regulator_desc pma8084_switch = {
        .ops = &rpm_switch_ops,
 };
 
+static const struct regulator_desc pm8226_hfsmps = {
+       .linear_ranges = (struct linear_range[]) {
+               REGULATOR_LINEAR_RANGE(375000,   0,  95, 12500),
+               REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 159,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_ftsmps = {
+       .linear_ranges = (struct linear_range[]) {
+               REGULATOR_LINEAR_RANGE(350000,    0, 184,  5000),
+               REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 262,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_pldo = {
+       .linear_ranges = (struct linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000,    0,  63, 12500),
+               REGULATOR_LINEAR_RANGE(1550000,  64, 126, 25000),
+               REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
+       },
+       .n_linear_ranges = 3,
+       .n_voltages = 164,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_nldo = {
+       .linear_ranges = (struct linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 64,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_switch = {
+       .ops = &rpm_switch_ops,
+};
+
 static const struct regulator_desc pm8x41_hfsmps = {
        .linear_ranges = (struct linear_range[]) {
                REGULATOR_LINEAR_RANGE( 375000,  0,  95, 12500),
@@ -405,8 +449,8 @@ static const struct regulator_desc pm8950_pldo = {
 
 static const struct regulator_desc pm8953_lnldo = {
        .linear_ranges = (struct linear_range[]) {
-               REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000),
                REGULATOR_LINEAR_RANGE(690000, 0, 7, 60000),
+               REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000),
        },
        .n_linear_ranges = 2,
        .n_voltages = 16,
@@ -746,6 +790,44 @@ static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pm8226_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8226_hfsmps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8226_ftsmps, "vdd_s2" },
+       { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8226_hfsmps, "vdd_s3" },
+       { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8226_hfsmps, "vdd_s4" },
+       { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8226_hfsmps, "vdd_s5" },
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8226_nldo, "vdd_l3_l24_l26" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8226_pldo, "vdd_l10_l11_l13" },
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8226_pldo, "vdd_l10_l11_l13" },
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8226_pldo, "vdd_l12_l14" },
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8226_pldo, "vdd_l10_l11_l13" },
+       { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8226_pldo, "vdd_l12_l14" },
+       { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+       { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+       { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+       { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+       { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8226_nldo, "vdd_l3_l24_l26" },
+       { "l25", QCOM_SMD_RPM_LDOA, 25, &pm8226_pldo, "vdd_l25" },
+       { "l26", QCOM_SMD_RPM_LDOA, 26, &pm8226_nldo, "vdd_l3_l24_l26" },
+       { "l27", QCOM_SMD_RPM_LDOA, 27, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+       { "l28", QCOM_SMD_RPM_LDOA, 28, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+       { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8226_switch, "vdd_lvs1" },
+       {}
+};
+
 static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
        { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
        { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
@@ -1092,6 +1174,7 @@ static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-mp5496-regulators", .data = &rpm_mp5496_regulators },
        { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
        { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
+       { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators },
        { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
        { .compatible = "qcom,rpm-pm8950-regulators", .data = &rpm_pm8950_regulators },
        { .compatible = "qcom,rpm-pm8953-regulators", .data = &rpm_pm8953_regulators },
index 95677c5..41424a3 100644 (file)
@@ -595,11 +595,15 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev)
        return regulator_enable_regmap(rdev);
 }
 
-static int spmi_regulator_vs_ocp(struct regulator_dev *rdev)
+static int spmi_regulator_vs_ocp(struct regulator_dev *rdev, int lim_uA,
+                                int severity, bool enable)
 {
        struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
        u8 reg = SPMI_VS_OCP_OVERRIDE;
 
+       if (lim_uA || !enable || severity != REGULATOR_SEVERITY_PROT)
+               return -EINVAL;
+
        return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, &reg, 1);
 }
 
index 457788b..2e627c2 100644 (file)
 
 #define CMD_OTG                                0x40
 #define OTG_EN                         BIT(0)
+#define OTG_CURRENT_LIMIT_CFG          0x52
+#define OTG_CURRENT_LIMIT_MASK         GENMASK(2, 0)
 #define OTG_CFG                                0x53
 #define OTG_EN_SRC_CFG                 BIT(1)
 
+static const unsigned int curr_table[] = {
+       500000, 1000000, 1500000, 2000000, 2500000, 3000000,
+};
+
 static const struct regulator_ops qcom_usb_vbus_reg_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
+       .get_current_limit = regulator_get_current_limit_regmap,
+       .set_current_limit = regulator_set_current_limit_regmap,
 };
 
 static struct regulator_desc qcom_usb_vbus_rdesc = {
@@ -30,6 +38,8 @@ static struct regulator_desc qcom_usb_vbus_rdesc = {
        .ops = &qcom_usb_vbus_reg_ops,
        .owner = THIS_MODULE,
        .type = REGULATOR_VOLTAGE,
+       .curr_table = curr_table,
+       .n_current_limits = ARRAY_SIZE(curr_table),
 };
 
 static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev)
@@ -61,6 +71,8 @@ static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev)
 
        qcom_usb_vbus_rdesc.enable_reg = base + CMD_OTG;
        qcom_usb_vbus_rdesc.enable_mask = OTG_EN;
+       qcom_usb_vbus_rdesc.csel_reg = base + OTG_CURRENT_LIMIT_CFG;
+       qcom_usb_vbus_rdesc.csel_mask = OTG_CURRENT_LIMIT_MASK;
        config.dev = dev;
        config.init_data = init_data;
        config.of_node = dev->of_node;
index e926c1a..127dc2e 100644 (file)
@@ -158,13 +158,6 @@ struct rk808_regulator_data {
        struct gpio_desc *dvs_gpio[2];
 };
 
-static const int rk808_buck_config_regs[] = {
-       RK808_BUCK1_CONFIG_REG,
-       RK808_BUCK2_CONFIG_REG,
-       RK808_BUCK3_CONFIG_REG,
-       RK808_BUCK4_CONFIG_REG,
-};
-
 static const struct linear_range rk808_ldo3_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
        REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
@@ -215,6 +208,15 @@ static const struct linear_range rk817_buck3_voltage_ranges[] = {
                               RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1),
 };
 
+static const unsigned int rk808_buck1_2_ramp_table[] = {
+       2000, 4000, 6000, 10000
+};
+
+/* RK817 RK809 */
+static const unsigned int rk817_buck1_4_ramp_table[] = {
+       3000, 6300, 12500, 25000
+};
+
 static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev)
 {
        struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
@@ -340,62 +342,6 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev,
        return regulator_set_voltage_time_sel(rdev, old_selector, new_selector);
 }
 
-static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US;
-       unsigned int reg = rk808_buck_config_regs[rdev_get_id(rdev)];
-
-       switch (ramp_delay) {
-       case 1 ... 2000:
-               ramp_value = RK808_RAMP_RATE_2MV_PER_US;
-               break;
-       case 2001 ... 4000:
-               ramp_value = RK808_RAMP_RATE_4MV_PER_US;
-               break;
-       case 4001 ... 6000:
-               ramp_value = RK808_RAMP_RATE_6MV_PER_US;
-               break;
-       case 6001 ... 10000:
-               break;
-       default:
-               pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
-                       rdev->desc->name, ramp_delay);
-       }
-
-       return regmap_update_bits(rdev->regmap, reg,
-                                 RK808_RAMP_RATE_MASK, ramp_value);
-}
-
-/*
- * RK817 RK809
- */
-static int rk817_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       unsigned int ramp_value = RK817_RAMP_RATE_25MV_PER_US;
-       unsigned int reg = RK817_BUCK_CONFIG_REG(rdev_get_id(rdev));
-
-       switch (ramp_delay) {
-       case 0 ... 3000:
-               ramp_value = RK817_RAMP_RATE_3MV_PER_US;
-               break;
-       case 3001 ... 6300:
-               ramp_value = RK817_RAMP_RATE_6_3MV_PER_US;
-               break;
-       case 6301 ... 12500:
-               ramp_value = RK817_RAMP_RATE_12_5MV_PER_US;
-               break;
-       case 12501 ... 25000:
-               break;
-       default:
-               dev_warn(&rdev->dev,
-                        "%s ramp_delay: %d not supported, setting 25000\n",
-                        rdev->desc->name, ramp_delay);
-       }
-
-       return regmap_update_bits(rdev->regmap, reg,
-                                 RK817_RAMP_RATE_MASK, ramp_value);
-}
-
 static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
 {
        unsigned int reg;
@@ -625,7 +571,7 @@ static const struct regulator_ops rk808_buck1_2_ops = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
-       .set_ramp_delay         = rk808_set_ramp_delay,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
        .set_suspend_voltage    = rk808_set_suspend_voltage,
        .set_suspend_enable     = rk808_set_suspend_enable,
        .set_suspend_disable    = rk808_set_suspend_disable,
@@ -722,7 +668,7 @@ static const struct regulator_ops rk817_buck_ops_range = {
        .set_mode               = rk8xx_set_mode,
        .get_mode               = rk8xx_get_mode,
        .set_suspend_mode       = rk8xx_set_suspend_mode,
-       .set_ramp_delay         = rk817_set_ramp_delay,
+       .set_ramp_delay         = regulator_set_ramp_delay_regmap,
        .set_suspend_voltage    = rk808_set_suspend_voltage_range,
        .set_suspend_enable     = rk817_set_suspend_enable,
        .set_suspend_disable    = rk817_set_suspend_disable,
@@ -814,6 +760,10 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_BUCK_VSEL_MASK,
                .enable_reg = RK808_DCDC_EN_REG,
                .enable_mask = BIT(0),
+               .ramp_reg = RK808_BUCK1_CONFIG_REG,
+               .ramp_mask = RK808_RAMP_RATE_MASK,
+               .ramp_delay_table = rk808_buck1_2_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table),
                .owner = THIS_MODULE,
        }, {
                .name = "DCDC_REG2",
@@ -830,6 +780,10 @@ static const struct regulator_desc rk808_reg[] = {
                .vsel_mask = RK808_BUCK_VSEL_MASK,
                .enable_reg = RK808_DCDC_EN_REG,
                .enable_mask = BIT(1),
+               .ramp_reg = RK808_BUCK2_CONFIG_REG,
+               .ramp_mask = RK808_RAMP_RATE_MASK,
+               .ramp_delay_table = rk808_buck1_2_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table),
                .owner = THIS_MODULE,
        }, {
                .name = "DCDC_REG3",
@@ -910,6 +864,10 @@ static const struct regulator_desc rk809_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -929,6 +887,10 @@ static const struct regulator_desc rk809_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -948,6 +910,10 @@ static const struct regulator_desc rk809_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -967,6 +933,10 @@ static const struct regulator_desc rk809_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        },
@@ -1052,6 +1022,10 @@ static const struct regulator_desc rk817_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -1071,6 +1045,10 @@ static const struct regulator_desc rk817_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -1090,6 +1068,10 @@ static const struct regulator_desc rk817_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        }, {
@@ -1109,6 +1091,10 @@ static const struct regulator_desc rk817_reg[] = {
                .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
                .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
                .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+               .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4),
+               .ramp_mask = RK817_RAMP_RATE_MASK,
+               .ramp_delay_table = rk817_buck1_4_ramp_table,
+               .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
                .of_map_mode = rk8xx_regulator_of_map_mode,
                .owner = THIS_MODULE,
        },
index e3aaac9..676b041 100644 (file)
@@ -108,6 +108,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
                .bypass_reg = RT4831_REG_DSVEN,
                .bypass_val_on = DSV_MODE_BYPASS,
                .bypass_val_off = DSV_MODE_NORMAL,
+               .owner = THIS_MODULE,
        },
        {
                .name = "DSVP",
@@ -125,6 +126,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
                .enable_mask = RT4831_POSEN_MASK,
                .active_discharge_reg = RT4831_REG_DSVEN,
                .active_discharge_mask = RT4831_POSADEN_MASK,
+               .owner = THIS_MODULE,
        },
        {
                .name = "DSVN",
@@ -142,6 +144,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
                .enable_mask = RT4831_NEGEN_MASK,
                .active_discharge_reg = RT4831_REG_DSVEN,
                .active_discharge_mask = RT4831_NEGADEN_MASK,
+               .owner = THIS_MODULE,
        }
 };
 
diff --git a/drivers/regulator/rt6160-regulator.c b/drivers/regulator/rt6160-regulator.c
new file mode 100644 (file)
index 0000000..5d7b0e7
--- /dev/null
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT6160_MODE_AUTO       0
+#define RT6160_MODE_FPWM       1
+
+#define RT6160_REG_CNTL                0x01
+#define RT6160_REG_STATUS      0x02
+#define RT6160_REG_DEVID       0x03
+#define RT6160_REG_VSELL       0x04
+#define RT6160_REG_VSELH       0x05
+#define RT6160_NUM_REGS                (RT6160_REG_VSELH + 1)
+
+#define RT6160_FPWM_MASK       BIT(3)
+#define RT6160_RAMPRATE_MASK   GENMASK(1, 0)
+#define RT6160_VID_MASK                GENMASK(7, 4)
+#define RT6160_VSEL_MASK       GENMASK(6, 0)
+#define RT6160_HDSTAT_MASK     BIT(4)
+#define RT6160_UVSTAT_MASK     BIT(3)
+#define RT6160_OCSTAT_MASK     BIT(2)
+#define RT6160_TSDSTAT_MASK    BIT(1)
+#define RT6160_PGSTAT_MASK     BIT(0)
+
+#define RT6160_VENDOR_ID       0xA0
+#define RT6160_VOUT_MINUV      2025000
+#define RT6160_VOUT_MAXUV      5200000
+#define RT6160_VOUT_STPUV      25000
+#define RT6160_N_VOUTS         ((RT6160_VOUT_MAXUV - RT6160_VOUT_MINUV) / RT6160_VOUT_STPUV + 1)
+
+#define RT6160_I2CRDY_TIMEUS   100
+
+struct rt6160_priv {
+       struct regulator_desc desc;
+       struct gpio_desc *enable_gpio;
+       struct regmap *regmap;
+       bool enable_state;
+};
+
+static const unsigned int rt6160_ramp_tables[] = {
+       1000, 2500, 5000, 10000
+};
+
+static int rt6160_enable(struct regulator_dev *rdev)
+{
+       struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+       if (!priv->enable_gpio)
+               return 0;
+
+       gpiod_set_value_cansleep(priv->enable_gpio, 1);
+       priv->enable_state = true;
+
+       usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100);
+
+       regcache_cache_only(priv->regmap, false);
+       return regcache_sync(priv->regmap);
+}
+
+static int rt6160_disable(struct regulator_dev *rdev)
+{
+       struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+       if (!priv->enable_gpio)
+               return -EINVAL;
+
+       /* Mark regcache as dirty and cache only before HW disabled */
+       regcache_cache_only(priv->regmap, true);
+       regcache_mark_dirty(priv->regmap);
+
+       priv->enable_state = false;
+       gpiod_set_value_cansleep(priv->enable_gpio, 0);
+
+       return 0;
+}
+
+static int rt6160_is_enabled(struct regulator_dev *rdev)
+{
+       struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+       return priv->enable_state ? 1 : 0;
+}
+
+static int rt6160_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int mode_val;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               mode_val = RT6160_FPWM_MASK;
+               break;
+       case REGULATOR_MODE_NORMAL:
+               mode_val = 0;
+               break;
+       default:
+               dev_err(&rdev->dev, "mode not supported\n");
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(regmap, RT6160_REG_CNTL, RT6160_FPWM_MASK, mode_val);
+}
+
+static unsigned int rt6160_get_mode(struct regulator_dev *rdev)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(regmap, RT6160_REG_CNTL, &val);
+       if (ret)
+               return ret;
+
+       if (val & RT6160_FPWM_MASK)
+               return REGULATOR_MODE_FAST;
+
+       return REGULATOR_MODE_NORMAL;
+}
+
+static int rt6160_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int suspend_vsel_reg;
+       int vsel;
+
+       vsel = regulator_map_voltage_linear(rdev, uV, uV);
+       if (vsel < 0)
+               return vsel;
+
+       if (rdev->desc->vsel_reg == RT6160_REG_VSELL)
+               suspend_vsel_reg = RT6160_REG_VSELH;
+       else
+               suspend_vsel_reg = RT6160_REG_VSELL;
+
+       return regmap_update_bits(regmap, suspend_vsel_reg,
+                                 RT6160_VSEL_MASK, vsel);
+}
+
+static int rt6160_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
+{
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       unsigned int val, events = 0;
+       int ret;
+
+       ret = regmap_read(regmap, RT6160_REG_STATUS, &val);
+       if (ret)
+               return ret;
+
+       if (val & (RT6160_HDSTAT_MASK | RT6160_TSDSTAT_MASK))
+               events |= REGULATOR_ERROR_OVER_TEMP;
+
+       if (val & RT6160_UVSTAT_MASK)
+               events |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+       if (val & RT6160_OCSTAT_MASK)
+               events |= REGULATOR_ERROR_OVER_CURRENT;
+
+       if (val & RT6160_PGSTAT_MASK)
+               events |= REGULATOR_ERROR_FAIL;
+
+       *flags = events;
+       return 0;
+}
+
+static const struct regulator_ops rt6160_regulator_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+       .enable = rt6160_enable,
+       .disable = rt6160_disable,
+       .is_enabled = rt6160_is_enabled,
+
+       .set_mode = rt6160_set_mode,
+       .get_mode = rt6160_get_mode,
+       .set_suspend_voltage = rt6160_set_suspend_voltage,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
+       .get_error_flags = rt6160_get_error_flags,
+};
+
+static unsigned int rt6160_of_map_mode(unsigned int mode)
+{
+       switch (mode) {
+       case RT6160_MODE_FPWM:
+               return REGULATOR_MODE_FAST;
+       case RT6160_MODE_AUTO:
+               return REGULATOR_MODE_NORMAL;
+       }
+
+       return REGULATOR_MODE_INVALID;
+}
+
+static bool rt6160_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+       if (reg >= RT6160_REG_CNTL && reg <= RT6160_REG_VSELH)
+               return true;
+       return false;
+}
+
+static bool rt6160_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       if (reg == RT6160_REG_STATUS)
+               return true;
+       return false;
+}
+
+static const struct regmap_config rt6160_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = RT6160_REG_VSELH,
+       .num_reg_defaults_raw = RT6160_NUM_REGS,
+       .cache_type = REGCACHE_FLAT,
+
+       .writeable_reg = rt6160_is_accessible_reg,
+       .readable_reg = rt6160_is_accessible_reg,
+       .volatile_reg = rt6160_is_volatile_reg,
+};
+
+static int rt6160_probe(struct i2c_client *i2c)
+{
+       struct rt6160_priv *priv;
+       struct regulator_config regulator_cfg = {};
+       struct regulator_dev *rdev;
+       bool vsel_active_low;
+       unsigned int devid;
+       int ret;
+
+       priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       vsel_active_low =
+               device_property_present(&i2c->dev, "richtek,vsel-active-low");
+
+       priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->enable_gpio)) {
+               dev_err(&i2c->dev, "Failed to get 'enable' gpio\n");
+               return PTR_ERR(priv->enable_gpio);
+       }
+       priv->enable_state = true;
+
+       usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100);
+
+       priv->regmap = devm_regmap_init_i2c(i2c, &rt6160_regmap_config);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&i2c->dev, "Failed to init regmap (%d)\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(priv->regmap, RT6160_REG_DEVID, &devid);
+       if (ret)
+               return ret;
+
+       if ((devid & RT6160_VID_MASK) != RT6160_VENDOR_ID) {
+               dev_err(&i2c->dev, "VID not correct [0x%02x]\n", devid);
+               return -ENODEV;
+       }
+
+       priv->desc.name = "rt6160-buckboost";
+       priv->desc.type = REGULATOR_VOLTAGE;
+       priv->desc.owner = THIS_MODULE;
+       priv->desc.min_uV = RT6160_VOUT_MINUV;
+       priv->desc.uV_step = RT6160_VOUT_STPUV;
+       if (vsel_active_low)
+               priv->desc.vsel_reg = RT6160_REG_VSELL;
+       else
+               priv->desc.vsel_reg = RT6160_REG_VSELH;
+       priv->desc.vsel_mask = RT6160_VSEL_MASK;
+       priv->desc.n_voltages = RT6160_N_VOUTS;
+       priv->desc.ramp_reg = RT6160_REG_CNTL;
+       priv->desc.ramp_mask = RT6160_RAMPRATE_MASK;
+       priv->desc.ramp_delay_table = rt6160_ramp_tables;
+       priv->desc.n_ramp_values = ARRAY_SIZE(rt6160_ramp_tables);
+       priv->desc.of_map_mode = rt6160_of_map_mode;
+       priv->desc.ops = &rt6160_regulator_ops;
+
+       regulator_cfg.dev = &i2c->dev;
+       regulator_cfg.of_node = i2c->dev.of_node;
+       regulator_cfg.regmap = priv->regmap;
+       regulator_cfg.driver_data = priv;
+       regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node,
+                                                            &priv->desc);
+
+       rdev = devm_regulator_register(&i2c->dev, &priv->desc, &regulator_cfg);
+       if (IS_ERR(rdev)) {
+               dev_err(&i2c->dev, "Failed to register regulator\n");
+               return PTR_ERR(rdev);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id __maybe_unused rt6160_of_match_table[] = {
+       { .compatible = "richtek,rt6160", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rt6160_of_match_table);
+
+static struct i2c_driver rt6160_driver = {
+       .driver = {
+               .name = "rt6160",
+               .of_match_table = rt6160_of_match_table,
+       },
+       .probe_new = rt6160_probe,
+};
+module_i2c_driver(rt6160_driver);
+
+MODULE_DESCRIPTION("Richtek RT6160 voltage regulator driver");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/rt6245-regulator.c b/drivers/regulator/rt6245-regulator.c
new file mode 100644 (file)
index 0000000..d3299a7
--- /dev/null
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT6245_VIRT_OCLIMIT    0x00
+#define RT6245_VIRT_OTLEVEL    0x01
+#define RT6245_VIRT_PGDLYTIME  0x02
+#define RT6245_VIRT_SLEWRATE   0x03
+#define RT6245_VIRT_SWFREQ     0x04
+#define RT6245_VIRT_VOUT       0x05
+
+#define RT6245_VOUT_MASK       GENMASK(6, 0)
+#define RT6245_SLEW_MASK       GENMASK(2, 0)
+#define RT6245_CHKSUM_MASK     BIT(7)
+#define RT6245_CODE_MASK       GENMASK(6, 0)
+
+/* HW Enable + Soft start time */
+#define RT6245_ENTIME_IN_US    5000
+
+#define RT6245_VOUT_MINUV      437500
+#define RT6245_VOUT_MAXUV      1387500
+#define RT6245_VOUT_STEPUV     12500
+#define RT6245_NUM_VOUT                ((RT6245_VOUT_MAXUV - RT6245_VOUT_MINUV) / RT6245_VOUT_STEPUV + 1)
+
+struct rt6245_priv {
+       struct gpio_desc *enable_gpio;
+       bool enable_state;
+};
+
+static int rt6245_enable(struct regulator_dev *rdev)
+{
+       struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+       struct regmap *regmap = rdev_get_regmap(rdev);
+       int ret;
+
+       if (!priv->enable_gpio)
+               return 0;
+
+       gpiod_direction_output(priv->enable_gpio, 1);
+       usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000);
+
+       regcache_cache_only(regmap, false);
+       ret = regcache_sync(regmap);
+       if (ret)
+               return ret;
+
+       priv->enable_state = true;
+       return 0;
+}
+
+static int rt6245_disable(struct regulator_dev *rdev)
+{
+       struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+       struct regmap *regmap = rdev_get_regmap(rdev);
+
+       if (!priv->enable_gpio)
+               return -EINVAL;
+
+       regcache_cache_only(regmap, true);
+       regcache_mark_dirty(regmap);
+
+       gpiod_direction_output(priv->enable_gpio, 0);
+
+       priv->enable_state = false;
+       return 0;
+}
+
+static int rt6245_is_enabled(struct regulator_dev *rdev)
+{
+       struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+
+       return priv->enable_state ? 1 : 0;
+}
+
+static const struct regulator_ops rt6245_regulator_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
+       .enable = rt6245_enable,
+       .disable = rt6245_disable,
+       .is_enabled = rt6245_is_enabled,
+};
+
+/* ramp delay dividend is 12500 uV/uS, and divisor from 1 to 8 */
+static const unsigned int rt6245_ramp_delay_table[] = {
+       12500, 6250, 4167, 3125, 2500, 2083, 1786, 1562
+};
+
+static const struct regulator_desc rt6245_regulator_desc = {
+       .name = "rt6245-regulator",
+       .ops = &rt6245_regulator_ops,
+       .type = REGULATOR_VOLTAGE,
+       .min_uV = RT6245_VOUT_MINUV,
+       .uV_step = RT6245_VOUT_STEPUV,
+       .n_voltages = RT6245_NUM_VOUT,
+       .ramp_delay_table = rt6245_ramp_delay_table,
+       .n_ramp_values = ARRAY_SIZE(rt6245_ramp_delay_table),
+       .owner = THIS_MODULE,
+       .vsel_reg = RT6245_VIRT_VOUT,
+       .vsel_mask = RT6245_VOUT_MASK,
+       .ramp_reg = RT6245_VIRT_SLEWRATE,
+       .ramp_mask = RT6245_SLEW_MASK,
+};
+
+static int rt6245_init_device_properties(struct device *dev)
+{
+       const struct {
+               const char *name;
+               unsigned int reg;
+       } rt6245_props[] = {
+               { "richtek,oc-level-select",  RT6245_VIRT_OCLIMIT },
+               { "richtek,ot-level-select", RT6245_VIRT_OTLEVEL },
+               { "richtek,pgdly-time-select", RT6245_VIRT_PGDLYTIME },
+               { "richtek,switch-freq-select", RT6245_VIRT_SWFREQ }
+       };
+       struct regmap *regmap = dev_get_regmap(dev, NULL);
+       u8 propval;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(rt6245_props); i++) {
+               ret = device_property_read_u8(dev, rt6245_props[i].name, &propval);
+               if (ret)
+                       continue;
+
+               ret = regmap_write(regmap, rt6245_props[i].reg, propval);
+               if (ret) {
+                       dev_err(dev, "Fail to apply [%s:%d]\n", rt6245_props[i].name, propval);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int rt6245_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct i2c_client *i2c = context;
+       const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 };
+       unsigned int code, bit_count;
+
+       code = func_base[reg];
+       code += val;
+
+       /* xor checksum for bit 6 to 0 */
+       bit_count = hweight8(code & RT6245_CODE_MASK);
+       if (bit_count % 2)
+               code |= RT6245_CHKSUM_MASK;
+       else
+               code &= ~RT6245_CHKSUM_MASK;
+
+       return i2c_smbus_write_byte(i2c, code);
+}
+
+static const struct reg_default rt6245_reg_defaults[] = {
+       /* Default over current 14A */
+       { RT6245_VIRT_OCLIMIT, 2 },
+       /* Default over temperature 150'c */
+       { RT6245_VIRT_OTLEVEL, 0 },
+       /* Default power good delay time 10us */
+       { RT6245_VIRT_PGDLYTIME, 1 },
+       /* Default slewrate 12.5mV/uS */
+       { RT6245_VIRT_SLEWRATE, 0 },
+       /* Default switch frequency 800KHz */
+       { RT6245_VIRT_SWFREQ, 1 },
+       /* Default voltage 750mV */
+       { RT6245_VIRT_VOUT, 0x19 }
+};
+
+static const struct regmap_config rt6245_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = RT6245_VIRT_VOUT,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = rt6245_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(rt6245_reg_defaults),
+       .reg_write = rt6245_reg_write,
+};
+
+static int rt6245_probe(struct i2c_client *i2c)
+{
+       struct rt6245_priv *priv;
+       struct regmap *regmap;
+       struct regulator_config regulator_cfg = {};
+       struct regulator_dev *rdev;
+       int ret;
+
+       priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->enable_state = true;
+
+       priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->enable_gpio)) {
+               dev_err(&i2c->dev, "Failed to get 'enable' gpio\n");
+               return PTR_ERR(priv->enable_gpio);
+       }
+
+       usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000);
+
+       regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt6245_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&i2c->dev, "Failed to initialize the regmap\n");
+               return PTR_ERR(regmap);
+       }
+
+       ret = rt6245_init_device_properties(&i2c->dev);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to initialize device properties\n");
+               return ret;
+       }
+
+       regulator_cfg.dev = &i2c->dev;
+       regulator_cfg.of_node = i2c->dev.of_node;
+       regulator_cfg.regmap = regmap;
+       regulator_cfg.driver_data = priv;
+       regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node,
+                                                            &rt6245_regulator_desc);
+       rdev = devm_regulator_register(&i2c->dev, &rt6245_regulator_desc, &regulator_cfg);
+       if (IS_ERR(rdev)) {
+               dev_err(&i2c->dev, "Failed to register regulator\n");
+               return PTR_ERR(rdev);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id __maybe_unused rt6245_of_match_table[] = {
+       { .compatible = "richtek,rt6245", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rt6245_of_match_table);
+
+static struct i2c_driver rt6245_driver = {
+       .driver = {
+               .name = "rt6245",
+               .of_match_table = rt6245_of_match_table,
+       },
+       .probe_new = rt6245_probe,
+};
+module_i2c_driver(rt6245_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT6245 Regulator Driver");
+MODULE_LICENSE("GPL v2");
index cf10fdb..2d7597c 100644 (file)
@@ -32,7 +32,8 @@ struct stpmic1_regulator_cfg {
 
 static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
 static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
-static int stpmic1_set_icc(struct regulator_dev *rdev);
+static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
+                          bool enable);
 static unsigned int stpmic1_map_mode(unsigned int mode);
 
 enum {
@@ -491,11 +492,26 @@ static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
                                  STPMIC1_BUCK_MODE_LP, value);
 }
 
-static int stpmic1_set_icc(struct regulator_dev *rdev)
+static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
+                          bool enable)
 {
        struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev);
        struct regmap *regmap = rdev_get_regmap(rdev);
 
+       /*
+        * The code seems like one bit in a register controls whether OCP is
+        * enabled. So we might be able to turn it off here is if that
+        * was requested. I won't support this because I don't have the HW.
+        * Feel free to try and implement if you have the HW and need kernel
+        * to disable this.
+        *
+        * Also, I don't know if limit can be configured or if we support
+        * error/warning instead of protect. So I just keep existing logic
+        * and assume no.
+        */
+       if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+               return -EINVAL;
+
        /* enable switch off in case of over current */
        return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask,
                                  cfg->icc_mask);
diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
new file mode 100644 (file)
index 0000000..e021ae0
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Functions to access SY3686A power management chip voltages
+//
+// Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
+//
+// Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
+//          Alistair Francis <alistair@alistair23.me>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/sy7636a.h>
+
+#define SY7636A_POLL_ENABLED_TIME 500
+
+static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev)
+{
+       int ret;
+       unsigned int val, val_h;
+
+       ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h);
+       if (ret)
+               return ret;
+
+       val |= (val_h << VCOM_ADJUST_CTRL_SHIFT);
+
+       return (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL;
+}
+
+static int sy7636a_get_status(struct regulator_dev *rdev)
+{
+       struct sy7636a *sy7636a = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       ret = gpiod_get_value_cansleep(sy7636a->pgood_gpio);
+       if (ret < 0)
+               dev_err(&rdev->dev, "Failed to read pgood gpio: %d\n", ret);
+
+       return ret;
+}
+
+static const struct regulator_ops sy7636a_vcom_volt_ops = {
+       .get_voltage = sy7636a_get_vcom_voltage_op,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_status = sy7636a_get_status,
+};
+
+static const struct regulator_desc desc = {
+       .name = "vcom",
+       .id = 0,
+       .ops = &sy7636a_vcom_volt_ops,
+       .type = REGULATOR_VOLTAGE,
+       .owner = THIS_MODULE,
+       .enable_reg = SY7636A_REG_OPERATION_MODE_CRL,
+       .enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF,
+       .poll_enabled_time = SY7636A_POLL_ENABLED_TIME,
+       .regulators_node = of_match_ptr("regulators"),
+       .of_match = of_match_ptr("vcom"),
+};
+
+static int sy7636a_regulator_probe(struct platform_device *pdev)
+{
+       struct sy7636a *sy7636a = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = { };
+       struct regulator_dev *rdev;
+       struct gpio_desc *gdp;
+       int ret;
+
+       if (!sy7636a)
+               return -EPROBE_DEFER;
+
+       platform_set_drvdata(pdev, sy7636a);
+
+       gdp = devm_gpiod_get(sy7636a->dev, "epd-pwr-good", GPIOD_IN);
+       if (IS_ERR(gdp)) {
+               dev_err(sy7636a->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
+               return PTR_ERR(gdp);
+       }
+
+       sy7636a->pgood_gpio = gdp;
+
+       ret = regmap_write(sy7636a->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
+       if (ret) {
+               dev_err(sy7636a->dev, "Failed to initialize regulator: %d\n", ret);
+               return ret;
+       }
+
+       config.dev = &pdev->dev;
+       config.dev->of_node = sy7636a->dev->of_node;
+       config.driver_data = sy7636a;
+       config.regmap = sy7636a->regmap;
+
+       rdev = devm_regulator_register(&pdev->dev, &desc, &config);
+       if (IS_ERR(rdev)) {
+               dev_err(sy7636a->dev, "Failed to register %s regulator\n",
+                       pdev->name);
+               return PTR_ERR(rdev);
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id sy7636a_regulator_id_table[] = {
+       { "sy7636a-regulator", },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table);
+
+static struct platform_driver sy7636a_regulator_driver = {
+       .driver = {
+               .name = "sy7636a-regulator",
+       },
+       .probe = sy7636a_regulator_probe,
+       .id_table = sy7636a_regulator_id_table,
+};
+module_platform_driver(sy7636a_regulator_driver);
+
+MODULE_AUTHOR("Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>");
+MODULE_DESCRIPTION("SY7636A voltage regulator driver");
+MODULE_LICENSE("GPL v2");
index 2e02e26..e75b097 100644 (file)
@@ -201,6 +201,7 @@ static const struct of_device_id uniphier_regulator_match[] = {
        },
        { /* Sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, uniphier_regulator_match);
 
 static struct platform_driver uniphier_regulator_driver = {
        .probe = uniphier_regulator_probe,
index 8e3b5a6..8ca2866 100644 (file)
@@ -29,15 +29,15 @@ struct userspace_consumer_data {
        struct regulator_bulk_data *supplies;
 };
 
-static ssize_t reg_show_name(struct device *dev,
-                         struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
 
        return sprintf(buf, "%s\n", data->name);
 }
 
-static ssize_t reg_show_state(struct device *dev,
+static ssize_t state_show(struct device *dev,
                          struct device_attribute *attr, char *buf)
 {
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
@@ -48,8 +48,8 @@ static ssize_t reg_show_state(struct device *dev,
        return sprintf(buf, "disabled\n");
 }
 
-static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
-                        const char *buf, size_t count)
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
 {
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
        bool enabled;
@@ -87,8 +87,8 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
-static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
+static DEVICE_ATTR_RO(name);
+static DEVICE_ATTR_RW(state);
 
 static struct attribute *attributes[] = {
        &dev_attr_name.attr,
index 6655035..80dc479 100644 (file)
@@ -75,7 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
        tm->tm_min = data[RTC_OFFSET_MIN];
        tm->tm_hour = data[RTC_OFFSET_HOUR];
        tm->tm_mday = data[RTC_OFFSET_DOM];
-       tm->tm_mon = data[RTC_OFFSET_MTH];
+       tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
        tm->tm_year = data[RTC_OFFSET_YEAR];
 
        ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC, sec);
index ecefc25..337353c 100644 (file)
@@ -135,12 +135,13 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
 {
        struct ap_queue_status status;
        struct ap_message *ap_msg;
+       bool found = false;
 
        status = ap_dqap(aq->qid, &aq->reply->psmid,
                         aq->reply->msg, aq->reply->len);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
-               aq->queue_count--;
+               aq->queue_count = max_t(int, 0, aq->queue_count - 1);
                if (aq->queue_count > 0)
                        mod_timer(&aq->timeout,
                                  jiffies + aq->request_timeout);
@@ -150,8 +151,14 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
                        list_del_init(&ap_msg->list);
                        aq->pendingq_count--;
                        ap_msg->receive(aq, ap_msg, aq->reply);
+                       found = true;
                        break;
                }
+               if (!found) {
+                       AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n",
+                                   __func__, aq->reply->psmid,
+                                   AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+               }
                fallthrough;
        case AP_RESPONSE_NO_PENDING_REPLY:
                if (!status.queue_empty || aq->queue_count <= 0)
@@ -232,7 +239,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
                           ap_msg->flags & AP_MSG_FLAG_SPECIAL);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
-               aq->queue_count++;
+               aq->queue_count = max_t(int, 1, aq->queue_count + 1);
                if (aq->queue_count == 1)
                        mod_timer(&aq->timeout, jiffies + aq->request_timeout);
                list_move_tail(&ap_msg->list, &aq->pendingq);
index b2c7e10..122c85c 100644 (file)
@@ -366,16 +366,6 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev)
        struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
 
        mutex_lock(&matrix_dev->lock);
-
-       /*
-        * If the KVM pointer is in flux or the guest is running, disallow
-        * un-assignment of control domain.
-        */
-       if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
-               mutex_unlock(&matrix_dev->lock);
-               return -EBUSY;
-       }
-
        vfio_ap_mdev_reset_queues(mdev);
        list_del(&matrix_mdev->node);
        kfree(matrix_mdev);
index 6540d48..715c349 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/dmapool.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/of.h>
index 41ac947..10b6c6d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
index cb3c37d..a2c3d9a 100644 (file)
@@ -1387,6 +1387,22 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
        }
 }
 
+static bool sd_need_revalidate(struct block_device *bdev,
+               struct scsi_disk *sdkp)
+{
+       if (sdkp->device->removable || sdkp->write_prot) {
+               if (bdev_check_media_change(bdev))
+                       return true;
+       }
+
+       /*
+        * Force a full rescan after ioctl(BLKRRPART).  While the disk state has
+        * nothing to do with partitions, BLKRRPART is used to force a full
+        * revalidate after things like a format for historical reasons.
+        */
+       return test_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state);
+}
+
 /**
  *     sd_open - open a scsi disk device
  *     @bdev: Block device of the scsi disk to open
@@ -1423,10 +1439,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
        if (!scsi_block_when_processing_errors(sdev))
                goto error_out;
 
-       if (sdev->removable || sdkp->write_prot) {
-               if (bdev_check_media_change(bdev))
-                       sd_revalidate_disk(bdev->bd_disk);
-       }
+       if (sd_need_revalidate(bdev, sdkp))
+               sd_revalidate_disk(bdev->bd_disk);
 
        /*
         * If the drive is empty, just let the open fail.
index e4633b8..7815ed6 100644 (file)
@@ -220,6 +220,8 @@ static unsigned int sr_get_events(struct scsi_device *sdev)
                return DISK_EVENT_EJECT_REQUEST;
        else if (med->media_event_code == 2)
                return DISK_EVENT_MEDIA_CHANGE;
+       else if (med->media_event_code == 3)
+               return DISK_EVENT_EJECT_REQUEST;
        return 0;
 }
 
index e6718a7..4037539 100644 (file)
@@ -406,6 +406,14 @@ static void storvsc_on_channel_callback(void *context);
 #define STORVSC_IDE_MAX_TARGETS                                1
 #define STORVSC_IDE_MAX_CHANNELS                       1
 
+/*
+ * Upper bound on the size of a storvsc packet. vmscsi_size_delta is not
+ * included in the calculation because it is set after STORVSC_MAX_PKT_SIZE
+ * is used in storvsc_connect_to_vsp
+ */
+#define STORVSC_MAX_PKT_SIZE (sizeof(struct vmpacket_descriptor) +\
+                             sizeof(struct vstor_packet))
+
 struct storvsc_cmd_request {
        struct scsi_cmnd *cmd;
 
@@ -688,6 +696,23 @@ old_is_alloced:
        spin_unlock_irqrestore(&stor_device->lock, flags);
 }
 
+static u64 storvsc_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
+{
+       struct storvsc_cmd_request *request =
+               (struct storvsc_cmd_request *)(unsigned long)rqst_addr;
+
+       if (rqst_addr == VMBUS_RQST_INIT)
+               return VMBUS_RQST_INIT;
+       if (rqst_addr == VMBUS_RQST_RESET)
+               return VMBUS_RQST_RESET;
+
+       /*
+        * Cannot return an ID of 0, which is reserved for an unsolicited
+        * message from Hyper-V.
+        */
+       return (u64)blk_mq_unique_tag(request->cmd->request) + 1;
+}
+
 static void handle_sc_creation(struct vmbus_channel *new_sc)
 {
        struct hv_device *device = new_sc->primary_channel->device_obj;
@@ -701,12 +726,9 @@ static void handle_sc_creation(struct vmbus_channel *new_sc)
                return;
 
        memset(&props, 0, sizeof(struct vmstorage_channel_properties));
+       new_sc->max_pkt_size = STORVSC_MAX_PKT_SIZE;
 
-       /*
-        * The size of vmbus_requestor is an upper bound on the number of requests
-        * that can be in-progress at any one time across all channels.
-        */
-       new_sc->rqstor_size = scsi_driver.can_queue;
+       new_sc->next_request_id_callback = storvsc_next_request_id;
 
        ret = vmbus_open(new_sc,
                         storvsc_ringbuffer_size,
@@ -773,7 +795,7 @@ static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
        ret = vmbus_sendpacket(device->channel, vstor_packet,
                               (sizeof(struct vstor_packet) -
                               stor_device->vmscsi_size_delta),
-                              (unsigned long)request,
+                              VMBUS_RQST_INIT,
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 
@@ -842,7 +864,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device,
        ret = vmbus_sendpacket(device->channel, vstor_packet,
                               (sizeof(struct vstor_packet) -
                               stor_device->vmscsi_size_delta),
-                              (unsigned long)request,
+                              VMBUS_RQST_INIT,
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
        if (ret != 0)
@@ -1244,6 +1266,7 @@ static void storvsc_on_channel_callback(void *context)
        const struct vmpacket_descriptor *desc;
        struct hv_device *device;
        struct storvsc_device *stor_device;
+       struct Scsi_Host *shost;
 
        if (channel->primary_channel != NULL)
                device = channel->primary_channel->device_obj;
@@ -1254,20 +1277,12 @@ static void storvsc_on_channel_callback(void *context)
        if (!stor_device)
                return;
 
-       foreach_vmbus_pkt(desc, channel) {
-               void *packet = hv_pkt_data(desc);
-               struct storvsc_cmd_request *request;
-               u64 cmd_rqst;
-
-               cmd_rqst = vmbus_request_addr(&channel->requestor,
-                                             desc->trans_id);
-               if (cmd_rqst == VMBUS_RQST_ERROR) {
-                       dev_err(&device->device,
-                               "Incorrect transaction id\n");
-                       continue;
-               }
+       shost = stor_device->host;
 
-               request = (struct storvsc_cmd_request *)(unsigned long)cmd_rqst;
+       foreach_vmbus_pkt(desc, channel) {
+               struct vstor_packet *packet = hv_pkt_data(desc);
+               struct storvsc_cmd_request *request = NULL;
+               u64 rqst_id = desc->trans_id;
 
                if (hv_pkt_datalen(desc) < sizeof(struct vstor_packet) -
                                stor_device->vmscsi_size_delta) {
@@ -1275,14 +1290,44 @@ static void storvsc_on_channel_callback(void *context)
                        continue;
                }
 
-               if (request == &stor_device->init_request ||
-                   request == &stor_device->reset_request) {
-                       memcpy(&request->vstor_packet, packet,
-                              (sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
-                       complete(&request->wait_event);
+               if (rqst_id == VMBUS_RQST_INIT) {
+                       request = &stor_device->init_request;
+               } else if (rqst_id == VMBUS_RQST_RESET) {
+                       request = &stor_device->reset_request;
                } else {
+                       /* Hyper-V can send an unsolicited message with ID of 0 */
+                       if (rqst_id == 0) {
+                               /*
+                                * storvsc_on_receive() looks at the vstor_packet in the message
+                                * from the ring buffer.  If the operation in the vstor_packet is
+                                * COMPLETE_IO, then we call storvsc_on_io_completion(), and
+                                * dereference the guest memory address.  Make sure we don't call
+                                * storvsc_on_io_completion() with a guest memory address that is
+                                * zero if Hyper-V were to construct and send such a bogus packet.
+                                */
+                               if (packet->operation == VSTOR_OPERATION_COMPLETE_IO) {
+                                       dev_err(&device->device, "Invalid packet with ID of 0\n");
+                                       continue;
+                               }
+                       } else {
+                               struct scsi_cmnd *scmnd;
+
+                               /* Transaction 'rqst_id' corresponds to tag 'rqst_id - 1' */
+                               scmnd = scsi_host_find_tag(shost, rqst_id - 1);
+                               if (scmnd == NULL) {
+                                       dev_err(&device->device, "Incorrect transaction ID\n");
+                                       continue;
+                               }
+                               request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd);
+                       }
+
                        storvsc_on_receive(stor_device, packet, request);
+                       continue;
                }
+
+               memcpy(&request->vstor_packet, packet,
+                      (sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
+               complete(&request->wait_event);
        }
 }
 
@@ -1294,11 +1339,8 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
 
        memset(&props, 0, sizeof(struct vmstorage_channel_properties));
 
-       /*
-        * The size of vmbus_requestor is an upper bound on the number of requests
-        * that can be in-progress at any one time across all channels.
-        */
-       device->channel->rqstor_size = scsi_driver.can_queue;
+       device->channel->max_pkt_size = STORVSC_MAX_PKT_SIZE;
+       device->channel->next_request_id_callback = storvsc_next_request_id;
 
        ret = vmbus_open(device->channel,
                         ring_size,
@@ -1624,7 +1666,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
        ret = vmbus_sendpacket(device->channel, vstor_packet,
                               (sizeof(struct vstor_packet) -
                                stor_device->vmscsi_size_delta),
-                              (unsigned long)&stor_device->reset_request,
+                              VMBUS_RQST_RESET,
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
        if (ret != 0)
index ec90b44..3c15825 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/soc/ixp4xx/npe.h>
 
@@ -679,6 +680,7 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
 {
        int i, found = 0;
        struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
        struct resource *res;
 
        for (i = 0; i < NPE_COUNT; i++) {
@@ -711,6 +713,11 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
 
        if (!found)
                return -ENODEV;
+
+       /* Spawn crypto subdevice if using device tree */
+       if (IS_ENABLED(CONFIG_OF) && np)
+               devm_of_platform_populate(dev);
+
        return 0;
 }
 
index f4481fe..e71a4c5 100644 (file)
@@ -806,6 +806,7 @@ config SPI_STM32_QSPI
        tristate "STMicroelectronics STM32 QUAD SPI controller"
        depends on ARCH_STM32 || COMPILE_TEST
        depends on OF
+       depends on SPI_MEM
        help
          This enables support for the Quad SPI controller in master mode.
          This driver does not support generic SPI. The implementation only
index 3e32e4f..39a3e1a 100644 (file)
@@ -148,10 +148,8 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
 
        base = devm_ioremap_resource(dev, &dfl_dev->mmio_res);
 
-       if (IS_ERR(base)) {
-               dev_err(dev, "%s get mem resource fail!\n", __func__);
+       if (IS_ERR(base))
                return PTR_ERR(base);
-       }
 
        config_spi_master(base, master);
        dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
index 98ace74..d1e287d 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/err.h>
-#include <linux/platform_data/spi-ath79.h>
 
 #define DRV_NAME       "ath79-spi"
 
@@ -138,7 +137,6 @@ static int ath79_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct ath79_spi *sp;
-       struct ath79_spi_platform_data *pdata;
        unsigned long rate;
        int ret;
 
@@ -152,15 +150,10 @@ static int ath79_spi_probe(struct platform_device *pdev)
        master->dev.of_node = pdev->dev.of_node;
        platform_set_drvdata(pdev, sp);
 
-       pdata = dev_get_platdata(&pdev->dev);
-
        master->use_gpio_descriptors = true;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->flags = SPI_MASTER_GPIO_SS;
-       if (pdata) {
-               master->bus_num = pdata->bus_num;
-               master->num_chipselect = pdata->num_chipselect;
-       }
+       master->num_chipselect = 3;
 
        sp->bitbang.master = master;
        sp->bitbang.chipselect = ath79_spi_chipselect;
index 7cd5fe0..2ef7488 100644 (file)
@@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
 static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
                                struct spi_transfer *xfer,
                                u32 *plen)
-       __must_hold(&as->lock)
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
        struct dma_chan         *rxchan = master->dma_rx;
@@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
        if (!rxchan || !txchan)
                return -ENODEV;
 
-       /* release lock for DMA operations */
-       atmel_spi_unlock(as);
 
        *plen = xfer->len;
 
@@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
        rxchan->device->device_issue_pending(rxchan);
        txchan->device->device_issue_pending(txchan);
 
-       /* take back lock */
-       atmel_spi_lock(as);
        return 0;
 
 err_dma:
        spi_writel(as, IDR, SPI_BIT(OVRES));
        atmel_spi_stop_dma(master);
 err_exit:
-       atmel_spi_lock(as);
        return -ENOMEM;
 }
 
@@ -863,7 +857,6 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
  * lock is held, spi irq is blocked
  */
 static void atmel_spi_pdc_next_xfer(struct spi_master *master,
-                                       struct spi_message *msg,
                                        struct spi_transfer *xfer)
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
@@ -879,12 +872,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
        spi_writel(as, RPR, rx_dma);
        spi_writel(as, TPR, tx_dma);
 
-       if (msg->spi->bits_per_word > 8)
+       if (xfer->bits_per_word > 8)
                len >>= 1;
        spi_writel(as, RCR, len);
        spi_writel(as, TCR, len);
 
-       dev_dbg(&msg->spi->dev,
+       dev_dbg(&master->dev,
                "  start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
                xfer, xfer->len, xfer->tx_buf,
                (unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -898,12 +891,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
                spi_writel(as, RNPR, rx_dma);
                spi_writel(as, TNPR, tx_dma);
 
-               if (msg->spi->bits_per_word > 8)
+               if (xfer->bits_per_word > 8)
                        len >>= 1;
                spi_writel(as, RNCR, len);
                spi_writel(as, TNCR, len);
 
-               dev_dbg(&msg->spi->dev,
+               dev_dbg(&master->dev,
                        "  next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
                        xfer, xfer->len, xfer->tx_buf,
                        (unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -1054,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
 
 /* Interrupt
  *
- * No need for locking in this Interrupt handler: done_status is the
- * only information modified.
  */
 static irqreturn_t
 atmel_spi_pio_interrupt(int irq, void *dev_id)
@@ -1273,12 +1264,28 @@ static int atmel_spi_setup(struct spi_device *spi)
        return 0;
 }
 
+static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct atmel_spi *as = spi_master_get_devdata(spi->master);
+       /* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
+        * since we already have routines for activate/deactivate translate
+        * high/low to active/inactive
+        */
+       enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
+
+       if (enable) {
+               cs_activate(as, spi);
+       } else {
+               cs_deactivate(as, spi);
+       }
+
+}
+
 static int atmel_spi_one_transfer(struct spi_master *master,
-                                       struct spi_message *msg,
+                                       struct spi_device *spi,
                                        struct spi_transfer *xfer)
 {
        struct atmel_spi        *as;
-       struct spi_device       *spi = msg->spi;
        u8                      bits;
        u32                     len;
        struct atmel_spi_device *asd;
@@ -1288,11 +1295,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
 
        as = spi_master_get_devdata(master);
 
-       if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
-               dev_dbg(&spi->dev, "missing rx or tx buf\n");
-               return -EINVAL;
-       }
-
        asd = spi->controller_state;
        bits = (asd->csr >> 4) & 0xf;
        if (bits != xfer->bits_per_word - 8) {
@@ -1305,13 +1307,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
         * DMA map early, for performance (empties dcache ASAP) and
         * better fault reporting.
         */
-       if ((!msg->is_dma_mapped)
+       if ((!master->cur_msg_mapped)
                && as->use_pdc) {
                if (atmel_spi_dma_map_xfer(as, xfer) < 0)
                        return -ENOMEM;
        }
 
-       atmel_spi_set_xfer_speed(as, msg->spi, xfer);
+       atmel_spi_set_xfer_speed(as, spi, xfer);
 
        as->done_status = 0;
        as->current_transfer = xfer;
@@ -1320,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                reinit_completion(&as->xfer_completion);
 
                if (as->use_pdc) {
-                       atmel_spi_pdc_next_xfer(master, msg, xfer);
+                       atmel_spi_lock(as);
+                       atmel_spi_pdc_next_xfer(master, xfer);
+                       atmel_spi_unlock(as);
                } else if (atmel_spi_use_dma(as, xfer)) {
                        len = as->current_remaining_bytes;
                        ret = atmel_spi_next_xfer_dma_submit(master,
@@ -1328,21 +1332,21 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                        if (ret) {
                                dev_err(&spi->dev,
                                        "unable to use DMA, fallback to PIO\n");
-                               atmel_spi_next_xfer_pio(master, xfer);
+                               as->done_status = ret;
+                               break;
                        } else {
                                as->current_remaining_bytes -= len;
                                if (as->current_remaining_bytes < 0)
                                        as->current_remaining_bytes = 0;
                        }
                } else {
+                       atmel_spi_lock(as);
                        atmel_spi_next_xfer_pio(master, xfer);
+                       atmel_spi_unlock(as);
                }
 
-               /* interrupts are disabled, so free the lock for schedule */
-               atmel_spi_unlock(as);
                dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
                                                          SPI_DMA_TIMEOUT);
-               atmel_spi_lock(as);
                if (WARN_ON(dma_timeout == 0)) {
                        dev_err(&spi->dev, "spi transfer timeout\n");
                        as->done_status = -EIO;
@@ -1381,90 +1385,16 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                } else if (atmel_spi_use_dma(as, xfer)) {
                        atmel_spi_stop_dma(master);
                }
-
-               if (!msg->is_dma_mapped
-                       && as->use_pdc)
-                       atmel_spi_dma_unmap_xfer(master, xfer);
-
-               return 0;
-
-       } else {
-               /* only update length if no error */
-               msg->actual_length += xfer->len;
        }
 
-       if (!msg->is_dma_mapped
+       if (!master->cur_msg_mapped
                && as->use_pdc)
                atmel_spi_dma_unmap_xfer(master, xfer);
 
-       spi_transfer_delay_exec(xfer);
-
-       if (xfer->cs_change) {
-               if (list_is_last(&xfer->transfer_list,
-                                &msg->transfers)) {
-                       as->keep_cs = true;
-               } else {
-                       cs_deactivate(as, msg->spi);
-                       udelay(10);
-                       cs_activate(as, msg->spi);
-               }
-       }
-
-       return 0;
-}
-
-static int atmel_spi_transfer_one_message(struct spi_master *master,
-                                               struct spi_message *msg)
-{
-       struct atmel_spi *as;
-       struct spi_transfer *xfer;
-       struct spi_device *spi = msg->spi;
-       int ret = 0;
-
-       as = spi_master_get_devdata(master);
-
-       dev_dbg(&spi->dev, "new message %p submitted for %s\n",
-                                       msg, dev_name(&spi->dev));
-
-       atmel_spi_lock(as);
-       cs_activate(as, spi);
-
-       as->keep_cs = false;
-
-       msg->status = 0;
-       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)
                atmel_spi_disable_pdc_transfer(as);
 
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               dev_dbg(&spi->dev,
-                       "  xfer %p: len %u tx %p/%pad rx %p/%pad\n",
-                       xfer, xfer->len,
-                       xfer->tx_buf, &xfer->tx_dma,
-                       xfer->rx_buf, &xfer->rx_dma);
-       }
-
-msg_done:
-       if (!as->keep_cs)
-               cs_deactivate(as, msg->spi);
-
-       atmel_spi_unlock(as);
-
-       msg->status = as->done_status;
-       spi_finalize_current_message(spi->master);
-
-       return ret;
+       return as->done_status;
 }
 
 static void atmel_spi_cleanup(struct spi_device *spi)
@@ -1554,7 +1484,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
        master->num_chipselect = 4;
        master->setup = atmel_spi_setup;
        master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
-       master->transfer_one_message = atmel_spi_transfer_one_message;
+       master->transfer_one = atmel_spi_one_transfer;
+       master->set_cs = atmel_spi_set_cs;
        master->cleanup = atmel_spi_cleanup;
        master->auto_runtime_pm = true;
        master->max_dma_len = SPI_MAX_DMA_XFER;
index fe40626..5f8771f 100644 (file)
@@ -68,7 +68,6 @@
 #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             24  /* raise as necessary */
 #define BCM2835_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
                                | SPI_NO_CS | SPI_3WIRE)
 
@@ -96,8 +95,6 @@ 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
- * @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
@@ -107,7 +104,7 @@ 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
+ * @slv: 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
@@ -115,11 +112,6 @@ MODULE_PARM_DESC(polling_limit_us,
  * @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;
@@ -134,7 +126,6 @@ struct bcm2835_spi {
        int tx_prologue;
        int rx_prologue;
        unsigned int tx_spillover;
-       u32 prepare_cs[BCM2835_SPI_NUM_CS];
 
        struct dentry *debugfs_dir;
        u64 count_transfer_polling;
@@ -142,14 +133,28 @@ struct bcm2835_spi {
        u64 count_transfer_irq_after_polling;
        u64 count_transfer_dma;
 
-       u8 chip_select;
+       struct bcm2835_spidev *slv;
        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];
+};
+
+/**
+ * struct bcm2835_spidev - BCM2835 SPI slave
+ * @prepare_cs: precalculated CS register value for ->prepare_message()
+ *     (uses slave-specific clock polarity and phase settings)
+ * @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_spidev {
+       u32 prepare_cs;
+       struct dma_async_tx_descriptor *clear_rx_desc;
        dma_addr_t clear_rx_addr;
-       u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned;
+       u32 clear_rx_cs ____cacheline_aligned;
 };
 
 #if defined(CONFIG_DEBUG_FS)
@@ -624,8 +629,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
 
        /* 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]);
+               bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs);
 
        bs->tx_dma_active = false;
        smp_wmb();
@@ -646,18 +650,18 @@ static void bcm2835_spi_dma_tx_done(void *data)
 /**
  * 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
+ * @slv: BCM2835 SPI slave
  * @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,
+                                 struct bcm2835_spidev *slv,
                                  bool is_tx)
 {
        struct dma_chan *chan;
@@ -697,7 +701,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
        } else if (!tfr->rx_buf) {
                desc->callback = bcm2835_spi_dma_tx_done;
                desc->callback_param = ctlr;
-               bs->chip_select = spi->chip_select;
+               bs->slv = slv;
        }
 
        /* submit it to DMA-engine */
@@ -709,8 +713,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
 /**
  * bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
  * @ctlr: SPI master controller
- * @spi: SPI slave
  * @tfr: SPI transfer
+ * @slv: BCM2835 SPI slave
  * @cs: CS register
  *
  * For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
@@ -754,8 +758,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
  * 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,
+                                       struct bcm2835_spidev *slv,
                                        u32 cs)
 {
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
@@ -773,7 +777,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
 
        /* setup tx-DMA */
        if (bs->tx_buf) {
-               ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true);
+               ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true);
        } else {
                cookie = dmaengine_submit(bs->fill_tx_desc);
                ret = dma_submit_error(cookie);
@@ -799,9 +803,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
         * this saves 10us or more.
         */
        if (bs->rx_buf) {
-               ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false);
+               ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false);
        } else {
-               cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]);
+               cookie = dmaengine_submit(slv->clear_rx_desc);
                ret = dma_submit_error(cookie);
        }
        if (ret) {
@@ -850,8 +854,6 @@ static bool bcm2835_spi_can_dma(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);
 
@@ -870,17 +872,6 @@ static void bcm2835_dma_release(struct spi_controller *ctlr,
 
        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;
        }
@@ -892,7 +883,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
        struct dma_slave_config slave_config;
        const __be32 *addr;
        dma_addr_t dma_reg_base;
-       int ret, i;
+       int ret;
 
        /* base address in dma-space */
        addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
@@ -972,35 +963,6 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
        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;
-               ret = -ENOMEM;
-               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");
-                       ret = -ENOMEM;
-                       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;
 
@@ -1082,9 +1044,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
                                    struct spi_transfer *tfr)
 {
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       struct bcm2835_spidev *slv = spi_get_ctldata(spi);
        unsigned long spi_hz, clk_hz, cdiv;
        unsigned long hz_per_byte, byte_limit;
-       u32 cs = bs->prepare_cs[spi->chip_select];
+       u32 cs = slv->prepare_cs;
 
        /* set clock */
        spi_hz = tfr->speed_hz;
@@ -1133,7 +1096,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
         * this 1 idle clock cycle pattern but runs the spi clock without gaps
         */
        if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
-               return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs);
+               return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs);
 
        /* run in interrupt-mode */
        return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
@@ -1144,6 +1107,7 @@ 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);
+       struct bcm2835_spidev *slv = spi_get_ctldata(spi);
        int ret;
 
        if (ctlr->can_dma) {
@@ -1162,7 +1126,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
         * 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]);
+       bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs);
 
        return 0;
 }
@@ -1188,17 +1152,81 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
        return !strcmp(chip->label, data);
 }
 
+static void bcm2835_spi_cleanup(struct spi_device *spi)
+{
+       struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+       struct spi_controller *ctlr = spi->controller;
+
+       if (slv->clear_rx_desc)
+               dmaengine_desc_free(slv->clear_rx_desc);
+
+       if (slv->clear_rx_addr)
+               dma_unmap_single(ctlr->dma_rx->device->dev,
+                                slv->clear_rx_addr,
+                                sizeof(u32),
+                                DMA_TO_DEVICE);
+
+       kfree(slv);
+}
+
+static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
+                                struct spi_device *spi,
+                                struct bcm2835_spi *bs,
+                                struct bcm2835_spidev *slv)
+{
+       int ret;
+
+       if (!ctlr->dma_rx)
+               return 0;
+
+       slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
+                                           &slv->clear_rx_cs,
+                                           sizeof(u32),
+                                           DMA_TO_DEVICE);
+       if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) {
+               dev_err(&spi->dev, "cannot map clear_rx_cs\n");
+               slv->clear_rx_addr = 0;
+               return -ENOMEM;
+       }
+
+       slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
+                                                      slv->clear_rx_addr,
+                                                      sizeof(u32), 0,
+                                                      DMA_MEM_TO_DEV, 0);
+       if (!slv->clear_rx_desc) {
+               dev_err(&spi->dev, "cannot prepare clear_rx_desc\n");
+               return -ENOMEM;
+       }
+
+       ret = dmaengine_desc_set_reuse(slv->clear_rx_desc);
+       if (ret) {
+               dev_err(&spi->dev, "cannot reuse clear_rx_desc\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static int bcm2835_spi_setup(struct spi_device *spi)
 {
        struct spi_controller *ctlr = spi->controller;
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       struct bcm2835_spidev *slv = spi_get_ctldata(spi);
        struct gpio_chip *chip;
+       int ret;
        u32 cs;
 
-       if (spi->chip_select >= BCM2835_SPI_NUM_CS) {
-               dev_err(&spi->dev, "only %d chip-selects supported\n",
-                       BCM2835_SPI_NUM_CS - 1);
-               return -EINVAL;
+       if (!slv) {
+               slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()),
+                             GFP_KERNEL);
+               if (!slv)
+                       return -ENOMEM;
+
+               spi_set_ctldata(spi, slv);
+
+               ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv);
+               if (ret)
+                       goto err_cleanup;
        }
 
        /*
@@ -1212,20 +1240,19 @@ static int bcm2835_spi_setup(struct spi_device *spi)
                cs |= BCM2835_SPI_CS_CPOL;
        if (spi->mode & SPI_CPHA)
                cs |= BCM2835_SPI_CS_CPHA;
-       bs->prepare_cs[spi->chip_select] = cs;
+       slv->prepare_cs = 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;
+               slv->clear_rx_cs = 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),
+                                          slv->clear_rx_addr,
+                                          sizeof(u32),
                                           DMA_TO_DEVICE);
        }
 
@@ -1247,7 +1274,8 @@ static int bcm2835_spi_setup(struct spi_device *spi)
                 */
                dev_err(&spi->dev,
                        "setup: only two native chip-selects are supported\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_cleanup;
        }
 
        /*
@@ -1268,14 +1296,20 @@ static int bcm2835_spi_setup(struct spi_device *spi)
                                                  DRV_NAME,
                                                  GPIO_LOOKUP_FLAGS_DEFAULT,
                                                  GPIOD_OUT_LOW);
-       if (IS_ERR(spi->cs_gpiod))
-               return PTR_ERR(spi->cs_gpiod);
+       if (IS_ERR(spi->cs_gpiod)) {
+               ret = PTR_ERR(spi->cs_gpiod);
+               goto err_cleanup;
+       }
 
        /* and set up the "mode" and level */
        dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
                 spi->chip_select);
 
        return 0;
+
+err_cleanup:
+       bcm2835_spi_cleanup(spi);
+       return ret;
 }
 
 static int bcm2835_spi_probe(struct platform_device *pdev)
@@ -1284,8 +1318,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        struct bcm2835_spi *bs;
        int err;
 
-       ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
-                                                 dma_get_cache_alignment()));
+       ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
        if (!ctlr)
                return -ENOMEM;
 
@@ -1296,6 +1329,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
        ctlr->num_chipselect = 3;
        ctlr->setup = bcm2835_spi_setup;
+       ctlr->cleanup = bcm2835_spi_cleanup;
        ctlr->transfer_one = bcm2835_spi_transfer_one;
        ctlr->handle_err = bcm2835_spi_handle_err;
        ctlr->prepare_message = bcm2835_spi_prepare_message;
index 75589ac..37eab10 100644 (file)
@@ -384,7 +384,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
        bs->pending = 0;
 
        /* Calculate the estimated time in us the transfer runs.  Note that
-        * there are are 2 idle clocks cycles after each chunk getting
+        * there are 2 idle clocks cycles after each chunk getting
         * transferred - in our case the chunk size is 3 bytes, so we
         * approximate this by 9 cycles/byte.  This is used to find the number
         * of Hz per byte per polling limit.  E.g., we can transfer 1 byte in
index 17c0603..3379720 100644 (file)
@@ -56,7 +56,7 @@ struct dw_spi_mscc {
 /*
  * The Designware SPI controller (referred to as master in the documentation)
  * automatically deasserts chip select when the tx fifo is empty. The chip
- * selects then needs to be either driven as GPIOs or, for the first 4 using the
+ * selects then needs to be either driven as GPIOs or, for the first 4 using
  * the SPI boot controller registers. the final chip select is an OR gate
  * between the Designware SPI controller and the SPI boot controller.
  */
index 3d0d8dd..b3861fb 100644 (file)
@@ -639,8 +639,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
                complete(&mas->abort_done);
 
        /*
-        * It's safe or a good idea to Ack all of our our interrupts at the
-        * end of the function. Specifically:
+        * It's safe or a good idea to Ack all of our interrupts at the end
+        * of the function. Specifically:
         * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and
         *   clearing Acks. Clearing at the end relies on nobody else having
         *   started a new transfer yet or else we could be clearing _their_
index 3f986ba..58b823a 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
@@ -126,6 +127,7 @@ struct hisi_spi {
        void __iomem            *regs;
        int                     irq;
        u32                     fifo_len; /* depth of the FIFO buffer */
+       u16                     bus_num;
 
        /* Current message transfer state info */
        const void              *tx;
@@ -133,8 +135,49 @@ struct hisi_spi {
        void                    *rx;
        unsigned int            rx_len;
        u8                      n_bytes; /* current is a 1/2/4 bytes op */
+
+       struct dentry *debugfs;
+       struct debugfs_regset32 regset;
+};
+
+#define HISI_SPI_DBGFS_REG(_name, _off)        \
+{                                      \
+       .name = _name,                  \
+       .offset = _off,                 \
+}
+
+static const struct debugfs_reg32 hisi_spi_regs[] = {
+       HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR),
+       HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR),
+       HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR),
+       HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC),
+       HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR),
+       HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN),
+       HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT),
+       HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR),
+       HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR),
+       HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR),
+       HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR),
+       HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION),
 };
 
+static int hisi_spi_debugfs_init(struct hisi_spi *hs)
+{
+       char name[32];
+
+       snprintf(name, 32, "hisi_spi%d", hs->bus_num);
+       hs->debugfs = debugfs_create_dir(name, NULL);
+       if (!hs->debugfs)
+               return -ENOMEM;
+
+       hs->regset.regs = hisi_spi_regs;
+       hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs);
+       hs->regset.base = hs->regs;
+       debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset);
+
+       return 0;
+}
+
 static u32 hisi_spi_busy(struct hisi_spi *hs)
 {
        return readl(hs->regs + HISI_SPI_SR) & SR_BUSY;
@@ -424,6 +467,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
        hs = spi_controller_get_devdata(master);
        hs->dev = dev;
        hs->irq = irq;
+       hs->bus_num = pdev->id;
 
        hs->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(hs->regs))
@@ -446,7 +490,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
        master->use_gpio_descriptors = true;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
-       master->bus_num = pdev->id;
+       master->bus_num = hs->bus_num;
        master->setup = hisi_spi_setup;
        master->cleanup = hisi_spi_cleanup;
        master->transfer_one = hisi_spi_transfer_one;
@@ -462,6 +506,9 @@ static int hisi_spi_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (hisi_spi_debugfs_init(hs))
+               dev_info(dev, "failed to create debugfs dir\n");
+
        ret = spi_register_controller(master);
        if (ret) {
                dev_err(dev, "failed to register spi master, ret=%d\n", ret);
@@ -478,7 +525,9 @@ static int hisi_spi_probe(struct platform_device *pdev)
 static int hisi_spi_remove(struct platform_device *pdev)
 {
        struct spi_controller *master = platform_get_drvdata(pdev);
+       struct hisi_spi *hs = spi_controller_get_devdata(master);
 
+       debugfs_remove_recursive(hs->debugfs);
        spi_unregister_controller(master);
 
        return 0;
index f914b8d..ead0507 100644 (file)
@@ -202,7 +202,7 @@ static void spi_lm70llp_attach(struct parport *p)
         * the lm70 driver could verify it, reading the manf ID.
         */
 
-       master = spi_alloc_master(p->physport->dev, sizeof *pp);
+       master = spi_alloc_master(p->physport->dev, sizeof(*pp));
        if (!master) {
                status = -ENOMEM;
                goto out_fail;
index f1cf223..4d4f77a 100644 (file)
@@ -875,7 +875,7 @@ static int spi_test_run_iter(struct spi_device *spi,
                test.transfers[i].len = len;
                if (test.transfers[i].tx_buf)
                        test.transfers[i].tx_buf += tx_off;
-               if (test.transfers[i].tx_buf)
+               if (test.transfers[i].rx_buf)
                        test.transfers[i].rx_buf += rx_off;
        }
 
index 1513553..37f4443 100644 (file)
@@ -6,6 +6,7 @@
  * Author: Boris Brezillon <boris.brezillon@bootlin.com>
  */
 #include <linux/dmaengine.h>
+#include <linux/iopoll.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi-mem.h>
@@ -743,6 +744,91 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
        return container_of(drv, struct spi_mem_driver, spidrv.driver);
 }
 
+static int spi_mem_read_status(struct spi_mem *mem,
+                              const struct spi_mem_op *op,
+                              u16 *status)
+{
+       const u8 *bytes = (u8 *)op->data.buf.in;
+       int ret;
+
+       ret = spi_mem_exec_op(mem, op);
+       if (ret)
+               return ret;
+
+       if (op->data.nbytes > 1)
+               *status = ((u16)bytes[0] << 8) | bytes[1];
+       else
+               *status = bytes[0];
+
+       return 0;
+}
+
+/**
+ * spi_mem_poll_status() - Poll memory device status
+ * @mem: SPI memory device
+ * @op: the memory operation to execute
+ * @mask: status bitmask to ckeck
+ * @match: (status & mask) expected value
+ * @initial_delay_us: delay in us before starting to poll
+ * @polling_delay_us: time to sleep between reads in us
+ * @timeout_ms: timeout in milliseconds
+ *
+ * This function polls a status register and returns when
+ * (status & mask) == match or when the timeout has expired.
+ *
+ * Return: 0 in case of success, -ETIMEDOUT in case of error,
+ *         -EOPNOTSUPP if not supported.
+ */
+int spi_mem_poll_status(struct spi_mem *mem,
+                       const struct spi_mem_op *op,
+                       u16 mask, u16 match,
+                       unsigned long initial_delay_us,
+                       unsigned long polling_delay_us,
+                       u16 timeout_ms)
+{
+       struct spi_controller *ctlr = mem->spi->controller;
+       int ret = -EOPNOTSUPP;
+       int read_status_ret;
+       u16 status;
+
+       if (op->data.nbytes < 1 || op->data.nbytes > 2 ||
+           op->data.dir != SPI_MEM_DATA_IN)
+               return -EINVAL;
+
+       if (ctlr->mem_ops && ctlr->mem_ops->poll_status) {
+               ret = spi_mem_access_start(mem);
+               if (ret)
+                       return ret;
+
+               ret = ctlr->mem_ops->poll_status(mem, op, mask, match,
+                                                initial_delay_us, polling_delay_us,
+                                                timeout_ms);
+
+               spi_mem_access_end(mem);
+       }
+
+       if (ret == -EOPNOTSUPP) {
+               if (!spi_mem_supports_op(mem, op))
+                       return ret;
+
+               if (initial_delay_us < 10)
+                       udelay(initial_delay_us);
+               else
+                       usleep_range((initial_delay_us >> 2) + 1,
+                                    initial_delay_us);
+
+               ret = read_poll_timeout(spi_mem_read_status, read_status_ret,
+                                       (read_status_ret || ((status) & mask) == match),
+                                       polling_delay_us, timeout_ms * 1000, false, mem,
+                                       op, &status);
+               if (read_status_ret)
+                       return read_status_ret;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_poll_status);
+
 static int spi_mem_probe(struct spi_device *spi)
 {
        struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
@@ -810,7 +896,7 @@ int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv,
 EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner);
 
 /**
- * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver
+ * spi_mem_driver_unregister() - Unregister a SPI memory driver
  * @memdrv: the SPI memory driver to unregister
  *
  * Unregisters a SPI memory driver.
index ecba6b4..b2c4621 100644 (file)
@@ -725,7 +725,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
        ret = clk_prepare_enable(spicc->pclk);
        if (ret) {
                dev_err(&pdev->dev, "pclk clock enable failed\n");
-               goto out_master;
+               goto out_core_clk;
        }
 
        device_reset_optional(&pdev->dev);
@@ -752,7 +752,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
        ret = meson_spicc_clk_init(spicc);
        if (ret) {
                dev_err(&pdev->dev, "clock registration failed\n");
-               goto out_master;
+               goto out_clk;
        }
 
        ret = devm_spi_register_master(&pdev->dev, master);
@@ -764,9 +764,11 @@ static int meson_spicc_probe(struct platform_device *pdev)
        return 0;
 
 out_clk:
-       clk_disable_unprepare(spicc->core);
        clk_disable_unprepare(spicc->pclk);
 
+out_core_clk:
+       clk_disable_unprepare(spicc->core);
+
 out_master:
        spi_master_put(master);
 
index ea1b079..78a9bca 100644 (file)
@@ -369,7 +369,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
                return -EINVAL;
 
        if (!cs) {
-               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               cs = kzalloc(sizeof(*cs), GFP_KERNEL);
                if (!cs)
                        return -ENOMEM;
 
@@ -491,7 +491,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
        void *tempp;
        struct clk *clk;
 
-       master = spi_alloc_master(dev, sizeof *mps);
+       master = spi_alloc_master(dev, sizeof(*mps));
        if (master == NULL)
                return -ENOMEM;
 
index 17935e7..21ef5d4 100644 (file)
@@ -265,7 +265,7 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
                return -EINVAL;
 
        if (!cs) {
-               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               cs = kzalloc(sizeof(*cs), GFP_KERNEL);
                if (!cs)
                        return -ENOMEM;
                spi->controller_state = cs;
@@ -365,7 +365,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
        struct spi_master *master;
        int ret;
 
-       master = spi_alloc_master(dev, sizeof *mps);
+       master = spi_alloc_master(dev, sizeof(*mps));
        if (master == NULL)
                return -ENOMEM;
 
index 124cba7..5104152 100644 (file)
@@ -415,7 +415,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
        }
 
        dev_dbg(&op->dev, "allocating spi_master struct\n");
-       master = spi_alloc_master(&op->dev, sizeof *ms);
+       master = spi_alloc_master(&op->dev, sizeof(*ms));
        if (!master) {
                rc = -ENOMEM;
                goto err_alloc;
index 56d10c4..1668a34 100644 (file)
@@ -105,7 +105,7 @@ static void npcm_pspi_set_mode(struct spi_device *spi)
        u16 regtemp;
        u16 mode_val;
 
-       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       switch (spi->mode & SPI_MODE_X_MASK) {
        case SPI_MODE_0:
                mode_val = 0;
                break;
index 6e6c240..a66fa97 100644 (file)
@@ -1124,12 +1124,6 @@ static int nxp_fspi_probe(struct platform_device *pdev)
                goto err_put_ctrl;
        }
 
-       /* Clear potential interrupts */
-       reg = fspi_readl(f, f->iobase + FSPI_INTR);
-       if (reg)
-               fspi_writel(f, reg, f->iobase + FSPI_INTR);
-
-
        /* find the resources - controller memory mapped space */
        if (is_acpi_node(f->dev->fwnode))
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1167,6 +1161,11 @@ static int nxp_fspi_probe(struct platform_device *pdev)
                }
        }
 
+       /* Clear potential interrupts */
+       reg = fspi_readl(f, f->iobase + FSPI_INTR);
+       if (reg)
+               fspi_writel(f, reg, f->iobase + FSPI_INTR);
+
        /* find the irq */
        ret = platform_get_irq(pdev, 0);
        if (ret < 0)
index f3843f0..38c14c4 100644 (file)
@@ -86,7 +86,7 @@ static int tiny_spi_setup(struct spi_device *spi)
                hw->speed_hz = spi->max_speed_hz;
                hw->baud = tiny_spi_baud(spi, hw->speed_hz);
        }
-       hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA);
+       hw->mode = spi->mode & SPI_MODE_X_MASK;
        return 0;
 }
 
index 7062f29..20b0471 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 2005, 2006 Nokia Corporation
  * Author:      Samuel Ortiz <samuel.ortiz@nokia.com> and
- *              Juha Yrj�l� <juha.yrjola@nokia.com>
+ *              Juha Yrjola <juha.yrjola@nokia.com>
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -241,7 +241,7 @@ static int omap1_spi100k_setup_transfer(struct spi_device *spi,
        else
                word_len = spi->bits_per_word;
 
-       if (spi->bits_per_word > 32)
+       if (word_len > 32)
                return -EINVAL;
        cs->word_len = word_len;
 
@@ -296,7 +296,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
 
        list_for_each_entry(t, &m->transfers, transfer_list) {
                if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                       status = -EINVAL;
                        break;
                }
                status = omap1_spi100k_setup_transfer(spi, t);
@@ -315,7 +314,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
                        m->actual_length += count;
 
                        if (count != t->len) {
-                               status = -EIO;
                                break;
                        }
                }
index df28c66..087172a 100644 (file)
@@ -330,7 +330,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        if (spi->mode & SPI_CPOL)
                flags |= UWIRE_CLK_INVERTED;
 
-       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       switch (spi->mode & SPI_MODE_X_MASK) {
        case SPI_MODE_0:
        case SPI_MODE_3:
                flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
@@ -460,7 +460,7 @@ static int uwire_probe(struct platform_device *pdev)
        struct uwire_spi        *uwire;
        int                     status;
 
-       master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+       master = spi_alloc_master(&pdev->dev, sizeof(*uwire));
        if (!master)
                return -ENODEV;
 
index ede7f05..60c9cdf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2005, 2006 Nokia Corporation
  * Author:     Samuel Ortiz <samuel.ortiz@nokia.com> and
- *             Juha Yrj�l� <juha.yrjola@nokia.com>
+ *             Juha Yrjola <juha.yrjola@nokia.com>
  */
 
 #include <linux/kernel.h>
@@ -1054,7 +1054,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
        struct omap2_mcspi_cs   *cs = spi->controller_state;
 
        if (!cs) {
-               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               cs = kzalloc(sizeof(*cs), GFP_KERNEL);
                if (!cs)
                        return -ENOMEM;
                cs->base = mcspi->base + spi->chip_select * 0x14;
index 0c9e3f2..feebda6 100644 (file)
 #define SPI_POLLING_TIMEOUT 1000
 
 /*
- * The type of reading going on on this chip
+ * The type of reading going on this chip
  */
 enum ssp_reading {
        READING_NULL,
@@ -298,7 +298,7 @@ enum ssp_reading {
 };
 
 /*
- * The type of writing going on on this chip
+ * The type of writing going on this chip
  */
 enum ssp_writing {
        WRITING_NULL,
index d8ee363..d65f047 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
 
@@ -223,7 +223,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
        }
 
        if (cs == NULL) {
-               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               cs = kzalloc(sizeof(*cs), GFP_KERNEL);
                if (!cs)
                        return -ENOMEM;
                spi->controller_state = cs;
@@ -235,7 +235,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
         */
        cs->mode = SPI_PPC4XX_MODE_SPE;
 
-       switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
+       switch (spi->mode & SPI_MODE_X_MASK) {
        case SPI_MODE_0:
                cs->mode |= SPI_CLK_MODE0;
                break;
@@ -326,7 +326,7 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
 {
        /*
         * On all 4xx PPC's the SPI bus is shared/multiplexed with
-        * the 2nd I2C bus. We need to enable the the SPI bus before
+        * the 2nd I2C bus. We need to enable the SPI bus before
         * using it.
         */
 
@@ -349,7 +349,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
        int ret;
        const unsigned int *clk;
 
-       master = spi_alloc_master(dev, sizeof *hw);
+       master = spi_alloc_master(dev, sizeof(*hw));
        if (master == NULL)
                return -ENOMEM;
        master->dev.of_node = np;
index 37567bc..be563f0 100644 (file)
@@ -2,18 +2,18 @@
 /*
  * PXA2xx SPI DMA engine support.
  *
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/pxa2xx_ssp.h>
 #include <linux/scatterlist.h>
 #include <linux/sizes.h>
-#include <linux/spi/spi.h>
+
 #include <linux/spi/pxa2xx_spi.h>
+#include <linux/spi/spi.h>
 
 #include "spi-pxa2xx.h"
 
@@ -26,7 +26,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
         * It is possible that one CPU is handling ROR interrupt and other
         * just gets DMA completion. Calling pump_transfers() twice for the
         * same transfer leads to problems thus we prevent concurrent calls
-        * by using ->dma_running.
+        * by using dma_running.
         */
        if (atomic_dec_and_test(&drv_data->dma_running)) {
                /*
@@ -34,25 +34,18 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
                 * might not know about the error yet. So we re-check the
                 * ROR bit here before we clear the status register.
                 */
-               if (!error) {
-                       u32 status = pxa2xx_spi_read(drv_data, SSSR)
-                                    & drv_data->mask_sr;
-                       error = status & SSSR_ROR;
-               }
+               if (!error)
+                       error = read_SSSR_bits(drv_data, drv_data->mask_sr) & SSSR_ROR;
 
                /* Clear status & disable interrupts */
-               pxa2xx_spi_write(drv_data, SSCR1,
-                                pxa2xx_spi_read(drv_data, SSCR1)
-                                & ~drv_data->dma_cr1);
+               clear_SSCR1_bits(drv_data, drv_data->dma_cr1);
                write_SSSR_CS(drv_data, drv_data->clear_sr);
                if (!pxa25x_ssp_comp(drv_data))
                        pxa2xx_spi_write(drv_data, SSTO, 0);
 
                if (error) {
                        /* In case we got an error we disable the SSP now */
-                       pxa2xx_spi_write(drv_data, SSCR0,
-                                        pxa2xx_spi_read(drv_data, SSCR0)
-                                        & ~SSCR0_SSE);
+                       pxa_ssp_disable(drv_data->ssp);
                        msg->status = -EIO;
                }
 
@@ -94,14 +87,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
        cfg.direction = dir;
 
        if (dir == DMA_MEM_TO_DEV) {
-               cfg.dst_addr = drv_data->ssdr_physical;
+               cfg.dst_addr = drv_data->ssp->phys_base + SSDR;
                cfg.dst_addr_width = width;
                cfg.dst_maxburst = chip->dma_burst_size;
 
                sgt = &xfer->tx_sg;
                chan = drv_data->controller->dma_tx;
        } else {
-               cfg.src_addr = drv_data->ssdr_physical;
+               cfg.src_addr = drv_data->ssp->phys_base + SSDR;
                cfg.src_addr_width = width;
                cfg.src_maxburst = chip->dma_burst_size;
 
@@ -111,7 +104,7 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
 
        ret = dmaengine_slave_config(chan, &cfg);
        if (ret) {
-               dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n");
+               dev_warn(drv_data->ssp->dev, "DMA slave config failed\n");
                return NULL;
        }
 
@@ -123,9 +116,9 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
 {
        u32 status;
 
-       status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
+       status = read_SSSR_bits(drv_data, drv_data->mask_sr);
        if (status & SSSR_ROR) {
-               dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
+               dev_err(drv_data->ssp->dev, "FIFO overrun\n");
 
                dmaengine_terminate_async(drv_data->controller->dma_rx);
                dmaengine_terminate_async(drv_data->controller->dma_tx);
@@ -145,16 +138,14 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
 
        tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer);
        if (!tx_desc) {
-               dev_err(&drv_data->pdev->dev,
-                       "failed to get DMA TX descriptor\n");
+               dev_err(drv_data->ssp->dev, "failed to get DMA TX descriptor\n");
                err = -EBUSY;
                goto err_tx;
        }
 
        rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer);
        if (!rx_desc) {
-               dev_err(&drv_data->pdev->dev,
-                       "failed to get DMA RX descriptor\n");
+               dev_err(drv_data->ssp->dev, "failed to get DMA RX descriptor\n");
                err = -EBUSY;
                goto err_rx;
        }
@@ -191,8 +182,8 @@ void pxa2xx_spi_dma_stop(struct driver_data *drv_data)
 int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
 {
        struct pxa2xx_spi_controller *pdata = drv_data->controller_info;
-       struct device *dev = &drv_data->pdev->dev;
        struct spi_controller *controller = drv_data->controller;
+       struct device *dev = drv_data->ssp->dev;
        dma_cap_mask_t mask;
 
        dma_cap_zero(mask);
index 1833f58..2e134eb 100644 (file)
@@ -1,13 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * CE4100's SPI device is more or less the same one as found on PXA
+ * PCI glue driver for SPI PXA2xx compatible controllers.
+ * CE4100's SPI device is more or less the same one as found on PXA.
  *
- * Copyright (C) 2016, Intel Corporation
+ * Copyright (C) 2016, 2021 Intel Corporation
  */
 #include <linux/clk-provider.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+
 #include <linux/spi/pxa2xx_spi.h>
 
 #include <linux/dmaengine.h>
@@ -178,7 +180,7 @@ static struct pxa_spi_info spi_info_configs[] = {
                .rx_param = &bsw2_rx_param,
        },
        [PORT_MRFLD] = {
-               .type = PXA27x_SSP,
+               .type = MRFLD_SSP,
                .max_clk_rate = 25000000,
                .setup = mrfld_spi_setup,
        },
@@ -239,6 +241,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
        spi_pdata.dma_burst_size = c->dma_burst_size ? c->dma_burst_size : 1;
 
        ssp = &spi_pdata.ssp;
+       ssp->dev = &dev->dev;
        ssp->phys_base = pci_resource_start(dev, 0);
        ssp->mmio_base = pcim_iomap_table(dev)[0];
        ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
@@ -254,7 +257,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
        snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
        ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0,
                                           c->max_clk_rate);
-        if (IS_ERR(ssp->clk))
+       if (IS_ERR(ssp->clk))
                return PTR_ERR(ssp->clk);
 
        memset(&pi, 0, sizeof(pi));
index 8ee0cc0..974e307 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
  */
 
 #include <linux/acpi.h>
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/gpio/consumer.h>
@@ -25,6 +26,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/spi.h>
 
@@ -38,11 +40,11 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define TIMOUT_DFLT            1000
 
 /*
- * for testing SSCR1 changes that require SSP restart, basically
- * everything except the service and interrupt enables, the pxa270 developer
+ * For testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables, the PXA270 developer
  * manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this
- * list, but the PXA255 dev man says all bits without really meaning the
- * service and interrupt enables
+ * list, but the PXA255 developer manual says all bits without really meaning
+ * the service and interrupt enables.
  */
 #define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
                                | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
@@ -198,6 +200,17 @@ static bool is_mmp2_ssp(const struct driver_data *drv_data)
        return drv_data->ssp_type == MMP2_SSP;
 }
 
+static bool is_mrfld_ssp(const struct driver_data *drv_data)
+{
+       return drv_data->ssp_type == MRFLD_SSP;
+}
+
+static void pxa2xx_spi_update(const struct driver_data *drv_data, u32 reg, u32 mask, u32 value)
+{
+       if ((pxa2xx_spi_read(drv_data, reg) & mask) != value)
+               pxa2xx_spi_write(drv_data, reg, value & mask);
+}
+
 static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
 {
        switch (drv_data->ssp_type) {
@@ -239,7 +252,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
                break;
        }
 
-       return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask;
+       return read_SSSR_bits(drv_data, mask) == mask;
 }
 
 static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
@@ -284,13 +297,11 @@ static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data,
        case QUARK_X1000_SSP:
                return clk_div
                        | QUARK_X1000_SSCR0_Motorola
-                       | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits)
-                       | SSCR0_SSE;
+                       | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits);
        default:
                return clk_div
                        | SSCR0_Motorola
                        | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
-                       | SSCR0_SSE
                        | (bits > 16 ? SSCR0_EDSS : 0);
        }
 }
@@ -325,7 +336,7 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
        u32 value;
 
        config = lpss_get_config(drv_data);
-       drv_data->lpss_base = drv_data->ioaddr + config->offset;
+       drv_data->lpss_base = drv_data->ssp->mmio_base + config->offset;
 
        /* Enable software chip select control */
        value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
@@ -421,7 +432,7 @@ static void cs_assert(struct spi_device *spi)
                spi_controller_get_devdata(spi->controller);
 
        if (drv_data->ssp_type == CE4100_SSP) {
-               pxa2xx_spi_write(drv_data, SSSR, chip->frm);
+               pxa2xx_spi_write(drv_data, SSSR, spi->chip_select);
                return;
        }
 
@@ -430,11 +441,6 @@ static void cs_assert(struct spi_device *spi)
                return;
        }
 
-       if (chip->gpiod_cs) {
-               gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted);
-               return;
-       }
-
        if (is_lpss_ssp(drv_data))
                lpss_ssp_cs_control(spi, true);
 }
@@ -460,11 +466,6 @@ static void cs_deassert(struct spi_device *spi)
                return;
        }
 
-       if (chip->gpiod_cs) {
-               gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted);
-               return;
-       }
-
        if (is_lpss_ssp(drv_data))
                lpss_ssp_cs_control(spi, false);
 }
@@ -482,7 +483,7 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
        unsigned long limit = loops_per_jiffy << 1;
 
        do {
-               while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+               while (read_SSSR_bits(drv_data, SSSR_RNE))
                        pxa2xx_spi_read(drv_data, SSDR);
        } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit);
        write_SSSR_CS(drv_data, SSSR_ROR);
@@ -496,8 +497,7 @@ static void pxa2xx_spi_off(struct driver_data *drv_data)
        if (is_mmp2_ssp(drv_data))
                return;
 
-       pxa2xx_spi_write(drv_data, SSCR0,
-                        pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
+       pxa_ssp_disable(drv_data->ssp);
 }
 
 static int null_writer(struct driver_data *drv_data)
@@ -518,8 +518,7 @@ static int null_reader(struct driver_data *drv_data)
 {
        u8 n_bytes = drv_data->n_bytes;
 
-       while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
-              && (drv_data->rx < drv_data->rx_end)) {
+       while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
                pxa2xx_spi_read(drv_data, SSDR);
                drv_data->rx += n_bytes;
        }
@@ -541,8 +540,7 @@ static int u8_writer(struct driver_data *drv_data)
 
 static int u8_reader(struct driver_data *drv_data)
 {
-       while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
-              && (drv_data->rx < drv_data->rx_end)) {
+       while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
                *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
                ++drv_data->rx;
        }
@@ -564,8 +562,7 @@ static int u16_writer(struct driver_data *drv_data)
 
 static int u16_reader(struct driver_data *drv_data)
 {
-       while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
-              && (drv_data->rx < drv_data->rx_end)) {
+       while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
                *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
                drv_data->rx += 2;
        }
@@ -587,8 +584,7 @@ static int u32_writer(struct driver_data *drv_data)
 
 static int u32_reader(struct driver_data *drv_data)
 {
-       while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
-              && (drv_data->rx < drv_data->rx_end)) {
+       while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
                *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
                drv_data->rx += 4;
        }
@@ -618,47 +614,51 @@ static void reset_sccr1(struct driver_data *drv_data)
        pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
 }
 
-static void int_error_stop(struct driver_data *drv_data, const char *msg)
+static void int_stop_and_reset(struct driver_data *drv_data)
 {
-       /* Stop and reset SSP */
+       /* Clear and disable interrupts */
        write_SSSR_CS(drv_data, drv_data->clear_sr);
        reset_sccr1(drv_data);
-       if (!pxa25x_ssp_comp(drv_data))
-               pxa2xx_spi_write(drv_data, SSTO, 0);
+       if (pxa25x_ssp_comp(drv_data))
+               return;
+
+       pxa2xx_spi_write(drv_data, SSTO, 0);
+}
+
+static void int_error_stop(struct driver_data *drv_data, const char *msg, int err)
+{
+       int_stop_and_reset(drv_data);
        pxa2xx_spi_flush(drv_data);
        pxa2xx_spi_off(drv_data);
 
-       dev_err(&drv_data->pdev->dev, "%s\n", msg);
+       dev_err(drv_data->ssp->dev, "%s\n", msg);
 
-       drv_data->controller->cur_msg->status = -EIO;
+       drv_data->controller->cur_msg->status = err;
        spi_finalize_current_transfer(drv_data->controller);
 }
 
 static void int_transfer_complete(struct driver_data *drv_data)
 {
-       /* Clear and disable interrupts */
-       write_SSSR_CS(drv_data, drv_data->clear_sr);
-       reset_sccr1(drv_data);
-       if (!pxa25x_ssp_comp(drv_data))
-               pxa2xx_spi_write(drv_data, SSTO, 0);
+       int_stop_and_reset(drv_data);
 
        spi_finalize_current_transfer(drv_data->controller);
 }
 
 static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 {
-       u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ?
-                      drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
+       u32 irq_status;
 
-       u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask;
+       irq_status = read_SSSR_bits(drv_data, drv_data->mask_sr);
+       if (!(pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE))
+               irq_status &= ~SSSR_TFS;
 
        if (irq_status & SSSR_ROR) {
-               int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+               int_error_stop(drv_data, "interrupt_transfer: FIFO overrun", -EIO);
                return IRQ_HANDLED;
        }
 
        if (irq_status & SSSR_TUR) {
-               int_error_stop(drv_data, "interrupt_transfer: fifo underrun");
+               int_error_stop(drv_data, "interrupt_transfer: FIFO underrun", -EIO);
                return IRQ_HANDLED;
        }
 
@@ -670,7 +670,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
                }
        }
 
-       /* Drain rx fifo, Fill tx fifo and prevent overruns */
+       /* Drain Rx FIFO, Fill Tx FIFO and prevent overruns */
        do {
                if (drv_data->read(drv_data)) {
                        int_transfer_complete(drv_data);
@@ -691,8 +691,8 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
                sccr1_reg &= ~SSCR1_TIE;
 
                /*
-                * PXA25x_SSP has no timeout, set up rx threshould for the
-                * remaining RX bytes.
+                * PXA25x_SSP has no timeout, set up Rx threshold for
+                * the remaining Rx bytes.
                 */
                if (pxa25x_ssp_comp(drv_data)) {
                        u32 rx_thre;
@@ -725,14 +725,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 static void handle_bad_msg(struct driver_data *drv_data)
 {
        pxa2xx_spi_off(drv_data);
-       pxa2xx_spi_write(drv_data, SSCR1,
-                        pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1);
+       clear_SSCR1_bits(drv_data, drv_data->int_cr1);
        if (!pxa25x_ssp_comp(drv_data))
                pxa2xx_spi_write(drv_data, SSTO, 0);
        write_SSSR_CS(drv_data, drv_data->clear_sr);
 
-       dev_err(&drv_data->pdev->dev,
-               "bad message state in interrupt handler\n");
+       dev_err(drv_data->ssp->dev, "bad message state in interrupt handler\n");
 }
 
 static irqreturn_t ssp_int(int irq, void *dev_id)
@@ -748,7 +746,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
         * the IRQ was not for us (we shouldn't be RPM suspended when the
         * interrupt is enabled).
         */
-       if (pm_runtime_suspended(&drv_data->pdev->dev))
+       if (pm_runtime_suspended(drv_data->ssp->dev))
                return IRQ_NONE;
 
        /*
@@ -916,7 +914,7 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
 
        /*
         * Calculate the divisor for the SCR (Serial Clock Rate), avoiding
-        * that the SSP transmission rate can be greater than the device rate
+        * that the SSP transmission rate can be greater than the device rate.
         */
        if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
                return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff;
@@ -974,7 +972,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
        /* Check if we can DMA this transfer */
        if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
 
-               /* reject already-mapped transfers; PIO won't always work */
+               /* Reject already-mapped transfers; PIO won't always work */
                if (message->is_dma_mapped
                                || transfer->rx_dma || transfer->tx_dma) {
                        dev_err(&spi->dev,
@@ -983,10 +981,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
                        return -EINVAL;
                }
 
-               /* warn ... we force this to PIO mode */
+               /* Warn ... we force this to PIO mode */
                dev_warn_ratelimited(&spi->dev,
-                                    "DMA disabled for transfer length %ld greater than %d\n",
-                                    (long)transfer->len, MAX_DMA_LEN);
+                                    "DMA disabled for transfer length %u greater than %d\n",
+                                    transfer->len, MAX_DMA_LEN);
        }
 
        /* Setup the transfer state based on the type of transfer */
@@ -1028,8 +1026,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
                                        u32_writer : null_writer;
        }
        /*
-        * if bits/word is changed in dma mode, then must check the
-        * thresholds and burst also
+        * If bits per word is changed in DMA mode, then must check
+        * the thresholds and burst also.
         */
        if (chip->enable_dma) {
                if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
@@ -1080,47 +1078,45 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
                        dma_mapped ? "DMA" : "PIO");
 
        if (is_lpss_ssp(drv_data)) {
-               if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
-                   != chip->lpss_rx_threshold)
-                       pxa2xx_spi_write(drv_data, SSIRF,
-                                        chip->lpss_rx_threshold);
-               if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff)
-                   != chip->lpss_tx_threshold)
-                       pxa2xx_spi_write(drv_data, SSITF,
-                                        chip->lpss_tx_threshold);
+               pxa2xx_spi_update(drv_data, SSIRF, GENMASK(7, 0), chip->lpss_rx_threshold);
+               pxa2xx_spi_update(drv_data, SSITF, GENMASK(15, 0), chip->lpss_tx_threshold);
        }
 
-       if (is_quark_x1000_ssp(drv_data) &&
-           (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate))
-               pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate);
-
-       /* see if we need to reload the config registers */
-       if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0)
-           || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
-           != (cr1 & change_mask)) {
-               /* stop the SSP, and update the other bits */
-               if (!is_mmp2_ssp(drv_data))
-                       pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
-               if (!pxa25x_ssp_comp(drv_data))
-                       pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
-               /* first set CR1 without interrupt and service enables */
-               pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask);
-               /* restart the SSP */
-               pxa2xx_spi_write(drv_data, SSCR0, cr0);
+       if (is_mrfld_ssp(drv_data)) {
+               u32 mask = SFIFOTT_RFT | SFIFOTT_TFT;
+               u32 thresh = 0;
 
-       } else {
-               if (!pxa25x_ssp_comp(drv_data))
-                       pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
+               thresh |= SFIFOTT_RxThresh(chip->lpss_rx_threshold);
+               thresh |= SFIFOTT_TxThresh(chip->lpss_tx_threshold);
+
+               pxa2xx_spi_update(drv_data, SFIFOTT, mask, thresh);
        }
 
+       if (is_quark_x1000_ssp(drv_data))
+               pxa2xx_spi_update(drv_data, DDS_RATE, GENMASK(23, 0), chip->dds_rate);
+
+       /* Stop the SSP */
+       if (!is_mmp2_ssp(drv_data))
+               pxa_ssp_disable(drv_data->ssp);
+
+       if (!pxa25x_ssp_comp(drv_data))
+               pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
+
+       /* First set CR1 without interrupt and service enables */
+       pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1);
+
+       /* See if we need to reload the configuration registers */
+       pxa2xx_spi_update(drv_data, SSCR0, GENMASK(31, 0), cr0);
+
+       /* Restart the SSP */
+       pxa_ssp_enable(drv_data->ssp);
+
        if (is_mmp2_ssp(drv_data)) {
-               u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR)
-                                       & SSSR_TFL_MASK) >> 8;
+               u8 tx_level = read_SSSR_bits(drv_data, SSSR_TFL_MASK) >> 8;
 
                if (tx_level) {
-                       /* On MMP2, flipping SSE doesn't to empty TXFIFO. */
-                       dev_warn(&spi->dev, "%d bytes of garbage in TXFIFO!\n",
-                                                               tx_level);
+                       /* On MMP2, flipping SSE doesn't to empty Tx FIFO. */
+                       dev_warn(&spi->dev, "%u bytes of garbage in Tx FIFO!\n", tx_level);
                        if (tx_level > transfer->len)
                                tx_level = transfer->len;
                        drv_data->tx += tx_level;
@@ -1139,7 +1135,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
 
        /*
         * Release the data by enabling service requests and interrupts,
-        * without changing any mode bits
+        * without changing any mode bits.
         */
        pxa2xx_spi_write(drv_data, SSCR1, cr1);
 
@@ -1150,18 +1146,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller)
 {
        struct driver_data *drv_data = spi_controller_get_devdata(controller);
 
-       /* Stop and reset SSP */
-       write_SSSR_CS(drv_data, drv_data->clear_sr);
-       reset_sccr1(drv_data);
-       if (!pxa25x_ssp_comp(drv_data))
-               pxa2xx_spi_write(drv_data, SSTO, 0);
-       pxa2xx_spi_flush(drv_data);
-       pxa2xx_spi_off(drv_data);
-
-       dev_dbg(&drv_data->pdev->dev, "transfer aborted\n");
-
-       drv_data->controller->cur_msg->status = -EINTR;
-       spi_finalize_current_transfer(drv_data->controller);
+       int_error_stop(drv_data, "transfer aborted", -EINTR);
 
        return 0;
 }
@@ -1175,9 +1160,7 @@ static void pxa2xx_spi_handle_err(struct spi_controller *controller,
        pxa2xx_spi_off(drv_data);
        /* Clear and disable interrupts and service requests */
        write_SSSR_CS(drv_data, drv_data->clear_sr);
-       pxa2xx_spi_write(drv_data, SSCR1,
-                        pxa2xx_spi_read(drv_data, SSCR1)
-                        & ~(drv_data->int_cr1 | drv_data->dma_cr1));
+       clear_SSCR1_bits(drv_data, drv_data->int_cr1 | drv_data->dma_cr1);
        if (!pxa25x_ssp_comp(drv_data))
                pxa2xx_spi_write(drv_data, SSTO, 0);
 
@@ -1202,63 +1185,61 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller)
        return 0;
 }
 
+static void cleanup_cs(struct spi_device *spi)
+{
+       if (!gpio_is_valid(spi->cs_gpio))
+               return;
+
+       gpio_free(spi->cs_gpio);
+       spi->cs_gpio = -ENOENT;
+}
+
 static int setup_cs(struct spi_device *spi, struct chip_data *chip,
                    struct pxa2xx_spi_chip *chip_info)
 {
-       struct driver_data *drv_data =
-               spi_controller_get_devdata(spi->controller);
-       struct gpio_desc *gpiod;
-       int err = 0;
+       struct driver_data *drv_data = spi_controller_get_devdata(spi->controller);
 
        if (chip == NULL)
                return 0;
 
-       if (drv_data->cs_gpiods) {
-               gpiod = drv_data->cs_gpiods[spi->chip_select];
-               if (gpiod) {
-                       chip->gpiod_cs = gpiod;
-                       chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
-                       gpiod_set_value(gpiod, chip->gpio_cs_inverted);
-               }
-
+       if (chip_info == NULL)
                return 0;
-       }
 
-       if (chip_info == NULL)
+       if (drv_data->ssp_type == CE4100_SSP)
                return 0;
 
-       /* NOTE: setup() can be called multiple times, possibly with
-        * different chip_info, release previously requested GPIO
+       /*
+        * NOTE: setup() can be called multiple times, possibly with
+        * different chip_info, release previously requested GPIO.
         */
-       if (chip->gpiod_cs) {
-               gpiod_put(chip->gpiod_cs);
-               chip->gpiod_cs = NULL;
-       }
+       cleanup_cs(spi);
 
-       /* If (*cs_control) is provided, ignore GPIO chip select */
+       /* If ->cs_control() is provided, ignore GPIO chip select */
        if (chip_info->cs_control) {
                chip->cs_control = chip_info->cs_control;
                return 0;
        }
 
        if (gpio_is_valid(chip_info->gpio_cs)) {
-               err = gpio_request(chip_info->gpio_cs, "SPI_CS");
+               int gpio = chip_info->gpio_cs;
+               int err;
+
+               err = gpio_request(gpio, "SPI_CS");
                if (err) {
-                       dev_err(&spi->dev, "failed to request chip select GPIO%d\n",
-                               chip_info->gpio_cs);
+                       dev_err(&spi->dev, "failed to request chip select GPIO%d\n", gpio);
                        return err;
                }
 
-               gpiod = gpio_to_desc(chip_info->gpio_cs);
-               chip->gpiod_cs = gpiod;
-               chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+               err = gpio_direction_output(gpio, !(spi->mode & SPI_CS_HIGH));
+               if (err) {
+                       gpio_free(gpio);
+                       return err;
+               }
 
-               err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted);
-               if (err)
-                       gpiod_put(chip->gpiod_cs);
+               spi->cs_gpio = gpio;
        }
 
-       return err;
+       return 0;
 }
 
 static int setup(struct spi_device *spi)
@@ -1277,6 +1258,11 @@ static int setup(struct spi_device *spi)
                tx_hi_thres = 0;
                rx_thres = RX_THRESH_QUARK_X1000_DFLT;
                break;
+       case MRFLD_SSP:
+               tx_thres = TX_THRESH_MRFLD_DFLT;
+               tx_hi_thres = 0;
+               rx_thres = RX_THRESH_MRFLD_DFLT;
+               break;
        case CE4100_SSP:
                tx_thres = TX_THRESH_CE4100_DFLT;
                tx_hi_thres = 0;
@@ -1305,7 +1291,7 @@ static int setup(struct spi_device *spi)
                break;
        }
 
-       /* Only alloc on first setup */
+       /* Only allocate on the first setup */
        chip = spi_get_ctldata(spi);
        if (!chip) {
                chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
@@ -1319,15 +1305,15 @@ static int setup(struct spi_device *spi)
                                kfree(chip);
                                return -EINVAL;
                        }
-
-                       chip->frm = spi->chip_select;
                }
                chip->enable_dma = drv_data->controller_info->enable_dma;
                chip->timeout = TIMOUT_DFLT;
        }
 
-       /* protocol drivers may change the chip settings, so...
-        * if chip_info exists, use it */
+       /*
+        * Protocol drivers may change the chip settings, so...
+        * if chip_info exists, use it.
+        */
        chip_info = spi->controller_data;
 
        /* chip_info isn't always needed */
@@ -1352,15 +1338,24 @@ static int setup(struct spi_device *spi)
                chip->cr1 |= SSCR1_SPH;
        }
 
-       chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
-       chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
-                               | SSITF_TxHiThresh(tx_hi_thres);
+       if (is_lpss_ssp(drv_data)) {
+               chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
+               chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) |
+                                         SSITF_TxHiThresh(tx_hi_thres);
+       }
+
+       if (is_mrfld_ssp(drv_data)) {
+               chip->lpss_rx_threshold = rx_thres;
+               chip->lpss_tx_threshold = tx_thres;
+       }
 
-       /* set dma burst and threshold outside of chip_info path so that if
-        * chip_info goes away after setting chip->enable_dma, the
-        * burst and threshold can still respond to changes in bits_per_word */
+       /*
+        * Set DMA burst and threshold outside of chip_info path so that if
+        * chip_info goes away after setting chip->enable_dma, the burst and
+        * threshold can still respond to changes in bits_per_word.
+        */
        if (chip->enable_dma) {
-               /* set up legal burst and threshold for dma */
+               /* Set up legal burst and threshold for DMA */
                if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
                                                spi->bits_per_word,
                                                &chip->dma_burst_size,
@@ -1391,8 +1386,8 @@ static int setup(struct spi_device *spi)
        }
 
        chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
-       chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
-                       | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
+       chip->cr1 |= ((spi->mode & SPI_CPHA) ? SSCR1_SPH : 0) |
+                    ((spi->mode & SPI_CPOL) ? SSCR1_SPO : 0);
 
        if (spi->mode & SPI_LOOP)
                chip->cr1 |= SSCR1_LBM;
@@ -1426,16 +1421,8 @@ static int setup(struct spi_device *spi)
 static void cleanup(struct spi_device *spi)
 {
        struct chip_data *chip = spi_get_ctldata(spi);
-       struct driver_data *drv_data =
-               spi_controller_get_devdata(spi->controller);
-
-       if (!chip)
-               return;
-
-       if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
-           chip->gpiod_cs)
-               gpiod_put(chip->gpiod_cs);
 
+       cleanup_cs(spi);
        kfree(chip);
 }
 
@@ -1652,7 +1639,7 @@ static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller,
 {
        struct driver_data *drv_data = spi_controller_get_devdata(controller);
 
-       if (has_acpi_companion(&drv_data->pdev->dev)) {
+       if (has_acpi_companion(drv_data->ssp->dev)) {
                switch (drv_data->ssp_type) {
                /*
                 * For Atoms the ACPI DeviceSelection used by the Windows
@@ -1684,7 +1671,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        struct driver_data *drv_data;
        struct ssp_device *ssp;
        const struct lpss_config *config;
-       int status, count;
+       int status;
        u32 tmp;
 
        platform_info = dev_get_platdata(dev);
@@ -1701,7 +1688,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                ssp = &platform_info->ssp;
 
        if (!ssp->mmio_base) {
-               dev_err(&pdev->dev, "failed to get ssp\n");
+               dev_err(&pdev->dev, "failed to get SSP\n");
                return -ENODEV;
        }
 
@@ -1712,17 +1699,18 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 
        if (!controller) {
                dev_err(&pdev->dev, "cannot alloc spi_controller\n");
-               pxa_ssp_free(ssp);
-               return -ENOMEM;
+               status = -ENOMEM;
+               goto out_error_controller_alloc;
        }
        drv_data = spi_controller_get_devdata(controller);
        drv_data->controller = controller;
        drv_data->controller_info = platform_info;
-       drv_data->pdev = pdev;
        drv_data->ssp = ssp;
 
-       controller->dev.of_node = pdev->dev.of_node;
-       /* the spi->mode bits understood by this driver: */
+       controller->dev.of_node = dev->of_node;
+       controller->dev.fwnode = dev->fwnode;
+
+       /* The spi->mode bits understood by this driver: */
        controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
 
        controller->bus_num = ssp->port_id;
@@ -1740,8 +1728,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 
        drv_data->ssp_type = ssp->type;
 
-       drv_data->ioaddr = ssp->mmio_base;
-       drv_data->ssdr_physical = ssp->phys_base + SSDR;
        if (pxa25x_ssp_comp(drv_data)) {
                switch (drv_data->ssp_type) {
                case QUARK_X1000_SSP:
@@ -1803,15 +1789,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                controller->min_speed_hz =
                        DIV_ROUND_UP(controller->max_speed_hz, 512);
 
+       pxa_ssp_disable(ssp);
+
        /* Load default SSP configuration */
-       pxa2xx_spi_write(drv_data, SSCR0, 0);
        switch (drv_data->ssp_type) {
        case QUARK_X1000_SSP:
                tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) |
                      QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
                pxa2xx_spi_write(drv_data, SSCR1, tmp);
 
-               /* using the Motorola SPI protocol and use 8 bit frame */
+               /* Using the Motorola SPI protocol and use 8 bit frame */
                tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8);
                pxa2xx_spi_write(drv_data, SSCR0, tmp);
                break;
@@ -1863,38 +1850,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                }
        }
        controller->num_chipselect = platform_info->num_chipselect;
-
-       count = gpiod_count(&pdev->dev, "cs");
-       if (count > 0) {
-               int i;
-
-               controller->num_chipselect = max_t(int, count,
-                       controller->num_chipselect);
-
-               drv_data->cs_gpiods = devm_kcalloc(&pdev->dev,
-                       controller->num_chipselect, sizeof(struct gpio_desc *),
-                       GFP_KERNEL);
-               if (!drv_data->cs_gpiods) {
-                       status = -ENOMEM;
-                       goto out_error_clock_enabled;
-               }
-
-               for (i = 0; i < controller->num_chipselect; i++) {
-                       struct gpio_desc *gpiod;
-
-                       gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
-                       if (IS_ERR(gpiod)) {
-                               /* Means use native chip select */
-                               if (PTR_ERR(gpiod) == -ENOENT)
-                                       continue;
-
-                               status = PTR_ERR(gpiod);
-                               goto out_error_clock_enabled;
-                       } else {
-                               drv_data->cs_gpiods[i] = gpiod;
-                       }
-               }
-       }
+       controller->use_gpio_descriptors = true;
 
        if (platform_info->is_slave) {
                drv_data->gpiod_ready = devm_gpiod_get_optional(dev,
@@ -1913,8 +1869,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        /* Register with the SPI framework */
        platform_set_drvdata(pdev, drv_data);
        status = spi_register_controller(controller);
-       if (status != 0) {
-               dev_err(&pdev->dev, "problem registering spi controller\n");
+       if (status) {
+               dev_err(&pdev->dev, "problem registering SPI controller\n");
                goto out_error_pm_runtime_enabled;
        }
 
@@ -1945,7 +1901,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
        spi_unregister_controller(drv_data->controller);
 
        /* Disable the SSP at the peripheral and SOC level */
-       pxa2xx_spi_write(drv_data, SSCR0, 0);
+       pxa_ssp_disable(ssp);
        clk_disable_unprepare(ssp->clk);
 
        /* Release DMA */
@@ -1972,9 +1928,10 @@ static int pxa2xx_spi_suspend(struct device *dev)
        int status;
 
        status = spi_controller_suspend(drv_data->controller);
-       if (status != 0)
+       if (status)
                return status;
-       pxa2xx_spi_write(drv_data, SSCR0, 0);
+
+       pxa_ssp_disable(ssp);
 
        if (!pm_runtime_suspended(dev))
                clk_disable_unprepare(ssp->clk);
index 1400472..9a20fb8 100644 (file)
@@ -1,28 +1,26 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
  */
 
 #ifndef SPI_PXA2XX_H
 #define SPI_PXA2XX_H
 
-#include <linux/atomic.h>
-#include <linux/dmaengine.h>
-#include <linux/errno.h>
-#include <linux/io.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/pxa2xx_ssp.h>
-#include <linux/scatterlist.h>
+#include <linux/io.h>
+#include <linux/types.h>
 #include <linux/sizes.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/pxa2xx_spi.h>
 
-struct driver_data {
-       /* Driver model hookup */
-       struct platform_device *pdev;
+#include <linux/pxa2xx_ssp.h>
+
+struct gpio_desc;
+struct pxa2xx_spi_controller;
+struct spi_controller;
+struct spi_device;
+struct spi_transfer;
 
+struct driver_data {
        /* SSP Info */
        struct ssp_device *ssp;
 
@@ -33,10 +31,6 @@ struct driver_data {
        /* PXA hookup */
        struct pxa2xx_spi_controller *controller_info;
 
-       /* SSP register addresses */
-       void __iomem *ioaddr;
-       phys_addr_t ssdr_physical;
-
        /* SSP masks*/
        u32 dma_cr1;
        u32 int_cr1;
@@ -59,9 +53,6 @@ struct driver_data {
 
        void __iomem *lpss_base;
 
-       /* GPIOs for chip selects */
-       struct gpio_desc **cs_gpiods;
-
        /* Optional slave FIFO ready signal */
        struct gpio_desc *gpiod_ready;
 };
@@ -71,37 +62,32 @@ struct chip_data {
        u32 dds_rate;
        u32 timeout;
        u8 n_bytes;
+       u8 enable_dma;
        u32 dma_burst_size;
-       u32 threshold;
        u32 dma_threshold;
+       u32 threshold;
        u16 lpss_rx_threshold;
        u16 lpss_tx_threshold;
-       u8 enable_dma;
-       union {
-               struct gpio_desc *gpiod_cs;
-               unsigned int frm;
-       };
-       int gpio_cs_inverted;
+
        int (*write)(struct driver_data *drv_data);
        int (*read)(struct driver_data *drv_data);
+
        void (*cs_control)(u32 command);
 };
 
-static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data,
-                                 unsigned reg)
+static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
 {
-       return __raw_readl(drv_data->ioaddr + reg);
+       return pxa_ssp_read_reg(drv_data->ssp, reg);
 }
 
-static  inline void pxa2xx_spi_write(const struct driver_data *drv_data,
-                                    unsigned reg, u32 val)
+static inline void pxa2xx_spi_write(const struct driver_data *drv_data, u32 reg, u32 val)
 {
-       __raw_writel(val, drv_data->ioaddr + reg);
+       pxa_ssp_write_reg(drv_data->ssp, reg, val);
 }
 
 #define DMA_ALIGNMENT          8
 
-static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
+static inline int pxa25x_ssp_comp(const struct driver_data *drv_data)
 {
        switch (drv_data->ssp_type) {
        case PXA25x_SSP:
@@ -113,11 +99,21 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
        }
 }
 
-static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+static inline void clear_SSCR1_bits(const struct driver_data *drv_data, u32 bits)
+{
+       pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~bits);
+}
+
+static inline u32 read_SSSR_bits(const struct driver_data *drv_data, u32 bits)
+{
+       return pxa2xx_spi_read(drv_data, SSSR) & bits;
+}
+
+static inline void write_SSSR_CS(const struct driver_data *drv_data, u32 val)
 {
        if (drv_data->ssp_type == CE4100_SSP ||
            drv_data->ssp_type == QUARK_X1000_SSP)
-               val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK;
+               val |= read_SSSR_bits(drv_data, SSSR_ALT_FRM_MASK);
 
        pxa2xx_spi_write(drv_data, SSSR, val);
 }
index 52d6259..540861c 100644 (file)
 #define CR0_OPM_MASTER                         0x0
 #define CR0_OPM_SLAVE                          0x1
 
+#define CR0_SOI_OFFSET                         23
+
 #define CR0_MTM_OFFSET                         0x21
 
 /* Bit fields in SER, 2bit */
 #define BAUDR_SCKDV_MIN                                2
 #define BAUDR_SCKDV_MAX                                65534
 
-/* Bit fields in SR, 5bit */
-#define SR_MASK                                                0x1f
+/* Bit fields in SR, 6bit */
+#define SR_MASK                                                0x3f
 #define SR_BUSY                                                (1 << 0)
 #define SR_TF_FULL                                     (1 << 1)
 #define SR_TF_EMPTY                                    (1 << 2)
 #define SR_RF_EMPTY                                    (1 << 3)
 #define SR_RF_FULL                                     (1 << 4)
+#define SR_SLAVE_TX_BUSY                               (1 << 5)
 
 /* Bit fields in ISR, IMR, ISR, RISR, 5bit */
 #define INT_MASK                                       0x1f
  */
 #define ROCKCHIP_SPI_MAX_TRANLEN               0xffff
 
-#define ROCKCHIP_SPI_MAX_CS_NUM                        2
+/* 2 for native cs, 2 for cs-gpio */
+#define ROCKCHIP_SPI_MAX_CS_NUM                        4
 #define ROCKCHIP_SPI_VER2_TYPE1                        0x05EC0002
 #define ROCKCHIP_SPI_VER2_TYPE2                        0x00110002
 
@@ -197,13 +201,19 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
        writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
 }
 
-static inline void wait_for_idle(struct rockchip_spi *rs)
+static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(5);
 
        do {
-               if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
-                       return;
+               if (slave_mode) {
+                       if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) &&
+                           !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
+                               return;
+               } else {
+                       if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
+                               return;
+               }
        } while (!time_after(jiffies, timeout));
 
        dev_warn(rs->dev, "spi controller is in busy state!\n");
@@ -228,7 +238,7 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
 {
        struct spi_controller *ctlr = spi->controller;
        struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
-       bool cs_asserted = !enable;
+       bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
 
        /* Return immediately for no-op */
        if (cs_asserted == rs->cs_asserted[spi->chip_select])
@@ -238,11 +248,15 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
                /* Keep things powered as long as CS is asserted */
                pm_runtime_get_sync(rs->dev);
 
-               ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER,
-                                     BIT(spi->chip_select));
+               if (spi->cs_gpiod)
+                       ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+               else
+                       ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
        } else {
-               ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER,
-                                     BIT(spi->chip_select));
+               if (spi->cs_gpiod)
+                       ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+               else
+                       ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
 
                /* Drop reference from when we first asserted CS */
                pm_runtime_put(rs->dev);
@@ -383,7 +397,7 @@ static void rockchip_spi_dma_txcb(void *data)
                return;
 
        /* Wait until the FIFO data completely. */
-       wait_for_idle(rs);
+       wait_for_tx_idle(rs, ctlr->slave);
 
        spi_enable_chip(rs, false);
        spi_finalize_current_transfer(ctlr);
@@ -495,6 +509,8 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
        cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
        if (spi->mode & SPI_LSB_FIRST)
                cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
+       if (spi->mode & SPI_CS_HIGH)
+               cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET;
 
        if (xfer->rx_buf && xfer->tx_buf)
                cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
@@ -540,12 +556,12 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
         * interrupt exactly when the fifo is full doesn't seem to work,
         * so we need the strict inequality here
         */
-       if (xfer->len < rs->fifo_len)
-               writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+       if ((xfer->len / rs->n_bytes) < rs->fifo_len)
+               writel_relaxed(xfer->len / rs->n_bytes - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
        else
                writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
 
-       writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
+       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
        writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1,
                       rs->regs + ROCKCHIP_SPI_DMARDLR);
        writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
@@ -783,6 +799,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                ctlr->can_dma = rockchip_spi_can_dma;
        }
 
+       switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) {
+       case ROCKCHIP_SPI_VER2_TYPE2:
+               ctlr->mode_bits |= SPI_CS_HIGH;
+               break;
+       default:
+               break;
+       }
+
        ret = devm_spi_register_controller(&pdev->dev, ctlr);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register controller\n");
@@ -922,6 +946,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
        { .compatible = "rockchip,rk3368-spi", },
        { .compatible = "rockchip,rk3399-spi", },
        { .compatible = "rockchip,rv1108-spi", },
+       { .compatible = "rockchip,rv1126-spi", },
        { },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
index e39fd38..d16ed88 100644 (file)
@@ -618,9 +618,9 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
                        ret = -ETIMEDOUT;
                }
                if (tx)
-                       dmaengine_terminate_all(rspi->ctlr->dma_tx);
+                       dmaengine_terminate_sync(rspi->ctlr->dma_tx);
                if (rx)
-                       dmaengine_terminate_all(rspi->ctlr->dma_rx);
+                       dmaengine_terminate_sync(rspi->ctlr->dma_rx);
        }
 
        rspi_disable_irq(rspi, irq_mask);
@@ -634,7 +634,7 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
 
 no_dma_tx:
        if (rx)
-               dmaengine_terminate_all(rspi->ctlr->dma_rx);
+               dmaengine_terminate_sync(rspi->ctlr->dma_rx);
 no_dma_rx:
        if (ret == -EAGAIN) {
                dev_warn_once(&rspi->ctlr->dev,
index 41ed9ff..f88d9ac 100644 (file)
@@ -853,10 +853,10 @@ stop_reset:
        sh_msiof_spi_stop(p, rx);
 stop_dma:
        if (tx)
-               dmaengine_terminate_all(p->ctlr->dma_tx);
+               dmaengine_terminate_sync(p->ctlr->dma_tx);
 no_dma_tx:
        if (rx)
-               dmaengine_terminate_all(p->ctlr->dma_rx);
+               dmaengine_terminate_sync(p->ctlr->dma_rx);
        sh_msiof_write(p, SIIER, 0);
        return ret;
 }
index 594f641..27f35aa 100644 (file)
@@ -36,6 +36,7 @@
 #define CR_FTIE                        BIT(18)
 #define CR_SMIE                        BIT(19)
 #define CR_TOIE                        BIT(20)
+#define CR_APMS                        BIT(22)
 #define CR_PRESC_MASK          GENMASK(31, 24)
 
 #define QSPI_DCR               0x04
@@ -53,6 +54,7 @@
 #define QSPI_FCR               0x0c
 #define FCR_CTEF               BIT(0)
 #define FCR_CTCF               BIT(1)
+#define FCR_CSMF               BIT(3)
 
 #define QSPI_DLR               0x10
 
@@ -91,7 +93,6 @@
 #define STM32_AUTOSUSPEND_DELAY -1
 
 struct stm32_qspi_flash {
-       struct stm32_qspi *qspi;
        u32 cs;
        u32 presc;
 };
@@ -107,6 +108,7 @@ struct stm32_qspi {
        u32 clk_rate;
        struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
        struct completion data_completion;
+       struct completion match_completion;
        u32 fmode;
 
        struct dma_chan *dma_chtx;
@@ -115,6 +117,7 @@ struct stm32_qspi {
 
        u32 cr_reg;
        u32 dcr_reg;
+       unsigned long status_timeout;
 
        /*
         * to protect device configuration, could be different between
@@ -128,11 +131,20 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
        struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
        u32 cr, sr;
 
+       cr = readl_relaxed(qspi->io_base + QSPI_CR);
        sr = readl_relaxed(qspi->io_base + QSPI_SR);
 
+       if (cr & CR_SMIE && sr & SR_SMF) {
+               /* disable irq */
+               cr &= ~CR_SMIE;
+               writel_relaxed(cr, qspi->io_base + QSPI_CR);
+               complete(&qspi->match_completion);
+
+               return IRQ_HANDLED;
+       }
+
        if (sr & (SR_TEF | SR_TCF)) {
                /* disable irq */
-               cr = readl_relaxed(qspi->io_base + QSPI_CR);
                cr &= ~CR_TCIE & ~CR_TEIE;
                writel_relaxed(cr, qspi->io_base + QSPI_CR);
                complete(&qspi->data_completion);
@@ -322,6 +334,24 @@ wait_nobusy:
        return err;
 }
 
+static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi,
+                                      const struct spi_mem_op *op)
+{
+       u32 cr;
+
+       reinit_completion(&qspi->match_completion);
+       cr = readl_relaxed(qspi->io_base + QSPI_CR);
+       writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR);
+
+       if (!wait_for_completion_timeout(&qspi->match_completion,
+                               msecs_to_jiffies(qspi->status_timeout)))
+               return -ETIMEDOUT;
+
+       writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR);
+
+       return 0;
+}
+
 static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth)
 {
        if (buswidth == 4)
@@ -335,7 +365,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
        struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
        struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select];
        u32 ccr, cr;
-       int timeout, err = 0;
+       int timeout, err = 0, err_poll_status = 0;
 
        dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
                op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
@@ -381,6 +411,9 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
        if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM)
                writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
 
+       if (qspi->fmode == CCR_FMODE_APM)
+               err_poll_status = stm32_qspi_wait_poll_status(qspi, op);
+
        err = stm32_qspi_tx(qspi, op);
 
        /*
@@ -390,7 +423,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
         *  byte of device (device size - fifo size). like device size is not
         *  knows, the prefetching is always stop.
         */
-       if (err || qspi->fmode == CCR_FMODE_MM)
+       if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM)
                goto abort;
 
        /* wait end of tx in indirect mode */
@@ -409,15 +442,49 @@ abort:
                                                    cr, !(cr & CR_ABORT), 1,
                                                    STM32_ABT_TIMEOUT_US);
 
-       writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR);
+       writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR);
 
-       if (err || timeout)
-               dev_err(qspi->dev, "%s err:%d abort timeout:%d\n",
-                       __func__, err, timeout);
+       if (err || err_poll_status || timeout)
+               dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n",
+                       __func__, err, err_poll_status, timeout);
 
        return err;
 }
 
+static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op,
+                                 u16 mask, u16 match,
+                                 unsigned long initial_delay_us,
+                                 unsigned long polling_rate_us,
+                                 unsigned long timeout_ms)
+{
+       struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+       int ret;
+
+       if (!spi_mem_supports_op(mem, op))
+               return -EOPNOTSUPP;
+
+       ret = pm_runtime_get_sync(qspi->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(qspi->dev);
+               return ret;
+       }
+
+       mutex_lock(&qspi->lock);
+
+       writel_relaxed(mask, qspi->io_base + QSPI_PSMKR);
+       writel_relaxed(match, qspi->io_base + QSPI_PSMAR);
+       qspi->fmode = CCR_FMODE_APM;
+       qspi->status_timeout = timeout_ms;
+
+       ret = stm32_qspi_send(mem, op);
+       mutex_unlock(&qspi->lock);
+
+       pm_runtime_mark_last_busy(qspi->dev);
+       pm_runtime_put_autosuspend(qspi->dev);
+
+       return ret;
+}
+
 static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
 {
        struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
@@ -525,12 +592,11 @@ static int stm32_qspi_setup(struct spi_device *spi)
        presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
 
        flash = &qspi->flash[spi->chip_select];
-       flash->qspi = qspi;
        flash->cs = spi->chip_select;
        flash->presc = presc;
 
        mutex_lock(&qspi->lock);
-       qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
+       qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
        writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
 
        /* set dcr fsize to max address */
@@ -610,6 +676,7 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
        .exec_op        = stm32_qspi_exec_op,
        .dirmap_create  = stm32_qspi_dirmap_create,
        .dirmap_read    = stm32_qspi_dirmap_read,
+       .poll_status    = stm32_qspi_poll_status,
 };
 
 static int stm32_qspi_probe(struct platform_device *pdev)
@@ -664,6 +731,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        }
 
        init_completion(&qspi->data_completion);
+       init_completion(&qspi->match_completion);
 
        qspi->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(qspi->clk)) {
index cc84019..23ad052 100644 (file)
@@ -379,6 +379,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
        }
 
        sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+       /* Finally enable the bus - doing so before might raise SCK to HIGH */
+       reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
+       reg |= SUN6I_GBL_CTL_BUS_ENABLE;
+       sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
 
        /* Setup the transfer now... */
        if (sspi->tx_buf)
@@ -504,7 +508,7 @@ static int sun6i_spi_runtime_resume(struct device *dev)
        }
 
        sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
-                       SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+                       SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
 
        return 0;
 
index a2e5907..5131141 100644 (file)
@@ -1071,8 +1071,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
                ret = wait_for_completion_timeout(&tspi->xfer_completion,
                                                SPI_DMA_TIMEOUT);
                if (WARN_ON(ret == 0)) {
-                       dev_err(tspi->dev,
-                               "spi transfer timeout, err %d\n", ret);
+                       dev_err(tspi->dev, "spi transfer timeout\n");
                        if (tspi->is_curr_dma_xfer &&
                            (tspi->cur_direction & DATA_DIR_TX))
                                dmaengine_terminate_all(tspi->tx_dma_chan);
index f7c832f..6a726c9 100644 (file)
@@ -1118,6 +1118,11 @@ static int tegra_slink_probe(struct platform_device *pdev)
                pm_runtime_put_noidle(&pdev->dev);
                goto exit_pm_disable;
        }
+
+       reset_control_assert(tspi->rst);
+       udelay(2);
+       reset_control_deassert(tspi->rst);
+
        tspi->def_command_reg  = SLINK_M_S;
        tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
        tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
index 2f806f4..2354ca1 100644 (file)
@@ -1028,7 +1028,7 @@ static int tegra_qspi_transfer_one_message(struct spi_master *master, struct spi
                ret = wait_for_completion_timeout(&tqspi->xfer_completion,
                                                  QSPI_DMA_TIMEOUT);
                if (WARN_ON(ret == 0)) {
-                       dev_err(tqspi->dev, "transfer timeout: %d\n", ret);
+                       dev_err(tqspi->dev, "transfer timeout\n");
                        if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_TX))
                                dmaengine_terminate_all(tqspi->tx_dma_chan);
                        if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
index b887078..8c4615b 100644 (file)
@@ -580,8 +580,10 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
        data->pkt_tx_buff = kzalloc(size, GFP_KERNEL);
        if (data->pkt_tx_buff != NULL) {
                data->pkt_rx_buff = kzalloc(size, GFP_KERNEL);
-               if (!data->pkt_rx_buff)
+               if (!data->pkt_rx_buff) {
                        kfree(data->pkt_tx_buff);
+                       data->pkt_tx_buff = NULL;
+               }
        }
 
        if (!data->pkt_rx_buff) {
index 6a9ef8e..8900e51 100644 (file)
@@ -142,7 +142,7 @@ static void uniphier_spi_set_mode(struct spi_device *spi)
         * FSTRT    start frame timing
         *          0: rising edge of clock, 1: falling edge of clock
         */
-       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       switch (spi->mode & SPI_MODE_X_MASK) {
        case SPI_MODE_0:
                /* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */
                val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY;
index e353b7a..c991811 100644 (file)
@@ -363,6 +363,10 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
        const struct spi_device         *spi = to_spi_device(dev);
        int rc;
 
+       rc = of_device_uevent_modalias(dev, env);
+       if (rc != -ENODEV)
+               return rc;
+
        rc = acpi_device_uevent_modalias(dev, env);
        if (rc != -ENODEV)
                return rc;
@@ -560,49 +564,23 @@ static void spi_cleanup(struct spi_device *spi)
                spi->controller->cleanup(spi);
 }
 
-/**
- * spi_add_device - Add spi_device allocated with spi_alloc_device
- * @spi: spi_device to register
- *
- * Companion function to spi_alloc_device.  Devices allocated with
- * spi_alloc_device can be added onto the spi bus with this function.
- *
- * Return: 0 on success; negative errno on failure
- */
-int spi_add_device(struct spi_device *spi)
+static int __spi_add_device(struct spi_device *spi)
 {
        struct spi_controller *ctlr = spi->controller;
        struct device *dev = ctlr->dev.parent;
        int status;
 
-       /* Chipselects are numbered 0..max; validate. */
-       if (spi->chip_select >= ctlr->num_chipselect) {
-               dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
-                       ctlr->num_chipselect);
-               return -EINVAL;
-       }
-
-       /* Set the bus ID string */
-       spi_dev_set_name(spi);
-
-       /* We need to make sure there's no other device with this
-        * chipselect **BEFORE** we call setup(), else we'll trash
-        * its configuration.  Lock against concurrent add() calls.
-        */
-       mutex_lock(&spi_add_lock);
-
        status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
        if (status) {
                dev_err(dev, "chipselect %d already in use\n",
                                spi->chip_select);
-               goto done;
+               return status;
        }
 
        /* Controller may unregister concurrently */
        if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
            !device_is_registered(&ctlr->dev)) {
-               status = -ENODEV;
-               goto done;
+               return -ENODEV;
        }
 
        /* Descriptors take precedence */
@@ -619,7 +597,7 @@ int spi_add_device(struct spi_device *spi)
        if (status < 0) {
                dev_err(dev, "can't setup %s, status %d\n",
                                dev_name(&spi->dev), status);
-               goto done;
+               return status;
        }
 
        /* Device may be bound to an active driver when this returns */
@@ -632,12 +610,64 @@ int spi_add_device(struct spi_device *spi)
                dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
        }
 
-done:
+       return status;
+}
+
+/**
+ * spi_add_device - Add spi_device allocated with spi_alloc_device
+ * @spi: spi_device to register
+ *
+ * Companion function to spi_alloc_device.  Devices allocated with
+ * spi_alloc_device can be added onto the spi bus with this function.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+int spi_add_device(struct spi_device *spi)
+{
+       struct spi_controller *ctlr = spi->controller;
+       struct device *dev = ctlr->dev.parent;
+       int status;
+
+       /* Chipselects are numbered 0..max; validate. */
+       if (spi->chip_select >= ctlr->num_chipselect) {
+               dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+                       ctlr->num_chipselect);
+               return -EINVAL;
+       }
+
+       /* Set the bus ID string */
+       spi_dev_set_name(spi);
+
+       /* We need to make sure there's no other device with this
+        * chipselect **BEFORE** we call setup(), else we'll trash
+        * its configuration.  Lock against concurrent add() calls.
+        */
+       mutex_lock(&spi_add_lock);
+       status = __spi_add_device(spi);
        mutex_unlock(&spi_add_lock);
        return status;
 }
 EXPORT_SYMBOL_GPL(spi_add_device);
 
+static int spi_add_device_locked(struct spi_device *spi)
+{
+       struct spi_controller *ctlr = spi->controller;
+       struct device *dev = ctlr->dev.parent;
+
+       /* Chipselects are numbered 0..max; validate. */
+       if (spi->chip_select >= ctlr->num_chipselect) {
+               dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+                       ctlr->num_chipselect);
+               return -EINVAL;
+       }
+
+       /* Set the bus ID string */
+       spi_dev_set_name(spi);
+
+       WARN_ON(!mutex_is_locked(&spi_add_lock));
+       return __spi_add_device(spi);
+}
+
 /**
  * spi_new_device - instantiate one new SPI device
  * @ctlr: Controller to which device is connected
@@ -804,6 +834,8 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
            (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
                return;
 
+       trace_spi_set_cs(spi, activate);
+
        spi->controller->last_cs_enable = enable;
        spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
 
@@ -961,11 +993,15 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
 
        if (ctlr->dma_tx)
                tx_dev = ctlr->dma_tx->device->dev;
+       else if (ctlr->dma_map_dev)
+               tx_dev = ctlr->dma_map_dev;
        else
                tx_dev = ctlr->dev.parent;
 
        if (ctlr->dma_rx)
                rx_dev = ctlr->dma_rx->device->dev;
+       else if (ctlr->dma_map_dev)
+               rx_dev = ctlr->dma_map_dev;
        else
                rx_dev = ctlr->dev.parent;
 
@@ -1132,10 +1168,20 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
                if (!speed_hz)
                        speed_hz = 100000;
 
-               ms = 8LL * 1000LL * xfer->len;
+               /*
+                * For each byte we wait for 8 cycles of the SPI clock.
+                * Since speed is defined in Hz and we want milliseconds,
+                * use respective multiplier, but before the division,
+                * otherwise we may get 0 for short transfers.
+                */
+               ms = 8LL * MSEC_PER_SEC * xfer->len;
                do_div(ms, speed_hz);
-               ms += ms + 200; /* some tolerance */
 
+               /*
+                * Increase it twice and add 200 ms tolerance, use
+                * predefined maximum in case of overflow.
+                */
+               ms += ms + 200;
                if (ms > UINT_MAX)
                        ms = UINT_MAX;
 
@@ -1158,10 +1204,10 @@ static void _spi_transfer_delay_ns(u32 ns)
 {
        if (!ns)
                return;
-       if (ns <= 1000) {
+       if (ns <= NSEC_PER_USEC) {
                ndelay(ns);
        } else {
-               u32 us = DIV_ROUND_UP(ns, 1000);
+               u32 us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
 
                if (us <= 10)
                        udelay(us);
@@ -1181,21 +1227,25 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
 
        switch (unit) {
        case SPI_DELAY_UNIT_USECS:
-               delay *= 1000;
+               delay *= NSEC_PER_USEC;
                break;
-       case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
+       case SPI_DELAY_UNIT_NSECS:
+               /* Nothing to do here */
                break;
        case SPI_DELAY_UNIT_SCK:
                /* clock cycles need to be obtained from spi_transfer */
                if (!xfer)
                        return -EINVAL;
-               /* if there is no effective speed know, then approximate
-                * by underestimating with half the requested hz
+               /*
+                * If there is unknown effective speed, approximate it
+                * by underestimating with half of the requested hz.
                 */
                hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
                if (!hz)
                        return -EINVAL;
-               delay *= DIV_ROUND_UP(1000000000, hz);
+
+               /* Convert delay to nanoseconds */
+               delay *= DIV_ROUND_UP(NSEC_PER_SEC, hz);
                break;
        default:
                return -EINVAL;
@@ -1227,6 +1277,7 @@ EXPORT_SYMBOL_GPL(spi_delay_exec);
 static void _spi_transfer_cs_change_delay(struct spi_message *msg,
                                          struct spi_transfer *xfer)
 {
+       u32 default_delay_ns = 10 * NSEC_PER_USEC;
        u32 delay = xfer->cs_change_delay.value;
        u32 unit = xfer->cs_change_delay.unit;
        int ret;
@@ -1234,16 +1285,16 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg,
        /* return early on "fast" mode - for everything but USECS */
        if (!delay) {
                if (unit == SPI_DELAY_UNIT_USECS)
-                       _spi_transfer_delay_ns(10000);
+                       _spi_transfer_delay_ns(default_delay_ns);
                return;
        }
 
        ret = spi_delay_exec(&xfer->cs_change_delay, xfer);
        if (ret) {
                dev_err_once(&msg->spi->dev,
-                            "Use of unsupported delay unit %i, using default of 10us\n",
-                            unit);
-               _spi_transfer_delay_ns(10000);
+                            "Use of unsupported delay unit %i, using default of %luus\n",
+                            unit, default_delay_ns / NSEC_PER_USEC);
+               _spi_transfer_delay_ns(default_delay_ns);
        }
 }
 
@@ -2057,6 +2108,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
        /* Store a pointer to the node in the device structure */
        of_node_get(nc);
        spi->dev.of_node = nc;
+       spi->dev.fwnode = of_fwnode_handle(nc);
 
        /* Register the new device */
        rc = spi_add_device(spi);
@@ -2104,6 +2156,55 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
 static void of_register_spi_devices(struct spi_controller *ctlr) { }
 #endif
 
+/**
+ * spi_new_ancillary_device() - Register ancillary SPI device
+ * @spi:         Pointer to the main SPI device registering the ancillary device
+ * @chip_select: Chip Select of the ancillary device
+ *
+ * Register an ancillary SPI device; for example some chips have a chip-select
+ * for normal device usage and another one for setup/firmware upload.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
+                                            u8 chip_select)
+{
+       struct spi_device *ancillary;
+       int rc = 0;
+
+       /* Alloc an spi_device */
+       ancillary = spi_alloc_device(spi->controller);
+       if (!ancillary) {
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
+       strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
+
+       /* Use provided chip-select for ancillary device */
+       ancillary->chip_select = chip_select;
+
+       /* Take over SPI mode/speed from SPI main device */
+       ancillary->max_speed_hz = spi->max_speed_hz;
+       ancillary->mode = spi->mode;
+
+       /* Register the new device */
+       rc = spi_add_device_locked(ancillary);
+       if (rc) {
+               dev_err(&spi->dev, "failed to register ancillary device\n");
+               goto err_out;
+       }
+
+       return ancillary;
+
+err_out:
+       spi_dev_put(ancillary);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(spi_new_ancillary_device);
+
 #ifdef CONFIG_ACPI
 struct acpi_spi_lookup {
        struct spi_controller   *ctlr;
@@ -2621,9 +2722,10 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr)
                native_cs_mask |= BIT(i);
        }
 
-       ctlr->unused_native_cs = ffz(native_cs_mask);
-       if (num_cs_gpios && ctlr->max_native_cs &&
-           ctlr->unused_native_cs >= ctlr->max_native_cs) {
+       ctlr->unused_native_cs = ffs(~native_cs_mask) - 1;
+
+       if ((ctlr->flags & SPI_MASTER_GPIO_SS) && num_cs_gpios &&
+           ctlr->max_native_cs && ctlr->unused_native_cs >= ctlr->max_native_cs) {
                dev_err(dev, "No unused native chip select available\n");
                return -EINVAL;
        }
@@ -3440,8 +3542,10 @@ int spi_setup(struct spi_device *spi)
                spi_set_thread_rt(spi->controller);
        }
 
-       dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
-                       (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
+       trace_spi_setup(spi, status);
+
+       dev_dbg(&spi->dev, "setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
+                       spi->mode & SPI_MODE_X_MASK,
                        (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
                        (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
                        (spi->mode & SPI_3WIRE) ? "3wire, " : "",
@@ -3453,79 +3557,6 @@ int spi_setup(struct spi_device *spi)
 }
 EXPORT_SYMBOL_GPL(spi_setup);
 
-/**
- * spi_set_cs_timing - configure CS setup, hold, and inactive delays
- * @spi: the device that requires specific CS timing configuration
- * @setup: CS setup time specified via @spi_delay
- * @hold: CS hold time specified via @spi_delay
- * @inactive: CS inactive delay between transfers specified via @spi_delay
- *
- * Return: zero on success, else a negative error code.
- */
-int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
-                     struct spi_delay *hold, struct spi_delay *inactive)
-{
-       struct device *parent = spi->controller->dev.parent;
-       size_t len;
-       int status;
-
-       if (spi->controller->set_cs_timing &&
-           !(spi->cs_gpiod || gpio_is_valid(spi->cs_gpio))) {
-               mutex_lock(&spi->controller->io_mutex);
-
-               if (spi->controller->auto_runtime_pm) {
-                       status = pm_runtime_get_sync(parent);
-                       if (status < 0) {
-                               mutex_unlock(&spi->controller->io_mutex);
-                               pm_runtime_put_noidle(parent);
-                               dev_err(&spi->controller->dev, "Failed to power device: %d\n",
-                                       status);
-                               return status;
-                       }
-
-                       status = spi->controller->set_cs_timing(spi, setup,
-                                                               hold, inactive);
-                       pm_runtime_mark_last_busy(parent);
-                       pm_runtime_put_autosuspend(parent);
-               } else {
-                       status = spi->controller->set_cs_timing(spi, setup, hold,
-                                                             inactive);
-               }
-
-               mutex_unlock(&spi->controller->io_mutex);
-               return status;
-       }
-
-       if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) ||
-           (hold && hold->unit == SPI_DELAY_UNIT_SCK) ||
-           (inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) {
-               dev_err(&spi->dev,
-                       "Clock-cycle delays for CS not supported in SW mode\n");
-               return -ENOTSUPP;
-       }
-
-       len = sizeof(struct spi_delay);
-
-       /* copy delays to controller */
-       if (setup)
-               memcpy(&spi->controller->cs_setup, setup, len);
-       else
-               memset(&spi->controller->cs_setup, 0, len);
-
-       if (hold)
-               memcpy(&spi->controller->cs_hold, hold, len);
-       else
-               memset(&spi->controller->cs_hold, 0, len);
-
-       if (inactive)
-               memcpy(&spi->controller->cs_inactive, inactive, len);
-       else
-               memset(&spi->controller->cs_inactive, 0, len);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(spi_set_cs_timing);
-
 static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
                                       struct spi_device *spi)
 {
index f56e0e9..24e9469 100644 (file)
@@ -59,7 +59,7 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
  *
  * REVISIT should changing those flags be privileged?
  */
-#define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
+#define SPI_MODE_MASK          (SPI_MODE_X_MASK | SPI_CS_HIGH \
                                | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
                                | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
                                | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
index ca59986..e3aaae9 100644 (file)
@@ -42,4 +42,6 @@ source "drivers/staging/media/tegra-video/Kconfig"
 
 source "drivers/staging/media/ipu3/Kconfig"
 
+source "drivers/staging/media/av7110/Kconfig"
+
 endif
index 716929a..5b5afc5 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_TEGRA_VDE)               += tegra-vde/
 obj-$(CONFIG_VIDEO_HANTRO)     += hantro/
 obj-$(CONFIG_VIDEO_IPU3_IMGU)  += ipu3/
 obj-$(CONFIG_VIDEO_ZORAN)      += zoran/
+obj-$(CONFIG_DVB_AV7110)       += av7110/
index 51498b2..606b775 100644 (file)
@@ -16,7 +16,6 @@ atomisp-objs += \
        pci/atomisp_acc.o \
        pci/atomisp_cmd.o \
        pci/atomisp_compat_css20.o \
-       pci/atomisp_compat_ioctl32.o \
        pci/atomisp_csi2.o \
        pci/atomisp_drvfs.o \
        pci/atomisp_file.o \
index 6987bb2..2d1ef9e 100644 (file)
@@ -120,6 +120,11 @@ TODO
     for this driver until the other work is done, as there will be a lot
     of code churn until this driver becomes functional again.
 
+16. Fix private ioctls to not need a compat_ioctl handler for running
+    32-bit tasks. The compat code has been removed because of bugs,
+    and should not be needed for modern drivers. Fixing this properly
+    unfortunately means an incompatible ABI change.
+
 Limitations
 ===========
 
index d170d0a..687888d 100644 (file)
@@ -300,7 +300,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
        /* pixel clock calculattion */
        dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
        buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
-       pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
+       dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
 
        /* get integration time */
        buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
@@ -326,7 +326,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
        if (ret)
                return ret;
        buf->crop_horizontal_start = val | (reg_val & 0xFF);
-       pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start);
+       dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start);
 
        /* Getting crop_vertical_start */
        ret =  gc0310_read_reg(client, GC0310_8BIT,
@@ -339,7 +339,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
        if (ret)
                return ret;
        buf->crop_vertical_start = val | (reg_val & 0xFF);
-       pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start);
+       dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start);
 
        /* Getting output_width */
        ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -352,7 +352,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
        if (ret)
                return ret;
        buf->output_width = val | (reg_val & 0xFF);
-       pr_info("output_width=%d\n", buf->output_width);
+       dev_dbg(&client->dev, "output_width=%d\n", buf->output_width);
 
        /* Getting output_height */
        ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -365,12 +365,12 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
        if (ret)
                return ret;
        buf->output_height = val | (reg_val & 0xFF);
-       pr_info("output_height=%d\n", buf->output_height);
+       dev_dbg(&client->dev, "output_height=%d\n", buf->output_height);
 
        buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
        buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
-       pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end);
-       pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end);
+       dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end);
+       dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end);
 
        /* Getting line_length_pck */
        ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -389,7 +389,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
                return ret;
        sh_delay = reg_val;
        buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
-       pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
+       dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
                sh_delay, buf->line_length_pck);
 
        /* Getting frame_length_lines */
@@ -404,7 +404,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
                return ret;
        vert_blanking = val | (reg_val & 0xFF);
        buf->frame_length_lines = buf->output_height + vert_blanking;
-       pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
+       dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
                buf->frame_length_lines);
 
        buf->binning_factor_x = res->bin_factor_x ?
@@ -434,7 +434,7 @@ static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
                dgain = gain / 2;
        }
 
-       pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
+       dev_dbg(&client->dev, "gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
 
        /* set analog gain */
        ret = gc0310_write_reg(client, GC0310_8BIT,
@@ -458,7 +458,7 @@ static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
-       pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
+       dev_dbg(&client->dev, "coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
 
        /* set exposure */
        ret = gc0310_write_reg(client, GC0310_8BIT,
@@ -718,7 +718,6 @@ static int gc0310_init(struct v4l2_subdev *sd)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct gc0310_device *dev = to_gc0310_sensor(sd);
 
-       pr_info("%s S\n", __func__);
        mutex_lock(&dev->input_lock);
 
        /* set initial registers */
@@ -730,7 +729,6 @@ static int gc0310_init(struct v4l2_subdev *sd)
 
        mutex_unlock(&dev->input_lock);
 
-       pr_info("%s E\n", __func__);
        return ret;
 }
 
@@ -796,7 +794,6 @@ static int power_up(struct v4l2_subdev *sd)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
-       pr_info("%s S\n", __func__);
        if (!dev->platform_data) {
                dev_err(&client->dev,
                        "no camera_sensor_platform_data");
@@ -823,7 +820,6 @@ static int power_up(struct v4l2_subdev *sd)
 
        msleep(100);
 
-       pr_info("%s E\n", __func__);
        return 0;
 
 fail_gpio:
@@ -959,20 +955,17 @@ static int startup(struct v4l2_subdev *sd)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret = 0;
 
-       pr_info("%s S\n", __func__);
-
        ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs);
        if (ret) {
                dev_err(&client->dev, "gc0310 write register err.\n");
                return ret;
        }
 
-       pr_info("%s E\n", __func__);
        return ret;
 }
 
 static int gc0310_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -982,8 +975,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
        int ret = 0;
        int idx = 0;
 
-       pr_info("%s S\n", __func__);
-
        if (format->pad)
                return -EINVAL;
 
@@ -1008,7 +999,7 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
        fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
 
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                mutex_unlock(&dev->input_lock);
                return 0;
        }
@@ -1020,8 +1011,8 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
                return -EINVAL;
        }
 
-       printk("%s: before gc0310_write_reg_array %s\n", __func__,
-              gc0310_res[dev->fmt_idx].desc);
+       dev_dbg(&client->dev, "%s: before gc0310_write_reg_array %s\n",
+               __func__, gc0310_res[dev->fmt_idx].desc);
        ret = startup(sd);
        if (ret) {
                dev_err(&client->dev, "gc0310 startup err\n");
@@ -1035,14 +1026,13 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
                goto err;
        }
 
-       pr_info("%s E\n", __func__);
 err:
        mutex_unlock(&dev->input_lock);
        return ret;
 }
 
 static int gc0310_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1068,7 +1058,6 @@ static int gc0310_detect(struct i2c_client *client)
        int ret;
        u16 id;
 
-       pr_info("%s S\n", __func__);
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
@@ -1085,7 +1074,7 @@ static int gc0310_detect(struct i2c_client *client)
                return -ENODEV;
        }
        id = ((((u16)high) << 8) | (u16)low);
-       pr_info("sensor ID = 0x%x\n", id);
+       dev_dbg(&client->dev, "sensor ID = 0x%x\n", id);
 
        if (id != GC0310_ID) {
                dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id,
@@ -1095,8 +1084,6 @@ static int gc0310_detect(struct i2c_client *client)
 
        dev_dbg(&client->dev, "detect gc0310 success\n");
 
-       pr_info("%s E\n", __func__);
-
        return 0;
 }
 
@@ -1106,7 +1093,7 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret;
 
-       pr_info("%s S enable=%d\n", __func__, enable);
+       dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable);
        mutex_lock(&dev->input_lock);
 
        if (enable) {
@@ -1142,7 +1129,6 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
        }
 
        mutex_unlock(&dev->input_lock);
-       pr_info("%s E\n", __func__);
        return ret;
 }
 
@@ -1153,7 +1139,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret = 0;
 
-       pr_info("%s S\n", __func__);
        if (!platform_data)
                return -ENODEV;
 
@@ -1196,7 +1181,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
        }
        mutex_unlock(&dev->input_lock);
 
-       pr_info("%s E\n", __func__);
        return 0;
 
 fail_csi_cfg:
@@ -1221,7 +1205,7 @@ static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= MAX_FMTS)
@@ -1232,7 +1216,7 @@ static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int gc0310_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
@@ -1365,7 +1349,6 @@ static int gc0310_probe(struct i2c_client *client)
        if (ret)
                gc0310_remove(client);
 
-       pr_info("%s E\n", __func__);
        return ret;
 out_free:
        v4l2_device_unregister_subdev(&dev->sd);
index 78147ff..9363c1a 100644 (file)
@@ -171,8 +171,8 @@ static int __gc2235_buf_reg_array(struct i2c_client *client,
 }
 
 static int __gc2235_write_reg_is_consecutive(struct i2c_client *client,
-       struct gc2235_write_ctrl *ctrl,
-       const struct gc2235_reg *next)
+                                            struct gc2235_write_ctrl *ctrl,
+                                            const struct gc2235_reg *next)
 {
        if (ctrl->index == 0)
                return 1;
@@ -228,7 +228,7 @@ static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
 
 static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
 {
-       /*const f number for imx*/
+       /* const f number for imx */
        *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
        return 0;
 }
@@ -427,7 +427,8 @@ static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        return 0;
 }
 
-/* This returns the exposure time being used. This should only be used
+/*
+ * This returns the exposure time being used. This should only be used
  * for filling in EXIF data, not for actual image processing.
  */
 static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value)
@@ -658,9 +659,9 @@ static int gc2235_s_power(struct v4l2_subdev *sd, int on)
 {
        int ret;
 
-       if (on == 0)
+       if (on == 0) {
                ret = power_down(sd);
-       else {
+       else {
                ret = power_up(sd);
                if (!ret)
                        ret = __gc2235_init(sd);
@@ -746,11 +747,12 @@ static int startup(struct v4l2_subdev *sd)
        int ret = 0;
 
        if (is_init == 0) {
-               /* force gc2235 to do a reset in res change, otherwise it
-               * can not output normal after switching res. and it is not
-               * necessary for first time run up after power on, for the sack
-               * of performance
-               */
+               /*
+                * force gc2235 to do a reset in res change, otherwise it
+                * can not output normal after switching res. and it is not
+                * necessary for first time run up after power on, for the sack
+                * of performance
+                */
                power_down(sd);
                power_up(sd);
                gc2235_write_reg_array(client, gc2235_init_settings);
@@ -767,7 +769,7 @@ static int startup(struct v4l2_subdev *sd)
 }
 
 static int gc2235_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -796,7 +798,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
        }
        fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                mutex_unlock(&dev->input_lock);
                return 0;
        }
@@ -825,7 +827,7 @@ err:
 }
 
 static int gc2235_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -904,7 +906,8 @@ static int gc2235_s_config(struct v4l2_subdev *sd,
            (struct camera_sensor_platform_data *)platform_data;
 
        mutex_lock(&dev->input_lock);
-       /* power off the module, then power on it in future
+       /*
+        * power off the module, then power on it in future
         * as first power on by board may not fulfill the
         * power on sequqence needed by the module
         */
@@ -963,7 +966,7 @@ static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= MAX_FMTS)
@@ -974,7 +977,7 @@ static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int gc2235_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
index b93c804..7a20d91 100644 (file)
@@ -50,14 +50,16 @@ struct tbd_data_record_header {
 static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr,
                                 unsigned int size)
 {
-       /* The configuration data contains any number of sequences where
+       /*
+        * The configuration data contains any number of sequences where
         * the first byte (that is, uint8_t) that marks the number of bytes
         * in the sequence to follow, is indeed followed by the indicated
         * number of bytes of actual data to be written to sensor.
         * By convention, the first two bytes of actual data should be
         * understood as an address in the sensor address space (hibyte
         * followed by lobyte) where the remaining data in the sequence
-        * will be written. */
+        * will be written.
+        */
 
        u8 *ptr = bufptr;
 
index f5de811..1119618 100644 (file)
@@ -475,10 +475,12 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
        if (!dev || !dev->platform_data)
                return -ENODEV;
 
-       /* Note: current modules wire only one GPIO signal (RESET#),
+       /*
+        * Note: current modules wire only one GPIO signal (RESET#),
         * but the schematic wires up two to the connector.  BIOS
         * versions have been unfortunately inconsistent with which
-        * ACPI index RESET# is on, so hit both */
+        * ACPI index RESET# is on, so hit both
+        */
 
        if (flag) {
                ret = dev->platform_data->gpio0_ctrl(sd, 0);
@@ -560,7 +562,7 @@ static int power_down(struct v4l2_subdev *sd)
        if (ret)
                dev_err(&client->dev, "vprog failed.\n");
 
-       /*according to DS, 20ms is needed after power down*/
+       /* according to DS, 20ms is needed after power down */
        msleep(20);
 
        return ret;
@@ -568,9 +570,9 @@ static int power_down(struct v4l2_subdev *sd)
 
 static int mt9m114_s_power(struct v4l2_subdev *sd, int power)
 {
-       if (power == 0)
+       if (power == 0) {
                return power_down(sd);
-       else {
+       else {
                if (power_up(sd))
                        return -EINVAL;
 
@@ -801,7 +803,7 @@ static int mt9m114_get_intg_factor(struct i2c_client *client,
 }
 
 static int mt9m114_get_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -822,7 +824,7 @@ static int mt9m114_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int mt9m114_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -846,7 +848,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
 
        mt9m114_try_res(&width, &height);
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                return 0;
        }
        res_index = mt9m114_to_res(width, height);
@@ -947,7 +949,7 @@ static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
 
 static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
 {
-       /*const f number for mt9m114*/
+       /* const f number for mt9m114 */
        *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
        return 0;
 }
@@ -998,44 +1000,48 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd,
        struct mt9m114_device *dev = to_mt9m114_sensor(sd);
        int ret = 0;
        unsigned int coarse_integration = 0;
-       unsigned int FLines = 0;
-       unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */
-       unsigned int AnalogGain, DigitalGain;
-       u32 AnalogGainToWrite = 0;
+       unsigned int f_lines = 0;
+       unsigned int frame_len_lines = 0; /* ExposureTime.FrameLengthLines; */
+       unsigned int analog_gain, digital_gain;
+       u32 analog_gain_to_write = 0;
 
        dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__,
                exposure->integration_time[0], exposure->gain[0],
                exposure->gain[1]);
 
        coarse_integration = exposure->integration_time[0];
-       /* fine_integration = ExposureTime.FineIntegrationTime; */
-       /* FrameLengthLines = ExposureTime.FrameLengthLines; */
-       FLines = mt9m114_res[dev->res].lines_per_frame;
-       AnalogGain = exposure->gain[0];
-       DigitalGain = exposure->gain[1];
+       /*
+        * fine_integration = ExposureTime.FineIntegrationTime;
+        * frame_len_lines = ExposureTime.FrameLengthLines;
+        */
+       f_lines = mt9m114_res[dev->res].lines_per_frame;
+       analog_gain = exposure->gain[0];
+       digital_gain = exposure->gain[1];
        if (!dev->streamon) {
                /*Save the first exposure values while stream is off*/
                dev->first_exp = coarse_integration;
-               dev->first_gain = AnalogGain;
-               dev->first_diggain = DigitalGain;
+               dev->first_gain = analog_gain;
+               dev->first_diggain = digital_gain;
        }
-       /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) +
-       ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */
+       /* digital_gain = 0x400 * (((u16) digital_gain) >> 8) +         */
+       /* ((unsigned int)(0x400 * (((u16) digital_gain) & 0xFF)) >>8); */
 
        /* set frame length */
-       if (FLines < coarse_integration + 6)
-               FLines = coarse_integration + 6;
-       if (FLines < FrameLengthLines)
-               FLines = FrameLengthLines;
-       ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines);
+       if (f_lines < coarse_integration + 6)
+               f_lines = coarse_integration + 6;
+       if (f_lines < frame_len_lines)
+               f_lines = frame_len_lines;
+       ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, f_lines);
        if (ret) {
-               v4l2_err(client, "%s: fail to set FLines\n", __func__);
+               v4l2_err(client, "%s: fail to set f_lines\n", __func__);
                return -EINVAL;
        }
 
        /* set coarse integration */
-       /* 3A provide real exposure time.
-               should not translate to any value here. */
+       /*
+        * 3A provide real exposure time.
+        * should not translate to any value here.
+        */
        ret = mt9m114_write_reg(client, MISENSOR_16BIT,
                                REG_EXPO_COARSE, (u16)(coarse_integration));
        if (ret) {
@@ -1044,38 +1050,40 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd,
        }
 
        /*
-       // set analog/digital gain
-       switch(AnalogGain)
+        * set analog/digital gain
+       switch(analog_gain)
        {
        case 0:
-         AnalogGainToWrite = 0x0;
+         analog_gain_to_write = 0x0;
          break;
        case 1:
-         AnalogGainToWrite = 0x20;
+         analog_gain_to_write = 0x20;
          break;
        case 2:
-         AnalogGainToWrite = 0x60;
+         analog_gain_to_write = 0x60;
          break;
        case 4:
-         AnalogGainToWrite = 0xA0;
+         analog_gain_to_write = 0xA0;
          break;
        case 8:
-         AnalogGainToWrite = 0xE0;
+         analog_gain_to_write = 0xE0;
          break;
        default:
-         AnalogGainToWrite = 0x20;
+         analog_gain_to_write = 0x20;
          break;
        }
        */
-       if (DigitalGain >= 16 || DigitalGain <= 1)
-               DigitalGain = 1;
-       /* AnalogGainToWrite =
-               (u16)((DigitalGain << 12) | AnalogGainToWrite); */
-       AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain);
+       if (digital_gain >= 16 || digital_gain <= 1)
+               digital_gain = 1;
+       /*
+        * analog_gain_to_write = (u16)((digital_gain << 12)
+        *                              | analog_gain_to_write);
+        */
+       analog_gain_to_write = (u16)((digital_gain << 12) | (u16)analog_gain);
        ret = mt9m114_write_reg(client, MISENSOR_16BIT,
-                               REG_GAIN, AnalogGainToWrite);
+                               REG_GAIN, analog_gain_to_write);
        if (ret) {
-               v4l2_err(client, "%s: fail to set AnalogGainToWrite\n",
+               v4l2_err(client, "%s: fail to set analog_gain_to_write\n",
                         __func__);
                return -EINVAL;
        }
@@ -1095,8 +1103,10 @@ static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        return 0;
 }
 
-/* This returns the exposure time being used. This should only be used
-   for filling in EXIF data, not for actual image processing. */
+/*
+ * This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
 static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1158,7 +1168,7 @@ static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val)
  * This function is for touch exposure feature.
  */
 static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd,
-                                       struct v4l2_subdev_pad_config *cfg,
+                                       struct v4l2_subdev_state *sd_state,
                                        struct v4l2_subdev_selection *sel)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1247,7 +1257,8 @@ static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
        s32 luma = 0x37;
        int err;
 
-       /* EV value only support -2 to 2
+       /*
+        * EV value only support -2 to 2
         * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17
         */
        if (val < -2 || val > 2)
@@ -1295,9 +1306,10 @@ static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val)
        return 0;
 }
 
-/* Fake interface
+/*
+ * Fake interface
  * mt9m114 now can not support 3a_lock
-*/
+ */
 static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val)
 {
        aaalock = val;
@@ -1719,7 +1731,7 @@ static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index)
@@ -1730,7 +1742,7 @@ static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int mt9m114_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        unsigned int index = fse->index;
@@ -1843,7 +1855,7 @@ static int mt9m114_probe(struct i2c_client *client)
                return ret;
        }
 
-       /*TODO add format code here*/
+       /* TODO add format code here */
        dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
        dev->pad.flags = MEDIA_PAD_FL_SOURCE;
        dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
index c907305..2111e4a 100644 (file)
@@ -127,7 +127,7 @@ static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
 
 static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
 {
-       /*const f number for ov2680*/
+       /* const f number for ov2680 */
 
        *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
        return 0;
@@ -399,7 +399,8 @@ static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        return 0;
 }
 
-/* This returns the exposure time being used. This should only be used
+/*
+ * This returns the exposure time being used. This should only be used
  * for filling in EXIF data, not for actual image processing.
  */
 static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
@@ -461,11 +462,11 @@ static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
        ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val);
        if (ret)
                return ret;
-       if (value) {
+       if (value)
                val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
-       } else {
+       else
                val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
-       }
+
        ret = ov2680_write_reg(client, 1,
                               OV2680_FLIP_REG, val);
        if (ret)
@@ -727,11 +728,13 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
        if (!dev || !dev->platform_data)
                return -ENODEV;
 
-       /* The OV2680 documents only one GPIO input (#XSHUTDN), but
+       /*
+        * The OV2680 documents only one GPIO input (#XSHUTDN), but
         * existing integrations often wire two (reset/power_down)
         * because that is the way other sensors work.  There is no
         * way to tell how it is wired internally, so existing
-        * firmwares expose both and we drive them symmetrically. */
+        * firmwares expose both and we drive them symmetrically.
+        */
        if (flag) {
                ret = dev->platform_data->gpio0_ctrl(sd, 1);
                usleep_range(10000, 15000);
@@ -911,7 +914,7 @@ static int get_resolution_index(int w, int h)
 }
 
 static int ov2680_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -948,7 +951,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
        }
        fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                mutex_unlock(&dev->input_lock);
                return 0;
        }
@@ -977,7 +980,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
                goto err;
        }
 
-       /*recall flip functions to avoid flip registers
+       /*
+        * recall flip functions to avoid flip registers
         * were overridden by default setting
         */
        if (h_flag)
@@ -987,7 +991,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
 
        v4l2_info(client, "\n%s idx %d\n", __func__, dev->fmt_idx);
 
-       /*ret = startup(sd);
+       /*
+        * ret = startup(sd);
         * if (ret)
         * dev_err(&client->dev, "ov2680 startup err\n");
         */
@@ -997,7 +1002,7 @@ err:
 }
 
 static int ov2680_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1096,7 +1101,8 @@ static int ov2680_s_config(struct v4l2_subdev *sd,
            (struct camera_sensor_platform_data *)platform_data;
 
        mutex_lock(&dev->input_lock);
-       /* power off the module, then power on it in future
+       /*
+        * power off the module, then power on it in future
         * as first power on by board may not fulfill the
         * power on sequqence needed by the module
         */
@@ -1155,7 +1161,7 @@ static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= MAX_FMTS)
@@ -1166,7 +1172,7 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
index 1209492..90d0871 100644 (file)
@@ -49,8 +49,8 @@ static int ov2722_read_reg(struct i2c_client *client,
                return -ENODEV;
        }
 
-       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT
-           && data_length != OV2722_32BIT) {
+       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT &&
+           data_length != OV2722_32BIT) {
                dev_err(&client->dev, "%s error, invalid data length\n",
                        __func__);
                return -EINVAL;
@@ -212,8 +212,8 @@ static int __ov2722_buf_reg_array(struct i2c_client *client,
 }
 
 static int __ov2722_write_reg_is_consecutive(struct i2c_client *client,
-       struct ov2722_write_ctrl *ctrl,
-       const struct ov2722_reg *next)
+                                            struct ov2722_write_ctrl *ctrl,
+                                            const struct ov2722_reg *next)
 {
        if (ctrl->index == 0)
                return 1;
@@ -774,11 +774,11 @@ static int ov2722_s_power(struct v4l2_subdev *sd, int on)
 
        if (on == 0)
                return power_down(sd);
-       else {
-               ret = power_up(sd);
-               if (!ret)
-                       return ov2722_init(sd);
-       }
+
+       ret = power_up(sd);
+       if (!ret)
+               return ov2722_init(sd);
+
        return ret;
 }
 
@@ -876,7 +876,7 @@ static int startup(struct v4l2_subdev *sd)
 }
 
 static int ov2722_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -906,7 +906,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
        }
        fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                mutex_unlock(&dev->input_lock);
                return 0;
        }
@@ -961,7 +961,7 @@ err:
 }
 
 static int ov2722_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1104,7 +1104,7 @@ static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= MAX_FMTS)
@@ -1115,7 +1115,7 @@ static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov2722_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
index 787bbf5..bcce18b 100644 (file)
@@ -764,8 +764,10 @@ static struct misensor_reg const mt9m114_common[] = {
        {MISENSOR_8BIT, 0xC85C, 0x03},    /* cam_crop_cropmode = 3 */
        {MISENSOR_16BIT, 0xC868, 0x0280}, /* cam_output_width = 952 */
        {MISENSOR_16BIT, 0xC86A, 0x01E0}, /* cam_output_height = 538 */
-       /* LOAD = Step3-Recommended
-        * Patch,Errata and Sensor optimization Setting */
+       /*
+        * LOAD = Step3-Recommended
+        * Patch, Errata and Sensor optimization Setting
+        */
        {MISENSOR_16BIT, 0x316A, 0x8270}, /* DAC_TXLO_ROW */
        {MISENSOR_16BIT, 0x316C, 0x8270}, /* DAC_TXLO */
        {MISENSOR_16BIT, 0x3ED0, 0x2305}, /* DAC_LD_4_5 */
index 4992024..4d43b45 100644 (file)
@@ -459,8 +459,8 @@ static struct ov2680_reg const ov2680_656x496_30fps[] = {
 };
 
 /*
-* 800x600 30fps  VBlanking 1lane 10Bit (binning)
-*/
+ * 800x600 30fps  VBlanking 1lane 10Bit (binning)
+ */
 static struct ov2680_reg const ov2680_720x592_30fps[] = {
        {0x3086, 0x01},
        {0x3501, 0x26},
@@ -504,8 +504,8 @@ static struct ov2680_reg const ov2680_720x592_30fps[] = {
 };
 
 /*
-* 800x600 30fps  VBlanking 1lane 10Bit (binning)
-*/
+ * 800x600 30fps  VBlanking 1lane 10Bit (binning)
+ */
 static struct ov2680_reg const ov2680_800x600_30fps[] = {
        {0x3086, 0x01},
        {0x3501, 0x26},
@@ -634,7 +634,7 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = {
 
 /*
  *   1456*1096 30fps  VBlanking 1lane 10bit(no-scaling)
-*/
+ */
 static struct ov2680_reg const ov2680_1456x1096_30fps[] = {
        {0x3086, 0x00},
        {0x3501, 0x48},
index e698b63..0828ca9 100644 (file)
@@ -1577,7 +1577,7 @@ static int startup(struct v4l2_subdev *sd)
 }
 
 static int ov5693_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1608,7 +1608,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
 
        fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                mutex_unlock(&dev->input_lock);
                return 0;
        }
@@ -1676,7 +1676,7 @@ err:
 }
 
 static int ov5693_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1825,7 +1825,7 @@ static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
 }
 
 static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= MAX_FMTS)
@@ -1836,7 +1836,7 @@ static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        int index = fse->index;
index f638d0b..9a17518 100644 (file)
@@ -77,8 +77,8 @@ acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle)
        struct atomisp_acc_fw *acc_fw;
 
        list_for_each_entry(acc_fw, &asd->acc.fw, list)
-       if (acc_fw->handle == handle)
-               return acc_fw;
+               if (acc_fw->handle == handle)
+                       return acc_fw;
 
        return NULL;
 }
@@ -464,9 +464,11 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd)
                        continue;
 
                for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
-                       /* QoS (ACC pipe) acceleration stages are currently
-                        * allowed only in continuous mode. Skip them for
-                        * all other modes. */
+                       /*
+                        * QoS (ACC pipe) acceleration stages are
+                        * currently allowed only in continuous mode.
+                        * Skip them for all other modes.
+                        */
                        if (!continuous &&
                            acc_flag_to_pipe[i].flag ==
                            ATOMISP_ACC_FW_LOAD_FL_ACC)
index 14abc1c..366161c 100644 (file)
@@ -1138,9 +1138,10 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
                                        asd->frame_status[vb->i] =
                                            ATOMISP_FRAME_STATUS_OK;
                                }
-                       } else
+                       } else {
                                asd->frame_status[vb->i] =
                                    ATOMISP_FRAME_STATUS_OK;
+                       }
                } else {
                        asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK;
                }
@@ -4841,6 +4842,9 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
        struct atomisp_device *isp = video_get_drvdata(vdev);
        struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format format = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -4876,7 +4880,7 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
                snr_mbus_fmt->width, snr_mbus_fmt->height);
 
        ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
-                              pad, set_fmt, &pad_cfg, &format);
+                              pad, set_fmt, &pad_state, &format);
        if (ret)
                return ret;
 
@@ -4941,9 +4945,9 @@ atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f)
 
        depth = get_pixel_depth(pixelformat);
 
-       if (field == V4L2_FIELD_ANY)
+       if (field == V4L2_FIELD_ANY) {
                field = V4L2_FIELD_NONE;
-       else if (field != V4L2_FIELD_NONE) {
+       else if (field != V4L2_FIELD_NONE) {
                dev_err(isp->dev, "Wrong output field\n");
                return -EINVAL;
        }
@@ -5251,11 +5255,11 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev,
                   atomisp_output_fmts[] in atomisp_v4l2.c */
                vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420;
 
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             ATOMISP_SUBDEV_PAD_SOURCE_VF,
                                             V4L2_SEL_TGT_COMPOSE, 0, &vf_size);
-               atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+               atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
                                        V4L2_SUBDEV_FORMAT_ACTIVE,
                                        ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt);
                asd->video_out_vf.sh_fmt = IA_CSS_FRAME_FORMAT_NV12;
@@ -5492,6 +5496,9 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
        struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
        const struct atomisp_format_bridge *format;
        struct v4l2_subdev_pad_config pad_cfg;
+       struct v4l2_subdev_state pad_state = {
+               .pads = &pad_cfg
+               };
        struct v4l2_subdev_format vformat = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -5530,7 +5537,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
            source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
                vformat.which = V4L2_SUBDEV_FORMAT_TRY;
                ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
-                                      pad, set_fmt, &pad_cfg, &vformat);
+                                      pad, set_fmt, &pad_state, &vformat);
                if (ret)
                        return ret;
                if (ffmt->width < req_ffmt->width ||
@@ -5568,7 +5575,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
                asd->params.video_dis_en = false;
        }
 
-       atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+       atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
                                V4L2_SUBDEV_FORMAT_ACTIVE,
                                ATOMISP_SUBDEV_PAD_SINK, ffmt);
 
@@ -5647,7 +5654,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
                        }
 
                        atomisp_subdev_set_selection(
-                           &asd->subdev, fh.pad,
+                           &asd->subdev, fh.state,
                            V4L2_SUBDEV_FORMAT_ACTIVE, source_pad,
                            V4L2_SEL_TGT_COMPOSE, 0, &r);
 
@@ -5777,7 +5784,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
                                                ATOMISP_SUBDEV_PAD_SINK);
 
        isp_source_fmt.code = format_bridge->mbus_code;
-       atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+       atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
                                V4L2_SUBDEV_FORMAT_ACTIVE,
                                source_pad, &isp_source_fmt);
 
@@ -5896,13 +5903,13 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
                        isp_sink_crop.height = f->fmt.pix.height;
                }
 
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             ATOMISP_SUBDEV_PAD_SINK,
                                             V4L2_SEL_TGT_CROP,
                                             V4L2_SEL_FLAG_KEEP_CONFIG,
                                             &isp_sink_crop);
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             source_pad, V4L2_SEL_TGT_COMPOSE,
                                             0, &isp_sink_crop);
@@ -5921,7 +5928,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
                                         f->fmt.pix.height);
                }
 
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             source_pad,
                                             V4L2_SEL_TGT_COMPOSE, 0,
@@ -5955,14 +5962,14 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
                                                       f->fmt.pix.width,
                                                       ATOM_ISP_STEP_HEIGHT);
                        }
-                       atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+                       atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                                     V4L2_SUBDEV_FORMAT_ACTIVE,
                                                     ATOMISP_SUBDEV_PAD_SINK,
                                                     V4L2_SEL_TGT_CROP,
                                                     V4L2_SEL_FLAG_KEEP_CONFIG,
                                                     &sink_crop);
                }
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             source_pad,
                                             V4L2_SEL_TGT_COMPOSE, 0,
@@ -6053,7 +6060,8 @@ int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f)
        ffmt.height = f->fmt.pix.height;
        ffmt.code = format_bridge->mbus_code;
 
-       atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, V4L2_SUBDEV_FORMAT_ACTIVE,
+       atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
+                               V4L2_SUBDEV_FORMAT_ACTIVE,
                                ATOMISP_SUBDEV_PAD_SINK, &ffmt);
 
        return 0;
@@ -6564,17 +6572,17 @@ static int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe)
 {
        struct atomisp_sub_device *asd = pipe->asd;
 
-       if (ATOMISP_USE_YUVPP(asd))
+       if (ATOMISP_USE_YUVPP(asd)) {
                return IA_CSS_PIPE_ID_YUVPP;
-       else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER)
+       } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
                return IA_CSS_PIPE_ID_VIDEO;
-       else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT)
+       } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
                return IA_CSS_PIPE_ID_CAPTURE;
-       else if (pipe == &asd->video_out_video_capture)
+       } else if (pipe == &asd->video_out_video_capture) {
                return IA_CSS_PIPE_ID_VIDEO;
-       else if (pipe == &asd->video_out_vf)
+       } else if (pipe == &asd->video_out_vf) {
                return IA_CSS_PIPE_ID_CAPTURE;
-       else if (pipe == &asd->video_out_preview) {
+       else if (pipe == &asd->video_out_preview) {
                if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
                        return IA_CSS_PIPE_ID_VIDEO;
                else
index 412baeb..e8bdd26 100644 (file)
@@ -49,9 +49,7 @@ struct ia_css_frame;
 /* FIXME: check if can go */
 extern int atomisp_punit_hpll_freq;
 
-/*
- * Helper function
- */
+/* Helper function */
 void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
                  unsigned int size);
 struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd);
@@ -65,9 +63,7 @@ bool atomisp_buffers_queued(struct atomisp_sub_device *asd);
 /* ISP2401 */
 bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe);
 
-/*
- * Interrupt functions
- */
+/* Interrupt functions */
 void atomisp_msi_irq_init(struct atomisp_device *isp);
 void atomisp_msi_irq_uninit(struct atomisp_device *isp);
 void atomisp_wdt_work(struct work_struct *work);
@@ -82,15 +78,10 @@ int atomisp_get_frame_pgnr(struct atomisp_device *isp,
                           const struct ia_css_frame *frame, u32 *p_pgnr);
 void atomisp_delayed_init_work(struct work_struct *work);
 
-/*
- * Get internal fmt according to V4L2 fmt
- */
-
+/* Get internal fmt according to V4L2 fmt */
 bool atomisp_is_viewfinder_support(struct atomisp_device *isp);
 
-/*
- * ISP features control function
- */
+/* ISP features control function */
 
 /*
  * Function to set sensor runmode by user when
@@ -105,9 +96,7 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
 int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
                    __s32 *value);
 
-/*
- * Function to enable/disable low light mode (including ANR)
- */
+/* Function to enable/disable low light mode (including ANR) */
 int atomisp_low_light(struct atomisp_sub_device *asd, int flag,
                      __s32 *value);
 
@@ -120,91 +109,63 @@ int atomisp_xnr(struct atomisp_sub_device *asd, int flag, int *arg);
 int atomisp_formats(struct atomisp_sub_device *asd, int flag,
                    struct atomisp_formats_config *config);
 
-/*
- * Function to configure noise reduction
- */
+/* Function to configure noise reduction */
 int atomisp_nr(struct atomisp_sub_device *asd, int flag,
               struct atomisp_nr_config *config);
 
-/*
- * Function to configure temporal noise reduction (TNR)
- */
+/* Function to configure temporal noise reduction (TNR) */
 int atomisp_tnr(struct atomisp_sub_device *asd, int flag,
                struct atomisp_tnr_config *config);
 
-/*
- * Function to configure black level compensation
- */
+/* Function to configure black level compensation */
 int atomisp_black_level(struct atomisp_sub_device *asd, int flag,
                        struct atomisp_ob_config *config);
 
-/*
- * Function to configure edge enhancement
- */
+/* Function to configure edge enhancement */
 int atomisp_ee(struct atomisp_sub_device *asd, int flag,
               struct atomisp_ee_config *config);
 
-/*
- * Function to update Gamma table for gamma, brightness and contrast config
- */
+/* Function to update Gamma table for gamma, brightness and contrast config */
 int atomisp_gamma(struct atomisp_sub_device *asd, int flag,
                  struct atomisp_gamma_table *config);
-/*
- * Function to update Ctc table for Chroma Enhancement
- */
+
+/* Function to update Ctc table for Chroma Enhancement */
 int atomisp_ctc(struct atomisp_sub_device *asd, int flag,
                struct atomisp_ctc_table *config);
 
-/*
- * Function to update gamma correction parameters
- */
+/* Function to update gamma correction parameters */
 int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag,
                             struct atomisp_gc_config *config);
 
-/*
- * Function to update Gdc table for gdc
- */
+/* Function to update Gdc table for gdc */
 int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag,
                          struct atomisp_morph_table *config);
 
-/*
- * Function to update table for macc
- */
+/* Function to update table for macc */
 int atomisp_macc_table(struct atomisp_sub_device *asd, int flag,
                       struct atomisp_macc_config *config);
-/*
- * Function to get DIS statistics.
- */
+
+/* Function to get DIS statistics. */
 int atomisp_get_dis_stat(struct atomisp_sub_device *asd,
                         struct atomisp_dis_statistics *stats);
 
-/*
- * Function to get DVS2 BQ resolution settings
- */
+/* Function to get DVS2 BQ resolution settings */
 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd,
                                    struct atomisp_dvs2_bq_resolutions *bq_res);
 
-/*
- * Function to set the DIS coefficients.
- */
+/* Function to set the DIS coefficients. */
 int atomisp_set_dis_coefs(struct atomisp_sub_device *asd,
                          struct atomisp_dis_coefficients *coefs);
 
-/*
- * Function to set the DIS motion vector.
- */
+/* Function to set the DIS motion vector. */
 int atomisp_set_dis_vector(struct atomisp_sub_device *asd,
                           struct atomisp_dis_vector *vector);
 
-/*
- * Function to set/get 3A stat from isp
- */
+/* Function to set/get 3A stat from isp */
 int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag,
                    struct atomisp_3a_statistics *config);
 
-/*
- * Function to get metadata from isp
- */
+/* Function to get metadata from isp */
 int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag,
                         struct atomisp_metadata *config);
 
@@ -213,84 +174,59 @@ int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag,
 
 int atomisp_set_parameters(struct video_device *vdev,
                           struct atomisp_parameters *arg);
-/*
- * Function to set/get isp parameters to isp
- */
+
+/* Function to set/get isp parameters to isp */
 int atomisp_param(struct atomisp_sub_device *asd, int flag,
                  struct atomisp_parm *config);
 
-/*
- * Function to configure color effect of the image
- */
+/* Function to configure color effect of the image */
 int atomisp_color_effect(struct atomisp_sub_device *asd, int flag,
                         __s32 *effect);
 
-/*
- * Function to configure bad pixel correction
- */
+/* Function to configure bad pixel correction */
 int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag,
                      __s32 *value);
 
-/*
- * Function to configure bad pixel correction params
- */
+/* Function to configure bad pixel correction params */
 int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag,
                            struct atomisp_dp_config *config);
 
-/*
- * Function to enable/disable video image stablization
- */
+/* Function to enable/disable video image stablization */
 int atomisp_video_stable(struct atomisp_sub_device *asd, int flag,
                         __s32 *value);
 
-/*
- * Function to configure fixed pattern noise
- */
+/* Function to configure fixed pattern noise */
 int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
                          __s32 *value);
 
-/*
- * Function to configure fixed pattern noise table
- */
+/* Function to configure fixed pattern noise table */
 int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd,
                                struct v4l2_framebuffer *config);
 
-/*
- * Function to configure false color correction
- */
+/* Function to configure false color correction */
 int atomisp_false_color(struct atomisp_sub_device *asd, int flag,
                        __s32 *value);
 
-/*
- * Function to configure false color correction params
- */
+/* Function to configure false color correction params */
 int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag,
                              struct atomisp_de_config *config);
 
-/*
- * Function to configure white balance params
- */
+/* Function to configure white balance params */
 int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag,
                                struct atomisp_wb_config *config);
 
 int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag,
                            struct atomisp_3a_config *config);
 
-/*
- * Function to setup digital zoom
- */
+/* Function to setup digital zoom */
 int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
                         __s32 *value);
 
-/*
- * Function  set camera_prefiles.xml current sensor pixel array size
- */
+/* Function  set camera_prefiles.xml current sensor pixel array size */
 int atomisp_set_array_res(struct atomisp_sub_device *asd,
                          struct atomisp_resolution  *config);
 
-/*
- * Function to calculate real zoom region for every pipe
- */
+/* Function to calculate real zoom region for every pipe */
 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd,
                                       struct ia_css_dz_config   *dz_config,
                                       enum ia_css_pipe_id css_pipe_id);
@@ -371,9 +307,7 @@ void atomisp_css_flush(struct atomisp_device *isp);
 int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd,
                                    uint16_t source_pad);
 
-/*
- * Events. Only one event has to be exported for now.
- */
+/* Events. Only one event has to be exported for now. */
 void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id);
 
 enum mipi_port_id __get_mipi_port(struct atomisp_device *isp,
@@ -389,34 +323,25 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param);
 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe);
 
 void atomisp_flush_params_queue(struct atomisp_video_pipe *asd);
-/*
- * Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer
- */
+
+/* Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer */
 int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id);
 int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id);
 
-/*
- * Function to update Raw Buffer bitmap
- */
+/* Function to update Raw Buffer bitmap */
 int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id);
 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd);
 
-/*
- * Function to enable/disable zoom for capture pipe
- */
+/* Function to enable/disable zoom for capture pipe */
 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd,
                                unsigned int *enable);
 
-/*
- * Function to get metadata type bu pipe id
- */
+/* Function to get metadata type bu pipe id */
 enum atomisp_metadata_type
 atomisp_get_metadata_type(struct atomisp_sub_device *asd,
                          enum ia_css_pipe_id pipe_id);
 
-/*
- * Function for HAL to inject a fake event to wake up poll thread
- */
+/* Function for HAL to inject a fake event to wake up poll thread */
 int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event);
 
 /*
index ce31652..f60198b 100644 (file)
@@ -2782,9 +2782,9 @@ int atomisp_get_css_frame_info(struct atomisp_sub_device *asd,
        int stream_index;
        struct atomisp_device *isp = asd->isp;
 
-       if (ATOMISP_SOC_CAMERA(asd))
+       if (ATOMISP_SOC_CAMERA(asd)) {
                stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
-       else {
+       else {
                stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ?
                               ATOMISP_INPUT_STREAM_VIDEO :
                               atomisp_source_pad_to_stream_id(asd, source_pad);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c
deleted file mode 100644 (file)
index e5553df..0000000
+++ /dev/null
@@ -1,1202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 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.
- *
- *
- */
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-
-#include <linux/videodev2.h>
-
-#include "atomisp_internal.h"
-#include "atomisp_compat.h"
-#include "atomisp_ioctl.h"
-#include "atomisp_compat_ioctl32.h"
-
-/* Macros borrowed from v4l2-compat-ioctl32.c */
-
-#define get_user_cast(__x, __ptr)                                      \
-({                                                                     \
-       get_user(__x, (typeof(*__ptr) __user *)(__ptr));                \
-})
-
-#define put_user_force(__x, __ptr)                                     \
-({                                                                     \
-       put_user((typeof(*__x) __force *)(__x), __ptr);                 \
-})
-
-/* Use the same argument order as copy_in_user */
-#define assign_in_user(to, from)                                       \
-({                                                                     \
-       typeof(*from) __assign_tmp;                                     \
-                                                                       \
-       get_user_cast(__assign_tmp, from) || put_user(__assign_tmp, to);\
-})
-
-static int get_atomisp_histogram32(struct atomisp_histogram __user *kp,
-                                  struct atomisp_histogram32 __user *up)
-{
-       compat_uptr_t tmp;
-
-       if (!access_ok(up, sizeof(struct atomisp_histogram32)) ||
-           assign_in_user(&kp->num_elements, &up->num_elements) ||
-           get_user(tmp, &up->data) ||
-           put_user(compat_ptr(tmp), &kp->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_histogram32(struct atomisp_histogram __user *kp,
-                                  struct atomisp_histogram32 __user *up)
-{
-       void __user *tmp;
-
-       if (!access_ok(up, sizeof(struct atomisp_histogram32)) ||
-           assign_in_user(&up->num_elements, &kp->num_elements) ||
-           get_user(tmp, &kp->data) ||
-           put_user(ptr_to_compat(tmp), &up->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
-                                 struct v4l2_framebuffer32 __user *up)
-{
-       compat_uptr_t tmp;
-
-       if (!access_ok(up, sizeof(struct v4l2_framebuffer32)) ||
-           get_user(tmp, &up->base) ||
-           put_user_force(compat_ptr(tmp), &kp->base) ||
-           assign_in_user(&kp->capability, &up->capability) ||
-           assign_in_user(&kp->flags, &up->flags) ||
-           copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp,
-                                       struct atomisp_dis_statistics32 __user *up)
-{
-       compat_uptr_t hor_prod_odd_real;
-       compat_uptr_t hor_prod_odd_imag;
-       compat_uptr_t hor_prod_even_real;
-       compat_uptr_t hor_prod_even_imag;
-       compat_uptr_t ver_prod_odd_real;
-       compat_uptr_t ver_prod_odd_imag;
-       compat_uptr_t ver_prod_even_real;
-       compat_uptr_t ver_prod_even_imag;
-
-       if (!access_ok(up, sizeof(struct atomisp_dis_statistics32)) ||
-           copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) ||
-           get_user(hor_prod_odd_real,
-                    &up->dvs2_stat.hor_prod.odd_real) ||
-           get_user(hor_prod_odd_imag,
-                    &up->dvs2_stat.hor_prod.odd_imag) ||
-           get_user(hor_prod_even_real,
-                    &up->dvs2_stat.hor_prod.even_real) ||
-           get_user(hor_prod_even_imag,
-                    &up->dvs2_stat.hor_prod.even_imag) ||
-           get_user(ver_prod_odd_real,
-                    &up->dvs2_stat.ver_prod.odd_real) ||
-           get_user(ver_prod_odd_imag,
-                    &up->dvs2_stat.ver_prod.odd_imag) ||
-           get_user(ver_prod_even_real,
-                    &up->dvs2_stat.ver_prod.even_real) ||
-           get_user(ver_prod_even_imag,
-                    &up->dvs2_stat.ver_prod.even_imag) ||
-           assign_in_user(&kp->exp_id, &up->exp_id) ||
-           put_user(compat_ptr(hor_prod_odd_real),
-                    &kp->dvs2_stat.hor_prod.odd_real) ||
-           put_user(compat_ptr(hor_prod_odd_imag),
-                    &kp->dvs2_stat.hor_prod.odd_imag) ||
-           put_user(compat_ptr(hor_prod_even_real),
-                    &kp->dvs2_stat.hor_prod.even_real) ||
-           put_user(compat_ptr(hor_prod_even_imag),
-                    &kp->dvs2_stat.hor_prod.even_imag) ||
-           put_user(compat_ptr(ver_prod_odd_real),
-                    &kp->dvs2_stat.ver_prod.odd_real) ||
-           put_user(compat_ptr(ver_prod_odd_imag),
-                    &kp->dvs2_stat.ver_prod.odd_imag) ||
-           put_user(compat_ptr(ver_prod_even_real),
-                    &kp->dvs2_stat.ver_prod.even_real) ||
-           put_user(compat_ptr(ver_prod_even_imag),
-                    &kp->dvs2_stat.ver_prod.even_imag))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp,
-                                       struct atomisp_dis_statistics32 __user *up)
-{
-       void __user *hor_prod_odd_real;
-       void __user *hor_prod_odd_imag;
-       void __user *hor_prod_even_real;
-       void __user *hor_prod_even_imag;
-       void __user *ver_prod_odd_real;
-       void __user *ver_prod_odd_imag;
-       void __user *ver_prod_even_real;
-       void __user *ver_prod_even_imag;
-
-       if (!!access_ok(up, sizeof(struct atomisp_dis_statistics32)) ||
-           copy_in_user(up, kp, sizeof(struct atomisp_dvs_grid_info)) ||
-           get_user(hor_prod_odd_real,
-                    &kp->dvs2_stat.hor_prod.odd_real) ||
-           get_user(hor_prod_odd_imag,
-                    &kp->dvs2_stat.hor_prod.odd_imag) ||
-           get_user(hor_prod_even_real,
-                    &kp->dvs2_stat.hor_prod.even_real) ||
-           get_user(hor_prod_even_imag,
-                    &kp->dvs2_stat.hor_prod.even_imag) ||
-           get_user(ver_prod_odd_real,
-                    &kp->dvs2_stat.ver_prod.odd_real) ||
-           get_user(ver_prod_odd_imag,
-                    &kp->dvs2_stat.ver_prod.odd_imag) ||
-           get_user(ver_prod_even_real,
-                    &kp->dvs2_stat.ver_prod.even_real) ||
-           get_user(ver_prod_even_imag,
-                    &kp->dvs2_stat.ver_prod.even_imag) ||
-           put_user(ptr_to_compat(hor_prod_odd_real),
-                    &up->dvs2_stat.hor_prod.odd_real) ||
-           put_user(ptr_to_compat(hor_prod_odd_imag),
-                    &up->dvs2_stat.hor_prod.odd_imag) ||
-           put_user(ptr_to_compat(hor_prod_even_real),
-                    &up->dvs2_stat.hor_prod.even_real) ||
-           put_user(ptr_to_compat(hor_prod_even_imag),
-                    &up->dvs2_stat.hor_prod.even_imag) ||
-           put_user(ptr_to_compat(ver_prod_odd_real),
-                    &up->dvs2_stat.ver_prod.odd_real) ||
-           put_user(ptr_to_compat(ver_prod_odd_imag),
-                    &up->dvs2_stat.ver_prod.odd_imag) ||
-           put_user(ptr_to_compat(ver_prod_even_real),
-                    &up->dvs2_stat.ver_prod.even_real) ||
-           put_user(ptr_to_compat(ver_prod_even_imag),
-                    &up->dvs2_stat.ver_prod.even_imag) ||
-           assign_in_user(&up->exp_id, &kp->exp_id))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_dis_coefficients32(struct atomisp_dis_coefficients __user *kp,
-                                         struct atomisp_dis_coefficients32 __user *up)
-{
-       compat_uptr_t hor_coefs_odd_real;
-       compat_uptr_t hor_coefs_odd_imag;
-       compat_uptr_t hor_coefs_even_real;
-       compat_uptr_t hor_coefs_even_imag;
-       compat_uptr_t ver_coefs_odd_real;
-       compat_uptr_t ver_coefs_odd_imag;
-       compat_uptr_t ver_coefs_even_real;
-       compat_uptr_t ver_coefs_even_imag;
-
-       if (!access_ok(up, sizeof(struct atomisp_dis_coefficients32)) ||
-           copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) ||
-           get_user(hor_coefs_odd_real, &up->hor_coefs.odd_real) ||
-           get_user(hor_coefs_odd_imag, &up->hor_coefs.odd_imag) ||
-           get_user(hor_coefs_even_real, &up->hor_coefs.even_real) ||
-           get_user(hor_coefs_even_imag, &up->hor_coefs.even_imag) ||
-           get_user(ver_coefs_odd_real, &up->ver_coefs.odd_real) ||
-           get_user(ver_coefs_odd_imag, &up->ver_coefs.odd_imag) ||
-           get_user(ver_coefs_even_real, &up->ver_coefs.even_real) ||
-           get_user(ver_coefs_even_imag, &up->ver_coefs.even_imag) ||
-           put_user(compat_ptr(hor_coefs_odd_real),
-                    &kp->hor_coefs.odd_real) ||
-           put_user(compat_ptr(hor_coefs_odd_imag),
-                    &kp->hor_coefs.odd_imag) ||
-           put_user(compat_ptr(hor_coefs_even_real),
-                    &kp->hor_coefs.even_real) ||
-           put_user(compat_ptr(hor_coefs_even_imag),
-                    &kp->hor_coefs.even_imag) ||
-           put_user(compat_ptr(ver_coefs_odd_real),
-                    &kp->ver_coefs.odd_real) ||
-           put_user(compat_ptr(ver_coefs_odd_imag),
-                    &kp->ver_coefs.odd_imag) ||
-           put_user(compat_ptr(ver_coefs_even_real),
-                    &kp->ver_coefs.even_real) ||
-           put_user(compat_ptr(ver_coefs_even_imag),
-                    &kp->ver_coefs.even_imag))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_dvs_6axis_config32(struct atomisp_dvs_6axis_config __user *kp,
-                                         struct atomisp_dvs_6axis_config32 __user *up)
-{
-       compat_uptr_t xcoords_y;
-       compat_uptr_t ycoords_y;
-       compat_uptr_t xcoords_uv;
-       compat_uptr_t ycoords_uv;
-
-       if (!access_ok(up, sizeof(struct atomisp_dvs_6axis_config32)) ||
-           assign_in_user(&kp->exp_id, &up->exp_id) ||
-           assign_in_user(&kp->width_y, &up->width_y) ||
-           assign_in_user(&kp->height_y, &up->height_y) ||
-           assign_in_user(&kp->width_uv, &up->width_uv) ||
-           assign_in_user(&kp->height_uv, &up->height_uv) ||
-           get_user(xcoords_y, &up->xcoords_y) ||
-           get_user(ycoords_y, &up->ycoords_y) ||
-           get_user(xcoords_uv, &up->xcoords_uv) ||
-           get_user(ycoords_uv, &up->ycoords_uv) ||
-           put_user_force(compat_ptr(xcoords_y), &kp->xcoords_y) ||
-           put_user_force(compat_ptr(ycoords_y), &kp->ycoords_y) ||
-           put_user_force(compat_ptr(xcoords_uv), &kp->xcoords_uv) ||
-           put_user_force(compat_ptr(ycoords_uv), &kp->ycoords_uv))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp,
-                                      struct atomisp_3a_statistics32 __user *up)
-{
-       compat_uptr_t data;
-       compat_uptr_t rgby_data;
-
-       if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) ||
-           copy_in_user(kp, up, sizeof(struct atomisp_grid_info)) ||
-           get_user(rgby_data, &up->rgby_data) ||
-           put_user(compat_ptr(rgby_data), &kp->rgby_data) ||
-           get_user(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data) ||
-           assign_in_user(&kp->exp_id, &up->exp_id) ||
-           assign_in_user(&kp->isp_config_id, &up->isp_config_id))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp,
-                                      struct atomisp_3a_statistics32 __user *up)
-{
-       void __user *data;
-       void __user *rgby_data;
-
-       if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) ||
-           copy_in_user(up, kp, sizeof(struct atomisp_grid_info)) ||
-           get_user(rgby_data, &kp->rgby_data) ||
-           put_user(ptr_to_compat(rgby_data), &up->rgby_data) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data) ||
-           assign_in_user(&up->exp_id, &kp->exp_id) ||
-           assign_in_user(&up->isp_config_id, &kp->isp_config_id))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_metadata_stat32(struct atomisp_metadata __user *kp,
-                                      struct atomisp_metadata32 __user *up)
-{
-       compat_uptr_t data;
-       compat_uptr_t effective_width;
-
-       if (!access_ok(up, sizeof(struct atomisp_metadata32)) ||
-           get_user(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data) ||
-           assign_in_user(&kp->width, &up->width) ||
-           assign_in_user(&kp->height, &up->height) ||
-           assign_in_user(&kp->stride, &up->stride) ||
-           assign_in_user(&kp->exp_id, &up->exp_id) ||
-           get_user(effective_width, &up->effective_width) ||
-           put_user_force(compat_ptr(effective_width), &kp->effective_width))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_metadata_stat32(struct atomisp_metadata __user *kp,
-                               struct atomisp_metadata32 __user *up)
-{
-       void __user *data;
-       void *effective_width;
-
-       if (!access_ok(up, sizeof(struct atomisp_metadata32)) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data) ||
-           assign_in_user(&up->width, &kp->width) ||
-           assign_in_user(&up->height, &kp->height) ||
-           assign_in_user(&up->stride, &kp->stride) ||
-           assign_in_user(&up->exp_id, &kp->exp_id) ||
-           get_user(effective_width, &kp->effective_width) ||
-           put_user(ptr_to_compat((void __user *)effective_width),
-                                  &up->effective_width))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-put_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp,
-                                   struct atomisp_metadata_with_type32 __user *up)
-{
-       void __user *data;
-       u32 *effective_width;
-
-       if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data) ||
-           assign_in_user(&up->width, &kp->width) ||
-           assign_in_user(&up->height, &kp->height) ||
-           assign_in_user(&up->stride, &kp->stride) ||
-           assign_in_user(&up->exp_id, &kp->exp_id) ||
-           get_user(effective_width, &kp->effective_width) ||
-           put_user(ptr_to_compat((void __user *)effective_width),
-                    &up->effective_width) ||
-           assign_in_user(&up->type, &kp->type))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp,
-                                   struct atomisp_metadata_with_type32 __user *up)
-{
-       compat_uptr_t data;
-       compat_uptr_t effective_width;
-
-       if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) ||
-           get_user(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data) ||
-           assign_in_user(&kp->width, &up->width) ||
-           assign_in_user(&kp->height, &up->height) ||
-           assign_in_user(&kp->stride, &up->stride) ||
-           assign_in_user(&kp->exp_id, &up->exp_id) ||
-           get_user(effective_width, &up->effective_width) ||
-           put_user_force(compat_ptr(effective_width), &kp->effective_width) ||
-           assign_in_user(&kp->type, &up->type))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_morph_table32(struct atomisp_morph_table __user *kp,
-                         struct atomisp_morph_table32 __user *up)
-{
-       unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES;
-
-       if (!access_ok(up, sizeof(struct atomisp_morph_table32)) ||
-               assign_in_user(&kp->enabled, &up->enabled) ||
-               assign_in_user(&kp->width, &up->width) ||
-               assign_in_user(&kp->height, &up->height))
-                       return -EFAULT;
-
-       while (n-- > 0) {
-               compat_uptr_t coord_kp;
-
-               if (get_user(coord_kp, &up->coordinates_x[n]) ||
-                   put_user(compat_ptr(coord_kp), &kp->coordinates_x[n]) ||
-                   get_user(coord_kp, &up->coordinates_y[n]) ||
-                   put_user(compat_ptr(coord_kp), &kp->coordinates_y[n]))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static int put_atomisp_morph_table32(struct atomisp_morph_table __user *kp,
-                                    struct atomisp_morph_table32 __user *up)
-{
-       unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES;
-
-       if (!access_ok(up, sizeof(struct atomisp_morph_table32)) ||
-               assign_in_user(&up->enabled, &kp->enabled) ||
-               assign_in_user(&up->width, &kp->width) ||
-               assign_in_user(&up->height, &kp->height))
-                       return -EFAULT;
-
-       while (n-- > 0) {
-               void __user *coord_kp;
-
-               if (get_user(coord_kp, &kp->coordinates_x[n]) ||
-                   put_user(ptr_to_compat(coord_kp), &up->coordinates_x[n]) ||
-                   get_user(coord_kp, &kp->coordinates_y[n]) ||
-                   put_user(ptr_to_compat(coord_kp), &up->coordinates_y[n]))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static int get_atomisp_overlay32(struct atomisp_overlay __user *kp,
-                                struct atomisp_overlay32 __user *up)
-{
-       compat_uptr_t frame;
-
-       if (!access_ok(up, sizeof(struct atomisp_overlay32)) ||
-           get_user(frame, &up->frame) ||
-           put_user_force(compat_ptr(frame), &kp->frame) ||
-           assign_in_user(&kp->bg_y, &up->bg_y) ||
-           assign_in_user(&kp->bg_u, &up->bg_u) ||
-           assign_in_user(&kp->bg_v, &up->bg_v) ||
-           assign_in_user(&kp->blend_input_perc_y,
-                          &up->blend_input_perc_y) ||
-           assign_in_user(&kp->blend_input_perc_u,
-                          &up->blend_input_perc_u) ||
-           assign_in_user(&kp->blend_input_perc_v,
-                          &up->blend_input_perc_v) ||
-           assign_in_user(&kp->blend_overlay_perc_y,
-                          &up->blend_overlay_perc_y) ||
-           assign_in_user(&kp->blend_overlay_perc_u,
-                          &up->blend_overlay_perc_u) ||
-           assign_in_user(&kp->blend_overlay_perc_v,
-                          &up->blend_overlay_perc_v) ||
-           assign_in_user(&kp->overlay_start_x, &up->overlay_start_x) ||
-           assign_in_user(&kp->overlay_start_y, &up->overlay_start_y))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_overlay32(struct atomisp_overlay __user *kp,
-                                struct atomisp_overlay32 __user *up)
-{
-       void *frame;
-
-       if (!access_ok(up, sizeof(struct atomisp_overlay32)) ||
-           get_user(frame, &kp->frame) ||
-           put_user(ptr_to_compat((void __user *)frame), &up->frame) ||
-           assign_in_user(&up->bg_y, &kp->bg_y) ||
-           assign_in_user(&up->bg_u, &kp->bg_u) ||
-           assign_in_user(&up->bg_v, &kp->bg_v) ||
-           assign_in_user(&up->blend_input_perc_y,
-                          &kp->blend_input_perc_y) ||
-           assign_in_user(&up->blend_input_perc_u,
-                          &kp->blend_input_perc_u) ||
-           assign_in_user(&up->blend_input_perc_v,
-                          &kp->blend_input_perc_v) ||
-           assign_in_user(&up->blend_overlay_perc_y,
-                          &kp->blend_overlay_perc_y) ||
-           assign_in_user(&up->blend_overlay_perc_u,
-                          &kp->blend_overlay_perc_u) ||
-           assign_in_user(&up->blend_overlay_perc_v,
-                          &kp->blend_overlay_perc_v) ||
-           assign_in_user(&up->overlay_start_x, &kp->overlay_start_x) ||
-           assign_in_user(&up->overlay_start_y, &kp->overlay_start_y))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp,
-                               struct atomisp_calibration_group32 __user *up)
-{
-       compat_uptr_t calb_grp_values;
-
-       if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) ||
-           assign_in_user(&kp->size, &up->size) ||
-           assign_in_user(&kp->type, &up->type) ||
-           get_user(calb_grp_values, &up->calb_grp_values) ||
-           put_user_force(compat_ptr(calb_grp_values), &kp->calb_grp_values))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-put_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp,
-                               struct atomisp_calibration_group32 __user *up)
-{
-       void *calb_grp_values;
-
-       if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) ||
-           assign_in_user(&up->size, &kp->size) ||
-           assign_in_user(&up->type, &kp->type) ||
-           get_user(calb_grp_values, &kp->calb_grp_values) ||
-           put_user(ptr_to_compat((void __user *)calb_grp_values),
-                    &up->calb_grp_values))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp,
-                                    struct atomisp_acc_fw_load32 __user *up)
-{
-       compat_uptr_t data;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) ||
-           assign_in_user(&kp->size, &up->size) ||
-           assign_in_user(&kp->fw_handle, &up->fw_handle) ||
-           get_user_cast(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp,
-                                    struct atomisp_acc_fw_load32 __user *up)
-{
-       void __user *data;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) ||
-           assign_in_user(&up->size, &kp->size) ||
-           assign_in_user(&up->fw_handle, &kp->fw_handle) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp,
-                                   struct atomisp_acc_fw_arg32 __user *up)
-{
-       compat_uptr_t value;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) ||
-           assign_in_user(&kp->fw_handle, &up->fw_handle) ||
-           assign_in_user(&kp->index, &up->index) ||
-           get_user(value, &up->value) ||
-           put_user(compat_ptr(value), &kp->value) ||
-           assign_in_user(&kp->size, &up->size))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp,
-                                   struct atomisp_acc_fw_arg32 __user *up)
-{
-       void __user *value;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) ||
-           assign_in_user(&up->fw_handle, &kp->fw_handle) ||
-           assign_in_user(&up->index, &kp->index) ||
-           get_user(value, &kp->value) ||
-           put_user(ptr_to_compat(value), &up->value) ||
-           assign_in_user(&up->size, &kp->size))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp,
-                                      struct v4l2_private_int_data32 __user *up)
-{
-       compat_uptr_t data;
-
-       if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) ||
-           assign_in_user(&kp->size, &up->size) ||
-           get_user(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data) ||
-           assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
-           assign_in_user(&kp->reserved[1], &up->reserved[1]))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp,
-                                      struct v4l2_private_int_data32 __user *up)
-{
-       void __user *data;
-
-       if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) ||
-           assign_in_user(&up->size, &kp->size) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data) ||
-           assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
-           assign_in_user(&up->reserved[1], &kp->reserved[1]))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_shading_table32(struct atomisp_shading_table __user *kp,
-                                      struct atomisp_shading_table32 __user *up)
-{
-       unsigned int n = ATOMISP_NUM_SC_COLORS;
-
-       if (!access_ok(up, sizeof(struct atomisp_shading_table32)) ||
-           assign_in_user(&kp->enable, &up->enable) ||
-           assign_in_user(&kp->sensor_width, &up->sensor_width) ||
-           assign_in_user(&kp->sensor_height, &up->sensor_height) ||
-           assign_in_user(&kp->width, &up->width) ||
-           assign_in_user(&kp->height, &up->height) ||
-           assign_in_user(&kp->fraction_bits, &up->fraction_bits))
-               return -EFAULT;
-
-       while (n-- > 0) {
-               compat_uptr_t tmp;
-
-               if (get_user(tmp, &up->data[n]) ||
-                   put_user_force(compat_ptr(tmp), &kp->data[n]))
-                       return -EFAULT;
-       }
-       return 0;
-}
-
-static int get_atomisp_acc_map32(struct atomisp_acc_map __user *kp,
-                                struct atomisp_acc_map32 __user *up)
-{
-       compat_uptr_t user_ptr;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_map32)) ||
-           assign_in_user(&kp->flags, &up->flags) ||
-           assign_in_user(&kp->length, &up->length) ||
-           get_user(user_ptr, &up->user_ptr) ||
-           put_user(compat_ptr(user_ptr), &kp->user_ptr) ||
-           assign_in_user(&kp->css_ptr, &up->css_ptr) ||
-           assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
-           assign_in_user(&kp->reserved[1], &up->reserved[1]) ||
-           assign_in_user(&kp->reserved[2], &up->reserved[2]) ||
-           assign_in_user(&kp->reserved[3], &up->reserved[3]))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int put_atomisp_acc_map32(struct atomisp_acc_map __user *kp,
-                                struct atomisp_acc_map32 __user *up)
-{
-       void __user *user_ptr;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_map32)) ||
-           assign_in_user(&up->flags, &kp->flags) ||
-           assign_in_user(&up->length, &kp->length) ||
-           get_user(user_ptr, &kp->user_ptr) ||
-           put_user(ptr_to_compat(user_ptr), &up->user_ptr) ||
-           assign_in_user(&up->css_ptr, &kp->css_ptr) ||
-           assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
-           assign_in_user(&up->reserved[1], &kp->reserved[1]) ||
-           assign_in_user(&up->reserved[2], &kp->reserved[2]) ||
-           assign_in_user(&up->reserved[3], &kp->reserved[3]))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp,
-                              struct atomisp_acc_s_mapped_arg32 __user *up)
-{
-       if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) ||
-           assign_in_user(&kp->fw_handle, &up->fw_handle) ||
-           assign_in_user(&kp->memory, &up->memory) ||
-           assign_in_user(&kp->length, &up->length) ||
-           assign_in_user(&kp->css_ptr, &up->css_ptr))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-put_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp,
-                              struct atomisp_acc_s_mapped_arg32 __user *up)
-{
-       if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) ||
-           assign_in_user(&up->fw_handle, &kp->fw_handle) ||
-           assign_in_user(&up->memory, &kp->memory) ||
-           assign_in_user(&up->length, &kp->length) ||
-           assign_in_user(&up->css_ptr, &kp->css_ptr))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_atomisp_parameters32(struct atomisp_parameters __user *kp,
-                                   struct atomisp_parameters32 __user *up)
-{
-       int n = offsetof(struct atomisp_parameters32, output_frame) /
-               sizeof(compat_uptr_t);
-       compat_uptr_t stp, mtp, dcp, dscp;
-       struct {
-               struct atomisp_shading_table shading_table;
-               struct atomisp_morph_table morph_table;
-               struct atomisp_dis_coefficients dvs2_coefs;
-               struct atomisp_dvs_6axis_config dvs_6axis_config;
-       } __user *karg = (void __user *)(kp + 1);
-
-       if (!access_ok(up, sizeof(struct atomisp_parameters32)))
-               return -EFAULT;
-
-       while (n >= 0) {
-               compat_uptr_t __user *src = (compat_uptr_t __user *)up + n;
-               void * __user *dst = (void * __user *)kp + n;
-               compat_uptr_t tmp;
-
-               if (get_user_cast(tmp, src) || put_user_force(compat_ptr(tmp), dst))
-                       return -EFAULT;
-               n--;
-       }
-
-       if (assign_in_user(&kp->isp_config_id, &up->isp_config_id) ||
-           assign_in_user(&kp->per_frame_setting, &up->per_frame_setting) ||
-           get_user(stp, &up->shading_table) ||
-           get_user(mtp, &up->morph_table) ||
-           get_user(dcp, &up->dvs2_coefs) ||
-           get_user(dscp, &up->dvs_6axis_config))
-               return -EFAULT;
-
-       /* handle shading table */
-       if (stp && (get_atomisp_shading_table32(&karg->shading_table,
-                                               compat_ptr(stp)) ||
-                   put_user_force(&karg->shading_table, &kp->shading_table)))
-               return -EFAULT;
-
-       /* handle morph table */
-       if (mtp && (get_atomisp_morph_table32(&karg->morph_table,
-                                             compat_ptr(mtp)) ||
-                   put_user_force(&karg->morph_table, &kp->morph_table)))
-               return -EFAULT;
-
-       /* handle dvs2 coefficients */
-       if (dcp && (get_atomisp_dis_coefficients32(&karg->dvs2_coefs,
-                                                  compat_ptr(dcp)) ||
-                   put_user_force(&karg->dvs2_coefs, &kp->dvs2_coefs)))
-               return -EFAULT;
-
-       /* handle dvs 6axis configuration */
-       if (dscp &&
-           (get_atomisp_dvs_6axis_config32(&karg->dvs_6axis_config,
-                                           compat_ptr(dscp)) ||
-            put_user_force(&karg->dvs_6axis_config, &kp->dvs_6axis_config)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp,
-                                 struct atomisp_acc_fw_load_to_pipe32 __user *up)
-{
-       compat_uptr_t data;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) ||
-           assign_in_user(&kp->flags, &up->flags) ||
-           assign_in_user(&kp->fw_handle, &up->fw_handle) ||
-           assign_in_user(&kp->size, &up->size) ||
-           assign_in_user(&kp->type, &up->type) ||
-           assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
-           assign_in_user(&kp->reserved[1], &up->reserved[1]) ||
-           assign_in_user(&kp->reserved[2], &up->reserved[2]) ||
-           get_user(data, &up->data) ||
-           put_user(compat_ptr(data), &kp->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-put_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp,
-                                 struct atomisp_acc_fw_load_to_pipe32 __user *up)
-{
-       void __user *data;
-
-       if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) ||
-           assign_in_user(&up->flags, &kp->flags) ||
-           assign_in_user(&up->fw_handle, &kp->fw_handle) ||
-           assign_in_user(&up->size, &kp->size) ||
-           assign_in_user(&up->type, &kp->type) ||
-           assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
-           assign_in_user(&up->reserved[1], &kp->reserved[1]) ||
-           assign_in_user(&up->reserved[2], &kp->reserved[2]) ||
-           get_user(data, &kp->data) ||
-           put_user(ptr_to_compat(data), &up->data))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int
-get_atomisp_sensor_ae_bracketing_lut(struct atomisp_sensor_ae_bracketing_lut __user *kp,
-                                    struct atomisp_sensor_ae_bracketing_lut32 __user *up)
-{
-       compat_uptr_t lut;
-
-       if (!access_ok(up, sizeof(struct atomisp_sensor_ae_bracketing_lut32)) ||
-           assign_in_user(&kp->lut_size, &up->lut_size) ||
-           get_user(lut, &up->lut) ||
-           put_user_force(compat_ptr(lut), &kp->lut))
-               return -EFAULT;
-
-       return 0;
-}
-
-static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       long ret = -ENOIOCTLCMD;
-
-       if (file->f_op->unlocked_ioctl)
-               ret = file->f_op->unlocked_ioctl(file, cmd, arg);
-
-       return ret;
-}
-
-static long atomisp_do_compat_ioctl(struct file *file,
-                                   unsigned int cmd, unsigned long arg)
-{
-       union {
-               struct atomisp_histogram his;
-               struct atomisp_dis_statistics dis_s;
-               struct atomisp_dis_coefficients dis_c;
-               struct atomisp_dvs_6axis_config dvs_c;
-               struct atomisp_3a_statistics s3a_s;
-               struct atomisp_morph_table mor_t;
-               struct v4l2_framebuffer v4l2_buf;
-               struct atomisp_overlay overlay;
-               struct atomisp_calibration_group cal_grp;
-               struct atomisp_acc_fw_load acc_fw_load;
-               struct atomisp_acc_fw_arg acc_fw_arg;
-               struct v4l2_private_int_data v4l2_pri_data;
-               struct atomisp_shading_table shd_tbl;
-               struct atomisp_acc_map acc_map;
-               struct atomisp_acc_s_mapped_arg acc_map_arg;
-               struct atomisp_parameters param;
-               struct atomisp_acc_fw_load_to_pipe acc_fw_to_pipe;
-               struct atomisp_metadata md;
-               struct atomisp_metadata_with_type md_with_type;
-               struct atomisp_sensor_ae_bracketing_lut lut;
-       } __user *karg;
-       void __user *up = compat_ptr(arg);
-       long err = -ENOIOCTLCMD;
-
-       karg = compat_alloc_user_space(
-               sizeof(*karg) + (cmd == ATOMISP_IOC_S_PARAMETERS32 ?
-                                sizeof(struct atomisp_shading_table) +
-                                sizeof(struct atomisp_morph_table) +
-                                sizeof(struct atomisp_dis_coefficients) +
-                                sizeof(struct atomisp_dvs_6axis_config) : 0));
-       if (!karg)
-               return -ENOMEM;
-
-       /* First, convert the command. */
-       switch (cmd) {
-       case ATOMISP_IOC_G_HISTOGRAM32:
-               cmd = ATOMISP_IOC_G_HISTOGRAM;
-               break;
-       case ATOMISP_IOC_S_HISTOGRAM32:
-               cmd = ATOMISP_IOC_S_HISTOGRAM;
-               break;
-       case ATOMISP_IOC_G_DIS_STAT32:
-               cmd = ATOMISP_IOC_G_DIS_STAT;
-               break;
-       case ATOMISP_IOC_S_DIS_COEFS32:
-               cmd = ATOMISP_IOC_S_DIS_COEFS;
-               break;
-       case ATOMISP_IOC_S_DIS_VECTOR32:
-               cmd = ATOMISP_IOC_S_DIS_VECTOR;
-               break;
-       case ATOMISP_IOC_G_3A_STAT32:
-               cmd = ATOMISP_IOC_G_3A_STAT;
-               break;
-       case ATOMISP_IOC_G_ISP_GDC_TAB32:
-               cmd = ATOMISP_IOC_G_ISP_GDC_TAB;
-               break;
-       case ATOMISP_IOC_S_ISP_GDC_TAB32:
-               cmd = ATOMISP_IOC_S_ISP_GDC_TAB;
-               break;
-       case ATOMISP_IOC_S_ISP_FPN_TABLE32:
-               cmd = ATOMISP_IOC_S_ISP_FPN_TABLE;
-               break;
-       case ATOMISP_IOC_G_ISP_OVERLAY32:
-               cmd = ATOMISP_IOC_G_ISP_OVERLAY;
-               break;
-       case ATOMISP_IOC_S_ISP_OVERLAY32:
-               cmd = ATOMISP_IOC_S_ISP_OVERLAY;
-               break;
-       case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32:
-               cmd = ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP;
-               break;
-       case ATOMISP_IOC_ACC_LOAD32:
-               cmd = ATOMISP_IOC_ACC_LOAD;
-               break;
-       case ATOMISP_IOC_ACC_S_ARG32:
-               cmd = ATOMISP_IOC_ACC_S_ARG;
-               break;
-       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32:
-               cmd = ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA;
-               break;
-       case ATOMISP_IOC_S_ISP_SHD_TAB32:
-               cmd = ATOMISP_IOC_S_ISP_SHD_TAB;
-               break;
-       case ATOMISP_IOC_ACC_DESTAB32:
-               cmd = ATOMISP_IOC_ACC_DESTAB;
-               break;
-       case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32:
-               cmd = ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA;
-               break;
-       case ATOMISP_IOC_ACC_MAP32:
-               cmd = ATOMISP_IOC_ACC_MAP;
-               break;
-       case ATOMISP_IOC_ACC_UNMAP32:
-               cmd = ATOMISP_IOC_ACC_UNMAP;
-               break;
-       case ATOMISP_IOC_ACC_S_MAPPED_ARG32:
-               cmd = ATOMISP_IOC_ACC_S_MAPPED_ARG;
-               break;
-       case ATOMISP_IOC_S_PARAMETERS32:
-               cmd = ATOMISP_IOC_S_PARAMETERS;
-               break;
-       case ATOMISP_IOC_ACC_LOAD_TO_PIPE32:
-               cmd = ATOMISP_IOC_ACC_LOAD_TO_PIPE;
-               break;
-       case ATOMISP_IOC_G_METADATA32:
-               cmd = ATOMISP_IOC_G_METADATA;
-               break;
-       case ATOMISP_IOC_G_METADATA_BY_TYPE32:
-               cmd = ATOMISP_IOC_G_METADATA_BY_TYPE;
-               break;
-       case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32:
-               cmd = ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT;
-               break;
-       }
-
-       switch (cmd) {
-       case ATOMISP_IOC_G_HISTOGRAM:
-       case ATOMISP_IOC_S_HISTOGRAM:
-               err = get_atomisp_histogram32(&karg->his, up);
-               break;
-       case ATOMISP_IOC_G_DIS_STAT:
-               err = get_atomisp_dis_statistics32(&karg->dis_s, up);
-               break;
-       case ATOMISP_IOC_S_DIS_COEFS:
-               err = get_atomisp_dis_coefficients32(&karg->dis_c, up);
-               break;
-       case ATOMISP_IOC_S_DIS_VECTOR:
-               err = get_atomisp_dvs_6axis_config32(&karg->dvs_c, up);
-               break;
-       case ATOMISP_IOC_G_3A_STAT:
-               err = get_atomisp_3a_statistics32(&karg->s3a_s, up);
-               break;
-       case ATOMISP_IOC_G_ISP_GDC_TAB:
-       case ATOMISP_IOC_S_ISP_GDC_TAB:
-               err = get_atomisp_morph_table32(&karg->mor_t, up);
-               break;
-       case ATOMISP_IOC_S_ISP_FPN_TABLE:
-               err = get_v4l2_framebuffer32(&karg->v4l2_buf, up);
-               break;
-       case ATOMISP_IOC_G_ISP_OVERLAY:
-       case ATOMISP_IOC_S_ISP_OVERLAY:
-               err = get_atomisp_overlay32(&karg->overlay, up);
-               break;
-       case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP:
-               err = get_atomisp_calibration_group32(&karg->cal_grp, up);
-               break;
-       case ATOMISP_IOC_ACC_LOAD:
-               err = get_atomisp_acc_fw_load32(&karg->acc_fw_load, up);
-               break;
-       case ATOMISP_IOC_ACC_S_ARG:
-       case ATOMISP_IOC_ACC_DESTAB:
-               err = get_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up);
-               break;
-       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
-       case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
-               err = get_v4l2_private_int_data32(&karg->v4l2_pri_data, up);
-               break;
-       case ATOMISP_IOC_S_ISP_SHD_TAB:
-               err = get_atomisp_shading_table32(&karg->shd_tbl, up);
-               break;
-       case ATOMISP_IOC_ACC_MAP:
-       case ATOMISP_IOC_ACC_UNMAP:
-               err = get_atomisp_acc_map32(&karg->acc_map, up);
-               break;
-       case ATOMISP_IOC_ACC_S_MAPPED_ARG:
-               err = get_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up);
-               break;
-       case ATOMISP_IOC_S_PARAMETERS:
-               err = get_atomisp_parameters32(&karg->param, up);
-               break;
-       case ATOMISP_IOC_ACC_LOAD_TO_PIPE:
-               err = get_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe,
-                                                       up);
-               break;
-       case ATOMISP_IOC_G_METADATA:
-               err = get_atomisp_metadata_stat32(&karg->md, up);
-               break;
-       case ATOMISP_IOC_G_METADATA_BY_TYPE:
-               err = get_atomisp_metadata_by_type_stat32(&karg->md_with_type,
-                                                         up);
-               break;
-       case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT:
-               err = get_atomisp_sensor_ae_bracketing_lut(&karg->lut, up);
-               break;
-       }
-       if (err)
-               return err;
-
-       err = native_ioctl(file, cmd, (unsigned long)karg);
-       if (err)
-               return err;
-
-       switch (cmd) {
-       case ATOMISP_IOC_G_HISTOGRAM:
-               err = put_atomisp_histogram32(&karg->his, up);
-               break;
-       case ATOMISP_IOC_G_DIS_STAT:
-               err = put_atomisp_dis_statistics32(&karg->dis_s, up);
-               break;
-       case ATOMISP_IOC_G_3A_STAT:
-               err = put_atomisp_3a_statistics32(&karg->s3a_s, up);
-               break;
-       case ATOMISP_IOC_G_ISP_GDC_TAB:
-               err = put_atomisp_morph_table32(&karg->mor_t, up);
-               break;
-       case ATOMISP_IOC_G_ISP_OVERLAY:
-               err = put_atomisp_overlay32(&karg->overlay, up);
-               break;
-       case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP:
-               err = put_atomisp_calibration_group32(&karg->cal_grp, up);
-               break;
-       case ATOMISP_IOC_ACC_LOAD:
-               err = put_atomisp_acc_fw_load32(&karg->acc_fw_load, up);
-               break;
-       case ATOMISP_IOC_ACC_S_ARG:
-       case ATOMISP_IOC_ACC_DESTAB:
-               err = put_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up);
-               break;
-       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
-       case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
-               err = put_v4l2_private_int_data32(&karg->v4l2_pri_data, up);
-               break;
-       case ATOMISP_IOC_ACC_MAP:
-       case ATOMISP_IOC_ACC_UNMAP:
-               err = put_atomisp_acc_map32(&karg->acc_map, up);
-               break;
-       case ATOMISP_IOC_ACC_S_MAPPED_ARG:
-               err = put_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up);
-               break;
-       case ATOMISP_IOC_ACC_LOAD_TO_PIPE:
-               err = put_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe,
-                                                       up);
-               break;
-       case ATOMISP_IOC_G_METADATA:
-               err = put_atomisp_metadata_stat32(&karg->md, up);
-               break;
-       case ATOMISP_IOC_G_METADATA_BY_TYPE:
-               err = put_atomisp_metadata_by_type_stat32(&karg->md_with_type,
-                                                         up);
-               break;
-       }
-
-       return err;
-}
-
-long atomisp_compat_ioctl32(struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct atomisp_device *isp = video_get_drvdata(vdev);
-       long ret = -ENOIOCTLCMD;
-
-       if (!file->f_op->unlocked_ioctl)
-               return ret;
-
-       switch (cmd) {
-       case ATOMISP_IOC_G_XNR:
-       case ATOMISP_IOC_S_XNR:
-       case ATOMISP_IOC_G_NR:
-       case ATOMISP_IOC_S_NR:
-       case ATOMISP_IOC_G_TNR:
-       case ATOMISP_IOC_S_TNR:
-       case ATOMISP_IOC_G_BLACK_LEVEL_COMP:
-       case ATOMISP_IOC_S_BLACK_LEVEL_COMP:
-       case ATOMISP_IOC_G_EE:
-       case ATOMISP_IOC_S_EE:
-       case ATOMISP_IOC_S_DIS_VECTOR:
-       case ATOMISP_IOC_G_ISP_PARM:
-       case ATOMISP_IOC_S_ISP_PARM:
-       case ATOMISP_IOC_G_ISP_GAMMA:
-       case ATOMISP_IOC_S_ISP_GAMMA:
-       case ATOMISP_IOC_ISP_MAKERNOTE:
-       case ATOMISP_IOC_G_ISP_MACC:
-       case ATOMISP_IOC_S_ISP_MACC:
-       case ATOMISP_IOC_G_ISP_BAD_PIXEL_DETECTION:
-       case ATOMISP_IOC_S_ISP_BAD_PIXEL_DETECTION:
-       case ATOMISP_IOC_G_ISP_FALSE_COLOR_CORRECTION:
-       case ATOMISP_IOC_S_ISP_FALSE_COLOR_CORRECTION:
-       case ATOMISP_IOC_G_ISP_CTC:
-       case ATOMISP_IOC_S_ISP_CTC:
-       case ATOMISP_IOC_G_ISP_WHITE_BALANCE:
-       case ATOMISP_IOC_S_ISP_WHITE_BALANCE:
-       case ATOMISP_IOC_CAMERA_BRIDGE:
-       case ATOMISP_IOC_G_SENSOR_MODE_DATA:
-       case ATOMISP_IOC_S_EXPOSURE:
-       case ATOMISP_IOC_G_3A_CONFIG:
-       case ATOMISP_IOC_S_3A_CONFIG:
-       case ATOMISP_IOC_ACC_UNLOAD:
-       case ATOMISP_IOC_ACC_START:
-       case ATOMISP_IOC_ACC_WAIT:
-       case ATOMISP_IOC_ACC_ABORT:
-       case ATOMISP_IOC_G_ISP_GAMMA_CORRECTION:
-       case ATOMISP_IOC_S_ISP_GAMMA_CORRECTION:
-       case ATOMISP_IOC_S_CONT_CAPTURE_CONFIG:
-       case ATOMISP_IOC_G_DVS2_BQ_RESOLUTIONS:
-       case ATOMISP_IOC_EXT_ISP_CTRL:
-       case ATOMISP_IOC_EXP_ID_UNLOCK:
-       case ATOMISP_IOC_EXP_ID_CAPTURE:
-       case ATOMISP_IOC_S_ENABLE_DZ_CAPT_PIPE:
-       case ATOMISP_IOC_G_FORMATS_CONFIG:
-       case ATOMISP_IOC_S_FORMATS_CONFIG:
-       case ATOMISP_IOC_S_EXPOSURE_WINDOW:
-       case ATOMISP_IOC_S_ACC_STATE:
-       case ATOMISP_IOC_G_ACC_STATE:
-       case ATOMISP_IOC_INJECT_A_FAKE_EVENT:
-       case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_INFO:
-       case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_MODE:
-       case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_MODE:
-       case ATOMISP_IOC_G_INVALID_FRAME_NUM:
-       case ATOMISP_IOC_S_ARRAY_RESOLUTION:
-       case ATOMISP_IOC_S_SENSOR_RUNMODE:
-       case ATOMISP_IOC_G_UPDATE_EXPOSURE:
-               ret = native_ioctl(file, cmd, arg);
-               break;
-
-       case ATOMISP_IOC_G_HISTOGRAM32:
-       case ATOMISP_IOC_S_HISTOGRAM32:
-       case ATOMISP_IOC_G_DIS_STAT32:
-       case ATOMISP_IOC_S_DIS_COEFS32:
-       case ATOMISP_IOC_S_DIS_VECTOR32:
-       case ATOMISP_IOC_G_3A_STAT32:
-       case ATOMISP_IOC_G_ISP_GDC_TAB32:
-       case ATOMISP_IOC_S_ISP_GDC_TAB32:
-       case ATOMISP_IOC_S_ISP_FPN_TABLE32:
-       case ATOMISP_IOC_G_ISP_OVERLAY32:
-       case ATOMISP_IOC_S_ISP_OVERLAY32:
-       case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32:
-       case ATOMISP_IOC_ACC_LOAD32:
-       case ATOMISP_IOC_ACC_S_ARG32:
-       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32:
-       case ATOMISP_IOC_S_ISP_SHD_TAB32:
-       case ATOMISP_IOC_ACC_DESTAB32:
-       case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32:
-       case ATOMISP_IOC_ACC_MAP32:
-       case ATOMISP_IOC_ACC_UNMAP32:
-       case ATOMISP_IOC_ACC_S_MAPPED_ARG32:
-       case ATOMISP_IOC_S_PARAMETERS32:
-       case ATOMISP_IOC_ACC_LOAD_TO_PIPE32:
-       case ATOMISP_IOC_G_METADATA32:
-       case ATOMISP_IOC_G_METADATA_BY_TYPE32:
-       case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32:
-               ret = atomisp_do_compat_ioctl(file, cmd, arg);
-               break;
-
-       default:
-               dev_warn(isp->dev,
-                        "%s: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
-                        __func__, _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
-                        cmd);
-               break;
-       }
-       return ret;
-}
-#endif /* CONFIG_COMPAT */
index 060b876..56456e5 100644 (file)
 static struct v4l2_mbus_framefmt *__csi2_get_format(struct
        atomisp_mipi_csi2_device
        * csi2,
-       struct
-       v4l2_subdev_pad_config *cfg,
+       struct v4l2_subdev_state *sd_state,
        enum
        v4l2_subdev_format_whence
        which, unsigned int pad) {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+                                                 pad);
        else
                return &csi2->formats[pad];
 }
@@ -44,7 +44,7 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct
  * return -EINVAL or zero on success
 */
 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv;
@@ -70,13 +70,13 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
 */
 static int csi2_get_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csi2_get_format(csi2, cfg, fmt->which, fmt->pad);
+       format = __csi2_get_format(csi2, sd_state, fmt->which, fmt->pad);
 
        fmt->format = *format;
 
@@ -84,12 +84,14 @@ static int csi2_get_format(struct v4l2_subdev *sd,
 }
 
 int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          unsigned int which, uint16_t pad,
                          struct v4l2_mbus_framefmt *ffmt)
 {
        struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
-       struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2, cfg, which, pad);
+       struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2,
+                                                                  sd_state,
+                                                                  which, pad);
 
        if (pad == CSI2_PAD_SINK) {
                const struct atomisp_in_fmt_conv *ic;
@@ -110,12 +112,14 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
 
                tmp_ffmt = *ffmt = *actual_ffmt;
 
-               return atomisp_csi2_set_ffmt(sd, cfg, which, CSI2_PAD_SOURCE,
+               return atomisp_csi2_set_ffmt(sd, sd_state, which,
+                                            CSI2_PAD_SOURCE,
                                             &tmp_ffmt);
        }
 
        /* FIXME: DPCM decompression */
-       *actual_ffmt = *ffmt = *__csi2_get_format(csi2, cfg, which, CSI2_PAD_SINK);
+       *actual_ffmt = *ffmt = *__csi2_get_format(csi2, sd_state, which,
+                                                 CSI2_PAD_SINK);
 
        return 0;
 }
@@ -129,10 +133,10 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
 */
 static int csi2_set_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
-       return atomisp_csi2_set_ffmt(sd, cfg, fmt->which, fmt->pad,
+       return atomisp_csi2_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
                                     &fmt->format);
 }
 
index 59261e8..e35711b 100644 (file)
@@ -44,7 +44,7 @@ struct atomisp_mipi_csi2_device {
 };
 
 int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          unsigned int which, uint16_t pad,
                          struct v4l2_mbus_framefmt *ffmt);
 int atomisp_mipi_csi2_init(struct atomisp_device *isp);
index e568ca9..4570a9a 100644 (file)
@@ -80,7 +80,7 @@ static int file_input_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int file_input_get_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -104,16 +104,16 @@ static int file_input_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int file_input_set_fmt(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
 
        if (format->pad)
                return -EINVAL;
-       file_input_get_fmt(sd, cfg, format);
+       file_input_get_fmt(sd, sd_state, format);
        if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
        return 0;
 }
 
@@ -130,7 +130,7 @@ static int file_input_s_power(struct v4l2_subdev *sd, int on)
 }
 
 static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_mbus_code_enum *code)
 {
        /*to fake*/
@@ -138,7 +138,7 @@ static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int file_input_enum_frame_size(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_size_enum *fse)
 {
        /*to fake*/
@@ -146,7 +146,7 @@ static int file_input_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int file_input_enum_frame_ival(struct v4l2_subdev *sd,
-                                     struct v4l2_subdev_pad_config *cfg,
+                                     struct v4l2_subdev_state *sd_state,
                                      struct v4l2_subdev_frame_interval_enum
                                      *fie)
 {
index f1e6b25..f82bf08 100644 (file)
@@ -837,7 +837,7 @@ dev_init:
        }
 
        /* runtime power management, turn on ISP */
-       ret = pm_runtime_get_sync(vdev->v4l2_dev->dev);
+       ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev);
        if (ret < 0) {
                dev_err(isp->dev, "Failed to power on device\n");
                goto error;
@@ -881,9 +881,9 @@ done:
 
 css_error:
        atomisp_css_uninit(isp);
+       pm_runtime_put(vdev->v4l2_dev->dev);
 error:
        hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC);
-       pm_runtime_put(vdev->v4l2_dev->dev);
        rt_mutex_unlock(&isp->mutex);
        return ret;
 }
@@ -963,7 +963,7 @@ static int atomisp_release(struct file *file)
        if (!isp->sw_contex.file_input && asd->fmt_auto->val) {
                struct v4l2_mbus_framefmt isp_sink_fmt = { 0 };
 
-               atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+               atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
                                        V4L2_SUBDEV_FORMAT_ACTIVE,
                                        ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt);
        }
@@ -975,7 +975,7 @@ subdev_uninit:
        if (isp->sw_contex.file_input && asd->fmt_auto->val) {
                struct v4l2_mbus_framefmt isp_sink_fmt = { 0 };
 
-               atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+               atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
                                        V4L2_SUBDEV_FORMAT_ACTIVE,
                                        ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt);
        }
@@ -1016,7 +1016,7 @@ subdev_uninit:
 
 done:
        if (!acc_node) {
-               atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+               atomisp_subdev_set_selection(&asd->subdev, fh.state,
                                             V4L2_SUBDEV_FORMAT_ACTIVE,
                                             atomisp_subdev_source_pad(vdev),
                                             V4L2_SEL_TGT_COMPOSE, 0,
@@ -1283,7 +1283,8 @@ const struct v4l2_file_operations atomisp_fops = {
        .unlocked_ioctl = video_ioctl2,
 #ifdef CONFIG_COMPAT
        /*
-        * There are problems with this code. Disable this for now.
+        * this was removed because of bugs, the interface
+        * needs to be made safe for compat tasks instead.
        .compat_ioctl32 = atomisp_compat_ioctl32,
         */
 #endif
@@ -1297,10 +1298,7 @@ const struct v4l2_file_operations atomisp_file_fops = {
        .mmap = atomisp_file_mmap,
        .unlocked_ioctl = video_ioctl2,
 #ifdef CONFIG_COMPAT
-       /*
-        * There are problems with this code. Disable this for now.
-       .compat_ioctl32 = atomisp_compat_ioctl32,
-        */
+       /* .compat_ioctl32 = atomisp_compat_ioctl32, */
 #endif
        .poll = atomisp_poll,
 };
index 2ef5f44..12f22ad 100644 (file)
@@ -213,7 +213,7 @@ static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
@@ -246,7 +246,7 @@ static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
 }
 
 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
-       struct v4l2_subdev_pad_config *cfg,
+       struct v4l2_subdev_state *sd_state,
        u32 which, uint32_t pad,
        uint32_t target)
 {
@@ -255,9 +255,9 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
        if (which == V4L2_SUBDEV_FORMAT_TRY) {
                switch (target) {
                case V4L2_SEL_TGT_CROP:
-                       return v4l2_subdev_get_try_crop(sd, cfg, pad);
+                       return v4l2_subdev_get_try_crop(sd, sd_state, pad);
                case V4L2_SEL_TGT_COMPOSE:
-                       return v4l2_subdev_get_try_compose(sd, cfg, pad);
+                       return v4l2_subdev_get_try_compose(sd, sd_state, pad);
                }
        }
 
@@ -273,19 +273,20 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
 
 struct v4l2_mbus_framefmt
 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg, uint32_t which,
+                        struct v4l2_subdev_state *sd_state, uint32_t which,
                         uint32_t pad)
 {
        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(sd, cfg, pad);
+               return v4l2_subdev_get_try_format(sd, sd_state, pad);
 
        return &isp_sd->fmt[pad].fmt;
 }
 
 static void isp_get_fmt_rect(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg, uint32_t which,
+                            struct v4l2_subdev_state *sd_state,
+                            uint32_t which,
                             struct v4l2_mbus_framefmt **ffmt,
                             struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
                             struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
@@ -293,16 +294,16 @@ static void isp_get_fmt_rect(struct v4l2_subdev *sd,
        unsigned int i;
 
        for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
-               ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i);
-               crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
+               ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i);
+               crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
                                                  V4L2_SEL_TGT_CROP);
-               comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
+               comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
                                                  V4L2_SEL_TGT_COMPOSE);
        }
 }
 
 static void isp_subdev_propagate(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 u32 which, uint32_t pad, uint32_t target,
                                 uint32_t flags)
 {
@@ -313,7 +314,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
        if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
                return;
 
-       isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
+       isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
 
        switch (pad) {
        case ATOMISP_SUBDEV_PAD_SINK: {
@@ -323,7 +324,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
                r.width = ffmt[pad]->width;
                r.height = ffmt[pad]->height;
 
-               atomisp_subdev_set_selection(sd, cfg, which, pad,
+               atomisp_subdev_set_selection(sd, sd_state, which, pad,
                                             target, flags, &r);
                break;
        }
@@ -331,7 +332,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
 }
 
 static int isp_subdev_get_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        struct v4l2_rect *rec;
@@ -340,7 +341,7 @@ static int isp_subdev_get_selection(struct v4l2_subdev *sd,
        if (rval)
                return rval;
 
-       rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad,
+       rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad,
                                      sel->target);
        if (!rec)
                return -EINVAL;
@@ -365,7 +366,7 @@ static const char *atomisp_pad_str(unsigned int pad)
 }
 
 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 u32 which, uint32_t pad, uint32_t target,
                                 u32 flags, struct v4l2_rect *r)
 {
@@ -382,7 +383,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
 
        stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
 
-       isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
+       isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
 
        dev_dbg(isp->dev,
                "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
@@ -450,7 +451,8 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
                                struct v4l2_rect tmp = *crop[pad];
 
                                atomisp_subdev_set_selection(
-                                   sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE,
+                                   sd, sd_state, which, i,
+                                   V4L2_SEL_TGT_COMPOSE,
                                    flags, &tmp);
                        }
                }
@@ -472,9 +474,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
                         * when dvs is disabled.
                         */
                        dvs_w = dvs_h = 12;
-               } else
+               } else {
                        dvs_w = dvs_h = 0;
-
+               }
                atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
                atomisp_css_input_set_effective_resolution(isp_sd, stream_id,
                        crop[pad]->width, crop[pad]->height);
@@ -551,9 +553,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
                ffmt[pad]->height = comp[pad]->height;
        }
 
-       if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target))
+       if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target))
                return -EINVAL;
-       *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target);
+       *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target);
 
        dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
                r->left, r->top, r->width, r->height);
@@ -562,7 +564,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
 }
 
 static int isp_subdev_set_selection(struct v4l2_subdev *sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_selection *sel)
 {
        int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
@@ -570,7 +572,8 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd,
        if (rval)
                return rval;
 
-       return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad,
+       return atomisp_subdev_set_selection(sd, sd_state, sel->which,
+                                           sel->pad,
                                            sel->target, sel->flags, &sel->r);
 }
 
@@ -609,13 +612,14 @@ static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
 }
 
 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg, uint32_t which,
+                            struct v4l2_subdev_state *sd_state,
+                            uint32_t which,
                             u32 pad, struct v4l2_mbus_framefmt *ffmt)
 {
        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
        struct atomisp_device *isp = isp_sd->isp;
        struct v4l2_mbus_framefmt *__ffmt =
-           atomisp_subdev_get_ffmt(sd, cfg, which, pad);
+           atomisp_subdev_get_ffmt(sd, sd_state, which, pad);
        u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode);
        enum atomisp_input_stream_id stream_id;
 
@@ -640,7 +644,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
 
                *__ffmt = *ffmt;
 
-               isp_subdev_propagate(sd, cfg, which, pad,
+               isp_subdev_propagate(sd, sd_state, which, pad,
                                     V4L2_SEL_TGT_CROP, 0);
 
                if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
@@ -679,10 +683,11 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int isp_subdev_get_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
-       fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad);
+       fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which,
+                                              fmt->pad);
 
        return 0;
 }
@@ -698,10 +703,11 @@ static int isp_subdev_get_format(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int isp_subdev_set_format(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
-       atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format);
+       atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
+                               &fmt->format);
 
        return 0;
 }
index 330a77e..d6fcfab 100644 (file)
@@ -437,19 +437,20 @@ uint16_t atomisp_subdev_source_pad(struct video_device *vdev);
 /* Get pointer to appropriate format */
 struct v4l2_mbus_framefmt
 *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg, uint32_t which,
+                        struct v4l2_subdev_state *sd_state, uint32_t which,
                         uint32_t pad);
 struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
-       struct v4l2_subdev_pad_config *cfg,
+       struct v4l2_subdev_state *sd_state,
        u32 which, uint32_t pad,
        uint32_t target);
 int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 u32 which, uint32_t pad, uint32_t target,
                                 u32 flags, struct v4l2_rect *r);
 /* Actually set the format */
 void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg, uint32_t which,
+                            struct v4l2_subdev_state *sd_state,
+                            uint32_t which,
                             u32 pad, struct v4l2_mbus_framefmt *ffmt);
 
 int atomisp_update_run_mode(struct atomisp_sub_device *asd);
index 1def80b..e29a96d 100644 (file)
@@ -29,7 +29,7 @@ static int tpg_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int tpg_get_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *format)
 {
        /*to fake*/
@@ -37,7 +37,7 @@ static int tpg_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int tpg_set_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *format)
 {
        struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd,
        /* only raw8 grbg is supported by TPG */
        fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
+               sd_state->pads->try_fmt = *fmt;
                return 0;
        }
        return 0;
@@ -65,7 +65,7 @@ static int tpg_s_power(struct v4l2_subdev *sd, int on)
 }
 
 static int tpg_enum_mbus_code(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        /*to fake*/
@@ -73,7 +73,7 @@ static int tpg_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int tpg_enum_frame_size(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        /*to fake*/
@@ -81,7 +81,7 @@ static int tpg_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int tpg_enum_frame_ival(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_interval_enum *fie)
 {
        /*to fake*/
index 0295e2e..948769c 100644 (file)
@@ -1178,7 +1178,7 @@ static void atomisp_unregister_entities(struct atomisp_device *isp)
                atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]);
 
        list_for_each_entry_safe(sd, next, &isp->v4l2_dev.subdevs, list)
-       v4l2_device_unregister_subdev(sd);
+               v4l2_device_unregister_subdev(sd);
 
        v4l2_device_unregister(&isp->v4l2_dev);
        media_device_unregister(&isp->media_dev);
@@ -1500,9 +1500,9 @@ static int init_atomisp_wdts(struct atomisp_device *isp)
        for (i = 0; i < isp->num_of_streams; i++) {
                struct atomisp_sub_device *asd = &isp->asd[i];
 
-               if (!IS_ISP2401)
+               if (!IS_ISP2401) {
                        timer_setup(&asd->wdt, atomisp_wdt, 0);
-               else {
+               else {
                        timer_setup(&asd->video_out_capture.wdt,
                                    atomisp_wdt, 0);
                        timer_setup(&asd->video_out_preview.wdt,
index 27dd8ce..d26b130 100644 (file)
@@ -239,8 +239,8 @@ ia_css_reset_defaults(struct sh_css *css);
 static void
 sh_css_init_host_sp_control_vars(void);
 
-static int set_num_primary_stages(unsigned int *num,
-       enum ia_css_pipe_version version);
+static int
+set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version);
 
 static bool
 need_capture_pp(const struct ia_css_pipe *pipe);
@@ -308,8 +308,7 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
                              const void *acc_fw);
 
 static int
-alloc_continuous_frames(
-    struct ia_css_pipe *pipe, bool init_time);
+alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
 
 static void
 pipe_global_init(void);
@@ -413,7 +412,6 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
 static void
 sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe)
 {
-       assert(pipe);
        if (!pipe) {
                IA_CSS_ERROR("NULL input parameter");
                return;
@@ -453,15 +451,15 @@ static enum ia_css_frame_format yuv422_copy_formats[] = {
  * by the copy binary given the stream format.
  * */
 static int
-verify_copy_out_frame_format(struct ia_css_pipe *pipe) {
+verify_copy_out_frame_format(struct ia_css_pipe *pipe)
+{
        enum ia_css_frame_format out_fmt = pipe->output_info[0].format;
        unsigned int i, found = 0;
 
        assert(pipe);
        assert(pipe->stream);
 
-       switch (pipe->stream->config.input_config.format)
-       {
+       switch (pipe->stream->config.input_config.format) {
        case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
        case ATOMISP_INPUT_FORMAT_YUV420_8:
                for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++)
@@ -528,7 +526,8 @@ ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream)
 
 #if !defined(ISP2401)
 static int
-sh_css_config_input_network(struct ia_css_stream *stream) {
+sh_css_config_input_network(struct ia_css_stream *stream)
+{
        unsigned int fmt_type;
        struct ia_css_pipe *pipe = stream->last_pipe;
        struct ia_css_binary *binary = NULL;
@@ -554,8 +553,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
                                        stream->config.mode);
 
        if ((binary && (binary->online || stream->config.continuous)) ||
-           pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
-       {
+           pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
                err = ia_css_ifmtr_configure(&stream->config,
                                             binary);
                if (err)
@@ -563,8 +561,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
        }
 
        if (stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
-           stream->config.mode == IA_CSS_INPUT_MODE_PRBS)
-       {
+           stream->config.mode == IA_CSS_INPUT_MODE_PRBS) {
                unsigned int hblank_cycles = 100,
                vblank_lines = 6,
                width,
@@ -723,35 +720,32 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_id(
        switch (stream_cfg->mode) {
        case IA_CSS_INPUT_MODE_TPG:
 
-               if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0) {
+               if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
-               } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1) {
+               else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
-               } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2) {
+               else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
-               }
 
                break;
        case IA_CSS_INPUT_MODE_PRBS:
 
-               if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0) {
+               if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
-               } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1) {
+               else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
-               } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2) {
+               else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
-               }
 
                break;
        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 
-               if (stream_cfg->source.port.port == MIPI_PORT0_ID) {
+               if (stream_cfg->source.port.port == MIPI_PORT0_ID)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID;
-               } else if (stream_cfg->source.port.port == MIPI_PORT1_ID) {
+               else if (stream_cfg->source.port.port == MIPI_PORT1_ID)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID;
-               } else if (stream_cfg->source.port.port == MIPI_PORT2_ID) {
+               else if (stream_cfg->source.port.port == MIPI_PORT2_ID)
                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID;
-               }
 
                break;
        default:
@@ -804,15 +798,14 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr(
        rc = true;
        switch (stream_cfg->mode) {
        case IA_CSS_INPUT_MODE_TPG:
-               if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP) {
+               if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP)
                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP;
-               } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD) {
+               else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD)
                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO;
-               } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO) {
+               else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO)
                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO;
-               } else {
+               else
                        rc = false;
-               }
 
                /*
                 * TODO
@@ -951,12 +944,12 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
             stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) &&
            stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) {
                if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
-                   UNCOMPRESSED_BITS_PER_PIXEL_10) {
+                   UNCOMPRESSED_BITS_PER_PIXEL_10)
                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_10;
-               else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
-                          UNCOMPRESSED_BITS_PER_PIXEL_12) {
+               else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
+                          UNCOMPRESSED_BITS_PER_PIXEL_12)
                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_12;
-               else
+               else
                        return false;
        }
 
@@ -1045,7 +1038,8 @@ static bool sh_css_translate_binary_info_to_input_system_output_port_attr(
 }
 
 static int
-sh_css_config_input_network(struct ia_css_stream *stream) {
+sh_css_config_input_network(struct ia_css_stream *stream)
+{
        bool                                    rc;
        ia_css_isys_descr_t                     isys_stream_descr;
        unsigned int                            sp_thread_id;
@@ -1060,19 +1054,16 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
                            "sh_css_config_input_network() enter 0x%p:\n", stream);
 
-       if (stream->config.continuous)
-       {
-               if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
+       if (stream->config.continuous) {
+               if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)
                        pipe = stream->last_pipe;
-               } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP) {
+               else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP)
                        pipe = stream->last_pipe;
-               } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
+               else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
                        pipe = stream->last_pipe->pipe_settings.preview.copy_pipe;
-               } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
+               else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO)
                        pipe = stream->last_pipe->pipe_settings.video.copy_pipe;
-               }
-       } else
-       {
+       } else {
                pipe = stream->last_pipe;
                if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
                        /*
@@ -1087,7 +1078,6 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
                }
        }
 
-       assert(pipe);
        if (!pipe)
                return -EINVAL;
 
@@ -1095,8 +1085,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
                if (pipe->pipeline.stages->binary)
                        binary = pipe->pipeline.stages->binary;
 
-       if (binary)
-       {
+       if (binary) {
                /* this was being done in ifmtr in 2400.
                 * online and cont bypass the init_in_frameinfo_memory_defaults
                 * so need to do it here
@@ -1111,8 +1100,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
        /* get the target input terminal */
        sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input;
 
-       for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++)
-       {
+       for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
                /* initialization */
                memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t));
                sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0;
@@ -1210,11 +1198,10 @@ static inline struct ia_css_pipe *stream_get_target_pipe(
        struct ia_css_pipe *target_pipe;
 
        /* get the pipe that consumes the stream */
-       if (stream->config.continuous) {
+       if (stream->config.continuous)
                target_pipe = stream_get_copy_pipe(stream);
-       } else {
+       else
                target_pipe = stream_get_last_pipe(stream);
-       }
 
        return target_pipe;
 }
@@ -1388,10 +1375,9 @@ start_binary(struct ia_css_pipe *pipe,
 /* start the copy function on the SP */
 static int
 start_copy_on_sp(struct ia_css_pipe *pipe,
-                struct ia_css_frame *out_frame) {
+                struct ia_css_frame *out_frame)
+{
        (void)out_frame;
-       assert(pipe);
-       assert(pipe->stream);
 
        if ((!pipe) || (!pipe->stream))
                return -EINVAL;
@@ -1406,8 +1392,7 @@ start_copy_on_sp(struct ia_css_pipe *pipe,
        sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2);
 
 #if !defined(ISP2401)
-       if (pipe->stream->reconfigure_css_rx)
-       {
+       if (pipe->stream->reconfigure_css_rx) {
                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
                                         pipe->stream->config.mode);
                pipe->stream->reconfigure_css_rx = false;
@@ -1596,7 +1581,8 @@ ia_css_reset_defaults(struct sh_css *css)
 
 int
 ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
-                    const struct ia_css_fw  *fw) {
+                    const struct ia_css_fw  *fw)
+{
        int err;
 
        if (!env)
@@ -1607,16 +1593,14 @@ ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n");
 
        /* make sure we initialize my_css */
-       if (my_css.flush != env->cpu_mem_env.flush)
-       {
+       if (my_css.flush != env->cpu_mem_env.flush) {
                ia_css_reset_defaults(&my_css);
                my_css.flush = env->cpu_mem_env.flush;
        }
 
        ia_css_unload_firmware(); /* in case we are called twice */
        err = sh_css_load_firmware(dev, fw->data, fw->bytes);
-       if (!err)
-       {
+       if (!err) {
                err = ia_css_binary_init_infos();
                if (!err)
                        fw_explicitly_loaded = true;
@@ -1630,7 +1614,8 @@ int
 ia_css_init(struct device *dev, const struct ia_css_env *env,
            const struct ia_css_fw  *fw,
            u32                 mmu_l1_base,
-           enum ia_css_irq_type     irq_type) {
+           enum ia_css_irq_type     irq_type)
+{
        int err;
        ia_css_spctrl_cfg spctrl_cfg;
 
@@ -1704,16 +1689,14 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
        my_css.flush     = flush_func;
 
        err = ia_css_rmgr_init();
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
 
        IA_CSS_LOG("init: %d", my_css_save_initialized);
 
-       if (!my_css_save_initialized)
-       {
+       if (!my_css_save_initialized) {
                my_css_save_initialized = true;
                my_css_save.mode = sh_css_mode_working;
                memset(my_css_save.stream_seeds, 0,
@@ -1741,19 +1724,16 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0);
 
        err = ia_css_refcount_init(REFCOUNT_SIZE);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
        err = sh_css_params_init();
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
-       if (fw)
-       {
+       if (fw) {
                ia_css_unload_firmware(); /* in case we already had firmware loaded */
                err = sh_css_load_firmware(dev, fw->data, fw->bytes);
                if (err) {
@@ -1774,23 +1754,20 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
                return -EINVAL;
 
        err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
 
 #if WITH_PC_MONITORING
-       if (!thread_alive)
-       {
+       if (!thread_alive) {
                thread_alive++;
                sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n",
                             __func__);
                spying_thread_create();
        }
 #endif
-       if (!sh_css_hrt_system_is_idle())
-       {
+       if (!sh_css_hrt_system_is_idle()) {
                IA_CSS_LEAVE_ERR(-EBUSY);
                return -EBUSY;
        }
@@ -1823,7 +1800,8 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
 }
 
 int
-ia_css_enable_isys_event_queue(bool enable) {
+ia_css_enable_isys_event_queue(bool enable)
+{
        if (sh_css_sp_is_running())
                return -EBUSY;
        sh_css_sp_enable_isys_event_queue(enable);
@@ -1844,7 +1822,8 @@ sh_css_flush(struct ia_css_acc_fw *fw)
  * doing it from stream_create since we could run out of sp threads due to
  * allocation on inactive pipelines. */
 static int
-map_sp_threads(struct ia_css_stream *stream, bool map) {
+map_sp_threads(struct ia_css_stream *stream, bool map)
+{
        struct ia_css_pipe *main_pipe = NULL;
        struct ia_css_pipe *copy_pipe = NULL;
        struct ia_css_pipe *capture_pipe = NULL;
@@ -1852,12 +1831,10 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
        int err = 0;
        enum ia_css_pipe_id pipe_id;
 
-       assert(stream);
        IA_CSS_ENTER_PRIVATE("stream = %p, map = %s",
                             stream, map ? "true" : "false");
 
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -1867,8 +1844,7 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
 
        ia_css_pipeline_map(main_pipe->pipe_num, map);
 
-       switch (pipe_id)
-       {
+       switch (pipe_id) {
        case IA_CSS_PIPE_ID_PREVIEW:
                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
@@ -1887,23 +1863,17 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
        }
 
        if (acc_pipe)
-       {
                ia_css_pipeline_map(acc_pipe->pipe_num, map);
-       }
 
        if (capture_pipe)
-       {
                ia_css_pipeline_map(capture_pipe->pipe_num, map);
-       }
 
        /* Firmware expects copy pipe to be the last pipe mapped. (if needed) */
        if (copy_pipe)
-       {
                ia_css_pipeline_map(copy_pipe->pipe_num, map);
-       }
+
        /* DH regular multi pipe - not continuous mode: map the next pipes too */
-       if (!stream->config.continuous)
-       {
+       if (!stream->config.continuous) {
                int i;
 
                for (i = 1; i < stream->num_pipes; i++)
@@ -1917,7 +1887,8 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
 /* creates a host pipeline skeleton for all pipes in a stream. Called during
  * stream_create. */
 static int
-create_host_pipeline_structure(struct ia_css_stream *stream) {
+create_host_pipeline_structure(struct ia_css_stream *stream)
+{
        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
        struct ia_css_pipe *acc_pipe = NULL;
        enum ia_css_pipe_id pipe_id;
@@ -1926,27 +1897,22 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
        unsigned int copy_pipe_delay = 0,
        capture_pipe_delay = 0;
 
-       assert(stream);
        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
 
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
 
        main_pipe       = stream->last_pipe;
-       assert(main_pipe);
-       if (!main_pipe)
-       {
+       if (!main_pipe) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
 
        pipe_id = main_pipe->mode;
 
-       switch (pipe_id)
-       {
+       switch (pipe_id) {
        case IA_CSS_PIPE_ID_PREVIEW:
                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
                copy_pipe_delay = main_pipe->dvs_frame_delay;
@@ -1986,30 +1952,23 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
        }
 
        if (!(err) && copy_pipe)
-       {
                err = ia_css_pipeline_create(&copy_pipe->pipeline,
                                             copy_pipe->mode,
                                             copy_pipe->pipe_num,
                                             copy_pipe_delay);
-       }
 
        if (!(err) && capture_pipe)
-       {
                err = ia_css_pipeline_create(&capture_pipe->pipeline,
                                             capture_pipe->mode,
                                             capture_pipe->pipe_num,
                                             capture_pipe_delay);
-       }
 
        if (!(err) && acc_pipe)
-       {
                err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
                                             acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
-       }
 
        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
-       if (!stream->config.continuous)
-       {
+       if (!stream->config.continuous) {
                int i;
 
                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
@@ -2028,7 +1987,8 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
 /* creates a host pipeline for all pipes in a stream. Called during
  * stream_start. */
 static int
-create_host_pipeline(struct ia_css_stream *stream) {
+create_host_pipeline(struct ia_css_stream *stream)
+{
        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
        struct ia_css_pipe *acc_pipe = NULL;
        enum ia_css_pipe_id pipe_id;
@@ -2037,8 +1997,7 @@ create_host_pipeline(struct ia_css_stream *stream) {
        unsigned int max_input_width = 0;
 
        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -2049,8 +2008,7 @@ create_host_pipeline(struct ia_css_stream *stream) {
        /* No continuous frame allocation for capture pipe. It uses the
         * "main" pipe's frames. */
        if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
-           (pipe_id == IA_CSS_PIPE_ID_VIDEO))
-       {
+           (pipe_id == IA_CSS_PIPE_ID_VIDEO)) {
                /* About pipe_id == IA_CSS_PIPE_ID_PREVIEW && stream->config.mode != IA_CSS_INPUT_MODE_MEMORY:
                 * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is too strong. E.g. in SkyCam (with memory
                 * based input frames) there is no continuous mode and thus no need for allocated continuous frames
@@ -2068,24 +2026,21 @@ create_host_pipeline(struct ia_css_stream *stream) {
 
 #if !defined(ISP2401)
        /* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
-       if (pipe_id != IA_CSS_PIPE_ID_ACC)
-       {
+       if (pipe_id != IA_CSS_PIPE_ID_ACC) {
                err = allocate_mipi_frames(main_pipe, &stream->info);
                if (err)
                        goto ERR;
        }
 #elif defined(ISP2401)
        if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
-           (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY))
-       {
+           (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
                err = allocate_mipi_frames(main_pipe, &stream->info);
                if (err)
                        goto ERR;
        }
 #endif
 
-       switch (pipe_id)
-       {
+       switch (pipe_id) {
        case IA_CSS_PIPE_ID_PREVIEW:
                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
@@ -2135,31 +2090,27 @@ create_host_pipeline(struct ia_css_stream *stream) {
        if (err)
                goto ERR;
 
-       if (copy_pipe)
-       {
+       if (copy_pipe) {
                err = create_host_copy_pipeline(copy_pipe, max_input_width,
                                                main_pipe->continuous_frames[0]);
                if (err)
                        goto ERR;
        }
 
-       if (capture_pipe)
-       {
+       if (capture_pipe) {
                err = create_host_capture_pipeline(capture_pipe);
                if (err)
                        goto ERR;
        }
 
-       if (acc_pipe)
-       {
+       if (acc_pipe) {
                err = create_host_acc_pipeline(acc_pipe);
                if (err)
                        goto ERR;
        }
 
        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
-       if (!stream->config.continuous)
-       {
+       if (!stream->config.continuous) {
                int i;
 
                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
@@ -2201,10 +2152,9 @@ static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
 static int
 init_pipe_defaults(enum ia_css_pipe_mode mode,
                   struct ia_css_pipe *pipe,
-                  bool copy_pipe) {
-
-       if (!pipe)
-       {
+                  bool copy_pipe)
+{
+       if (!pipe) {
                IA_CSS_ERROR("NULL pipe parameter");
                return -EINVAL;
        }
@@ -2213,18 +2163,17 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
        memcpy(pipe, &default_pipe, sizeof(default_pipe));
 
        /* TODO: JB should not be needed, but temporary backward reference */
-       switch (mode)
-       {
+       switch (mode) {
        case IA_CSS_PIPE_MODE_PREVIEW:
                pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
                memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview));
                break;
        case IA_CSS_PIPE_MODE_CAPTURE:
-               if (copy_pipe) {
+               if (copy_pipe)
                        pipe->mode = IA_CSS_PIPE_ID_COPY;
-               } else {
+               else
                        pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
-               }
+
                memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture));
                break;
        case IA_CSS_PIPE_MODE_VIDEO:
@@ -2254,27 +2203,25 @@ pipe_global_init(void)
        u8 i;
 
        my_css.pipe_counter = 0;
-       for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
+       for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
                my_css.all_pipes[i] = NULL;
-       }
 }
 
 static int
 pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
-                      unsigned int *pipe_number) {
+                      unsigned int *pipe_number)
+{
        const u8 INVALID_PIPE_NUM = (uint8_t)~(0);
        u8 pipe_num = INVALID_PIPE_NUM;
        u8 i;
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_ERROR("NULL pipe parameter");
                return -EINVAL;
        }
 
        /* Assign a new pipe_num .... search for empty place */
-       for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
-       {
+       for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
                if (!my_css.all_pipes[i]) {
                        /*position is reserved */
                        my_css.all_pipes[i] = (struct ia_css_pipe *)pipe;
@@ -2282,8 +2229,7 @@ pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
                        break;
                }
        }
-       if (pipe_num == INVALID_PIPE_NUM)
-       {
+       if (pipe_num == INVALID_PIPE_NUM) {
                /* Max number of pipes already allocated */
                IA_CSS_ERROR("Max number of pipes already created");
                return -ENOSPC;
@@ -2309,12 +2255,12 @@ pipe_release_pipe_num(unsigned int pipe_num)
 static int
 create_pipe(enum ia_css_pipe_mode mode,
            struct ia_css_pipe **pipe,
-           bool copy_pipe) {
+           bool copy_pipe)
+{
        int err = 0;
        struct ia_css_pipe *me;
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_ERROR("NULL pipe parameter");
                return -EINVAL;
        }
@@ -2324,15 +2270,13 @@ create_pipe(enum ia_css_pipe_mode mode,
                return -ENOMEM;
 
        err = init_pipe_defaults(mode, me, copy_pipe);
-       if (err)
-       {
+       if (err) {
                kfree(me);
                return err;
        }
 
        err = pipe_generate_pipe_num(me, &me->pipe_num);
-       if (err)
-       {
+       if (err) {
                kfree(me);
                return err;
        }
@@ -2361,7 +2305,6 @@ static void sh_css_pipe_free_acc_binaries(
        struct ia_css_pipeline *pipeline;
        struct ia_css_pipeline_stage *stage;
 
-       assert(pipe);
        if (!pipe) {
                IA_CSS_ERROR("NULL input pointer");
                return;
@@ -2378,26 +2321,24 @@ static void sh_css_pipe_free_acc_binaries(
 }
 
 int
-ia_css_pipe_destroy(struct ia_css_pipe *pipe) {
+ia_css_pipe_destroy(struct ia_css_pipe *pipe)
+{
        int err = 0;
 
        IA_CSS_ENTER("pipe = %p", pipe);
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       if (pipe->stream)
-       {
+       if (pipe->stream) {
                IA_CSS_LOG("ia_css_stream_destroy not called!");
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       switch (pipe->config.mode)
-       {
+       switch (pipe->config.mode) {
        case IA_CSS_PIPE_MODE_PREVIEW:
                /* need to take into account that this function is also called
                   on the internal copy pipe */
@@ -2461,9 +2402,8 @@ ia_css_pipe_destroy(struct ia_css_pipe *pipe) {
 
        /* Temporarily, not every sh_css_pipe has an acc_extension. */
        if (pipe->config.acc_extension)
-       {
                ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
-       }
+
        kfree(pipe);
        IA_CSS_LEAVE("err = %d", err);
        return err;
@@ -2493,9 +2433,9 @@ ia_css_uninit(void)
        ifmtr_set_if_blocking_mode_reset = true;
 #endif
 
-       if (!fw_explicitly_loaded) {
+       if (!fw_explicitly_loaded)
                ia_css_unload_firmware();
-       }
+
        ia_css_spctrl_unload_fw(SP0_ID);
        sh_css_sp_set_sp_running(false);
        /* check and free any remaining mipi frames */
@@ -2681,8 +2621,8 @@ static int load_copy_binary(
 }
 
 static int
-alloc_continuous_frames(
-    struct ia_css_pipe *pipe, bool init_time) {
+alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time)
+{
        int err = 0;
        struct ia_css_frame_info ref_info;
        enum ia_css_pipe_id pipe_id;
@@ -2692,8 +2632,7 @@ alloc_continuous_frames(
 
        IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time);
 
-       if ((!pipe) || (!pipe->stream))
-       {
+       if ((!pipe) || (!pipe->stream)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -2701,26 +2640,22 @@ alloc_continuous_frames(
        pipe_id = pipe->mode;
        continuous = pipe->stream->config.continuous;
 
-       if (continuous)
-       {
+       if (continuous) {
                if (init_time) {
                        num_frames = pipe->stream->config.init_num_cont_raw_buf;
                        pipe->stream->continuous_pipe = pipe;
-               } else
+               } else {
                        num_frames = pipe->stream->config.target_num_cont_raw_buf;
-       } else
-       {
+               }
+       } else {
                num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES;
        }
 
-       if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
-       {
+       if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
                ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info;
-       } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
-       {
+       } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
                ref_info = pipe->pipe_settings.video.video_binary.in_frame_info;
-       } else
-       {
+       } else {
                /* should not happen */
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
@@ -2736,8 +2671,7 @@ alloc_continuous_frames(
 #endif
 
 #if !defined(HAS_NO_PACKED_RAW_PIXELS)
-       if (pipe->stream->config.pack_raw_pixels)
-       {
+       if (pipe->stream->config.pack_raw_pixels) {
                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
                                    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n");
                ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED;
@@ -2766,8 +2700,7 @@ alloc_continuous_frames(
        else
                idx = pipe->stream->config.init_num_cont_raw_buf;
 
-       for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++)
-       {
+       for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) {
                /* free previous frame */
                if (pipe->continuous_frames[i]) {
                        ia_css_frame_free(pipe->continuous_frames[i]);
@@ -2797,14 +2730,16 @@ alloc_continuous_frames(
 }
 
 int
-ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream) {
+ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream)
+{
        if (!stream)
                return -EINVAL;
        return alloc_continuous_frames(stream->continuous_pipe, false);
 }
 
 static int
-load_preview_binaries(struct ia_css_pipe *pipe) {
+load_preview_binaries(struct ia_css_pipe *pipe)
+{
        struct ia_css_frame_info prev_in_info,
                prev_bds_out_info,
                prev_out_info,
@@ -2912,8 +2847,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
         * then the preview binary selection is done again.
         */
        if (need_vf_pp &&
-           (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE))
-       {
+           (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) {
                /* Preview step 2 */
                if (pipe->vf_yuv_ds_input_info.res.width)
                        prev_vf_info = pipe->vf_yuv_ds_input_info;
@@ -2938,8 +2872,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
                        return err;
        }
 
-       if (need_vf_pp)
-       {
+       if (need_vf_pp) {
                struct ia_css_binary_descr vf_pp_descr;
 
                /* Viewfinder post-processing */
@@ -2970,8 +2903,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
 #endif
 
        /* Copy */
-       if (need_isp_copy_binary)
-       {
+       if (need_isp_copy_binary) {
                err = load_copy_binary(pipe,
                                       &mycs->copy_binary,
                                       &mycs->preview_binary);
@@ -2979,8 +2911,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
                        return err;
        }
 
-       if (pipe->shading_table)
-       {
+       if (pipe->shading_table) {
                ia_css_shading_table_free(pipe->shading_table);
                pipe->shading_table = NULL;
        }
@@ -2995,11 +2926,11 @@ ia_css_binary_unload(struct ia_css_binary *binary)
 }
 
 static int
-unload_preview_binaries(struct ia_css_pipe *pipe) {
+unload_preview_binaries(struct ia_css_pipe *pipe)
+{
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
 
-       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
-       {
+       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -3052,20 +2983,19 @@ static int add_firmwares(
                struct ia_css_frame *in = NULL;
                struct ia_css_frame *vf = NULL;
 
-               if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame  != 0)) {
+               if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame  != 0))
                        out[0] = out_frame;
-               }
-               if (fw->info.isp.sp.enable.in_frame != 0) {
+
+               if (fw->info.isp.sp.enable.in_frame != 0)
                        in = in_frame;
-               }
-               if (fw->info.isp.sp.enable.out_frame != 0) {
+
+               if (fw->info.isp.sp.enable.out_frame != 0)
                        vf = vf_frame;
-               }
+
                ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary,
                                                     out, in, vf, fw, binary_mode);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       &extra_stage);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          &extra_stage);
                if (err)
                        return err;
                if (fw->info.isp.sp.enable.output != 0)
@@ -3173,9 +3103,8 @@ static int add_yuv_scaler_stage(
                ia_css_pipe_get_generic_stage_desc(&stage_desc,
                                                   yuv_scaler_binary, out_frames, in_frame, vf_frame);
        }
-       err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc,
-               pre_vf_pp_stage);
+       err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                  pre_vf_pp_stage);
        if (err)
                return err;
        in_frame = (*pre_vf_pp_stage)->args.out_frame[0];
@@ -3233,9 +3162,8 @@ static int add_capture_pp_stage(
                ia_css_pipe_get_generic_stage_desc(&stage_desc,
                                                   capture_pp_binary, out_frames, NULL, vf_frame);
        }
-       err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc,
-               capture_pp_stage);
+       err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                  capture_pp_stage);
        if (err)
                return err;
        err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw,
@@ -3274,7 +3202,8 @@ static void sh_css_setup_queues(void)
 
 static int
 init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
-                          struct ia_css_frame *vf_frame, unsigned int idx) {
+                          struct ia_css_frame *vf_frame, unsigned int idx)
+{
        int err = 0;
        unsigned int thread_id;
        enum sh_css_queue_id queue_id;
@@ -3439,7 +3368,8 @@ ia_css_get_crop_offsets(
 
 static int
 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
-                                 struct ia_css_frame *frame, enum ia_css_frame_format format) {
+                                 struct ia_css_frame *frame, enum ia_css_frame_format format)
+{
        struct ia_css_frame *in_frame;
        int err = 0;
        unsigned int thread_id;
@@ -3480,7 +3410,8 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
 
 static int
 init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
-                           struct ia_css_frame *out_frame, unsigned int idx) {
+                           struct ia_css_frame *out_frame, unsigned int idx)
+{
        int err = 0;
        unsigned int thread_id;
        enum sh_css_queue_id queue_id;
@@ -3587,9 +3518,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
                                                   out_frames, NULL, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       &copy_stage);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          &copy_stage);
                if (err)
                        goto ERR;
                in_frame = me->stages->args.out_frame[0];
@@ -3616,9 +3546,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
                                                   out_frames, in_frame, vf_frame);
        }
-       err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc,
-               &video_stage);
+       err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                  &video_stage);
        if (err)
                goto ERR;
 
@@ -3681,13 +3610,10 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
                struct ia_css_frame *tmp_out_frame = NULL;
 
                for (i = 0; i < num_yuv_scaler; i++) {
-                       if (is_output_stage[i]) {
-                               tmp_out_frame = out_frame;
-                       } else {
-                               tmp_out_frame = NULL;
-                       }
-                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
-                                                  NULL,
+                       tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
+
+                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+                                                  tmp_out_frame, NULL,
                                                   &yuv_scaler_binary[i],
                                                   &yuv_scaler_stage);
 
@@ -3711,14 +3637,14 @@ ERR:
 }
 
 static int
-create_host_acc_pipeline(struct ia_css_pipe *pipe) {
+create_host_acc_pipeline(struct ia_css_pipe *pipe)
+{
        int err = 0;
        const struct ia_css_fw_info *fw;
        unsigned int i;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
-       if ((!pipe) || (!pipe->stream))
-       {
+       if ((!pipe) || (!pipe->stream)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -3729,15 +3655,13 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe) {
                pipe->pipeline.pipe_qos_config = 0;
 
        fw = pipe->vf_stage;
-       for (i = 0; fw; fw = fw->next)
-       {
+       for (i = 0; fw; fw = fw->next) {
                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
                if (err)
                        goto ERR;
        }
 
-       for (i = 0; i < pipe->config.num_acc_stages; i++)
-       {
+       for (i = 0; i < pipe->config.num_acc_stages; i++) {
                struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
 
                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
@@ -3754,7 +3678,8 @@ ERR:
 
 /* Create stages for preview */
 static int
-create_host_preview_pipeline(struct ia_css_pipe *pipe) {
+create_host_preview_pipeline(struct ia_css_pipe *pipe)
+{
        struct ia_css_pipeline_stage *copy_stage = NULL;
        struct ia_css_pipeline_stage *preview_stage = NULL;
        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
@@ -3774,8 +3699,7 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
 #endif
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
-       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
-       {
+       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -3803,16 +3727,14 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
        /* Construct in_frame info (only in case we have dynamic input */
        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
 #endif
-       if (need_in_frameinfo_memory)
-       {
+       if (need_in_frameinfo_memory) {
                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
                                                        IA_CSS_FRAME_FORMAT_RAW);
                if (err)
                        goto ERR;
 
                in_frame = &me->in_frame;
-       } else
-       {
+       } else {
                in_frame = NULL;
        }
 
@@ -3826,14 +3748,12 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
        if (pipe->pipe_settings.preview.vf_pp_binary.info)
                vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
 
-       if (pipe->pipe_settings.preview.copy_binary.info)
-       {
+       if (pipe->pipe_settings.preview.copy_binary.info) {
                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
                                                   out_frames, NULL, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       &copy_stage);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          &copy_stage);
                if (err)
                        goto ERR;
                in_frame = me->stages->args.out_frame[0];
@@ -3842,42 +3762,37 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
                /* When continuous is enabled, configure in_frame with the
                 * last pipe, which is the copy pipe.
                 */
-               if (continuous || !online) {
+               if (continuous || !online)
                        in_frame = pipe->stream->last_pipe->continuous_frames[0];
-               }
+
 #else
                in_frame = pipe->continuous_frames[0];
 #endif
        }
 
-       if (vf_pp_binary)
-       {
+       if (vf_pp_binary) {
                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
                                                   out_frames, in_frame, NULL);
-       } else
-       {
+       } else {
                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
                                                   out_frames, in_frame, NULL);
        }
-       err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc,
-               &preview_stage);
+       err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                  &preview_stage);
        if (err)
                goto ERR;
        /* If we use copy iso preview, the input must be yuv iso raw */
        preview_stage->args.copy_vf =
            preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
        preview_stage->args.copy_output = !preview_stage->args.copy_vf;
-       if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame)
-       {
+       if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
                /* in case of copy, use the vf frame as output frame */
                preview_stage->args.out_vf_frame =
                    preview_stage->args.out_frame[0];
        }
-       if (vf_pp_binary)
-       {
+       if (vf_pp_binary) {
                if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
                        in_frame = preview_stage->args.out_vf_frame;
                else
@@ -3917,7 +3832,8 @@ static void send_raw_frames(struct ia_css_pipe *pipe)
 }
 
 static int
-preview_start(struct ia_css_pipe *pipe) {
+preview_start(struct ia_css_pipe *pipe)
+{
        int err = 0;
        struct ia_css_pipe *copy_pipe, *capture_pipe;
        struct ia_css_pipe *acc_pipe;
@@ -3927,8 +3843,7 @@ preview_start(struct ia_css_pipe *pipe) {
        const struct ia_css_isp_parameters *params = NULL;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
-       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
-       {
+       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -3955,8 +3870,7 @@ preview_start(struct ia_css_pipe *pipe) {
                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
                copy_ovrd = 1 << thread_id;
 
-               if (pipe->stream->cont_capt)
-               {
+               if (pipe->stream->cont_capt) {
                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
                                                         &thread_id);
                        copy_ovrd |= 1 << thread_id;
@@ -3969,8 +3883,7 @@ preview_start(struct ia_css_pipe *pipe) {
        }
 
        /* Construct and load the copy pipe */
-       if (pipe->stream->config.continuous)
-       {
+       if (pipe->stream->config.continuous) {
                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
                                        IA_CSS_PIPE_ID_COPY,
                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
@@ -3991,8 +3904,7 @@ preview_start(struct ia_css_pipe *pipe) {
        }
 
        /* Construct and load the capture pipe */
-       if (pipe->stream->cont_capt)
-       {
+       if (pipe->stream->cont_capt) {
                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
                                        IA_CSS_PIPE_ID_CAPTURE,
                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
@@ -4010,8 +3922,7 @@ preview_start(struct ia_css_pipe *pipe) {
                                        params);
        }
 
-       if (acc_pipe)
-       {
+       if (acc_pipe) {
                sh_css_sp_init_pipeline(&acc_pipe->pipeline,
                                        IA_CSS_PIPE_ID_ACC,
                                        (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
@@ -4037,7 +3948,8 @@ preview_start(struct ia_css_pipe *pipe) {
 
 int
 ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
-                          const struct ia_css_buffer *buffer) {
+                          const struct ia_css_buffer *buffer)
+{
        int return_err = 0;
        unsigned int thread_id;
        enum sh_css_queue_id queue_id;
@@ -4052,8 +3964,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
 
        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
 
-       if ((!pipe) || (!buffer))
-       {
+       if ((!pipe) || (!buffer)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
@@ -4062,8 +3973,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
        /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
           is removed */
 #if 0
-       if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
-       {
+       if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
                bool found_pipe = false;
 
                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
@@ -4077,8 +3987,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
                if (!found_pipe)
                        return -EINVAL;
        }
-       if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
-       {
+       if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
                bool found_pipe = false;
 
                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
@@ -4099,36 +4008,31 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
 
        assert(pipe_id < IA_CSS_PIPE_ID_NUM);
        assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
-       if ((buf_type == IA_CSS_BUFFER_TYPE_INVALID) ||
-           (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE) ||
-           (pipe_id >= IA_CSS_PIPE_ID_NUM))
-       {
+       if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
+           buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
+           pipe_id >= IA_CSS_PIPE_ID_NUM) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
-       if (!ret_err)
-       {
+       if (!ret_err) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
-       if (!ret_err)
-       {
+       if (!ret_err) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES))
-       {
+       if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       if (!sh_css_sp_is_running())
-       {
+       if (!sh_css_sp_is_running()) {
                IA_CSS_LOG("SP is not running!");
                IA_CSS_LEAVE_ERR(-EBUSY);
                /* SP is not running. The queues are not valid */
@@ -4146,36 +4050,32 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
        ddr_buffer.cookie_ptr = buffer->driver_cookie;
        ddr_buffer.timing_data = buffer->timing_data;
 
-       if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS)
-       {
+       if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
                if (!buffer->data.stats_3a) {
                        IA_CSS_LEAVE_ERR(-EINVAL);
                        return -EINVAL;
                }
                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
                ddr_buffer.payload.s3a = *buffer->data.stats_3a;
-       } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS)
-       {
+       } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
                if (!buffer->data.stats_dvs) {
                        IA_CSS_LEAVE_ERR(-EINVAL);
                        return -EINVAL;
                }
                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
                ddr_buffer.payload.dis = *buffer->data.stats_dvs;
-       } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA)
-       {
+       } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
                if (!buffer->data.metadata) {
                        IA_CSS_LEAVE_ERR(-EINVAL);
                        return -EINVAL;
                }
                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
                ddr_buffer.payload.metadata = *buffer->data.metadata;
-       } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME))
-       {
+       } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
                if (!buffer->data.frame) {
                        IA_CSS_LEAVE_ERR(-EINVAL);
                        return -EINVAL;
@@ -4207,22 +4107,17 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
        /* TODO: change next to correct pool for optimization */
        ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
 
-       assert(h_vbuf);
-       assert(h_vbuf->vptr != 0x0);
-
-       if ((!h_vbuf) || (h_vbuf->vptr == 0x0))
-       {
+       if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
        hmm_store(h_vbuf->vptr,
-                  (void *)(&ddr_buffer),
-                  sizeof(struct sh_css_hmm_buffer));
-       if ((buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS)
-           || (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS)
-           || (buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS))
-       {
+                 (void *)(&ddr_buffer),
+                 sizeof(struct sh_css_hmm_buffer));
+       if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
+           buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
+           buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
                if (!pipeline) {
                        ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
                        IA_CSS_LOG("pipeline is empty!");
@@ -4240,19 +4135,18 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
                                                                        (uint32_t)h_vbuf->vptr);
                        }
                }
-       } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME)
-                  || (buf_type == IA_CSS_BUFFER_TYPE_METADATA))
-       {
+       } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
+                  buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
                return_err = ia_css_bufq_enqueue_buffer(thread_id,
                                                        queue_id,
                                                        (uint32_t)h_vbuf->vptr);
 #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
-               if (!(return_err) &&
-                   (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)) {
+               if (!return_err &&
+                   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
                        IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
                                   ddr_buffer.payload.frame.frame_data,
                                   queue_id, thread_id);
@@ -4260,8 +4154,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
 #endif
        }
 
-       if (!return_err)
-       {
+       if (!return_err) {
                if (sh_css_hmm_buffer_record_acquire(
                        h_vbuf, buf_type,
                        HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
@@ -4276,8 +4169,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
         * Tell the SP which queues are not empty,
         * by sending the software event.
         */
-       if (!return_err)
-       {
+       if (!return_err) {
                if (!sh_css_sp_is_running()) {
                        /* SP is not running. The queues are not valid */
                        IA_CSS_LOG("SP is not running!");
@@ -4289,8 +4181,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
                                 (uint8_t)thread_id,
                                 queue_id,
                                 0);
-       } else
-       {
+       } else {
                ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
                IA_CSS_ERROR("buffer not enqueued");
        }
@@ -4305,7 +4196,8 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
         */
 int
 ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
-                          struct ia_css_buffer *buffer) {
+                          struct ia_css_buffer *buffer)
+{
        int return_err;
        enum sh_css_queue_id queue_id;
        ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
@@ -4318,8 +4210,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
 
        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
 
-       if ((!pipe) || (!buffer))
-       {
+       if ((!pipe) || (!buffer)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
@@ -4333,27 +4224,23 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
        ddr_buffer.kernel_ptr = 0;
 
        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
-       if (!ret_err)
-       {
+       if (!ret_err) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
-       if (!ret_err)
-       {
+       if (!ret_err) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES))
-       {
+       if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
-       if (!sh_css_sp_is_running())
-       {
+       if (!sh_css_sp_is_running()) {
                IA_CSS_LOG("SP is not running!");
                IA_CSS_LEAVE_ERR(-EBUSY);
                /* SP is not running. The queues are not valid */
@@ -4363,8 +4250,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
        return_err = ia_css_bufq_dequeue_buffer(queue_id,
                                                (uint32_t *)&ddr_buffer_addr);
 
-       if (!return_err)
-       {
+       if (!return_err) {
                struct ia_css_frame *frame;
                struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
 
@@ -4389,8 +4275,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
                }
 
                hmm_load(ddr_buffer_addr,
-                         &ddr_buffer,
-                         sizeof(struct sh_css_hmm_buffer));
+                        &ddr_buffer,
+                        sizeof(struct sh_css_hmm_buffer));
 
                /* if the kernel_ptr is 0 or an invalid, return an error.
                 * do not access the buffer via the kernal_ptr.
@@ -4412,8 +4298,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
                        buffer->driver_cookie = ddr_buffer.cookie_ptr;
                        buffer->timing_data = ddr_buffer.timing_data;
 
-                       if ((buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) ||
-                           (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)) {
+                       if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+                           buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
                                buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
                        }
 
@@ -4506,8 +4392,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
         * Tell the SP which queues are not full,
         * by sending the software event.
         */
-       if (!return_err)
-       {
+       if (!return_err) {
                if (!sh_css_sp_is_running()) {
                        IA_CSS_LOG("SP is not running!");
                        IA_CSS_LEAVE_ERR(-EBUSY);
@@ -4556,12 +4441,14 @@ static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
 };
 
 int
-ia_css_dequeue_event(struct ia_css_event *event) {
+ia_css_dequeue_event(struct ia_css_event *event)
+{
        return ia_css_dequeue_psys_event(event);
 }
 
 int
-ia_css_dequeue_psys_event(struct ia_css_event *event) {
+ia_css_dequeue_psys_event(struct ia_css_event *event)
+{
        enum ia_css_pipe_id pipe_id = 0;
        u8 payload[4] = {0, 0, 0, 0};
        int ret_err;
@@ -4576,11 +4463,9 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
        if (!event)
                return -EINVAL;
 
+       /* SP is not running. The queues are not valid */
        if (!sh_css_sp_is_running())
-       {
-               /* SP is not running. The queues are not valid */
                return -EBUSY;
-       }
 
        /* dequeue the event (if any) from the psys event queue */
        ret_err = ia_css_bufq_dequeue_psys_event(payload);
@@ -4607,8 +4492,7 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
        event->timer_code = 0;
        event->timer_subcode = 0;
 
-       if (event->type == IA_CSS_EVENT_TYPE_TIMER)
-       {
+       if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
                /* timer event ??? get the 2nd event and decode the data into the event struct */
                u32 tmp_data;
                /* 1st event: LSB 16-bit timer data and code */
@@ -4632,37 +4516,32 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
                        tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
                        event->timer_data |= (tmp_data << 16);
                        event->timer_subcode = payload[2];
-               }
+               } else {
                /* It's a non timer event. So clear first half of the timer event data.
                * If the second part of the TIMER event is not received, we discard
                * the first half of the timer data and process the non timer event without
                * affecting the flow. So the non timer event falls through
                * the code. */
-               else {
                        event->timer_data = 0;
                        event->timer_code = 0;
                        event->timer_subcode = 0;
                        IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
                }
        }
-       if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF)
-       {
+       if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
                event->port = (enum mipi_port_id)payload[1];
                event->exp_id = payload[3];
-       } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING)
-       {
+       } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
                event->fw_warning = (enum ia_css_fw_warning)payload[1];
                /* exp_id is only available in these warning types */
                if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
                    event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
                        event->exp_id = payload[3];
-       } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT)
-       {
+       } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
                event->fw_assert_module_id = payload[1]; /* module */
                event->fw_assert_line_no = (payload[2] << 8) + payload[3];
                /* payload[2] is line_no>>8, payload[3] is line_no&0xff */
-       } else if (event->type != IA_CSS_EVENT_TYPE_TIMER)
-       {
+       } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
                /* pipe related events.
                 * payload[1] contains the pipe_num,
                 * payload[2] contains the pipe_id. These are different. */
@@ -4712,7 +4591,8 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
 }
 
 int
-ia_css_dequeue_isys_event(struct ia_css_event *event) {
+ia_css_dequeue_isys_event(struct ia_css_event *event)
+{
        u8 payload[4] = {0, 0, 0, 0};
        int err = 0;
 
@@ -4722,11 +4602,9 @@ ia_css_dequeue_isys_event(struct ia_css_event *event) {
        if (!event)
                return -EINVAL;
 
+       /* SP is not running. The queues are not valid */
        if (!sh_css_sp_is_running())
-       {
-               /* SP is not running. The queues are not valid */
                return -EBUSY;
-       }
 
        err = ia_css_bufq_dequeue_isys_event(payload);
        if (err)
@@ -4759,7 +4637,8 @@ acc_start(struct ia_css_pipe *pipe)
 }
 
 static int
-sh_css_pipe_start(struct ia_css_stream *stream) {
+sh_css_pipe_start(struct ia_css_stream *stream)
+{
        int err = 0;
 
        struct ia_css_pipe *pipe;
@@ -4768,22 +4647,19 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
 
        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
 
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
        pipe = stream->last_pipe;
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
 
        pipe_id = pipe->mode;
 
-       if (stream->started)
-       {
+       if (stream->started) {
                IA_CSS_WARNING("Cannot start stream that is already started");
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -4791,8 +4667,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
 
        pipe->stop_requested = false;
 
-       switch (pipe_id)
-       {
+       switch (pipe_id) {
        case IA_CSS_PIPE_ID_PREVIEW:
                err = preview_start(pipe);
                break;
@@ -4812,8 +4687,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
                err = -EINVAL;
        }
        /* DH regular multi pipe - not continuous mode: start the next pipes too */
-       if (!stream->config.continuous)
-       {
+       if (!stream->config.continuous) {
                int i;
 
                for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
@@ -4843,8 +4717,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
                        }
                }
        }
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
@@ -4854,8 +4727,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
         * don't use ISP parameters anyway. So this should be okay.
         * The SP binary (jpeg) copy does not use any parameters.
         */
-       if (!copy_on_sp(pipe))
-       {
+       if (!copy_on_sp(pipe)) {
                sh_css_invalidate_params(stream);
                err = sh_css_param_update_isp_params(pipe,
                                                     stream->isp_params_configs, true, NULL);
@@ -4869,8 +4741,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
 
        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
 
-       if (!sh_css_sp_is_running())
-       {
+       if (!sh_css_sp_is_running()) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
                /* SP is not running. The queues are not valid */
                return -EBUSY;
@@ -4879,8 +4750,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
                                       (uint8_t)thread_id, 0, 0);
 
        /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
-       if (!stream->config.continuous)
-       {
+       if (!stream->config.continuous) {
                int i;
 
                for (i = 1; i < stream->num_pipes; i++) {
@@ -4894,8 +4764,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
        }
 
        /* in case of continuous capture mode, we also start capture thread and copy thread*/
-       if (pipe->stream->config.continuous)
-       {
+       if (pipe->stream->config.continuous) {
                struct ia_css_pipe *copy_pipe = NULL;
 
                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
@@ -4914,8 +4783,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
                    IA_CSS_PSYS_SW_EVENT_START_STREAM,
                    (uint8_t)thread_id, 0,  0);
        }
-       if (pipe->stream->cont_capt)
-       {
+       if (pipe->stream->cont_capt) {
                struct ia_css_pipe *capture_pipe = NULL;
 
                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
@@ -4936,8 +4804,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
        }
 
        /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
-       if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
-       {
+       if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
                struct ia_css_pipe *acc_pipe = NULL;
 
                acc_pipe = pipe->pipe_settings.preview.acc_pipe;
@@ -4988,7 +4855,8 @@ sh_css_continuous_is_enabled(uint8_t pipe_num)
 /* ISP2400 */
 int
 ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
-                                  int *buffer_depth) {
+                                  int *buffer_depth)
+{
        if (!buffer_depth)
                return -EINVAL;
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
@@ -4998,7 +4866,8 @@ ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
 }
 
 int
-ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) {
+ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
+{
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
        (void)stream;
        if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
@@ -5012,7 +4881,8 @@ ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) {
 /* ISP2401 */
 int
 ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
-                              int *buffer_depth) {
+                              int *buffer_depth)
+{
        if (!buffer_depth)
                return -EINVAL;
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
@@ -5036,18 +4906,14 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
        enum ia_css_pipe_id main_pipe_id;
        int i;
 
-       assert(stream);
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LOG("stream does NOT exist!");
                err = -EINVAL;
                goto ERR;
        }
 
        main_pipe = stream->last_pipe;
-       assert(main_pipe);
-       if (!main_pipe)
-       {
+       if (!main_pipe) {
                IA_CSS_LOG("main_pipe does NOT exist!");
                err = -EINVAL;
                goto ERR;
@@ -5060,11 +4926,10 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
         * Stop all "ia_css_pipe" instances in this target
         * "ia_css_stream" instance.
         */
-       for (i = 0; i < stream->num_pipes; i++)
-       {
+       for (i = 0; i < stream->num_pipes; i++) {
                /* send the "stop" request to the "ia_css_pipe" instance */
                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
-                       stream->pipes[i]->pipeline.pipe_id);
+                          stream->pipes[i]->pipeline.pipe_id);
                err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline);
 
                /*
@@ -5095,8 +4960,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
         *
         * We need to stop this "Copy Pipe", as well.
         */
-       if (main_pipe->stream->config.continuous)
-       {
+       if (main_pipe->stream->config.continuous) {
                struct ia_css_pipe *copy_pipe = NULL;
 
                /* get the reference to "Copy Pipe" */
@@ -5106,7 +4970,6 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
 
                /* return the error code if "Copy Pipe" does NOT exist */
-               assert(copy_pipe);
                if (!copy_pipe) {
                        IA_CSS_LOG("Copy Pipe does NOT exist!");
                        err = -EINVAL;
@@ -5115,7 +4978,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
 
                /* send the "stop" request to "Copy Pipe" */
                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
-                       copy_pipe->pipeline.pipe_id);
+                          copy_pipe->pipeline.pipe_id);
                err = ia_css_pipeline_request_stop(&copy_pipe->pipeline);
        }
 
@@ -5141,7 +5004,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
 
        int i;
 
-       assert(stream);
        if (!stream) {
                IA_CSS_LOG("stream does NOT exist!");
                rval = false;
@@ -5149,7 +5011,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
        }
 
        main_pipe = stream->last_pipe;
-       assert(main_pipe);
 
        if (!main_pipe) {
                IA_CSS_LOG("main_pipe does NOT exist!");
@@ -5190,7 +5051,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
 
                /* return if "Copy Pipe" does NOT exist */
-               assert(copy_pipe);
                if (!copy_pipe) {
                        IA_CSS_LOG("Copy Pipe does NOT exist!");
 
@@ -5272,8 +5132,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
 
        binary = ia_css_pipe_get_shading_correction_binary(pipe);
 
-       if (binary)
-       {
+       if (binary) {
                err = ia_css_binary_get_shading_info(binary,
                                                     IA_CSS_SHADING_CORRECTION_TYPE_1,
                                                     pipe->required_bds_factor,
@@ -5283,8 +5142,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
                /* Other function calls can be added here when other shading correction types will be added
                 * in the future.
                 */
-       } else
-       {
+       } else {
                /* When the pipe does not have a binary which has the shading
                 * correction, this function does not need to fill the shading
                 * information. It is not a error case, and then
@@ -5297,7 +5155,8 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
 
 static int
 sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
-                         struct ia_css_grid_info *info) {
+                         struct ia_css_grid_info *info)
+{
        int err = 0;
        struct ia_css_binary *binary = NULL;
 
@@ -5308,30 +5167,27 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
 
        binary = ia_css_pipe_get_s3a_binary(pipe);
 
-       if (binary)
-       {
+       if (binary) {
                err = ia_css_binary_3a_grid_info(binary, info, pipe);
                if (err)
                        goto ERR;
-       } else
+       } else {
                memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
+       }
 
        binary = ia_css_pipe_get_sdis_binary(pipe);
 
-       if (binary)
-       {
+       if (binary) {
                ia_css_binary_dvs_grid_info(binary, info, pipe);
                ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
-       } else
-       {
+       } else {
                memset(&info->dvs_grid.dvs_grid_info, 0,
                       sizeof(info->dvs_grid.dvs_grid_info));
                memset(&info->dvs_grid.dvs_stat_grid_info, 0,
                       sizeof(info->dvs_grid.dvs_stat_grid_info));
        }
 
-       if (binary)
-       {
+       if (binary) {
                /* copy pipe does not have ISP binary*/
                info->isp_in_width = binary->internal_frame_info.res.width;
                info->isp_in_height = binary->internal_frame_info.res.height;
@@ -5351,7 +5207,8 @@ ERR :
  */
 static int
 ia_css_pipe_check_format(struct ia_css_pipe *pipe,
-                        enum ia_css_frame_format format) {
+                        enum ia_css_frame_format format)
+{
        const enum ia_css_frame_format *supported_formats;
        int number_of_formats;
        int found = 0;
@@ -5359,8 +5216,7 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe,
 
        IA_CSS_ENTER_PRIVATE("");
 
-       if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info)
-       {
+       if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
                IA_CSS_ERROR("Pipe or binary info is not set");
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
@@ -5369,23 +5225,19 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe,
        supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
        number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
 
-       for (i = 0; i < number_of_formats && !found; i++)
-       {
+       for (i = 0; i < number_of_formats && !found; i++) {
                if (supported_formats[i] == format) {
                        found = 1;
                        break;
                }
        }
-       if (!found)
-       {
+       if (!found) {
                IA_CSS_ERROR("Requested format is not supported by binary");
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
-       } else
-       {
-               IA_CSS_LEAVE_ERR_PRIVATE(0);
-               return 0;
        }
+       IA_CSS_LEAVE_ERR_PRIVATE(0);
+       return 0;
 }
 
 static int load_video_binaries(struct ia_css_pipe *pipe)
@@ -5528,10 +5380,10 @@ static int load_video_binaries(struct ia_css_pipe *pipe)
                                         &mycs->video_binary);
 
                if (err) {
-                       if (video_vf_info) {
-                               /* This will do another video binary lookup later for YUV_LINE format*/
+                       /* This will do another video binary lookup later for YUV_LINE format*/
+                       if (video_vf_info)
                                need_vf_pp = true;
-                       else
+                       else
                                return err;
                } else if (video_vf_info) {
                        /* The first video binary lookup is successful, but we may
@@ -5694,13 +5546,13 @@ static int load_video_binaries(struct ia_css_pipe *pipe)
 }
 
 static int
-unload_video_binaries(struct ia_css_pipe *pipe) {
+unload_video_binaries(struct ia_css_pipe *pipe)
+{
        unsigned int i;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
 
-       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO))
-       {
+       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -5850,31 +5702,29 @@ static int
 sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
                                 unsigned int height, unsigned int min_width,
                                 enum ia_css_frame_format format,
-                                unsigned int idx) {
+                                unsigned int idx)
+{
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
                             pipe, width, height, min_width, format, idx);
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
 
        err = ia_css_util_check_res(width, height);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
        if (pipe->vf_output_info[idx].res.width != width ||
            pipe->vf_output_info[idx].res.height != height ||
            pipe->vf_output_info[idx].format != format)
-       {
                ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
                                       format, min_width);
-       }
+
        IA_CSS_LEAVE_ERR_PRIVATE(0);
        return 0;
 }
@@ -5955,7 +5805,7 @@ static bool need_capt_ldc(
 }
 
 static int set_num_primary_stages(unsigned int *num,
-       enum ia_css_pipe_version version)
+                                 enum ia_css_pipe_version version)
 {
        int err = 0;
 
@@ -6155,10 +6005,13 @@ static int load_primary_binaries(
                        capt_pp_in_info = &prim_out_info;
 
                ia_css_pipe_get_capturepp_binarydesc(pipe,
-                                                       &capture_pp_descr, capt_pp_in_info,
-                                                       &capt_pp_out_info, &vf_info);
+                                                    &capture_pp_descr,
+                                                    capt_pp_in_info,
+                                                    &capt_pp_out_info,
+                                                    &vf_info);
+
                err = ia_css_binary_find(&capture_pp_descr,
-                                           &mycs->capture_pp_binary);
+                                        &mycs->capture_pp_binary);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
@@ -6168,11 +6021,12 @@ static int load_primary_binaries(
                        struct ia_css_binary_descr capt_ldc_descr;
 
                        ia_css_pipe_get_ldc_binarydesc(pipe,
-                                                       &capt_ldc_descr, &prim_out_info,
-                                                       &capt_ldc_out_info);
+                                                      &capt_ldc_descr,
+                                                      &prim_out_info,
+                                                      &capt_ldc_out_info);
 
                        err = ia_css_binary_find(&capt_ldc_descr,
-                                                   &mycs->capture_ldc_binary);
+                                                &mycs->capture_ldc_binary);
                        if (err) {
                                IA_CSS_LEAVE_ERR_PRIVATE(err);
                                return err;
@@ -6189,8 +6043,9 @@ static int load_primary_binaries(
                if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
                    (i == mycs->num_primary_stage - 1))
                        local_vf_info = &vf_info;
-               ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], &prim_in_info,
-                                                   &prim_out_info, local_vf_info, i);
+               ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
+                                                  &prim_in_info, &prim_out_info,
+                                                  local_vf_info, i);
                err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -6242,8 +6097,8 @@ static int load_primary_binaries(
        /* ISP Copy */
        if (need_isp_copy_binary) {
                err = load_copy_binary(pipe,
-                                       &mycs->copy_binary,
-                                       &mycs->primary_binary[0]);
+                                      &mycs->copy_binary,
+                                      &mycs->primary_binary[0]);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
@@ -6254,7 +6109,8 @@ static int load_primary_binaries(
 }
 
 static int
-allocate_delay_frames(struct ia_css_pipe *pipe) {
+allocate_delay_frames(struct ia_css_pipe *pipe)
+{
        unsigned int num_delay_frames = 0, i = 0;
        unsigned int dvs_frame_delay = 0;
        struct ia_css_frame_info ref_info;
@@ -6264,8 +6120,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
 
        IA_CSS_ENTER_PRIVATE("");
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_ERROR("Invalid args - pipe %p", pipe);
                return -EINVAL;
        }
@@ -6276,8 +6131,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
        if (dvs_frame_delay > 0)
                num_delay_frames = dvs_frame_delay + 1;
 
-       switch (mode)
-       {
+       switch (mode) {
        case IA_CSS_PIPE_ID_CAPTURE: {
                struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
                (void)mycs_capture;
@@ -6329,8 +6183,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
        ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
 
        assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
-       for (i = 0; i < num_delay_frames; i++)
-       {
+       for (i = 0; i < num_delay_frames; i++) {
                err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info);
                if (err)
                        return err;
@@ -6339,8 +6192,8 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
        return 0;
 }
 
-static int load_advanced_binaries(
-    struct ia_css_pipe *pipe) {
+static int load_advanced_binaries(struct ia_css_pipe *pipe)
+{
        struct ia_css_frame_info pre_in_info, gdc_in_info,
                        post_in_info, post_out_info,
                        vf_info, *vf_pp_in_info, *pipe_out_info,
@@ -6353,7 +6206,7 @@ static int load_advanced_binaries(
 
        assert(pipe);
        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
-               pipe->mode == IA_CSS_PIPE_ID_COPY);
+              pipe->mode == IA_CSS_PIPE_ID_COPY);
        if (pipe->pipe_settings.capture.pre_isp_binary.info)
                return 0;
        pipe_out_info = &pipe->output_info[0];
@@ -6366,17 +6219,18 @@ static int load_advanced_binaries(
        need_pp = need_capture_pp(pipe);
 
        ia_css_frame_info_set_format(&vf_info,
-                                       IA_CSS_FRAME_FORMAT_YUV_LINE);
+                                    IA_CSS_FRAME_FORMAT_YUV_LINE);
 
        /* we build up the pipeline starting at the end */
        /* Capture post-processing */
        if (need_pp) {
                struct ia_css_binary_descr capture_pp_descr;
 
-               ia_css_pipe_get_capturepp_binarydesc(pipe,
-                                                       &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info);
+               ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
+                                                    &post_out_info,
+                                                    pipe_out_info, &vf_info);
                err = ia_css_binary_find(&capture_pp_descr,
-                                           &pipe->pipe_settings.capture.capture_pp_binary);
+                                        &pipe->pipe_settings.capture.capture_pp_binary);
                if (err)
                        return err;
        } else {
@@ -6387,10 +6241,11 @@ static int load_advanced_binaries(
        {
                struct ia_css_binary_descr post_gdc_descr;
 
-               ia_css_pipe_get_post_gdc_binarydesc(pipe,
-                                                   &post_gdc_descr, &post_in_info, &post_out_info, &vf_info);
+               ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
+                                                   &post_in_info,
+                                                   &post_out_info, &vf_info);
                err = ia_css_binary_find(&post_gdc_descr,
-                                           &pipe->pipe_settings.capture.post_isp_binary);
+                                        &pipe->pipe_settings.capture.post_isp_binary);
                if (err)
                        return err;
        }
@@ -6400,9 +6255,9 @@ static int load_advanced_binaries(
                struct ia_css_binary_descr gdc_descr;
 
                ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
-                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
+                                              &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
                err = ia_css_binary_find(&gdc_descr,
-                                           &pipe->pipe_settings.capture.anr_gdc_binary);
+                                        &pipe->pipe_settings.capture.anr_gdc_binary);
                if (err)
                        return err;
        }
@@ -6414,9 +6269,9 @@ static int load_advanced_binaries(
                struct ia_css_binary_descr pre_gdc_descr;
 
                ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
-                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
+                                                  &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
                err = ia_css_binary_find(&pre_gdc_descr,
-                                           &pipe->pipe_settings.capture.pre_isp_binary);
+                                        &pipe->pipe_settings.capture.pre_isp_binary);
                if (err)
                        return err;
        }
@@ -6438,7 +6293,7 @@ static int load_advanced_binaries(
                ia_css_pipe_get_vfpp_binarydesc(pipe,
                                                &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
                err = ia_css_binary_find(&vf_pp_descr,
-                                           &pipe->pipe_settings.capture.vf_pp_binary);
+                                        &pipe->pipe_settings.capture.vf_pp_binary);
                if (err)
                        return err;
        }
@@ -6450,14 +6305,14 @@ static int load_advanced_binaries(
 #endif
        if (need_isp_copy)
                load_copy_binary(pipe,
-                                   &pipe->pipe_settings.capture.copy_binary,
-                                   &pipe->pipe_settings.capture.pre_isp_binary);
+                                &pipe->pipe_settings.capture.copy_binary,
+                                &pipe->pipe_settings.capture.pre_isp_binary);
 
        return err;
 }
 
-static int load_bayer_isp_binaries(
-    struct ia_css_pipe *pipe) {
+static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
+{
        struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
        int err = 0;
        struct ia_css_binary_descr pre_de_descr;
@@ -6465,7 +6320,7 @@ static int load_bayer_isp_binaries(
        IA_CSS_ENTER_PRIVATE("");
        assert(pipe);
        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
-               pipe->mode == IA_CSS_PIPE_ID_COPY);
+              pipe->mode == IA_CSS_PIPE_ID_COPY);
        pipe_out_info = &pipe->output_info[0];
 
        if (pipe->pipe_settings.capture.pre_isp_binary.info)
@@ -6476,17 +6331,17 @@ static int load_bayer_isp_binaries(
                return err;
 
        ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
-                                           &pre_isp_in_info,
-                                           pipe_out_info);
+                                         &pre_isp_in_info,
+                                         pipe_out_info);
 
        err = ia_css_binary_find(&pre_de_descr,
-                                   &pipe->pipe_settings.capture.pre_isp_binary);
+                                &pipe->pipe_settings.capture.pre_isp_binary);
 
        return err;
 }
 
-static int load_low_light_binaries(
-    struct ia_css_pipe *pipe) {
+static int load_low_light_binaries(struct ia_css_pipe *pipe)
+{
        struct ia_css_frame_info pre_in_info, anr_in_info,
                        post_in_info, post_out_info,
                        vf_info, *pipe_vf_out_info, *pipe_out_info,
@@ -6498,7 +6353,7 @@ static int load_low_light_binaries(
        IA_CSS_ENTER_PRIVATE("");
        assert(pipe);
        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
-               pipe->mode == IA_CSS_PIPE_ID_COPY);
+              pipe->mode == IA_CSS_PIPE_ID_COPY);
 
        if (pipe->pipe_settings.capture.pre_isp_binary.info)
                return 0;
@@ -6513,17 +6368,18 @@ static int load_low_light_binaries(
        need_pp = need_capture_pp(pipe);
 
        ia_css_frame_info_set_format(&vf_info,
-                                       IA_CSS_FRAME_FORMAT_YUV_LINE);
+                                    IA_CSS_FRAME_FORMAT_YUV_LINE);
 
        /* we build up the pipeline starting at the end */
        /* Capture post-processing */
        if (need_pp) {
                struct ia_css_binary_descr capture_pp_descr;
 
-               ia_css_pipe_get_capturepp_binarydesc(pipe,
-                                                       &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info);
+               ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
+                                                    &post_out_info,
+                                                    pipe_out_info, &vf_info);
                err = ia_css_binary_find(&capture_pp_descr,
-                                           &pipe->pipe_settings.capture.capture_pp_binary);
+                                        &pipe->pipe_settings.capture.capture_pp_binary);
                if (err)
                        return err;
        } else {
@@ -6537,7 +6393,7 @@ static int load_low_light_binaries(
                ia_css_pipe_get_post_anr_binarydesc(pipe,
                                                    &post_anr_descr, &post_in_info, &post_out_info, &vf_info);
                err = ia_css_binary_find(&post_anr_descr,
-                                           &pipe->pipe_settings.capture.post_isp_binary);
+                                        &pipe->pipe_settings.capture.post_isp_binary);
                if (err)
                        return err;
        }
@@ -6547,9 +6403,9 @@ static int load_low_light_binaries(
                struct ia_css_binary_descr anr_descr;
 
                ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
-                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
+                                              &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
                err = ia_css_binary_find(&anr_descr,
-                                           &pipe->pipe_settings.capture.anr_gdc_binary);
+                                        &pipe->pipe_settings.capture.anr_gdc_binary);
                if (err)
                        return err;
        }
@@ -6561,9 +6417,9 @@ static int load_low_light_binaries(
                struct ia_css_binary_descr pre_anr_descr;
 
                ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
-                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
+                                                  &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
                err = ia_css_binary_find(&pre_anr_descr,
-                                           &pipe->pipe_settings.capture.pre_isp_binary);
+                                        &pipe->pipe_settings.capture.pre_isp_binary);
                if (err)
                        return err;
        }
@@ -6582,10 +6438,10 @@ static int load_low_light_binaries(
        {
                struct ia_css_binary_descr vf_pp_descr;
 
-               ia_css_pipe_get_vfpp_binarydesc(pipe,
-                                               &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
+               ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
+                                               vf_pp_in_info, pipe_vf_out_info);
                err = ia_css_binary_find(&vf_pp_descr,
-                                           &pipe->pipe_settings.capture.vf_pp_binary);
+                                        &pipe->pipe_settings.capture.vf_pp_binary);
                if (err)
                        return err;
        }
@@ -6597,8 +6453,8 @@ static int load_low_light_binaries(
 #endif
        if (need_isp_copy)
                err = load_copy_binary(pipe,
-                                       &pipe->pipe_settings.capture.copy_binary,
-                                       &pipe->pipe_settings.capture.pre_isp_binary);
+                                      &pipe->pipe_settings.capture.copy_binary,
+                                      &pipe->pipe_settings.capture.pre_isp_binary);
 
        return err;
 }
@@ -6623,15 +6479,15 @@ static bool copy_on_sp(struct ia_css_pipe *pipe)
        return rval;
 }
 
-static int load_capture_binaries(
-    struct ia_css_pipe *pipe) {
+static int load_capture_binaries(struct ia_css_pipe *pipe)
+{
        int err = 0;
        bool must_be_raw;
 
        IA_CSS_ENTER_PRIVATE("");
        assert(pipe);
        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
-               pipe->mode == IA_CSS_PIPE_ID_COPY);
+              pipe->mode == IA_CSS_PIPE_ID_COPY);
 
        if (pipe->pipe_settings.capture.primary_binary[0].info) {
                IA_CSS_LEAVE_ERR_PRIVATE(0);
@@ -6692,13 +6548,14 @@ static int load_capture_binaries(
 }
 
 static int
-unload_capture_binaries(struct ia_css_pipe *pipe) {
+unload_capture_binaries(struct ia_css_pipe *pipe)
+{
        unsigned int i;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
 
-       if ((!pipe) || ((pipe->mode != IA_CSS_PIPE_ID_CAPTURE) && (pipe->mode != IA_CSS_PIPE_ID_COPY)))
-       {
+       if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
+                     pipe->mode != IA_CSS_PIPE_ID_COPY)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -6726,7 +6583,8 @@ unload_capture_binaries(struct ia_css_pipe *pipe) {
 
 static bool
 need_downscaling(const struct ia_css_resolution in_res,
-                   const struct ia_css_resolution out_res) {
+                const struct ia_css_resolution out_res)
+{
        if (in_res.width > out_res.width || in_res.height > out_res.height)
                return true;
 
@@ -6734,7 +6592,8 @@ need_downscaling(const struct ia_css_resolution in_res,
 }
 
 static bool
-need_yuv_scaler_stage(const struct ia_css_pipe *pipe) {
+need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
+{
        unsigned int i;
        struct ia_css_resolution in_res, out_res;
 
@@ -6773,10 +6632,11 @@ need_yuv_scaler_stage(const struct ia_css_pipe *pipe) {
 /* which has some hard-coded knowledge which prevents reuse of the function. */
 /* Later, merge this with ia_css_pipe_create_cas_scaler_desc */
 static int ia_css_pipe_create_cas_scaler_desc_single_output(
-    struct ia_css_frame_info *cas_scaler_in_info,
-    struct ia_css_frame_info *cas_scaler_out_info,
-    struct ia_css_frame_info *cas_scaler_vf_info,
-    struct ia_css_cas_binary_descr *descr) {
+           struct ia_css_frame_info *cas_scaler_in_info,
+           struct ia_css_frame_info *cas_scaler_out_info,
+           struct ia_css_frame_info *cas_scaler_vf_info,
+           struct ia_css_cas_binary_descr *descr)
+{
        unsigned int i;
        unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
        int err = 0;
@@ -6794,9 +6654,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
        descr->num_output_stage = 1;
 
        hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
-                                   cas_scaler_out_info->res.width);
+                                cas_scaler_out_info->res.width);
        ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
-                                   cas_scaler_out_info->res.height);
+                                cas_scaler_out_info->res.height);
        /* use the same horizontal and vertical downscaling factor for simplicity */
        assert(hor_ds_factor == ver_ds_factor);
 
@@ -6806,31 +6666,36 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
                i *= max_scale_factor_per_stage;
        }
 
-       descr->in_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
-                                   GFP_KERNEL);
+       descr->in_info = kmalloc(descr->num_stage *
+                                sizeof(struct ia_css_frame_info),
+                                GFP_KERNEL);
        if (!descr->in_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->internal_out_info = kmalloc(descr->num_stage * sizeof(
-                                               struct ia_css_frame_info), GFP_KERNEL);
+       descr->internal_out_info = kmalloc(descr->num_stage *
+                                          sizeof(struct ia_css_frame_info),
+                                          GFP_KERNEL);
        if (!descr->internal_out_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
-                                   GFP_KERNEL);
+       descr->out_info = kmalloc(descr->num_stage *
+                                 sizeof(struct ia_css_frame_info),
+                                 GFP_KERNEL);
        if (!descr->out_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
-                                   GFP_KERNEL);
+       descr->vf_info = kmalloc(descr->num_stage *
+                                sizeof(struct ia_css_frame_info),
+                                GFP_KERNEL);
        if (!descr->vf_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL);
+       descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
+                                        GFP_KERNEL);
        if (!descr->is_output_stage) {
                err = -ENOMEM;
                goto ERR;
@@ -6874,9 +6739,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
                                max_scale_factor_per_stage;
                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
                        ia_css_frame_info_init(&descr->internal_out_info[i],
-                                               tmp_in_info.res.width / max_scale_factor_per_stage,
-                                               tmp_in_info.res.height / max_scale_factor_per_stage,
-                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
+                                              tmp_in_info.res.width / max_scale_factor_per_stage,
+                                              tmp_in_info.res.height / max_scale_factor_per_stage,
+                                              IA_CSS_FRAME_FORMAT_YUV420, 0);
                        descr->out_info[i].res.width = 0;
                        descr->out_info[i].res.height = 0;
                        descr->vf_info[i].res.width = 0;
@@ -6892,9 +6757,10 @@ ERR:
 }
 
 /* FIXME: merge most of this and single output version */
-static int ia_css_pipe_create_cas_scaler_desc(
-    struct ia_css_pipe *pipe,
-    struct ia_css_cas_binary_descr *descr) {
+static int
+ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
+                                  struct ia_css_cas_binary_descr *descr)
+{
        struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
        struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
        struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
@@ -6951,30 +6817,35 @@ static int ia_css_pipe_create_cas_scaler_desc(
        descr->num_stage = num_stages;
 
        descr->in_info = kmalloc_array(descr->num_stage,
-                                       sizeof(struct ia_css_frame_info), GFP_KERNEL);
+                                      sizeof(struct ia_css_frame_info),
+                                      GFP_KERNEL);
        if (!descr->in_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->internal_out_info = kmalloc(descr->num_stage * sizeof(
-                                               struct ia_css_frame_info), GFP_KERNEL);
+       descr->internal_out_info = kmalloc(descr->num_stage *
+                                          sizeof(struct ia_css_frame_info),
+                                          GFP_KERNEL);
        if (!descr->internal_out_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
-                                   GFP_KERNEL);
+       descr->out_info = kmalloc(descr->num_stage *
+                                 sizeof(struct ia_css_frame_info),
+                                 GFP_KERNEL);
        if (!descr->out_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
-                                   GFP_KERNEL);
+       descr->vf_info = kmalloc(descr->num_stage *
+                                sizeof(struct ia_css_frame_info),
+                                GFP_KERNEL);
        if (!descr->vf_info) {
                err = -ENOMEM;
                goto ERR;
        }
-       descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL);
+       descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
+                                        GFP_KERNEL);
        if (!descr->is_output_stage) {
                err = -ENOMEM;
                goto ERR;
@@ -6984,7 +6855,7 @@ static int ia_css_pipe_create_cas_scaler_desc(
                if (out_info[i]) {
                        if (i > 0) {
                                assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
-                                       (out_info[i - 1]->res.height >= out_info[i]->res.height));
+                                      (out_info[i - 1]->res.height >= out_info[i]->res.height));
                        }
                }
        }
@@ -7032,9 +6903,9 @@ static int ia_css_pipe_create_cas_scaler_desc(
                                max_scale_factor_per_stage;
                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
                        ia_css_frame_info_init(&descr->internal_out_info[i],
-                                               tmp_in_info.res.width / max_scale_factor_per_stage,
-                                               tmp_in_info.res.height / max_scale_factor_per_stage,
-                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
+                                              tmp_in_info.res.width / max_scale_factor_per_stage,
+                                              tmp_in_info.res.height / max_scale_factor_per_stage,
+                                              IA_CSS_FRAME_FORMAT_YUV420, 0);
                        descr->out_info[i].res.width = 0;
                        descr->out_info[i].res.height = 0;
                        descr->vf_info[i].res.width = 0;
@@ -7050,7 +6921,8 @@ ERR:
 }
 
 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
-       *descr) {
+       *descr)
+{
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
                            "ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
        kfree(descr->in_info);
@@ -7068,7 +6940,8 @@ static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
 }
 
 static int
-load_yuvpp_binaries(struct ia_css_pipe *pipe) {
+load_yuvpp_binaries(struct ia_css_pipe *pipe)
+{
        int err = 0;
        bool need_scaler = false;
        struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
@@ -7093,8 +6966,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
 
        mycs = &pipe->pipe_settings.yuvpp;
 
-       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
-       {
+       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
                if (pipe->vf_output_info[i].res.width != 0) {
                        err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
                                                            &pipe->vf_output_info[i]);
@@ -7108,18 +6980,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
 
        /* we build up the pipeline starting at the end */
        /* Capture post-processing */
-       if (need_scaler)
-       {
+       if (need_scaler) {
                struct ia_css_binary_descr yuv_scaler_descr;
 
                err = ia_css_pipe_create_cas_scaler_desc(pipe,
-                       &cas_scaler_descr);
+                                                        &cas_scaler_descr);
                if (err)
                        goto ERR;
                mycs->num_output = cas_scaler_descr.num_output_stage;
                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
                mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage *
-                                                   sizeof(struct ia_css_binary), GFP_KERNEL);
+                                                 sizeof(struct ia_css_binary),
+                                                 GFP_KERNEL);
                if (!mycs->yuv_scaler_binary) {
                        err = -ENOMEM;
                        goto ERR;
@@ -7133,28 +7005,25 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
-                                                               &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
-                                                               &cas_scaler_descr.out_info[i],
-                                                               &cas_scaler_descr.internal_out_info[i],
-                                                               &cas_scaler_descr.vf_info[i]);
+                                                            &yuv_scaler_descr,
+                                                            &cas_scaler_descr.in_info[i],
+                                                            &cas_scaler_descr.out_info[i],
+                                                            &cas_scaler_descr.internal_out_info[i],
+                                                            &cas_scaler_descr.vf_info[i]);
                        err = ia_css_binary_find(&yuv_scaler_descr,
-                                                   &mycs->yuv_scaler_binary[i]);
+                                                &mycs->yuv_scaler_binary[i]);
                        if (err)
                                goto ERR;
                }
                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
-       } else
-       {
+       } else {
                mycs->num_output = 1;
        }
 
        if (need_scaler)
-       {
                next_binary = &mycs->yuv_scaler_binary[0];
-       } else
-       {
+       else
                next_binary = NULL;
-       }
 
 #if defined(ISP2401)
        /*
@@ -7180,11 +7049,10 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
        need_isp_copy_binary = true;
 #endif /*  ISP2401 */
 
-       if (need_isp_copy_binary)
-       {
+       if (need_isp_copy_binary) {
                err = load_copy_binary(pipe,
-                                       &mycs->copy_binary,
-                                       next_binary);
+                                      &mycs->copy_binary,
+                                      next_binary);
 
                if (err)
                        goto ERR;
@@ -7211,8 +7079,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
        }
 
        /* Viewfinder post-processing */
-       if (need_scaler)
-       {
+       if (need_scaler) {
                for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
                        if (mycs->is_output_stage[i]) {
                                assert(j < 2);
@@ -7222,19 +7089,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
                        }
                }
                mycs->num_vf_pp = j;
-       } else
-       {
+       } else {
                vf_pp_in_info[0] =
                    &mycs->copy_binary.vf_frame_info;
-               for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
+               for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
                        vf_pp_in_info[i] = NULL;
-               }
+
                mycs->num_vf_pp = 1;
        }
-       mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * sizeof(struct ia_css_binary),
-                                       GFP_KERNEL);
-       if (!mycs->vf_pp_binary)
-       {
+       mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp *
+                                    sizeof(struct ia_css_binary),
+                                    GFP_KERNEL);
+       if (!mycs->vf_pp_binary) {
                err = -ENOMEM;
                goto ERR;
        }
@@ -7242,8 +7108,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
        {
                struct ia_css_binary_descr vf_pp_descr;
 
-               for (i = 0; i < mycs->num_vf_pp; i++)
-               {
+               for (i = 0; i < mycs->num_vf_pp; i++) {
                        if (pipe->vf_output_info[i].res.width != 0) {
                                ia_css_pipe_get_vfpp_binarydesc(pipe,
                                                                &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
@@ -7259,34 +7124,31 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
 
 ERR:
        if (need_scaler)
-       {
                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
-       }
+
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
                            err);
        return err;
 }
 
 static int
-unload_yuvpp_binaries(struct ia_css_pipe *pipe) {
+unload_yuvpp_binaries(struct ia_css_pipe *pipe)
+{
        unsigned int i;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
 
-       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP))
-       {
+       if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
        ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
        for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
-       {
                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
-       }
+
        for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
-       {
                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
-       }
+
        kfree(pipe->pipe_settings.yuvpp.is_output_stage);
        pipe->pipe_settings.yuvpp.is_output_stage = NULL;
        kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
@@ -7336,25 +7198,23 @@ static int yuvpp_start(struct ia_css_pipe *pipe)
 }
 
 static int
-sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) {
+sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
+{
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
        /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
-       if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
-       {
+       if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
                IA_CSS_LEAVE_ERR_PRIVATE(0);
                return 0;
        }
 
-       switch (pipe->mode)
-       {
+       switch (pipe->mode) {
        case IA_CSS_PIPE_ID_PREVIEW:
                err = unload_preview_binaries(pipe);
                break;
@@ -7375,7 +7235,8 @@ sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) {
 }
 
 static int
-sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
+sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
+{
        int err = 0;
 
        assert(pipe);
@@ -7385,8 +7246,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
                return err;
 
-       switch (pipe->mode)
-       {
+       switch (pipe->mode) {
        case IA_CSS_PIPE_ID_PREVIEW:
                err = load_preview_binaries(pipe);
                break;
@@ -7405,8 +7265,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
                err = -EINVAL;
                break;
        }
-       if (err)
-       {
+       if (err) {
                if (sh_css_pipe_unload_binaries(pipe)) {
                        /* currently css does not support multiple error returns in a single function,
                            * using -EINVAL in this case */
@@ -7417,7 +7276,8 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
 }
 
 static int
-create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
+create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
+{
        struct ia_css_pipeline *me;
        int err = 0;
        struct ia_css_pipeline_stage *vf_pp_stage = NULL,
@@ -7444,15 +7304,13 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
 #endif
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
-       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP))
-       {
+       if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
        me = &pipe->pipeline;
        ia_css_pipeline_clean(me);
-       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
-       {
+       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
                out_frame[i] = NULL;
                vf_frame[i] = NULL;
        }
@@ -7480,8 +7338,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
        /* the input frame can come from:
            *  a) memory: connect yuvscaler to me->in_frame
            *  b) sensor, via copy binary: connect yuvscaler to copy binary later on */
-       if (need_in_frameinfo_memory)
-       {
+       if (need_in_frameinfo_memory) {
                /* TODO: improve for different input formats. */
 
                /*
@@ -7530,13 +7387,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                }
 
                in_frame = &me->in_frame;
-       } else
-       {
+       } else {
                in_frame = NULL;
        }
 
-       for (i = 0; i < num_output_stage; i++)
-       {
+       for (i = 0; i < num_output_stage; i++) {
                assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
                if (pipe->output_info[i].res.width != 0) {
                        err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
@@ -7563,8 +7418,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
        yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
        need_scaler = need_yuv_scaler_stage(pipe);
 
-       if (pipe->pipe_settings.yuvpp.copy_binary.info)
-       {
+       if (pipe->pipe_settings.yuvpp.copy_binary.info) {
                struct ia_css_frame *in_frame_local = NULL;
 
 #ifdef ISP2401
@@ -7574,18 +7428,26 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
 #endif
 
                if (need_scaler) {
-                       ia_css_pipe_util_set_output_frames(bin_out_frame, 0, NULL);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                           bin_out_frame, in_frame_local, NULL);
+                       ia_css_pipe_util_set_output_frames(bin_out_frame,
+                                                          0, NULL);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          copy_binary,
+                                                          bin_out_frame,
+                                                          in_frame_local,
+                                                          NULL);
                } else {
-                       ia_css_pipe_util_set_output_frames(bin_out_frame, 0, out_frame[0]);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                           bin_out_frame, in_frame_local, NULL);
+                       ia_css_pipe_util_set_output_frames(bin_out_frame,
+                                                          0, out_frame[0]);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          copy_binary,
+                                                          bin_out_frame,
+                                                          in_frame_local,
+                                                          NULL);
                }
 
                err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       &copy_stage);
+                                                          &stage_desc,
+                                                          &copy_stage);
 
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7602,8 +7464,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                }
        }
 
-       if (need_scaler)
-       {
+       if (need_scaler) {
                struct ia_css_frame *tmp_out_frame = NULL;
                struct ia_css_frame *tmp_vf_frame = NULL;
                struct ia_css_frame *tmp_in_frame = in_frame;
@@ -7618,10 +7479,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                                tmp_vf_frame = NULL;
                        }
 
-                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
-                                                   NULL,
-                                                   &yuv_scaler_binary[i],
-                                                   &yuv_scaler_stage);
+                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+                                                  tmp_out_frame,
+                                                  NULL,
+                                                  &yuv_scaler_binary[i],
+                                                  &yuv_scaler_stage);
 
                        if (err) {
                                IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7632,8 +7494,10 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                        if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
                                if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
                                        in_frame = yuv_scaler_stage->args.out_vf_frame;
-                                       err = add_vf_pp_stage(pipe, in_frame, tmp_vf_frame, &vf_pp_binary[j],
-                                                               &vf_pp_stage);
+                                       err = add_vf_pp_stage(pipe, in_frame,
+                                                             tmp_vf_frame,
+                                                             &vf_pp_binary[j],
+                                                             &vf_pp_stage);
 
                                        if (err) {
                                                IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7643,12 +7507,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                                j++;
                        }
                }
-       } else if (copy_stage)
-       {
+       } else if (copy_stage) {
                if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
                        in_frame = copy_stage->args.out_vf_frame;
-                       err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], &vf_pp_binary[0],
-                                               &vf_pp_stage);
+                       err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
+                                             &vf_pp_binary[0], &vf_pp_stage);
                }
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7656,7 +7519,8 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
                }
        }
 
-       ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
+       ia_css_pipeline_finalize_stages(&pipe->pipeline,
+                                       pipe->stream->config.continuous);
 
        IA_CSS_LEAVE_ERR_PRIVATE(0);
 
@@ -7665,8 +7529,9 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
 
 static int
 create_host_copy_pipeline(struct ia_css_pipe *pipe,
-                           unsigned int max_input_width,
-                           struct ia_css_frame *out_frame) {
+                         unsigned int max_input_width,
+                         struct ia_css_frame *out_frame)
+{
        struct ia_css_pipeline *me;
        int err = 0;
        struct ia_css_pipeline_stage_desc stage_desc;
@@ -7683,16 +7548,10 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
 
        if (copy_on_sp(pipe) &&
-           pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8)
-       {
-               ia_css_frame_info_init(
-                   &out_frame->info,
-                   JPEG_BYTES,
-                   1,
-                   IA_CSS_FRAME_FORMAT_BINARY_8,
-                   0);
-       } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW)
-       {
+           pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
+               ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
+                                      IA_CSS_FRAME_FORMAT_BINARY_8, 0);
+       } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
                out_frame->info.raw_bit_depth =
                ia_css_pipe_util_pipe_input_format_bpp(pipe);
        }
@@ -7702,12 +7561,12 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
        pipe->mode  = IA_CSS_PIPE_ID_COPY;
 
        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
-                                           IA_CSS_PIPELINE_RAW_COPY, max_input_width);
-       err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc,
-               NULL);
+                                          IA_CSS_PIPELINE_RAW_COPY,
+                                          max_input_width);
+       err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
 
-       ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
+       ia_css_pipeline_finalize_stages(&pipe->pipeline,
+                                       pipe->stream->config.continuous);
 
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
                            "create_host_copy_pipeline() leave:\n");
@@ -7716,7 +7575,8 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
 }
 
 static int
-create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
+{
        struct ia_css_pipeline *me = &pipe->pipeline;
        int err = 0;
        struct ia_css_pipeline_stage_desc stage_desc;
@@ -7745,9 +7605,10 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
        me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
        pipe->mode  = IA_CSS_PIPE_ID_CAPTURE;
        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
-                                           IA_CSS_PIPELINE_ISYS_COPY, max_input_width);
+                                          IA_CSS_PIPELINE_ISYS_COPY,
+                                          max_input_width);
        err = ia_css_pipeline_create_and_add_stage(me,
-               &stage_desc, &out_stage);
+                                                  &stage_desc, &out_stage);
        if (err)
                return err;
 
@@ -7760,7 +7621,8 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
 }
 
 static int
-create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
+{
        struct ia_css_pipeline *me;
        int err = 0;
        enum ia_css_capture_mode mode;
@@ -7798,7 +7660,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
        IA_CSS_ENTER_PRIVATE("");
        assert(pipe);
        assert(pipe->stream);
-       assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || pipe->mode == IA_CSS_PIPE_ID_COPY);
+       assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
+              pipe->mode == IA_CSS_PIPE_ID_COPY);
 
        me = &pipe->pipeline;
        mode = pipe->config.default_capture_config.mode;
@@ -7824,8 +7687,7 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
        /* Construct in_frame info (only in case we have dynamic input */
        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
 #endif
-       if (need_in_frameinfo_memory)
-       {
+       if (need_in_frameinfo_memory) {
                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
                                                        IA_CSS_FRAME_FORMAT_RAW);
                if (err) {
@@ -7834,22 +7696,19 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
                }
 
                in_frame = &me->in_frame;
-       } else
-       {
+       } else {
                in_frame = NULL;
        }
 
        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
        out_frame = &me->out_frame[0];
 
        /* Construct vf_frame info (only in case we have VF) */
-       if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
-       {
+       if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
                if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
                        /* These modes don't support viewfinder output */
                        vf_frame = NULL;
@@ -7857,22 +7716,20 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
                        init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
                        vf_frame = &me->vf_frame[0];
                }
-       } else
-       {
+       } else {
                vf_frame = NULL;
        }
 
        copy_binary       = &pipe->pipe_settings.capture.copy_binary;
        num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
-       if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY))
-       {
+       if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
+
        for (i = 0; i < num_primary_stage; i++)
-       {
                primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
-       }
+
        vf_pp_binary      = &pipe->pipe_settings.capture.vf_pp_binary;
        pre_isp_binary    = &pipe->pipe_settings.capture.pre_isp_binary;
        anr_gdc_binary    = &pipe->pipe_settings.capture.anr_gdc_binary;
@@ -7889,43 +7746,51 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
        need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
 
-       if (pipe->pipe_settings.capture.copy_binary.info)
-       {
+       if (pipe->pipe_settings.capture.copy_binary.info) {
                if (raw) {
                        ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
 #if defined(ISP2401)
                        if (!continuous) {
-                               ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                                   out_frames, in_frame, NULL);
+                               ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                                  copy_binary,
+                                                                  out_frames,
+                                                                  in_frame,
+                                                                  NULL);
                        } else {
                                in_frame = pipe->stream->last_pipe->continuous_frames[0];
-                               ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                                   out_frames, in_frame, NULL);
+                               ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                                  copy_binary,
+                                                                  out_frames,
+                                                                  in_frame,
+                                                                  NULL);
                        }
 #else
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                           out_frames, NULL, NULL);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          copy_binary,
+                                                          out_frames,
+                                                          NULL, NULL);
 #endif
                } else {
-                       ia_css_pipe_util_set_output_frames(out_frames, 0, in_frame);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
-                                                           out_frames, NULL, NULL);
+                       ia_css_pipe_util_set_output_frames(out_frames, 0,
+                                                          in_frame);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          copy_binary,
+                                                          out_frames,
+                                                          NULL, NULL);
                }
 
                err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       &current_stage);
+                                                          &stage_desc,
+                                                          &current_stage);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
                }
-       } else if (pipe->stream->config.continuous)
-       {
+       } else if (pipe->stream->config.continuous) {
                in_frame = pipe->stream->last_pipe->continuous_frames[0];
        }
 
-       if (mode == IA_CSS_CAPTURE_MODE_PRIMARY)
-       {
+       if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
                struct ia_css_frame *local_in_frame = NULL;
                struct ia_css_frame *local_out_frame = NULL;
 
@@ -7953,11 +7818,14 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
                            * Proper investigation should be done to come up with the clean
                            * solution.
                            * */
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, primary_binary[i],
-                                                           out_frames, local_in_frame, NULL);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          primary_binary[i],
+                                                          out_frames,
+                                                          local_in_frame,
+                                                          NULL);
                        err = ia_css_pipeline_create_and_add_stage(me,
-                               &stage_desc,
-                               &current_stage);
+                                                                  &stage_desc,
+                                                                  &current_stage);
                        if (err) {
                                IA_CSS_LEAVE_ERR_PRIVATE(err);
                                return err;
@@ -7970,22 +7838,21 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
                    IA_CSS_BINARY_MODE_COPY;
                current_stage->args.copy_output = current_stage->args.copy_vf;
        } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
-                   mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT)
-       {
+                   mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
-                                                   out_frames, in_frame, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc, NULL);
+                                                  out_frames, in_frame, NULL);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          NULL);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
                }
                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
-                                                   out_frames, NULL, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc, NULL);
+                                                  out_frames, NULL, NULL);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          NULL);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
@@ -7993,28 +7860,31 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
 
                if (need_pp) {
                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary,
-                                                           out_frames, NULL, NULL);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          post_isp_binary,
+                                                          out_frames,
+                                                          NULL, NULL);
                } else {
-                       ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary,
-                                                           out_frames, NULL, NULL);
+                       ia_css_pipe_util_set_output_frames(out_frames, 0,
+                                                          out_frame);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          post_isp_binary,
+                                                          out_frames,
+                                                          NULL, NULL);
                }
 
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc, &current_stage);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          &current_stage);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
                }
-       } else if (mode == IA_CSS_CAPTURE_MODE_BAYER)
-       {
+       } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
-                                                   out_frames, in_frame, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       NULL);
+                                                  out_frames, in_frame, NULL);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          NULL);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
@@ -8022,49 +7892,48 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
        }
 
 #ifndef ISP2401
-       if (need_pp && current_stage)
-       {
+       if (need_pp && current_stage) {
                struct ia_css_frame *local_in_frame = NULL;
 
                local_in_frame = current_stage->args.out_frame[0];
 
                if (need_ldc) {
                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
-                       ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
-                                                           out_frames, local_in_frame, NULL);
+                       ia_css_pipe_get_generic_stage_desc(&stage_desc,
+                                                          capture_ldc_binary,
+                                                          out_frames,
+                                                          local_in_frame,
+                                                          NULL);
                        err = ia_css_pipeline_create_and_add_stage(me,
-                               &stage_desc,
-                               &current_stage);
+                                                                  &stage_desc,
+                                                                  &current_stage);
                        local_in_frame = current_stage->args.out_frame[0];
                }
                err = add_capture_pp_stage(pipe, me, local_in_frame,
-                                           need_yuv_pp ? NULL : out_frame,
+                                          need_yuv_pp ? NULL : out_frame,
 #else
        /* ldc and capture_pp not supported in same pipeline */
-       if (need_ldc && current_stage)
-       {
+       if (need_ldc && current_stage) {
                in_frame = current_stage->args.out_frame[0];
                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
                ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
-                                                   out_frames, in_frame, NULL);
-               err = ia_css_pipeline_create_and_add_stage(me,
-                       &stage_desc,
-                       NULL);
-       } else if (need_pp && current_stage)
-       {
+                                                  out_frames, in_frame, NULL);
+               err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+                                                          NULL);
+       } else if (need_pp && current_stage) {
                in_frame = current_stage->args.out_frame[0];
-               err = add_capture_pp_stage(pipe, me, in_frame, need_yuv_pp ? NULL : out_frame,
+               err = add_capture_pp_stage(pipe, me, in_frame,
+                                          need_yuv_pp ? NULL : out_frame,
 #endif
-                                           capture_pp_binary,
-                                           &current_stage);
+                                          capture_pp_binary,
+                                          &current_stage);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
                }
        }
 
-       if (need_yuv_pp && current_stage)
-       {
+       if (need_yuv_pp && current_stage) {
                struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
                struct ia_css_frame *tmp_out_frame = NULL;
 
@@ -8074,10 +7943,10 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
                        else
                                tmp_out_frame = NULL;
 
-                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
-                                                   NULL,
-                                                   &yuv_scaler_binary[i],
-                                                   &yuv_scaler_stage);
+                       err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+                                                  tmp_out_frame, NULL,
+                                                  &yuv_scaler_binary[i],
+                                                  &yuv_scaler_stage);
                        if (err) {
                                IA_CSS_LEAVE_ERR_PRIVATE(err);
                                return err;
@@ -8096,11 +7965,12 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
            * should not be considered as a clean solution. Proper
            * investigation should be done to come up with the clean solution.
            * */
-       if (mode != IA_CSS_CAPTURE_MODE_RAW && mode != IA_CSS_CAPTURE_MODE_BAYER && current_stage && vf_frame)
-       {
+       if (mode != IA_CSS_CAPTURE_MODE_RAW &&
+           mode != IA_CSS_CAPTURE_MODE_BAYER &&
+           current_stage && vf_frame) {
                in_frame = current_stage->args.out_vf_frame;
                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
-                                       &current_stage);
+                                     &current_stage);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        return err;
@@ -8115,7 +7985,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
 }
 
 static int
-create_host_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_capture_pipeline(struct ia_css_pipe *pipe)
+{
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
@@ -8124,8 +7995,7 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) {
                err = create_host_isyscopy_capture_pipeline(pipe);
        else
                err = create_host_regular_capture_pipeline(pipe);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
@@ -8135,8 +8005,8 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) {
        return err;
 }
 
-static int capture_start(
-    struct ia_css_pipe *pipe) {
+static int capture_start(struct ia_css_pipe *pipe)
+{
        struct ia_css_pipeline *me;
 
        int err = 0;
@@ -8151,7 +8021,7 @@ static int capture_start(
        me = &pipe->pipeline;
 
        if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW   ||
-               pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
+            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
            (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
                if (copy_on_sp(pipe)) {
                        err = start_copy_on_sp(pipe, &me->out_frame[0]);
@@ -8195,7 +8065,7 @@ static int capture_start(
        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
            pipe->stream->reconfigure_css_rx) {
                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
-                                           pipe->stream->config.mode);
+                                        pipe->stream->config.mode);
                pipe->stream->reconfigure_css_rx = false;
        }
 #endif
@@ -8206,8 +8076,9 @@ static int capture_start(
 
 static int
 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
-                                   struct ia_css_frame_info *info,
-                                   unsigned int idx) {
+                                 struct ia_css_frame_info *info,
+                                 unsigned int idx)
+{
        assert(pipe);
        assert(info);
 
@@ -8216,8 +8087,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
 
        *info = pipe->output_info[idx];
        if (copy_on_sp(pipe) &&
-           pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8)
-       {
+           pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
                ia_css_frame_info_init(
                    info,
                    JPEG_BYTES,
@@ -8225,8 +8095,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
                    IA_CSS_FRAME_FORMAT_BINARY_8,
                    0);
        } else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
-                   info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)
-       {
+                  info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
                info->raw_bit_depth =
                ia_css_pipe_util_pipe_input_format_bpp(pipe);
        }
@@ -8238,9 +8107,10 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
 
 void
 ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
-                               const unsigned short *data,
-                               unsigned int width,
-                               unsigned int height) {
+                              const unsigned short *data,
+                              unsigned int width,
+                              unsigned int height)
+{
        assert(stream);
 
        ia_css_inputfifo_send_input_frame(
@@ -8251,7 +8121,8 @@ ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
 }
 
 void
-ia_css_stream_start_input_frame(const struct ia_css_stream *stream) {
+ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
+{
        assert(stream);
 
        ia_css_inputfifo_start_frame(
@@ -8262,21 +8133,23 @@ ia_css_stream_start_input_frame(const struct ia_css_stream *stream) {
 
 void
 ia_css_stream_send_input_line(const struct ia_css_stream *stream,
-                               const unsigned short *data,
-                               unsigned int width,
-                               const unsigned short *data2,
-                               unsigned int width2) {
+                             const unsigned short *data,
+                             unsigned int width,
+                             const unsigned short *data2,
+                             unsigned int width2)
+{
        assert(stream);
 
        ia_css_inputfifo_send_line(stream->config.channel_id,
-                                   data, width, data2, width2);
+                                  data, width, data2, width2);
 }
 
 void
 ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
-                                       enum atomisp_input_format format,
-                                       const unsigned short *data,
-                                       unsigned int width) {
+                                      enum atomisp_input_format format,
+                                      const unsigned short *data,
+                                      unsigned int width)
+{
        assert(stream);
        if (!data || width == 0)
                return;
@@ -8285,14 +8158,16 @@ ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
 }
 
 void
-ia_css_stream_end_input_frame(const struct ia_css_stream *stream) {
+ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
+{
        assert(stream);
 
        ia_css_inputfifo_end_frame(stream->config.channel_id);
 }
 
 static void
-append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
+append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
+{
        IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
        if (!l) {
                IA_CSS_ERROR("NULL fw_info");
@@ -8307,7 +8182,8 @@ append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
 }
 
 static void
-remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
+remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
+{
        assert(*l);
        assert(firmware);
        (void)l;
@@ -8349,12 +8225,12 @@ static int upload_isp_code(struct ia_css_fw_info *firmware)
 }
 
 static int
-acc_load_extension(struct ia_css_fw_info *firmware) {
+acc_load_extension(struct ia_css_fw_info *firmware)
+{
        int err;
        struct ia_css_fw_info *hd = firmware;
 
-       while (hd)
-       {
+       while (hd) {
                err = upload_isp_code(hd);
                if (err)
                        return err;
@@ -8368,7 +8244,8 @@ acc_load_extension(struct ia_css_fw_info *firmware) {
 }
 
 static void
-acc_unload_extension(struct ia_css_fw_info *firmware) {
+acc_unload_extension(struct ia_css_fw_info *firmware)
+{
        struct ia_css_fw_info *hd = firmware;
        struct ia_css_fw_info *hdn = NULL;
 
@@ -8392,13 +8269,13 @@ acc_unload_extension(struct ia_css_fw_info *firmware) {
 /* Load firmware for extension */
 static int
 ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
-                           struct ia_css_fw_info *firmware) {
+                          struct ia_css_fw_info *firmware)
+{
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
 
-       if ((!firmware) || (!pipe))
-       {
+       if ((!firmware) || (!pipe)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -8416,7 +8293,8 @@ ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
 /* Unload firmware for extension */
 static void
 ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
-                               struct ia_css_fw_info *firmware) {
+                            struct ia_css_fw_info *firmware)
+{
        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
 
        if ((!firmware) || (!pipe)) {
@@ -8435,7 +8313,8 @@ ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
 }
 
 bool
-ia_css_pipeline_uses_params(struct ia_css_pipeline *me) {
+ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
+{
        struct ia_css_pipeline_stage *stage;
 
        assert(me);
@@ -8456,7 +8335,8 @@ ia_css_pipeline_uses_params(struct ia_css_pipeline *me) {
 
 static int
 sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
-                               const void *acc_fw) {
+                             const void *acc_fw)
+{
        struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
        /* In QoS case, load_extension already called, so skipping */
        int     err = 0;
@@ -8468,14 +8348,13 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
                            "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
                            pipeline, acc_fw);
 
-       if (!err)
-       {
+       if (!err) {
                struct ia_css_pipeline_stage_desc stage_desc;
 
                ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
                err = ia_css_pipeline_create_and_add_stage(pipeline,
-                       &stage_desc,
-                       NULL);
+                                                          &stage_desc,
+                                                          NULL);
        }
 
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -8488,7 +8367,8 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
     * Refer to "sh_css_internal.h" for details.
     */
 int ia_css_stream_capture_frame(struct ia_css_stream *stream,
-       unsigned int exp_id) {
+                               unsigned int exp_id)
+{
        struct sh_css_tag_descr tag_descr;
        u32 encoded_tag_descr;
        int err;
@@ -8526,11 +8406,9 @@ int ia_css_stream_capture_frame(struct ia_css_stream *stream,
     * @brief Configure the continuous capture.
     * Refer to "sh_css_internal.h" for details.
     */
-int ia_css_stream_capture(
-    struct ia_css_stream *stream,
-    int num_captures,
-    unsigned int skip,
-    int offset) {
+int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
+                         unsigned int skip, int offset)
+{
        struct sh_css_tag_descr tag_descr;
        unsigned int encoded_tag_descr;
        int return_err;
@@ -8593,8 +8471,9 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream)
                        ia_css_debug_dump_sp_sw_debug_info();
                        ia_css_debug_dump_debug_info(NULL);
                }
-       } else
+       } else {
                IA_CSS_LOG("SP is not running!");
+       }
 
 #endif
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -8602,7 +8481,8 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream)
 }
 
 static void
-sh_css_init_host_sp_control_vars(void) {
+sh_css_init_host_sp_control_vars(void)
+{
        const struct ia_css_fw_info *fw;
        unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
 
@@ -8643,22 +8523,22 @@ sh_css_init_host_sp_control_vars(void) {
        (void)HIVE_ADDR_host_sp_com;
 
        sp_dmem_store_uint32(SP0_ID,
-                               (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
-                               (uint32_t)(0));
+                            (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
+                            (uint32_t)(0));
 
        sp_dmem_store_uint32(SP0_ID,
-                               (unsigned int)sp_address_of(host_sp_queues_initialized),
-                               (uint32_t)(0));
+                            (unsigned int)sp_address_of(host_sp_queues_initialized),
+                            (uint32_t)(0));
        sp_dmem_store_uint32(SP0_ID,
-                               (unsigned int)sp_address_of(sp_sleep_mode),
-                               (uint32_t)(0));
+                            (unsigned int)sp_address_of(sp_sleep_mode),
+                            (uint32_t)(0));
        sp_dmem_store_uint32(SP0_ID,
-                               (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
-                               (uint32_t)(false));
+                            (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
+                            (uint32_t)(false));
 #ifndef ISP2401
        sp_dmem_store_uint32(SP0_ID,
-                               (unsigned int)sp_address_of(sp_stop_copy_preview),
-                               my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
+                            (unsigned int)sp_address_of(sp_stop_copy_preview),
+                            my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
 #endif
        store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
 
@@ -8685,8 +8565,8 @@ void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
 }
 
 void
-ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config
-                                   *extra_config) {
+ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
+{
        if (!extra_config) {
                IA_CSS_ERROR("NULL input parameter");
                return;
@@ -8716,11 +8596,11 @@ void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
 }
 
 static int
-ia_css_acc_pipe_create(struct ia_css_pipe *pipe) {
+ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
+{
        int err = 0;
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_ERROR("NULL input parameter");
                return -EINVAL;
        }
@@ -8730,9 +8610,7 @@ ia_css_acc_pipe_create(struct ia_css_pipe *pipe) {
                pipe->config.acc_num_execs = 1;
 
        if (pipe->config.acc_extension)
-       {
                err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
-       }
 
        return err;
 }
@@ -8751,9 +8629,8 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config,
 
        err = ia_css_pipe_create_extra(config, NULL, pipe);
 
-       if (err == 0) {
+       if (err == 0)
                IA_CSS_LOG("pipe created successfully = %p", *pipe);
-       }
 
        IA_CSS_LEAVE_ERR_PRIVATE(err);
 
@@ -8762,8 +8639,9 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config,
 
 int
 ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
-                           const struct ia_css_pipe_extra_config *extra_config,
-                           struct ia_css_pipe **pipe) {
+                        const struct ia_css_pipe_extra_config *extra_config,
+                        struct ia_css_pipe **pipe)
+{
        int err = -EINVAL;
        struct ia_css_pipe *internal_pipe = NULL;
        unsigned int i;
@@ -8771,14 +8649,12 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
        IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
 
        /* do not allow to create more than the maximum limit */
-       if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX)
-       {
+       if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
                IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
                return -EINVAL;
        }
 
-       if ((!pipe) || (!config))
-       {
+       if ((!pipe) || (!config)) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
@@ -8787,8 +8663,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
        ia_css_debug_dump_pipe_extra_config(extra_config);
 
        err = create_pipe(config->mode, &internal_pipe, false);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
@@ -8800,8 +8675,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
        else
                ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
 
-       if (config->mode == IA_CSS_PIPE_MODE_ACC)
-       {
+       if (config->mode == IA_CSS_PIPE_MODE_ACC) {
                /* Temporary hack to migrate acceleration to CSS 2.0.
                    * In the future the code for all pipe types should be
                    * unified. */
@@ -8828,15 +8702,13 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
            set bayer_ds_out_res equal to IF output resolution(IF may do cropping on
            sensor output) or use default decimation factor 1. */
        if (internal_pipe->extra_config.enable_raw_binning &&
-           internal_pipe->config.bayer_ds_out_res.width)
-       {
+           internal_pipe->config.bayer_ds_out_res.width) {
                /* fill some code here, if no code is needed, please remove it during integration */
        }
 
        /* YUV downscaling */
        if ((internal_pipe->config.vf_pp_in_res.width ||
-               internal_pipe->config.capt_pp_in_res.width))
-       {
+            internal_pipe->config.capt_pp_in_res.width)) {
                enum ia_css_frame_format format;
 
                if (internal_pipe->config.vf_pp_in_res.width) {
@@ -8857,8 +8729,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
                }
        }
        if (internal_pipe->config.vf_pp_in_res.width &&
-           internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
-       {
+           internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
                ia_css_frame_info_init(
                    &internal_pipe->vf_yuv_ds_input_info,
                    internal_pipe->config.vf_pp_in_res.width,
@@ -8866,8 +8737,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
                    IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
        }
        /* handle bayer downscaling output info */
-       if (internal_pipe->config.bayer_ds_out_res.width)
-       {
+       if (internal_pipe->config.bayer_ds_out_res.width) {
                ia_css_frame_info_init(
                    &internal_pipe->bds_output_info,
                    internal_pipe->config.bayer_ds_out_res.width,
@@ -8876,8 +8746,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
        }
 
        /* handle output info, assume always needed */
-       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
-       {
+       for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
                if (internal_pipe->config.output_info[i].res.width) {
                        err = sh_css_pipe_configure_output(
                                    internal_pipe,
@@ -8913,10 +8782,9 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
                        }
                }
        }
-       if (internal_pipe->config.acc_extension)
-       {
+       if (internal_pipe->config.acc_extension) {
                err = ia_css_pipe_load_extension(internal_pipe,
-                                                   internal_pipe->config.acc_extension);
+                                                internal_pipe->config.acc_extension);
                if (err) {
                        IA_CSS_LEAVE_ERR_PRIVATE(err);
                        kvfree(internal_pipe);
@@ -8934,18 +8802,16 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
 
 int
 ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
-                       struct ia_css_pipe_info *pipe_info) {
+                    struct ia_css_pipe_info *pipe_info)
+{
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
                            "ia_css_pipe_get_info()\n");
-       assert(pipe_info);
-       if (!pipe_info)
-       {
+       if (!pipe_info) {
                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
                                    "ia_css_pipe_get_info: pipe_info cannot be NULL\n");
                return -EINVAL;
        }
-       if (!pipe || !pipe->stream)
-       {
+       if (!pipe || !pipe->stream) {
                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
                                    "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
                return -EINVAL;
@@ -8972,41 +8838,37 @@ bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
 
 int
 ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
-                                   int pin_index,
-                                   enum ia_css_frame_format new_format) {
+                                 int pin_index,
+                                 enum ia_css_frame_format new_format)
+{
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
 
-       if (!pipe)
-       {
+       if (!pipe) {
                IA_CSS_ERROR("pipe is not set");
                err = -EINVAL;
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
-       if (0 != pin_index && 1 != pin_index)
-       {
+       if (0 != pin_index && 1 != pin_index) {
                IA_CSS_ERROR("pin index is not valid");
                err = -EINVAL;
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
-       if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY)
-       {
+       if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
                IA_CSS_ERROR("new format is not valid");
                err = -EINVAL;
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
-       } else
-       {
+       } else {
                err = ia_css_pipe_check_format(pipe, new_format);
                if (!err) {
-                       if (pin_index == 0) {
+                       if (pin_index == 0)
                                pipe->output_info[0].format = new_format;
-                       } else {
+                       else
                                pipe->vf_output_info[0].format = new_format;
-                       }
                }
        }
        IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -9016,7 +8878,8 @@ ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
 #if !defined(ISP2401)
 /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
 static int
-ia_css_stream_configure_rx(struct ia_css_stream *stream) {
+ia_css_stream_configure_rx(struct ia_css_stream *stream)
+{
        struct ia_css_input_port *config;
 
        assert(stream);
@@ -9045,11 +8908,10 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) {
        if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
                stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
        else
-       {
                /* not implemented yet, requires extension of the rx_cfg_t
                    * struct */
                return -EINVAL;
-       }
+
        stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
        stream->reconfigure_css_rx = true;
        return 0;
@@ -9057,10 +8919,9 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) {
 #endif
 
 static struct ia_css_pipe *
-find_pipe(struct ia_css_pipe *pipes[],
-           unsigned int num_pipes,
-           enum ia_css_pipe_mode mode,
-           bool copy_pipe) {
+find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
+         enum ia_css_pipe_mode mode, bool copy_pipe)
+{
        unsigned int i;
 
        assert(pipes);
@@ -9076,24 +8937,21 @@ find_pipe(struct ia_css_pipe *pipes[],
 }
 
 static int
-ia_css_acc_stream_create(struct ia_css_stream *stream) {
+ia_css_acc_stream_create(struct ia_css_stream *stream)
+{
        int i;
        int err = 0;
 
-       assert(stream);
        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
 
-       if (!stream)
-       {
+       if (!stream) {
                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                return -EINVAL;
        }
 
-       for (i = 0;  i < stream->num_pipes; i++)
-       {
+       for (i = 0;  i < stream->num_pipes; i++) {
                struct ia_css_pipe *pipe = stream->pipes[i];
 
-               assert(pipe);
                if (!pipe) {
                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
                        return -EINVAL;
@@ -9104,14 +8962,12 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
 
        /* Map SP threads before doing anything. */
        err = map_sp_threads(stream, true);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
 
-       for (i = 0;  i < stream->num_pipes; i++)
-       {
+       for (i = 0;  i < stream->num_pipes; i++) {
                struct ia_css_pipe *pipe = stream->pipes[i];
 
                assert(pipe);
@@ -9119,8 +8975,7 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
        }
 
        err = create_host_pipeline_structure(stream);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
        }
@@ -9134,7 +8989,8 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
 
 static int
 metadata_info_init(const struct ia_css_metadata_config *mdc,
-                   struct ia_css_metadata_info *md) {
+                  struct ia_css_metadata_info *md)
+{
        /* Either both width and height should be set or neither */
        if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
                return -EINVAL;
@@ -9161,7 +9017,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
        }
 
        if (ia_css_util_check_res(pipe->config.input_effective_res.width,
-                                   pipe->config.input_effective_res.height) != 0) {
+                                 pipe->config.input_effective_res.height) != 0) {
                IA_CSS_ERROR("effective resolution not supported");
                err = -EINVAL;
                goto EXIT;
@@ -9169,7 +9025,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
        if (!ia_css_util_resolution_is_zero(
                pipe->stream->config.input_config.input_res)) {
                if (!ia_css_util_res_leq(pipe->config.input_effective_res,
-                                           pipe->stream->config.input_config.input_res)) {
+                                        pipe->stream->config.input_config.input_res)) {
                        IA_CSS_ERROR("effective resolution is larger than input resolution");
                        err = -EINVAL;
                        goto EXIT;
@@ -9192,9 +9048,10 @@ EXIT:
 
 int
 ia_css_stream_create(const struct ia_css_stream_config *stream_config,
-                       int num_pipes,
-                       struct ia_css_pipe *pipes[],
-                       struct ia_css_stream **stream) {
+                    int num_pipes,
+                    struct ia_css_pipe *pipes[],
+                    struct ia_css_stream **stream)
+{
        struct ia_css_pipe *curr_pipe;
        struct ia_css_stream *curr_stream = NULL;
        bool spcopyonly;
@@ -9213,8 +9070,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
        /* some checks */
        if (num_pipes == 0 ||
            !stream ||
-           !pipes)
-       {
+           !pipes) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -9223,8 +9079,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 #if !defined(ISP2401)
        /* We don't support metadata for JPEG stream, since they both use str2mem */
        if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
-           stream_config->metadata_config.resolution.height > 0)
-       {
+           stream_config->metadata_config.resolution.height > 0) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -9232,8 +9087,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 #endif
 
 #ifdef ISP2401
-       if (stream_config->online && stream_config->pack_raw_pixels)
-       {
+       if (stream_config->online && stream_config->pack_raw_pixels) {
                IA_CSS_LOG("online and pack raw is invalid on input system 2401");
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
@@ -9288,16 +9142,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 
        /* Currently we only supported metadata up to a certain size. */
        err = metadata_info_init(&stream_config->metadata_config, &md_info);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
 
        /* allocate the stream instance */
        curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
-       if (!curr_stream)
-       {
+       if (!curr_stream) {
                err = -ENOMEM;
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -9308,8 +9160,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
        /* allocate pipes */
        curr_stream->num_pipes = num_pipes;
        curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
-       if (!curr_stream->pipes)
-       {
+       if (!curr_stream->pipes) {
                curr_stream->num_pipes = 0;
                kfree(curr_stream);
                curr_stream = NULL;
@@ -9332,8 +9183,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 #endif
 
 #ifdef ISP2401
-       if (curr_stream->config.online)
-       {
+       if (curr_stream->config.online) {
                curr_stream->config.source.port.num_lanes =
                    stream_config->source.port.num_lanes;
                curr_stream->config.mode =  IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
@@ -9351,8 +9201,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                    curr_stream->config.lock_all);
 
        /* copy mode specific stuff */
-       switch (curr_stream->config.mode)
-       {
+       switch (curr_stream->config.mode) {
        case IA_CSS_INPUT_MODE_SENSOR:
        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 #if !defined(ISP2401)
@@ -9362,11 +9211,11 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
        case IA_CSS_INPUT_MODE_TPG:
 #if !defined(ISP2401)
                IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
-                           curr_stream->config.source.tpg.x_mask,
-                           curr_stream->config.source.tpg.y_mask,
-                           curr_stream->config.source.tpg.x_delta,
-                           curr_stream->config.source.tpg.y_delta,
-                           curr_stream->config.source.tpg.xy_mask);
+                          curr_stream->config.source.tpg.x_mask,
+                          curr_stream->config.source.tpg.y_mask,
+                          curr_stream->config.source.tpg.x_delta,
+                          curr_stream->config.source.tpg.y_delta,
+                          curr_stream->config.source.tpg.xy_mask);
 
                sh_css_sp_configure_tpg(
                    curr_stream->config.source.tpg.x_mask,
@@ -9391,17 +9240,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
        }
 
 #ifdef ISP2401
-       err = aspect_ratio_crop_init(curr_stream,
-                                       pipes,
-                                       &aspect_ratio_crop_enabled);
-       if (err)
-       {
+       err = aspect_ratio_crop_init(curr_stream, pipes,
+                                    &aspect_ratio_crop_enabled);
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                goto ERR;
        }
 #endif
-       for (i = 0; i < num_pipes; i++)
-       {
+       for (i = 0; i < num_pipes; i++) {
                struct ia_css_resolution effective_res;
 
                curr_pipe = pipes[i];
@@ -9432,8 +9278,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                        curr_pipe->config.input_effective_res = effective_res;
                }
                IA_CSS_LOG("effective_res=%dx%d",
-                           effective_res.width,
-                           effective_res.height);
+                          effective_res.width,
+                          effective_res.height);
        }
 
        if (IS_ISP2401) {
@@ -9441,9 +9287,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                        if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC &&
                            pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) {
                                err = check_pipe_resolutions(pipes[i]);
-                               if (err) {
+                               if (err)
                                        goto ERR;
-                               }
                        }
                }
        }
@@ -9453,32 +9298,28 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                goto ERR;
        IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
 
-       if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC)
-       {
+       if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
                *stream = curr_stream;
                err = ia_css_acc_stream_create(curr_stream);
                goto ERR;
        }
        /* sensor binning */
-       if (!spcopyonly)
-       {
+       if (!spcopyonly) {
                sensor_binning_changed =
                    sh_css_params_set_binning_factor(curr_stream,
-                                                       curr_stream->config.sensor_binning_factor);
-       } else
-       {
+                                                    curr_stream->config.sensor_binning_factor);
+       } else {
                sensor_binning_changed = false;
        }
 
        IA_CSS_LOG("sensor_binning=%d, changed=%d",
-                   curr_stream->config.sensor_binning_factor, sensor_binning_changed);
+                  curr_stream->config.sensor_binning_factor, sensor_binning_changed);
        /* loop over pipes */
        IA_CSS_LOG("num_pipes=%d", num_pipes);
        curr_stream->cont_capt = false;
        /* Temporary hack: we give the preview pipe a reference to the capture
            * pipe in continuous capture mode. */
-       if (curr_stream->config.continuous)
-       {
+       if (curr_stream->config.continuous) {
                /* Search for the preview pipe and create the copy pipe */
                struct ia_css_pipe *preview_pipe;
                struct ia_css_pipe *video_pipe;
@@ -9496,17 +9337,18 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 
                /* Create copy pipe here, since it may not be exposed to the driver */
                preview_pipe = find_pipe(pipes, num_pipes,
-                                           IA_CSS_PIPE_MODE_PREVIEW, false);
+                                        IA_CSS_PIPE_MODE_PREVIEW, false);
                video_pipe = find_pipe(pipes, num_pipes,
-                                       IA_CSS_PIPE_MODE_VIDEO, false);
-               acc_pipe = find_pipe(pipes, num_pipes,
-                                       IA_CSS_PIPE_MODE_ACC, false);
+                                      IA_CSS_PIPE_MODE_VIDEO, false);
+               acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
+                                    false);
                if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
                        curr_stream->cont_capt =
                            false; /* preview + QoS case will not need cont_capt switch */
                if (curr_stream->cont_capt) {
                        capture_pipe = find_pipe(pipes, num_pipes,
-                                                   IA_CSS_PIPE_MODE_CAPTURE, false);
+                                                IA_CSS_PIPE_MODE_CAPTURE,
+                                                false);
                        if (!capture_pipe) {
                                err = -EINVAL;
                                goto ERR;
@@ -9526,9 +9368,9 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                        preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
                        copy_pipe->stream = curr_stream;
                }
-               if (preview_pipe && curr_stream->cont_capt) {
+               if (preview_pipe && curr_stream->cont_capt)
                        preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
-               }
+
                if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
                        err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
                        if (err)
@@ -9537,15 +9379,13 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                        video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
                        copy_pipe->stream = curr_stream;
                }
-               if (video_pipe && curr_stream->cont_capt) {
+               if (video_pipe && curr_stream->cont_capt)
                        video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
-               }
-               if (preview_pipe && acc_pipe) {
+
+               if (preview_pipe && acc_pipe)
                        preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
-               }
        }
-       for (i = 0; i < num_pipes; i++)
-       {
+       for (i = 0; i < num_pipes; i++) {
                curr_pipe = pipes[i];
                /* set current stream */
                curr_pipe->stream = curr_stream;
@@ -9566,8 +9406,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
        }
 
        /* now pipes have been configured, info should be available */
-       for (i = 0; i < num_pipes; i++)
-       {
+       for (i = 0; i < num_pipes; i++) {
                struct ia_css_pipe_info *pipe_info = NULL;
 
                curr_pipe = pipes[i];
@@ -9591,10 +9430,12 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                if (!spcopyonly) {
                        if (!IS_ISP2401)
                                err = sh_css_pipe_get_shading_info(curr_pipe,
-                                                                   &pipe_info->shading_info, NULL);
+                                                                  &pipe_info->shading_info,
+                                                                  NULL);
                        else
                                err = sh_css_pipe_get_shading_info(curr_pipe,
-                                                                   &pipe_info->shading_info, &curr_pipe->config);
+                                                                  &pipe_info->shading_info,
+                                                                  &curr_pipe->config);
 
                        if (err)
                                goto ERR;
@@ -9604,7 +9445,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
                                goto ERR;
                        for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
                                sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
-                                                                       &pipe_info->vf_output_info[j], j);
+                                                                     &pipe_info->vf_output_info[j],
+                                                                     j);
                                if (err)
                                        goto ERR;
                        }
@@ -9617,22 +9459,19 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
 
        /* Map SP threads before doing anything. */
        err = map_sp_threads(curr_stream, true);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LOG("map_sp_threads: return_err=%d", err);
                goto ERR;
        }
 
-       for (i = 0; i < num_pipes; i++)
-       {
+       for (i = 0; i < num_pipes; i++) {
                curr_pipe = pipes[i];
                ia_css_pipe_map_queue(curr_pipe, true);
        }
 
        /* Create host side pipeline objects without stages */
        err = create_host_pipeline_structure(curr_stream);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
                goto ERR;
        }
@@ -9670,13 +9509,13 @@ ERR:
 }
 
 int
-ia_css_stream_destroy(struct ia_css_stream *stream) {
+ia_css_stream_destroy(struct ia_css_stream *stream)
+{
        int i;
        int err = 0;
 
        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
-       if (!stream)
-       {
+       if (!stream) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR_PRIVATE(err);
                return err;
@@ -9685,8 +9524,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
        ia_css_stream_isp_parameters_uninit(stream);
 
        if ((stream->last_pipe) &&
-           ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num))
-       {
+           ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
 #if defined(ISP2401)
                bool free_mpi;
 
@@ -9748,8 +9586,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
        }
 
        /* remove references from pipes to stream */
-       for (i = 0; i < stream->num_pipes; i++)
-       {
+       for (i = 0; i < stream->num_pipes; i++) {
                struct ia_css_pipe *entry = stream->pipes[i];
 
                assert(entry);
@@ -9778,8 +9615,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
        /* working mode: take out of the seed list */
        if (my_css_save.mode == sh_css_mode_working) {
                for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
-                       if (my_css_save.stream_seeds[i].stream == stream)
-                       {
+                       if (my_css_save.stream_seeds[i].stream == stream) {
                                IA_CSS_LOG("took out stream %d", i);
                                my_css_save.stream_seeds[i].stream = NULL;
                                break;
@@ -9795,7 +9631,8 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
 
 int
 ia_css_stream_get_info(const struct ia_css_stream *stream,
-                       struct ia_css_stream_info *stream_info) {
+                      struct ia_css_stream_info *stream_info)
+{
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
        assert(stream);
        assert(stream_info);
@@ -9811,59 +9648,58 @@ ia_css_stream_get_info(const struct ia_css_stream *stream,
     * The stream handle is used to identify the correct entry in the css_save struct
     */
 int
-ia_css_stream_load(struct ia_css_stream *stream) {
-       if (!IS_ISP2401) {
-               int i;
-               int err;
-
-               assert(stream);
-               ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
-               for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
-               {
-                       if (my_css_save.stream_seeds[i].stream == stream) {
-                               int j;
-
-                               for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
-                                       if ((err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
-                                                                   &my_css_save.stream_seeds[i].pipes[j])) != 0) {
-                                               if (j) {
-                                                       int k;
+ia_css_stream_load(struct ia_css_stream *stream)
+{
+       int i, j, err;
 
-                                                       for (k = 0; k < j; k++)
-                                                               ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
-                                               }
-                                               return err;
-                                       }
-                               }
-                               err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
-                                                       my_css_save.stream_seeds[i].num_pipes,
-                                                       my_css_save.stream_seeds[i].pipes,
-                                                       &my_css_save.stream_seeds[i].stream);
-                               if (err) {
-                                       ia_css_stream_destroy(stream);
-                                       for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
-                                               ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
-                                       return err;
-                               }
-                               break;
-                       }
-               }
-               ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
-               return 0;
-       } else {
+       if (IS_ISP2401) {
                /* TODO remove function - DEPRECATED */
                (void)stream;
                return -ENOTSUPP;
        }
+
+       assert(stream);
+       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
+       for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
+               if (my_css_save.stream_seeds[i].stream != stream)
+                       continue;
+
+               for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
+                       int k;
+
+                       err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
+                                                &my_css_save.stream_seeds[i].pipes[j]);
+                       if (!err)
+                               continue;
+
+                       for (k = 0; k < j; k++)
+                               ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
+                       return err;
+               }
+               err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
+                                          my_css_save.stream_seeds[i].num_pipes,
+                                          my_css_save.stream_seeds[i].pipes,
+                                          &my_css_save.stream_seeds[i].stream);
+               if (!err)
+                       break;
+
+               ia_css_stream_destroy(stream);
+               for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
+                       ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
+               return err;
+       }
+
+       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
+       return 0;
 }
 
 int
-ia_css_stream_start(struct ia_css_stream *stream) {
+ia_css_stream_start(struct ia_css_stream *stream)
+{
        int err = 0;
 
        IA_CSS_ENTER("stream = %p", stream);
-       if ((!stream) || (!stream->last_pipe))
-       {
+       if ((!stream) || (!stream->last_pipe)) {
                IA_CSS_LEAVE_ERR(-EINVAL);
                return -EINVAL;
        }
@@ -9873,8 +9709,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
 
        /* Create host side pipeline. */
        err = create_host_pipeline(stream);
-       if (err)
-       {
+       if (err) {
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
@@ -9887,8 +9722,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
 
 #if !defined(ISP2401)
        /* Initialize mipi size checks */
-       if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
-       {
+       if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
                unsigned int idx;
                unsigned int port = (unsigned int)(stream->config.source.port.port);
 
@@ -9899,8 +9733,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
        }
 #endif
 
-       if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)
-       {
+       if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
                err = sh_css_config_input_network(stream);
                if (err)
                        return err;
@@ -9912,7 +9745,8 @@ ia_css_stream_start(struct ia_css_stream *stream) {
 }
 
 int
-ia_css_stream_stop(struct ia_css_stream *stream) {
+ia_css_stream_stop(struct ia_css_stream *stream)
+{
        int err = 0;
 
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
@@ -9923,22 +9757,19 @@ ia_css_stream_stop(struct ia_css_stream *stream) {
 
 #if !defined(ISP2401)
        /* De-initialize mipi size checks */
-       if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
-       {
+       if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
                unsigned int idx;
                unsigned int port = (unsigned int)(stream->config.source.port.port);
 
-               for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
+               for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
                        sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
-               }
        }
 #endif
 
-       if (!IS_ISP2401) {
+       if (!IS_ISP2401)
                err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
-       } else {
+       else
                err = sh_css_pipes_stop(stream);
-       }
 
        if (err)
                return err;
@@ -9951,16 +9782,16 @@ ia_css_stream_stop(struct ia_css_stream *stream) {
 }
 
 bool
-ia_css_stream_has_stopped(struct ia_css_stream *stream) {
+ia_css_stream_has_stopped(struct ia_css_stream *stream)
+{
        bool stopped;
 
        assert(stream);
 
-       if (!IS_ISP2401) {
+       if (!IS_ISP2401)
                stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
-       } else {
+       else
                stopped = sh_css_pipes_have_stopped(stream);
-       }
 
        return stopped;
 }
@@ -9971,7 +9802,8 @@ ia_css_stream_has_stopped(struct ia_css_stream *stream) {
     * The stream handle is used to identify the correct entry in the css_save struct
     */
 int
-ia_css_stream_unload(struct ia_css_stream *stream) {
+ia_css_stream_unload(struct ia_css_stream *stream)
+{
        int i;
 
        assert(stream);
@@ -9979,8 +9811,7 @@ ia_css_stream_unload(struct ia_css_stream *stream) {
        /* some checks */
        assert(stream);
        for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
-               if (my_css_save.stream_seeds[i].stream == stream)
-               {
+               if (my_css_save.stream_seeds[i].stream == stream) {
                        int j;
 
                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -10000,7 +9831,8 @@ ia_css_stream_unload(struct ia_css_stream *stream) {
 
 int
 ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
-                           enum ia_css_pipe_id *pipe_id) {
+                           enum ia_css_pipe_id *pipe_id)
+{
        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
        if (pipe)
                *pipe_id = pipe->mode;
@@ -10011,18 +9843,21 @@ ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
 }
 
 enum atomisp_input_format
-ia_css_stream_get_format(const struct ia_css_stream *stream) {
+ia_css_stream_get_format(const struct ia_css_stream *stream)
+{
        return stream->config.input_config.format;
 }
 
 bool
-ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) {
+ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
+{
        return (stream->config.pixels_per_clock == 2);
 }
 
 struct ia_css_binary *
 ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
-       *stream) {
+       *stream)
+{
        struct ia_css_pipe *pipe;
 
        assert(stream);
@@ -10040,7 +9875,8 @@ ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
 }
 
 struct ia_css_binary *
-ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) {
+ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
+{
        int i;
        struct ia_css_pipe *video_pipe = NULL;
 
@@ -10059,7 +9895,8 @@ ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) {
 }
 
 struct ia_css_binary *
-ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) {
+ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
+{
        struct ia_css_pipe *pipe;
        struct ia_css_binary *s3a_binary = NULL;
 
@@ -10081,7 +9918,8 @@ ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) {
 
 int
 ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
-                                       unsigned int output_padded_width) {
+                                     unsigned int output_padded_width)
+{
        struct ia_css_pipe *pipe;
 
        assert(stream);
@@ -10098,7 +9936,8 @@ ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
 }
 
 static struct ia_css_binary *
-ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
+{
        struct ia_css_binary *binary = NULL;
 
        assert(pipe);
@@ -10143,7 +9982,8 @@ ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) {
 }
 
 static struct ia_css_binary *
-ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
+{
        struct ia_css_binary *binary = NULL;
 
        assert(pipe);
@@ -10166,9 +10006,9 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
                                }
                        }
                } else if (pipe->config.default_capture_config.mode ==
-                           IA_CSS_CAPTURE_MODE_BAYER)
+                           IA_CSS_CAPTURE_MODE_BAYER) {
                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
-               else if (pipe->config.default_capture_config.mode ==
+               else if (pipe->config.default_capture_config.mode ==
                            IA_CSS_CAPTURE_MODE_ADVANCED ||
                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
                        if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
@@ -10190,7 +10030,8 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
 }
 
 static struct ia_css_binary *
-ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
+{
        struct ia_css_binary *binary = NULL;
 
        assert(pipe);
@@ -10210,14 +10051,16 @@ ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) {
 }
 
 struct ia_css_pipeline *
-ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
+{
        assert(pipe);
 
        return (struct ia_css_pipeline *)&pipe->pipeline;
 }
 
 unsigned int
-ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
+{
        assert(pipe);
 
        /* KW was not sure this function was not returning a value
@@ -10234,7 +10077,8 @@ ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) {
 }
 
 unsigned int
-ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
+{
        assert(pipe);
 
        return (unsigned int)pipe->config.isp_pipe_version;
@@ -10243,7 +10087,8 @@ ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) {
 #define SP_START_TIMEOUT_US 30000000
 
 int
-ia_css_start_sp(void) {
+ia_css_start_sp(void)
+{
        unsigned long timeout;
        int err = 0;
 
@@ -10252,13 +10097,11 @@ ia_css_start_sp(void) {
 
        /* waiting for the SP is completely started */
        timeout = SP_START_TIMEOUT_US;
-       while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout)
-       {
+       while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
                timeout--;
                udelay(1);
        }
-       if (timeout == 0)
-       {
+       if (timeout == 0) {
                IA_CSS_ERROR("timeout during SP initialization");
                return -EINVAL;
        }
@@ -10286,14 +10129,14 @@ ia_css_start_sp(void) {
 #define SP_SHUTDOWN_TIMEOUT_US 200000
 
 int
-ia_css_stop_sp(void) {
+ia_css_stop_sp(void)
+{
        unsigned long timeout;
        int err = 0;
 
        IA_CSS_ENTER("void");
 
-       if (!sh_css_sp_is_running())
-       {
+       if (!sh_css_sp_is_running()) {
                err = -EINVAL;
                IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
 
@@ -10305,8 +10148,7 @@ ia_css_stop_sp(void) {
        if (!IS_ISP2401) {
                sh_css_write_host2sp_command(host2sp_cmd_terminate);
        } else {
-               if (!sh_css_write_host2sp_command(host2sp_cmd_terminate))
-               {
+               if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
                        IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
                        ia_css_debug_dump_sp_sw_debug_info();
                        ia_css_debug_dump_debug_info(NULL);
@@ -10316,27 +10158,23 @@ ia_css_stop_sp(void) {
        sh_css_sp_set_sp_running(false);
 
        timeout = SP_SHUTDOWN_TIMEOUT_US;
-       while (!ia_css_spctrl_is_idle(SP0_ID) && timeout)
-       {
+       while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
                timeout--;
                udelay(1);
        }
        if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED))
                IA_CSS_WARNING("SP has not terminated (SW)");
 
-       if (timeout == 0)
-       {
+       if (timeout == 0) {
                IA_CSS_WARNING("SP is not idle");
                ia_css_debug_dump_sp_sw_debug_info();
        }
        timeout = SP_SHUTDOWN_TIMEOUT_US;
-       while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout)
-       {
+       while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
                timeout--;
                udelay(1);
        }
-       if (timeout == 0)
-       {
+       if (timeout == 0) {
                IA_CSS_WARNING("ISP is not idle");
                ia_css_debug_dump_sp_sw_debug_info();
        }
@@ -10351,7 +10189,8 @@ ia_css_stop_sp(void) {
 }
 
 int
-ia_css_update_continuous_frames(struct ia_css_stream *stream) {
+ia_css_update_continuous_frames(struct ia_css_stream *stream)
+{
        struct ia_css_pipe *pipe;
        unsigned int i;
 
@@ -10359,8 +10198,7 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) {
            IA_CSS_DEBUG_TRACE,
            "sh_css_update_continuous_frames() enter:\n");
 
-       if (!stream)
-       {
+       if (!stream) {
                ia_css_debug_dtrace(
                    IA_CSS_DEBUG_TRACE,
                    "sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
@@ -10371,10 +10209,9 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) {
 
        for (i = stream->config.init_num_cont_raw_buf;
                i < stream->config.target_num_cont_raw_buf; i++)
-       {
                sh_css_update_host2sp_offline_frame(i,
                                                    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
-       }
+
        sh_css_update_host2sp_cont_num_raw_frames
        (stream->config.target_num_cont_raw_buf, true);
        ia_css_debug_dtrace(
@@ -10500,7 +10337,8 @@ void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
 
 #if CONFIG_ON_FRAME_ENQUEUE()
 static int set_config_on_frame_enqueue(struct ia_css_frame_info
-       *info, struct frame_data_wrapper *frame) {
+       *info, struct frame_data_wrapper *frame)
+{
        frame->config_on_frame_enqueue.padded_width = 0;
 
        /* currently we support configuration on frame enqueue only on YUV formats */
@@ -10508,11 +10346,11 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info
        switch (info->format) {
        case IA_CSS_FRAME_FORMAT_YUV420:
        case IA_CSS_FRAME_FORMAT_NV12:
-               if (info->padded_width > info->res.width) {
+               if (info->padded_width > info->res.width)
                        frame->config_on_frame_enqueue.padded_width = info->padded_width;
-               } else if ((info->padded_width < info->res.width) && (info->padded_width > 0)) {
+               else if ((info->padded_width < info->res.width) && (info->padded_width > 0))
                        return -EINVAL;
-               }
+
                /* nothing to do if width == padded width or padded width is zeroed (the same) */
                break;
        default:
@@ -10524,22 +10362,21 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info
 #endif
 
 int
-ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) {
+ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
+{
        int ret;
 
        IA_CSS_ENTER("");
 
        /* Only continuous streams have a tagger to which we can send the
            * unlock message. */
-       if (!stream || !stream->config.continuous)
-       {
+       if (!stream || !stream->config.continuous) {
                IA_CSS_ERROR("invalid stream pointer");
                return -EINVAL;
        }
 
        if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
-           exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID)
-       {
+           exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
                IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
                return -EINVAL;
        }
@@ -10558,7 +10395,8 @@ ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) {
     */
 int
 ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
-                               bool enable) {
+                             bool enable)
+{
        unsigned int thread_id;
        struct ia_css_pipeline_stage *stage;
        int err = 0;
@@ -10566,20 +10404,16 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
        IA_CSS_ENTER("");
 
        /* Parameter Check */
-       if (!pipe || !pipe->stream)
-       {
+       if (!pipe || !pipe->stream) {
                IA_CSS_ERROR("Invalid Pipe.");
                err = -EINVAL;
-       } else if (!(pipe->config.acc_extension))
-       {
+       } else if (!(pipe->config.acc_extension)) {
                IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
                err = -EINVAL;
-       } else if (!sh_css_sp_is_running())
-       {
+       } else if (!sh_css_sp_is_running()) {
                IA_CSS_ERROR("Leaving: queue unavailable.");
                err = -EBUSY;
-       } else
-       {
+       } else {
                /* Query the threadid and stage_num for the Extension firmware*/
                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
@@ -10607,7 +10441,8 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
     */
 int
 ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
-                               bool *enable) {
+                             bool *enable)
+{
        struct ia_css_pipeline_stage *stage;
        unsigned int thread_id;
        int err = 0;
@@ -10615,20 +10450,16 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
        IA_CSS_ENTER("");
 
        /* Parameter Check */
-       if (!pipe || !pipe->stream)
-       {
+       if (!pipe || !pipe->stream) {
                IA_CSS_ERROR("Invalid Pipe.");
                err = -EINVAL;
-       } else if (!(pipe->config.acc_extension))
-       {
+       } else if (!(pipe->config.acc_extension)) {
                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
                err = -EINVAL;
-       } else if (!sh_css_sp_is_running())
-       {
+       } else if (!sh_css_sp_is_running()) {
                IA_CSS_ERROR("Leaving: queue unavailable.");
                err = -EBUSY;
-       } else
-       {
+       } else {
                /* Query the threadid and stage_num corresponding to the Extension firmware*/
                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
@@ -10646,9 +10477,10 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
 /* ISP2401 */
 int
 ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
-                                       u32 fw_handle,
-                                       struct ia_css_isp_param_css_segments *css_seg,
-                                       struct ia_css_isp_param_isp_segments *isp_seg) {
+                                     u32 fw_handle,
+                                     struct ia_css_isp_param_css_segments *css_seg,
+                                     struct ia_css_isp_param_isp_segments *isp_seg)
+{
        unsigned int HIVE_ADDR_sp_group;
        static struct sh_css_sp_group sp_group;
        static struct sh_css_sp_stage sp_stage;
@@ -10666,27 +10498,23 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
        fw = &sh_css_sp_fw;
 
        /* Parameter Check */
-       if (!pipe || !pipe->stream)
-       {
+       if (!pipe || !pipe->stream) {
                IA_CSS_ERROR("Invalid Pipe.");
                err = -EINVAL;
-       } else if (!(pipe->config.acc_extension))
-       {
+       } else if (!(pipe->config.acc_extension)) {
                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
                err = -EINVAL;
-       } else if (!sh_css_sp_is_running())
-       {
+       } else if (!sh_css_sp_is_running()) {
                IA_CSS_ERROR("Leaving: queue unavailable.");
                err = -EBUSY;
-       } else
-       {
+       } else {
                /* Query the thread_id and stage_num corresponding to the Extension firmware */
                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
                if (!err) {
                        /* Get the Extension State */
                        enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
-                                                               stage->stage_num)) ? true : false;
+                                                              stage->stage_num)) ? true : false;
                        /* Update mapped arg only when extension stage is not enabled */
                        if (enabled) {
                                IA_CSS_ERROR("Leaving: cannot update when stage is enabled.");
@@ -10696,13 +10524,14 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
 
                                HIVE_ADDR_sp_group = fw->info.sp.group;
                                sp_dmem_load(SP0_ID,
-                                               (unsigned int)sp_address_of(sp_group),
-                                               &sp_group, sizeof(struct sh_css_sp_group));
+                                            (unsigned int)sp_address_of(sp_group),
+                                            &sp_group,
+                                            sizeof(struct sh_css_sp_group));
                                hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num],
-                                           &sp_stage, sizeof(struct sh_css_sp_stage));
+                                        &sp_stage, sizeof(struct sh_css_sp_stage));
 
                                hmm_load(sp_stage.isp_stage_addr,
-                                           &isp_stage, sizeof(struct sh_css_isp_stage));
+                                        &isp_stage, sizeof(struct sh_css_isp_stage));
 
                                for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) {
                                        isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address =
@@ -10718,7 +10547,8 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
                                }
 
                                hmm_store(sp_stage.isp_stage_addr,
-                                           &isp_stage, sizeof(struct sh_css_isp_stage));
+                                         &isp_stage,
+                                         sizeof(struct sh_css_isp_stage));
                        }
                }
        }
@@ -10729,8 +10559,9 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
 #ifdef ISP2401
 static int
 aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
-                       struct ia_css_pipe *pipes[],
-                       bool *do_crop_status) {
+                      struct ia_css_pipe *pipes[],
+                      bool *do_crop_status)
+{
        int err = 0;
        int i;
        struct ia_css_pipe *curr_pipe;
@@ -10739,15 +10570,13 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
        if ((!curr_stream) ||
            (curr_stream->num_pipes == 0) ||
            (!pipes) ||
-           (!do_crop_status))
-       {
+           (!do_crop_status)) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
                return err;
        }
 
-       for (i = 0; i < curr_stream->num_pipes; i++)
-       {
+       for (i = 0; i < curr_stream->num_pipes; i++) {
                curr_pipe = pipes[i];
                pipe_mask |= (1 << curr_pipe->config.mode);
        }
@@ -10761,7 +10590,8 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
 }
 
 static bool
-aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) {
+aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe)
+{
        bool status = false;
 
        if ((curr_pipe) && enabled) {
@@ -10776,7 +10606,8 @@ aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) {
 
 static int
 aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
-                   struct ia_css_resolution *effective_res) {
+                 struct ia_css_resolution *effective_res)
+{
        int err = 0;
        struct ia_css_resolution crop_res;
        struct ia_css_resolution *in_res = NULL;
@@ -10786,8 +10617,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
        bool use_capt_pp_in_res = false;
 
        if ((!curr_pipe) ||
-           (!effective_res))
-       {
+           (!effective_res)) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -10795,8 +10625,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
 
        if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) &&
            (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) &&
-           (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE))
-       {
+           (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) {
                err = -EINVAL;
                IA_CSS_LEAVE_ERR(err);
                return err;
@@ -10817,8 +10646,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
        in_res = &curr_pipe->stream->config.input_config.effective_res;
        out_res = &curr_pipe->output_info[0].res;
 
-       switch (curr_pipe->config.mode)
-       {
+       switch (curr_pipe->config.mode) {
        case IA_CSS_PIPE_MODE_PREVIEW:
                if (use_bds_output_info)
                        out_res = &curr_pipe->bds_output_info.res;
@@ -10838,27 +10666,26 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
        case IA_CSS_PIPE_MODE_YUVPP:
        default:
                IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n",
-                               curr_pipe->config.mode);
+                            curr_pipe->config.mode);
                assert(0);
                break;
        }
 
        err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res);
        if (!err)
-       {
                *effective_res = crop_res;
-       } else
-       {
+       else
                /* in case of error fallback to default
                    * effective resolution from driver. */
                IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err);
-       }
+
        return err;
 }
 #endif
 
 static void
-sh_css_hmm_buffer_record_init(void) {
+sh_css_hmm_buffer_record_init(void)
+{
        int i;
 
        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
@@ -10866,7 +10693,8 @@ sh_css_hmm_buffer_record_init(void) {
 }
 
 static void
-sh_css_hmm_buffer_record_uninit(void) {
+sh_css_hmm_buffer_record_uninit(void)
+{
        int i;
        struct sh_css_hmm_buffer_record *buffer_record = NULL;
 
@@ -10882,7 +10710,8 @@ sh_css_hmm_buffer_record_uninit(void) {
 }
 
 static void
-sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) {
+sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
+{
        assert(buffer_record);
        buffer_record->in_use = false;
        buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
@@ -10893,14 +10722,15 @@ sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) {
 static struct sh_css_hmm_buffer_record
 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
                                    enum ia_css_buffer_type type,
-                                   hrt_address kernel_ptr) {
+                                   hrt_address kernel_ptr)
+{
        int i;
        struct sh_css_hmm_buffer_record *buffer_record = NULL;
        struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
 
        assert(h_vbuf);
        assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
-               (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
+              (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
        assert(kernel_ptr != 0);
 
        buffer_record = &hmm_buffer_record[0];
@@ -10921,7 +10751,8 @@ static struct sh_css_hmm_buffer_record
 
 static struct sh_css_hmm_buffer_record
 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
-                                   enum ia_css_buffer_type type) {
+                                   enum ia_css_buffer_type type)
+{
        int i;
        struct sh_css_hmm_buffer_record *buffer_record = NULL;
        bool found_record = false;
diff --git a/drivers/staging/media/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig
new file mode 100644 (file)
index 0000000..9faf9d2
--- /dev/null
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DVB_AV7110_IR
+       bool
+       depends on RC_CORE=y || RC_CORE = DVB_AV7110
+       default DVB_AV7110
+
+config DVB_AV7110
+       tristate "AV7110 cards"
+       depends on DVB_CORE && PCI && I2C
+       select TTPCI_EEPROM
+       select VIDEO_SAA7146_VV
+       depends on VIDEO_DEV    # dependencies of VIDEO_SAA7146_VV
+       select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Support for SAA7146 and AV7110 based DVB cards as produced
+         by Fujitsu-Siemens, Technotrend, Hauppauge and others.
+
+         This driver only supports the fullfeatured cards with
+         onboard MPEG2 decoder.
+
+         This driver needs an external firmware. Please use the script
+         "<kerneldir>/scripts/get_dvb_firmware av7110" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
+         Alternatively, you can download the file and use the kernel's
+         EXTRA_FIRMWARE configuration option to build it into your
+         kernel image by adding the filename to the EXTRA_FIRMWARE
+         configuration option string.
+
+         Say Y if you own such a card and want to use it.
+
+config DVB_AV7110_OSD
+       bool "AV7110 OSD support"
+       depends on DVB_AV7110
+       default y if DVB_AV7110=y || DVB_AV7110=m
+       help
+         The AV7110 firmware provides some code to generate an OnScreenDisplay
+         on the video output. This is kind of nonstandard and not guaranteed to
+         be maintained.
+
+         Anyway, some popular DVB software like VDR uses this OSD to render
+         its menus, so say Y if you want to use this software.
+
+         All other people say N.
+
+config DVB_BUDGET_PATCH
+       tristate "AV7110 cards with Budget Patch"
+       depends on DVB_BUDGET_CORE && I2C
+       depends on DVB_AV7110
+       select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Support for Budget Patch (full TS) modification on
+         SAA7146+AV7110 based cards (DVB-S cards). This
+         driver doesn't use onboard MPEG2 decoder. The
+         card is driven in Budget-only mode. Card is
+         required to have loaded firmware to tune properly.
+         Firmware can be loaded by insertion and removal of
+         standard AV7110 driver prior to loading this
+         driver.
+
+         Say Y if you own such a card and want to use it.
+
+         To compile this driver as a module, choose M here: the
+         module will be called budget-patch.
+
+if DVB_AV7110
+
+# Frontend driver that it is used only by AV7110 driver
+# While technically independent, it doesn't make sense to keep
+# it if we drop support for AV7110, as no other driver will use it.
+
+config DVB_SP8870
+       tristate "Spase sp8870 based"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
+
+         This driver needs external firmware. Please use the command
+         "<kerneldir>/scripts/get_dvb_firmware sp8870" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
+endif
diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/av7110/Makefile
new file mode 100644 (file)
index 0000000..307b267
--- /dev/null
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the AV7110 DVB device driver
+#
+
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o \
+                 av7110_ipack.o dvb_filter.o
+
+ifdef CONFIG_DVB_AV7110_IR
+dvb-ttpci-objs += av7110_ir.o
+endif
+
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+
+ccflags-y += -I $(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/pci/ttpci
+ccflags-y += -I $(srctree)/drivers/media/common
diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO
new file mode 100644 (file)
index 0000000..60062d8
--- /dev/null
@@ -0,0 +1,3 @@
+- This driver is too old and relies on a different API.
+  Drop it from Kernel on a couple of versions.
+- Cleanup patches for the drivers here won't be accepted.
@@ -50,7 +50,7 @@ Description
 
 This ioctl call asks the Audio Device to bypass the Audio decoder and
 forward the stream without decoding. This mode shall be used if streams
-that cant be handled by the Digital TV system shall be decoded. Dolby
+that can't be handled by the Digital TV system shall be decoded. Dolby
 DigitalTM streams are automatically forwarded by the Digital TV subsystem if
 the hardware can handle it.
 
similarity index 90%
rename from Documentation/userspace-api/media/dvb/audio.rst
rename to drivers/staging/media/av7110/audio.rst
index eaae567..aa75333 100644 (file)
@@ -11,7 +11,7 @@ TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data
 types and ioctl definitions can be accessed by including
 ``linux/dvb/audio.h`` in your application.
 
-Please note that some Digital TV cards dont have their own MPEG decoder, which
+Please note that some Digital TV cards don't have their own MPEG decoder, which
 results in the omission of the audio and video device.
 
 These ioctls were also used by V4L2 to control MPEG decoders implemented
similarity index 98%
rename from drivers/media/pci/ttpci/av7110.h
rename to drivers/staging/media/av7110/av7110.h
index 809d938..b8e8fc8 100644 (file)
@@ -9,11 +9,12 @@
 #include <linux/input.h>
 #include <linux/time.h>
 
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
+#include "video.h"
+#include "audio.h"
+#include "osd.h"
+
 #include <linux/dvb/dmx.h>
 #include <linux/dvb/ca.h>
-#include <linux/dvb/osd.h>
 #include <linux/dvb/net.h>
 #include <linux/mutex.h>
 
similarity index 93%
rename from Documentation/userspace-api/media/dvb/video.rst
rename to drivers/staging/media/av7110/video.rst
index 38a8d39..808705b 100644 (file)
@@ -16,7 +16,7 @@ stream, not its presentation on the TV or computer screen. On PCs this
 is typically handled by an associated video4linux device, e.g.
 **/dev/video**, which allows scaling and defining output windows.
 
-Some Digital TV cards dont have their own MPEG decoder, which results in the
+Some Digital TV cards don't have their own MPEG decoder, which results in the
 omission of the audio and video device as well as the video4linux
 device.
 
index 5b6cf9f..20b1f6d 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 config VIDEO_HANTRO
        tristate "Hantro VPU driver"
-       depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST
+       depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || COMPILE_TEST
        depends on VIDEO_DEV && VIDEO_V4L2
        select MEDIA_CONTROLLER
        select MEDIA_CONTROLLER_REQUEST_API
@@ -24,6 +24,14 @@ config VIDEO_HANTRO_IMX8M
        help
          Enable support for i.MX8M SoCs.
 
+config VIDEO_HANTRO_SAMA5D4
+       bool "Hantro VDEC SAMA5D4 support"
+       depends on VIDEO_HANTRO
+       depends on ARCH_AT91 || COMPILE_TEST
+       default y
+       help
+         Enable support for Microchip SAMA5D4 SoCs.
+
 config VIDEO_HANTRO_ROCKCHIP
        bool "Hantro VPU Rockchip support"
        depends on VIDEO_HANTRO
index 743ce08..2873701 100644 (file)
@@ -7,20 +7,25 @@ hantro-vpu-y += \
                hantro_v4l2.o \
                hantro_postproc.o \
                hantro_h1_jpeg_enc.o \
+               hantro_g1.o \
                hantro_g1_h264_dec.o \
                hantro_g1_mpeg2_dec.o \
+               hantro_g2_hevc_dec.o \
                hantro_g1_vp8_dec.o \
-               rk3399_vpu_hw_jpeg_enc.o \
-               rk3399_vpu_hw_mpeg2_dec.o \
-               rk3399_vpu_hw_vp8_dec.o \
+               rockchip_vpu2_hw_jpeg_enc.o \
+               rockchip_vpu2_hw_mpeg2_dec.o \
+               rockchip_vpu2_hw_vp8_dec.o \
                hantro_jpeg.o \
                hantro_h264.o \
+               hantro_hevc.o \
                hantro_mpeg2.o \
                hantro_vp8.o
 
 hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \
                imx8m_vpu_hw.o
 
+hantro-vpu-$(CONFIG_VIDEO_HANTRO_SAMA5D4) += \
+               sama5d4_vdec_hw.o
+
 hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
-               rk3288_vpu_hw.o \
-               rk3399_vpu_hw.o
+               rockchip_vpu_hw.o
index 6c1b888..a70c386 100644 (file)
@@ -34,6 +34,7 @@ struct hantro_codec_ops;
 #define HANTRO_MPEG2_DECODER   BIT(16)
 #define HANTRO_VP8_DECODER     BIT(17)
 #define HANTRO_H264_DECODER    BIT(18)
+#define HANTRO_HEVC_DECODER    BIT(19)
 #define HANTRO_DECODERS                0xffff0000
 
 /**
@@ -99,6 +100,7 @@ struct hantro_variant {
  * @HANTRO_MODE_H264_DEC: H264 decoder.
  * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder.
  * @HANTRO_MODE_VP8_DEC: VP8 decoder.
+ * @HANTRO_MODE_HEVC_DEC: HEVC decoder.
  */
 enum hantro_codec_mode {
        HANTRO_MODE_NONE = -1,
@@ -106,6 +108,7 @@ enum hantro_codec_mode {
        HANTRO_MODE_H264_DEC,
        HANTRO_MODE_MPEG2_DEC,
        HANTRO_MODE_VP8_DEC,
+       HANTRO_MODE_HEVC_DEC,
 };
 
 /*
@@ -218,6 +221,7 @@ struct hantro_dev {
  * @jpeg_enc:          JPEG-encoding context.
  * @mpeg2_dec:         MPEG-2-decoding context.
  * @vp8_dec:           VP8-decoding context.
+ * @hevc_dec:          HEVC-decoding context.
  */
 struct hantro_ctx {
        struct hantro_dev *dev;
@@ -244,6 +248,7 @@ struct hantro_ctx {
                struct hantro_jpeg_enc_hw_ctx jpeg_enc;
                struct hantro_mpeg2_dec_hw_ctx mpeg2_dec;
                struct hantro_vp8_dec_hw_ctx vp8_dec;
+               struct hantro_hevc_dec_hw_ctx hevc_dec;
        };
 };
 
@@ -410,12 +415,8 @@ hantro_get_dst_buf(struct hantro_ctx *ctx)
        return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 }
 
-static inline bool
-hantro_needs_postproc(const struct hantro_ctx *ctx,
-                     const struct hantro_fmt *fmt)
-{
-       return !ctx->is_encoder && fmt->fourcc != V4L2_PIX_FMT_NV12;
-}
+bool hantro_needs_postproc(const struct hantro_ctx *ctx,
+                          const struct hantro_fmt *fmt);
 
 static inline dma_addr_t
 hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb)
index 595e82a..31d8449 100644 (file)
@@ -56,16 +56,12 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts)
        return hantro_get_dec_buf_addr(ctx, buf);
 }
 
-static void hantro_job_finish(struct hantro_dev *vpu,
-                             struct hantro_ctx *ctx,
-                             enum vb2_buffer_state result)
+static void hantro_job_finish_no_pm(struct hantro_dev *vpu,
+                                   struct hantro_ctx *ctx,
+                                   enum vb2_buffer_state result)
 {
        struct vb2_v4l2_buffer *src, *dst;
 
-       pm_runtime_mark_last_busy(vpu->dev);
-       pm_runtime_put_autosuspend(vpu->dev);
-       clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
-
        src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
@@ -81,6 +77,18 @@ static void hantro_job_finish(struct hantro_dev *vpu,
                                         result);
 }
 
+static void hantro_job_finish(struct hantro_dev *vpu,
+                             struct hantro_ctx *ctx,
+                             enum vb2_buffer_state result)
+{
+       pm_runtime_mark_last_busy(vpu->dev);
+       pm_runtime_put_autosuspend(vpu->dev);
+
+       clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
+
+       hantro_job_finish_no_pm(vpu, ctx, result);
+}
+
 void hantro_irq_done(struct hantro_dev *vpu,
                     enum vb2_buffer_state result)
 {
@@ -152,20 +160,23 @@ static void device_run(void *priv)
        src = hantro_get_src_buf(ctx);
        dst = hantro_get_dst_buf(ctx);
 
+       ret = pm_runtime_resume_and_get(ctx->dev->dev);
+       if (ret < 0)
+               goto err_cancel_job;
+
        ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks);
        if (ret)
                goto err_cancel_job;
-       ret = pm_runtime_get_sync(ctx->dev->dev);
-       if (ret < 0)
-               goto err_cancel_job;
 
        v4l2_m2m_buf_copy_metadata(src, dst, true);
 
-       ctx->codec_ops->run(ctx);
+       if (ctx->codec_ops->run(ctx))
+               goto err_cancel_job;
+
        return;
 
 err_cancel_job:
-       hantro_job_finish(ctx->dev, ctx, VB2_BUF_STATE_ERROR);
+       hantro_job_finish_no_pm(ctx->dev, ctx, VB2_BUF_STATE_ERROR);
 }
 
 static struct v4l2_m2m_ops vpu_m2m_ops = {
@@ -243,6 +254,18 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
                if (sps->bit_depth_luma_minus8 != 0)
                        /* Only 8-bit is supported */
                        return -EINVAL;
+       } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) {
+               const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+               if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+                       /* Luma and chroma bit depth mismatch */
+                       return -EINVAL;
+               if (sps->bit_depth_luma_minus8 != 0)
+                       /* Only 8-bit is supported */
+                       return -EINVAL;
+               if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED)
+                       /* No scaling support */
+                       return -EINVAL;
        }
        return 0;
 }
@@ -267,6 +290,26 @@ static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
+static int hantro_hevc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct hantro_ctx *ctx;
+
+       ctx = container_of(ctrl->handler,
+                          struct hantro_ctx, ctrl_handler);
+
+       vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP:
+               ctx->hevc_dec.ctrls.hevc_hdr_skip_length = ctrl->val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct v4l2_ctrl_ops hantro_ctrl_ops = {
        .try_ctrl = hantro_try_ctrl,
 };
@@ -275,6 +318,10 @@ static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = {
        .s_ctrl = hantro_jpeg_s_ctrl,
 };
 
+static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = {
+       .s_ctrl = hantro_hevc_s_ctrl,
+};
+
 static const struct hantro_ctrl controls[] = {
        {
                .codec = HANTRO_JPEG_ENCODER,
@@ -289,12 +336,17 @@ static const struct hantro_ctrl controls[] = {
        }, {
                .codec = HANTRO_MPEG2_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+                       .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
+               },
+       }, {
+               .codec = HANTRO_MPEG2_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
                },
        }, {
                .codec = HANTRO_MPEG2_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+                       .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
                },
        }, {
                .codec = HANTRO_VP8_DECODER,
@@ -349,6 +401,64 @@ static const struct hantro_ctrl controls[] = {
                        .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
                }
        }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
+                       .min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+                       .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+                       .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
+                       .min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+                       .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+                       .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+                       .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+                       .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+                       .def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+                       .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+                       .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+                       .ops = &hantro_ctrl_ops,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+               },
+       }, {
+               .codec = HANTRO_HEVC_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP,
+                       .name = "Hantro HEVC slice header skip bytes",
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .min = 0,
+                       .def = 0,
+                       .max = 0x100,
+                       .step = 1,
+                       .ops = &hantro_hevc_ctrl_ops,
+               },
        },
 };
 
@@ -472,12 +582,18 @@ static const struct v4l2_file_operations hantro_fops = {
 
 static const struct of_device_id of_hantro_match[] = {
 #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP
-       { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
-       { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
+       { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, },
+       { .compatible = "rockchip,rk3066-vpu", .data = &rk3066_vpu_variant, },
        { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
+       { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
+       { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
 #endif
 #ifdef CONFIG_VIDEO_HANTRO_IMX8M
        { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, },
+       { .compatible = "nxp,imx8mq-vpu-g2", .data = &imx8mq_vpu_g2_variant },
+#endif
+#ifdef CONFIG_VIDEO_HANTRO_SAMA5D4
+       { .compatible = "microchip,sama5d4-vdec", .data = &sama5d4_vdec_variant, },
 #endif
        { /* sentinel */ }
 };
@@ -752,12 +868,23 @@ static int hantro_probe(struct platform_device *pdev)
        if (!vpu->clocks)
                return -ENOMEM;
 
-       for (i = 0; i < vpu->variant->num_clocks; i++)
-               vpu->clocks[i].id = vpu->variant->clk_names[i];
-       ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks,
-                               vpu->clocks);
-       if (ret)
-               return ret;
+       if (vpu->variant->num_clocks > 1) {
+               for (i = 0; i < vpu->variant->num_clocks; i++)
+                       vpu->clocks[i].id = vpu->variant->clk_names[i];
+
+               ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks,
+                                       vpu->clocks);
+               if (ret)
+                       return ret;
+       } else {
+               /*
+                * If the driver has a single clk, chances are there will be no
+                * actual name in the DT bindings.
+                */
+               vpu->clocks[0].clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(vpu->clocks[0].clk))
+                       return PTR_ERR(vpu->clocks[0].clk);
+       }
 
        num_bases = vpu->variant->num_regs ?: 1;
        vpu->reg_bases = devm_kcalloc(&pdev->dev, num_bases,
@@ -785,13 +912,23 @@ static int hantro_probe(struct platform_device *pdev)
        vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
 
        for (i = 0; i < vpu->variant->num_irqs; i++) {
-               const char *irq_name = vpu->variant->irqs[i].name;
+               const char *irq_name;
                int irq;
 
                if (!vpu->variant->irqs[i].handler)
                        continue;
 
-               irq = platform_get_irq_byname(vpu->pdev, irq_name);
+               if (vpu->variant->num_clocks > 1) {
+                       irq_name = vpu->variant->irqs[i].name;
+                       irq = platform_get_irq_byname(vpu->pdev, irq_name);
+               } else {
+                       /*
+                        * If the driver has a single IRQ, chances are there
+                        * will be no actual name in the DT bindings.
+                        */
+                       irq_name = "default";
+                       irq = platform_get_irq(vpu->pdev, 0);
+               }
                if (irq <= 0)
                        return -ENXIO;
 
diff --git a/drivers/staging/media/hantro/hantro_g1.c b/drivers/staging/media/hantro/hantro_g1.c
new file mode 100644 (file)
index 0000000..0ab1cee
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
+ * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com>
+ */
+
+#include "hantro.h"
+#include "hantro_g1_regs.h"
+
+irqreturn_t hantro_g1_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vdpu_read(vpu, G1_REG_INTERRUPT);
+       state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
+                VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vdpu_write(vpu, 0, G1_REG_INTERRUPT);
+       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+
+       hantro_irq_done(vpu, state);
+
+       return IRQ_HANDLED;
+}
+
+void hantro_g1_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT);
+       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+       vdpu_write(vpu, 1, G1_REG_SOFT_RESET);
+}
index 845bef7..5c792b7 100644 (file)
@@ -273,13 +273,15 @@ static void set_buffers(struct hantro_ctx *ctx)
        vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE);
 }
 
-void hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
+int hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
+       int ret;
 
        /* Prepare the H264 decoder context. */
-       if (hantro_h264_dec_prepare_run(ctx))
-               return;
+       ret = hantro_h264_dec_prepare_run(ctx);
+       if (ret)
+               return ret;
 
        /* Configure hardware registers. */
        set_params(ctx);
@@ -301,4 +303,6 @@ void hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
                           G1_REG_CONFIG_DEC_CLK_GATE_E,
                           G1_REG_CONFIG);
        vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+       return 0;
 }
index 6386a39..9aea331 100644 (file)
@@ -10,6 +10,7 @@
 #include <media/v4l2-mem2mem.h>
 #include "hantro.h"
 #include "hantro_hw.h"
+#include "hantro_g1_regs.h"
 
 #define G1_SWREG(nr)                   ((nr) * 4)
 
@@ -20,7 +21,6 @@
 #define G1_REG_REFER2_BASE             G1_SWREG(16)
 #define G1_REG_REFER3_BASE             G1_SWREG(17)
 #define G1_REG_QTABLE_BASE             G1_SWREG(40)
-#define G1_REG_DEC_E(v)                        ((v) ? BIT(0) : 0)
 
 #define G1_REG_DEC_AXI_RD_ID(v)                (((v) << 24) & GENMASK(31, 24))
 #define G1_REG_DEC_TIMEOUT_E(v)                ((v) ? BIT(23) : 0)
 
 #define G1_REG_APF_THRESHOLD(v)                (((v) << 0) & GENMASK(13, 0))
 
-#define PICT_TOP_FIELD     1
-#define PICT_BOTTOM_FIELD  2
-#define PICT_FRAME         3
-
 static void
-hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu,
+hantro_g1_mpeg2_dec_set_quantisation(struct hantro_dev *vpu,
                                     struct hantro_ctx *ctx)
 {
-       struct v4l2_ctrl_mpeg2_quantization *quantization;
-
-       quantization = hantro_get_ctrl(ctx,
-                                      V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
-       hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu,
-                                    quantization);
-       vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma,
-                          G1_REG_QTABLE_BASE);
+       struct v4l2_ctrl_mpeg2_quantisation *q;
+
+       q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION);
+       hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q);
+       vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, G1_REG_QTABLE_BASE);
 }
 
 static void
 hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
                                struct vb2_buffer *src_buf,
                                struct vb2_buffer *dst_buf,
-                               const struct v4l2_mpeg2_sequence *sequence,
-                               const struct v4l2_mpeg2_picture *picture,
-                               const struct v4l2_ctrl_mpeg2_slice_params *slice_params)
+                               const struct v4l2_ctrl_mpeg2_sequence *seq,
+                               const struct v4l2_ctrl_mpeg2_picture *pic)
 {
        dma_addr_t forward_addr = 0, backward_addr = 0;
        dma_addr_t current_addr, addr;
 
-       switch (picture->picture_coding_type) {
-       case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
-               backward_addr = hantro_get_ref(ctx,
-                                              slice_params->backward_ref_ts);
+       switch (pic->picture_coding_type) {
+       case V4L2_MPEG2_PIC_CODING_TYPE_B:
+               backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts);
                fallthrough;
-       case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
-               forward_addr = hantro_get_ref(ctx,
-                                             slice_params->forward_ref_ts);
+       case V4L2_MPEG2_PIC_CODING_TYPE_P:
+               forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts);
        }
 
        /* Source bitstream buffer */
@@ -124,7 +114,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
        addr = hantro_get_dec_buf_addr(ctx, dst_buf);
        current_addr = addr;
 
-       if (picture->picture_structure == PICT_BOTTOM_FIELD)
+       if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD)
                addr += ALIGN(ctx->dst_fmt.width, 16);
        vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE);
 
@@ -134,18 +124,18 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
                backward_addr = current_addr;
 
        /* Set forward ref frame (top/bottom field) */
-       if (picture->picture_structure == PICT_FRAME ||
-           picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B ||
-           (picture->picture_structure == PICT_TOP_FIELD &&
-            picture->top_field_first) ||
-           (picture->picture_structure == PICT_BOTTOM_FIELD &&
-            !picture->top_field_first)) {
+       if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME ||
+           pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B ||
+           (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD &&
+            pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST) ||
+           (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD &&
+            !(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST))) {
                vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE);
-       } else if (picture->picture_structure == PICT_TOP_FIELD) {
+       } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) {
                vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE);
-       } else if (picture->picture_structure == PICT_BOTTOM_FIELD) {
+       } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) {
                vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE);
        }
@@ -155,13 +145,12 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
        vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE);
 }
 
-void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
+int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
-       const struct v4l2_mpeg2_sequence *sequence;
-       const struct v4l2_mpeg2_picture *picture;
+       const struct v4l2_ctrl_mpeg2_sequence *seq;
+       const struct v4l2_ctrl_mpeg2_picture *pic;
        u32 reg;
 
        src_buf = hantro_get_src_buf(ctx);
@@ -170,10 +159,10 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
        /* Apply request controls if any */
        hantro_start_prepare_run(ctx);
 
-       slice_params = hantro_get_ctrl(ctx,
-                                      V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
-       sequence = &slice_params->sequence;
-       picture = &slice_params->picture;
+       seq = hantro_get_ctrl(ctx,
+                             V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+       pic = hantro_get_ctrl(ctx,
+                             V4L2_CID_STATELESS_MPEG2_PICTURE);
 
        reg = G1_REG_DEC_AXI_RD_ID(0) |
              G1_REG_DEC_TIMEOUT_E(1) |
@@ -193,11 +182,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
 
        reg = G1_REG_DEC_MODE(5) |
              G1_REG_RLC_MODE_E(0) |
-             G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) |
-             G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) |
-             G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) |
-             G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) |
-             G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) |
+             G1_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) |
+             G1_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) |
+             G1_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) |
+             G1_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) |
+             G1_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) |
              G1_REG_FWD_INTERLACE_E(0) |
              G1_REG_FILTERING_DIS(1) |
              G1_REG_WRITE_MVS_E(0) |
@@ -206,27 +195,27 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
 
        reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) |
              G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) |
-             G1_REG_ALT_SCAN_E(picture->alternate_scan) |
-             G1_REG_TOPFIELDFIRST_E(picture->top_field_first);
+             G1_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+             G1_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
        vdpu_write_relaxed(vpu, reg, G1_SWREG(4));
 
-       reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) |
-             G1_REG_QSCALE_TYPE(picture->q_scale_type) |
-             G1_REG_CON_MV_E(picture->concealment_motion_vectors) |
-             G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) |
-             G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) |
-             G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct);
+       reg = G1_REG_STRM_START_BIT(0) |
+             G1_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) |
+             G1_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) |
+             G1_REG_INTRA_DC_PREC(pic->intra_dc_precision) |
+             G1_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) |
+             G1_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
        vdpu_write_relaxed(vpu, reg, G1_SWREG(5));
 
        reg = G1_REG_INIT_QP(1) |
-             G1_REG_STREAM_LEN(slice_params->bit_size >> 3);
+             G1_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0));
        vdpu_write_relaxed(vpu, reg, G1_SWREG(6));
 
-       reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) |
-             G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) |
-             G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) |
-             G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) |
-             G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) |
+       reg = G1_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+             G1_REG_FCODE_FWD_HOR(pic->f_code[0][0]) |
+             G1_REG_FCODE_FWD_VER(pic->f_code[0][1]) |
+             G1_REG_FCODE_BWD_HOR(pic->f_code[1][0]) |
+             G1_REG_FCODE_BWD_VER(pic->f_code[1][1]) |
              G1_REG_MV_ACCURACY_FWD(1) |
              G1_REG_MV_ACCURACY_BWD(1);
        vdpu_write_relaxed(vpu, reg, G1_SWREG(18));
@@ -238,14 +227,14 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
        reg = G1_REG_APF_THRESHOLD(8);
        vdpu_write_relaxed(vpu, reg, G1_SWREG(55));
 
-       hantro_g1_mpeg2_dec_set_quantization(vpu, ctx);
-
+       hantro_g1_mpeg2_dec_set_quantisation(vpu, ctx);
        hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
                                        &dst_buf->vb2_buf,
-                                       sequence, picture, slice_params);
+                                       seq, pic);
 
        hantro_end_prepare_run(ctx);
 
-       reg = G1_REG_DEC_E(1);
-       vdpu_write(vpu, reg, G1_SWREG(1));
+       vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+       return 0;
 }
index 57002ba..96622a7 100644 (file)
@@ -425,7 +425,7 @@ static void cfg_buffers(struct hantro_ctx *ctx,
        vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST);
 }
 
-void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
+int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
 {
        const struct v4l2_ctrl_vp8_frame *hdr;
        struct hantro_dev *vpu = ctx->dev;
@@ -438,7 +438,7 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
 
        hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME);
        if (WARN_ON(!hdr))
-               return;
+               return -EINVAL;
 
        /* Reset segment_map buffer in keyframe */
        if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
@@ -498,4 +498,6 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
        hantro_end_prepare_run(ctx);
 
        vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+       return 0;
 }
diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c
new file mode 100644 (file)
index 0000000..340efb5
--- /dev/null
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU HEVC codec driver
+ *
+ * Copyright (C) 2020 Safran Passenger Innovations LLC
+ */
+
+#include "hantro_hw.h"
+#include "hantro_g2_regs.h"
+
+#define HEVC_DEC_MODE  0xC
+
+#define BUS_WIDTH_32           0
+#define BUS_WIDTH_64           1
+#define BUS_WIDTH_128          2
+#define BUS_WIDTH_256          3
+
+static inline void hantro_write_addr(struct hantro_dev *vpu,
+                                    unsigned long offset,
+                                    dma_addr_t addr)
+{
+       vdpu_write(vpu, addr & 0xffffffff, offset);
+}
+
+static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu);
+       unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1;
+       unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+       unsigned int pic_width_in_ctbs, pic_height_in_ctbs;
+       unsigned int max_log2_ctb_size, ctb_size;
+       bool tiles_enabled, uniform_spacing;
+       u32 no_chroma = 0;
+
+       tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+       uniform_spacing = !!(pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING);
+
+       hantro_reg_write(vpu, &g2_tile_e, tiles_enabled);
+
+       max_log2_ctb_size = sps->log2_min_luma_coding_block_size_minus3 + 3 +
+                           sps->log2_diff_max_min_luma_coding_block_size;
+       pic_width_in_ctbs = (sps->pic_width_in_luma_samples +
+                           (1 << max_log2_ctb_size) - 1) >> max_log2_ctb_size;
+       pic_height_in_ctbs = (sps->pic_height_in_luma_samples + (1 << max_log2_ctb_size) - 1)
+                            >> max_log2_ctb_size;
+       ctb_size = 1 << max_log2_ctb_size;
+
+       vpu_debug(1, "Preparing tile sizes buffer for %dx%d CTBs (CTB size %d)\n",
+                 pic_width_in_ctbs, pic_height_in_ctbs, ctb_size);
+
+       if (tiles_enabled) {
+               unsigned int i, j, h;
+
+               vpu_debug(1, "Tiles enabled! %dx%d\n", num_tile_cols, num_tile_rows);
+
+               hantro_reg_write(vpu, &g2_num_tile_rows, num_tile_rows);
+               hantro_reg_write(vpu, &g2_num_tile_cols, num_tile_cols);
+
+               /* write width + height for each tile in pic */
+               if (!uniform_spacing) {
+                       u32 tmp_w = 0, tmp_h = 0;
+
+                       for (i = 0; i < num_tile_rows; i++) {
+                               if (i == num_tile_rows - 1)
+                                       h = pic_height_in_ctbs - tmp_h;
+                               else
+                                       h = pps->row_height_minus1[i] + 1;
+                               tmp_h += h;
+                               if (i == 0 && h == 1 && ctb_size == 16)
+                                       no_chroma = 1;
+                               for (j = 0, tmp_w = 0; j < num_tile_cols - 1; j++) {
+                                       tmp_w += pps->column_width_minus1[j] + 1;
+                                       *p++ = pps->column_width_minus1[j + 1];
+                                       *p++ = h;
+                                       if (i == 0 && h == 1 && ctb_size == 16)
+                                               no_chroma = 1;
+                               }
+                               /* last column */
+                               *p++ = pic_width_in_ctbs - tmp_w;
+                               *p++ = h;
+                       }
+               } else { /* uniform spacing */
+                       u32 tmp, prev_h, prev_w;
+
+                       for (i = 0, prev_h = 0; i < num_tile_rows; i++) {
+                               tmp = (i + 1) * pic_height_in_ctbs / num_tile_rows;
+                               h = tmp - prev_h;
+                               prev_h = tmp;
+                               if (i == 0 && h == 1 && ctb_size == 16)
+                                       no_chroma = 1;
+                               for (j = 0, prev_w = 0; j < num_tile_cols; j++) {
+                                       tmp = (j + 1) * pic_width_in_ctbs / num_tile_cols;
+                                       *p++ = tmp - prev_w;
+                                       *p++ = h;
+                                       if (j == 0 &&
+                                           (pps->column_width_minus1[0] + 1) == 1 &&
+                                           ctb_size == 16)
+                                               no_chroma = 1;
+                                       prev_w = tmp;
+                               }
+                       }
+               }
+       } else {
+               hantro_reg_write(vpu, &g2_num_tile_rows, 1);
+               hantro_reg_write(vpu, &g2_num_tile_cols, 1);
+
+               /* There's one tile, with dimensions equal to pic size. */
+               p[0] = pic_width_in_ctbs;
+               p[1] = pic_height_in_ctbs;
+       }
+
+       if (no_chroma)
+               vpu_debug(1, "%s: no chroma!\n", __func__);
+}
+
+static void set_params(struct hantro_ctx *ctx)
+{
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+       const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+       struct hantro_dev *vpu = ctx->dev;
+       u32 min_log2_cb_size, max_log2_ctb_size, min_cb_size, max_ctb_size;
+       u32 pic_width_in_min_cbs, pic_height_in_min_cbs;
+       u32 pic_width_aligned, pic_height_aligned;
+       u32 partial_ctb_x, partial_ctb_y;
+
+       hantro_reg_write(vpu, &g2_bit_depth_y_minus8, sps->bit_depth_luma_minus8);
+       hantro_reg_write(vpu, &g2_bit_depth_c_minus8, sps->bit_depth_chroma_minus8);
+
+       hantro_reg_write(vpu, &g2_output_8_bits, 0);
+
+       hantro_reg_write(vpu, &g2_hdr_skip_length, ctrls->hevc_hdr_skip_length);
+
+       min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+       max_log2_ctb_size = min_log2_cb_size + sps->log2_diff_max_min_luma_coding_block_size;
+
+       hantro_reg_write(vpu, &g2_min_cb_size, min_log2_cb_size);
+       hantro_reg_write(vpu, &g2_max_cb_size, max_log2_ctb_size);
+
+       min_cb_size = 1 << min_log2_cb_size;
+       max_ctb_size = 1 << max_log2_ctb_size;
+
+       pic_width_in_min_cbs = sps->pic_width_in_luma_samples / min_cb_size;
+       pic_height_in_min_cbs = sps->pic_height_in_luma_samples / min_cb_size;
+       pic_width_aligned = ALIGN(sps->pic_width_in_luma_samples, max_ctb_size);
+       pic_height_aligned = ALIGN(sps->pic_height_in_luma_samples, max_ctb_size);
+
+       partial_ctb_x = !!(sps->pic_width_in_luma_samples != pic_width_aligned);
+       partial_ctb_y = !!(sps->pic_height_in_luma_samples != pic_height_aligned);
+
+       hantro_reg_write(vpu, &g2_partial_ctb_x, partial_ctb_x);
+       hantro_reg_write(vpu, &g2_partial_ctb_y, partial_ctb_y);
+
+       hantro_reg_write(vpu, &g2_pic_width_in_cbs, pic_width_in_min_cbs);
+       hantro_reg_write(vpu, &g2_pic_height_in_cbs, pic_height_in_min_cbs);
+
+       hantro_reg_write(vpu, &g2_pic_width_4x4,
+                        (pic_width_in_min_cbs * min_cb_size) / 4);
+       hantro_reg_write(vpu, &g2_pic_height_4x4,
+                        (pic_height_in_min_cbs * min_cb_size) / 4);
+
+       hantro_reg_write(vpu, &hevc_max_inter_hierdepth,
+                        sps->max_transform_hierarchy_depth_inter);
+       hantro_reg_write(vpu, &hevc_max_intra_hierdepth,
+                        sps->max_transform_hierarchy_depth_intra);
+       hantro_reg_write(vpu, &hevc_min_trb_size,
+                        sps->log2_min_luma_transform_block_size_minus2 + 2);
+       hantro_reg_write(vpu, &hevc_max_trb_size,
+                        sps->log2_min_luma_transform_block_size_minus2 + 2 +
+                        sps->log2_diff_max_min_luma_transform_block_size);
+
+       hantro_reg_write(vpu, &g2_tempor_mvp_e,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) &&
+                        !(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC));
+       hantro_reg_write(vpu, &g2_strong_smooth_e,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED));
+       hantro_reg_write(vpu, &g2_asym_pred_e,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED));
+       hantro_reg_write(vpu, &g2_sao_e,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET));
+       hantro_reg_write(vpu, &g2_sign_data_hide,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED));
+
+       if (pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED) {
+               hantro_reg_write(vpu, &g2_cu_qpd_e, 1);
+               hantro_reg_write(vpu, &g2_max_cu_qpd_depth, pps->diff_cu_qp_delta_depth);
+       } else {
+               hantro_reg_write(vpu, &g2_cu_qpd_e, 0);
+               hantro_reg_write(vpu, &g2_max_cu_qpd_depth, 0);
+       }
+
+       if (pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT) {
+               hantro_reg_write(vpu, &g2_cb_qp_offset, pps->pps_cb_qp_offset);
+               hantro_reg_write(vpu, &g2_cr_qp_offset, pps->pps_cr_qp_offset);
+       } else {
+               hantro_reg_write(vpu, &g2_cb_qp_offset, 0);
+               hantro_reg_write(vpu, &g2_cr_qp_offset, 0);
+       }
+
+       hantro_reg_write(vpu, &g2_filt_offset_beta, pps->pps_beta_offset_div2);
+       hantro_reg_write(vpu, &g2_filt_offset_tc, pps->pps_tc_offset_div2);
+       hantro_reg_write(vpu, &g2_slice_hdr_ext_e,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT));
+       hantro_reg_write(vpu, &g2_slice_hdr_ext_bits, pps->num_extra_slice_header_bits);
+       hantro_reg_write(vpu, &g2_slice_chqp_present,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT));
+       hantro_reg_write(vpu, &g2_weight_bipr_idc,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED));
+       hantro_reg_write(vpu, &g2_transq_bypass,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED));
+       hantro_reg_write(vpu, &g2_list_mod_e,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT));
+       hantro_reg_write(vpu, &g2_entropy_sync_e,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED));
+       hantro_reg_write(vpu, &g2_cabac_init_present,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT));
+       hantro_reg_write(vpu, &g2_idr_pic_e,
+                        !!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC));
+       hantro_reg_write(vpu, &hevc_parallel_merge,
+                        pps->log2_parallel_merge_level_minus2 + 2);
+       hantro_reg_write(vpu, &g2_pcm_filt_d,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED));
+       hantro_reg_write(vpu, &g2_pcm_e,
+                        !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED));
+       if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) {
+               hantro_reg_write(vpu, &g2_max_pcm_size,
+                                sps->log2_diff_max_min_pcm_luma_coding_block_size +
+                                sps->log2_min_pcm_luma_coding_block_size_minus3 + 3);
+               hantro_reg_write(vpu, &g2_min_pcm_size,
+                                sps->log2_min_pcm_luma_coding_block_size_minus3 + 3);
+               hantro_reg_write(vpu, &g2_bit_depth_pcm_y,
+                                sps->pcm_sample_bit_depth_luma_minus1 + 1);
+               hantro_reg_write(vpu, &g2_bit_depth_pcm_c,
+                                sps->pcm_sample_bit_depth_chroma_minus1 + 1);
+       } else {
+               hantro_reg_write(vpu, &g2_max_pcm_size, 0);
+               hantro_reg_write(vpu, &g2_min_pcm_size, 0);
+               hantro_reg_write(vpu, &g2_bit_depth_pcm_y, 0);
+               hantro_reg_write(vpu, &g2_bit_depth_pcm_c, 0);
+       }
+
+       hantro_reg_write(vpu, &g2_start_code_e, 1);
+       hantro_reg_write(vpu, &g2_init_qp, pps->init_qp_minus26 + 26);
+       hantro_reg_write(vpu, &g2_weight_pred_e,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED));
+       hantro_reg_write(vpu, &g2_cabac_init_present,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT));
+       hantro_reg_write(vpu, &g2_const_intra_e,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED));
+       hantro_reg_write(vpu, &g2_transform_skip,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED));
+       hantro_reg_write(vpu, &g2_out_filtering_dis,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER));
+       hantro_reg_write(vpu, &g2_filt_ctrl_pres,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT));
+       hantro_reg_write(vpu, &g2_dependent_slice,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED));
+       hantro_reg_write(vpu, &g2_filter_override,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED));
+       hantro_reg_write(vpu, &g2_refidx0_active,
+                        pps->num_ref_idx_l0_default_active_minus1 + 1);
+       hantro_reg_write(vpu, &g2_refidx1_active,
+                        pps->num_ref_idx_l1_default_active_minus1 + 1);
+       hantro_reg_write(vpu, &g2_apf_threshold, 8);
+}
+
+static int find_ref_pic_index(const struct v4l2_hevc_dpb_entry *dpb, int pic_order_cnt)
+{
+       int i;
+
+       for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+               if (dpb[i].pic_order_cnt[0] == pic_order_cnt)
+                       return i;
+       }
+
+       return 0x0;
+}
+
+static void set_ref_pic_list(struct hantro_ctx *ctx)
+{
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       struct hantro_dev *vpu = ctx->dev;
+       const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+       const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+       u32 list0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {};
+       u32 list1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {};
+       static const struct hantro_reg ref_pic_regs0[] = {
+               hevc_rlist_f0,
+               hevc_rlist_f1,
+               hevc_rlist_f2,
+               hevc_rlist_f3,
+               hevc_rlist_f4,
+               hevc_rlist_f5,
+               hevc_rlist_f6,
+               hevc_rlist_f7,
+               hevc_rlist_f8,
+               hevc_rlist_f9,
+               hevc_rlist_f10,
+               hevc_rlist_f11,
+               hevc_rlist_f12,
+               hevc_rlist_f13,
+               hevc_rlist_f14,
+               hevc_rlist_f15,
+       };
+       static const struct hantro_reg ref_pic_regs1[] = {
+               hevc_rlist_b0,
+               hevc_rlist_b1,
+               hevc_rlist_b2,
+               hevc_rlist_b3,
+               hevc_rlist_b4,
+               hevc_rlist_b5,
+               hevc_rlist_b6,
+               hevc_rlist_b7,
+               hevc_rlist_b8,
+               hevc_rlist_b9,
+               hevc_rlist_b10,
+               hevc_rlist_b11,
+               hevc_rlist_b12,
+               hevc_rlist_b13,
+               hevc_rlist_b14,
+               hevc_rlist_b15,
+       };
+       unsigned int i, j;
+
+       /* List 0 contains: short term before, short term after and long term */
+       j = 0;
+       for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list0); i++)
+               list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]);
+       for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list0); i++)
+               list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]);
+       for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list0); i++)
+               list0[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]);
+
+       /* Fill the list, copying over and over */
+       i = 0;
+       while (j < ARRAY_SIZE(list0))
+               list0[j++] = list0[i++];
+
+       j = 0;
+       for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list1); i++)
+               list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]);
+       for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list1); i++)
+               list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]);
+       for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list1); i++)
+               list1[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]);
+
+       i = 0;
+       while (j < ARRAY_SIZE(list1))
+               list1[j++] = list1[i++];
+
+       for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+               hantro_reg_write(vpu, &ref_pic_regs0[i], list0[i]);
+               hantro_reg_write(vpu, &ref_pic_regs1[i], list1[i]);
+       }
+}
+
+static int set_ref(struct hantro_ctx *ctx)
+{
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+       const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+       const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+       dma_addr_t luma_addr, chroma_addr, mv_addr = 0;
+       struct hantro_dev *vpu = ctx->dev;
+       size_t cr_offset = hantro_hevc_chroma_offset(sps);
+       size_t mv_offset = hantro_hevc_motion_vectors_offset(sps);
+       u32 max_ref_frames;
+       u16 dpb_longterm_e;
+       static const struct hantro_reg cur_poc[] = {
+               hevc_cur_poc_00,
+               hevc_cur_poc_01,
+               hevc_cur_poc_02,
+               hevc_cur_poc_03,
+               hevc_cur_poc_04,
+               hevc_cur_poc_05,
+               hevc_cur_poc_06,
+               hevc_cur_poc_07,
+               hevc_cur_poc_08,
+               hevc_cur_poc_09,
+               hevc_cur_poc_10,
+               hevc_cur_poc_11,
+               hevc_cur_poc_12,
+               hevc_cur_poc_13,
+               hevc_cur_poc_14,
+               hevc_cur_poc_15,
+       };
+       unsigned int i;
+
+       max_ref_frames = decode_params->num_poc_lt_curr +
+               decode_params->num_poc_st_curr_before +
+               decode_params->num_poc_st_curr_after;
+       /*
+        * Set max_ref_frames to non-zero to avoid HW hang when decoding
+        * badly marked I-frames.
+        */
+       max_ref_frames = max_ref_frames ? max_ref_frames : 1;
+       hantro_reg_write(vpu, &g2_num_ref_frames, max_ref_frames);
+       hantro_reg_write(vpu, &g2_filter_over_slices,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED));
+       hantro_reg_write(vpu, &g2_filter_over_tiles,
+                        !!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED));
+
+       /*
+        * Write POC count diff from current pic. For frame decoding only compute
+        * pic_order_cnt[0] and ignore pic_order_cnt[1] used in field-coding.
+        */
+       for (i = 0; i < decode_params->num_active_dpb_entries && i < ARRAY_SIZE(cur_poc); i++) {
+               char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt[0];
+
+               hantro_reg_write(vpu, &cur_poc[i], poc_diff);
+       }
+
+       if (i < ARRAY_SIZE(cur_poc)) {
+               /*
+                * After the references, fill one entry pointing to itself,
+                * i.e. difference is zero.
+                */
+               hantro_reg_write(vpu, &cur_poc[i], 0);
+               i++;
+       }
+
+       /* Fill the rest with the current picture */
+       for (; i < ARRAY_SIZE(cur_poc); i++)
+               hantro_reg_write(vpu, &cur_poc[i], decode_params->pic_order_cnt_val);
+
+       set_ref_pic_list(ctx);
+
+       /* We will only keep the references picture that are still used */
+       ctx->hevc_dec.ref_bufs_used = 0;
+
+       /* Set up addresses of DPB buffers */
+       dpb_longterm_e = 0;
+       for (i = 0; i < decode_params->num_active_dpb_entries &&
+            i < (V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1); i++) {
+               luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt[0]);
+               if (!luma_addr)
+                       return -ENOMEM;
+
+               chroma_addr = luma_addr + cr_offset;
+               mv_addr = luma_addr + mv_offset;
+
+               if (dpb[i].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR)
+                       dpb_longterm_e |= BIT(V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1 - i);
+
+               hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr);
+               hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr);
+               hantro_write_addr(vpu, G2_REG_DMV_REF(i), mv_addr);
+       }
+
+       luma_addr = hantro_hevc_get_ref_buf(ctx, decode_params->pic_order_cnt_val);
+       if (!luma_addr)
+               return -ENOMEM;
+
+       chroma_addr = luma_addr + cr_offset;
+       mv_addr = luma_addr + mv_offset;
+
+       hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr);
+       hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr);
+       hantro_write_addr(vpu, G2_REG_DMV_REF(i++), mv_addr);
+
+       hantro_write_addr(vpu, G2_ADDR_DST, luma_addr);
+       hantro_write_addr(vpu, G2_ADDR_DST_CHR, chroma_addr);
+       hantro_write_addr(vpu, G2_ADDR_DST_MV, mv_addr);
+
+       hantro_hevc_ref_remove_unused(ctx);
+
+       for (; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+               hantro_write_addr(vpu, G2_REG_ADDR_REF(i), 0);
+               hantro_write_addr(vpu, G2_REG_CHR_REF(i), 0);
+               hantro_write_addr(vpu, G2_REG_DMV_REF(i), 0);
+       }
+
+       hantro_reg_write(vpu, &g2_refer_lterm_e, dpb_longterm_e);
+
+       return 0;
+}
+
+static void set_buffers(struct hantro_ctx *ctx)
+{
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
+       struct hantro_dev *vpu = ctx->dev;
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       size_t cr_offset = hantro_hevc_chroma_offset(sps);
+       dma_addr_t src_dma, dst_dma;
+       u32 src_len, src_buf_len;
+
+       src_buf = hantro_get_src_buf(ctx);
+       dst_buf = hantro_get_dst_buf(ctx);
+
+       /* Source (stream) buffer. */
+       src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+       src_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+       src_buf_len = vb2_plane_size(&src_buf->vb2_buf, 0);
+
+       hantro_write_addr(vpu, G2_ADDR_STR, src_dma);
+       hantro_reg_write(vpu, &g2_stream_len, src_len);
+       hantro_reg_write(vpu, &g2_strm_buffer_len, src_buf_len);
+       hantro_reg_write(vpu, &g2_strm_start_offset, 0);
+       hantro_reg_write(vpu, &g2_write_mvs_e, 1);
+
+       /* Destination (decoded frame) buffer. */
+       dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf);
+
+       hantro_write_addr(vpu, G2_RASTER_SCAN, dst_dma);
+       hantro_write_addr(vpu, G2_RASTER_SCAN_CHR, dst_dma + cr_offset);
+       hantro_write_addr(vpu, G2_ADDR_TILE_SIZE, ctx->hevc_dec.tile_sizes.dma);
+       hantro_write_addr(vpu, G2_TILE_FILTER, ctx->hevc_dec.tile_filter.dma);
+       hantro_write_addr(vpu, G2_TILE_SAO, ctx->hevc_dec.tile_sao.dma);
+       hantro_write_addr(vpu, G2_TILE_BSD, ctx->hevc_dec.tile_bsd.dma);
+}
+
+static void hantro_g2_check_idle(struct hantro_dev *vpu)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               u32 status;
+
+               /* Make sure the VPU is idle */
+               status = vdpu_read(vpu, G2_REG_INTERRUPT);
+               if (status & G2_REG_INTERRUPT_DEC_E) {
+                       dev_warn(vpu->dev, "device still running, aborting");
+                       status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS;
+                       vdpu_write(vpu, status, G2_REG_INTERRUPT);
+               }
+       }
+}
+
+int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+       int ret;
+
+       hantro_g2_check_idle(vpu);
+
+       /* Prepare HEVC decoder context. */
+       ret = hantro_hevc_dec_prepare_run(ctx);
+       if (ret)
+               return ret;
+
+       /* Configure hardware registers. */
+       set_params(ctx);
+
+       /* set reference pictures */
+       ret = set_ref(ctx);
+       if (ret)
+               return ret;
+
+       set_buffers(ctx);
+       prepare_tile_info_buffer(ctx);
+
+       hantro_end_prepare_run(ctx);
+
+       hantro_reg_write(vpu, &g2_mode, HEVC_DEC_MODE);
+       hantro_reg_write(vpu, &g2_clk_gate_e, 1);
+
+       /* Don't disable output */
+       hantro_reg_write(vpu, &g2_out_dis, 0);
+
+       /* Don't compress buffers */
+       hantro_reg_write(vpu, &g2_ref_compress_bypass, 1);
+
+       /* use NV12 as output format */
+       hantro_reg_write(vpu, &g2_out_rs_e, 1);
+
+       /* Bus width and max burst */
+       hantro_reg_write(vpu, &g2_buswidth, BUS_WIDTH_128);
+       hantro_reg_write(vpu, &g2_max_burst, 16);
+
+       /* Swap */
+       hantro_reg_write(vpu, &g2_strm_swap, 0xf);
+       hantro_reg_write(vpu, &g2_dirmv_swap, 0xf);
+       hantro_reg_write(vpu, &g2_compress_swap, 0xf);
+
+       /* Start decoding! */
+       vdpu_write(vpu, G2_REG_INTERRUPT_DEC_E, G2_REG_INTERRUPT);
+
+       return 0;
+}
diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/staging/media/hantro/hantro_g2_regs.h
new file mode 100644 (file)
index 0000000..bb22fa9
--- /dev/null
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Collabora
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@collabora.com>
+ */
+
+#ifndef HANTRO_G2_REGS_H_
+#define HANTRO_G2_REGS_H_
+
+#include "hantro.h"
+
+#define G2_SWREG(nr)   ((nr) * 4)
+
+#define G2_DEC_REG(b, s, m) \
+       ((const struct hantro_reg) { \
+               .base = G2_SWREG(b), \
+               .shift = s, \
+               .mask = m, \
+       })
+
+#define G2_REG_VERSION                 G2_SWREG(0)
+
+#define G2_REG_INTERRUPT               G2_SWREG(1)
+#define G2_REG_INTERRUPT_DEC_RDY_INT   BIT(12)
+#define G2_REG_INTERRUPT_DEC_ABORT_E   BIT(5)
+#define G2_REG_INTERRUPT_DEC_IRQ_DIS   BIT(4)
+#define G2_REG_INTERRUPT_DEC_E         BIT(0)
+
+#define g2_strm_swap           G2_DEC_REG(2, 28, 0xf)
+#define g2_dirmv_swap          G2_DEC_REG(2, 20, 0xf)
+
+#define g2_mode                        G2_DEC_REG(3, 27, 0x1f)
+#define g2_compress_swap       G2_DEC_REG(3, 20, 0xf)
+#define g2_ref_compress_bypass G2_DEC_REG(3, 17, 0x1)
+#define g2_out_rs_e            G2_DEC_REG(3, 16, 0x1)
+#define g2_out_dis             G2_DEC_REG(3, 15, 0x1)
+#define g2_out_filtering_dis   G2_DEC_REG(3, 14, 0x1)
+#define g2_write_mvs_e         G2_DEC_REG(3, 12, 0x1)
+
+#define g2_pic_width_in_cbs    G2_DEC_REG(4, 19, 0x1fff)
+#define g2_pic_height_in_cbs   G2_DEC_REG(4, 6,  0x1fff)
+#define g2_num_ref_frames      G2_DEC_REG(4, 0,  0x1f)
+
+#define g2_scaling_list_e      G2_DEC_REG(5, 24, 0x1)
+#define g2_cb_qp_offset                G2_DEC_REG(5, 19, 0x1f)
+#define g2_cr_qp_offset                G2_DEC_REG(5, 14, 0x1f)
+#define g2_sign_data_hide      G2_DEC_REG(5, 12, 0x1)
+#define g2_tempor_mvp_e                G2_DEC_REG(5, 11, 0x1)
+#define g2_max_cu_qpd_depth    G2_DEC_REG(5, 5,  0x3f)
+#define g2_cu_qpd_e            G2_DEC_REG(5, 4,  0x1)
+
+#define g2_stream_len          G2_DEC_REG(6, 0,  0xffffffff)
+
+#define g2_cabac_init_present  G2_DEC_REG(7, 31, 0x1)
+#define g2_weight_pred_e       G2_DEC_REG(7, 28, 0x1)
+#define g2_weight_bipr_idc     G2_DEC_REG(7, 26, 0x3)
+#define g2_filter_over_slices  G2_DEC_REG(7, 25, 0x1)
+#define g2_filter_over_tiles   G2_DEC_REG(7, 24, 0x1)
+#define g2_asym_pred_e         G2_DEC_REG(7, 23, 0x1)
+#define g2_sao_e               G2_DEC_REG(7, 22, 0x1)
+#define g2_pcm_filt_d          G2_DEC_REG(7, 21, 0x1)
+#define g2_slice_chqp_present  G2_DEC_REG(7, 20, 0x1)
+#define g2_dependent_slice     G2_DEC_REG(7, 19, 0x1)
+#define g2_filter_override     G2_DEC_REG(7, 18, 0x1)
+#define g2_strong_smooth_e     G2_DEC_REG(7, 17, 0x1)
+#define g2_filt_offset_beta    G2_DEC_REG(7, 12, 0x1f)
+#define g2_filt_offset_tc      G2_DEC_REG(7, 7,  0x1f)
+#define g2_slice_hdr_ext_e     G2_DEC_REG(7, 6,  0x1)
+#define g2_slice_hdr_ext_bits  G2_DEC_REG(7, 3,  0x7)
+
+#define g2_const_intra_e       G2_DEC_REG(8, 31, 0x1)
+#define g2_filt_ctrl_pres      G2_DEC_REG(8, 30, 0x1)
+#define g2_idr_pic_e           G2_DEC_REG(8, 16, 0x1)
+#define g2_bit_depth_pcm_y     G2_DEC_REG(8, 12, 0xf)
+#define g2_bit_depth_pcm_c     G2_DEC_REG(8, 8,  0xf)
+#define g2_bit_depth_y_minus8  G2_DEC_REG(8, 6,  0x3)
+#define g2_bit_depth_c_minus8  G2_DEC_REG(8, 4,  0x3)
+#define g2_output_8_bits       G2_DEC_REG(8, 3,  0x1)
+
+#define g2_refidx1_active      G2_DEC_REG(9, 19, 0x1f)
+#define g2_refidx0_active      G2_DEC_REG(9, 14, 0x1f)
+#define g2_hdr_skip_length     G2_DEC_REG(9, 0,  0x3fff)
+
+#define g2_start_code_e                G2_DEC_REG(10, 31, 0x1)
+#define g2_init_qp             G2_DEC_REG(10, 24, 0x3f)
+#define g2_num_tile_cols       G2_DEC_REG(10, 19, 0x1f)
+#define g2_num_tile_rows       G2_DEC_REG(10, 14, 0x1f)
+#define g2_tile_e              G2_DEC_REG(10, 1,  0x1)
+#define g2_entropy_sync_e      G2_DEC_REG(10, 0,  0x1)
+
+#define g2_refer_lterm_e       G2_DEC_REG(12, 16, 0xffff)
+#define g2_min_cb_size         G2_DEC_REG(12, 13, 0x7)
+#define g2_max_cb_size         G2_DEC_REG(12, 10, 0x7)
+#define g2_min_pcm_size                G2_DEC_REG(12, 7,  0x7)
+#define g2_max_pcm_size                G2_DEC_REG(12, 4,  0x7)
+#define g2_pcm_e               G2_DEC_REG(12, 3,  0x1)
+#define g2_transform_skip      G2_DEC_REG(12, 2,  0x1)
+#define g2_transq_bypass       G2_DEC_REG(12, 1,  0x1)
+#define g2_list_mod_e          G2_DEC_REG(12, 0,  0x1)
+
+#define hevc_min_trb_size              G2_DEC_REG(13, 13, 0x7)
+#define hevc_max_trb_size              G2_DEC_REG(13, 10, 0x7)
+#define hevc_max_intra_hierdepth       G2_DEC_REG(13, 7,  0x7)
+#define hevc_max_inter_hierdepth       G2_DEC_REG(13, 4,  0x7)
+#define hevc_parallel_merge            G2_DEC_REG(13, 0,  0xf)
+
+#define hevc_rlist_f0          G2_DEC_REG(14, 0,  0x1f)
+#define hevc_rlist_f1          G2_DEC_REG(14, 10, 0x1f)
+#define hevc_rlist_f2          G2_DEC_REG(14, 20, 0x1f)
+#define hevc_rlist_b0          G2_DEC_REG(14, 5,  0x1f)
+#define hevc_rlist_b1          G2_DEC_REG(14, 15, 0x1f)
+#define hevc_rlist_b2          G2_DEC_REG(14, 25, 0x1f)
+
+#define hevc_rlist_f3          G2_DEC_REG(15, 0,  0x1f)
+#define hevc_rlist_f4          G2_DEC_REG(15, 10, 0x1f)
+#define hevc_rlist_f5          G2_DEC_REG(15, 20, 0x1f)
+#define hevc_rlist_b3          G2_DEC_REG(15, 5,  0x1f)
+#define hevc_rlist_b4          G2_DEC_REG(15, 15, 0x1f)
+#define hevc_rlist_b5          G2_DEC_REG(15, 25, 0x1f)
+
+#define hevc_rlist_f6          G2_DEC_REG(16, 0,  0x1f)
+#define hevc_rlist_f7          G2_DEC_REG(16, 10, 0x1f)
+#define hevc_rlist_f8          G2_DEC_REG(16, 20, 0x1f)
+#define hevc_rlist_b6          G2_DEC_REG(16, 5,  0x1f)
+#define hevc_rlist_b7          G2_DEC_REG(16, 15, 0x1f)
+#define hevc_rlist_b8          G2_DEC_REG(16, 25, 0x1f)
+
+#define hevc_rlist_f9          G2_DEC_REG(17, 0,  0x1f)
+#define hevc_rlist_f10         G2_DEC_REG(17, 10, 0x1f)
+#define hevc_rlist_f11         G2_DEC_REG(17, 20, 0x1f)
+#define hevc_rlist_b9          G2_DEC_REG(17, 5,  0x1f)
+#define hevc_rlist_b10         G2_DEC_REG(17, 15, 0x1f)
+#define hevc_rlist_b11         G2_DEC_REG(17, 25, 0x1f)
+
+#define hevc_rlist_f12         G2_DEC_REG(18, 0,  0x1f)
+#define hevc_rlist_f13         G2_DEC_REG(18, 10, 0x1f)
+#define hevc_rlist_f14         G2_DEC_REG(18, 20, 0x1f)
+#define hevc_rlist_b12         G2_DEC_REG(18, 5,  0x1f)
+#define hevc_rlist_b13         G2_DEC_REG(18, 15, 0x1f)
+#define hevc_rlist_b14         G2_DEC_REG(18, 25, 0x1f)
+
+#define hevc_rlist_f15         G2_DEC_REG(19, 0,  0x1f)
+#define hevc_rlist_b15         G2_DEC_REG(19, 5,  0x1f)
+
+#define g2_partial_ctb_x       G2_DEC_REG(20, 31, 0x1)
+#define g2_partial_ctb_y       G2_DEC_REG(20, 30, 0x1)
+#define g2_pic_width_4x4       G2_DEC_REG(20, 16, 0xfff)
+#define g2_pic_height_4x4      G2_DEC_REG(20, 0,  0xfff)
+#define hevc_cur_poc_00                G2_DEC_REG(46, 24, 0xff)
+#define hevc_cur_poc_01                G2_DEC_REG(46, 16, 0xff)
+#define hevc_cur_poc_02                G2_DEC_REG(46, 8,  0xff)
+#define hevc_cur_poc_03                G2_DEC_REG(46, 0,  0xff)
+
+#define hevc_cur_poc_04                G2_DEC_REG(47, 24, 0xff)
+#define hevc_cur_poc_05                G2_DEC_REG(47, 16, 0xff)
+#define hevc_cur_poc_06                G2_DEC_REG(47, 8,  0xff)
+#define hevc_cur_poc_07                G2_DEC_REG(47, 0,  0xff)
+
+#define hevc_cur_poc_08                G2_DEC_REG(48, 24, 0xff)
+#define hevc_cur_poc_09                G2_DEC_REG(48, 16, 0xff)
+#define hevc_cur_poc_10                G2_DEC_REG(48, 8,  0xff)
+#define hevc_cur_poc_11                G2_DEC_REG(48, 0,  0xff)
+
+#define hevc_cur_poc_12                G2_DEC_REG(49, 24, 0xff)
+#define hevc_cur_poc_13                G2_DEC_REG(49, 16, 0xff)
+#define hevc_cur_poc_14                G2_DEC_REG(49, 8,  0xff)
+#define hevc_cur_poc_15                G2_DEC_REG(49, 0,  0xff)
+
+#define g2_apf_threshold       G2_DEC_REG(55, 0, 0xffff)
+
+#define g2_clk_gate_e          G2_DEC_REG(58, 16, 0x1)
+#define g2_buswidth            G2_DEC_REG(58, 8,  0x7)
+#define g2_max_burst           G2_DEC_REG(58, 0,  0xff)
+
+#define G2_REG_CONFIG                          G2_SWREG(58)
+#define G2_REG_CONFIG_DEC_CLK_GATE_E           BIT(16)
+#define G2_REG_CONFIG_DEC_CLK_GATE_IDLE_E      BIT(17)
+
+#define G2_ADDR_DST            (G2_SWREG(65))
+#define G2_REG_ADDR_REF(i)     (G2_SWREG(67)  + ((i) * 0x8))
+#define G2_ADDR_DST_CHR                (G2_SWREG(99))
+#define G2_REG_CHR_REF(i)      (G2_SWREG(101) + ((i) * 0x8))
+#define G2_ADDR_DST_MV         (G2_SWREG(133))
+#define G2_REG_DMV_REF(i)      (G2_SWREG(135) + ((i) * 0x8))
+#define G2_ADDR_TILE_SIZE      (G2_SWREG(167))
+#define G2_ADDR_STR            (G2_SWREG(169))
+#define HEVC_SCALING_LIST      (G2_SWREG(171))
+#define G2_RASTER_SCAN         (G2_SWREG(175))
+#define G2_RASTER_SCAN_CHR     (G2_SWREG(177))
+#define G2_TILE_FILTER         (G2_SWREG(179))
+#define G2_TILE_SAO            (G2_SWREG(181))
+#define G2_TILE_BSD            (G2_SWREG(183))
+
+#define g2_strm_buffer_len     G2_DEC_REG(258, 0, 0xffffffff)
+#define g2_strm_start_offset   G2_DEC_REG(259, 0, 0xffffffff)
+
+#endif
index b88dc4e..56cf261 100644 (file)
@@ -88,7 +88,7 @@ hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu,
        }
 }
 
-void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
+int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
@@ -136,6 +136,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
        hantro_end_prepare_run(ctx);
 
        vepu_write(vpu, reg, H1_REG_ENC_CTRL);
+
+       return 0;
 }
 
 void hantro_jpeg_enc_done(struct hantro_ctx *ctx)
diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c
new file mode 100644 (file)
index 0000000..5347f5a
--- /dev/null
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU HEVC codec driver
+ *
+ * Copyright (C) 2020 Safran Passenger Innovations LLC
+ */
+
+#include <linux/types.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "hantro.h"
+#include "hantro_hw.h"
+
+#define VERT_FILTER_RAM_SIZE 8 /* bytes per pixel row */
+/*
+ * BSD control data of current picture at tile border
+ * 128 bits per 4x4 tile = 128/(8*4) bytes per row
+ */
+#define BSD_CTRL_RAM_SIZE 4 /* bytes per pixel row */
+/* tile border coefficients of filter */
+#define VERT_SAO_RAM_SIZE 48 /* bytes per pixel */
+
+#define MAX_TILE_COLS 20
+#define MAX_TILE_ROWS 22
+
+#define UNUSED_REF     -1
+
+#define G2_ALIGN               16
+
+size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps)
+{
+       int bytes_per_pixel = sps->bit_depth_luma_minus8 == 0 ? 1 : 2;
+
+       return sps->pic_width_in_luma_samples *
+              sps->pic_height_in_luma_samples * bytes_per_pixel;
+}
+
+size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps)
+{
+       size_t cr_offset = hantro_hevc_chroma_offset(sps);
+
+       return ALIGN((cr_offset * 3) / 2, G2_ALIGN);
+}
+
+static size_t hantro_hevc_mv_size(const struct v4l2_ctrl_hevc_sps *sps)
+{
+       u32 min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3;
+       u32 ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size;
+       u32 pic_width_in_ctbs_y = (sps->pic_width_in_luma_samples + (1 << ctb_log2_size_y) - 1)
+                                 >> ctb_log2_size_y;
+       u32 pic_height_in_ctbs_y = (sps->pic_height_in_luma_samples + (1 << ctb_log2_size_y) - 1)
+                                  >> ctb_log2_size_y;
+       size_t mv_size;
+
+       mv_size = pic_width_in_ctbs_y * pic_height_in_ctbs_y *
+                 (1 << (2 * (ctb_log2_size_y - 4))) * 16;
+
+       vpu_debug(4, "%dx%d (CTBs) %zu MV bytes\n",
+                 pic_width_in_ctbs_y, pic_height_in_ctbs_y, mv_size);
+
+       return mv_size;
+}
+
+static size_t hantro_hevc_ref_size(struct hantro_ctx *ctx)
+{
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+
+       return hantro_hevc_motion_vectors_offset(sps) + hantro_hevc_mv_size(sps);
+}
+
+static void hantro_hevc_ref_free(struct hantro_ctx *ctx)
+{
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       struct hantro_dev *vpu = ctx->dev;
+       int i;
+
+       for (i = 0;  i < NUM_REF_PICTURES; i++) {
+               if (hevc_dec->ref_bufs[i].cpu)
+                       dma_free_coherent(vpu->dev, hevc_dec->ref_bufs[i].size,
+                                         hevc_dec->ref_bufs[i].cpu,
+                                         hevc_dec->ref_bufs[i].dma);
+       }
+}
+
+static void hantro_hevc_ref_init(struct hantro_ctx *ctx)
+{
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       int i;
+
+       for (i = 0;  i < NUM_REF_PICTURES; i++)
+               hevc_dec->ref_bufs_poc[i] = UNUSED_REF;
+}
+
+dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx,
+                                  int poc)
+{
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       int i;
+
+       /* Find the reference buffer in already know ones */
+       for (i = 0;  i < NUM_REF_PICTURES; i++) {
+               if (hevc_dec->ref_bufs_poc[i] == poc) {
+                       hevc_dec->ref_bufs_used |= 1 << i;
+                       return hevc_dec->ref_bufs[i].dma;
+               }
+       }
+
+       /* Allocate a new reference buffer */
+       for (i = 0; i < NUM_REF_PICTURES; i++) {
+               if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) {
+                       if (!hevc_dec->ref_bufs[i].cpu) {
+                               struct hantro_dev *vpu = ctx->dev;
+
+                               /*
+                                * Allocate the space needed for the raw data +
+                                * motion vector data. Optimizations could be to
+                                * allocate raw data in non coherent memory and only
+                                * clear the motion vector data.
+                                */
+                               hevc_dec->ref_bufs[i].cpu =
+                                       dma_alloc_coherent(vpu->dev,
+                                                          hantro_hevc_ref_size(ctx),
+                                                          &hevc_dec->ref_bufs[i].dma,
+                                                          GFP_KERNEL);
+                               if (!hevc_dec->ref_bufs[i].cpu)
+                                       return 0;
+
+                               hevc_dec->ref_bufs[i].size = hantro_hevc_ref_size(ctx);
+                       }
+                       hevc_dec->ref_bufs_used |= 1 << i;
+                       memset(hevc_dec->ref_bufs[i].cpu, 0, hantro_hevc_ref_size(ctx));
+                       hevc_dec->ref_bufs_poc[i] = poc;
+
+                       return hevc_dec->ref_bufs[i].dma;
+               }
+       }
+
+       return 0;
+}
+
+void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx)
+{
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       int i;
+
+       /* Just tag buffer as unused, do not free them */
+       for (i = 0;  i < NUM_REF_PICTURES; i++) {
+               if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF)
+                       continue;
+
+               if (hevc_dec->ref_bufs_used & (1 << i))
+                       continue;
+
+               hevc_dec->ref_bufs_poc[i] = UNUSED_REF;
+       }
+}
+
+static int tile_buffer_reallocate(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+       unsigned int height64 = (sps->pic_height_in_luma_samples + 63) & ~63;
+       unsigned int size;
+
+       if (num_tile_cols <= 1 ||
+           num_tile_cols <= hevc_dec->num_tile_cols_allocated)
+               return 0;
+
+       /* Need to reallocate due to tiles passed via PPS */
+       if (hevc_dec->tile_filter.cpu) {
+               dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+                                 hevc_dec->tile_filter.cpu,
+                                 hevc_dec->tile_filter.dma);
+               hevc_dec->tile_filter.cpu = NULL;
+       }
+
+       if (hevc_dec->tile_sao.cpu) {
+               dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+                                 hevc_dec->tile_sao.cpu,
+                                 hevc_dec->tile_sao.dma);
+               hevc_dec->tile_sao.cpu = NULL;
+       }
+
+       if (hevc_dec->tile_bsd.cpu) {
+               dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+                                 hevc_dec->tile_bsd.cpu,
+                                 hevc_dec->tile_bsd.dma);
+               hevc_dec->tile_bsd.cpu = NULL;
+       }
+
+       size = VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1);
+       hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size,
+                                                      &hevc_dec->tile_filter.dma,
+                                                      GFP_KERNEL);
+       if (!hevc_dec->tile_filter.cpu)
+               goto err_free_tile_buffers;
+       hevc_dec->tile_filter.size = size;
+
+       size = VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1);
+       hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size,
+                                                   &hevc_dec->tile_sao.dma,
+                                                   GFP_KERNEL);
+       if (!hevc_dec->tile_sao.cpu)
+               goto err_free_tile_buffers;
+       hevc_dec->tile_sao.size = size;
+
+       size = BSD_CTRL_RAM_SIZE * height64 * (num_tile_cols - 1);
+       hevc_dec->tile_bsd.cpu = dma_alloc_coherent(vpu->dev, size,
+                                                   &hevc_dec->tile_bsd.dma,
+                                                   GFP_KERNEL);
+       if (!hevc_dec->tile_bsd.cpu)
+               goto err_free_tile_buffers;
+       hevc_dec->tile_bsd.size = size;
+
+       hevc_dec->num_tile_cols_allocated = num_tile_cols;
+
+       return 0;
+
+err_free_tile_buffers:
+       if (hevc_dec->tile_filter.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+                                 hevc_dec->tile_filter.cpu,
+                                 hevc_dec->tile_filter.dma);
+       hevc_dec->tile_filter.cpu = NULL;
+
+       if (hevc_dec->tile_sao.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+                                 hevc_dec->tile_sao.cpu,
+                                 hevc_dec->tile_sao.dma);
+       hevc_dec->tile_sao.cpu = NULL;
+
+       if (hevc_dec->tile_bsd.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+                                 hevc_dec->tile_bsd.cpu,
+                                 hevc_dec->tile_bsd.dma);
+       hevc_dec->tile_bsd.cpu = NULL;
+
+       return -ENOMEM;
+}
+
+int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)
+{
+       struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec;
+       struct hantro_hevc_dec_ctrls *ctrls = &hevc_ctx->ctrls;
+       int ret;
+
+       hantro_start_prepare_run(ctx);
+
+       ctrls->decode_params =
+               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
+       if (WARN_ON(!ctrls->decode_params))
+               return -EINVAL;
+
+       ctrls->sps =
+               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+       if (WARN_ON(!ctrls->sps))
+               return -EINVAL;
+
+       ctrls->pps =
+               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_PPS);
+       if (WARN_ON(!ctrls->pps))
+               return -EINVAL;
+
+       ret = tile_buffer_reallocate(ctx);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+void hantro_hevc_dec_exit(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+
+       if (hevc_dec->tile_sizes.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_sizes.size,
+                                 hevc_dec->tile_sizes.cpu,
+                                 hevc_dec->tile_sizes.dma);
+       hevc_dec->tile_sizes.cpu = NULL;
+
+       if (hevc_dec->tile_filter.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+                                 hevc_dec->tile_filter.cpu,
+                                 hevc_dec->tile_filter.dma);
+       hevc_dec->tile_filter.cpu = NULL;
+
+       if (hevc_dec->tile_sao.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+                                 hevc_dec->tile_sao.cpu,
+                                 hevc_dec->tile_sao.dma);
+       hevc_dec->tile_sao.cpu = NULL;
+
+       if (hevc_dec->tile_bsd.cpu)
+               dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+                                 hevc_dec->tile_bsd.cpu,
+                                 hevc_dec->tile_bsd.dma);
+       hevc_dec->tile_bsd.cpu = NULL;
+
+       hantro_hevc_ref_free(ctx);
+}
+
+int hantro_hevc_dec_init(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+       struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+       unsigned int size;
+
+       memset(hevc_dec, 0, sizeof(*hevc_dec));
+
+       /*
+        * Maximum number of tiles times width and height (2 bytes each),
+        * rounding up to next 16 bytes boundary + one extra 16 byte
+        * chunk (HW guys wanted to have this).
+        */
+       size = round_up(MAX_TILE_COLS * MAX_TILE_ROWS * 4 * sizeof(u16) + 16, 16);
+       hevc_dec->tile_sizes.cpu = dma_alloc_coherent(vpu->dev, size,
+                                                     &hevc_dec->tile_sizes.dma,
+                                                     GFP_KERNEL);
+       if (!hevc_dec->tile_sizes.cpu)
+               return -ENOMEM;
+
+       hevc_dec->tile_sizes.size = size;
+
+       hantro_hevc_ref_init(ctx);
+
+       return 0;
+}
index 83b3e42..5dcf658 100644 (file)
@@ -20,6 +20,8 @@
 #define MB_WIDTH(w)            DIV_ROUND_UP(w, MB_DIM)
 #define MB_HEIGHT(h)           DIV_ROUND_UP(h, MB_DIM)
 
+#define NUM_REF_PICTURES       (V4L2_HEVC_DPB_ENTRIES_NUM_MAX + 1)
+
 struct hantro_dev;
 struct hantro_ctx;
 struct hantro_buf;
@@ -96,6 +98,46 @@ struct hantro_h264_dec_hw_ctx {
 };
 
 /**
+ * struct hantro_hevc_dec_ctrls
+ * @decode_params: Decode params
+ * @sps:       SPS info
+ * @pps:       PPS info
+ * @hevc_hdr_skip_length: the number of data (in bits) to skip in the
+ *                       slice segment header syntax after 'slice type'
+ *                       token
+ */
+struct hantro_hevc_dec_ctrls {
+       const struct v4l2_ctrl_hevc_decode_params *decode_params;
+       const struct v4l2_ctrl_hevc_sps *sps;
+       const struct v4l2_ctrl_hevc_pps *pps;
+       u32 hevc_hdr_skip_length;
+};
+
+/**
+ * struct hantro_hevc_dec_hw_ctx
+ * @tile_sizes:                Tile sizes buffer
+ * @tile_filter:       Tile vertical filter buffer
+ * @tile_sao:          Tile SAO buffer
+ * @tile_bsd:          Tile BSD control buffer
+ * @ref_bufs:          Internal reference buffers
+ * @ref_bufs_poc:      Internal reference buffers picture order count
+ * @ref_bufs_used:     Bitfield of used reference buffers
+ * @ctrls:             V4L2 controls attached to a run
+ * @num_tile_cols_allocated: number of allocated tiles
+ */
+struct hantro_hevc_dec_hw_ctx {
+       struct hantro_aux_buf tile_sizes;
+       struct hantro_aux_buf tile_filter;
+       struct hantro_aux_buf tile_sao;
+       struct hantro_aux_buf tile_bsd;
+       struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES];
+       int ref_bufs_poc[NUM_REF_PICTURES];
+       u32 ref_bufs_used;
+       struct hantro_hevc_dec_ctrls ctrls;
+       unsigned int num_tile_cols_allocated;
+};
+
+/**
  * struct hantro_mpeg2_dec_hw_ctx
  *
  * @qtable:            Quantization table
@@ -133,14 +175,15 @@ struct hantro_postproc_ctx {
  *             Optional and called from process context.
  * @run:       Start single {en,de)coding job. Called from atomic context
  *             to indicate that a pair of buffers is ready and the hardware
- *             should be programmed and started.
+ *             should be programmed and started. Returns zero if OK, a
+ *             negative value in error cases.
  * @done:      Read back processing results and additional data from hardware.
  * @reset:     Reset the hardware in case of a timeout.
  */
 struct hantro_codec_ops {
        int (*init)(struct hantro_ctx *ctx);
        void (*exit)(struct hantro_ctx *ctx);
-       void (*run)(struct hantro_ctx *ctx);
+       int (*run)(struct hantro_ctx *ctx);
        void (*done)(struct hantro_ctx *ctx);
        void (*reset)(struct hantro_ctx *ctx);
 };
@@ -148,22 +191,26 @@ struct hantro_codec_ops {
 /**
  * enum hantro_enc_fmt - source format ID for hardware registers.
  *
- * @RK3288_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format
- * @RK3288_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format
- * @RK3288_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV)
- * @RK3288_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY)
+ * @ROCKCHIP_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format
+ * @ROCKCHIP_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format
+ * @ROCKCHIP_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV)
+ * @ROCKCHIP_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY)
  */
 enum hantro_enc_fmt {
-       RK3288_VPU_ENC_FMT_YUV420P = 0,
-       RK3288_VPU_ENC_FMT_YUV420SP = 1,
-       RK3288_VPU_ENC_FMT_YUYV422 = 2,
-       RK3288_VPU_ENC_FMT_UYVY422 = 3,
+       ROCKCHIP_VPU_ENC_FMT_YUV420P = 0,
+       ROCKCHIP_VPU_ENC_FMT_YUV420SP = 1,
+       ROCKCHIP_VPU_ENC_FMT_YUYV422 = 2,
+       ROCKCHIP_VPU_ENC_FMT_UYVY422 = 3,
 };
 
-extern const struct hantro_variant rk3399_vpu_variant;
-extern const struct hantro_variant rk3328_vpu_variant;
-extern const struct hantro_variant rk3288_vpu_variant;
+extern const struct hantro_variant imx8mq_vpu_g2_variant;
 extern const struct hantro_variant imx8mq_vpu_variant;
+extern const struct hantro_variant rk3036_vpu_variant;
+extern const struct hantro_variant rk3066_vpu_variant;
+extern const struct hantro_variant rk3288_vpu_variant;
+extern const struct hantro_variant rk3328_vpu_variant;
+extern const struct hantro_variant rk3399_vpu_variant;
+extern const struct hantro_variant sama5d4_vdec_variant;
 
 extern const struct hantro_postproc_regs hantro_g1_postproc_regs;
 
@@ -176,8 +223,11 @@ void hantro_irq_done(struct hantro_dev *vpu,
 void hantro_start_prepare_run(struct hantro_ctx *ctx);
 void hantro_end_prepare_run(struct hantro_ctx *ctx);
 
-void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
-void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx);
+irqreturn_t hantro_g1_irq(int irq, void *dev_id);
+void hantro_g1_reset(struct hantro_ctx *ctx);
+
+int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx);
 int hantro_jpeg_enc_init(struct hantro_ctx *ctx);
 void hantro_jpeg_enc_exit(struct hantro_ctx *ctx);
 void hantro_jpeg_enc_done(struct hantro_ctx *ctx);
@@ -185,10 +235,19 @@ void hantro_jpeg_enc_done(struct hantro_ctx *ctx);
 dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
                                   unsigned int dpb_idx);
 int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx);
-void hantro_g1_h264_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_h264_dec_run(struct hantro_ctx *ctx);
 int hantro_h264_dec_init(struct hantro_ctx *ctx);
 void hantro_h264_dec_exit(struct hantro_ctx *ctx);
 
+int hantro_hevc_dec_init(struct hantro_ctx *ctx);
+void hantro_hevc_dec_exit(struct hantro_ctx *ctx);
+int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx);
+int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx);
+dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc);
+void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx);
+size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps);
+size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps);
+
 static inline size_t
 hantro_h264_mv_size(unsigned int width, unsigned int height)
 {
@@ -216,15 +275,15 @@ hantro_h264_mv_size(unsigned int width, unsigned int height)
        return 64 * MB_WIDTH(width) * MB_WIDTH(height) + 32;
 }
 
-void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
-void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx);
 void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
-       const struct v4l2_ctrl_mpeg2_quantization *ctrl);
+                                 const struct v4l2_ctrl_mpeg2_quantisation *ctrl);
 int hantro_mpeg2_dec_init(struct hantro_ctx *ctx);
 void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx);
 
-void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx);
-void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx);
 int hantro_vp8_dec_init(struct hantro_ctx *ctx);
 void hantro_vp8_dec_exit(struct hantro_ctx *ctx);
 void hantro_vp8_prob_update(struct hantro_ctx *ctx,
index 1d334e6..04e545e 100644 (file)
@@ -19,7 +19,7 @@ static const u8 zigzag[64] = {
 };
 
 void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
-       const struct v4l2_ctrl_mpeg2_quantization *ctrl)
+                                 const struct v4l2_ctrl_mpeg2_quantisation *ctrl)
 {
        int i, n;
 
index 6d2a8f2..ed8916c 100644 (file)
@@ -50,6 +50,20 @@ const struct hantro_postproc_regs hantro_g1_postproc_regs = {
        .display_width = {G1_REG_PP_DISPLAY_WIDTH, 0, 0xfff},
 };
 
+bool hantro_needs_postproc(const struct hantro_ctx *ctx,
+                          const struct hantro_fmt *fmt)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       if (ctx->is_encoder)
+               return false;
+
+       if (!vpu->variant->postproc_fmts)
+               return false;
+
+       return fmt->fourcc != V4L2_PIX_FMT_NV12;
+}
+
 void hantro_postproc_enable(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
index 1bc118e..bcb0bdf 100644 (file)
@@ -55,7 +55,9 @@ static const struct hantro_fmt *
 hantro_get_postproc_formats(const struct hantro_ctx *ctx,
                            unsigned int *num_fmts)
 {
-       if (ctx->is_encoder) {
+       struct hantro_dev *vpu = ctx->dev;
+
+       if (ctx->is_encoder || !vpu->variant->postproc_fmts) {
                *num_fmts = 0;
                return NULL;
        }
@@ -390,6 +392,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc)
        case V4L2_PIX_FMT_MPEG2_SLICE:
        case V4L2_PIX_FMT_VP8_FRAME:
        case V4L2_PIX_FMT_H264_SLICE:
+       case V4L2_PIX_FMT_HEVC_SLICE:
                ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
                break;
        default:
@@ -639,7 +642,14 @@ static int hantro_buf_prepare(struct vb2_buffer *vb)
        ret = hantro_buf_plane_check(vb, pix_fmt);
        if (ret)
                return ret;
-       vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage);
+       /*
+        * Buffer's bytesused must be written by driver for CAPTURE buffers.
+        * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+        * it to buffer length).
+        */
+       if (V4L2_TYPE_IS_CAPTURE(vq->type))
+               vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage);
+
        return 0;
 }
 
index c222de0..ea919bf 100644 (file)
@@ -11,6 +11,7 @@
 #include "hantro.h"
 #include "hantro_jpeg.h"
 #include "hantro_g1_regs.h"
+#include "hantro_g2_regs.h"
 
 #define CTRL_SOFT_RESET                0x00
 #define RESET_G1               BIT(1)
@@ -109,10 +110,10 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
                .frmsize = {
                        .min_width = 48,
                        .max_width = 3840,
-                       .step_width = 16,
+                       .step_width = MB_DIM,
                        .min_height = 48,
                        .max_height = 2160,
-                       .step_height = 16,
+                       .step_height = MB_DIM,
                },
        },
        {
@@ -130,6 +131,26 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
        },
 };
 
+static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+               .codec_mode = HANTRO_MODE_HEVC_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 3840,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 2160,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
 static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
 {
        struct hantro_dev *vpu = dev_id;
@@ -148,9 +169,26 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t imx8m_vpu_g2_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vdpu_read(vpu, G2_REG_INTERRUPT);
+       state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ?
+                VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vdpu_write(vpu, 0, G2_REG_INTERRUPT);
+       vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG);
+
+       hantro_irq_done(vpu, state);
+
+       return IRQ_HANDLED;
+}
+
 static int imx8mq_vpu_hw_init(struct hantro_dev *vpu)
 {
-       vpu->dec_base = vpu->reg_bases[0];
        vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
 
        return 0;
@@ -163,6 +201,13 @@ static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
        imx8m_soft_reset(vpu, RESET_G1);
 }
 
+static void imx8m_vpu_g2_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       imx8m_soft_reset(vpu, RESET_G2);
+}
+
 /*
  * Supported codec ops.
  */
@@ -188,13 +233,25 @@ static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = {
        },
 };
 
+static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = {
+       [HANTRO_MODE_HEVC_DEC] = {
+               .run = hantro_g2_hevc_dec_run,
+               .reset = imx8m_vpu_g2_reset,
+               .init = hantro_hevc_dec_init,
+               .exit = hantro_hevc_dec_exit,
+       },
+};
+
 /*
  * VPU variants.
  */
 
 static const struct hantro_irq imx8mq_irqs[] = {
        { "g1", imx8m_vpu_g1_irq },
-       { "g2", NULL /* TODO: imx8m_vpu_g2_irq */ },
+};
+
+static const struct hantro_irq imx8mq_g2_irqs[] = {
+       { "g2", imx8m_vpu_g2_irq },
 };
 
 static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" };
@@ -218,3 +275,17 @@ const struct hantro_variant imx8mq_vpu_variant = {
        .reg_names = imx8mq_reg_names,
        .num_regs = ARRAY_SIZE(imx8mq_reg_names)
 };
+
+const struct hantro_variant imx8mq_vpu_g2_variant = {
+       .dec_offset = 0x0,
+       .dec_fmts = imx8m_vpu_g2_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts),
+       .codec = HANTRO_HEVC_DECODER,
+       .codec_ops = imx8mq_vpu_g2_codec_ops,
+       .init = imx8mq_vpu_hw_init,
+       .runtime_resume = imx8mq_runtime_resume,
+       .irqs = imx8mq_g2_irqs,
+       .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
+       .clk_names = imx8mq_clk_names,
+       .num_clocks = ARRAY_SIZE(imx8mq_clk_names),
+};
diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c
deleted file mode 100644 (file)
index 7b299ee..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Hantro VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- *     Jeffy Chen <jeffy.chen@rock-chips.com>
- */
-
-#include <linux/clk.h>
-
-#include "hantro.h"
-#include "hantro_jpeg.h"
-#include "hantro_g1_regs.h"
-#include "hantro_h1_regs.h"
-
-#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
-
-/*
- * Supported formats.
- */
-
-static const struct hantro_fmt rk3288_vpu_enc_fmts[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_YUV420M,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_NV12M,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_YUYV,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_UYVY,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_JPEG,
-               .codec_mode = HANTRO_MODE_JPEG_ENC,
-               .max_depth = 2,
-               .header_size = JPEG_HEADER_SIZE,
-               .frmsize = {
-                       .min_width = 96,
-                       .max_width = 8192,
-                       .step_width = MB_DIM,
-                       .min_height = 32,
-                       .max_height = 8192,
-                       .step_height = MB_DIM,
-               },
-       },
-};
-
-static const struct hantro_fmt rk3288_vpu_postproc_fmts[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_YUYV,
-               .codec_mode = HANTRO_MODE_NONE,
-       },
-};
-
-static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_NV12,
-               .codec_mode = HANTRO_MODE_NONE,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_H264_SLICE,
-               .codec_mode = HANTRO_MODE_H264_DEC,
-               .max_depth = 2,
-               .frmsize = {
-                       .min_width = 48,
-                       .max_width = 4096,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2304,
-                       .step_height = MB_DIM,
-               },
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
-               .codec_mode = HANTRO_MODE_MPEG2_DEC,
-               .max_depth = 2,
-               .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
-                       .step_height = MB_DIM,
-               },
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
-               .codec_mode = HANTRO_MODE_VP8_DEC,
-               .max_depth = 2,
-               .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
-                       .step_height = MB_DIM,
-               },
-       },
-};
-
-static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id)
-{
-       struct hantro_dev *vpu = dev_id;
-       enum vb2_buffer_state state;
-       u32 status;
-
-       status = vepu_read(vpu, H1_REG_INTERRUPT);
-       state = (status & H1_REG_INTERRUPT_FRAME_RDY) ?
-               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
-       vepu_write(vpu, 0, H1_REG_INTERRUPT);
-       vepu_write(vpu, 0, H1_REG_AXI_CTRL);
-
-       hantro_irq_done(vpu, state);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id)
-{
-       struct hantro_dev *vpu = dev_id;
-       enum vb2_buffer_state state;
-       u32 status;
-
-       status = vdpu_read(vpu, G1_REG_INTERRUPT);
-       state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
-               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
-       vdpu_write(vpu, 0, G1_REG_INTERRUPT);
-       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
-
-       hantro_irq_done(vpu, state);
-
-       return IRQ_HANDLED;
-}
-
-static int rk3288_vpu_hw_init(struct hantro_dev *vpu)
-{
-       /* Bump ACLK to max. possible freq. to improve performance. */
-       clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
-       return 0;
-}
-
-static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx)
-{
-       struct hantro_dev *vpu = ctx->dev;
-
-       vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT);
-       vepu_write(vpu, 0, H1_REG_ENC_CTRL);
-       vepu_write(vpu, 0, H1_REG_AXI_CTRL);
-}
-
-static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx)
-{
-       struct hantro_dev *vpu = ctx->dev;
-
-       vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT);
-       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
-       vdpu_write(vpu, 1, G1_REG_SOFT_RESET);
-}
-
-/*
- * Supported codec ops.
- */
-
-static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
-       [HANTRO_MODE_JPEG_ENC] = {
-               .run = hantro_h1_jpeg_enc_run,
-               .reset = rk3288_vpu_enc_reset,
-               .init = hantro_jpeg_enc_init,
-               .done = hantro_jpeg_enc_done,
-               .exit = hantro_jpeg_enc_exit,
-       },
-       [HANTRO_MODE_H264_DEC] = {
-               .run = hantro_g1_h264_dec_run,
-               .reset = rk3288_vpu_dec_reset,
-               .init = hantro_h264_dec_init,
-               .exit = hantro_h264_dec_exit,
-       },
-       [HANTRO_MODE_MPEG2_DEC] = {
-               .run = hantro_g1_mpeg2_dec_run,
-               .reset = rk3288_vpu_dec_reset,
-               .init = hantro_mpeg2_dec_init,
-               .exit = hantro_mpeg2_dec_exit,
-       },
-       [HANTRO_MODE_VP8_DEC] = {
-               .run = hantro_g1_vp8_dec_run,
-               .reset = rk3288_vpu_dec_reset,
-               .init = hantro_vp8_dec_init,
-               .exit = hantro_vp8_dec_exit,
-       },
-};
-
-/*
- * VPU variant.
- */
-
-static const struct hantro_irq rk3288_irqs[] = {
-       { "vepu", rk3288_vepu_irq },
-       { "vdpu", rk3288_vdpu_irq },
-};
-
-static const char * const rk3288_clk_names[] = {
-       "aclk", "hclk"
-};
-
-const struct hantro_variant rk3288_vpu_variant = {
-       .enc_offset = 0x0,
-       .enc_fmts = rk3288_vpu_enc_fmts,
-       .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts),
-       .dec_offset = 0x400,
-       .dec_fmts = rk3288_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
-       .postproc_fmts = rk3288_vpu_postproc_fmts,
-       .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts),
-       .postproc_regs = &hantro_g1_postproc_regs,
-       .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
-                HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
-       .codec_ops = rk3288_vpu_codec_ops,
-       .irqs = rk3288_irqs,
-       .num_irqs = ARRAY_SIZE(rk3288_irqs),
-       .init = rk3288_vpu_hw_init,
-       .clk_names = rk3288_clk_names,
-       .num_clocks = ARRAY_SIZE(rk3288_clk_names)
-};
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c
deleted file mode 100644 (file)
index 7a7962c..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Hantro VPU codec driver
- *
- * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
- *     Jeffy Chen <jeffy.chen@rock-chips.com>
- */
-
-#include <linux/clk.h>
-
-#include "hantro.h"
-#include "hantro_jpeg.h"
-#include "rk3399_vpu_regs.h"
-
-#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000)
-
-/*
- * Supported formats.
- */
-
-static const struct hantro_fmt rk3399_vpu_enc_fmts[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_YUV420M,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_NV12M,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_YUYV,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_UYVY,
-               .codec_mode = HANTRO_MODE_NONE,
-               .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_JPEG,
-               .codec_mode = HANTRO_MODE_JPEG_ENC,
-               .max_depth = 2,
-               .header_size = JPEG_HEADER_SIZE,
-               .frmsize = {
-                       .min_width = 96,
-                       .max_width = 8192,
-                       .step_width = MB_DIM,
-                       .min_height = 32,
-                       .max_height = 8192,
-                       .step_height = MB_DIM,
-               },
-       },
-};
-
-static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_NV12,
-               .codec_mode = HANTRO_MODE_NONE,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
-               .codec_mode = HANTRO_MODE_MPEG2_DEC,
-               .max_depth = 2,
-               .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
-                       .step_height = MB_DIM,
-               },
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
-               .codec_mode = HANTRO_MODE_VP8_DEC,
-               .max_depth = 2,
-               .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
-                       .step_height = MB_DIM,
-               },
-       },
-};
-
-static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id)
-{
-       struct hantro_dev *vpu = dev_id;
-       enum vb2_buffer_state state;
-       u32 status;
-
-       status = vepu_read(vpu, VEPU_REG_INTERRUPT);
-       state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ?
-               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
-       vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
-       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-
-       hantro_irq_done(vpu, state);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id)
-{
-       struct hantro_dev *vpu = dev_id;
-       enum vb2_buffer_state state;
-       u32 status;
-
-       status = vdpu_read(vpu, VDPU_REG_INTERRUPT);
-       state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ?
-               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
-
-       vdpu_write(vpu, 0, VDPU_REG_INTERRUPT);
-       vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL);
-
-       hantro_irq_done(vpu, state);
-
-       return IRQ_HANDLED;
-}
-
-static int rk3399_vpu_hw_init(struct hantro_dev *vpu)
-{
-       /* Bump ACLK to max. possible freq. to improve performance. */
-       clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ);
-       return 0;
-}
-
-static void rk3399_vpu_enc_reset(struct hantro_ctx *ctx)
-{
-       struct hantro_dev *vpu = ctx->dev;
-
-       vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
-       vepu_write(vpu, 0, VEPU_REG_ENCODE_START);
-       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
-}
-
-static void rk3399_vpu_dec_reset(struct hantro_ctx *ctx)
-{
-       struct hantro_dev *vpu = ctx->dev;
-
-       vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT);
-       vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS);
-       vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET);
-}
-
-/*
- * Supported codec ops.
- */
-
-static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
-       [HANTRO_MODE_JPEG_ENC] = {
-               .run = rk3399_vpu_jpeg_enc_run,
-               .reset = rk3399_vpu_enc_reset,
-               .init = hantro_jpeg_enc_init,
-               .exit = hantro_jpeg_enc_exit,
-       },
-       [HANTRO_MODE_MPEG2_DEC] = {
-               .run = rk3399_vpu_mpeg2_dec_run,
-               .reset = rk3399_vpu_dec_reset,
-               .init = hantro_mpeg2_dec_init,
-               .exit = hantro_mpeg2_dec_exit,
-       },
-       [HANTRO_MODE_VP8_DEC] = {
-               .run = rk3399_vpu_vp8_dec_run,
-               .reset = rk3399_vpu_dec_reset,
-               .init = hantro_vp8_dec_init,
-               .exit = hantro_vp8_dec_exit,
-       },
-};
-
-/*
- * VPU variant.
- */
-
-static const struct hantro_irq rk3399_irqs[] = {
-       { "vepu", rk3399_vepu_irq },
-       { "vdpu", rk3399_vdpu_irq },
-};
-
-static const char * const rk3399_clk_names[] = {
-       "aclk", "hclk"
-};
-
-const struct hantro_variant rk3399_vpu_variant = {
-       .enc_offset = 0x0,
-       .enc_fmts = rk3399_vpu_enc_fmts,
-       .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts),
-       .dec_offset = 0x400,
-       .dec_fmts = rk3399_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
-       .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
-                HANTRO_VP8_DECODER,
-       .codec_ops = rk3399_vpu_codec_ops,
-       .irqs = rk3399_irqs,
-       .num_irqs = ARRAY_SIZE(rk3399_irqs),
-       .init = rk3399_vpu_hw_init,
-       .clk_names = rk3399_clk_names,
-       .num_clocks = ARRAY_SIZE(rk3399_clk_names)
-};
-
-static const struct hantro_irq rk3328_irqs[] = {
-       { "vdpu", rk3399_vdpu_irq },
-};
-
-const struct hantro_variant rk3328_vpu_variant = {
-       .dec_offset = 0x400,
-       .dec_fmts = rk3399_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
-       .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER,
-       .codec_ops = rk3399_vpu_codec_ops,
-       .irqs = rk3328_irqs,
-       .num_irqs = ARRAY_SIZE(rk3328_irqs),
-       .init = rk3399_vpu_hw_init,
-       .clk_names = rk3399_clk_names,
-       .num_clocks = ARRAY_SIZE(rk3399_clk_names),
-};
 #include "hantro.h"
 #include "hantro_v4l2.h"
 #include "hantro_hw.h"
-#include "rk3399_vpu_regs.h"
+#include "rockchip_vpu2_regs.h"
 
 #define VEPU_JPEG_QUANT_TABLE_COUNT 16
 
-static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu,
-                                       struct hantro_ctx *ctx)
+static void rockchip_vpu2_set_src_img_ctrl(struct hantro_dev *vpu,
+                                          struct hantro_ctx *ctx)
 {
        struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
        u32 reg;
@@ -59,9 +59,9 @@ static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu,
        vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1);
 }
 
-static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu,
-                                           struct hantro_ctx *ctx,
-                                           struct vb2_buffer *src_buf)
+static void rockchip_vpu2_jpeg_enc_set_buffers(struct hantro_dev *vpu,
+                                              struct hantro_ctx *ctx,
+                                              struct vb2_buffer *src_buf)
 {
        struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
        dma_addr_t src[3];
@@ -92,9 +92,9 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu,
 }
 
 static void
-rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
-                              unsigned char *luma_qtable,
-                              unsigned char *chroma_qtable)
+rockchip_vpu2_jpeg_enc_set_qtable(struct hantro_dev *vpu,
+                                 unsigned char *luma_qtable,
+                                 unsigned char *chroma_qtable)
 {
        u32 reg, i;
        __be32 *luma_qtable_p;
@@ -118,7 +118,7 @@ rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
        }
 }
 
-void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
@@ -141,11 +141,11 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
        vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG,
                           VEPU_REG_ENCODE_START);
 
-       rk3399_vpu_set_src_img_ctrl(vpu, ctx);
-       rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
-       rk3399_vpu_jpeg_enc_set_qtable(vpu,
-                                      hantro_jpeg_get_qtable(0),
-                                      hantro_jpeg_get_qtable(1));
+       rockchip_vpu2_set_src_img_ctrl(vpu, ctx);
+       rockchip_vpu2_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
+       rockchip_vpu2_jpeg_enc_set_qtable(vpu,
+                                         hantro_jpeg_get_qtable(0),
+                                         hantro_jpeg_get_qtable(1));
 
        reg = VEPU_REG_OUTPUT_SWAP32
                | VEPU_REG_OUTPUT_SWAP16
@@ -168,4 +168,6 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
        /* Kick the watchdog and start encoding */
        hantro_end_prepare_run(ctx);
        vepu_write(vpu, reg, VEPU_REG_ENCODE_START);
+
+       return 0;
 }
 #define VDPU_REG_MV_ACCURACY_FWD(v)    ((v) ? BIT(2) : 0)
 #define VDPU_REG_MV_ACCURACY_BWD(v)    ((v) ? BIT(1) : 0)
 
-#define PICT_TOP_FIELD     1
-#define PICT_BOTTOM_FIELD  2
-#define PICT_FRAME         3
-
 static void
-rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu,
-                                     struct hantro_ctx *ctx)
+rockchip_vpu2_mpeg2_dec_set_quantisation(struct hantro_dev *vpu,
+                                        struct hantro_ctx *ctx)
 {
-       struct v4l2_ctrl_mpeg2_quantization *quantization;
+       struct v4l2_ctrl_mpeg2_quantisation *q;
 
-       quantization = hantro_get_ctrl(ctx,
-                                      V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
-       hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization);
-       vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma,
-                          VDPU_REG_QTABLE_BASE);
+       q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION);
+       hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q);
+       vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, VDPU_REG_QTABLE_BASE);
 }
 
 static void
-rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
-                                struct hantro_ctx *ctx,
-                                struct vb2_buffer *src_buf,
-                                struct vb2_buffer *dst_buf,
-                                const struct v4l2_mpeg2_sequence *sequence,
-                                const struct v4l2_mpeg2_picture *picture,
-                                const struct v4l2_ctrl_mpeg2_slice_params *slice_params)
+rockchip_vpu2_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
+                                   struct hantro_ctx *ctx,
+                                   struct vb2_buffer *src_buf,
+                                   struct vb2_buffer *dst_buf,
+                                   const struct v4l2_ctrl_mpeg2_sequence *seq,
+                                   const struct v4l2_ctrl_mpeg2_picture *pic)
 {
        dma_addr_t forward_addr = 0, backward_addr = 0;
        dma_addr_t current_addr, addr;
 
-       switch (picture->picture_coding_type) {
-       case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
-               backward_addr = hantro_get_ref(ctx,
-                                              slice_params->backward_ref_ts);
+       switch (pic->picture_coding_type) {
+       case V4L2_MPEG2_PIC_CODING_TYPE_B:
+               backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts);
                fallthrough;
-       case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
-               forward_addr = hantro_get_ref(ctx,
-                                             slice_params->forward_ref_ts);
+       case V4L2_MPEG2_PIC_CODING_TYPE_P:
+               forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts);
        }
 
        /* Source bitstream buffer */
@@ -126,7 +117,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
        addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
        current_addr = addr;
 
-       if (picture->picture_structure == PICT_BOTTOM_FIELD)
+       if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD)
                addr += ALIGN(ctx->dst_fmt.width, 16);
        vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE);
 
@@ -136,18 +127,18 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
                backward_addr = current_addr;
 
        /* Set forward ref frame (top/bottom field) */
-       if (picture->picture_structure == PICT_FRAME ||
-           picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B ||
-           (picture->picture_structure == PICT_TOP_FIELD &&
-            picture->top_field_first) ||
-           (picture->picture_structure == PICT_BOTTOM_FIELD &&
-            !picture->top_field_first)) {
+       if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME ||
+           pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B ||
+           (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD &&
+            pic->flags & V4L2_MPEG2_PIC_TOP_FIELD) ||
+           (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD &&
+            !(pic->flags & V4L2_MPEG2_PIC_TOP_FIELD))) {
                vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE);
-       } else if (picture->picture_structure == PICT_TOP_FIELD) {
+       } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) {
                vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE);
-       } else if (picture->picture_structure == PICT_BOTTOM_FIELD) {
+       } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) {
                vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE);
                vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE);
        }
@@ -157,13 +148,12 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
        vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE);
 }
 
-void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
        struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
-       const struct v4l2_mpeg2_sequence *sequence;
-       const struct v4l2_mpeg2_picture *picture;
+       const struct v4l2_ctrl_mpeg2_sequence *seq;
+       const struct v4l2_ctrl_mpeg2_picture *pic;
        u32 reg;
 
        src_buf = hantro_get_src_buf(ctx);
@@ -171,10 +161,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
 
        hantro_start_prepare_run(ctx);
 
-       slice_params = hantro_get_ctrl(ctx,
-                                      V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
-       sequence = &slice_params->sequence;
-       picture = &slice_params->picture;
+       seq = hantro_get_ctrl(ctx,
+                             V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+       pic = hantro_get_ctrl(ctx,
+                             V4L2_CID_STATELESS_MPEG2_PICTURE);
 
        reg = VDPU_REG_DEC_ADV_PRE_DIS(0) |
              VDPU_REG_DEC_SCMD_DIS(0) |
@@ -183,7 +173,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50));
 
        reg = VDPU_REG_INIT_QP(1) |
-             VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3);
+             VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0));
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51));
 
        reg = VDPU_REG_APF_THRESHOLD(8) |
@@ -209,11 +199,11 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56));
 
        reg = VDPU_REG_RLC_MODE_E(0) |
-             VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) |
-             VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) |
-             VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) |
-             VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) |
-             VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) |
+             VDPU_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) |
+             VDPU_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) |
+             VDPU_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) |
+             VDPU_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) |
+             VDPU_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) |
              VDPU_REG_FWD_INTERLACE_E(0) |
              VDPU_REG_WRITE_MVS_E(0) |
              VDPU_REG_DEC_TIMEOUT_E(1) |
@@ -222,36 +212,37 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
 
        reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) |
              VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) |
-             VDPU_REG_ALT_SCAN_E(picture->alternate_scan) |
-             VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first);
+             VDPU_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+             VDPU_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120));
 
-       reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) |
-             VDPU_REG_QSCALE_TYPE(picture->q_scale_type) |
-             VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) |
-             VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) |
-             VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) |
-             VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct);
+       reg = VDPU_REG_STRM_START_BIT(0) |
+             VDPU_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) |
+             VDPU_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) |
+             VDPU_REG_INTRA_DC_PREC(pic->intra_dc_precision) |
+             VDPU_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) |
+             VDPU_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122));
 
-       reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) |
-             VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) |
-             VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) |
-             VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) |
-             VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) |
+       reg = VDPU_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+             VDPU_REG_FCODE_FWD_HOR(pic->f_code[0][0]) |
+             VDPU_REG_FCODE_FWD_VER(pic->f_code[0][1]) |
+             VDPU_REG_FCODE_BWD_HOR(pic->f_code[1][0]) |
+             VDPU_REG_FCODE_BWD_VER(pic->f_code[1][1]) |
              VDPU_REG_MV_ACCURACY_FWD(1) |
              VDPU_REG_MV_ACCURACY_BWD(1);
        vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136));
 
-       rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx);
+       rockchip_vpu2_mpeg2_dec_set_quantisation(vpu, ctx);
 
-       rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
-                                        &dst_buf->vb2_buf,
-                                        sequence, picture, slice_params);
+       rockchip_vpu2_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
+                                           &dst_buf->vb2_buf, seq, pic);
 
        /* Kick the watchdog and start decoding */
        hantro_end_prepare_run(ctx);
 
        reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1);
        vdpu_write(vpu, reg, VDPU_SWREG(57));
+
+       return 0;
 }
@@ -503,7 +503,7 @@ static void cfg_buffers(struct hantro_ctx *ctx,
        vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST);
 }
 
-void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx)
 {
        const struct v4l2_ctrl_vp8_frame *hdr;
        struct hantro_dev *vpu = ctx->dev;
@@ -516,7 +516,7 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
 
        hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME);
        if (WARN_ON(!hdr))
-               return;
+               return -EINVAL;
 
        /* Reset segment_map buffer in keyframe */
        if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
@@ -589,4 +589,6 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
        hantro_end_prepare_run(ctx);
 
        hantro_reg_write(vpu, &vp8_dec_start_dec, 1);
+
+       return 0;
 }
@@ -6,8 +6,8 @@
  *     Alpha Lin <alpha.lin@rock-chips.com>
  */
 
-#ifndef RK3399_VPU_REGS_H_
-#define RK3399_VPU_REGS_H_
+#ifndef ROCKCHIP_VPU2_REGS_H_
+#define ROCKCHIP_VPU2_REGS_H_
 
 /* Encoder registers. */
 #define VEPU_REG_VP8_QUT_1ST(i)                        (0x000 + ((i) * 0x24))
 #define     VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x)       (((x) & 0x3ff) << 12)
 #define     VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x)       (((x) & 0x3ff) << 2)
 
-#endif /* RK3399_VPU_REGS_H_ */
+#endif /* ROCKCHIP_VPU2_REGS_H_ */
diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c
new file mode 100644 (file)
index 0000000..3ccc164
--- /dev/null
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *     Jeffy Chen <jeffy.chen@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+
+#include "hantro.h"
+#include "hantro_jpeg.h"
+#include "hantro_g1_regs.h"
+#include "hantro_h1_regs.h"
+#include "rockchip_vpu2_regs.h"
+
+#define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000)
+#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt rockchip_vpu_enc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUV420M,
+               .codec_mode = HANTRO_MODE_NONE,
+               .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420P,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = HANTRO_MODE_NONE,
+               .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420SP,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = HANTRO_MODE_NONE,
+               .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUYV422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .codec_mode = HANTRO_MODE_NONE,
+               .enc_fmt = ROCKCHIP_VPU_ENC_FMT_UYVY422,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .codec_mode = HANTRO_MODE_JPEG_ENC,
+               .max_depth = 2,
+               .header_size = JPEG_HEADER_SIZE,
+               .frmsize = {
+                       .min_width = 96,
+                       .max_width = 8192,
+                       .step_width = MB_DIM,
+                       .min_height = 32,
+                       .max_height = 8192,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static const struct hantro_fmt rockchip_vpu1_postproc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+};
+
+static const struct hantro_fmt rk3066_vpu_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .codec_mode = HANTRO_MODE_H264_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .codec_mode = HANTRO_MODE_H264_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 4096,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 2304,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 3840,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 2160,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 3840,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 2160,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static irqreturn_t rockchip_vpu1_vepu_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vepu_read(vpu, H1_REG_INTERRUPT);
+       state = (status & H1_REG_INTERRUPT_FRAME_RDY) ?
+               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vepu_write(vpu, 0, H1_REG_INTERRUPT);
+       vepu_write(vpu, 0, H1_REG_AXI_CTRL);
+
+       hantro_irq_done(vpu, state);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_vpu2_vdpu_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vdpu_read(vpu, VDPU_REG_INTERRUPT);
+       state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ?
+               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vdpu_write(vpu, 0, VDPU_REG_INTERRUPT);
+       vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL);
+
+       hantro_irq_done(vpu, state);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_vpu2_vepu_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vepu_read(vpu, VEPU_REG_INTERRUPT);
+       state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ?
+               VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vepu_write(vpu, 0, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+
+       hantro_irq_done(vpu, state);
+
+       return IRQ_HANDLED;
+}
+
+static int rk3036_vpu_hw_init(struct hantro_dev *vpu)
+{
+       /* Bump ACLK to max. possible freq. to improve performance. */
+       clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ);
+       return 0;
+}
+
+static int rk3066_vpu_hw_init(struct hantro_dev *vpu)
+{
+       /* Bump ACLKs to max. possible freq. to improve performance. */
+       clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ);
+       clk_set_rate(vpu->clocks[2].clk, RK3066_ACLK_MAX_FREQ);
+       return 0;
+}
+
+static int rockchip_vpu_hw_init(struct hantro_dev *vpu)
+{
+       /* Bump ACLK to max. possible freq. to improve performance. */
+       clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ);
+       return 0;
+}
+
+static void rk3066_vpu_dec_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT);
+       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+}
+
+static void rockchip_vpu1_enc_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT);
+       vepu_write(vpu, 0, H1_REG_ENC_CTRL);
+       vepu_write(vpu, 0, H1_REG_AXI_CTRL);
+}
+
+static void rockchip_vpu2_dec_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT);
+       vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS);
+       vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET);
+}
+
+static void rockchip_vpu2_enc_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT);
+       vepu_write(vpu, 0, VEPU_REG_ENCODE_START);
+       vepu_write(vpu, 0, VEPU_REG_AXI_CTRL);
+}
+
+/*
+ * Supported codec ops.
+ */
+static const struct hantro_codec_ops rk3036_vpu_codec_ops[] = {
+       [HANTRO_MODE_H264_DEC] = {
+               .run = hantro_g1_h264_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_h264_dec_init,
+               .exit = hantro_h264_dec_exit,
+       },
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = hantro_g1_mpeg2_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = hantro_g1_vp8_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+};
+
+static const struct hantro_codec_ops rk3066_vpu_codec_ops[] = {
+       [HANTRO_MODE_JPEG_ENC] = {
+               .run = hantro_h1_jpeg_enc_run,
+               .reset = rockchip_vpu1_enc_reset,
+               .init = hantro_jpeg_enc_init,
+               .done = hantro_jpeg_enc_done,
+               .exit = hantro_jpeg_enc_exit,
+       },
+       [HANTRO_MODE_H264_DEC] = {
+               .run = hantro_g1_h264_dec_run,
+               .reset = rk3066_vpu_dec_reset,
+               .init = hantro_h264_dec_init,
+               .exit = hantro_h264_dec_exit,
+       },
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = hantro_g1_mpeg2_dec_run,
+               .reset = rk3066_vpu_dec_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = hantro_g1_vp8_dec_run,
+               .reset = rk3066_vpu_dec_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+};
+
+static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
+       [HANTRO_MODE_JPEG_ENC] = {
+               .run = hantro_h1_jpeg_enc_run,
+               .reset = rockchip_vpu1_enc_reset,
+               .init = hantro_jpeg_enc_init,
+               .done = hantro_jpeg_enc_done,
+               .exit = hantro_jpeg_enc_exit,
+       },
+       [HANTRO_MODE_H264_DEC] = {
+               .run = hantro_g1_h264_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_h264_dec_init,
+               .exit = hantro_h264_dec_exit,
+       },
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = hantro_g1_mpeg2_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = hantro_g1_vp8_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+};
+
+static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
+       [HANTRO_MODE_JPEG_ENC] = {
+               .run = rockchip_vpu2_jpeg_enc_run,
+               .reset = rockchip_vpu2_enc_reset,
+               .init = hantro_jpeg_enc_init,
+               .exit = hantro_jpeg_enc_exit,
+       },
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = rockchip_vpu2_mpeg2_dec_run,
+               .reset = rockchip_vpu2_dec_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = rockchip_vpu2_vp8_dec_run,
+               .reset = rockchip_vpu2_dec_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+};
+
+/*
+ * VPU variant.
+ */
+
+static const struct hantro_irq rockchip_vdpu1_irqs[] = {
+       { "vdpu", hantro_g1_irq },
+};
+
+static const struct hantro_irq rockchip_vpu1_irqs[] = {
+       { "vepu", rockchip_vpu1_vepu_irq },
+       { "vdpu", hantro_g1_irq },
+};
+
+static const struct hantro_irq rockchip_vdpu2_irqs[] = {
+       { "vdpu", rockchip_vpu2_vdpu_irq },
+};
+
+static const struct hantro_irq rockchip_vpu2_irqs[] = {
+       { "vepu", rockchip_vpu2_vepu_irq },
+       { "vdpu", rockchip_vpu2_vdpu_irq },
+};
+
+static const char * const rk3066_vpu_clk_names[] = {
+       "aclk_vdpu", "hclk_vdpu",
+       "aclk_vepu", "hclk_vepu"
+};
+
+static const char * const rockchip_vpu_clk_names[] = {
+       "aclk", "hclk"
+};
+
+const struct hantro_variant rk3036_vpu_variant = {
+       .dec_offset = 0x400,
+       .dec_fmts = rk3066_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts),
+       .postproc_fmts = rockchip_vpu1_postproc_fmts,
+       .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+       .postproc_regs = &hantro_g1_postproc_regs,
+       .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
+                HANTRO_H264_DECODER,
+       .codec_ops = rk3036_vpu_codec_ops,
+       .irqs = rockchip_vdpu1_irqs,
+       .num_irqs = ARRAY_SIZE(rockchip_vdpu1_irqs),
+       .init = rk3036_vpu_hw_init,
+       .clk_names = rockchip_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
+
+/*
+ * Despite this variant has separate clocks for decoder and encoder,
+ * it's still required to enable all four of them for either decoding
+ * or encoding and we can't split it in separate g1/h1 variants.
+ */
+const struct hantro_variant rk3066_vpu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rockchip_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+       .dec_offset = 0x400,
+       .dec_fmts = rk3066_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts),
+       .postproc_fmts = rockchip_vpu1_postproc_fmts,
+       .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+       .postproc_regs = &hantro_g1_postproc_regs,
+       .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+                HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
+       .codec_ops = rk3066_vpu_codec_ops,
+       .irqs = rockchip_vpu1_irqs,
+       .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
+       .init = rk3066_vpu_hw_init,
+       .clk_names = rk3066_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rk3066_vpu_clk_names)
+};
+
+const struct hantro_variant rk3288_vpu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rockchip_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+       .dec_offset = 0x400,
+       .dec_fmts = rk3288_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
+       .postproc_fmts = rockchip_vpu1_postproc_fmts,
+       .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+       .postproc_regs = &hantro_g1_postproc_regs,
+       .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+                HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
+       .codec_ops = rk3288_vpu_codec_ops,
+       .irqs = rockchip_vpu1_irqs,
+       .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
+       .init = rockchip_vpu_hw_init,
+       .clk_names = rockchip_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
+
+const struct hantro_variant rk3328_vpu_variant = {
+       .dec_offset = 0x400,
+       .dec_fmts = rk3399_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+       .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER,
+       .codec_ops = rk3399_vpu_codec_ops,
+       .irqs = rockchip_vdpu2_irqs,
+       .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs),
+       .init = rockchip_vpu_hw_init,
+       .clk_names = rockchip_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names),
+};
+
+const struct hantro_variant rk3399_vpu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rockchip_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+       .dec_offset = 0x400,
+       .dec_fmts = rk3399_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+       .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+                HANTRO_VP8_DECODER,
+       .codec_ops = rk3399_vpu_codec_ops,
+       .irqs = rockchip_vpu2_irqs,
+       .num_irqs = ARRAY_SIZE(rockchip_vpu2_irqs),
+       .init = rockchip_vpu_hw_init,
+       .clk_names = rockchip_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c
new file mode 100644 (file)
index 0000000..58ae72c
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VDEC driver
+ *
+ * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com>
+ */
+
+#include "hantro.h"
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt sama5d4_vdec_postproc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+};
+
+static const struct hantro_fmt sama5d4_vdec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1280,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 720,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1280,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 720,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .codec_mode = HANTRO_MODE_H264_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1280,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 720,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static int sama5d4_hw_init(struct hantro_dev *vpu)
+{
+       return 0;
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct hantro_codec_ops sama5d4_vdec_codec_ops[] = {
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = hantro_g1_mpeg2_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = hantro_g1_vp8_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+       [HANTRO_MODE_H264_DEC] = {
+               .run = hantro_g1_h264_dec_run,
+               .reset = hantro_g1_reset,
+               .init = hantro_h264_dec_init,
+               .exit = hantro_h264_dec_exit,
+       },
+};
+
+static const struct hantro_irq sama5d4_irqs[] = {
+       { "vdec", hantro_g1_irq },
+};
+
+static const char * const sama5d4_clk_names[] = { "vdec_clk" };
+
+const struct hantro_variant sama5d4_vdec_variant = {
+       .dec_fmts = sama5d4_vdec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(sama5d4_vdec_fmts),
+       .postproc_fmts = sama5d4_vdec_postproc_fmts,
+       .num_postproc_fmts = ARRAY_SIZE(sama5d4_vdec_postproc_fmts),
+       .postproc_regs = &hantro_g1_postproc_regs,
+       .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
+                HANTRO_H264_DECODER,
+       .codec_ops = sama5d4_vdec_codec_ops,
+       .init = sama5d4_hw_init,
+       .irqs = sama5d4_irqs,
+       .num_irqs = ARRAY_SIZE(sama5d4_irqs),
+       .clk_names = sama5d4_clk_names,
+       .num_clocks = ARRAY_SIZE(sama5d4_clk_names),
+};
index f21ed88..ac5fb33 100644 (file)
@@ -79,13 +79,13 @@ static void prp_stop(struct prp_priv *priv)
 }
 
 static struct v4l2_mbus_framefmt *
-__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
              unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        struct imx_ic_priv *ic_priv = priv->ic_priv;
 
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
        else
                return &priv->format_mbus;
 }
@@ -95,7 +95,7 @@ __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
  */
 
 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -115,7 +115,8 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd,
                        ret = -EINVAL;
                        goto out;
                }
-               infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, code->which);
+               infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD,
+                                     code->which);
                code->code = infmt->code;
                break;
        default:
@@ -127,7 +128,7 @@ out:
 }
 
 static int prp_get_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -139,7 +140,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out;
@@ -152,7 +153,7 @@ out:
 }
 
 static int prp_set_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -171,7 +172,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
                goto out;
        }
 
-       infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which);
+       infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, sdformat->which);
 
        switch (sdformat->pad) {
        case PRP_SINK_PAD:
@@ -201,7 +202,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
 
        imx_media_try_colorimetry(&sdformat->format, true);
 
-       fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        *fmt = sdformat->format;
 out:
        mutex_unlock(&priv->lock);
index d990553..9b81cfb 100644 (file)
@@ -787,13 +787,13 @@ static void prp_stop(struct prp_priv *priv)
 }
 
 static struct v4l2_mbus_framefmt *
-__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
              unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        struct imx_ic_priv *ic_priv = priv->ic_priv;
 
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
        else
                return &priv->format_mbus[pad];
 }
@@ -841,7 +841,7 @@ static bool prp_bound_align_output(struct v4l2_mbus_framefmt *outfmt,
  */
 
 static int prp_enum_mbus_code(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad >= PRPENCVF_NUM_PADS)
@@ -852,7 +852,7 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int prp_get_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -864,7 +864,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out;
@@ -877,7 +877,7 @@ out:
 }
 
 static void prp_try_fmt(struct prp_priv *priv,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat,
                        const struct imx_media_pixfmt **cc)
 {
@@ -894,7 +894,8 @@ static void prp_try_fmt(struct prp_priv *priv,
                sdformat->format.code = (*cc)->codes[0];
        }
 
-       infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which);
+       infmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SINK_PAD,
+                             sdformat->which);
 
        if (sdformat->pad == PRPENCVF_SRC_PAD) {
                sdformat->format.field = infmt->field;
@@ -920,7 +921,7 @@ static void prp_try_fmt(struct prp_priv *priv,
 }
 
 static int prp_set_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -938,9 +939,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
                goto out;
        }
 
-       prp_try_fmt(priv, cfg, sdformat, &cc);
+       prp_try_fmt(priv, sd_state, sdformat, &cc);
 
-       fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        *fmt = sdformat->format;
 
        /* propagate a default format to source pad */
@@ -952,9 +953,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
                format.pad = PRPENCVF_SRC_PAD;
                format.which = sdformat->which;
                format.format = sdformat->format;
-               prp_try_fmt(priv, cfg, &format, &outcc);
+               prp_try_fmt(priv, sd_state, &format, &outcc);
 
-               outfmt = __prp_get_fmt(priv, cfg, PRPENCVF_SRC_PAD,
+               outfmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SRC_PAD,
                                       sdformat->which);
                *outfmt = format.format;
                if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -970,7 +971,7 @@ out:
 }
 
 static int prp_enum_frame_size(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct prp_priv *priv = sd_to_priv(sd);
@@ -988,7 +989,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd,
        format.format.code = fse->code;
        format.format.width = 1;
        format.format.height = 1;
-       prp_try_fmt(priv, cfg, &format, &cc);
+       prp_try_fmt(priv, sd_state, &format, &cc);
        fse->min_width = format.format.width;
        fse->min_height = format.format.height;
 
@@ -1000,7 +1001,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd,
        format.format.code = fse->code;
        format.format.width = -1;
        format.format.height = -1;
-       prp_try_fmt(priv, cfg, &format, &cc);
+       prp_try_fmt(priv, sd_state, &format, &cc);
        fse->max_width = format.format.width;
        fse->max_height = format.format.height;
 out:
index e3bfd63..bb1305c 100644 (file)
@@ -750,9 +750,10 @@ static int csi_setup(struct csi_priv *priv)
 
 static int csi_start(struct csi_priv *priv)
 {
-       struct v4l2_fract *output_fi;
+       struct v4l2_fract *input_fi, *output_fi;
        int ret;
 
+       input_fi = &priv->frame_interval[CSI_SINK_PAD];
        output_fi = &priv->frame_interval[priv->active_output_pad];
 
        /* start upstream */
@@ -761,6 +762,17 @@ static int csi_start(struct csi_priv *priv)
        if (ret)
                return ret;
 
+       /* Skip first few frames from a BT.656 source */
+       if (priv->upstream_ep.bus_type == V4L2_MBUS_BT656) {
+               u32 delay_usec, bad_frames = 20;
+
+               delay_usec = DIV_ROUND_UP_ULL((u64)USEC_PER_SEC *
+                       input_fi->numerator * bad_frames,
+                       input_fi->denominator);
+
+               usleep_range(delay_usec, delay_usec + 1000);
+       }
+
        if (priv->dest == IPU_CSI_DEST_IDMAC) {
                ret = csi_idmac_start(priv);
                if (ret)
@@ -1139,31 +1151,32 @@ static int csi_link_validate(struct v4l2_subdev *sd,
 }
 
 static struct v4l2_mbus_framefmt *
-__csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
              unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
        else
                return &priv->format_mbus[pad];
 }
 
 static struct v4l2_rect *
-__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
               enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_crop(&priv->sd, cfg, CSI_SINK_PAD);
+               return v4l2_subdev_get_try_crop(&priv->sd, sd_state,
+                                               CSI_SINK_PAD);
        else
                return &priv->crop;
 }
 
 static struct v4l2_rect *
-__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
                  enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_compose(&priv->sd, cfg,
+               return v4l2_subdev_get_try_compose(&priv->sd, sd_state,
                                                   CSI_SINK_PAD);
        else
                return &priv->compose;
@@ -1171,7 +1184,7 @@ __csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
 
 static void csi_try_crop(struct csi_priv *priv,
                         struct v4l2_rect *crop,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_mbus_framefmt *infmt,
                         struct v4l2_fwnode_endpoint *upstream_ep)
 {
@@ -1210,7 +1223,7 @@ static void csi_try_crop(struct csi_priv *priv,
 }
 
 static int csi_enum_mbus_code(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_mbus_code_enum *code)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1221,7 +1234,7 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, code->which);
+       infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, code->which);
        incc = imx_media_find_mbus_format(infmt->code, PIXFMT_SEL_ANY);
 
        switch (code->pad) {
@@ -1263,7 +1276,7 @@ out:
 }
 
 static int csi_enum_frame_size(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1282,7 +1295,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd,
                fse->min_height = MIN_H;
                fse->max_height = MAX_H;
        } else {
-               crop = __csi_get_crop(priv, cfg, fse->which);
+               crop = __csi_get_crop(priv, sd_state, fse->which);
 
                fse->min_width = fse->index & 1 ?
                        crop->width / 2 : crop->width;
@@ -1297,7 +1310,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 static int csi_enum_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1313,7 +1326,7 @@ static int csi_enum_frame_interval(struct v4l2_subdev *sd,
        mutex_lock(&priv->lock);
 
        input_fi = &priv->frame_interval[CSI_SINK_PAD];
-       crop = __csi_get_crop(priv, cfg, fie->which);
+       crop = __csi_get_crop(priv, sd_state, fie->which);
 
        if ((fie->width != crop->width && fie->width != crop->width / 2) ||
            (fie->height != crop->height && fie->height != crop->height / 2)) {
@@ -1333,7 +1346,7 @@ out:
 }
 
 static int csi_get_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1345,7 +1358,7 @@ static int csi_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out;
@@ -1358,11 +1371,11 @@ out:
 }
 
 static void csi_try_field(struct csi_priv *priv,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *sdformat)
 {
        struct v4l2_mbus_framefmt *infmt =
-               __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which);
+               __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which);
 
        /*
         * no restrictions on sink pad field type except must
@@ -1408,7 +1421,7 @@ static void csi_try_field(struct csi_priv *priv,
 
 static void csi_try_fmt(struct csi_priv *priv,
                        struct v4l2_fwnode_endpoint *upstream_ep,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat,
                        struct v4l2_rect *crop,
                        struct v4l2_rect *compose,
@@ -1418,7 +1431,7 @@ static void csi_try_fmt(struct csi_priv *priv,
        struct v4l2_mbus_framefmt *infmt;
        u32 code;
 
-       infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which);
+       infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which);
 
        switch (sdformat->pad) {
        case CSI_SRC_PAD_DIRECT:
@@ -1445,7 +1458,7 @@ static void csi_try_fmt(struct csi_priv *priv,
                        }
                }
 
-               csi_try_field(priv, cfg, sdformat);
+               csi_try_field(priv, sd_state, sdformat);
 
                /* propagate colorimetry from sink */
                sdformat->format.colorspace = infmt->colorspace;
@@ -1469,7 +1482,7 @@ static void csi_try_fmt(struct csi_priv *priv,
                        sdformat->format.code = (*cc)->codes[0];
                }
 
-               csi_try_field(priv, cfg, sdformat);
+               csi_try_field(priv, sd_state, sdformat);
 
                /* Reset crop and compose rectangles */
                crop->left = 0;
@@ -1478,7 +1491,8 @@ static void csi_try_fmt(struct csi_priv *priv,
                crop->height = sdformat->format.height;
                if (sdformat->format.field == V4L2_FIELD_ALTERNATE)
                        crop->height *= 2;
-               csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep);
+               csi_try_crop(priv, crop, sd_state, &sdformat->format,
+                            upstream_ep);
                compose->left = 0;
                compose->top = 0;
                compose->width = crop->width;
@@ -1492,7 +1506,7 @@ static void csi_try_fmt(struct csi_priv *priv,
 }
 
 static int csi_set_fmt(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *sd_state,
                       struct v4l2_subdev_format *sdformat)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1518,12 +1532,13 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
                goto out;
        }
 
-       crop = __csi_get_crop(priv, cfg, sdformat->which);
-       compose = __csi_get_compose(priv, cfg, sdformat->which);
+       crop = __csi_get_crop(priv, sd_state, sdformat->which);
+       compose = __csi_get_compose(priv, sd_state, sdformat->which);
 
-       csi_try_fmt(priv, &upstream_ep, cfg, sdformat, crop, compose, &cc);
+       csi_try_fmt(priv, &upstream_ep, sd_state, sdformat, crop, compose,
+                   &cc);
 
-       fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        *fmt = sdformat->format;
 
        if (sdformat->pad == CSI_SINK_PAD) {
@@ -1538,10 +1553,11 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
                        format.pad = pad;
                        format.which = sdformat->which;
                        format.format = sdformat->format;
-                       csi_try_fmt(priv, &upstream_ep, cfg, &format,
+                       csi_try_fmt(priv, &upstream_ep, sd_state, &format,
                                    NULL, compose, &outcc);
 
-                       outfmt = __csi_get_fmt(priv, cfg, pad, sdformat->which);
+                       outfmt = __csi_get_fmt(priv, sd_state, pad,
+                                              sdformat->which);
                        *outfmt = format.format;
 
                        if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -1558,7 +1574,7 @@ out:
 }
 
 static int csi_get_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1571,9 +1587,9 @@ static int csi_get_selection(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which);
-       crop = __csi_get_crop(priv, cfg, sel->which);
-       compose = __csi_get_compose(priv, cfg, sel->which);
+       infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which);
+       crop = __csi_get_crop(priv, sd_state, sel->which);
+       compose = __csi_get_compose(priv, sd_state, sel->which);
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -1622,7 +1638,7 @@ static int csi_set_scale(u32 *compose, u32 crop, u32 flags)
 }
 
 static int csi_set_selection(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1647,9 +1663,9 @@ static int csi_set_selection(struct v4l2_subdev *sd,
                goto out;
        }
 
-       infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which);
-       crop = __csi_get_crop(priv, cfg, sel->which);
-       compose = __csi_get_compose(priv, cfg, sel->which);
+       infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which);
+       crop = __csi_get_crop(priv, sd_state, sel->which);
+       compose = __csi_get_compose(priv, sd_state, sel->which);
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
@@ -1665,7 +1681,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
                        goto out;
                }
 
-               csi_try_crop(priv, &sel->r, cfg, infmt, &upstream_ep);
+               csi_try_crop(priv, &sel->r, sd_state, infmt, &upstream_ep);
 
                *crop = sel->r;
 
@@ -1706,7 +1722,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
        for (pad = CSI_SINK_PAD + 1; pad < CSI_NUM_PADS; pad++) {
                struct v4l2_mbus_framefmt *outfmt;
 
-               outfmt = __csi_get_fmt(priv, cfg, pad, sel->which);
+               outfmt = __csi_get_fmt(priv, sd_state, pad, sel->which);
                outfmt->width = compose->width;
                outfmt->height = compose->height;
        }
index 5128915..6f90acf 100644 (file)
@@ -429,7 +429,7 @@ EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
  * of a subdev. Can be used as the .init_cfg pad operation.
  */
 int imx_media_init_cfg(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg)
+                      struct v4l2_subdev_state *sd_state)
 {
        struct v4l2_mbus_framefmt *mf_try;
        struct v4l2_subdev_format format;
@@ -445,7 +445,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd,
                if (ret)
                        continue;
 
-               mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
+               mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad);
                *mf_try = format.format;
        }
 
index abf290b..3c2093c 100644 (file)
@@ -532,17 +532,17 @@ out:
 }
 
 static struct v4l2_mbus_framefmt *
-__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_state *sd_state,
               unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
        else
                return &priv->format_mbus[pad];
 }
 
 static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->pad >= VDIC_NUM_PADS)
@@ -553,7 +553,7 @@ static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int vdic_get_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat)
 {
        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
@@ -565,7 +565,7 @@ static int vdic_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&priv->lock);
 
-       fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out;
@@ -578,7 +578,7 @@ out:
 }
 
 static void vdic_try_fmt(struct vdic_priv *priv,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_subdev_format *sdformat,
                         const struct imx_media_pixfmt **cc)
 {
@@ -594,7 +594,7 @@ static void vdic_try_fmt(struct vdic_priv *priv,
                sdformat->format.code = (*cc)->codes[0];
        }
 
-       infmt = __vdic_get_fmt(priv, cfg, priv->active_input_pad,
+       infmt = __vdic_get_fmt(priv, sd_state, priv->active_input_pad,
                               sdformat->which);
 
        switch (sdformat->pad) {
@@ -620,7 +620,7 @@ static void vdic_try_fmt(struct vdic_priv *priv,
 }
 
 static int vdic_set_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat)
 {
        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
@@ -638,9 +638,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd,
                goto out;
        }
 
-       vdic_try_fmt(priv, cfg, sdformat, &cc);
+       vdic_try_fmt(priv, sd_state, sdformat, &cc);
 
-       fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+       fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
        *fmt = sdformat->format;
 
        /* propagate format to source pad */
@@ -653,9 +653,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd,
                format.pad = VDIC_SRC_PAD_DIRECT;
                format.which = sdformat->which;
                format.format = sdformat->format;
-               vdic_try_fmt(priv, cfg, &format, &outcc);
+               vdic_try_fmt(priv, sd_state, &format, &outcc);
 
-               outfmt = __vdic_get_fmt(priv, cfg, VDIC_SRC_PAD_DIRECT,
+               outfmt = __vdic_get_fmt(priv, sd_state, VDIC_SRC_PAD_DIRECT,
                                        sdformat->which);
                *outfmt = format.format;
                if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
index 492d9a6..6740e79 100644 (file)
@@ -193,7 +193,7 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
                            u32 width, u32 height, u32 code, u32 field,
                            const struct imx_media_pixfmt **cc);
 int imx_media_init_cfg(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg);
+                      struct v4l2_subdev_state *sd_state);
 void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
                               bool ic_route);
 int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
index fc2378a..9de0ebd 100644 (file)
@@ -508,17 +508,17 @@ out:
 }
 
 static struct v4l2_mbus_framefmt *
-__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_pad_config *cfg,
+__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_state *sd_state,
               unsigned int pad, enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi2->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&csi2->sd, sd_state, pad);
        else
                return &csi2->format_mbus;
 }
 
 static int csi2_get_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat)
 {
        struct csi2_dev *csi2 = sd_to_dev(sd);
@@ -526,7 +526,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&csi2->lock);
 
-       fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
+       fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which);
 
        sdformat->format = *fmt;
 
@@ -536,7 +536,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int csi2_set_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg,
+                       struct v4l2_subdev_state *sd_state,
                        struct v4l2_subdev_format *sdformat)
 {
        struct csi2_dev *csi2 = sd_to_dev(sd);
@@ -557,7 +557,7 @@ static int csi2_set_fmt(struct v4l2_subdev *sd,
        if (sdformat->pad != CSI2_SINK_PAD)
                sdformat->format = csi2->format_mbus;
 
-       fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
+       fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which);
 
        *fmt = sdformat->format;
 out:
index f85a2f5..894c4de 100644 (file)
@@ -724,7 +724,7 @@ out_unlock:
 }
 
 static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg)
+                            struct v4l2_subdev_state *sd_state)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *mf;
@@ -732,7 +732,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
        int i;
 
        for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
-               mf = v4l2_subdev_get_try_format(sd, cfg, i);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, i);
 
                ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
                                              &csi->cc[i]);
@@ -745,18 +745,18 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
 
 static struct v4l2_mbus_framefmt *
 imx7_csi_get_format(struct imx7_csi *csi,
-                   struct v4l2_subdev_pad_config *cfg,
+                   struct v4l2_subdev_state *sd_state,
                    unsigned int pad,
                    enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi->sd, cfg, pad);
+               return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
 
        return &csi->format_mbus[pad];
 }
 
 static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -765,7 +765,8 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
 
        mutex_lock(&csi->lock);
 
-       in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which);
+       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
+                                    code->which);
 
        switch (code->pad) {
        case IMX7_CSI_PAD_SINK:
@@ -791,7 +792,7 @@ out_unlock:
 }
 
 static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *sdformat)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -800,7 +801,8 @@ static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
 
        mutex_lock(&csi->lock);
 
-       fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+                                 sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out_unlock;
@@ -815,7 +817,7 @@ out_unlock:
 }
 
 static int imx7_csi_try_fmt(struct imx7_csi *csi,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *sdformat,
                            const struct imx_media_pixfmt **cc)
 {
@@ -823,7 +825,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
        struct v4l2_mbus_framefmt *in_fmt;
        u32 code;
 
-       in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK,
+       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
                                     sdformat->which);
        if (!in_fmt)
                return -EINVAL;
@@ -868,7 +870,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
 }
 
 static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *sdformat)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -889,11 +891,12 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
                goto out_unlock;
        }
 
-       ret = imx7_csi_try_fmt(csi, cfg, sdformat, &cc);
+       ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
        if (ret < 0)
                goto out_unlock;
 
-       fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+                                 sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
                goto out_unlock;
@@ -906,11 +909,11 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
                format.pad = IMX7_CSI_PAD_SRC;
                format.which = sdformat->which;
                format.format = sdformat->format;
-               if (imx7_csi_try_fmt(csi, cfg, &format, &outcc)) {
+               if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) {
                        ret = -EINVAL;
                        goto out_unlock;
                }
-               outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC,
+               outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC,
                                             sdformat->which);
                *outfmt = format.format;
 
index 025fdc4..ead696e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #define MIPI_CSIS_ISP_CONFIG_CH(n)             (0x40 + (n) * 0x10)
 #define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK      (0xff << 24)
 #define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x)       ((x) << 24)
-#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT          BIT(12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE     (0 << 12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL       (1 << 12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD       (2 << 12)       /* i.MX8M[MNP] only */
 #define MIPI_CSIS_ISPCFG_ALIGN_32BIT           BIT(11)
-#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT     (0x1e << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW8              (0x2a << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW10             (0x2b << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW12             (0x2c << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW14             (0x2d << 2)
-/* User defined formats, x = 1...4 */
-#define MIPI_CSIS_ISPCFG_FMT_USER(x)           ((0x30 + (x) - 1) << 2)
+#define MIPI_CSIS_ISPCFG_FMT(fmt)              ((fmt) << 2)
 #define MIPI_CSIS_ISPCFG_FMT_MASK              (0x3f << 2)
 
 /* ISP Image Resolution register */
 
 /* Debug control register */
 #define MIPI_CSIS_DBG_CTRL                     0xc0
+#define MIPI_CSIS_DBG_INTR_MSK                 0xc4
+#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT  BIT(25)
+#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE       BIT(24)
+#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE  BIT(20)
+#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE                BIT(12)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS                BIT(8)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL  BIT(4)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE  BIT(0)
+#define MIPI_CSIS_DBG_INTR_SRC                 0xc8
+#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT  BIT(25)
+#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE       BIT(24)
+#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE  BIT(20)
+#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE                BIT(12)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS                BIT(8)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL  BIT(4)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE  BIT(0)
 
 /* Non-image packet data buffers */
 #define MIPI_CSIS_PKTDATA_ODD                  0x2000
 
 #define DEFAULT_SCLK_CSIS_FREQ                 166000000UL
 
+/* MIPI CSI-2 Data Types */
+#define MIPI_CSI2_DATA_TYPE_YUV420_8           0x18
+#define MIPI_CSI2_DATA_TYPE_YUV420_10          0x19
+#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8                0x1a
+#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8                0x1c
+#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10       0x1d
+#define MIPI_CSI2_DATA_TYPE_YUV422_8           0x1e
+#define MIPI_CSI2_DATA_TYPE_YUV422_10          0x1f
+#define MIPI_CSI2_DATA_TYPE_RGB565             0x22
+#define MIPI_CSI2_DATA_TYPE_RGB666             0x23
+#define MIPI_CSI2_DATA_TYPE_RGB888             0x24
+#define MIPI_CSI2_DATA_TYPE_RAW6               0x28
+#define MIPI_CSI2_DATA_TYPE_RAW7               0x29
+#define MIPI_CSI2_DATA_TYPE_RAW8               0x2a
+#define MIPI_CSI2_DATA_TYPE_RAW10              0x2b
+#define MIPI_CSI2_DATA_TYPE_RAW12              0x2c
+#define MIPI_CSI2_DATA_TYPE_RAW14              0x2d
+#define MIPI_CSI2_DATA_TYPE_USER(x)            (0x30 + (x))
+
 enum {
        ST_POWERED      = 1,
        ST_STREAMING    = 2,
@@ -210,6 +244,7 @@ enum {
 };
 
 struct mipi_csis_event {
+       bool debug;
        u32 mask;
        const char * const name;
        unsigned int counter;
@@ -217,22 +252,30 @@ struct mipi_csis_event {
 
 static const struct mipi_csis_event mipi_csis_events[] = {
        /* Errors */
-       { MIPI_CSIS_INT_SRC_ERR_SOT_HS,         "SOT Error" },
-       { MIPI_CSIS_INT_SRC_ERR_LOST_FS,        "Lost Frame Start Error" },
-       { MIPI_CSIS_INT_SRC_ERR_LOST_FE,        "Lost Frame End Error" },
-       { MIPI_CSIS_INT_SRC_ERR_OVER,           "FIFO Overflow Error" },
-       { MIPI_CSIS_INT_SRC_ERR_WRONG_CFG,      "Wrong Configuration Error" },
-       { MIPI_CSIS_INT_SRC_ERR_ECC,            "ECC Error" },
-       { MIPI_CSIS_INT_SRC_ERR_CRC,            "CRC Error" },
-       { MIPI_CSIS_INT_SRC_ERR_UNKNOWN,        "Unknown Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS,          "SOT Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS,         "Lost Frame Start Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE,         "Lost Frame End Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_OVER,            "FIFO Overflow Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG,       "Wrong Configuration Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_ECC,             "ECC Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_CRC,             "CRC Error" },
+       { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN,         "Unknown Error" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT,  "Data Type Not Supported" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE,       "Data Type Ignored" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE,  "Frame Size Error" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE,        "Early Frame End" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS,        "Early Frame Start" },
        /* Non-image data receive events */
-       { MIPI_CSIS_INT_SRC_EVEN_BEFORE,        "Non-image data before even frame" },
-       { MIPI_CSIS_INT_SRC_EVEN_AFTER,         "Non-image data after even frame" },
-       { MIPI_CSIS_INT_SRC_ODD_BEFORE,         "Non-image data before odd frame" },
-       { MIPI_CSIS_INT_SRC_ODD_AFTER,          "Non-image data after odd frame" },
+       { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE,         "Non-image data before even frame" },
+       { false, MIPI_CSIS_INT_SRC_EVEN_AFTER,          "Non-image data after even frame" },
+       { false, MIPI_CSIS_INT_SRC_ODD_BEFORE,          "Non-image data before odd frame" },
+       { false, MIPI_CSIS_INT_SRC_ODD_AFTER,           "Non-image data after odd frame" },
        /* Frame start/end */
-       { MIPI_CSIS_INT_SRC_FRAME_START,        "Frame Start" },
-       { MIPI_CSIS_INT_SRC_FRAME_END,          "Frame End" },
+       { false, MIPI_CSIS_INT_SRC_FRAME_START,         "Frame Start" },
+       { false, MIPI_CSIS_INT_SRC_FRAME_END,           "Frame End" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL,  "VSYNC Falling Edge" },
+       { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE,  "VSYNC Rising Edge" },
 };
 
 #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
@@ -241,63 +284,63 @@ enum mipi_csis_clk {
        MIPI_CSIS_CLK_PCLK,
        MIPI_CSIS_CLK_WRAP,
        MIPI_CSIS_CLK_PHY,
+       MIPI_CSIS_CLK_AXI,
 };
 
 static const char * const mipi_csis_clk_id[] = {
        "pclk",
        "wrap",
        "phy",
+       "axi",
+};
+
+enum mipi_csis_version {
+       MIPI_CSIS_V3_3,
+       MIPI_CSIS_V3_6_3,
 };
 
-struct csis_hw_reset {
-       struct regmap *src;
-       u8 req_src;
-       u8 rst_bit;
+struct mipi_csis_info {
+       enum mipi_csis_version version;
+       unsigned int num_clocks;
 };
 
 struct csi_state {
-       /* lock elements below */
-       struct mutex lock;
-       /* lock for event handler */
-       spinlock_t slock;
        struct device *dev;
+       void __iomem *regs;
+       struct clk_bulk_data *clks;
+       struct reset_control *mrst;
+       struct regulator *mipi_phy_regulator;
+       const struct mipi_csis_info *info;
+       u8 index;
+
+       struct v4l2_subdev sd;
        struct media_pad pads[CSIS_PADS_NUM];
-       struct v4l2_subdev mipi_sd;
        struct v4l2_async_notifier notifier;
        struct v4l2_subdev *src_sd;
 
-       u8 index;
-       struct platform_device *pdev;
-       struct phy *phy;
-       void __iomem *regs;
-       int irq;
-       u32 flags;
-
-       struct dentry *debugfs_root;
-       bool debug;
-
-       int num_clks;
-       struct clk_bulk_data *clks;
-
+       struct v4l2_fwnode_bus_mipi_csi2 bus;
        u32 clk_frequency;
        u32 hs_settle;
+       u32 clk_settle;
 
-       struct reset_control *mrst;
-
+       struct mutex lock;      /* Protect csis_fmt, format_mbus and state */
        const struct csis_pix_format *csis_fmt;
        struct v4l2_mbus_framefmt format_mbus;
+       u32 state;
 
-       struct v4l2_fwnode_bus_mipi_csi2 bus;
-
+       spinlock_t slock;       /* Protect events */
        struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
-
-       struct csis_hw_reset hw_reset;
-       struct regulator *mipi_phy_regulator;
+       struct dentry *debugfs_root;
+       bool debug;
 };
 
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
 struct csis_pix_format {
        u32 code;
-       u32 fmt_reg;
+       u32 data_type;
        u8 width;
 };
 
@@ -305,156 +348,117 @@ static const struct csis_pix_format mipi_csis_formats[] = {
        /* YUV formats. */
        {
                .code = MEDIA_BUS_FMT_UYVY8_1X16,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+               .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8,
                .width = 16,
        },
        /* RAW (Bayer and greyscale) formats. */
        {
                .code = MEDIA_BUS_FMT_SBGGR8_1X8,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
                .width = 8,
        }, {
                .code = MEDIA_BUS_FMT_SGBRG8_1X8,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
                .width = 8,
        }, {
                .code = MEDIA_BUS_FMT_SGRBG8_1X8,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
                .width = 8,
        }, {
                .code = MEDIA_BUS_FMT_SRGGB8_1X8,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
                .width = 8,
        }, {
                .code = MEDIA_BUS_FMT_Y8_1X8,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
                .width = 8,
        }, {
                .code = MEDIA_BUS_FMT_SBGGR10_1X10,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
                .width = 10,
        }, {
                .code = MEDIA_BUS_FMT_SGBRG10_1X10,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
                .width = 10,
        }, {
                .code = MEDIA_BUS_FMT_SGRBG10_1X10,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
                .width = 10,
        }, {
                .code = MEDIA_BUS_FMT_SRGGB10_1X10,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
                .width = 10,
        }, {
                .code = MEDIA_BUS_FMT_Y10_1X10,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
                .width = 10,
        }, {
                .code = MEDIA_BUS_FMT_SBGGR12_1X12,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
                .width = 12,
        }, {
                .code = MEDIA_BUS_FMT_SGBRG12_1X12,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
                .width = 12,
        }, {
                .code = MEDIA_BUS_FMT_SGRBG12_1X12,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
                .width = 12,
        }, {
                .code = MEDIA_BUS_FMT_SRGGB12_1X12,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
                .width = 12,
        }, {
                .code = MEDIA_BUS_FMT_Y12_1X12,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
                .width = 12,
        }, {
                .code = MEDIA_BUS_FMT_SBGGR14_1X14,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
                .width = 14,
        }, {
                .code = MEDIA_BUS_FMT_SGBRG14_1X14,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
                .width = 14,
        }, {
                .code = MEDIA_BUS_FMT_SGRBG14_1X14,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
                .width = 14,
        }, {
                .code = MEDIA_BUS_FMT_SRGGB14_1X14,
-               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+               .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
                .width = 14,
        }
 };
 
-static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
-{
-       writel(val, state->regs + reg);
-}
-
-static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
-{
-       return readl(state->regs + reg);
-}
-
-static int mipi_csis_dump_regs(struct csi_state *state)
+static const struct csis_pix_format *find_csis_format(u32 code)
 {
-       struct device *dev = &state->pdev->dev;
        unsigned int i;
-       u32 cfg;
-       static const struct {
-               u32 offset;
-               const char * const name;
-       } registers[] = {
-               { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
-               { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
-               { MIPI_CSIS_INT_MSK, "INT_MSK" },
-               { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
-               { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
-               { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
-               { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
-               { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
-               { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
-               { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
-               { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
-               { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
-       };
-
-       dev_info(dev, "--- REGISTERS ---\n");
-
-       for (i = 0; i < ARRAY_SIZE(registers); i++) {
-               cfg = mipi_csis_read(state, registers[i].offset);
-               dev_info(dev, "%14s: 0x%08x\n", registers[i].name, cfg);
-       }
 
-       return 0;
+       for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
+               if (code == mipi_csis_formats[i].code)
+                       return &mipi_csis_formats[i];
+       return NULL;
 }
 
-static struct csi_state *
-mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
-{
-       return container_of(n, struct csi_state, notifier);
-}
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
 
-static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
+static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
 {
-       return container_of(sdev, struct csi_state, mipi_sd);
+       return readl(state->regs + reg);
 }
 
-static const struct csis_pix_format *find_csis_format(u32 code)
+static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
 {
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
-               if (code == mipi_csis_formats[i].code)
-                       return &mipi_csis_formats[i];
-       return NULL;
+       writel(val, state->regs + reg);
 }
 
 static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
 {
        mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
+       mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
 }
 
 static void mipi_csis_sw_reset(struct csi_state *state)
@@ -466,25 +470,6 @@ static void mipi_csis_sw_reset(struct csi_state *state)
        usleep_range(10, 20);
 }
 
-static int mipi_csis_phy_init(struct csi_state *state)
-{
-       state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
-       if (IS_ERR(state->mipi_phy_regulator))
-               return PTR_ERR(state->mipi_phy_regulator);
-
-       return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
-                                    1000000);
-}
-
-static void mipi_csis_phy_reset(struct csi_state *state)
-{
-       reset_control_assert(state->mrst);
-
-       msleep(20);
-
-       reset_control_deassert(state->mrst);
-}
-
 static void mipi_csis_system_enable(struct csi_state *state, int on)
 {
        u32 val, mask;
@@ -514,7 +499,7 @@ static void __mipi_csis_set_format(struct csi_state *state)
        /* Color format */
        val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0));
        val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK);
-       val |= state->csis_fmt->fmt_reg;
+       val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type);
        mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val);
 
        /* Pixel resolution */
@@ -546,11 +531,15 @@ static int mipi_csis_calculate_params(struct csi_state *state)
 
        /*
         * The HSSETTLE counter value is document in a table, but can also
-        * easily be calculated.
+        * easily be calculated. Hardcode the CLKSETTLE value to 0 for now
+        * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until
+        * we figure out how to compute it correctly.
         */
        state->hs_settle = (lane_rate - 5000000) / 45000000;
-       dev_dbg(state->dev, "lane rate %u, Ths_settle %u\n",
-               lane_rate, state->hs_settle);
+       state->clk_settle = 0;
+
+       dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n",
+               lane_rate, state->clk_settle, state->hs_settle);
 
        return 0;
 }
@@ -563,13 +552,15 @@ static void mipi_csis_set_params(struct csi_state *state)
        val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
        val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
        val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
-       val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
+       if (state->info->version == MIPI_CSIS_V3_3)
+               val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
        mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
 
        __mipi_csis_set_format(state);
 
        mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL,
-                       MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle));
+                       MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) |
+                       MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle));
 
        val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET)
            | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET)
@@ -601,31 +592,30 @@ static void mipi_csis_set_params(struct csi_state *state)
 
 static int mipi_csis_clk_enable(struct csi_state *state)
 {
-       return clk_bulk_prepare_enable(state->num_clks, state->clks);
+       return clk_bulk_prepare_enable(state->info->num_clocks, state->clks);
 }
 
 static void mipi_csis_clk_disable(struct csi_state *state)
 {
-       clk_bulk_disable_unprepare(state->num_clks, state->clks);
+       clk_bulk_disable_unprepare(state->info->num_clocks, state->clks);
 }
 
 static int mipi_csis_clk_get(struct csi_state *state)
 {
-       struct device *dev = &state->pdev->dev;
        unsigned int i;
        int ret;
 
-       state->num_clks = ARRAY_SIZE(mipi_csis_clk_id);
-       state->clks = devm_kcalloc(dev, state->num_clks, sizeof(*state->clks),
-                                  GFP_KERNEL);
+       state->clks = devm_kcalloc(state->dev, state->info->num_clocks,
+                                  sizeof(*state->clks), GFP_KERNEL);
 
        if (!state->clks)
                return -ENOMEM;
 
-       for (i = 0; i < state->num_clks; i++)
+       for (i = 0; i < state->info->num_clocks; i++)
                state->clks[i].id = mipi_csis_clk_id[i];
 
-       ret = devm_clk_bulk_get(dev, state->num_clks, state->clks);
+       ret = devm_clk_bulk_get(state->dev, state->info->num_clocks,
+                               state->clks);
        if (ret < 0)
                return ret;
 
@@ -633,8 +623,8 @@ static int mipi_csis_clk_get(struct csi_state *state)
        ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk,
                           state->clk_frequency);
        if (ret < 0)
-               dev_err(dev, "set rate=%d failed: %d\n", state->clk_frequency,
-                       ret);
+               dev_err(state->dev, "set rate=%d failed: %d\n",
+                       state->clk_frequency, ret);
 
        return ret;
 }
@@ -653,6 +643,89 @@ static void mipi_csis_stop_stream(struct csi_state *state)
        mipi_csis_system_enable(state, false);
 }
 
+static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
+{
+       struct csi_state *state = dev_id;
+       unsigned long flags;
+       unsigned int i;
+       u32 status;
+       u32 dbg_status;
+
+       status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
+       dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC);
+
+       spin_lock_irqsave(&state->slock, flags);
+
+       /* Update the event/error counters */
+       if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
+               for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+                       struct mipi_csis_event *event = &state->events[i];
+
+                       if ((!event->debug && (status & event->mask)) ||
+                           (event->debug && (dbg_status & event->mask)))
+                               event->counter++;
+               }
+       }
+       spin_unlock_irqrestore(&state->slock, flags);
+
+       mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
+       mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
+
+       return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * PHY regulator and reset
+ */
+
+static int mipi_csis_phy_enable(struct csi_state *state)
+{
+       if (state->info->version != MIPI_CSIS_V3_3)
+               return 0;
+
+       return regulator_enable(state->mipi_phy_regulator);
+}
+
+static int mipi_csis_phy_disable(struct csi_state *state)
+{
+       if (state->info->version != MIPI_CSIS_V3_3)
+               return 0;
+
+       return regulator_disable(state->mipi_phy_regulator);
+}
+
+static void mipi_csis_phy_reset(struct csi_state *state)
+{
+       if (state->info->version != MIPI_CSIS_V3_3)
+               return;
+
+       reset_control_assert(state->mrst);
+       msleep(20);
+       reset_control_deassert(state->mrst);
+}
+
+static int mipi_csis_phy_init(struct csi_state *state)
+{
+       if (state->info->version != MIPI_CSIS_V3_3)
+               return 0;
+
+       /* Get MIPI PHY reset and regulator. */
+       state->mrst = devm_reset_control_get_exclusive(state->dev, NULL);
+       if (IS_ERR(state->mrst))
+               return PTR_ERR(state->mrst);
+
+       state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
+       if (IS_ERR(state->mipi_phy_regulator))
+               return PTR_ERR(state->mipi_phy_regulator);
+
+       return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
+                                    1000000);
+}
+
+/* -----------------------------------------------------------------------------
+ * Debug
+ */
+
 static void mipi_csis_clear_counters(struct csi_state *state)
 {
        unsigned long flags;
@@ -666,26 +739,90 @@ static void mipi_csis_clear_counters(struct csi_state *state)
 
 static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
 {
-       int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4;
-       struct device *dev = &state->pdev->dev;
+       unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS
+                               : MIPI_CSIS_NUM_EVENTS - 8;
        unsigned long flags;
+       unsigned int i;
 
        spin_lock_irqsave(&state->slock, flags);
 
-       for (i--; i >= 0; i--) {
+       for (i = 0; i < num_events; ++i) {
                if (state->events[i].counter > 0 || state->debug)
-                       dev_info(dev, "%s events: %d\n", state->events[i].name,
+                       dev_info(state->dev, "%s events: %d\n",
+                                state->events[i].name,
                                 state->events[i].counter);
        }
        spin_unlock_irqrestore(&state->slock, flags);
 }
 
-/*
+static int mipi_csis_dump_regs(struct csi_state *state)
+{
+       static const struct {
+               u32 offset;
+               const char * const name;
+       } registers[] = {
+               { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
+               { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
+               { MIPI_CSIS_INT_MSK, "INT_MSK" },
+               { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
+               { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
+               { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
+               { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
+               { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
+               { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
+               { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
+               { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
+               { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
+       };
+
+       unsigned int i;
+       u32 cfg;
+
+       dev_info(state->dev, "--- REGISTERS ---\n");
+
+       for (i = 0; i < ARRAY_SIZE(registers); i++) {
+               cfg = mipi_csis_read(state, registers[i].offset);
+               dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg);
+       }
+
+       return 0;
+}
+
+static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
+{
+       struct csi_state *state = m->private;
+
+       return mipi_csis_dump_regs(state);
+}
+DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
+
+static void mipi_csis_debugfs_init(struct csi_state *state)
+{
+       state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
+
+       debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
+                           &state->debug);
+       debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
+                           &mipi_csis_dump_regs_fops);
+}
+
+static void mipi_csis_debugfs_exit(struct csi_state *state)
+{
+       debugfs_remove_recursive(state->debugfs_root);
+}
+
+/* -----------------------------------------------------------------------------
  * V4L2 subdev operations
  */
-static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
+
+static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+       return container_of(sdev, struct csi_state, sd);
+}
+
+static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
        int ret;
 
        if (enable) {
@@ -695,11 +832,10 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
 
                mipi_csis_clear_counters(state);
 
-               ret = pm_runtime_get_sync(&state->pdev->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(&state->pdev->dev);
+               ret = pm_runtime_resume_and_get(state->dev);
+               if (ret < 0)
                        return ret;
-               }
+
                ret = v4l2_subdev_call(state->src_sd, core, s_power, 1);
                if (ret < 0 && ret != -ENOIOCTLCMD)
                        goto done;
@@ -708,7 +844,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
        mutex_lock(&state->lock);
 
        if (enable) {
-               if (state->flags & ST_SUSPENDED) {
+               if (state->state & ST_SUSPENDED) {
                        ret = -EBUSY;
                        goto unlock;
                }
@@ -720,14 +856,14 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
 
                mipi_csis_log_counters(state, true);
 
-               state->flags |= ST_STREAMING;
+               state->state |= ST_STREAMING;
        } else {
                v4l2_subdev_call(state->src_sd, video, s_stream, 0);
                ret = v4l2_subdev_call(state->src_sd, core, s_power, 0);
                if (ret == -ENOIOCTLCMD)
                        ret = 0;
                mipi_csis_stop_stream(state);
-               state->flags &= ~ST_STREAMING;
+               state->state &= ~ST_STREAMING;
                if (state->debug)
                        mipi_csis_log_counters(state, true);
        }
@@ -737,62 +873,33 @@ unlock:
 
 done:
        if (!enable || ret < 0)
-               pm_runtime_put(&state->pdev->dev);
+               pm_runtime_put(state->dev);
 
        return ret;
 }
 
-static int mipi_csis_link_setup(struct media_entity *entity,
-                               const struct media_pad *local_pad,
-                               const struct media_pad *remote_pad, u32 flags)
+static struct v4l2_mbus_framefmt *
+mipi_csis_get_format(struct csi_state *state,
+                    struct v4l2_subdev_state *sd_state,
+                    enum v4l2_subdev_format_whence which,
+                    unsigned int pad)
 {
-       struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity);
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-       struct v4l2_subdev *remote_sd;
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(&state->sd, sd_state, pad);
 
-       dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
-               local_pad->entity->name);
+       return &state->format_mbus;
+}
 
-       /* We only care about the link to the source. */
-       if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
-               return 0;
+static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state)
+{
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
+       struct v4l2_mbus_framefmt *fmt_sink;
+       struct v4l2_mbus_framefmt *fmt_source;
+       enum v4l2_subdev_format_whence which;
 
-       remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
-
-       if (flags & MEDIA_LNK_FL_ENABLED) {
-               if (state->src_sd)
-                       return -EBUSY;
-
-               state->src_sd = remote_sd;
-       } else {
-               state->src_sd = NULL;
-       }
-
-       return 0;
-}
-
-static struct v4l2_mbus_framefmt *
-mipi_csis_get_format(struct csi_state *state,
-                    struct v4l2_subdev_pad_config *cfg,
-                    enum v4l2_subdev_format_whence which,
-                    unsigned int pad)
-{
-       if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&state->mipi_sd, cfg, pad);
-
-       return &state->format_mbus;
-}
-
-static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
-                             struct v4l2_subdev_pad_config *cfg)
-{
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-       struct v4l2_mbus_framefmt *fmt_sink;
-       struct v4l2_mbus_framefmt *fmt_source;
-       enum v4l2_subdev_format_whence which;
-
-       which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
-       fmt_sink = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SINK);
+       which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK);
 
        fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16;
        fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
@@ -811,35 +918,38 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
         * configuration, cfg is NULL, which indicates there's no source pad
         * configuration to set.
         */
-       if (!cfg)
+       if (!sd_state)
                return 0;
 
-       fmt_source = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SOURCE);
+       fmt_source = mipi_csis_get_format(state, sd_state, which,
+                                         CSIS_PAD_SOURCE);
        *fmt_source = *fmt_sink;
 
        return 0;
 }
 
-static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
-                            struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *sdformat)
 {
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
        struct v4l2_mbus_framefmt *fmt;
 
+       fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
+                                  sdformat->pad);
+
        mutex_lock(&state->lock);
-       fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
        sdformat->format = *fmt;
        mutex_unlock(&state->lock);
 
        return 0;
 }
 
-static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
-                                   struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
+                                   struct v4l2_subdev_state *sd_state,
                                    struct v4l2_subdev_mbus_code_enum *code)
 {
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
 
        /*
         * The CSIS can't transcode in any way, the source format is identical
@@ -851,7 +961,8 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
                if (code->index > 0)
                        return -EINVAL;
 
-               fmt = mipi_csis_get_format(state, cfg, code->which, code->pad);
+               fmt = mipi_csis_get_format(state, sd_state, code->which,
+                                          code->pad);
                code->code = fmt->code;
                return 0;
        }
@@ -867,11 +978,11 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
        return 0;
 }
 
-static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
-                            struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *sdformat)
 {
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
        struct csis_pix_format const *csis_fmt;
        struct v4l2_mbus_framefmt *fmt;
        unsigned int align;
@@ -881,29 +992,22 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
         * modified.
         */
        if (sdformat->pad == CSIS_PAD_SOURCE)
-               return mipi_csis_get_fmt(mipi_sd, cfg, sdformat);
+               return mipi_csis_get_fmt(sd, sd_state, sdformat);
 
        if (sdformat->pad != CSIS_PAD_SINK)
                return -EINVAL;
 
-       fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
-
-       mutex_lock(&state->lock);
-
-       /* Validate the media bus code and clamp the size. */
-       csis_fmt = find_csis_format(sdformat->format.code);
-       if (!csis_fmt)
-               csis_fmt = &mipi_csis_formats[0];
-
-       fmt->code = csis_fmt->code;
-       fmt->width = sdformat->format.width;
-       fmt->height = sdformat->format.height;
-
        /*
+        * Validate the media bus code and clamp and align the size.
+        *
         * The total number of bits per line must be a multiple of 8. We thus
         * need to align the width for formats that are not multiples of 8
         * bits.
         */
+       csis_fmt = find_csis_format(sdformat->format.code);
+       if (!csis_fmt)
+               csis_fmt = &mipi_csis_formats[0];
+
        switch (csis_fmt->width % 8) {
        case 0:
                align = 0;
@@ -923,13 +1027,24 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
                break;
        }
 
-       v4l_bound_align_image(&fmt->width, 1, CSIS_MAX_PIX_WIDTH, align,
-                             &fmt->height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0);
+       v4l_bound_align_image(&sdformat->format.width, 1,
+                             CSIS_MAX_PIX_WIDTH, align,
+                             &sdformat->format.height, 1,
+                             CSIS_MAX_PIX_HEIGHT, 0, 0);
+
+       fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
+                                  sdformat->pad);
+
+       mutex_lock(&state->lock);
+
+       fmt->code = csis_fmt->code;
+       fmt->width = sdformat->format.width;
+       fmt->height = sdformat->format.height;
 
        sdformat->format = *fmt;
 
        /* Propagate the format from sink to source. */
-       fmt = mipi_csis_get_format(state, cfg, sdformat->which,
+       fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
                                   CSIS_PAD_SOURCE);
        *fmt = sdformat->format;
 
@@ -942,55 +1057,23 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
        return 0;
 }
 
-static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
+static int mipi_csis_log_status(struct v4l2_subdev *sd)
 {
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
 
        mutex_lock(&state->lock);
        mipi_csis_log_counters(state, true);
-       if (state->debug && (state->flags & ST_POWERED))
+       if (state->debug && (state->state & ST_POWERED))
                mipi_csis_dump_regs(state);
        mutex_unlock(&state->lock);
 
        return 0;
 }
 
-static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
-{
-       struct csi_state *state = dev_id;
-       unsigned long flags;
-       unsigned int i;
-       u32 status;
-
-       status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
-
-       spin_lock_irqsave(&state->slock, flags);
-
-       /* Update the event/error counters */
-       if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
-               for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
-                       if (!(status & state->events[i].mask))
-                               continue;
-                       state->events[i].counter++;
-               }
-       }
-       spin_unlock_irqrestore(&state->slock, flags);
-
-       mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
-
-       return IRQ_HANDLED;
-}
-
 static const struct v4l2_subdev_core_ops mipi_csis_core_ops = {
        .log_status     = mipi_csis_log_status,
 };
 
-static const struct media_entity_operations mipi_csis_entity_ops = {
-       .link_setup     = mipi_csis_link_setup,
-       .link_validate  = v4l2_subdev_link_validate,
-       .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
-};
-
 static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
        .s_stream       = mipi_csis_s_stream,
 };
@@ -1008,31 +1091,61 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
        .pad    = &mipi_csis_pad_ops,
 };
 
-static int mipi_csis_parse_dt(struct platform_device *pdev,
-                             struct csi_state *state)
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static int mipi_csis_link_setup(struct media_entity *entity,
+                               const struct media_pad *local_pad,
+                               const struct media_pad *remote_pad, u32 flags)
 {
-       struct device_node *node = pdev->dev.of_node;
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
+       struct v4l2_subdev *remote_sd;
 
-       if (of_property_read_u32(node, "clock-frequency",
-                                &state->clk_frequency))
-               state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+       dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
+               local_pad->entity->name);
 
-       /* Get MIPI PHY resets */
-       state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-       if (IS_ERR(state->mrst))
-               return PTR_ERR(state->mrst);
+       /* We only care about the link to the source. */
+       if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
+               return 0;
+
+       remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+       if (flags & MEDIA_LNK_FL_ENABLED) {
+               if (state->src_sd)
+                       return -EBUSY;
+
+               state->src_sd = remote_sd;
+       } else {
+               state->src_sd = NULL;
+       }
 
        return 0;
 }
 
-static int mipi_csis_pm_resume(struct device *dev, bool runtime);
+static const struct media_entity_operations mipi_csis_entity_ops = {
+       .link_setup     = mipi_csis_link_setup,
+       .link_validate  = v4l2_subdev_link_validate,
+       .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+/* -----------------------------------------------------------------------------
+ * Async subdev notifier
+ */
+
+static struct csi_state *
+mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
+{
+       return container_of(n, struct csi_state, notifier);
+}
 
 static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
                                  struct v4l2_subdev *sd,
                                  struct v4l2_async_subdev *asd)
 {
        struct csi_state *state = mipi_notifier_to_csis_state(notifier);
-       struct media_pad *sink = &state->mipi_sd.entity.pads[CSIS_PAD_SINK];
+       struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK];
 
        return v4l2_create_fwnode_links_to_pad(sd, sink, 0);
 }
@@ -1041,38 +1154,6 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = {
        .bound = mipi_csis_notify_bound,
 };
 
-static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
-                                struct platform_device *pdev,
-                                const struct v4l2_subdev_ops *ops)
-{
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-
-       v4l2_subdev_init(mipi_sd, ops);
-       mipi_sd->owner = THIS_MODULE;
-       snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
-                CSIS_SUBDEV_NAME, state->index);
-
-       mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       mipi_sd->ctrl_handler = NULL;
-
-       mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
-       mipi_sd->entity.ops = &mipi_csis_entity_ops;
-
-       mipi_sd->dev = &pdev->dev;
-
-       state->csis_fmt = &mipi_csis_formats[0];
-       mipi_csis_init_cfg(mipi_sd, NULL);
-
-       v4l2_set_subdevdata(mipi_sd, &pdev->dev);
-
-       state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
-                                        | MEDIA_PAD_FL_MUST_CONNECT;
-       state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
-                                          | MEDIA_PAD_FL_MUST_CONNECT;
-       return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
-                                     state->pads);
-}
-
 static int mipi_csis_async_register(struct csi_state *state)
 {
        struct v4l2_fwnode_endpoint vep = {
@@ -1080,6 +1161,7 @@ static int mipi_csis_async_register(struct csi_state *state)
        };
        struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
+       unsigned int i;
        int ret;
 
        v4l2_async_notifier_init(&state->notifier);
@@ -1093,6 +1175,15 @@ static int mipi_csis_async_register(struct csi_state *state)
        if (ret)
                goto err_parse;
 
+       for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
+               if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
+                       dev_err(state->dev,
+                               "data lanes reordering is not supported");
+                       ret = -EINVAL;
+                       goto err_parse;
+               }
+       }
+
        state->bus = vep.bus.mipi_csi2;
 
        dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
@@ -1109,12 +1200,11 @@ static int mipi_csis_async_register(struct csi_state *state)
 
        state->notifier.ops = &mipi_csis_notify_ops;
 
-       ret = v4l2_async_subdev_notifier_register(&state->mipi_sd,
-                                                 &state->notifier);
+       ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier);
        if (ret)
                return ret;
 
-       return v4l2_async_register_subdev(&state->mipi_sd);
+       return v4l2_async_register_subdev(&state->sd);
 
 err_parse:
        fwnode_handle_put(ep);
@@ -1122,98 +1212,209 @@ err_parse:
        return ret;
 }
 
-static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
 {
-       struct csi_state *state = m->private;
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
+       int ret = 0;
 
-       return mipi_csis_dump_regs(state);
+       mutex_lock(&state->lock);
+       if (state->state & ST_POWERED) {
+               mipi_csis_stop_stream(state);
+               ret = mipi_csis_phy_disable(state);
+               if (ret)
+                       goto unlock;
+               mipi_csis_clk_disable(state);
+               state->state &= ~ST_POWERED;
+               if (!runtime)
+                       state->state |= ST_SUSPENDED;
+       }
+
+unlock:
+       mutex_unlock(&state->lock);
+
+       return ret ? -EAGAIN : 0;
 }
-DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
 
-static void mipi_csis_debugfs_init(struct csi_state *state)
+static int mipi_csis_pm_resume(struct device *dev, bool runtime)
 {
-       state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
+       int ret = 0;
 
-       debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
-                           &state->debug);
-       debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
-                           &mipi_csis_dump_regs_fops);
+       mutex_lock(&state->lock);
+       if (!runtime && !(state->state & ST_SUSPENDED))
+               goto unlock;
+
+       if (!(state->state & ST_POWERED)) {
+               ret = mipi_csis_phy_enable(state);
+               if (ret)
+                       goto unlock;
+
+               state->state |= ST_POWERED;
+               mipi_csis_clk_enable(state);
+       }
+       if (state->state & ST_STREAMING)
+               mipi_csis_start_stream(state);
+
+       state->state &= ~ST_SUSPENDED;
+
+unlock:
+       mutex_unlock(&state->lock);
+
+       return ret ? -EAGAIN : 0;
 }
 
-static void mipi_csis_debugfs_exit(struct csi_state *state)
+static int __maybe_unused mipi_csis_suspend(struct device *dev)
 {
-       debugfs_remove_recursive(state->debugfs_root);
+       return mipi_csis_pm_suspend(dev, false);
+}
+
+static int __maybe_unused mipi_csis_resume(struct device *dev)
+{
+       return mipi_csis_pm_resume(dev, false);
+}
+
+static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
+{
+       return mipi_csis_pm_suspend(dev, true);
+}
+
+static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
+{
+       return mipi_csis_pm_resume(dev, true);
+}
+
+static const struct dev_pm_ops mipi_csis_pm_ops = {
+       SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove & platform driver
+ */
+
+static int mipi_csis_subdev_init(struct csi_state *state)
+{
+       struct v4l2_subdev *sd = &state->sd;
+
+       v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
+       sd->owner = THIS_MODULE;
+       snprintf(sd->name, sizeof(sd->name), "%s.%d",
+                CSIS_SUBDEV_NAME, state->index);
+
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sd->ctrl_handler = NULL;
+
+       sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+       sd->entity.ops = &mipi_csis_entity_ops;
+
+       sd->dev = state->dev;
+
+       state->csis_fmt = &mipi_csis_formats[0];
+       mipi_csis_init_cfg(sd, NULL);
+
+       state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                        | MEDIA_PAD_FL_MUST_CONNECT;
+       state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
+                                          | MEDIA_PAD_FL_MUST_CONNECT;
+       return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
+                                     state->pads);
+}
+
+static int mipi_csis_parse_dt(struct csi_state *state)
+{
+       struct device_node *node = state->dev->of_node;
+
+       if (of_property_read_u32(node, "clock-frequency",
+                                &state->clk_frequency))
+               state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+
+       return 0;
 }
 
 static int mipi_csis_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct csi_state *state;
+       int irq;
        int ret;
 
        state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
+       mutex_init(&state->lock);
        spin_lock_init(&state->slock);
 
-       state->pdev = pdev;
        state->dev = dev;
+       state->info = of_device_get_match_data(dev);
+
+       memcpy(state->events, mipi_csis_events, sizeof(state->events));
 
-       ret = mipi_csis_parse_dt(pdev, state);
+       /* Parse DT properties. */
+       ret = mipi_csis_parse_dt(state);
        if (ret < 0) {
                dev_err(dev, "Failed to parse device tree: %d\n", ret);
                return ret;
        }
 
-       ret = mipi_csis_phy_init(state);
-       if (ret < 0)
-               return ret;
-
-       mipi_csis_phy_reset(state);
-
+       /* Acquire resources. */
        state->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(state->regs))
                return PTR_ERR(state->regs);
 
-       state->irq = platform_get_irq(pdev, 0);
-       if (state->irq < 0)
-               return state->irq;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = mipi_csis_phy_init(state);
+       if (ret < 0)
+               return ret;
 
        ret = mipi_csis_clk_get(state);
        if (ret < 0)
                return ret;
 
+       /* Reset PHY and enable the clocks. */
+       mipi_csis_phy_reset(state);
+
        ret = mipi_csis_clk_enable(state);
        if (ret < 0) {
                dev_err(state->dev, "failed to enable clocks: %d\n", ret);
                return ret;
        }
 
-       ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler,
-                              0, dev_name(dev), state);
+       /* Now that the hardware is initialized, request the interrupt. */
+       ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
+                              dev_name(dev), state);
        if (ret) {
                dev_err(dev, "Interrupt request failed\n");
                goto disable_clock;
        }
 
-       platform_set_drvdata(pdev, &state->mipi_sd);
-
-       mutex_init(&state->lock);
-       ret = mipi_csis_subdev_init(&state->mipi_sd, pdev,
-                                   &mipi_csis_subdev_ops);
+       /* Initialize and register the subdev. */
+       ret = mipi_csis_subdev_init(state);
        if (ret < 0)
                goto disable_clock;
 
+       platform_set_drvdata(pdev, &state->sd);
+
        ret = mipi_csis_async_register(state);
        if (ret < 0) {
-               dev_err(&pdev->dev, "async register failed: %d\n", ret);
+               dev_err(dev, "async register failed: %d\n", ret);
                goto cleanup;
        }
 
-       memcpy(state->events, mipi_csis_events, sizeof(state->events));
-
+       /* Initialize debugfs. */
        mipi_csis_debugfs_init(state);
+
+       /* Enable runtime PM. */
        pm_runtime_enable(dev);
        if (!pm_runtime_enabled(dev)) {
                ret = mipi_csis_pm_resume(dev, true);
@@ -1221,7 +1422,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
                        goto unregister_all;
        }
 
-       dev_info(&pdev->dev, "lanes: %d, freq: %u\n",
+       dev_info(dev, "lanes: %d, freq: %u\n",
                 state->bus.num_data_lanes, state->clk_frequency);
 
        return 0;
@@ -1229,10 +1430,10 @@ static int mipi_csis_probe(struct platform_device *pdev)
 unregister_all:
        mipi_csis_debugfs_exit(state);
 cleanup:
-       media_entity_cleanup(&state->mipi_sd.entity);
+       media_entity_cleanup(&state->sd.entity);
        v4l2_async_notifier_unregister(&state->notifier);
        v4l2_async_notifier_cleanup(&state->notifier);
-       v4l2_async_unregister_subdev(&state->mipi_sd);
+       v4l2_async_unregister_subdev(&state->sd);
 disable_clock:
        mipi_csis_clk_disable(state);
        mutex_destroy(&state->lock);
@@ -1240,107 +1441,40 @@ disable_clock:
        return ret;
 }
 
-static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
-{
-       struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-       int ret = 0;
-
-       mutex_lock(&state->lock);
-       if (state->flags & ST_POWERED) {
-               mipi_csis_stop_stream(state);
-               ret = regulator_disable(state->mipi_phy_regulator);
-               if (ret)
-                       goto unlock;
-               mipi_csis_clk_disable(state);
-               state->flags &= ~ST_POWERED;
-               if (!runtime)
-                       state->flags |= ST_SUSPENDED;
-       }
-
-unlock:
-       mutex_unlock(&state->lock);
-
-       return ret ? -EAGAIN : 0;
-}
-
-static int mipi_csis_pm_resume(struct device *dev, bool runtime)
-{
-       struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-       int ret = 0;
-
-       mutex_lock(&state->lock);
-       if (!runtime && !(state->flags & ST_SUSPENDED))
-               goto unlock;
-
-       if (!(state->flags & ST_POWERED)) {
-               ret = regulator_enable(state->mipi_phy_regulator);
-               if (ret)
-                       goto unlock;
-
-               state->flags |= ST_POWERED;
-               mipi_csis_clk_enable(state);
-       }
-       if (state->flags & ST_STREAMING)
-               mipi_csis_start_stream(state);
-
-       state->flags &= ~ST_SUSPENDED;
-
-unlock:
-       mutex_unlock(&state->lock);
-
-       return ret ? -EAGAIN : 0;
-}
-
-static int __maybe_unused mipi_csis_suspend(struct device *dev)
-{
-       return mipi_csis_pm_suspend(dev, false);
-}
-
-static int __maybe_unused mipi_csis_resume(struct device *dev)
-{
-       return mipi_csis_pm_resume(dev, false);
-}
-
-static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
-{
-       return mipi_csis_pm_suspend(dev, true);
-}
-
-static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
-{
-       return mipi_csis_pm_resume(dev, true);
-}
-
 static int mipi_csis_remove(struct platform_device *pdev)
 {
-       struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+       struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+       struct csi_state *state = mipi_sd_to_csis_state(sd);
 
        mipi_csis_debugfs_exit(state);
        v4l2_async_notifier_unregister(&state->notifier);
        v4l2_async_notifier_cleanup(&state->notifier);
-       v4l2_async_unregister_subdev(&state->mipi_sd);
+       v4l2_async_unregister_subdev(&state->sd);
 
        pm_runtime_disable(&pdev->dev);
        mipi_csis_pm_suspend(&pdev->dev, true);
        mipi_csis_clk_disable(state);
-       media_entity_cleanup(&state->mipi_sd.entity);
+       media_entity_cleanup(&state->sd.entity);
        mutex_destroy(&state->lock);
        pm_runtime_set_suspended(&pdev->dev);
 
        return 0;
 }
 
-static const struct dev_pm_ops mipi_csis_pm_ops = {
-       SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
-                          NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
-};
-
 static const struct of_device_id mipi_csis_of_match[] = {
-       { .compatible = "fsl,imx7-mipi-csi2", },
+       {
+               .compatible = "fsl,imx7-mipi-csi2",
+               .data = &(const struct mipi_csis_info){
+                       .version = MIPI_CSIS_V3_3,
+                       .num_clocks = 3,
+               },
+       }, {
+               .compatible = "fsl,imx8mm-mipi-csi2",
+               .data = &(const struct mipi_csis_info){
+                       .version = MIPI_CSIS_V3_6_3,
+                       .num_clocks = 4,
+               },
+       },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
@@ -1357,6 +1491,6 @@ static struct platform_driver mipi_csis_driver = {
 
 module_platform_driver(mipi_csis_driver);
 
-MODULE_DESCRIPTION("i.MX7 MIPI CSI-2 Receiver driver");
+MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:imx7-mipi-csi2");
@@ -9,8 +9,10 @@
 /* from /drivers/staging/media/ipu3/include/videodev2.h */
 
 /* Vendor specific - used for IPU3 camera sub-system */
-#define V4L2_META_FMT_IPU3_PARAMS      v4l2_fourcc('i', 'p', '3', 'p') /* IPU3 processing parameters */
-#define V4L2_META_FMT_IPU3_STAT_3A     v4l2_fourcc('i', 'p', '3', 's') /* IPU3 3A statistics */
+/* IPU3 processing parameters */
+#define V4L2_META_FMT_IPU3_PARAMS      v4l2_fourcc('i', 'p', '3', 'p')
+/* IPU3 3A statistics */
+#define V4L2_META_FMT_IPU3_STAT_3A     v4l2_fourcc('i', 'p', '3', 's')
 
 /* from include/uapi/linux/v4l2-controls.h */
 #define V4L2_CID_INTEL_IPU3_BASE       (V4L2_CID_USER_BASE + 0x10c0)
@@ -74,7 +76,6 @@ struct ipu3_uapi_grid_config {
        (IPU3_UAPI_AWB_MAX_SETS * \
         (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
 
-
 /**
  * struct ipu3_uapi_awb_raw_buffer - AWB raw buffer
  *
@@ -244,8 +245,8 @@ struct ipu3_uapi_ae_ccm {
  */
 struct ipu3_uapi_ae_config {
        struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32)));
-       struct ipu3_uapi_ae_weight_elem weights[
-                       IPU3_UAPI_AE_WEIGHTS] __attribute__((aligned(32)));
+       struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
+                                               __attribute__((aligned(32)));
        struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32)));
 } __packed;
 
@@ -630,7 +631,7 @@ struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
  * @cg:        Gain coefficient for threshold calculation, [0, 31], default 8.
  * @ci:        Intensity coefficient for threshold calculation. range [0, 0x1f]
  *     default 6.
- *     format: u3.2 (3 most significant bits represent whole number,
+ *     format: u3.2 (3 most significant bits represent whole number,
  *     2 least significant bits represent the fractional part
  *     with each count representing 0.25)
  *     e.g. 6 in binary format is 00110, that translates to 1.5
index e118560..c76935b 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef __IPU3_ABI_H
 #define __IPU3_ABI_H
 
-#include "include/intel-ipu3.h"
+#include "include/uapi/intel-ipu3.h"
 
 /******************* IMGU Hardware information *******************/
 
index 35519a0..3f9e32e 100644 (file)
@@ -15,6 +15,7 @@ struct imgu_device;
  * @size:              size of the buffer in bytes.
  * @vaddr:             kernel virtual address.
  * @daddr:             iova dma address to access IPU3.
+ * @pages:             pages mapped to this buffer
  */
 struct imgu_css_map {
        size_t size;
index 6d9c49b..38a2407 100644 (file)
@@ -36,7 +36,7 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        /* Initialize try_fmt */
        for (i = 0; i < IMGU_NODE_NUM; i++) {
                struct v4l2_mbus_framefmt *try_fmt =
-                       v4l2_subdev_get_try_format(sd, fh->pad, i);
+                       v4l2_subdev_get_try_format(sd, fh->state, i);
 
                try_fmt->width = try_crop.width;
                try_fmt->height = try_crop.height;
@@ -44,8 +44,8 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
                try_fmt->field = V4L2_FIELD_NONE;
        }
 
-       *v4l2_subdev_get_try_crop(sd, fh->pad, IMGU_NODE_IN) = try_crop;
-       *v4l2_subdev_get_try_compose(sd, fh->pad, IMGU_NODE_IN) = try_crop;
+       *v4l2_subdev_get_try_crop(sd, fh->state, IMGU_NODE_IN) = try_crop;
+       *v4l2_subdev_get_try_compose(sd, fh->state, IMGU_NODE_IN) = try_crop;
 
        return 0;
 }
@@ -120,7 +120,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable)
 }
 
 static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct imgu_device *imgu = v4l2_get_subdevdata(sd);
@@ -136,7 +136,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                fmt->format = imgu_pipe->nodes[pad].pad_fmt;
        } else {
-               mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
                fmt->format = *mf;
        }
 
@@ -144,7 +144,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
 }
 
 static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct imgu_media_pipe *imgu_pipe;
@@ -161,7 +161,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
 
        imgu_pipe = &imgu->imgu_pipe[pipe];
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+               mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
        else
                mf = &imgu_pipe->nodes[pad].pad_fmt;
 
@@ -189,7 +189,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
 }
 
 static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct v4l2_rect *try_sel, *r;
@@ -202,11 +202,11 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
-               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                r = &imgu_sd->rect.eff;
                break;
        case V4L2_SEL_TGT_COMPOSE:
-               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
                r = &imgu_sd->rect.bds;
                break;
        default:
@@ -222,7 +222,7 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
 }
 
 static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_selection *sel)
 {
        struct imgu_device *imgu = v4l2_get_subdevdata(sd);
@@ -241,11 +241,11 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
 
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP:
-               try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
                rect = &imgu_sd->rect.eff;
                break;
        case V4L2_SEL_TGT_COMPOSE:
-               try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+               try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
                rect = &imgu_sd->rect.bds;
                break;
        default:
index ee1bba6..8e1e9e4 100644 (file)
@@ -392,10 +392,9 @@ int imgu_s_stream(struct imgu_device *imgu, int enable)
        }
 
        /* Set Power */
-       r = pm_runtime_get_sync(dev);
+       r = pm_runtime_resume_and_get(dev);
        if (r < 0) {
                dev_err(dev, "failed to set imgu power\n");
-               pm_runtime_put(dev);
                return r;
        }
 
index 7f07a91..b9125c2 100644 (file)
@@ -183,7 +183,7 @@ int amvdec_set_canvases(struct amvdec_session *sess,
        u32 pixfmt = sess->pixfmt_cap;
        u32 width = ALIGN(sess->width, 32);
        u32 height = ALIGN(sess->height, 32);
-       u32 reg_cur = reg_base[0];
+       u32 reg_cur;
        u32 reg_num_cur = 0;
        u32 reg_base_cur = 0;
        int i = 0;
index b88f952..3f587e0 100644 (file)
@@ -119,9 +119,6 @@ struct iss_device {
        unsigned int isp_subclk_resources;
 };
 
-#define v4l2_dev_to_iss_device(dev) \
-       container_of(dev, struct iss_device, v4l2_dev)
-
 int omap4iss_get_external_info(struct iss_pipeline *pipe,
                               struct media_link *link);
 
index a6dc2d2..124ab2f 100644 (file)
@@ -825,19 +825,20 @@ static const struct iss_video_operations csi2_issvideo_ops = {
 
 static struct v4l2_mbus_framefmt *
 __csi2_get_format(struct iss_csi2_device *csi2,
-                 struct v4l2_subdev_pad_config *cfg,
+                 struct v4l2_subdev_state *sd_state,
                  unsigned int pad,
                  enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+                                                 pad);
 
        return &csi2->formats[pad];
 }
 
 static void
 csi2_try_format(struct iss_csi2_device *csi2,
-               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_state *sd_state,
                unsigned int pad,
                struct v4l2_mbus_framefmt *fmt,
                enum v4l2_subdev_format_whence which)
@@ -868,7 +869,8 @@ csi2_try_format(struct iss_csi2_device *csi2,
                 * compression.
                 */
                pixelcode = fmt->code;
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which);
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
+                                          which);
                memcpy(fmt, format, sizeof(*fmt));
 
                /*
@@ -894,7 +896,7 @@ csi2_try_format(struct iss_csi2_device *csi2,
  * return -EINVAL or zero on success
  */
 static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_mbus_code_enum *code)
 {
        struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -907,7 +909,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
 
                code->code = csi2_input_fmts[code->index];
        } else {
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK,
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
                                           code->which);
                switch (code->index) {
                case 0:
@@ -931,7 +933,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int csi2_enum_frame_size(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_frame_size_enum *fse)
 {
        struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -943,7 +945,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+       csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -953,7 +955,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+       csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -968,13 +970,13 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int csi2_get_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+       format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -990,25 +992,26 @@ static int csi2_get_format(struct v4l2_subdev *sd,
  * return -EINVAL or zero on success
  */
 static int csi2_set_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *sd_state,
                           struct v4l2_subdev_format *fmt)
 {
        struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+       format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
-       csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which);
+       csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == CSI2_PAD_SINK) {
-               format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE,
+               format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE,
                                           fmt->which);
                *format = fmt->format;
-               csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which);
+               csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format,
+                               fmt->which);
        }
 
        return 0;
@@ -1050,7 +1053,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       csi2_set_format(sd, fh ? fh->pad : NULL, &format);
+       csi2_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index 26be078..23f707c 100644 (file)
@@ -21,7 +21,7 @@
 
 static struct v4l2_mbus_framefmt *
 __ipipe_get_format(struct iss_ipipe_device *ipipe,
-                  struct v4l2_subdev_pad_config *cfg,
+                  struct v4l2_subdev_state *sd_state,
                   unsigned int pad,
                   enum v4l2_subdev_format_whence which);
 
@@ -175,12 +175,13 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
 
 static struct v4l2_mbus_framefmt *
 __ipipe_get_format(struct iss_ipipe_device *ipipe,
-                  struct v4l2_subdev_pad_config *cfg,
+                  struct v4l2_subdev_state *sd_state,
                   unsigned int pad,
                   enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state,
+                                                 pad);
 
        return &ipipe->formats[pad];
 }
@@ -194,7 +195,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe,
  */
 static void
 ipipe_try_format(struct iss_ipipe_device *ipipe,
-                struct v4l2_subdev_pad_config *cfg,
+                struct v4l2_subdev_state *sd_state,
                 unsigned int pad,
                 struct v4l2_mbus_framefmt *fmt,
                 enum v4l2_subdev_format_whence which)
@@ -222,7 +223,8 @@ ipipe_try_format(struct iss_ipipe_device *ipipe,
                break;
 
        case IPIPE_PAD_SOURCE_VP:
-               format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which);
+               format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK,
+                                           which);
                memcpy(fmt, format, sizeof(*fmt));
 
                fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
@@ -243,7 +245,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe,
  * return -EINVAL or zero on success
  */
 static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_state *sd_state,
                                struct v4l2_subdev_mbus_code_enum *code)
 {
        switch (code->pad) {
@@ -270,7 +272,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_frame_size_enum *fse)
 {
        struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
@@ -282,7 +284,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
+       ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -292,7 +294,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
+       ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -309,13 +311,13 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int ipipe_get_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
+       format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -333,25 +335,26 @@ static int ipipe_get_format(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int ipipe_set_format(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_format *fmt)
 {
        struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
+       format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
-       ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which);
+       ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == IPIPE_PAD_SINK) {
-               format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP,
+               format = __ipipe_get_format(ipipe, sd_state,
+                                           IPIPE_PAD_SOURCE_VP,
                                            fmt->which);
                *format = fmt->format;
-               ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format,
+               ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format,
                                 fmt->which);
        }
 
@@ -392,7 +395,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       ipipe_set_format(sd, fh ? fh->pad : NULL, &format);
+       ipipe_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index c2978d0..5e7f25c 100644 (file)
@@ -357,11 +357,12 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
 
 static struct v4l2_mbus_framefmt *
 __ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
-                    struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                    struct v4l2_subdev_state *sd_state, unsigned int pad,
                     enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state,
+                                                 pad);
        return &ipipeif->formats[pad];
 }
 
@@ -374,7 +375,7 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
  */
 static void
 ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
-                  struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                  struct v4l2_subdev_state *sd_state, unsigned int pad,
                   struct v4l2_mbus_framefmt *fmt,
                   enum v4l2_subdev_format_whence which)
 {
@@ -403,7 +404,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
                break;
 
        case IPIPEIF_PAD_SOURCE_ISIF_SF:
-               format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+               format = __ipipeif_get_format(ipipeif, sd_state,
+                                             IPIPEIF_PAD_SINK,
                                              which);
                memcpy(fmt, format, sizeof(*fmt));
 
@@ -418,7 +420,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
                break;
 
        case IPIPEIF_PAD_SOURCE_VP:
-               format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+               format = __ipipeif_get_format(ipipeif, sd_state,
+                                             IPIPEIF_PAD_SINK,
                                              which);
                memcpy(fmt, format, sizeof(*fmt));
 
@@ -442,7 +445,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
  * return -EINVAL or zero on success
  */
 static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
@@ -462,7 +465,8 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
                if (code->index != 0)
                        return -EINVAL;
 
-               format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+               format = __ipipeif_get_format(ipipeif, sd_state,
+                                             IPIPEIF_PAD_SINK,
                                              code->which);
 
                code->code = format->code;
@@ -476,7 +480,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
@@ -488,7 +492,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
+       ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -498,7 +502,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
+       ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -515,13 +519,13 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int ipipeif_get_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
+       format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -539,33 +543,36 @@ static int ipipeif_get_format(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int ipipeif_set_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
+       format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
-       ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which);
+       ipipeif_try_format(ipipeif, sd_state, fmt->pad, &fmt->format,
+                          fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == IPIPEIF_PAD_SINK) {
-               format = __ipipeif_get_format(ipipeif, cfg,
+               format = __ipipeif_get_format(ipipeif, sd_state,
                                              IPIPEIF_PAD_SOURCE_ISIF_SF,
                                              fmt->which);
                *format = fmt->format;
-               ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF,
+               ipipeif_try_format(ipipeif, sd_state,
+                                  IPIPEIF_PAD_SOURCE_ISIF_SF,
                                   format, fmt->which);
 
-               format = __ipipeif_get_format(ipipeif, cfg,
+               format = __ipipeif_get_format(ipipeif, sd_state,
                                              IPIPEIF_PAD_SOURCE_VP,
                                              fmt->which);
                *format = fmt->format;
-               ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format,
+               ipipeif_try_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP,
+                                  format,
                                   fmt->which);
        }
 
@@ -608,7 +615,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd,
        format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
        format.format.width = 4096;
        format.format.height = 4096;
-       ipipeif_set_format(sd, fh ? fh->pad : NULL, &format);
+       ipipeif_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index 3b6875c..a5f8f9f 100644 (file)
@@ -416,11 +416,12 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
 
 static struct v4l2_mbus_framefmt *
 __resizer_get_format(struct iss_resizer_device *resizer,
-                    struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                    struct v4l2_subdev_state *sd_state, unsigned int pad,
                     enum v4l2_subdev_format_whence which)
 {
        if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&resizer->subdev, cfg, pad);
+               return v4l2_subdev_get_try_format(&resizer->subdev, sd_state,
+                                                 pad);
        return &resizer->formats[pad];
 }
 
@@ -433,7 +434,7 @@ __resizer_get_format(struct iss_resizer_device *resizer,
  */
 static void
 resizer_try_format(struct iss_resizer_device *resizer,
-                  struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                  struct v4l2_subdev_state *sd_state, unsigned int pad,
                   struct v4l2_mbus_framefmt *fmt,
                   enum v4l2_subdev_format_whence which)
 {
@@ -461,7 +462,8 @@ resizer_try_format(struct iss_resizer_device *resizer,
 
        case RESIZER_PAD_SOURCE_MEM:
                pixelcode = fmt->code;
-               format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK,
+               format = __resizer_get_format(resizer, sd_state,
+                                             RESIZER_PAD_SINK,
                                              which);
                memcpy(fmt, format, sizeof(*fmt));
 
@@ -492,7 +494,7 @@ resizer_try_format(struct iss_resizer_device *resizer,
  * return -EINVAL or zero on success
  */
 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
@@ -507,7 +509,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
                break;
 
        case RESIZER_PAD_SOURCE_MEM:
-               format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK,
+               format = __resizer_get_format(resizer, sd_state,
+                                             RESIZER_PAD_SINK,
                                              code->which);
 
                if (code->index == 0) {
@@ -537,7 +540,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
@@ -549,7 +552,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = 1;
        format.height = 1;
-       resizer_try_format(resizer, cfg, fse->pad, &format, fse->which);
+       resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which);
        fse->min_width = format.width;
        fse->min_height = format.height;
 
@@ -559,7 +562,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
        format.code = fse->code;
        format.width = -1;
        format.height = -1;
-       resizer_try_format(resizer, cfg, fse->pad, &format, fse->which);
+       resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which);
        fse->max_width = format.width;
        fse->max_height = format.height;
 
@@ -576,13 +579,13 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int resizer_get_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which);
+       format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
@@ -600,26 +603,28 @@ static int resizer_get_format(struct v4l2_subdev *sd,
  * to the format type.
  */
 static int resizer_set_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which);
+       format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which);
        if (!format)
                return -EINVAL;
 
-       resizer_try_format(resizer, cfg, fmt->pad, &fmt->format, fmt->which);
+       resizer_try_format(resizer, sd_state, fmt->pad, &fmt->format,
+                          fmt->which);
        *format = fmt->format;
 
        /* Propagate the format from sink to source */
        if (fmt->pad == RESIZER_PAD_SINK) {
-               format = __resizer_get_format(resizer, cfg,
+               format = __resizer_get_format(resizer, sd_state,
                                              RESIZER_PAD_SOURCE_MEM,
                                              fmt->which);
                *format = fmt->format;
-               resizer_try_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, format,
+               resizer_try_format(resizer, sd_state, RESIZER_PAD_SOURCE_MEM,
+                                  format,
                                   fmt->which);
        }
 
@@ -662,7 +667,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
        format.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
        format.format.width = 4096;
        format.format.height = 4096;
-       resizer_set_format(sd, fh ? fh->pad : NULL, &format);
+       resizer_set_format(sd, fh ? fh->state : NULL, &format);
 
        return 0;
 }
index 930f638..d0da083 100644 (file)
@@ -399,7 +399,7 @@ static void iss_video_buf_queue(struct vb2_buffer *vb)
 
                if (start)
                        omap4iss_pipeline_set_stream(pipe,
-                                               ISS_PIPELINE_STREAM_SINGLESHOT);
+                                                    ISS_PIPELINE_STREAM_SINGLESHOT);
        }
 }
 
@@ -960,7 +960,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
                unsigned long flags;
 
                ret = omap4iss_pipeline_set_stream(pipe,
-                                             ISS_PIPELINE_STREAM_CONTINUOUS);
+                                                  ISS_PIPELINE_STREAM_CONTINUOUS);
                if (ret < 0)
                        goto err_omap4iss_set_stream;
                spin_lock_irqsave(&video->qlock, flags);
index d821661..7131156 100644 (file)
@@ -481,7 +481,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb)
                if (vb2_plane_size(vb, i) < sizeimage)
                        return -EINVAL;
        }
-       vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+       /*
+        * Buffer's bytesused must be written by driver for CAPTURE buffers.
+        * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+        * it to buffer length).
+        */
+       if (V4L2_TYPE_IS_CAPTURE(vq->type))
+               vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
        return 0;
 }
 
@@ -658,7 +666,7 @@ static void rkvdec_device_run(void *priv)
        if (WARN_ON(!desc))
                return;
 
-       ret = pm_runtime_get_sync(rkvdec->dev);
+       ret = pm_runtime_resume_and_get(rkvdec->dev);
        if (ret < 0) {
                rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR);
                return;
index 92812d1..c0d005d 100644 (file)
 static const struct cedrus_control cedrus_controls[] = {
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+                       .id     = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
                },
                .codec          = CEDRUS_CODEC_MPEG2,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+                       .id     = V4L2_CID_STATELESS_MPEG2_PICTURE,
+               },
+               .codec          = CEDRUS_CODEC_MPEG2,
+       },
+       {
+               .cfg = {
+                       .id     = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
                },
                .codec          = CEDRUS_CODEC_MPEG2,
        },
@@ -151,6 +157,12 @@ static const struct cedrus_control cedrus_controls[] = {
                },
                .codec          = CEDRUS_CODEC_VP8,
        },
+       {
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+               },
+               .codec          = CEDRUS_CODEC_H265,
+       },
 };
 
 #define CEDRUS_CONTROLS_COUNT  ARRAY_SIZE(cedrus_controls)
index 15f147d..88afba1 100644 (file)
@@ -68,14 +68,16 @@ struct cedrus_h264_run {
 };
 
 struct cedrus_mpeg2_run {
-       const struct v4l2_ctrl_mpeg2_slice_params       *slice_params;
-       const struct v4l2_ctrl_mpeg2_quantization       *quantization;
+       const struct v4l2_ctrl_mpeg2_sequence           *sequence;
+       const struct v4l2_ctrl_mpeg2_picture            *picture;
+       const struct v4l2_ctrl_mpeg2_quantisation       *quantisation;
 };
 
 struct cedrus_h265_run {
        const struct v4l2_ctrl_hevc_sps                 *sps;
        const struct v4l2_ctrl_hevc_pps                 *pps;
        const struct v4l2_ctrl_hevc_slice_params        *slice_params;
+       const struct v4l2_ctrl_hevc_decode_params       *decode_params;
 };
 
 struct cedrus_vp8_run {
index d696b3e..40e8c41 100644 (file)
@@ -40,10 +40,12 @@ void cedrus_device_run(void *priv)
 
        switch (ctx->src_fmt.pixelformat) {
        case V4L2_PIX_FMT_MPEG2_SLICE:
-               run.mpeg2.slice_params = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
-               run.mpeg2.quantization = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
+               run.mpeg2.sequence = cedrus_find_control_data(ctx,
+                       V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+               run.mpeg2.picture = cedrus_find_control_data(ctx,
+                       V4L2_CID_STATELESS_MPEG2_PICTURE);
+               run.mpeg2.quantisation = cedrus_find_control_data(ctx,
+                       V4L2_CID_STATELESS_MPEG2_QUANTISATION);
                break;
 
        case V4L2_PIX_FMT_H264_SLICE:
@@ -68,6 +70,8 @@ void cedrus_device_run(void *priv)
                        V4L2_CID_MPEG_VIDEO_HEVC_PPS);
                run.h265.slice_params = cedrus_find_control_data(ctx,
                        V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+               run.h265.decode_params = cedrus_find_control_data(ctx,
+                       V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
                break;
 
        case V4L2_PIX_FMT_VP8_FRAME:
index ce497d0..6821e3d 100644 (file)
@@ -245,6 +245,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        const struct v4l2_ctrl_hevc_sps *sps;
        const struct v4l2_ctrl_hevc_pps *pps;
        const struct v4l2_ctrl_hevc_slice_params *slice_params;
+       const struct v4l2_ctrl_hevc_decode_params *decode_params;
        const struct v4l2_hevc_pred_weight_table *pred_weight_table;
        dma_addr_t src_buf_addr;
        dma_addr_t src_buf_end_addr;
@@ -256,6 +257,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        sps = run->h265.sps;
        pps = run->h265.pps;
        slice_params = run->h265.slice_params;
+       decode_params = run->h265.decode_params;
        pred_weight_table = &slice_params->pred_weight_table;
 
        /* MV column buffer size and allocation. */
@@ -477,8 +479,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
                                slice_params->flags);
 
        reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT,
-                               V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT,
-                               pps->flags);
+                               V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT,
+                               slice_params->flags);
 
        /* FIXME: For multi-slice support. */
        reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
@@ -487,7 +489,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) |
-             VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(slice_params->num_rps_poc_st_curr_after == 0) |
+             VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(decode_params->num_poc_st_curr_after == 0) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta);
@@ -527,8 +529,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        cedrus_write(dev, VE_DEC_H265_NEIGHBOR_INFO_ADDR, reg);
 
        /* Write decoded picture buffer in pic list. */
-       cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb,
-                                        slice_params->num_active_dpb_entries);
+       cedrus_h265_frame_info_write_dpb(ctx, decode_params->dpb,
+                                        decode_params->num_active_dpb_entries);
 
        /* Output frame. */
 
@@ -545,7 +547,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        /* Reference picture list 0 (for P/B frames). */
        if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) {
-               cedrus_h265_ref_pic_list_write(dev, slice_params->dpb,
+               cedrus_h265_ref_pic_list_write(dev, decode_params->dpb,
                                               slice_params->ref_idx_l0,
                                               slice_params->num_ref_idx_l0_active_minus1 + 1,
                                               VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0);
@@ -564,7 +566,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        /* Reference picture list 1 (for B frames). */
        if (slice_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) {
-               cedrus_h265_ref_pic_list_write(dev, slice_params->dpb,
+               cedrus_h265_ref_pic_list_write(dev, decode_params->dpb,
                                               slice_params->ref_idx_l1,
                                               slice_params->num_ref_idx_l1_active_minus1 + 1,
                                               VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1);
index 8bcd6b8..5dad2f2 100644 (file)
 #include "cedrus_hw.h"
 #include "cedrus_regs.h"
 
-/* Default MPEG-2 quantization coefficients, from the specification. */
-
-static const u8 intra_quantization_matrix_default[64] = {
-       8,  16, 16, 19, 16, 19, 22, 22,
-       22, 22, 22, 22, 26, 24, 26, 27,
-       27, 27, 26, 26, 26, 26, 27, 27,
-       27, 29, 29, 29, 34, 34, 34, 29,
-       29, 29, 27, 27, 29, 29, 32, 32,
-       34, 34, 37, 38, 37, 35, 35, 34,
-       35, 38, 38, 40, 40, 40, 48, 48,
-       46, 46, 56, 56, 58, 69, 69, 83
-};
-
-static const u8 non_intra_quantization_matrix_default[64] = {
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16,
-       16, 16, 16, 16, 16, 16, 16, 16
-};
-
 static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx)
 {
        struct cedrus_dev *dev = ctx->dev;
@@ -74,10 +50,9 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
 
 static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 {
-       const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
-       const struct v4l2_mpeg2_sequence *sequence;
-       const struct v4l2_mpeg2_picture *picture;
-       const struct v4l2_ctrl_mpeg2_quantization *quantization;
+       const struct v4l2_ctrl_mpeg2_sequence *seq;
+       const struct v4l2_ctrl_mpeg2_picture *pic;
+       const struct v4l2_ctrl_mpeg2_quantisation *quantisation;
        dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
        dma_addr_t fwd_luma_addr, fwd_chroma_addr;
        dma_addr_t bwd_luma_addr, bwd_chroma_addr;
@@ -89,22 +64,16 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
        unsigned int i;
        u32 reg;
 
-       slice_params = run->mpeg2.slice_params;
-       sequence = &slice_params->sequence;
-       picture = &slice_params->picture;
+       seq = run->mpeg2.sequence;
+       pic = run->mpeg2.picture;
 
-       quantization = run->mpeg2.quantization;
+       quantisation = run->mpeg2.quantisation;
 
        /* Activate MPEG engine. */
        cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
 
-       /* Set intra quantization matrix. */
-
-       if (quantization && quantization->load_intra_quantiser_matrix)
-               matrix = quantization->intra_quantiser_matrix;
-       else
-               matrix = intra_quantization_matrix_default;
-
+       /* Set intra quantisation matrix. */
+       matrix = quantisation->intra_quantiser_matrix;
        for (i = 0; i < 64; i++) {
                reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
                reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
@@ -112,13 +81,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
                cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
        }
 
-       /* Set non-intra quantization matrix. */
-
-       if (quantization && quantization->load_non_intra_quantiser_matrix)
-               matrix = quantization->non_intra_quantiser_matrix;
-       else
-               matrix = non_intra_quantization_matrix_default;
-
+       /* Set non-intra quantisation matrix. */
+       matrix = quantisation->non_intra_quantiser_matrix;
        for (i = 0; i < 64; i++) {
                reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
                reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
@@ -128,19 +92,19 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 
        /* Set MPEG picture header. */
 
-       reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type);
-       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]);
-       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]);
-       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]);
-       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]);
-       reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision);
-       reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure);
-       reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first);
-       reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct);
-       reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors);
-       reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type);
-       reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format);
-       reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan);
+       reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type);
+       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]);
+       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]);
+       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]);
+       reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]);
+       reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision);
+       reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure);
+       reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
+       reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
+       reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV);
+       reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE);
+       reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC);
+       reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN);
        reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
        reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
 
@@ -148,8 +112,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 
        /* Set frame dimensions. */
 
-       reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size);
-       reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size);
+       reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size);
+       reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size);
 
        cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
 
@@ -162,14 +126,14 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 
        vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 
-       forward_idx = vb2_find_timestamp(vq, slice_params->forward_ref_ts, 0);
+       forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0);
        fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0);
        fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1);
 
        cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr);
        cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr);
 
-       backward_idx = vb2_find_timestamp(vq, slice_params->backward_ref_ts, 0);
+       backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0);
        bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0);
        bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1);
 
@@ -186,10 +150,9 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 
        /* Source offset and length in bits. */
 
-       cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET,
-                    slice_params->data_bit_offset);
+       cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, 0);
 
-       reg = slice_params->bit_size - slice_params->data_bit_offset;
+       reg = vb2_get_plane_payload(&run->src->vb2_buf, 0) * 8;
        cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
 
        /* Source beginning and end addresses. */
@@ -203,7 +166,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 
        cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
 
-       reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8);
+       reg = src_buf_addr + vb2_get_plane_payload(&run->src->vb2_buf, 0);
        cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
 
        /* Macroblock address: start at the beginning. */
index b62eb8e..32c13ec 100644 (file)
@@ -457,7 +457,13 @@ static int cedrus_buf_prepare(struct vb2_buffer *vb)
        if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
                return -EINVAL;
 
-       vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+       /*
+        * Buffer's bytesused must be written by driver for CAPTURE buffers.
+        * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+        * it to buffer length).
+        */
+       if (V4L2_TYPE_IS_CAPTURE(vq->type))
+               vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
 
        return 0;
 }
@@ -490,11 +496,9 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
        }
 
        if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
-               ret = pm_runtime_get_sync(dev->dev);
-               if (ret < 0) {
-                       pm_runtime_put_noidle(dev->dev);
+               ret = pm_runtime_resume_and_get(dev->dev);
+               if (ret < 0)
                        goto err_cleanup;
-               }
 
                if (dev->dec_ops[ctx->current_codec]->start) {
                        ret = dev->dec_ops[ctx->current_codec]->start(ctx);
index 28845b5..ed4c125 100644 (file)
@@ -775,9 +775,9 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
        if (ret)
                goto release_dpb_frames;
 
-       ret = pm_runtime_get_sync(dev);
+       ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto put_runtime_pm;
+               goto unlock;
 
        /*
         * We rely on the VDE registers reset value, otherwise VDE
@@ -843,6 +843,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
 put_runtime_pm:
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
+
+unlock:
        mutex_unlock(&vde->lock);
 
 release_dpb_frames:
@@ -1069,11 +1071,20 @@ static int tegra_vde_probe(struct platform_device *pdev)
         * power-cycle it in order to put hardware into a predictable lower
         * power state.
         */
-       pm_runtime_get_sync(dev);
+       err = pm_runtime_resume_and_get(dev);
+       if (err)
+               goto err_pm_runtime;
+
        pm_runtime_put(dev);
 
        return 0;
 
+err_pm_runtime:
+       misc_deregister(&vde->miscdev);
+
+       pm_runtime_dont_use_autosuspend(dev);
+       pm_runtime_disable(dev);
+
 err_deinit_iommu:
        tegra_vde_iommu_deinit(vde);
 
@@ -1089,7 +1100,12 @@ static int tegra_vde_remove(struct platform_device *pdev)
        struct tegra_vde *vde = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
 
+       /*
+        * As it increments RPM usage_count even on errors, we don't need to
+        * check the returned code here.
+        */
        pm_runtime_get_sync(dev);
+
        pm_runtime_dont_use_autosuspend(dev);
        pm_runtime_disable(dev);
 
index 033a693..b26e44a 100644 (file)
@@ -64,7 +64,7 @@ static const struct v4l2_frmsize_discrete tegra_csi_tpg_sizes[] = {
  * V4L2 Subdevice Pad Operations
  */
 static int csi_enum_bus_code(struct v4l2_subdev *subdev,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_mbus_code_enum *code)
 {
        if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
@@ -79,7 +79,7 @@ static int csi_enum_bus_code(struct v4l2_subdev *subdev,
 }
 
 static int csi_get_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -127,7 +127,7 @@ static void csi_chan_update_blank_intervals(struct tegra_csi_channel *csi_chan,
 }
 
 static int csi_enum_framesizes(struct v4l2_subdev *subdev,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_frame_size_enum *fse)
 {
        unsigned int i;
@@ -154,7 +154,7 @@ static int csi_enum_framesizes(struct v4l2_subdev *subdev,
 }
 
 static int csi_enum_frameintervals(struct v4l2_subdev *subdev,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_interval_enum *fie)
 {
        struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -181,7 +181,7 @@ static int csi_enum_frameintervals(struct v4l2_subdev *subdev,
 }
 
 static int csi_set_format(struct v4l2_subdev *subdev,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -298,10 +298,9 @@ static int tegra_csi_enable_stream(struct v4l2_subdev *subdev)
        struct tegra_csi *csi = csi_chan->csi;
        int ret, err;
 
-       ret = pm_runtime_get_sync(csi->dev);
+       ret = pm_runtime_resume_and_get(csi->dev);
        if (ret < 0) {
                dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
-               pm_runtime_put_noidle(csi->dev);
                return ret;
        }
 
index df5ca35..89709cd 100644 (file)
@@ -297,10 +297,9 @@ static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count)
        struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
        int ret;
 
-       ret = pm_runtime_get_sync(chan->vi->dev);
+       ret = pm_runtime_resume_and_get(chan->vi->dev);
        if (ret < 0) {
                dev_err(chan->vi->dev, "failed to get runtime PM: %d\n", ret);
-               pm_runtime_put_noidle(chan->vi->dev);
                return ret;
        }
 
@@ -494,7 +493,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
        const struct tegra_video_format *fmtinfo;
        struct v4l2_subdev *subdev;
        struct v4l2_subdev_format fmt;
-       struct v4l2_subdev_pad_config *pad_cfg;
+       struct v4l2_subdev_state *sd_state;
        struct v4l2_subdev_frame_size_enum fse = {
                .which = V4L2_SUBDEV_FORMAT_TRY,
        };
@@ -508,8 +507,8 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
        if (!subdev)
                return -ENODEV;
 
-       pad_cfg = v4l2_subdev_alloc_pad_config(subdev);
-       if (!pad_cfg)
+       sd_state = v4l2_subdev_alloc_state(subdev);
+       if (!sd_state)
                return -ENOMEM;
        /*
         * Retrieve the format information and if requested format isn't
@@ -533,33 +532,33 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
         * If not available, try to get crop boundary from subdev.
         */
        fse.code = fmtinfo->code;
-       ret = v4l2_subdev_call(subdev, pad, enum_frame_size, pad_cfg, &fse);
+       ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse);
        if (ret) {
                if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
-                       pad_cfg->try_crop.width = 0;
-                       pad_cfg->try_crop.height = 0;
+                       sd_state->pads->try_crop.width = 0;
+                       sd_state->pads->try_crop.height = 0;
                } else {
                        ret = v4l2_subdev_call(subdev, pad, get_selection,
                                               NULL, &sdsel);
                        if (ret)
                                return -EINVAL;
 
-                       pad_cfg->try_crop.width = sdsel.r.width;
-                       pad_cfg->try_crop.height = sdsel.r.height;
+                       sd_state->pads->try_crop.width = sdsel.r.width;
+                       sd_state->pads->try_crop.height = sdsel.r.height;
                }
        } else {
-               pad_cfg->try_crop.width = fse.max_width;
-               pad_cfg->try_crop.height = fse.max_height;
+               sd_state->pads->try_crop.width = fse.max_width;
+               sd_state->pads->try_crop.height = fse.max_height;
        }
 
-       ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt);
+       ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
        if (ret < 0)
                return ret;
 
        v4l2_fill_pix_format(pix, &fmt.format);
        tegra_channel_fmt_align(chan, pix, fmtinfo->bpp);
 
-       v4l2_subdev_free_pad_config(pad_cfg);
+       v4l2_subdev_free_state(sd_state);
 
        return 0;
 }
@@ -1812,8 +1811,8 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
                        continue;
                }
 
-               tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier,
-                               remote, struct tegra_vi_graph_entity);
+               tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier, remote,
+                                                            struct tegra_vi_graph_entity);
                if (IS_ERR(tvge)) {
                        ret = PTR_ERR(tvge);
                        dev_err(vi->dev,
index e7fe8da..b1ad2a2 100644 (file)
@@ -158,7 +158,6 @@ struct zoran_jpg_settings {
        struct v4l2_jpegcompression jpg_comp;   /* JPEG-specific capture settings */
 };
 
-
 struct zoran;
 
 /* zoran_fh contains per-open() settings */
index dfc60e2..f259585 100644 (file)
@@ -37,9 +37,10 @@ module_param_array(card, int, NULL, 0444);
 MODULE_PARM_DESC(card, "Card type");
 
 /*
- * The video mem address of the video card. The driver has a little database for some videocards
- * to determine it from there. If your video card is not in there you have either to give it to
- * the driver as a parameter or set in in a VIDIOCSFBUF ioctl
+ * The video mem address of the video card. The driver has a little database
+ * for some videocards to determine it from there. If your video card is not
+ * in there you have either to give it to the driver as a parameter or set
+ * in a VIDIOCSFBUF ioctl
  */
 
 static unsigned long vidmem;   /* default = 0 - Video memory base address */
index cf788d9..5b12a73 100644 (file)
@@ -148,71 +148,6 @@ int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg)
 }
 
 /*
- * detect guests
- */
-
-static void dump_guests(struct zoran *zr)
-{
-       if (zr36067_debug > 2) {
-               int i, guest[8];
-
-               /* do not print random data */
-               guest[0] = 0;
-
-               for (i = 1; i < 8; i++) /* Don't read jpeg codec here */
-                       guest[i] = post_office_read(zr, i, 0);
-
-               pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest);
-       }
-}
-
-void detect_guest_activity(struct zoran *zr)
-{
-       int timeout, i, j, res, guest[8], guest0[8], change[8][3];
-       ktime_t t0, t1;
-
-       /* do not print random data */
-       guest[0] = 0;
-       guest0[0] = 0;
-
-       dump_guests(zr);
-       pci_info(zr->pci_dev, "Detecting guests activity, please wait...\n");
-       for (i = 1; i < 8; i++) /* Don't read jpeg codec here */
-               guest0[i] = guest[i] = post_office_read(zr, i, 0);
-
-       timeout = 0;
-       j = 0;
-       t0 = ktime_get();
-       while (timeout < 10000) {
-               udelay(10);
-               timeout++;
-               for (i = 1; (i < 8) && (j < 8); i++) {
-                       res = post_office_read(zr, i, 0);
-                       if (res != guest[i]) {
-                               t1 = ktime_get();
-                               change[j][0] = ktime_to_us(ktime_sub(t1, t0));
-                               t0 = t1;
-                               change[j][1] = i;
-                               change[j][2] = res;
-                               j++;
-                               guest[i] = res;
-                       }
-               }
-               if (j >= 8)
-                       break;
-       }
-
-       pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest0);
-
-       if (j == 0) {
-               pci_info(zr->pci_dev, "No activity detected.\n");
-               return;
-       }
-       for (i = 0; i < j; i++)
-               pci_info(zr->pci_dev, "%6d: %d => 0x%02x\n", change[i][0], change[i][1], change[i][2]);
-}
-
-/*
  * JPEG Codec access
  */
 
index 24be19a..6c5d702 100644 (file)
@@ -20,8 +20,6 @@ extern int post_office_wait(struct zoran *zr);
 extern int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, unsigned int value);
 extern int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg);
 
-extern void detect_guest_activity(struct zoran *zr);
-
 extern void jpeg_codec_sleep(struct zoran *zr, int sleep);
 extern int jpeg_codec_reset(struct zoran *zr);
 
index e8902f8..46382e4 100644 (file)
@@ -678,12 +678,14 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio
                sel->r.height = zr->jpg_settings.img_height;
                break;
        case V4L2_SEL_TGT_CROP_DEFAULT:
-               sel->r.top = sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.left = 0;
                sel->r.width = BUZ_MIN_WIDTH;
                sel->r.height = BUZ_MIN_HEIGHT;
                break;
        case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.top = sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.left = 0;
                sel->r.width = BUZ_MAX_WIDTH;
                sel->r.height = BUZ_MAX_HEIGHT;
                break;
index 2d7dc7a..9b350a8 100644 (file)
@@ -361,7 +361,8 @@ static int zr36016_setup(struct videocodec *codec)
                return -ENOSPC;
        }
        //mem structure init
-       codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL);
+       ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+       codec->data = ptr;
        if (!ptr)
                return -ENOMEM;
 
index 2826f4e..c62af27 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/wait.h>
 
 /* I/O commands, error codes */
-#include <asm/io.h>
+#include <linux/io.h>
 
 /* headerfile of this module */
 #include "zr36050.h"
@@ -754,7 +754,8 @@ static int zr36050_setup(struct videocodec *codec)
                return -ENOSPC;
        }
        //mem structure init
-       codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL);
+       ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+       codec->data = ptr;
        if (!ptr)
                return -ENOMEM;
 
index 71b651a..a2a75fd 100644 (file)
 #define ZR36057_VFESPFR_HOR_DCM          14
 #define ZR36057_VFESPFR_VER_DCM          8
 #define ZR36057_VFESPFR_DISP_MODE        6
-#define ZR36057_VFESPFR_YUV422          (0<<3)
-#define ZR36057_VFESPFR_RGB888          (1<<3)
-#define ZR36057_VFESPFR_RGB565          (2<<3)
-#define ZR36057_VFESPFR_RGB555          (3<<3)
-#define ZR36057_VFESPFR_ERR_DIF          (1<<2)
-#define ZR36057_VFESPFR_PACK24          (1<<1)
-#define ZR36057_VFESPFR_LITTLE_ENDIAN    (1<<0)
+#define ZR36057_VFESPFR_YUV422          (0 << 3)
+#define ZR36057_VFESPFR_RGB888          (1 << 3)
+#define ZR36057_VFESPFR_RGB565          (2 << 3)
+#define ZR36057_VFESPFR_RGB555          (3 << 3)
+#define ZR36057_VFESPFR_ERR_DIF          (1 << 2)
+#define ZR36057_VFESPFR_PACK24          (1 << 1)
+#define ZR36057_VFESPFR_LITTLE_ENDIAN    (1 << 0)
 
 #define ZR36057_VDTR            0x00c  /* Video Display "Top" Register */
 
index 4f9eb9f..1c3af11 100644 (file)
@@ -790,7 +790,8 @@ static int zr36060_setup(struct videocodec *codec)
                return -ENOSPC;
        }
        //mem structure init
-       codec->data = ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+       ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+       codec->data = ptr;
        if (!ptr)
                return -ENOMEM;
 
index f27f20a..a1cd81d 100644 (file)
 #include <linux/module.h>
 #include <linux/usb/hcd.h>
 #include <linux/prefetch.h>
+#include <linux/irqdomain.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <asm/octeon/octeon.h>
 
index ffa1cf4..4378592 100644 (file)
@@ -2284,7 +2284,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str
        mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
        mon_ndev->ieee80211_ptr = mon_wdev;
 
-       ret = register_netdevice(mon_ndev);
+       ret = cfg80211_register_netdevice(mon_ndev);
        if (ret) {
                goto out;
        }
@@ -2360,7 +2360,7 @@ static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
        adapter = rtw_netdev_priv(ndev);
        pwdev_priv = adapter_wdev_data(adapter);
 
-       unregister_netdevice(ndev);
+       cfg80211_unregister_netdevice(ndev);
 
        if (ndev == pwdev_priv->pmon_ndev) {
                pwdev_priv->pmon_ndev = NULL;
index 480d294..2b37bc4 100644 (file)
@@ -452,6 +452,7 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
                        if (put_user((u64)p->u.memref.size, &up->b))
                                return -EFAULT;
+                       break;
                default:
                        break;
                }
index eeb4e4b..43b1ae8 100644 (file)
@@ -478,7 +478,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
        ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
        if (ret >= 0) {
                cpufreq_cdev->cpufreq_state = state;
-               cpus = cpufreq_cdev->policy->cpus;
+               cpus = cpufreq_cdev->policy->related_cpus;
                max_capacity = arch_scale_cpu_capacity(cpumask_first(cpus));
                capacity = frequency * max_capacity;
                capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
index d20b25f..10a2d8e 100644 (file)
@@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
-static DEFINE_MUTEX(poweroff_lock);
 
 static atomic_t in_suspend;
-static bool power_off_triggered;
 
 static struct thermal_governor *def_governor;
 
@@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip)
                       def_governor->throttle(tz, trip);
 }
 
-/**
- * thermal_emergency_poweroff_func - emergency poweroff work after a known delay
- * @work: work_struct associated with the emergency poweroff function
- *
- * This function is called in very critical situations to force
- * a kernel poweroff after a configurable timeout value.
- */
-static void thermal_emergency_poweroff_func(struct work_struct *work)
-{
-       /*
-        * We have reached here after the emergency thermal shutdown
-        * Waiting period has expired. This means orderly_poweroff has
-        * not been able to shut off the system for some reason.
-        * Try to shut down the system immediately using kernel_power_off
-        * if populated
-        */
-       WARN(1, "Attempting kernel_power_off: Temperature too high\n");
-       kernel_power_off();
-
-       /*
-        * Worst of the worst case trigger emergency restart
-        */
-       WARN(1, "Attempting emergency_restart: Temperature too high\n");
-       emergency_restart();
-}
-
-static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work,
-                           thermal_emergency_poweroff_func);
-
-/**
- * thermal_emergency_poweroff - Trigger an emergency system poweroff
- *
- * This may be called from any critical situation to trigger a system shutdown
- * after a known period of time. By default this is not scheduled.
- */
-static void thermal_emergency_poweroff(void)
+void thermal_zone_device_critical(struct thermal_zone_device *tz)
 {
-       int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
        /*
         * poweroff_delay_ms must be a carefully profiled positive value.
-        * Its a must for thermal_emergency_poweroff_work to be scheduled
+        * Its a must for forced_emergency_poweroff_work to be scheduled.
         */
-       if (poweroff_delay_ms <= 0)
-               return;
-       schedule_delayed_work(&thermal_emergency_poweroff_work,
-                             msecs_to_jiffies(poweroff_delay_ms));
-}
+       int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
 
-void thermal_zone_device_critical(struct thermal_zone_device *tz)
-{
        dev_emerg(&tz->device, "%s: critical temperature reached, "
                  "shutting down\n", tz->type);
 
-       mutex_lock(&poweroff_lock);
-       if (!power_off_triggered) {
-               /*
-                * Queue a backup emergency shutdown in the event of
-                * orderly_poweroff failure
-                */
-               thermal_emergency_poweroff();
-               orderly_poweroff(true);
-               power_off_triggered = true;
-       }
-       mutex_unlock(&poweroff_lock);
+       hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
 }
 EXPORT_SYMBOL(thermal_zone_device_critical);
 
@@ -1538,7 +1484,6 @@ error:
        ida_destroy(&thermal_cdev_ida);
        mutex_destroy(&thermal_list_lock);
        mutex_destroy(&thermal_governor_lock);
-       mutex_destroy(&poweroff_lock);
        return result;
 }
 postcore_initcall(thermal_init);
index 4545b23..bac0f54 100644 (file)
@@ -686,6 +686,16 @@ static int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data)
        int val;
        unsigned long flags;
 
+       /* Clear VDATSRCENB0 to disable VDP_SRC and IDM_SNK required by BC 1.2 spec */
+       spin_lock_irqsave(&usbmisc->lock, flags);
+       val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+       val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0;
+       writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+       spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+       /* TVDMSRC_DIS */
+       msleep(20);
+
        /* VDM_SRC is connected to D- and IDP_SINK is connected to D+ */
        spin_lock_irqsave(&usbmisc->lock, flags);
        val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
@@ -695,7 +705,8 @@ static int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data)
                                usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
        spin_unlock_irqrestore(&usbmisc->lock, flags);
 
-       usleep_range(1000, 2000);
+       /* TVDMSRC_ON */
+       msleep(40);
 
        /*
         * Per BC 1.2, check voltage of D+:
@@ -798,7 +809,8 @@ static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data)
                                usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
        spin_unlock_irqrestore(&usbmisc->lock, flags);
 
-       usleep_range(1000, 2000);
+       /* TVDPSRC_ON */
+       msleep(40);
 
        /* Check if D- is less than VDAT_REF to determine an SDP per BC 1.2 */
        val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
index fc7d6cd..df8e69e 100644 (file)
@@ -41,6 +41,8 @@
 #define USB_VENDOR_GENESYS_LOGIC               0x05e3
 #define USB_VENDOR_SMSC                                0x0424
 #define USB_PRODUCT_USB5534B                   0x5534
+#define USB_VENDOR_CYPRESS                     0x04b4
+#define USB_PRODUCT_CY7C65632                  0x6570
 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND       0x01
 #define HUB_QUIRK_DISABLE_AUTOSUSPEND          0x02
 
@@ -5698,6 +5700,11 @@ static const struct usb_device_id hub_id_table[] = {
       .bInterfaceClass = USB_CLASS_HUB,
       .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
     { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+                   | USB_DEVICE_ID_MATCH_PRODUCT,
+      .idVendor = USB_VENDOR_CYPRESS,
+      .idProduct = USB_PRODUCT_CY7C65632,
+      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
+    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
                        | USB_DEVICE_ID_MATCH_INT_CLASS,
       .idVendor = USB_VENDOR_GENESYS_LOGIC,
       .bInterfaceClass = USB_CLASS_HUB,
index 21129d3..4ac397e 100644 (file)
@@ -1671,8 +1671,8 @@ static int dwc3_remove(struct platform_device *pdev)
 
        pm_runtime_get_sync(&pdev->dev);
 
-       dwc3_debugfs_exit(dwc);
        dwc3_core_exit_mode(dwc);
+       dwc3_debugfs_exit(dwc);
 
        dwc3_core_exit(dwc);
        dwc3_ulpi_exit(dwc);
index 3517954..34f4db5 100644 (file)
@@ -509,8 +509,7 @@ static irqreturn_t max3420_vbus_handler(int irq, void *dev_id)
                             ? USB_STATE_POWERED : USB_STATE_NOTATTACHED);
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       if (udc->thread_task &&
-           udc->thread_task->state != TASK_RUNNING)
+       if (udc->thread_task)
                wake_up_process(udc->thread_task);
 
        return IRQ_HANDLED;
@@ -529,8 +528,7 @@ static irqreturn_t max3420_irq_handler(int irq, void *dev_id)
        }
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       if (udc->thread_task &&
-           udc->thread_task->state != TASK_RUNNING)
+       if (udc->thread_task)
                wake_up_process(udc->thread_task);
 
        return IRQ_HANDLED;
@@ -1093,8 +1091,7 @@ static int max3420_wakeup(struct usb_gadget *gadget)
 
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       if (udc->thread_task &&
-           udc->thread_task->state != TASK_RUNNING)
+       if (udc->thread_task)
                wake_up_process(udc->thread_task);
        return ret;
 }
@@ -1117,8 +1114,7 @@ static int max3420_udc_start(struct usb_gadget *gadget,
        udc->todo |= UDC_START;
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       if (udc->thread_task &&
-           udc->thread_task->state != TASK_RUNNING)
+       if (udc->thread_task)
                wake_up_process(udc->thread_task);
 
        return 0;
@@ -1137,8 +1133,7 @@ static int max3420_udc_stop(struct usb_gadget *gadget)
        udc->todo |= UDC_START;
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       if (udc->thread_task &&
-           udc->thread_task->state != TASK_RUNNING)
+       if (udc->thread_task)
                wake_up_process(udc->thread_task);
 
        return 0;
index afd9174..e7a8e06 100644 (file)
@@ -1169,8 +1169,7 @@ max3421_irq_handler(int irq, void *dev_id)
        struct spi_device *spi = to_spi_device(hcd->self.controller);
        struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
 
-       if (max3421_hcd->spi_thread &&
-           max3421_hcd->spi_thread->state != TASK_RUNNING)
+       if (max3421_hcd->spi_thread)
                wake_up_process(max3421_hcd->spi_thread);
        if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo))
                disable_irq_nosync(spi->irq);
index 50bb91b..c738767 100644 (file)
@@ -917,7 +917,6 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
        struct xhci_op_regs __iomem *op;
        unsigned long timeout;
        time64_t timestamp;
-       struct tm time;
        u64 address;
        u32 value;
        int err;
@@ -1014,11 +1013,8 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
        }
 
        timestamp = le32_to_cpu(header->fwimg_created_time);
-       time64_to_tm(timestamp, 0, &time);
 
-       dev_info(dev, "Firmware timestamp: %ld-%02d-%02d %02d:%02d:%02d UTC\n",
-                time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
-                time.tm_hour, time.tm_min, time.tm_sec);
+       dev_info(dev, "Firmware timestamp: %ptTs UTC\n", &timestamp);
 
        return 0;
 }
index 743377c..73f2221 100644 (file)
@@ -174,6 +174,7 @@ static inline void zf_set_timer(unsigned short new, unsigned char n)
                fallthrough;
        case WD2:
                zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
+               fallthrough;
        default:
                return;
        }
index fde9e73..391c774 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/delay.h>
 #include <linux/cpu.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mipsregs.h>
 #include <asm/uasm.h>
index 7bbfd58..d7e361f 100644 (file)
@@ -642,6 +642,9 @@ static void xen_irq_lateeoi_locked(struct irq_info *info, bool spurious)
        }
 
        info->eoi_time = 0;
+
+       /* is_active hasn't been reset yet, do it now. */
+       smp_store_release(&info->is_active, 0);
        do_unmask(info, EVT_MASK_REASON_EOI_PENDING);
 }
 
@@ -811,6 +814,7 @@ static void xen_evtchn_close(evtchn_port_t port)
                BUG();
 }
 
+/* Not called for lateeoi events. */
 static void event_handler_exit(struct irq_info *info)
 {
        smp_store_release(&info->is_active, 0);
@@ -1883,7 +1887,12 @@ static void lateeoi_ack_dynirq(struct irq_data *data)
 
        if (VALID_EVTCHN(evtchn)) {
                do_mask(info, EVT_MASK_REASON_EOI_PENDING);
-               event_handler_exit(info);
+               /*
+                * Don't call event_handler_exit().
+                * Need to keep is_active non-zero in order to ignore re-raised
+                * events after cpu affinity changes while a lateeoi is pending.
+                */
+               clear_evtchn(evtchn);
        }
 }
 
index b297525..179004b 100644 (file)
@@ -203,8 +203,8 @@ static int __init afs_init(void)
                goto error_fs;
 
        afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs");
-       if (IS_ERR(afs_proc_symlink)) {
-               ret = PTR_ERR(afs_proc_symlink);
+       if (!afs_proc_symlink) {
+               ret = -ENOMEM;
                goto error_proc;
        }
 
index a523bb8..3104b62 100644 (file)
@@ -118,6 +118,15 @@ int afs_write_end(struct file *file, struct address_space *mapping,
        _enter("{%llx:%llu},{%lx}",
               vnode->fid.vid, vnode->fid.vnode, page->index);
 
+       if (!PageUptodate(page)) {
+               if (copied < len) {
+                       copied = 0;
+                       goto out;
+               }
+
+               SetPageUptodate(page);
+       }
+
        if (copied == 0)
                goto out;
 
@@ -132,8 +141,6 @@ int afs_write_end(struct file *file, struct address_space *mapping,
                write_sequnlock(&vnode->cb_lock);
        }
 
-       ASSERT(PageUptodate(page));
-
        if (PagePrivate(page)) {
                priv = page_private(page);
                f = afs_page_dirty_from(page, priv);
@@ -837,6 +844,7 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
        struct inode *inode = file_inode(file);
        struct afs_vnode *vnode = AFS_FS_I(inode);
        unsigned long priv;
+       vm_fault_t ret = VM_FAULT_RETRY;
 
        _enter("{{%llx:%llu}},{%lx}", vnode->fid.vid, vnode->fid.vnode, page->index);
 
@@ -848,14 +856,14 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
 #ifdef CONFIG_AFS_FSCACHE
        if (PageFsCache(page) &&
            wait_on_page_fscache_killable(page) < 0)
-               return VM_FAULT_RETRY;
+               goto out;
 #endif
 
        if (wait_on_page_writeback_killable(page))
-               return VM_FAULT_RETRY;
+               goto out;
 
        if (lock_page_killable(page) < 0)
-               return VM_FAULT_RETRY;
+               goto out;
 
        /* We mustn't change page->private until writeback is complete as that
         * details the portion of the page we need to write back and we might
@@ -863,7 +871,7 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
         */
        if (wait_on_page_writeback_killable(page) < 0) {
                unlock_page(page);
-               return VM_FAULT_RETRY;
+               goto out;
        }
 
        priv = afs_page_dirty(page, 0, thp_size(page));
@@ -877,8 +885,10 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
        }
        file_update_time(file);
 
+       ret = VM_FAULT_LOCKED;
+out:
        sb_end_pagefault(inode->i_sb);
-       return VM_FAULT_LOCKED;
+       return ret;
 }
 
 /*
index 187b3f2..3d73cbb 100644 (file)
@@ -1537,7 +1537,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 {
        const struct cred *cred;
        unsigned int i, len;
-       
+       unsigned int state;
+
        /* first copy the parameters from user space */
        memset(psinfo, 0, sizeof(struct elf_prpsinfo));
 
@@ -1559,7 +1560,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        psinfo->pr_pgrp = task_pgrp_vnr(p);
        psinfo->pr_sid = task_session_vnr(p);
 
-       i = p->state ? ffz(~p->state) + 1 : 0;
+       state = READ_ONCE(p->__state);
+       i = state ? ffz(~state) + 1 : 0;
        psinfo->pr_state = i;
        psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
        psinfo->pr_zomb = psinfo->pr_sname == 'Z';
@@ -1571,7 +1573,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
        rcu_read_unlock();
        strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
-       
+
        return 0;
 }
 
index 2c99b10..ab9c31d 100644 (file)
@@ -1331,6 +1331,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
 {
        const struct cred *cred;
        unsigned int i, len;
+       unsigned int state;
 
        /* first copy the parameters from user space */
        memset(psinfo, 0, sizeof(struct elf_prpsinfo));
@@ -1353,7 +1354,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        psinfo->pr_pgrp = task_pgrp_vnr(p);
        psinfo->pr_sid = task_session_vnr(p);
 
-       i = p->state ? ffz(~p->state) + 1 : 0;
+       state = READ_ONCE(p->__state);
+       i = state ? ffz(~state) + 1 : 0;
        psinfo->pr_state = i;
        psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];
        psinfo->pr_zomb = psinfo->pr_sname == 'Z';
index 68b95ad..520a0f6 100644 (file)
@@ -18,6 +18,8 @@ config BTRFS_FS
        select RAID6_PQ
        select XOR_BLOCKS
        select SRCU
+       depends on !PPC_256K_PAGES      # powerpc
+       depends on !PAGE_SIZE_256KB     # hexagon
 
        help
          Btrfs is a general purpose copy-on-write filesystem with extents,
index 117d423..7a8a2fc 100644 (file)
@@ -2675,7 +2675,7 @@ static int handle_direct_tree_backref(struct btrfs_backref_cache *cache,
  *
  * @ref_key:   The same as @ref_key in  handle_direct_tree_backref()
  * @tree_key:  The first key of this tree block.
- * @path:      A clean (released) path, to avoid allocating path everytime
+ * @path:      A clean (released) path, to avoid allocating path every time
  *             the function get called.
  */
 static int handle_indirect_tree_backref(struct btrfs_backref_cache *cache,
index aa57bdc..38b127b 100644 (file)
@@ -1399,7 +1399,6 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                btrfs_space_info_update_bytes_pinned(fs_info, space_info,
                                                     -block_group->pinned);
                space_info->bytes_readonly += block_group->pinned;
-               __btrfs_mod_total_bytes_pinned(space_info, -block_group->pinned);
                block_group->pinned = 0;
 
                spin_unlock(&block_group->lock);
@@ -1491,7 +1490,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
                container_of(work, struct btrfs_fs_info, reclaim_bgs_work);
        struct btrfs_block_group *bg;
        struct btrfs_space_info *space_info;
-       int ret;
+       LIST_HEAD(again_list);
 
        if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))
                return;
@@ -1502,6 +1501,8 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
        mutex_lock(&fs_info->reclaim_bgs_lock);
        spin_lock(&fs_info->unused_bgs_lock);
        while (!list_empty(&fs_info->reclaim_bgs)) {
+               int ret = 0;
+
                bg = list_first_entry(&fs_info->reclaim_bgs,
                                      struct btrfs_block_group,
                                      bg_list);
@@ -1547,9 +1548,13 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
                                  bg->start);
 
 next:
-               btrfs_put_block_group(bg);
                spin_lock(&fs_info->unused_bgs_lock);
+               if (ret == -EAGAIN && list_empty(&bg->bg_list))
+                       list_add_tail(&bg->bg_list, &again_list);
+               else
+                       btrfs_put_block_group(bg);
        }
+       list_splice_tail(&again_list, &fs_info->reclaim_bgs);
        spin_unlock(&fs_info->unused_bgs_lock);
        mutex_unlock(&fs_info->reclaim_bgs_lock);
        btrfs_exclop_finish(fs_info);
@@ -2442,16 +2447,16 @@ void btrfs_dec_block_group_ro(struct btrfs_block_group *cache)
        spin_lock(&sinfo->lock);
        spin_lock(&cache->lock);
        if (!--cache->ro) {
-               num_bytes = cache->length - cache->reserved -
-                           cache->pinned - cache->bytes_super -
-                           cache->zone_unusable - cache->used;
-               sinfo->bytes_readonly -= num_bytes;
                if (btrfs_is_zoned(cache->fs_info)) {
                        /* Migrate zone_unusable bytes back */
                        cache->zone_unusable = cache->alloc_offset - cache->used;
                        sinfo->bytes_zone_unusable += cache->zone_unusable;
                        sinfo->bytes_readonly -= cache->zone_unusable;
                }
+               num_bytes = cache->length - cache->reserved -
+                           cache->pinned - cache->bytes_super -
+                           cache->zone_unusable - cache->used;
+               sinfo->bytes_readonly -= num_bytes;
                list_del_init(&cache->ro_list);
        }
        spin_unlock(&cache->lock);
@@ -2505,7 +2510,7 @@ static int cache_save_setup(struct btrfs_block_group *block_group,
        struct extent_changeset *data_reserved = NULL;
        u64 alloc_hint = 0;
        int dcs = BTRFS_DC_ERROR;
-       u64 num_pages = 0;
+       u64 cache_size = 0;
        int retries = 0;
        int ret = 0;
 
@@ -2617,20 +2622,20 @@ again:
         * taking up quite a bit since it's not folded into the other space
         * cache.
         */
-       num_pages = div_u64(block_group->length, SZ_256M);
-       if (!num_pages)
-               num_pages = 1;
+       cache_size = div_u64(block_group->length, SZ_256M);
+       if (!cache_size)
+               cache_size = 1;
 
-       num_pages *= 16;
-       num_pages *= PAGE_SIZE;
+       cache_size *= 16;
+       cache_size *= fs_info->sectorsize;
 
        ret = btrfs_check_data_free_space(BTRFS_I(inode), &data_reserved, 0,
-                                         num_pages);
+                                         cache_size);
        if (ret)
                goto out_put;
 
-       ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
-                                             num_pages, num_pages,
+       ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, cache_size,
+                                             cache_size, cache_size,
                                              &alloc_hint);
        /*
         * Our cache requires contiguous chunks so that we don't modify a bunch
@@ -3062,8 +3067,6 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
 
-                       __btrfs_mod_total_bytes_pinned(cache->space_info,
-                                                      num_bytes);
                        set_extent_dirty(&trans->transaction->pinned_extents,
                                         bytenr, bytenr + num_bytes - 1,
                                         GFP_NOFS | __GFP_NOFAIL);
index 1346d69..9a023ae 100644 (file)
@@ -149,7 +149,7 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
        const u32 csum_size = fs_info->csum_size;
        const u32 sectorsize = fs_info->sectorsize;
        struct page *page;
-       unsigned long i;
+       unsigned int i;
        char *kaddr;
        u8 csum[BTRFS_CSUM_SIZE];
        struct compressed_bio *cb = bio->bi_private;
@@ -208,7 +208,7 @@ static void end_compressed_bio_read(struct bio *bio)
        struct compressed_bio *cb = bio->bi_private;
        struct inode *inode;
        struct page *page;
-       unsigned long index;
+       unsigned int index;
        unsigned int mirror = btrfs_io_bio(bio)->mirror_num;
        int ret = 0;
 
@@ -334,7 +334,7 @@ static void end_compressed_bio_write(struct bio *bio)
        struct compressed_bio *cb = bio->bi_private;
        struct inode *inode;
        struct page *page;
-       unsigned long index;
+       unsigned int index;
 
        if (bio->bi_status)
                cb->errors = 1;
@@ -349,12 +349,10 @@ static void end_compressed_bio_write(struct bio *bio)
         * call back into the FS and do all the end_io operations
         */
        inode = cb->inode;
-       cb->compressed_pages[0]->mapping = cb->inode->i_mapping;
        btrfs_record_physical_zoned(inode, cb->start, bio);
-       btrfs_writepage_endio_finish_ordered(cb->compressed_pages[0],
+       btrfs_writepage_endio_finish_ordered(BTRFS_I(inode), NULL,
                        cb->start, cb->start + cb->len - 1,
                        bio->bi_status == BLK_STS_OK);
-       cb->compressed_pages[0]->mapping = NULL;
 
        end_compressed_writeback(inode, cb);
        /* note, our inode could be gone now */
@@ -387,10 +385,10 @@ out:
  * the end io hooks.
  */
 blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
-                                unsigned long len, u64 disk_start,
-                                unsigned long compressed_len,
+                                unsigned int len, u64 disk_start,
+                                unsigned int compressed_len,
                                 struct page **compressed_pages,
-                                unsigned long nr_pages,
+                                unsigned int nr_pages,
                                 unsigned int write_flags,
                                 struct cgroup_subsys_state *blkcg_css)
 {
@@ -427,24 +425,16 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
        bio->bi_end_io = end_compressed_bio_write;
 
        if (use_append) {
-               struct extent_map *em;
-               struct map_lookup *map;
-               struct block_device *bdev;
+               struct btrfs_device *device;
 
-               em = btrfs_get_chunk_map(fs_info, disk_start, PAGE_SIZE);
-               if (IS_ERR(em)) {
+               device = btrfs_zoned_get_device(fs_info, disk_start, PAGE_SIZE);
+               if (IS_ERR(device)) {
                        kfree(cb);
                        bio_put(bio);
                        return BLK_STS_NOTSUPP;
                }
 
-               map = em->map_lookup;
-               /* We only support single profile for now */
-               ASSERT(map->num_stripes == 1);
-               bdev = map->stripes[0].dev->bdev;
-
-               bio_set_dev(bio, bdev);
-               free_extent_map(em);
+               bio_set_dev(bio, device->bdev);
        }
 
        if (blkcg_css) {
@@ -515,7 +505,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
                }
                if (bytes_left < PAGE_SIZE) {
                        btrfs_info(fs_info,
-                                       "bytes left %lu compress len %lu nr %lu",
+                                       "bytes left %lu compress len %u nr %u",
                               bytes_left, cb->compressed_len, cb->nr_pages);
                }
                bytes_left -= PAGE_SIZE;
@@ -677,9 +667,9 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct extent_map_tree *em_tree;
        struct compressed_bio *cb;
-       unsigned long compressed_len;
-       unsigned long nr_pages;
-       unsigned long pg_index;
+       unsigned int compressed_len;
+       unsigned int nr_pages;
+       unsigned int pg_index;
        struct page *page;
        struct bio *comp_bio;
        u64 cur_disk_byte = bio->bi_iter.bi_sector << 9;
@@ -1202,9 +1192,6 @@ static unsigned int btrfs_compress_set_level(int type, unsigned level)
  *
  * @total_out is an in/out parameter, must be set to the input length and will
  * be also used to return the total number of compressed bytes
- *
- * @max_out tells us the max number of bytes that we're allowed to
- * stuff into pages
  */
 int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
                         u64 start, struct page **pages,
@@ -1225,20 +1212,6 @@ int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
        return ret;
 }
 
-/*
- * pages_in is an array of pages with compressed data.
- *
- * disk_start is the starting logical offset of this array in the file
- *
- * orig_bio contains the pages from the file that we want to decompress into
- *
- * srclen is the number of bytes in pages_in
- *
- * The basic idea is that we have a bio that was created by readpages.
- * The pages in the bio are for the uncompressed data, and they may not
- * be contiguous.  They all correspond to the range of bytes covered by
- * the compressed extent.
- */
 static int btrfs_decompress_bio(struct compressed_bio *cb)
 {
        struct list_head *workspace;
index 8001b70..c359f20 100644 (file)
@@ -31,6 +31,9 @@ struct compressed_bio {
        /* number of bios pending for this compressed extent */
        refcount_t pending_bios;
 
+       /* Number of compressed pages in the array */
+       unsigned int nr_pages;
+
        /* the pages with the compressed data on them */
        struct page **compressed_pages;
 
@@ -40,20 +43,17 @@ struct compressed_bio {
        /* starting offset in the inode for our pages */
        u64 start;
 
-       /* number of bytes in the inode we're working on */
-       unsigned long len;
-
-       /* number of bytes on disk */
-       unsigned long compressed_len;
+       /* Number of bytes in the inode we're working on */
+       unsigned int len;
 
-       /* the compression algorithm for this bio */
-       int compress_type;
+       /* Number of bytes on disk */
+       unsigned int compressed_len;
 
-       /* number of compressed pages in the array */
-       unsigned long nr_pages;
+       /* The compression algorithm for this bio */
+       u8 compress_type;
 
        /* IO errors */
-       int errors;
+       u8 errors;
        int mirror_num;
 
        /* for reads, this is the bio we are copying the data into */
@@ -91,10 +91,10 @@ int btrfs_decompress_buf2page(const char *buf, unsigned long buf_start,
                              struct bio *bio);
 
 blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
-                                 unsigned long len, u64 disk_start,
-                                 unsigned long compressed_len,
+                                 unsigned int len, u64 disk_start,
+                                 unsigned int compressed_len,
                                  struct page **compressed_pages,
-                                 unsigned long nr_pages,
+                                 unsigned int nr_pages,
                                  unsigned int write_flags,
                                  struct cgroup_subsys_state *blkcg_css);
 blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
index a484fb7..4bc3ca2 100644 (file)
@@ -596,7 +596,6 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
                       trans->transid, fs_info->generation);
 
        if (!should_cow_block(trans, root, buf)) {
-               trans->dirty = true;
                *cow_ret = buf;
                return 0;
        }
@@ -1788,10 +1787,8 @@ again:
                         * then we don't want to set the path blocking,
                         * so we test it here
                         */
-                       if (!should_cow_block(trans, root, b)) {
-                               trans->dirty = true;
+                       if (!should_cow_block(trans, root, b))
                                goto cow_done;
-                       }
 
                        /*
                         * must have write locks on this node and the
index 9fb7682..e5e53e5 100644 (file)
@@ -561,10 +561,16 @@ enum {
        /*
         * Indicate that balance has been set up from the ioctl and is in the
         * main phase. The fs_info::balance_ctl is initialized.
-        * Set and cleared while holding fs_info::balance_mutex.
         */
        BTRFS_FS_BALANCE_RUNNING,
 
+       /*
+        * Indicate that relocation of a chunk has started, it's set per chunk
+        * and is toggled between chunks.
+        * Set, tested and cleared while holding fs_info::send_reloc_lock.
+        */
+       BTRFS_FS_RELOC_RUNNING,
+
        /* Indicate that the cleaner thread is awake and doing something. */
        BTRFS_FS_CLEANER_RUNNING,
 
@@ -817,8 +823,6 @@ struct btrfs_fs_info {
        struct kobject *space_info_kobj;
        struct kobject *qgroups_kobj;
 
-       u64 total_pinned;
-
        /* used to keep from writing metadata until there is a nice batch */
        struct percpu_counter dirty_metadata_bytes;
        struct percpu_counter delalloc_bytes;
@@ -871,6 +875,9 @@ struct btrfs_fs_info {
        struct btrfs_balance_control *balance_ctl;
        wait_queue_head_t balance_wait_q;
 
+       /* Cancellation requests for chunk relocation */
+       atomic_t reloc_cancel_req;
+
        u32 data_chunk_allocations;
        u32 metadata_ratio;
 
@@ -986,14 +993,15 @@ struct btrfs_fs_info {
 
        struct crypto_shash *csum_shash;
 
+       spinlock_t send_reloc_lock;
        /*
         * Number of send operations in progress.
-        * Updated while holding fs_info::balance_mutex.
+        * Updated while holding fs_info::send_reloc_lock.
         */
        int send_in_progress;
 
-       /* Type of exclusive operation running */
-       unsigned long exclusive_operation;
+       /* Type of exclusive operation running, protected by super_lock */
+       enum btrfs_exclusive_operation exclusive_operation;
 
        /*
         * Zone size > 0 when in ZONED mode, otherwise it's used for a check
@@ -1375,38 +1383,39 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
  *
  * Note: don't forget to add new options to btrfs_show_options()
  */
-#define BTRFS_MOUNT_NODATASUM          (1 << 0)
-#define BTRFS_MOUNT_NODATACOW          (1 << 1)
-#define BTRFS_MOUNT_NOBARRIER          (1 << 2)
-#define BTRFS_MOUNT_SSD                        (1 << 3)
-#define BTRFS_MOUNT_DEGRADED           (1 << 4)
-#define BTRFS_MOUNT_COMPRESS           (1 << 5)
-#define BTRFS_MOUNT_NOTREELOG           (1 << 6)
-#define BTRFS_MOUNT_FLUSHONCOMMIT       (1 << 7)
-#define BTRFS_MOUNT_SSD_SPREAD         (1 << 8)
-#define BTRFS_MOUNT_NOSSD              (1 << 9)
-#define BTRFS_MOUNT_DISCARD_SYNC       (1 << 10)
-#define BTRFS_MOUNT_FORCE_COMPRESS      (1 << 11)
-#define BTRFS_MOUNT_SPACE_CACHE                (1 << 12)
-#define BTRFS_MOUNT_CLEAR_CACHE                (1 << 13)
-#define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14)
-#define BTRFS_MOUNT_ENOSPC_DEBUG        (1 << 15)
-#define BTRFS_MOUNT_AUTO_DEFRAG                (1 << 16)
-/* bit 17 is free */
-#define BTRFS_MOUNT_USEBACKUPROOT      (1 << 18)
-#define BTRFS_MOUNT_SKIP_BALANCE       (1 << 19)
-#define BTRFS_MOUNT_CHECK_INTEGRITY    (1 << 20)
-#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
-#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR       (1 << 22)
-#define BTRFS_MOUNT_RESCAN_UUID_TREE   (1 << 23)
-#define BTRFS_MOUNT_FRAGMENT_DATA      (1 << 24)
-#define BTRFS_MOUNT_FRAGMENT_METADATA  (1 << 25)
-#define BTRFS_MOUNT_FREE_SPACE_TREE    (1 << 26)
-#define BTRFS_MOUNT_NOLOGREPLAY                (1 << 27)
-#define BTRFS_MOUNT_REF_VERIFY         (1 << 28)
-#define BTRFS_MOUNT_DISCARD_ASYNC      (1 << 29)
-#define BTRFS_MOUNT_IGNOREBADROOTS     (1 << 30)
-#define BTRFS_MOUNT_IGNOREDATACSUMS    (1 << 31)
+enum {
+       BTRFS_MOUNT_NODATASUM                   = (1UL << 0),
+       BTRFS_MOUNT_NODATACOW                   = (1UL << 1),
+       BTRFS_MOUNT_NOBARRIER                   = (1UL << 2),
+       BTRFS_MOUNT_SSD                         = (1UL << 3),
+       BTRFS_MOUNT_DEGRADED                    = (1UL << 4),
+       BTRFS_MOUNT_COMPRESS                    = (1UL << 5),
+       BTRFS_MOUNT_NOTREELOG                   = (1UL << 6),
+       BTRFS_MOUNT_FLUSHONCOMMIT               = (1UL << 7),
+       BTRFS_MOUNT_SSD_SPREAD                  = (1UL << 8),
+       BTRFS_MOUNT_NOSSD                       = (1UL << 9),
+       BTRFS_MOUNT_DISCARD_SYNC                = (1UL << 10),
+       BTRFS_MOUNT_FORCE_COMPRESS              = (1UL << 11),
+       BTRFS_MOUNT_SPACE_CACHE                 = (1UL << 12),
+       BTRFS_MOUNT_CLEAR_CACHE                 = (1UL << 13),
+       BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED      = (1UL << 14),
+       BTRFS_MOUNT_ENOSPC_DEBUG                = (1UL << 15),
+       BTRFS_MOUNT_AUTO_DEFRAG                 = (1UL << 16),
+       BTRFS_MOUNT_USEBACKUPROOT               = (1UL << 17),
+       BTRFS_MOUNT_SKIP_BALANCE                = (1UL << 18),
+       BTRFS_MOUNT_CHECK_INTEGRITY             = (1UL << 19),
+       BTRFS_MOUNT_CHECK_INTEGRITY_DATA        = (1UL << 20),
+       BTRFS_MOUNT_PANIC_ON_FATAL_ERROR        = (1UL << 21),
+       BTRFS_MOUNT_RESCAN_UUID_TREE            = (1UL << 22),
+       BTRFS_MOUNT_FRAGMENT_DATA               = (1UL << 23),
+       BTRFS_MOUNT_FRAGMENT_METADATA           = (1UL << 24),
+       BTRFS_MOUNT_FREE_SPACE_TREE             = (1UL << 25),
+       BTRFS_MOUNT_NOLOGREPLAY                 = (1UL << 26),
+       BTRFS_MOUNT_REF_VERIFY                  = (1UL << 27),
+       BTRFS_MOUNT_DISCARD_ASYNC               = (1UL << 28),
+       BTRFS_MOUNT_IGNOREBADROOTS              = (1UL << 29),
+       BTRFS_MOUNT_IGNOREDATACSUMS             = (1UL << 30),
+};
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
 #define BTRFS_DEFAULT_MAX_INLINE       (2048)
@@ -2216,11 +2225,13 @@ BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
 
 static inline bool btrfs_root_readonly(const struct btrfs_root *root)
 {
+       /* Byte-swap the constant at compile time, root_item::flags is LE */
        return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0;
 }
 
 static inline bool btrfs_root_dead(const struct btrfs_root *root)
 {
+       /* Byte-swap the constant at compile time, root_item::flags is LE */
        return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
 }
 
@@ -2746,9 +2757,9 @@ enum btrfs_reserve_flush_enum {
        /*
         * Flush space by above mentioned methods and by:
         * - Running delayed iputs
-        * - Commiting transaction
+        * - Committing transaction
         *
-        * Can be interruped by fatal signal.
+        * Can be interrupted by a fatal signal.
         */
        BTRFS_RESERVE_FLUSH_DATA,
        BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE,
@@ -2758,7 +2769,7 @@ enum btrfs_reserve_flush_enum {
         * Pretty much the same as FLUSH_ALL, but can also steal space from
         * global rsv.
         *
-        * Can be interruped by fatal signal.
+        * Can be interrupted by a fatal signal.
         */
        BTRFS_RESERVE_FLUSH_ALL_STEAL,
 };
@@ -2774,7 +2785,6 @@ enum btrfs_flush_state {
        ALLOC_CHUNK_FORCE       =       8,
        RUN_DELAYED_IPUTS       =       9,
        COMMIT_TRANS            =       10,
-       FORCE_COMMIT_TRANS      =       11,
 };
 
 int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
@@ -3100,8 +3110,8 @@ u64 btrfs_file_extent_end(const struct btrfs_path *path);
 /* inode.c */
 blk_status_t btrfs_submit_data_bio(struct inode *inode, struct bio *bio,
                                   int mirror_num, unsigned long bio_flags);
-int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
-                          struct page *page, u64 start, u64 end);
+unsigned int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
+                                   struct page *page, u64 start, u64 end);
 struct extent_map *btrfs_get_extent_fiemap(struct btrfs_inode *inode,
                                           u64 start, u64 len);
 noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
@@ -3125,7 +3135,7 @@ int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
 int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               struct btrfs_inode *inode, u64 new_size,
-                              u32 min_type);
+                              u32 min_type, u64 *extents_found);
 
 int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
 int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
@@ -3146,9 +3156,7 @@ void btrfs_split_delalloc_extent(struct inode *inode,
                                 struct extent_state *orig, u64 split);
 int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio,
                             unsigned long bio_flags);
-bool btrfs_bio_fits_in_ordered_extent(struct page *page, struct bio *bio,
-                                     unsigned int size);
-void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end);
+void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end);
 vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_evict_inode(struct inode *inode);
@@ -3187,7 +3195,8 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
                u64 start, u64 end, int *page_started, unsigned long *nr_written,
                struct writeback_control *wbc);
 int btrfs_writepage_cow_fixup(struct page *page, u64 start, u64 end);
-void btrfs_writepage_endio_finish_ordered(struct page *page, u64 start,
+void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
+                                         struct page *page, u64 start,
                                          u64 end, int uptodate);
 extern const struct dentry_operations btrfs_dentry_operations;
 extern const struct iomap_ops btrfs_dio_iomap_ops;
@@ -3222,6 +3231,9 @@ void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
                               struct btrfs_ioctl_balance_args *bargs);
 bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
                        enum btrfs_exclusive_operation type);
+bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
+                                enum btrfs_exclusive_operation type);
+void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
 void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
 
 /* file.c */
@@ -3786,4 +3798,14 @@ static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info)
        return fs_info->zoned != 0;
 }
 
+/*
+ * We use page status Private2 to indicate there is an ordered extent with
+ * unfinished IO.
+ *
+ * Rename the Private2 accessors to Ordered, to improve readability.
+ */
+#define PageOrdered(page)              PagePrivate2(page)
+#define SetPageOrdered(page)           SetPagePrivate2(page)
+#define ClearPageOrdered(page)         ClearPagePrivate2(page)
+
 #endif
index 56642ca..2059d15 100644 (file)
@@ -89,7 +89,7 @@
  *    ->outstanding_extents += 1 (current value is 1)
  *
  *  -> set_delalloc
- *    ->outstanding_extents += 1 (currrent value is 2)
+ *    ->outstanding_extents += 1 (current value is 2)
  *
  *  -> btrfs_delalloc_release_extents()
  *    ->outstanding_extents -= 1 (current value is 1)
index 1a88f62..257c1e1 100644 (file)
@@ -681,7 +681,7 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
 {
        struct btrfs_delayed_item *curr, *next;
        int free_space;
-       int total_data_size = 0, total_size = 0;
+       int total_size = 0;
        struct extent_buffer *leaf;
        char *data_ptr;
        struct btrfs_key *keys;
@@ -706,7 +706,6 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
         */
        while (total_size + next->data_len + sizeof(struct btrfs_item) <=
               free_space) {
-               total_data_size += next->data_len;
                total_size += next->data_len + sizeof(struct btrfs_item);
                list_add_tail(&next->tree_list, &head);
                nitems++;
@@ -974,14 +973,16 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
 
 static void btrfs_release_delayed_iref(struct btrfs_delayed_node *delayed_node)
 {
-       struct btrfs_delayed_root *delayed_root;
 
-       ASSERT(delayed_node->root);
-       clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
-       delayed_node->count--;
+       if (test_and_clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) {
+               struct btrfs_delayed_root *delayed_root;
 
-       delayed_root = delayed_node->root->fs_info->delayed_root;
-       finish_one_item(delayed_root);
+               ASSERT(delayed_node->root);
+               delayed_node->count--;
+
+               delayed_root = delayed_node->root->fs_info->delayed_root;
+               finish_one_item(delayed_root);
+       }
 }
 
 static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
@@ -1009,12 +1010,10 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        nofs_flag = memalloc_nofs_save();
        ret = btrfs_lookup_inode(trans, root, path, &key, mod);
        memalloc_nofs_restore(nofs_flag);
-       if (ret > 0) {
-               btrfs_release_path(path);
-               return -ENOENT;
-       } else if (ret < 0) {
-               return ret;
-       }
+       if (ret > 0)
+               ret = -ENOENT;
+       if (ret < 0)
+               goto out;
 
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
@@ -1024,7 +1023,7 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
 
        if (!test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
-               goto no_iref;
+               goto out;
 
        path->slots[0]++;
        if (path->slots[0] >= btrfs_header_nritems(leaf))
@@ -1046,12 +1045,19 @@ again:
        btrfs_del_item(trans, root, path);
 out:
        btrfs_release_delayed_iref(node);
-no_iref:
        btrfs_release_path(path);
 err_out:
        btrfs_delayed_inode_release_metadata(fs_info, node, (ret < 0));
        btrfs_release_delayed_inode(node);
 
+       /*
+        * If we fail to update the delayed inode we need to abort the
+        * transaction, because we could leave the inode with the improper
+        * counts behind.
+        */
+       if (ret && ret != -ENOENT)
+               btrfs_abort_transaction(trans, ret);
+
        return ret;
 
 search:
@@ -1898,8 +1904,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
                btrfs_release_delayed_item(prev_item);
        }
 
-       if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
-               btrfs_release_delayed_iref(delayed_node);
+       btrfs_release_delayed_iref(delayed_node);
 
        if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                btrfs_delayed_inode_release_metadata(fs_info, delayed_node, false);
index c92d9d4..06bc842 100644 (file)
@@ -641,7 +641,6 @@ static noinline void update_existing_head_ref(struct btrfs_trans_handle *trans,
        struct btrfs_delayed_ref_root *delayed_refs =
                &trans->transaction->delayed_refs;
        struct btrfs_fs_info *fs_info = trans->fs_info;
-       u64 flags = btrfs_ref_head_to_space_flags(existing);
        int old_ref_mod;
 
        BUG_ON(existing->is_data != update->is_data);
@@ -711,26 +710,6 @@ static noinline void update_existing_head_ref(struct btrfs_trans_handle *trans,
                }
        }
 
-       /*
-        * This handles the following conditions:
-        *
-        * 1. We had a ref mod of 0 or more and went negative, indicating that
-        *    we may be freeing space, so add our space to the
-        *    total_bytes_pinned counter.
-        * 2. We were negative and went to 0 or positive, so no longer can say
-        *    that the space would be pinned, decrement our counter from the
-        *    total_bytes_pinned counter.
-        * 3. We are now at 0 and have ->must_insert_reserved set, which means
-        *    this was a new allocation and then we dropped it, and thus must
-        *    add our space to the total_bytes_pinned counter.
-        */
-       if (existing->total_ref_mod < 0 && old_ref_mod >= 0)
-               btrfs_mod_total_bytes_pinned(fs_info, flags, existing->num_bytes);
-       else if (existing->total_ref_mod >= 0 && old_ref_mod < 0)
-               btrfs_mod_total_bytes_pinned(fs_info, flags, -existing->num_bytes);
-       else if (existing->total_ref_mod == 0 && existing->must_insert_reserved)
-               btrfs_mod_total_bytes_pinned(fs_info, flags, existing->num_bytes);
-
        spin_unlock(&existing->lock);
 }
 
@@ -835,17 +814,12 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
                kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref);
                head_ref = existing;
        } else {
-               u64 flags = btrfs_ref_head_to_space_flags(head_ref);
-
                if (head_ref->is_data && head_ref->ref_mod < 0) {
                        delayed_refs->pending_csums += head_ref->num_bytes;
                        trans->delayed_ref_updates +=
                                btrfs_csum_bytes_to_leaves(trans->fs_info,
                                                           head_ref->num_bytes);
                }
-               if (head_ref->ref_mod < 0)
-                       btrfs_mod_total_bytes_pinned(trans->fs_info, flags,
-                                                    head_ref->num_bytes);
                delayed_refs->num_heads++;
                delayed_refs->num_heads_ready++;
                atomic_inc(&delayed_refs->num_entries);
index d05f735..d029be4 100644 (file)
@@ -37,7 +37,7 @@
  * - Write duplication
  *
  *   All new writes will be written to both target and source devices, so even
- *   if replace gets canceled, sources device still contans up-to-date data.
+ *   if replace gets canceled, sources device still contains up-to-date data.
  *
  *   Location:         handle_ops_on_dev_replace() from __btrfs_map_block()
  *   Start:            btrfs_dev_replace_start()
index 306ff20..e1b7bd9 100644 (file)
@@ -624,7 +624,7 @@ void btrfs_discard_update_discardable(struct btrfs_block_group *block_group)
  * @fs_info: fs_info of interest
  *
  * The unused_bgs list needs to be punted to the discard lists because the
- * order of operations is changed.  In the normal sychronous discard path, the
+ * order of operations is changed.  In the normal synchronous discard path, the
  * block groups are trimmed via a single large trim in transaction commit.  This
  * is ultimately what we are trying to avoid with asynchronous discard.  Thus,
  * it must be done before going down the unused_bgs path.
index 8d386a5..b117dd3 100644 (file)
@@ -241,7 +241,6 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
 {
        struct extent_state *cached_state = NULL;
        int ret;
-       bool need_lock = (current->journal_info == BTRFS_SEND_TRANS_STUB);
 
        if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
                return 0;
@@ -249,9 +248,6 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
        if (atomic)
                return -EAGAIN;
 
-       if (need_lock)
-               btrfs_tree_read_lock(eb);
-
        lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
                         &cached_state);
        if (extent_buffer_uptodate(eb) &&
@@ -264,22 +260,10 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                        eb->start,
                        parent_transid, btrfs_header_generation(eb));
        ret = 1;
-
-       /*
-        * Things reading via commit roots that don't have normal protection,
-        * like send, can have a really old block in cache that may point at a
-        * block that has been freed and re-allocated.  So don't clear uptodate
-        * if we find an eb that is under IO (dirty/writeback) because we could
-        * end up reading in the stale data and then writing it back out and
-        * making everybody very sad.
-        */
-       if (!extent_buffer_under_io(eb))
-               clear_extent_buffer_uptodate(eb);
+       clear_extent_buffer_uptodate(eb);
 out:
        unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
                             &cached_state);
-       if (need_lock)
-               btrfs_tree_read_unlock(eb);
        return ret;
 }
 
@@ -584,6 +568,7 @@ static int validate_extent_buffer(struct extent_buffer *eb)
        const u32 csum_size = fs_info->csum_size;
        u8 found_level;
        u8 result[BTRFS_CSUM_SIZE];
+       const u8 *header_csum;
        int ret = 0;
 
        found_start = btrfs_header_bytenr(eb);
@@ -608,15 +593,14 @@ static int validate_extent_buffer(struct extent_buffer *eb)
        }
 
        csum_tree_block(eb, result);
+       header_csum = page_address(eb->pages[0]) +
+               get_eb_offset_in_page(eb, offsetof(struct btrfs_header, csum));
 
-       if (memcmp_extent_buffer(eb, result, 0, csum_size)) {
-               u8 val[BTRFS_CSUM_SIZE] = { 0 };
-
-               read_extent_buffer(eb, &val, 0, csum_size);
+       if (memcmp(result, header_csum, csum_size) != 0) {
                btrfs_warn_rl(fs_info,
-       "%s checksum verify failed on %llu wanted " CSUM_FMT " found " CSUM_FMT " level %d",
-                             fs_info->sb->s_id, eb->start,
-                             CSUM_FMT_VALUE(csum_size, val),
+       "checksum verify failed on %llu wanted " CSUM_FMT " found " CSUM_FMT " level %d",
+                             eb->start,
+                             CSUM_FMT_VALUE(csum_size, header_csum),
                              CSUM_FMT_VALUE(csum_size, result),
                              btrfs_header_level(eb));
                ret = -EUCLEAN;
@@ -917,23 +901,22 @@ static blk_status_t btree_submit_bio_start(struct inode *inode, struct bio *bio,
        return btree_csum_one_bio(bio);
 }
 
-static int check_async_write(struct btrfs_fs_info *fs_info,
+static bool should_async_write(struct btrfs_fs_info *fs_info,
                             struct btrfs_inode *bi)
 {
        if (btrfs_is_zoned(fs_info))
-               return 0;
+               return false;
        if (atomic_read(&bi->sync_writers))
-               return 0;
+               return false;
        if (test_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags))
-               return 0;
-       return 1;
+               return false;
+       return true;
 }
 
 blk_status_t btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio,
                                       int mirror_num, unsigned long bio_flags)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       int async = check_async_write(fs_info, BTRFS_I(inode));
        blk_status_t ret;
 
        if (btrfs_op(bio) != BTRFS_MAP_WRITE) {
@@ -946,7 +929,7 @@ blk_status_t btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio,
                if (ret)
                        goto out_w_error;
                ret = btrfs_map_bio(fs_info, bio, mirror_num);
-       } else if (!async) {
+       } else if (!should_async_write(fs_info, BTRFS_I(inode))) {
                ret = btree_csum_one_bio(bio);
                if (ret)
                        goto out_w_error;
@@ -2252,6 +2235,7 @@ static void btrfs_init_balance(struct btrfs_fs_info *fs_info)
        atomic_set(&fs_info->balance_cancel_req, 0);
        fs_info->balance_ctl = NULL;
        init_waitqueue_head(&fs_info->balance_wait_q);
+       atomic_set(&fs_info->reloc_cancel_req, 0);
 }
 
 static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info)
@@ -2999,6 +2983,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        spin_lock_init(&fs_info->swapfile_pins_lock);
        fs_info->swapfile_pins = RB_ROOT;
 
+       spin_lock_init(&fs_info->send_reloc_lock);
        fs_info->send_in_progress = 0;
 
        fs_info->bg_reclaim_threshold = BTRFS_DEFAULT_RECLAIM_THRESH;
@@ -3471,7 +3456,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
         * At this point we know all the devices that make this filesystem,
         * including the seed devices but we don't know yet if the replace
         * target is required. So free devices that are not part of this
-        * filesystem but skip the replace traget device which is checked
+        * filesystem but skip the replace target device which is checked
         * below in btrfs_init_dev_replace().
         */
        btrfs_free_extra_devids(fs_devices);
@@ -3598,8 +3583,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
        if (btrfs_test_opt(fs_info, CHECK_INTEGRITY)) {
                ret = btrfsic_mount(fs_info, fs_devices,
                                    btrfs_test_opt(fs_info,
-                                       CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ?
-                                   1 : 0,
+                                       CHECK_INTEGRITY_DATA) ? 1 : 0,
                                    fs_info->check_integrity_print_mask);
                if (ret)
                        btrfs_warn(fs_info,
@@ -4696,9 +4680,6 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                        cache->space_info->bytes_reserved -= head->num_bytes;
                        spin_unlock(&cache->lock);
                        spin_unlock(&cache->space_info->lock);
-                       percpu_counter_add_batch(
-                               &cache->space_info->total_bytes_pinned,
-                               head->num_bytes, BTRFS_TOTAL_BYTES_PINNED_BATCH);
 
                        btrfs_put_block_group(cache);
 
index 3d5c35e..d296483 100644 (file)
@@ -1425,7 +1425,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
  *                 bytenr of the parent block. Since new extents are always
  *                 created with indirect references, this will only be the case
  *                 when relocating a shared extent. In that case, root_objectid
- *                 will be BTRFS_TREE_RELOC_OBJECTID. Otheriwse, parent must
+ *                 will be BTRFS_TREE_RELOC_OBJECTID. Otherwise, parent must
  *                 be 0
  *
  * @root_objectid:  The id of the root where this modification has originated,
@@ -1804,19 +1804,6 @@ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
                nr_items += btrfs_csum_bytes_to_leaves(fs_info, head->num_bytes);
        }
 
-       /*
-        * We were dropping refs, or had a new ref and dropped it, and thus must
-        * adjust down our total_bytes_pinned, the space may or may not have
-        * been pinned and so is accounted for properly in the pinned space by
-        * now.
-        */
-       if (head->total_ref_mod < 0 ||
-           (head->total_ref_mod == 0 && head->must_insert_reserved)) {
-               u64 flags = btrfs_ref_head_to_space_flags(head);
-
-               btrfs_mod_total_bytes_pinned(fs_info, flags, -head->num_bytes);
-       }
-
        btrfs_delayed_refs_rsv_release(fs_info, nr_items);
 }
 
@@ -2551,7 +2538,6 @@ static int pin_down_extent(struct btrfs_trans_handle *trans,
        spin_unlock(&cache->lock);
        spin_unlock(&cache->space_info->lock);
 
-       __btrfs_mod_total_bytes_pinned(cache->space_info, num_bytes);
        set_extent_dirty(&trans->transaction->pinned_extents, bytenr,
                         bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL);
        return 0;
@@ -2762,7 +2748,6 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
                cache->pinned -= len;
                btrfs_space_info_update_bytes_pinned(fs_info, space_info, -len);
                space_info->max_extent_size = 0;
-               __btrfs_mod_total_bytes_pinned(space_info, -len);
                if (cache->ro) {
                        space_info->bytes_readonly += len;
                        readonly = true;
@@ -4784,7 +4769,6 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
                         buf->start + buf->len - 1, GFP_NOFS);
        }
-       trans->dirty = true;
        /* this returns a buffer locked for blocking */
        return buf;
 }
index dee2daf..9e81d25 100644 (file)
@@ -136,7 +136,7 @@ struct tree_entry {
 };
 
 struct extent_page_data {
-       struct bio *bio;
+       struct btrfs_bio_ctrl bio_ctrl;
        /* tells writepage not to lock the state bits for this range
         * it still does the unlocking
         */
@@ -185,10 +185,12 @@ int __must_check submit_one_bio(struct bio *bio, int mirror_num,
 /* Cleanup unsubmitted bios */
 static void end_write_bio(struct extent_page_data *epd, int ret)
 {
-       if (epd->bio) {
-               epd->bio->bi_status = errno_to_blk_status(ret);
-               bio_endio(epd->bio);
-               epd->bio = NULL;
+       struct bio *bio = epd->bio_ctrl.bio;
+
+       if (bio) {
+               bio->bi_status = errno_to_blk_status(ret);
+               bio_endio(bio);
+               epd->bio_ctrl.bio = NULL;
        }
 }
 
@@ -201,9 +203,10 @@ static void end_write_bio(struct extent_page_data *epd, int ret)
 static int __must_check flush_write_bio(struct extent_page_data *epd)
 {
        int ret = 0;
+       struct bio *bio = epd->bio_ctrl.bio;
 
-       if (epd->bio) {
-               ret = submit_one_bio(epd->bio, 0, 0);
+       if (bio) {
+               ret = submit_one_bio(bio, 0, 0);
                /*
                 * Clean up of epd->bio is handled by its endio function.
                 * And endio is either triggered by successful bio execution
@@ -211,7 +214,7 @@ static int __must_check flush_write_bio(struct extent_page_data *epd)
                 * So at this point, no matter what happened, we don't need
                 * to clean up epd->bio.
                 */
-               epd->bio = NULL;
+               epd->bio_ctrl.bio = NULL;
        }
        return ret;
 }
@@ -1805,10 +1808,130 @@ out:
        return found;
 }
 
+/*
+ * Process one page for __process_pages_contig().
+ *
+ * Return >0 if we hit @page == @locked_page.
+ * Return 0 if we updated the page status.
+ * Return -EGAIN if the we need to try again.
+ * (For PAGE_LOCK case but got dirty page or page not belong to mapping)
+ */
+static int process_one_page(struct btrfs_fs_info *fs_info,
+                           struct address_space *mapping,
+                           struct page *page, struct page *locked_page,
+                           unsigned long page_ops, u64 start, u64 end)
+{
+       u32 len;
+
+       ASSERT(end + 1 - start != 0 && end + 1 - start < U32_MAX);
+       len = end + 1 - start;
+
+       if (page_ops & PAGE_SET_ORDERED)
+               btrfs_page_clamp_set_ordered(fs_info, page, start, len);
+       if (page_ops & PAGE_SET_ERROR)
+               btrfs_page_clamp_set_error(fs_info, page, start, len);
+       if (page_ops & PAGE_START_WRITEBACK) {
+               btrfs_page_clamp_clear_dirty(fs_info, page, start, len);
+               btrfs_page_clamp_set_writeback(fs_info, page, start, len);
+       }
+       if (page_ops & PAGE_END_WRITEBACK)
+               btrfs_page_clamp_clear_writeback(fs_info, page, start, len);
+
+       if (page == locked_page)
+               return 1;
+
+       if (page_ops & PAGE_LOCK) {
+               int ret;
+
+               ret = btrfs_page_start_writer_lock(fs_info, page, start, len);
+               if (ret)
+                       return ret;
+               if (!PageDirty(page) || page->mapping != mapping) {
+                       btrfs_page_end_writer_lock(fs_info, page, start, len);
+                       return -EAGAIN;
+               }
+       }
+       if (page_ops & PAGE_UNLOCK)
+               btrfs_page_end_writer_lock(fs_info, page, start, len);
+       return 0;
+}
+
 static int __process_pages_contig(struct address_space *mapping,
                                  struct page *locked_page,
-                                 pgoff_t start_index, pgoff_t end_index,
-                                 unsigned long page_ops, pgoff_t *index_ret);
+                                 u64 start, u64 end, unsigned long page_ops,
+                                 u64 *processed_end)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(mapping->host->i_sb);
+       pgoff_t start_index = start >> PAGE_SHIFT;
+       pgoff_t end_index = end >> PAGE_SHIFT;
+       pgoff_t index = start_index;
+       unsigned long nr_pages = end_index - start_index + 1;
+       unsigned long pages_processed = 0;
+       struct page *pages[16];
+       int err = 0;
+       int i;
+
+       if (page_ops & PAGE_LOCK) {
+               ASSERT(page_ops == PAGE_LOCK);
+               ASSERT(processed_end && *processed_end == start);
+       }
+
+       if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
+               mapping_set_error(mapping, -EIO);
+
+       while (nr_pages > 0) {
+               int found_pages;
+
+               found_pages = find_get_pages_contig(mapping, index,
+                                    min_t(unsigned long,
+                                    nr_pages, ARRAY_SIZE(pages)), pages);
+               if (found_pages == 0) {
+                       /*
+                        * Only if we're going to lock these pages, we can find
+                        * nothing at @index.
+                        */
+                       ASSERT(page_ops & PAGE_LOCK);
+                       err = -EAGAIN;
+                       goto out;
+               }
+
+               for (i = 0; i < found_pages; i++) {
+                       int process_ret;
+
+                       process_ret = process_one_page(fs_info, mapping,
+                                       pages[i], locked_page, page_ops,
+                                       start, end);
+                       if (process_ret < 0) {
+                               for (; i < found_pages; i++)
+                                       put_page(pages[i]);
+                               err = -EAGAIN;
+                               goto out;
+                       }
+                       put_page(pages[i]);
+                       pages_processed++;
+               }
+               nr_pages -= found_pages;
+               index += found_pages;
+               cond_resched();
+       }
+out:
+       if (err && processed_end) {
+               /*
+                * Update @processed_end. I know this is awful since it has
+                * two different return value patterns (inclusive vs exclusive).
+                *
+                * But the exclusive pattern is necessary if @start is 0, or we
+                * underflow and check against processed_end won't work as
+                * expected.
+                */
+               if (pages_processed)
+                       *processed_end = min(end,
+                       ((u64)(start_index + pages_processed) << PAGE_SHIFT) - 1);
+               else
+                       *processed_end = start;
+       }
+       return err;
+}
 
 static noinline void __unlock_for_delalloc(struct inode *inode,
                                           struct page *locked_page,
@@ -1821,7 +1944,7 @@ static noinline void __unlock_for_delalloc(struct inode *inode,
        if (index == locked_page->index && end_index == index)
                return;
 
-       __process_pages_contig(inode->i_mapping, locked_page, index, end_index,
+       __process_pages_contig(inode->i_mapping, locked_page, start, end,
                               PAGE_UNLOCK, NULL);
 }
 
@@ -1831,19 +1954,19 @@ static noinline int lock_delalloc_pages(struct inode *inode,
                                        u64 delalloc_end)
 {
        unsigned long index = delalloc_start >> PAGE_SHIFT;
-       unsigned long index_ret = index;
        unsigned long end_index = delalloc_end >> PAGE_SHIFT;
+       u64 processed_end = delalloc_start;
        int ret;
 
        ASSERT(locked_page);
        if (index == locked_page->index && index == end_index)
                return 0;
 
-       ret = __process_pages_contig(inode->i_mapping, locked_page, index,
-                                    end_index, PAGE_LOCK, &index_ret);
-       if (ret == -EAGAIN)
+       ret = __process_pages_contig(inode->i_mapping, locked_page, delalloc_start,
+                                    delalloc_end, PAGE_LOCK, &processed_end);
+       if (ret == -EAGAIN && processed_end > delalloc_start)
                __unlock_for_delalloc(inode, locked_page, delalloc_start,
-                                     (u64)index_ret << PAGE_SHIFT);
+                                     processed_end);
        return ret;
 }
 
@@ -1936,84 +2059,6 @@ out_failed:
        return found;
 }
 
-static int __process_pages_contig(struct address_space *mapping,
-                                 struct page *locked_page,
-                                 pgoff_t start_index, pgoff_t end_index,
-                                 unsigned long page_ops, pgoff_t *index_ret)
-{
-       unsigned long nr_pages = end_index - start_index + 1;
-       unsigned long pages_processed = 0;
-       pgoff_t index = start_index;
-       struct page *pages[16];
-       unsigned ret;
-       int err = 0;
-       int i;
-
-       if (page_ops & PAGE_LOCK) {
-               ASSERT(page_ops == PAGE_LOCK);
-               ASSERT(index_ret && *index_ret == start_index);
-       }
-
-       if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
-               mapping_set_error(mapping, -EIO);
-
-       while (nr_pages > 0) {
-               ret = find_get_pages_contig(mapping, index,
-                                    min_t(unsigned long,
-                                    nr_pages, ARRAY_SIZE(pages)), pages);
-               if (ret == 0) {
-                       /*
-                        * Only if we're going to lock these pages,
-                        * can we find nothing at @index.
-                        */
-                       ASSERT(page_ops & PAGE_LOCK);
-                       err = -EAGAIN;
-                       goto out;
-               }
-
-               for (i = 0; i < ret; i++) {
-                       if (page_ops & PAGE_SET_PRIVATE2)
-                               SetPagePrivate2(pages[i]);
-
-                       if (locked_page && pages[i] == locked_page) {
-                               put_page(pages[i]);
-                               pages_processed++;
-                               continue;
-                       }
-                       if (page_ops & PAGE_START_WRITEBACK) {
-                               clear_page_dirty_for_io(pages[i]);
-                               set_page_writeback(pages[i]);
-                       }
-                       if (page_ops & PAGE_SET_ERROR)
-                               SetPageError(pages[i]);
-                       if (page_ops & PAGE_END_WRITEBACK)
-                               end_page_writeback(pages[i]);
-                       if (page_ops & PAGE_UNLOCK)
-                               unlock_page(pages[i]);
-                       if (page_ops & PAGE_LOCK) {
-                               lock_page(pages[i]);
-                               if (!PageDirty(pages[i]) ||
-                                   pages[i]->mapping != mapping) {
-                                       unlock_page(pages[i]);
-                                       for (; i < ret; i++)
-                                               put_page(pages[i]);
-                                       err = -EAGAIN;
-                                       goto out;
-                               }
-                       }
-                       put_page(pages[i]);
-                       pages_processed++;
-               }
-               nr_pages -= ret;
-               index += ret;
-               cond_resched();
-       }
-out:
-       if (err && index_ret)
-               *index_ret = start_index + pages_processed - 1;
-       return err;
-}
-
 void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
                                  struct page *locked_page,
                                  u32 clear_bits, unsigned long page_ops)
@@ -2021,8 +2066,7 @@ void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
        clear_extent_bit(&inode->io_tree, start, end, clear_bits, 1, 0, NULL);
 
        __process_pages_contig(inode->vfs_inode.i_mapping, locked_page,
-                              start >> PAGE_SHIFT, end >> PAGE_SHIFT,
-                              page_ops, NULL);
+                              start, end, page_ops, NULL);
 }
 
 /*
@@ -2381,13 +2425,6 @@ int clean_io_failure(struct btrfs_fs_info *fs_info,
 
        BUG_ON(!failrec->this_mirror);
 
-       if (failrec->in_validation) {
-               /* there was no real error, just free the record */
-               btrfs_debug(fs_info,
-                       "clean_io_failure: freeing dummy error at %llu",
-                       failrec->start);
-               goto out;
-       }
        if (sb_rdonly(fs_info->sb))
                goto out;
 
@@ -2449,7 +2486,7 @@ void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start, u64 end)
 }
 
 static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode,
-                                                            u64 start, u64 end)
+                                                            u64 start)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct io_failure_record *failrec;
@@ -2457,15 +2494,15 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode
        struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
        struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       const u32 sectorsize = fs_info->sectorsize;
        int ret;
        u64 logical;
 
        failrec = get_state_failrec(failure_tree, start);
        if (!IS_ERR(failrec)) {
                btrfs_debug(fs_info,
-                       "Get IO Failure Record: (found) logical=%llu, start=%llu, len=%llu, validation=%d",
-                       failrec->logical, failrec->start, failrec->len,
-                       failrec->in_validation);
+       "Get IO Failure Record: (found) logical=%llu, start=%llu, len=%llu",
+                       failrec->logical, failrec->start, failrec->len);
                /*
                 * when data can be on disk more than twice, add to failrec here
                 * (e.g. with a list for failed_mirror) to make
@@ -2480,10 +2517,9 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode
                return ERR_PTR(-ENOMEM);
 
        failrec->start = start;
-       failrec->len = end - start + 1;
+       failrec->len = sectorsize;
        failrec->this_mirror = 0;
        failrec->bio_flags = 0;
-       failrec->in_validation = 0;
 
        read_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, start, failrec->len);
@@ -2519,12 +2555,13 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode
        free_extent_map(em);
 
        /* Set the bits in the private failure tree */
-       ret = set_extent_bits(failure_tree, start, end,
+       ret = set_extent_bits(failure_tree, start, start + sectorsize - 1,
                              EXTENT_LOCKED | EXTENT_DIRTY);
        if (ret >= 0) {
                ret = set_state_failrec(failure_tree, start, failrec);
                /* Set the bits in the inode's tree */
-               ret = set_extent_bits(tree, start, end, EXTENT_DAMAGED);
+               ret = set_extent_bits(tree, start, start + sectorsize - 1,
+                                     EXTENT_DAMAGED);
        } else if (ret < 0) {
                kfree(failrec);
                return ERR_PTR(ret);
@@ -2533,7 +2570,7 @@ static struct io_failure_record *btrfs_get_io_failure_record(struct inode *inode
        return failrec;
 }
 
-static bool btrfs_check_repairable(struct inode *inode, bool needs_validation,
+static bool btrfs_check_repairable(struct inode *inode,
                                   struct io_failure_record *failrec,
                                   int failed_mirror)
 {
@@ -2553,39 +2590,22 @@ static bool btrfs_check_repairable(struct inode *inode, bool needs_validation,
                return false;
        }
 
+       /* The failure record should only contain one sector */
+       ASSERT(failrec->len == fs_info->sectorsize);
+
        /*
-        * there are two premises:
-        *      a) deliver good data to the caller
-        *      b) correct the bad sectors on disk
+        * There are two premises:
+        * a) deliver good data to the caller
+        * b) correct the bad sectors on disk
+        *
+        * Since we're only doing repair for one sector, we only need to get
+        * a good copy of the failed sector and if we succeed, we have setup
+        * everything for repair_io_failure to do the rest for us.
         */
-       if (needs_validation) {
-               /*
-                * to fulfill b), we need to know the exact failing sectors, as
-                * we don't want to rewrite any more than the failed ones. thus,
-                * we need separate read requests for the failed bio
-                *
-                * if the following BUG_ON triggers, our validation request got
-                * merged. we need separate requests for our algorithm to work.
-                */
-               BUG_ON(failrec->in_validation);
-               failrec->in_validation = 1;
-               failrec->this_mirror = failed_mirror;
-       } else {
-               /*
-                * we're ready to fulfill a) and b) alongside. get a good copy
-                * of the failed sector and if we succeed, we have setup
-                * everything for repair_io_failure to do the rest for us.
-                */
-               if (failrec->in_validation) {
-                       BUG_ON(failrec->this_mirror != failed_mirror);
-                       failrec->in_validation = 0;
-                       failrec->this_mirror = 0;
-               }
-               failrec->failed_mirror = failed_mirror;
+       failrec->failed_mirror = failed_mirror;
+       failrec->this_mirror++;
+       if (failrec->this_mirror == failed_mirror)
                failrec->this_mirror++;
-               if (failrec->this_mirror == failed_mirror)
-                       failrec->this_mirror++;
-       }
 
        if (failrec->this_mirror > num_copies) {
                btrfs_debug(fs_info,
@@ -2597,53 +2617,11 @@ static bool btrfs_check_repairable(struct inode *inode, bool needs_validation,
        return true;
 }
 
-static bool btrfs_io_needs_validation(struct inode *inode, struct bio *bio)
-{
-       u64 len = 0;
-       const u32 blocksize = inode->i_sb->s_blocksize;
-
-       /*
-        * If bi_status is BLK_STS_OK, then this was a checksum error, not an
-        * I/O error. In this case, we already know exactly which sector was
-        * bad, so we don't need to validate.
-        */
-       if (bio->bi_status == BLK_STS_OK)
-               return false;
-
-       /*
-        * We need to validate each sector individually if the failed I/O was
-        * for multiple sectors.
-        *
-        * There are a few possible bios that can end up here:
-        * 1. A buffered read bio, which is not cloned.
-        * 2. A direct I/O read bio, which is cloned.
-        * 3. A (buffered or direct) repair bio, which is not cloned.
-        *
-        * For cloned bios (case 2), we can get the size from
-        * btrfs_io_bio->iter; for non-cloned bios (cases 1 and 3), we can get
-        * it from the bvecs.
-        */
-       if (bio_flagged(bio, BIO_CLONED)) {
-               if (btrfs_io_bio(bio)->iter.bi_size > blocksize)
-                       return true;
-       } else {
-               struct bio_vec *bvec;
-               int i;
-
-               bio_for_each_bvec_all(bvec, bio, i) {
-                       len += bvec->bv_len;
-                       if (len > blocksize)
-                               return true;
-               }
-       }
-       return false;
-}
-
-blk_status_t btrfs_submit_read_repair(struct inode *inode,
-                                     struct bio *failed_bio, u32 bio_offset,
-                                     struct page *page, unsigned int pgoff,
-                                     u64 start, u64 end, int failed_mirror,
-                                     submit_bio_hook_t *submit_bio_hook)
+int btrfs_repair_one_sector(struct inode *inode,
+                           struct bio *failed_bio, u32 bio_offset,
+                           struct page *page, unsigned int pgoff,
+                           u64 start, int failed_mirror,
+                           submit_bio_hook_t *submit_bio_hook)
 {
        struct io_failure_record *failrec;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -2651,7 +2629,6 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode,
        struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree;
        struct btrfs_io_bio *failed_io_bio = btrfs_io_bio(failed_bio);
        const int icsum = bio_offset >> fs_info->sectorsize_bits;
-       bool need_validation;
        struct bio *repair_bio;
        struct btrfs_io_bio *repair_io_bio;
        blk_status_t status;
@@ -2661,23 +2638,19 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode,
 
        BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
 
-       failrec = btrfs_get_io_failure_record(inode, start, end);
+       failrec = btrfs_get_io_failure_record(inode, start);
        if (IS_ERR(failrec))
-               return errno_to_blk_status(PTR_ERR(failrec));
+               return PTR_ERR(failrec);
 
-       need_validation = btrfs_io_needs_validation(inode, failed_bio);
 
-       if (!btrfs_check_repairable(inode, need_validation, failrec,
-                                   failed_mirror)) {
+       if (!btrfs_check_repairable(inode, failrec, failed_mirror)) {
                free_io_failure(failure_tree, tree, failrec);
-               return BLK_STS_IOERR;
+               return -EIO;
        }
 
        repair_bio = btrfs_io_bio_alloc(1);
        repair_io_bio = btrfs_io_bio(repair_bio);
        repair_bio->bi_opf = REQ_OP_READ;
-       if (need_validation)
-               repair_bio->bi_opf |= REQ_FAILFAST_DEV;
        repair_bio->bi_end_io = failed_bio->bi_end_io;
        repair_bio->bi_iter.bi_sector = failrec->logical >> 9;
        repair_bio->bi_private = failed_bio->bi_private;
@@ -2695,8 +2668,8 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode,
        repair_io_bio->iter = repair_bio->bi_iter;
 
        btrfs_debug(btrfs_sb(inode->i_sb),
-"repair read error: submitting new read to mirror %d, in_validation=%d",
-                   failrec->this_mirror, failrec->in_validation);
+                   "repair read error: submitting new read to mirror %d",
+                   failrec->this_mirror);
 
        status = submit_bio_hook(inode, repair_bio, failrec->this_mirror,
                                 failrec->bio_flags);
@@ -2704,17 +2677,114 @@ blk_status_t btrfs_submit_read_repair(struct inode *inode,
                free_io_failure(failure_tree, tree, failrec);
                bio_put(repair_bio);
        }
-       return status;
+       return blk_status_to_errno(status);
+}
+
+static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
+
+       ASSERT(page_offset(page) <= start &&
+              start + len <= page_offset(page) + PAGE_SIZE);
+
+       if (uptodate) {
+               btrfs_page_set_uptodate(fs_info, page, start, len);
+       } else {
+               btrfs_page_clear_uptodate(fs_info, page, start, len);
+               btrfs_page_set_error(fs_info, page, start, len);
+       }
+
+       if (fs_info->sectorsize == PAGE_SIZE)
+               unlock_page(page);
+       else
+               btrfs_subpage_end_reader(fs_info, page, start, len);
+}
+
+static blk_status_t submit_read_repair(struct inode *inode,
+                                     struct bio *failed_bio, u32 bio_offset,
+                                     struct page *page, unsigned int pgoff,
+                                     u64 start, u64 end, int failed_mirror,
+                                     unsigned int error_bitmap,
+                                     submit_bio_hook_t *submit_bio_hook)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       const u32 sectorsize = fs_info->sectorsize;
+       const int nr_bits = (end + 1 - start) >> fs_info->sectorsize_bits;
+       int error = 0;
+       int i;
+
+       BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE);
+
+       /* We're here because we had some read errors or csum mismatch */
+       ASSERT(error_bitmap);
+
+       /*
+        * We only get called on buffered IO, thus page must be mapped and bio
+        * must not be cloned.
+        */
+       ASSERT(page->mapping && !bio_flagged(failed_bio, BIO_CLONED));
+
+       /* Iterate through all the sectors in the range */
+       for (i = 0; i < nr_bits; i++) {
+               const unsigned int offset = i * sectorsize;
+               struct extent_state *cached = NULL;
+               bool uptodate = false;
+               int ret;
+
+               if (!(error_bitmap & (1U << i))) {
+                       /*
+                        * This sector has no error, just end the page read
+                        * and unlock the range.
+                        */
+                       uptodate = true;
+                       goto next;
+               }
+
+               ret = btrfs_repair_one_sector(inode, failed_bio,
+                               bio_offset + offset,
+                               page, pgoff + offset, start + offset,
+                               failed_mirror, submit_bio_hook);
+               if (!ret) {
+                       /*
+                        * We have submitted the read repair, the page release
+                        * will be handled by the endio function of the
+                        * submitted repair bio.
+                        * Thus we don't need to do any thing here.
+                        */
+                       continue;
+               }
+               /*
+                * Repair failed, just record the error but still continue.
+                * Or the remaining sectors will not be properly unlocked.
+                */
+               if (!error)
+                       error = ret;
+next:
+               end_page_read(page, uptodate, start + offset, sectorsize);
+               if (uptodate)
+                       set_extent_uptodate(&BTRFS_I(inode)->io_tree,
+                                       start + offset,
+                                       start + offset + sectorsize - 1,
+                                       &cached, GFP_ATOMIC);
+               unlock_extent_cached_atomic(&BTRFS_I(inode)->io_tree,
+                               start + offset,
+                               start + offset + sectorsize - 1,
+                               &cached);
+       }
+       return errno_to_blk_status(error);
 }
 
 /* lots and lots of room for performance fixes in the end_bio funcs */
 
 void end_extent_writepage(struct page *page, int err, u64 start, u64 end)
 {
+       struct btrfs_inode *inode;
        int uptodate = (err == 0);
        int ret = 0;
 
-       btrfs_writepage_endio_finish_ordered(page, start, end, uptodate);
+       ASSERT(page && page->mapping);
+       inode = BTRFS_I(page->mapping->host);
+       btrfs_writepage_endio_finish_ordered(inode, page, start, end, uptodate);
 
        if (!uptodate) {
                ClearPageUptodate(page);
@@ -2747,25 +2817,20 @@ static void end_bio_extent_writepage(struct bio *bio)
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
                struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+               const u32 sectorsize = fs_info->sectorsize;
 
-               /* We always issue full-page reads, but if some block
-                * in a page fails to read, blk_update_request() will
-                * advance bv_offset and adjust bv_len to compensate.
-                * Print a warning for nonzero offsets, and an error
-                * if they don't add up to a full page.  */
-               if (bvec->bv_offset || bvec->bv_len != PAGE_SIZE) {
-                       if (bvec->bv_offset + bvec->bv_len != PAGE_SIZE)
-                               btrfs_err(fs_info,
-                                  "partial page write in btrfs with offset %u and length %u",
-                                       bvec->bv_offset, bvec->bv_len);
-                       else
-                               btrfs_info(fs_info,
-                                  "incomplete page write in btrfs with offset %u and length %u",
-                                       bvec->bv_offset, bvec->bv_len);
-               }
+               /* Our read/write should always be sector aligned. */
+               if (!IS_ALIGNED(bvec->bv_offset, sectorsize))
+                       btrfs_err(fs_info,
+               "partial page write in btrfs with offset %u and length %u",
+                                 bvec->bv_offset, bvec->bv_len);
+               else if (!IS_ALIGNED(bvec->bv_len, sectorsize))
+                       btrfs_info(fs_info,
+               "incomplete page write with offset %u and length %u",
+                                  bvec->bv_offset, bvec->bv_len);
 
-               start = page_offset(page);
-               end = start + bvec->bv_offset + bvec->bv_len - 1;
+               start = page_offset(page) + bvec->bv_offset;
+               end = start + bvec->bv_len - 1;
 
                if (first_bvec) {
                        btrfs_record_physical_zoned(inode, start, bio);
@@ -2773,7 +2838,8 @@ static void end_bio_extent_writepage(struct bio *bio)
                }
 
                end_extent_writepage(page, error, start, end);
-               end_page_writeback(page);
+
+               btrfs_page_clear_writeback(fs_info, page, start, bvec->bv_len);
        }
 
        bio_put(bio);
@@ -2862,30 +2928,6 @@ static void begin_page_read(struct btrfs_fs_info *fs_info, struct page *page)
        btrfs_subpage_start_reader(fs_info, page, page_offset(page), PAGE_SIZE);
 }
 
-static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
-{
-       struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
-
-       ASSERT(page_offset(page) <= start &&
-               start + len <= page_offset(page) + PAGE_SIZE);
-
-       if (uptodate) {
-               btrfs_page_set_uptodate(fs_info, page, start, len);
-       } else {
-               btrfs_page_clear_uptodate(fs_info, page, start, len);
-               btrfs_page_set_error(fs_info, page, start, len);
-       }
-
-       if (fs_info->sectorsize == PAGE_SIZE)
-               unlock_page(page);
-       else if (is_data_inode(page->mapping->host))
-               /*
-                * For subpage data, unlock the page if we're the last reader.
-                * For subpage metadata, page lock is not utilized for read.
-                */
-               btrfs_subpage_end_reader(fs_info, page, start, len);
-}
-
 /*
  * Find extent buffer for a givne bytenr.
  *
@@ -2929,7 +2971,6 @@ static struct extent_buffer *find_extent_buffer_readpage(
 static void end_bio_extent_readpage(struct bio *bio)
 {
        struct bio_vec *bvec;
-       int uptodate = !bio->bi_status;
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct extent_io_tree *tree, *failure_tree;
        struct processed_extent processed = { 0 };
@@ -2944,10 +2985,12 @@ static void end_bio_extent_readpage(struct bio *bio)
 
        ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, iter_all) {
+               bool uptodate = !bio->bi_status;
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
                struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
                const u32 sectorsize = fs_info->sectorsize;
+               unsigned int error_bitmap = (unsigned int)-1;
                u64 start;
                u64 end;
                u32 len;
@@ -2982,14 +3025,16 @@ static void end_bio_extent_readpage(struct bio *bio)
 
                mirror = io_bio->mirror_num;
                if (likely(uptodate)) {
-                       if (is_data_inode(inode))
-                               ret = btrfs_verify_data_csum(io_bio,
+                       if (is_data_inode(inode)) {
+                               error_bitmap = btrfs_verify_data_csum(io_bio,
                                                bio_offset, page, start, end);
-                       else
+                               ret = error_bitmap;
+                       } else {
                                ret = btrfs_validate_metadata_buffer(io_bio,
                                        page, start, end, mirror);
+                       }
                        if (ret)
-                               uptodate = 0;
+                               uptodate = false;
                        else
                                clean_io_failure(BTRFS_I(inode)->root->fs_info,
                                                 failure_tree, tree, start,
@@ -3001,27 +3046,18 @@ static void end_bio_extent_readpage(struct bio *bio)
                        goto readpage_ok;
 
                if (is_data_inode(inode)) {
-
                        /*
-                        * The generic bio_readpage_error handles errors the
-                        * following way: If possible, new read requests are
-                        * created and submitted and will end up in
-                        * end_bio_extent_readpage as well (if we're lucky,
-                        * not in the !uptodate case). In that case it returns
-                        * 0 and we just go on with the next page in our bio.
-                        * If it can't handle the error it will return -EIO and
-                        * we remain responsible for that page.
+                        * btrfs_submit_read_repair() will handle all the good
+                        * and bad sectors, we just continue to the next bvec.
                         */
-                       if (!btrfs_submit_read_repair(inode, bio, bio_offset,
-                                               page,
-                                               start - page_offset(page),
-                                               start, end, mirror,
-                                               btrfs_submit_data_bio)) {
-                               uptodate = !bio->bi_status;
-                               ASSERT(bio_offset + len > bio_offset);
-                               bio_offset += len;
-                               continue;
-                       }
+                       submit_read_repair(inode, bio, bio_offset, page,
+                                          start - page_offset(page), start,
+                                          end, mirror, error_bitmap,
+                                          btrfs_submit_data_bio);
+
+                       ASSERT(bio_offset + len > bio_offset);
+                       bio_offset += len;
+                       continue;
                } else {
                        struct extent_buffer *eb;
 
@@ -3151,42 +3187,99 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, int offset, int size)
  *
  * Return true if successfully page added. Otherwise, return false.
  */
-static bool btrfs_bio_add_page(struct bio *bio, struct page *page,
+static bool btrfs_bio_add_page(struct btrfs_bio_ctrl *bio_ctrl,
+                              struct page *page,
                               u64 disk_bytenr, unsigned int size,
                               unsigned int pg_offset,
-                              unsigned long prev_bio_flags,
                               unsigned long bio_flags)
 {
+       struct bio *bio = bio_ctrl->bio;
+       u32 bio_size = bio->bi_iter.bi_size;
        const sector_t sector = disk_bytenr >> SECTOR_SHIFT;
        bool contig;
        int ret;
 
-       if (prev_bio_flags != bio_flags)
+       ASSERT(bio);
+       /* The limit should be calculated when bio_ctrl->bio is allocated */
+       ASSERT(bio_ctrl->len_to_oe_boundary && bio_ctrl->len_to_stripe_boundary);
+       if (bio_ctrl->bio_flags != bio_flags)
                return false;
 
-       if (prev_bio_flags & EXTENT_BIO_COMPRESSED)
+       if (bio_ctrl->bio_flags & EXTENT_BIO_COMPRESSED)
                contig = bio->bi_iter.bi_sector == sector;
        else
                contig = bio_end_sector(bio) == sector;
        if (!contig)
                return false;
 
-       if (btrfs_bio_fits_in_stripe(page, size, bio, bio_flags))
+       if (bio_size + size > bio_ctrl->len_to_oe_boundary ||
+           bio_size + size > bio_ctrl->len_to_stripe_boundary)
                return false;
 
-       if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
-               struct page *first_page = bio_first_bvec_all(bio)->bv_page;
-
-               if (!btrfs_bio_fits_in_ordered_extent(first_page, bio, size))
-                       return false;
+       if (bio_op(bio) == REQ_OP_ZONE_APPEND)
                ret = bio_add_zone_append_page(bio, page, size, pg_offset);
-       } else {
+       else
                ret = bio_add_page(bio, page, size, pg_offset);
-       }
 
        return ret == size;
 }
 
+static int calc_bio_boundaries(struct btrfs_bio_ctrl *bio_ctrl,
+                              struct btrfs_inode *inode)
+{
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       struct btrfs_io_geometry geom;
+       struct btrfs_ordered_extent *ordered;
+       struct extent_map *em;
+       u64 logical = (bio_ctrl->bio->bi_iter.bi_sector << SECTOR_SHIFT);
+       int ret;
+
+       /*
+        * Pages for compressed extent are never submitted to disk directly,
+        * thus it has no real boundary, just set them to U32_MAX.
+        *
+        * The split happens for real compressed bio, which happens in
+        * btrfs_submit_compressed_read/write().
+        */
+       if (bio_ctrl->bio_flags & EXTENT_BIO_COMPRESSED) {
+               bio_ctrl->len_to_oe_boundary = U32_MAX;
+               bio_ctrl->len_to_stripe_boundary = U32_MAX;
+               return 0;
+       }
+       em = btrfs_get_chunk_map(fs_info, logical, fs_info->sectorsize);
+       if (IS_ERR(em))
+               return PTR_ERR(em);
+       ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(bio_ctrl->bio),
+                                   logical, &geom);
+       free_extent_map(em);
+       if (ret < 0) {
+               return ret;
+       }
+       if (geom.len > U32_MAX)
+               bio_ctrl->len_to_stripe_boundary = U32_MAX;
+       else
+               bio_ctrl->len_to_stripe_boundary = (u32)geom.len;
+
+       if (!btrfs_is_zoned(fs_info) ||
+           bio_op(bio_ctrl->bio) != REQ_OP_ZONE_APPEND) {
+               bio_ctrl->len_to_oe_boundary = U32_MAX;
+               return 0;
+       }
+
+       ASSERT(fs_info->max_zone_append_size > 0);
+       /* Ordered extent not yet created, so we're good */
+       ordered = btrfs_lookup_ordered_extent(inode, logical);
+       if (!ordered) {
+               bio_ctrl->len_to_oe_boundary = U32_MAX;
+               return 0;
+       }
+
+       bio_ctrl->len_to_oe_boundary = min_t(u32, U32_MAX,
+               ordered->disk_bytenr + ordered->disk_num_bytes - logical);
+       btrfs_put_ordered_extent(ordered);
+       return 0;
+}
+
 /*
  * @opf:       bio REQ_OP_* and REQ_* flags as one value
  * @wbc:       optional writeback control for io accounting
@@ -3203,12 +3296,11 @@ static bool btrfs_bio_add_page(struct bio *bio, struct page *page,
  */
 static int submit_extent_page(unsigned int opf,
                              struct writeback_control *wbc,
+                             struct btrfs_bio_ctrl *bio_ctrl,
                              struct page *page, u64 disk_bytenr,
                              size_t size, unsigned long pg_offset,
-                             struct bio **bio_ret,
                              bio_end_io_t end_io_func,
                              int mirror_num,
-                             unsigned long prev_bio_flags,
                              unsigned long bio_flags,
                              bool force_bio_submit)
 {
@@ -3219,19 +3311,19 @@ static int submit_extent_page(unsigned int opf,
        struct extent_io_tree *tree = &inode->io_tree;
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
 
-       ASSERT(bio_ret);
+       ASSERT(bio_ctrl);
 
-       if (*bio_ret) {
-               bio = *bio_ret;
+       ASSERT(pg_offset < PAGE_SIZE && size <= PAGE_SIZE &&
+              pg_offset + size <= PAGE_SIZE);
+       if (bio_ctrl->bio) {
+               bio = bio_ctrl->bio;
                if (force_bio_submit ||
-                   !btrfs_bio_add_page(bio, page, disk_bytenr, io_size,
-                                       pg_offset, prev_bio_flags, bio_flags)) {
-                       ret = submit_one_bio(bio, mirror_num, prev_bio_flags);
-                       if (ret < 0) {
-                               *bio_ret = NULL;
+                   !btrfs_bio_add_page(bio_ctrl, page, disk_bytenr, io_size,
+                                       pg_offset, bio_flags)) {
+                       ret = submit_one_bio(bio, mirror_num, bio_ctrl->bio_flags);
+                       bio_ctrl->bio = NULL;
+                       if (ret < 0)
                                return ret;
-                       }
-                       bio = NULL;
                } else {
                        if (wbc)
                                wbc_account_cgroup_owner(wbc, page, io_size);
@@ -3254,22 +3346,18 @@ static int submit_extent_page(unsigned int opf,
                wbc_account_cgroup_owner(wbc, page, io_size);
        }
        if (btrfs_is_zoned(fs_info) && bio_op(bio) == REQ_OP_ZONE_APPEND) {
-               struct extent_map *em;
-               struct map_lookup *map;
+               struct btrfs_device *device;
 
-               em = btrfs_get_chunk_map(fs_info, disk_bytenr, io_size);
-               if (IS_ERR(em))
-                       return PTR_ERR(em);
+               device = btrfs_zoned_get_device(fs_info, disk_bytenr, io_size);
+               if (IS_ERR(device))
+                       return PTR_ERR(device);
 
-               map = em->map_lookup;
-               /* We only support single profile for now */
-               ASSERT(map->num_stripes == 1);
-               btrfs_io_bio(bio)->device = map->stripes[0].dev;
-
-               free_extent_map(em);
+               btrfs_io_bio(bio)->device = device;
        }
 
-       *bio_ret = bio;
+       bio_ctrl->bio = bio;
+       bio_ctrl->bio_flags = bio_flags;
+       ret = calc_bio_boundaries(bio_ctrl, inode);
 
        return ret;
 }
@@ -3382,7 +3470,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
  * return 0 on success, otherwise return error
  */
 int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
-                     struct bio **bio, unsigned long *bio_flags,
+                     struct btrfs_bio_ctrl *bio_ctrl,
                      unsigned int read_flags, u64 *prev_em_start)
 {
        struct inode *inode = page->mapping->host;
@@ -3558,15 +3646,13 @@ int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
                }
 
                ret = submit_extent_page(REQ_OP_READ | read_flags, NULL,
-                                        page, disk_bytenr, iosize,
-                                        pg_offset, bio,
+                                        bio_ctrl, page, disk_bytenr, iosize,
+                                        pg_offset,
                                         end_bio_extent_readpage, 0,
-                                        *bio_flags,
                                         this_bio_flag,
                                         force_bio_submit);
                if (!ret) {
                        nr++;
-                       *bio_flags = this_bio_flag;
                } else {
                        unlock_extent(tree, cur, cur + iosize - 1);
                        end_page_read(page, false, cur, iosize);
@@ -3580,11 +3666,10 @@ out:
 }
 
 static inline void contiguous_readpages(struct page *pages[], int nr_pages,
-                                            u64 start, u64 end,
-                                            struct extent_map **em_cached,
-                                            struct bio **bio,
-                                            unsigned long *bio_flags,
-                                            u64 *prev_em_start)
+                                       u64 start, u64 end,
+                                       struct extent_map **em_cached,
+                                       struct btrfs_bio_ctrl *bio_ctrl,
+                                       u64 *prev_em_start)
 {
        struct btrfs_inode *inode = BTRFS_I(pages[0]->mapping->host);
        int index;
@@ -3592,7 +3677,7 @@ static inline void contiguous_readpages(struct page *pages[], int nr_pages,
        btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
 
        for (index = 0; index < nr_pages; index++) {
-               btrfs_do_readpage(pages[index], em_cached, bio, bio_flags,
+               btrfs_do_readpage(pages[index], em_cached, bio_ctrl,
                                  REQ_RAHEAD, prev_em_start);
                put_page(pages[index]);
        }
@@ -3680,6 +3765,54 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
 }
 
 /*
+ * Find the first byte we need to write.
+ *
+ * For subpage, one page can contain several sectors, and
+ * __extent_writepage_io() will just grab all extent maps in the page
+ * range and try to submit all non-inline/non-compressed extents.
+ *
+ * This is a big problem for subpage, we shouldn't re-submit already written
+ * data at all.
+ * This function will lookup subpage dirty bit to find which range we really
+ * need to submit.
+ *
+ * Return the next dirty range in [@start, @end).
+ * If no dirty range is found, @start will be page_offset(page) + PAGE_SIZE.
+ */
+static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
+                                struct page *page, u64 *start, u64 *end)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       u64 orig_start = *start;
+       /* Declare as unsigned long so we can use bitmap ops */
+       unsigned long dirty_bitmap;
+       unsigned long flags;
+       int nbits = (orig_start - page_offset(page)) >> fs_info->sectorsize_bits;
+       int range_start_bit = nbits;
+       int range_end_bit;
+
+       /*
+        * For regular sector size == page size case, since one page only
+        * contains one sector, we return the page offset directly.
+        */
+       if (fs_info->sectorsize == PAGE_SIZE) {
+               *start = page_offset(page);
+               *end = page_offset(page) + PAGE_SIZE;
+               return;
+       }
+
+       /* We should have the page locked, but just in case */
+       spin_lock_irqsave(&subpage->lock, flags);
+       dirty_bitmap = subpage->dirty_bitmap;
+       spin_unlock_irqrestore(&subpage->lock, flags);
+
+       bitmap_next_set_region(&dirty_bitmap, &range_start_bit, &range_end_bit,
+                              BTRFS_SUBPAGE_BITMAP_SIZE);
+       *start = page_offset(page) + range_start_bit * fs_info->sectorsize;
+       *end = page_offset(page) + range_end_bit * fs_info->sectorsize;
+}
+
+/*
  * helper for __extent_writepage.  This calls the writepage start hooks,
  * and does the loop to map the page into extents and bios.
  *
@@ -3696,7 +3829,6 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
                                 int *nr_ret)
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct extent_io_tree *tree = &inode->io_tree;
        u64 start = page_offset(page);
        u64 end = start + PAGE_SIZE - 1;
        u64 cur = start;
@@ -3727,15 +3859,26 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
        while (cur <= end) {
                u64 disk_bytenr;
                u64 em_end;
+               u64 dirty_range_start = cur;
+               u64 dirty_range_end;
                u32 iosize;
 
                if (cur >= i_size) {
-                       btrfs_writepage_endio_finish_ordered(page, cur, end, 1);
+                       btrfs_writepage_endio_finish_ordered(inode, page, cur,
+                                                            end, 1);
                        break;
                }
+
+               find_next_dirty_byte(fs_info, page, &dirty_range_start,
+                                    &dirty_range_end);
+               if (cur < dirty_range_start) {
+                       cur = dirty_range_start;
+                       continue;
+               }
+
                em = btrfs_get_extent(inode, NULL, 0, cur, end - cur + 1);
                if (IS_ERR_OR_NULL(em)) {
-                       SetPageError(page);
+                       btrfs_page_set_error(fs_info, page, cur, end - cur + 1);
                        ret = PTR_ERR_OR_ZERO(em);
                        break;
                }
@@ -3750,8 +3893,11 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
                compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
                disk_bytenr = em->block_start + extent_offset;
 
-               /* Note that em_end from extent_map_end() is exclusive */
-               iosize = min(em_end, end + 1) - cur;
+               /*
+                * Note that em_end from extent_map_end() and dirty_range_end from
+                * find_next_dirty_byte() are all exclusive
+                */
+               iosize = min(min(em_end, end + 1), dirty_range_end) - cur;
 
                if (btrfs_use_zone_append(inode, em->block_start))
                        opf = REQ_OP_ZONE_APPEND;
@@ -3768,28 +3914,38 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
                        if (compressed)
                                nr++;
                        else
-                               btrfs_writepage_endio_finish_ordered(page, cur,
-                                                       cur + iosize - 1, 1);
+                               btrfs_writepage_endio_finish_ordered(inode,
+                                               page, cur, cur + iosize - 1, 1);
                        cur += iosize;
                        continue;
                }
 
-               btrfs_set_range_writeback(tree, cur, cur + iosize - 1);
+               btrfs_set_range_writeback(inode, cur, cur + iosize - 1);
                if (!PageWriteback(page)) {
                        btrfs_err(inode->root->fs_info,
                                   "page %lu not writeback, cur %llu end %llu",
                               page->index, cur, end);
                }
 
-               ret = submit_extent_page(opf | write_flags, wbc, page,
+               /*
+                * Although the PageDirty bit is cleared before entering this
+                * function, subpage dirty bit is not cleared.
+                * So clear subpage dirty bit here so next time we won't submit
+                * page for range already written to disk.
+                */
+               btrfs_page_clear_dirty(fs_info, page, cur, iosize);
+
+               ret = submit_extent_page(opf | write_flags, wbc,
+                                        &epd->bio_ctrl, page,
                                         disk_bytenr, iosize,
-                                        cur - page_offset(page), &epd->bio,
+                                        cur - page_offset(page),
                                         end_bio_extent_writepage,
-                                        0, 0, 0, false);
+                                        0, 0, false);
                if (ret) {
-                       SetPageError(page);
+                       btrfs_page_set_error(fs_info, page, cur, iosize);
                        if (PageWriteback(page))
-                               end_page_writeback(page);
+                               btrfs_page_clear_writeback(fs_info, page, cur,
+                                                          iosize);
                }
 
                cur += iosize;
@@ -4098,12 +4254,15 @@ static struct extent_buffer *find_extent_buffer_nolock(
  * Unlike end_bio_extent_buffer_writepage(), we only call end_page_writeback()
  * after all extent buffers in the page has finished their writeback.
  */
-static void end_bio_subpage_eb_writepage(struct btrfs_fs_info *fs_info,
-                                        struct bio *bio)
+static void end_bio_subpage_eb_writepage(struct bio *bio)
 {
+       struct btrfs_fs_info *fs_info;
        struct bio_vec *bvec;
        struct bvec_iter_all iter_all;
 
+       fs_info = btrfs_sb(bio_first_page_all(bio)->mapping->host->i_sb);
+       ASSERT(fs_info->sectorsize < PAGE_SIZE);
+
        ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, iter_all) {
                struct page *page = bvec->bv_page;
@@ -4154,16 +4313,11 @@ static void end_bio_subpage_eb_writepage(struct btrfs_fs_info *fs_info,
 
 static void end_bio_extent_buffer_writepage(struct bio *bio)
 {
-       struct btrfs_fs_info *fs_info;
        struct bio_vec *bvec;
        struct extent_buffer *eb;
        int done;
        struct bvec_iter_all iter_all;
 
-       fs_info = btrfs_sb(bio_first_page_all(bio)->mapping->host->i_sb);
-       if (fs_info->sectorsize < PAGE_SIZE)
-               return end_bio_subpage_eb_writepage(fs_info, bio);
-
        ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, iter_all) {
                struct page *page = bvec->bv_page;
@@ -4189,12 +4343,34 @@ static void end_bio_extent_buffer_writepage(struct bio *bio)
        bio_put(bio);
 }
 
+static void prepare_eb_write(struct extent_buffer *eb)
+{
+       u32 nritems;
+       unsigned long start;
+       unsigned long end;
+
+       clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags);
+       atomic_set(&eb->io_pages, num_extent_pages(eb));
+
+       /* Set btree blocks beyond nritems with 0 to avoid stale content */
+       nritems = btrfs_header_nritems(eb);
+       if (btrfs_header_level(eb) > 0) {
+               end = btrfs_node_key_ptr_offset(nritems);
+               memzero_extent_buffer(eb, end, eb->len - end);
+       } else {
+               /*
+                * Leaf:
+                * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0
+                */
+               start = btrfs_item_nr_offset(nritems);
+               end = BTRFS_LEAF_DATA_OFFSET + leaf_data_end(eb);
+               memzero_extent_buffer(eb, start, end - start);
+       }
+}
+
 /*
  * Unlike the work in write_one_eb(), we rely completely on extent locking.
  * Page locking is only utilized at minimum to keep the VMM code happy.
- *
- * Caller should still call write_one_eb() other than this function directly.
- * As write_one_eb() has extra preparation before submitting the extent buffer.
  */
 static int write_one_subpage_eb(struct extent_buffer *eb,
                                struct writeback_control *wbc,
@@ -4206,6 +4382,8 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
        bool no_dirty_ebs = false;
        int ret;
 
+       prepare_eb_write(eb);
+
        /* clear_page_dirty_for_io() in subpage helper needs page locked */
        lock_page(page);
        btrfs_subpage_set_writeback(fs_info, page, eb->start, eb->len);
@@ -4216,10 +4394,10 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
        if (no_dirty_ebs)
                clear_page_dirty_for_io(page);
 
-       ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc, page,
-                       eb->start, eb->len, eb->start - page_offset(page),
-                       &epd->bio, end_bio_extent_buffer_writepage, 0, 0, 0,
-                       false);
+       ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc,
+                       &epd->bio_ctrl, page, eb->start, eb->len,
+                       eb->start - page_offset(page),
+                       end_bio_subpage_eb_writepage, 0, 0, false);
        if (ret) {
                btrfs_subpage_clear_writeback(fs_info, page, eb->start, eb->len);
                set_btree_ioerr(page, eb);
@@ -4244,45 +4422,23 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
                        struct extent_page_data *epd)
 {
        u64 disk_bytenr = eb->start;
-       u32 nritems;
        int i, num_pages;
-       unsigned long start, end;
        unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META;
        int ret = 0;
 
-       clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags);
-       num_pages = num_extent_pages(eb);
-       atomic_set(&eb->io_pages, num_pages);
-
-       /* set btree blocks beyond nritems with 0 to avoid stale content. */
-       nritems = btrfs_header_nritems(eb);
-       if (btrfs_header_level(eb) > 0) {
-               end = btrfs_node_key_ptr_offset(nritems);
-
-               memzero_extent_buffer(eb, end, eb->len - end);
-       } else {
-               /*
-                * leaf:
-                * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0
-                */
-               start = btrfs_item_nr_offset(nritems);
-               end = BTRFS_LEAF_DATA_OFFSET + leaf_data_end(eb);
-               memzero_extent_buffer(eb, start, end - start);
-       }
-
-       if (eb->fs_info->sectorsize < PAGE_SIZE)
-               return write_one_subpage_eb(eb, wbc, epd);
+       prepare_eb_write(eb);
 
+       num_pages = num_extent_pages(eb);
        for (i = 0; i < num_pages; i++) {
                struct page *p = eb->pages[i];
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
                ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc,
-                                        p, disk_bytenr, PAGE_SIZE, 0,
-                                        &epd->bio,
+                                        &epd->bio_ctrl, p, disk_bytenr,
+                                        PAGE_SIZE, 0,
                                         end_bio_extent_buffer_writepage,
-                                        0, 0, 0, false);
+                                        0, 0, false);
                if (ret) {
                        set_btree_ioerr(p, eb);
                        if (PageWriteback(p))
@@ -4386,7 +4542,7 @@ static int submit_eb_subpage(struct page *page,
                        free_extent_buffer(eb);
                        goto cleanup;
                }
-               ret = write_one_eb(eb, wbc, epd);
+               ret = write_one_subpage_eb(eb, wbc, epd);
                free_extent_buffer(eb);
                if (ret < 0)
                        goto cleanup;
@@ -4498,7 +4654,7 @@ int btree_write_cache_pages(struct address_space *mapping,
 {
        struct extent_buffer *eb_context = NULL;
        struct extent_page_data epd = {
-               .bio = NULL,
+               .bio_ctrl = { 0 },
                .extent_locked = 0,
                .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
@@ -4780,7 +4936,7 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 {
        int ret;
        struct extent_page_data epd = {
-               .bio = NULL,
+               .bio_ctrl = { 0 },
                .extent_locked = 0,
                .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
@@ -4807,7 +4963,7 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
                PAGE_SHIFT;
 
        struct extent_page_data epd = {
-               .bio = NULL,
+               .bio_ctrl = { 0 },
                .extent_locked = 1,
                .sync_io = mode == WB_SYNC_ALL,
        };
@@ -4827,8 +4983,8 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
                if (clear_page_dirty_for_io(page))
                        ret = __extent_writepage(page, &wbc_writepages, &epd);
                else {
-                       btrfs_writepage_endio_finish_ordered(page, start,
-                                                   start + PAGE_SIZE - 1, 1);
+                       btrfs_writepage_endio_finish_ordered(BTRFS_I(inode),
+                                       page, start, start + PAGE_SIZE - 1, 1);
                        unlock_page(page);
                }
                put_page(page);
@@ -4850,7 +5006,7 @@ int extent_writepages(struct address_space *mapping,
 {
        int ret = 0;
        struct extent_page_data epd = {
-               .bio = NULL,
+               .bio_ctrl = { 0 },
                .extent_locked = 0,
                .sync_io = wbc->sync_mode == WB_SYNC_ALL,
        };
@@ -4867,8 +5023,7 @@ int extent_writepages(struct address_space *mapping,
 
 void extent_readahead(struct readahead_control *rac)
 {
-       struct bio *bio = NULL;
-       unsigned long bio_flags = 0;
+       struct btrfs_bio_ctrl bio_ctrl = { 0 };
        struct page *pagepool[16];
        struct extent_map *em_cached = NULL;
        u64 prev_em_start = (u64)-1;
@@ -4879,14 +5034,14 @@ void extent_readahead(struct readahead_control *rac)
                u64 contig_end = contig_start + readahead_batch_length(rac) - 1;
 
                contiguous_readpages(pagepool, nr, contig_start, contig_end,
-                               &em_cached, &bio, &bio_flags, &prev_em_start);
+                               &em_cached, &bio_ctrl, &prev_em_start);
        }
 
        if (em_cached)
                free_extent_map(em_cached);
 
-       if (bio) {
-               if (submit_one_bio(bio, 0, bio_flags))
+       if (bio_ctrl.bio) {
+               if (submit_one_bio(bio_ctrl.bio, 0, bio_ctrl.bio_flags))
                        return;
        }
 }
@@ -5429,6 +5584,12 @@ static bool page_range_has_eb(struct btrfs_fs_info *fs_info, struct page *page)
                subpage = (struct btrfs_subpage *)page->private;
                if (atomic_read(&subpage->eb_refs))
                        return true;
+               /*
+                * Even there is no eb refs here, we may still have
+                * end_page_read() call relying on page::private.
+                */
+               if (atomic_read(&subpage->readers))
+                       return true;
        }
        return false;
 }
@@ -5489,7 +5650,7 @@ static void detach_extent_buffer_page(struct extent_buffer *eb, struct page *pag
 
        /*
         * We can only detach the page private if there are no other ebs in the
-        * page range.
+        * page range and no unfinished IO.
         */
        if (!page_range_has_eb(fs_info, page))
                btrfs_detach_subpage(fs_info, page);
@@ -6176,7 +6337,7 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
        struct btrfs_fs_info *fs_info = eb->fs_info;
        struct extent_io_tree *io_tree;
        struct page *page = eb->pages[0];
-       struct bio *bio = NULL;
+       struct btrfs_bio_ctrl bio_ctrl = { 0 };
        int ret = 0;
 
        ASSERT(!test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags));
@@ -6184,10 +6345,8 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
        io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
 
        if (wait == WAIT_NONE) {
-               ret = try_lock_extent(io_tree, eb->start,
-                                     eb->start + eb->len - 1);
-               if (ret <= 0)
-                       return ret;
+               if (!try_lock_extent(io_tree, eb->start, eb->start + eb->len - 1))
+                       return -EAGAIN;
        } else {
                ret = lock_extent(io_tree, eb->start, eb->start + eb->len - 1);
                if (ret < 0)
@@ -6209,9 +6368,11 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
        check_buffer_tree_ref(eb);
        btrfs_subpage_clear_error(fs_info, page, eb->start, eb->len);
 
-       ret = submit_extent_page(REQ_OP_READ | REQ_META, NULL, page, eb->start,
-                                eb->len, eb->start - page_offset(page), &bio,
-                                end_bio_extent_readpage, mirror_num, 0, 0,
+       btrfs_subpage_start_reader(fs_info, page, eb->start, eb->len);
+       ret = submit_extent_page(REQ_OP_READ | REQ_META, NULL, &bio_ctrl,
+                                page, eb->start, eb->len,
+                                eb->start - page_offset(page),
+                                end_bio_extent_readpage, mirror_num, 0,
                                 true);
        if (ret) {
                /*
@@ -6221,10 +6382,11 @@ static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
                 */
                atomic_dec(&eb->io_pages);
        }
-       if (bio) {
+       if (bio_ctrl.bio) {
                int tmp;
 
-               tmp = submit_one_bio(bio, mirror_num, 0);
+               tmp = submit_one_bio(bio_ctrl.bio, mirror_num, 0);
+               bio_ctrl.bio = NULL;
                if (tmp < 0)
                        return tmp;
        }
@@ -6247,8 +6409,7 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
        int all_uptodate = 1;
        int num_pages;
        unsigned long num_reads = 0;
-       struct bio *bio = NULL;
-       unsigned long bio_flags = 0;
+       struct btrfs_bio_ctrl bio_ctrl = { 0 };
 
        if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
                return 0;
@@ -6312,9 +6473,9 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
 
                        ClearPageError(page);
                        err = submit_extent_page(REQ_OP_READ | REQ_META, NULL,
-                                        page, page_offset(page), PAGE_SIZE, 0,
-                                        &bio, end_bio_extent_readpage,
-                                        mirror_num, 0, 0, false);
+                                        &bio_ctrl, page, page_offset(page),
+                                        PAGE_SIZE, 0, end_bio_extent_readpage,
+                                        mirror_num, 0, false);
                        if (err) {
                                /*
                                 * We failed to submit the bio so it's the
@@ -6331,8 +6492,9 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
                }
        }
 
-       if (bio) {
-               err = submit_one_bio(bio, mirror_num, bio_flags);
+       if (bio_ctrl.bio) {
+               err = submit_one_bio(bio_ctrl.bio, mirror_num, bio_ctrl.bio_flags);
+               bio_ctrl.bio = NULL;
                if (err)
                        return err;
        }
@@ -6515,9 +6677,10 @@ void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
        char *kaddr;
 
        assert_eb_page_uptodate(eb, eb->pages[0]);
-       kaddr = page_address(eb->pages[0]) + get_eb_offset_in_page(eb, 0);
-       memcpy(kaddr + offsetof(struct btrfs_header, chunk_tree_uuid), srcv,
-                       BTRFS_FSID_SIZE);
+       kaddr = page_address(eb->pages[0]) +
+               get_eb_offset_in_page(eb, offsetof(struct btrfs_header,
+                                                  chunk_tree_uuid));
+       memcpy(kaddr, srcv, BTRFS_FSID_SIZE);
 }
 
 void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *srcv)
@@ -6525,9 +6688,9 @@ void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *srcv)
        char *kaddr;
 
        assert_eb_page_uptodate(eb, eb->pages[0]);
-       kaddr = page_address(eb->pages[0]) + get_eb_offset_in_page(eb, 0);
-       memcpy(kaddr + offsetof(struct btrfs_header, fsid), srcv,
-                       BTRFS_FSID_SIZE);
+       kaddr = page_address(eb->pages[0]) +
+               get_eb_offset_in_page(eb, offsetof(struct btrfs_header, fsid));
+       memcpy(kaddr, srcv, BTRFS_FSID_SIZE);
 }
 
 void write_extent_buffer(const struct extent_buffer *eb, const void *srcv,
index 227215a..62027f5 100644 (file)
@@ -39,7 +39,7 @@ enum {
 /* Page starts writeback, clear dirty bit and set writeback bit */
 #define PAGE_START_WRITEBACK   (1 << 1)
 #define PAGE_END_WRITEBACK     (1 << 2)
-#define PAGE_SET_PRIVATE2      (1 << 3)
+#define PAGE_SET_ORDERED       (1 << 3)
 #define PAGE_SET_ERROR         (1 << 4)
 #define PAGE_LOCK              (1 << 5)
 
@@ -102,6 +102,17 @@ struct extent_buffer {
 };
 
 /*
+ * Structure to record info about the bio being assembled, and other info like
+ * how many bytes are there before stripe/ordered extent boundary.
+ */
+struct btrfs_bio_ctrl {
+       struct bio *bio;
+       unsigned long bio_flags;
+       u32 len_to_stripe_boundary;
+       u32 len_to_oe_boundary;
+};
+
+/*
  * Structure to record how many bytes and which ranges are set/cleared
  */
 struct extent_changeset {
@@ -169,7 +180,7 @@ int try_release_extent_buffer(struct page *page);
 int __must_check submit_one_bio(struct bio *bio, int mirror_num,
                                unsigned long bio_flags);
 int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
-                     struct bio **bio, unsigned long *bio_flags,
+                     struct btrfs_bio_ctrl *bio_ctrl,
                      unsigned int read_flags, u64 *prev_em_start);
 int extent_write_full_page(struct page *page, struct writeback_control *wbc);
 int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
@@ -281,7 +292,7 @@ int btrfs_repair_eb_io_failure(const struct extent_buffer *eb, int mirror_num);
  * When IO fails, either with EIO or csum verification fails, we
  * try other mirrors that might have a good copy of the data.  This
  * io_failure_record is used to record state as we go through all the
- * mirrors.  If another mirror has good data, the page is set up to date
+ * mirrors.  If another mirror has good data, the sector is set up to date
  * and things continue.  If a good mirror can't be found, the original
  * bio end_io callback is called to indicate things have failed.
  */
@@ -293,15 +304,13 @@ struct io_failure_record {
        unsigned long bio_flags;
        int this_mirror;
        int failed_mirror;
-       int in_validation;
 };
 
-
-blk_status_t btrfs_submit_read_repair(struct inode *inode,
-                                     struct bio *failed_bio, u32 bio_offset,
-                                     struct page *page, unsigned int pgoff,
-                                     u64 start, u64 end, int failed_mirror,
-                                     submit_bio_hook_t *submit_bio_hook);
+int btrfs_repair_one_sector(struct inode *inode,
+                           struct bio *failed_bio, u32 bio_offset,
+                           struct page *page, unsigned int pgoff,
+                           u64 start, int failed_mirror,
+                           submit_bio_hook_t *submit_bio_hook);
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 bool find_lock_delalloc_range(struct inode *inode,
index 441cee7..df6631e 100644 (file)
@@ -618,7 +618,7 @@ fail:
  * @file_start:  offset in file this bio begins to describe
  * @contig:     Boolean. If true/1 means all bio vecs in this bio are
  *              contiguous and they begin at @file_start in the file. False/0
- *              means this bio can contains potentially discontigous bio vecs
+ *              means this bio can contain potentially discontiguous bio vecs
  *              so the logical offset of each should be calculated separately.
  */
 blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio,
index 55f6842..28a05ba 100644 (file)
@@ -28,6 +28,7 @@
 #include "compression.h"
 #include "delalloc-space.h"
 #include "reflink.h"
+#include "subpage.h"
 
 static struct kmem_cache *btrfs_inode_defrag_cachep;
 /*
@@ -482,6 +483,7 @@ int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages,
        start_pos = round_down(pos, fs_info->sectorsize);
        num_bytes = round_up(write_bytes + pos - start_pos,
                             fs_info->sectorsize);
+       ASSERT(num_bytes <= U32_MAX);
 
        end_of_last_block = start_pos + num_bytes - 1;
 
@@ -500,9 +502,10 @@ int btrfs_dirty_pages(struct btrfs_inode *inode, struct page **pages,
 
        for (i = 0; i < num_pages; i++) {
                struct page *p = pages[i];
-               SetPageUptodate(p);
+
+               btrfs_page_clamp_set_uptodate(fs_info, p, start_pos, num_bytes);
                ClearPageChecked(p);
-               set_page_dirty(p);
+               btrfs_page_clamp_set_dirty(fs_info, p, start_pos, num_bytes);
        }
 
        /*
@@ -2483,6 +2486,17 @@ static int btrfs_punch_hole_lock_range(struct inode *inode,
                                       const u64 lockend,
                                       struct extent_state **cached_state)
 {
+       /*
+        * For subpage case, if the range is not at page boundary, we could
+        * have pages at the leading/tailing part of the range.
+        * This could lead to dead loop since filemap_range_has_page()
+        * will always return true.
+        * So here we need to do extra page alignment for
+        * filemap_range_has_page().
+        */
+       const u64 page_lockstart = round_up(lockstart, PAGE_SIZE);
+       const u64 page_lockend = round_down(lockend + 1, PAGE_SIZE) - 1;
+
        while (1) {
                struct btrfs_ordered_extent *ordered;
                int ret;
@@ -2503,7 +2517,7 @@ static int btrfs_punch_hole_lock_range(struct inode *inode,
                    (ordered->file_offset + ordered->num_bytes <= lockstart ||
                     ordered->file_offset > lockend)) &&
                     !filemap_range_has_page(inode->i_mapping,
-                                            lockstart, lockend)) {
+                                            page_lockstart, page_lockend)) {
                        if (ordered)
                                btrfs_put_ordered_extent(ordered);
                        break;
@@ -3034,22 +3048,20 @@ struct falloc_range {
  */
 static int add_falloc_range(struct list_head *head, u64 start, u64 len)
 {
-       struct falloc_range *prev = NULL;
        struct falloc_range *range = NULL;
 
-       if (list_empty(head))
-               goto insert;
-
-       /*
-        * As fallocate iterate by bytenr order, we only need to check
-        * the last range.
-        */
-       prev = list_entry(head->prev, struct falloc_range, list);
-       if (prev->start + prev->len == start) {
-               prev->len += len;
-               return 0;
+       if (!list_empty(head)) {
+               /*
+                * As fallocate iterates by bytenr order, we only need to check
+                * the last range.
+                */
+               range = list_last_entry(head, struct falloc_range, list);
+               if (range->start + range->len == start) {
+                       range->len += len;
+                       return 0;
+               }
        }
-insert:
+
        range = kmalloc(sizeof(*range), GFP_KERNEL);
        if (!range)
                return -ENOMEM;
index 4806295..2131ae5 100644 (file)
@@ -327,7 +327,7 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
         * need to check for -EAGAIN.
         */
        ret = btrfs_truncate_inode_items(trans, root, BTRFS_I(inode),
-                                        0, BTRFS_EXTENT_DATA_KEY);
+                                        0, BTRFS_EXTENT_DATA_KEY, NULL);
        if (ret)
                goto fail;
 
index 46f3929..e6eb209 100644 (file)
@@ -51,6 +51,7 @@
 #include "block-group.h"
 #include "space-info.h"
 #include "zoned.h"
+#include "subpage.h"
 
 struct btrfs_iget_args {
        u64 ino;
@@ -166,22 +167,47 @@ static inline void btrfs_cleanup_ordered_extents(struct btrfs_inode *inode,
        struct page *page;
 
        while (index <= end_index) {
+               /*
+                * For locked page, we will call end_extent_writepage() on it
+                * in run_delalloc_range() for the error handling.  That
+                * end_extent_writepage() function will call
+                * btrfs_mark_ordered_io_finished() to clear page Ordered and
+                * run the ordered extent accounting.
+                *
+                * Here we can't just clear the Ordered bit, or
+                * btrfs_mark_ordered_io_finished() would skip the accounting
+                * for the page range, and the ordered extent will never finish.
+                */
+               if (index == (page_offset(locked_page) >> PAGE_SHIFT)) {
+                       index++;
+                       continue;
+               }
                page = find_get_page(inode->vfs_inode.i_mapping, index);
                index++;
                if (!page)
                        continue;
-               ClearPagePrivate2(page);
+
+               /*
+                * Here we just clear all Ordered bits for every page in the
+                * range, then __endio_write_update_ordered() will handle
+                * the ordered extent accounting for the range.
+                */
+               btrfs_page_clamp_clear_ordered(inode->root->fs_info, page,
+                                              offset, bytes);
                put_page(page);
        }
 
+       /* The locked page covers the full range, nothing needs to be done */
+       if (bytes + offset <= page_offset(locked_page) + PAGE_SIZE)
+               return;
        /*
         * In case this page belongs to the delalloc range being instantiated
         * then skip it, since the first page of a range is going to be
         * properly cleaned up by the caller of run_delalloc_range
         */
        if (page_start >= offset && page_end <= (offset + bytes - 1)) {
-               offset += PAGE_SIZE;
-               bytes -= PAGE_SIZE;
+               bytes = offset + bytes - page_offset(locked_page) - PAGE_SIZE;
+               offset = page_offset(locked_page) + PAGE_SIZE;
        }
 
        return __endio_write_update_ordered(inode, offset, bytes, false);
@@ -603,7 +629,7 @@ again:
         * inode has not been flagged as nocompress.  This flag can
         * change at any time if we discover bad compression ratios.
         */
-       if (inode_need_compress(BTRFS_I(inode), start, end)) {
+       if (nr_pages > 1 && inode_need_compress(BTRFS_I(inode), start, end)) {
                WARN_ON(pages);
                pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
                if (!pages) {
@@ -946,7 +972,8 @@ retry:
                        const u64 end = start + async_extent->ram_size - 1;
 
                        p->mapping = inode->vfs_inode.i_mapping;
-                       btrfs_writepage_endio_finish_ordered(p, start, end, 0);
+                       btrfs_writepage_endio_finish_ordered(inode, p, start,
+                                                            end, 0);
 
                        p->mapping = NULL;
                        extent_clear_unlock_delalloc(inode, start, end, NULL, 0,
@@ -1064,7 +1091,8 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
                         * our outstanding extent for clearing delalloc for this
                         * range.
                         */
-                       extent_clear_unlock_delalloc(inode, start, end, NULL,
+                       extent_clear_unlock_delalloc(inode, start, end,
+                                    locked_page,
                                     EXTENT_LOCKED | EXTENT_DELALLOC |
                                     EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
                                     EXTENT_DO_ACCOUNTING, PAGE_UNLOCK |
@@ -1072,6 +1100,19 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
                        *nr_written = *nr_written +
                             (end - start + PAGE_SIZE) / PAGE_SIZE;
                        *page_started = 1;
+                       /*
+                        * locked_page is locked by the caller of
+                        * writepage_delalloc(), not locked by
+                        * __process_pages_contig().
+                        *
+                        * We can't let __process_pages_contig() to unlock it,
+                        * as it doesn't have any subpage::writers recorded.
+                        *
+                        * Here we manually unlock the page, since the caller
+                        * can't use page_started to determine if it's an
+                        * inline extent or a compressed extent.
+                        */
+                       unlock_page(locked_page);
                        goto out;
                } else if (ret < 0) {
                        goto out_unlock;
@@ -1150,15 +1191,16 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
 
                btrfs_dec_block_group_reservations(fs_info, ins.objectid);
 
-               /* we're not doing compressed IO, don't unlock the first
-                * page (which the caller expects to stay locked), don't
-                * clear any dirty bits and don't set any writeback bits
+               /*
+                * We're not doing compressed IO, don't unlock the first page
+                * (which the caller expects to stay locked), don't clear any
+                * dirty bits and don't set any writeback bits
                 *
-                * Do set the Private2 bit so we know this page was properly
-                * setup for writepage
+                * Do set the Ordered (Private2) bit so we know this page was
+                * properly setup for writepage.
                 */
                page_ops = unlock ? PAGE_UNLOCK : 0;
-               page_ops |= PAGE_SET_PRIVATE2;
+               page_ops |= PAGE_SET_ORDERED;
 
                extent_clear_unlock_delalloc(inode, start, start + ram_size - 1,
                                             locked_page,
@@ -1822,7 +1864,7 @@ out_check:
                                             locked_page, EXTENT_LOCKED |
                                             EXTENT_DELALLOC |
                                             EXTENT_CLEAR_DATA_RESV,
-                                            PAGE_UNLOCK | PAGE_SET_PRIVATE2);
+                                            PAGE_UNLOCK | PAGE_SET_ORDERED);
 
                cur_offset = extent_end;
 
@@ -2193,26 +2235,22 @@ int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio,
        struct inode *inode = page->mapping->host;
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        u64 logical = bio->bi_iter.bi_sector << 9;
+       u32 bio_len = bio->bi_iter.bi_size;
        struct extent_map *em;
-       u64 length = 0;
-       u64 map_length;
        int ret = 0;
        struct btrfs_io_geometry geom;
 
        if (bio_flags & EXTENT_BIO_COMPRESSED)
                return 0;
 
-       length = bio->bi_iter.bi_size;
-       map_length = length;
-       em = btrfs_get_chunk_map(fs_info, logical, map_length);
+       em = btrfs_get_chunk_map(fs_info, logical, fs_info->sectorsize);
        if (IS_ERR(em))
                return PTR_ERR(em);
-       ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(bio), logical,
-                                   map_length, &geom);
+       ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(bio), logical, &geom);
        if (ret < 0)
                goto out;
 
-       if (geom.len < length + size)
+       if (geom.len < bio_len + size)
                ret = 1;
 out:
        free_extent_map(em);
@@ -2233,33 +2271,6 @@ static blk_status_t btrfs_submit_bio_start(struct inode *inode, struct bio *bio,
        return btrfs_csum_one_bio(BTRFS_I(inode), bio, 0, 0);
 }
 
-bool btrfs_bio_fits_in_ordered_extent(struct page *page, struct bio *bio,
-                                     unsigned int size)
-{
-       struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct btrfs_ordered_extent *ordered;
-       u64 len = bio->bi_iter.bi_size + size;
-       bool ret = true;
-
-       ASSERT(btrfs_is_zoned(fs_info));
-       ASSERT(fs_info->max_zone_append_size > 0);
-       ASSERT(bio_op(bio) == REQ_OP_ZONE_APPEND);
-
-       /* Ordered extent not yet created, so we're good */
-       ordered = btrfs_lookup_ordered_extent(inode, page_offset(page));
-       if (!ordered)
-               return ret;
-
-       if ((bio->bi_iter.bi_sector << SECTOR_SHIFT) + len >
-           ordered->disk_bytenr + ordered->disk_num_bytes)
-               ret = false;
-
-       btrfs_put_ordered_extent(ordered);
-
-       return ret;
-}
-
 static blk_status_t extract_ordered_extent(struct btrfs_inode *inode,
                                           struct bio *bio, loff_t file_offset)
 {
@@ -2601,7 +2612,7 @@ again:
        lock_extent_bits(&inode->io_tree, page_start, page_end, &cached_state);
 
        /* already ordered? We're done */
-       if (PagePrivate2(page))
+       if (PageOrdered(page))
                goto out_reserved;
 
        ordered = btrfs_lookup_ordered_range(inode, page_start, PAGE_SIZE);
@@ -2676,8 +2687,8 @@ int btrfs_writepage_cow_fixup(struct page *page, u64 start, u64 end)
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_writepage_fixup *fixup;
 
-       /* this page is properly in the ordered list */
-       if (TestClearPagePrivate2(page))
+       /* This page has ordered extent covering it already */
+       if (PageOrdered(page))
                return 0;
 
        /*
@@ -2773,7 +2784,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        /*
         * If we dropped an inline extent here, we know the range where it is
         * was not marked with the EXTENT_DELALLOC_NEW bit, so we update the
-        * number of bytes only for that range contaning the inline extent.
+        * number of bytes only for that range containing the inline extent.
         * The remaining of the range will be processed when clearning the
         * EXTENT_DELALLOC_BIT bit through the ordered extent completion.
         */
@@ -3069,28 +3080,14 @@ static void finish_ordered_fn(struct btrfs_work *work)
        btrfs_finish_ordered_io(ordered_extent);
 }
 
-void btrfs_writepage_endio_finish_ordered(struct page *page, u64 start,
+void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
+                                         struct page *page, u64 start,
                                          u64 end, int uptodate)
 {
-       struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct btrfs_ordered_extent *ordered_extent = NULL;
-       struct btrfs_workqueue *wq;
-
-       trace_btrfs_writepage_end_io_hook(page, start, end, uptodate);
-
-       ClearPagePrivate2(page);
-       if (!btrfs_dec_test_ordered_pending(inode, &ordered_extent, start,
-                                           end - start + 1, uptodate))
-               return;
+       trace_btrfs_writepage_end_io_hook(inode, start, end, uptodate);
 
-       if (btrfs_is_free_space_inode(inode))
-               wq = fs_info->endio_freespace_worker;
-       else
-               wq = fs_info->endio_write_workers;
-
-       btrfs_init_work(&ordered_extent->work, finish_ordered_fn, NULL, NULL);
-       btrfs_queue_work(wq, &ordered_extent->work);
+       btrfs_mark_ordered_io_finished(inode, page, start, end + 1 - start,
+                                      finish_ordered_fn, uptodate);
 }
 
 /*
@@ -3152,15 +3149,19 @@ zeroit:
  * @bio_offset:        offset to the beginning of the bio (in bytes)
  * @start:     file offset of the range start
  * @end:       file offset of the range end (inclusive)
+ *
+ * Return a bitmap where bit set means a csum mismatch, and bit not set means
+ * csum match.
  */
-int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
-                          struct page *page, u64 start, u64 end)
+unsigned int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
+                                   struct page *page, u64 start, u64 end)
 {
        struct inode *inode = page->mapping->host;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        const u32 sectorsize = root->fs_info->sectorsize;
        u32 pg_off;
+       unsigned int result = 0;
 
        if (PageChecked(page)) {
                ClearPageChecked(page);
@@ -3188,10 +3189,14 @@ int btrfs_verify_data_csum(struct btrfs_io_bio *io_bio, u32 bio_offset,
 
                ret = check_data_csum(inode, io_bio, bio_offset, page, pg_off,
                                      page_offset(page) + pg_off);
-               if (ret < 0)
-                       return -EIO;
+               if (ret < 0) {
+                       const int nr_bit = (pg_off - offset_in_page(start)) >>
+                                    root->fs_info->sectorsize_bits;
+
+                       result |= (1U << nr_bit);
+               }
        }
-       return 0;
+       return result;
 }
 
 /*
@@ -4109,7 +4114,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
         * This is a placeholder inode for a subvolume we didn't have a
         * reference to at the time of the snapshot creation.  In the meantime
         * we could have renamed the real subvol link into our snapshot, so
-        * depending on btrfs_del_root_ref to return -ENOENT here is incorret.
+        * depending on btrfs_del_root_ref to return -ENOENT here is incorrect.
         * Instead simply lookup the dir_index_item for this entry so we can
         * remove it.  Otherwise we know we have a ref to the root and we can
         * call btrfs_del_root_ref, and it _shouldn't_ fail.
@@ -4464,20 +4469,36 @@ out:
 #define NEED_TRUNCATE_BLOCK 1
 
 /*
- * this can truncate away extent items, csum items and directory items.
- * It starts at a high offset and removes keys until it can't find
- * any higher than new_size
+ * Remove inode items from a given root.
  *
- * csum items that cross the new i_size are truncated to the new size
- * as well.
+ * @trans:             A transaction handle.
+ * @root:              The root from which to remove items.
+ * @inode:             The inode whose items we want to remove.
+ * @new_size:          The new i_size for the inode. This is only applicable when
+ *                     @min_type is BTRFS_EXTENT_DATA_KEY, must be 0 otherwise.
+ * @min_type:          The minimum key type to remove. All keys with a type
+ *                     greater than this value are removed and all keys with
+ *                     this type are removed only if their offset is >= @new_size.
+ * @extents_found:     Output parameter that will contain the number of file
+ *                     extent items that were removed or adjusted to the new
+ *                     inode i_size. The caller is responsible for initializing
+ *                     the counter. Also, it can be NULL if the caller does not
+ *                     need this counter.
  *
- * min_type is the minimum key type to truncate down to.  If set to 0, this
- * will kill all the items on this inode, including the INODE_ITEM_KEY.
+ * Remove all keys associated with the inode from the given root that have a key
+ * with a type greater than or equals to @min_type. When @min_type has a value of
+ * BTRFS_EXTENT_DATA_KEY, only remove file extent items that have an offset value
+ * greater than or equals to @new_size. If a file extent item that starts before
+ * @new_size and ends after it is found, its length is adjusted.
+ *
+ * Returns: 0 on success, < 0 on error and NEED_TRUNCATE_BLOCK when @min_type is
+ * BTRFS_EXTENT_DATA_KEY and the caller must truncate the last block.
  */
 int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               struct btrfs_inode *inode,
-                              u64 new_size, u32 min_type)
+                              u64 new_size, u32 min_type,
+                              u64 *extents_found)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_path *path;
@@ -4623,6 +4644,9 @@ search_again:
                if (found_type != BTRFS_EXTENT_DATA_KEY)
                        goto delete;
 
+               if (extents_found != NULL)
+                       (*extents_found)++;
+
                if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                        u64 num_dec;
 
@@ -4941,7 +4965,7 @@ again:
                flush_dcache_page(page);
        }
        ClearPageChecked(page);
-       set_page_dirty(page);
+       btrfs_page_set_dirty(fs_info, page, block_start, block_end + 1 - block_start);
        unlock_extent_cached(io_tree, block_start, block_end, &cached_state);
 
        if (only_release_metadata)
@@ -5455,7 +5479,7 @@ void btrfs_evict_inode(struct inode *inode)
                trans->block_rsv = rsv;
 
                ret = btrfs_truncate_inode_items(trans, root, BTRFS_I(inode),
-                                                0, 0);
+                                                0, 0, NULL);
                trans->block_rsv = &fs_info->trans_block_rsv;
                btrfs_end_transaction(trans);
                btrfs_btree_balance_dirty(fs_info);
@@ -7937,19 +7961,17 @@ static blk_status_t btrfs_check_read_dio_bio(struct inode *inode,
                                                 btrfs_ino(BTRFS_I(inode)),
                                                 pgoff);
                        } else {
-                               blk_status_t status;
+                               int ret;
 
                                ASSERT((start - io_bio->logical) < UINT_MAX);
-                               status = btrfs_submit_read_repair(inode,
-                                                       &io_bio->bio,
-                                                       start - io_bio->logical,
-                                                       bvec.bv_page, pgoff,
-                                                       start,
-                                                       start + sectorsize - 1,
-                                                       io_bio->mirror_num,
-                                                       submit_dio_repair_bio);
-                               if (status)
-                                       err = status;
+                               ret = btrfs_repair_one_sector(inode,
+                                               &io_bio->bio,
+                                               start - io_bio->logical,
+                                               bvec.bv_page, pgoff,
+                                               start, io_bio->mirror_num,
+                                               submit_dio_repair_bio);
+                               if (ret)
+                                       err = errno_to_blk_status(ret);
                        }
                        start += sectorsize;
                        ASSERT(bio_offset + sectorsize > bio_offset);
@@ -7964,41 +7986,8 @@ static void __endio_write_update_ordered(struct btrfs_inode *inode,
                                         const u64 offset, const u64 bytes,
                                         const bool uptodate)
 {
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct btrfs_ordered_extent *ordered = NULL;
-       struct btrfs_workqueue *wq;
-       u64 ordered_offset = offset;
-       u64 ordered_bytes = bytes;
-       u64 last_offset;
-
-       if (btrfs_is_free_space_inode(inode))
-               wq = fs_info->endio_freespace_worker;
-       else
-               wq = fs_info->endio_write_workers;
-
-       while (ordered_offset < offset + bytes) {
-               last_offset = ordered_offset;
-               if (btrfs_dec_test_first_ordered_pending(inode, &ordered,
-                                                        &ordered_offset,
-                                                        ordered_bytes,
-                                                        uptodate)) {
-                       btrfs_init_work(&ordered->work, finish_ordered_fn, NULL,
-                                       NULL);
-                       btrfs_queue_work(wq, &ordered->work);
-               }
-
-               /* No ordered extent found in the range, exit */
-               if (ordered_offset == last_offset)
-                       return;
-               /*
-                * Our bio might span multiple ordered extents. In this case
-                * we keep going until we have accounted the whole dio.
-                */
-               if (ordered_offset < offset + bytes) {
-                       ordered_bytes = offset + bytes - ordered_offset;
-                       ordered = NULL;
-               }
-       }
+       btrfs_mark_ordered_io_finished(inode, NULL, offset, bytes,
+                                      finish_ordered_fn, uptodate);
 }
 
 static blk_status_t btrfs_submit_bio_start_direct_io(struct inode *inode,
@@ -8172,7 +8161,7 @@ static blk_qc_t btrfs_submit_direct(struct inode *inode, struct iomap *iomap,
                        goto out_err_em;
                }
                ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(dio_bio),
-                                           logical, submit_len, &geom);
+                                           logical, &geom);
                if (ret) {
                        status = errno_to_blk_status(ret);
                        goto out_err_em;
@@ -8276,15 +8265,14 @@ int btrfs_readpage(struct file *file, struct page *page)
        struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
        u64 start = page_offset(page);
        u64 end = start + PAGE_SIZE - 1;
-       unsigned long bio_flags = 0;
-       struct bio *bio = NULL;
+       struct btrfs_bio_ctrl bio_ctrl = { 0 };
        int ret;
 
        btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
 
-       ret = btrfs_do_readpage(page, NULL, &bio, &bio_flags, 0, NULL);
-       if (bio)
-               ret = submit_one_bio(bio, 0, bio_flags);
+       ret = btrfs_do_readpage(page, NULL, &bio_ctrl, 0, NULL);
+       if (bio_ctrl.bio)
+               ret = submit_one_bio(bio_ctrl.bio, 0, bio_ctrl.bio_flags);
        return ret;
 }
 
@@ -8353,9 +8341,9 @@ static int btrfs_migratepage(struct address_space *mapping,
        if (page_has_private(page))
                attach_page_private(newpage, detach_page_private(page));
 
-       if (PagePrivate2(page)) {
-               ClearPagePrivate2(page);
-               SetPagePrivate2(newpage);
+       if (PageOrdered(page)) {
+               ClearPageOrdered(page);
+               SetPageOrdered(newpage);
        }
 
        if (mode != MIGRATE_SYNC_NO_COPY)
@@ -8370,27 +8358,42 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
                                 unsigned int length)
 {
        struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct extent_io_tree *tree = &inode->io_tree;
-       struct btrfs_ordered_extent *ordered;
        struct extent_state *cached_state = NULL;
        u64 page_start = page_offset(page);
        u64 page_end = page_start + PAGE_SIZE - 1;
-       u64 start;
-       u64 end;
+       u64 cur;
        int inode_evicting = inode->vfs_inode.i_state & I_FREEING;
-       bool found_ordered = false;
-       bool completed_ordered = false;
 
        /*
-        * we have the page locked, so new writeback can't start,
-        * and the dirty bit won't be cleared while we are here.
+        * We have page locked so no new ordered extent can be created on this
+        * page, nor bio can be submitted for this page.
+        *
+        * But already submitted bio can still be finished on this page.
+        * Furthermore, endio function won't skip page which has Ordered
+        * (Private2) already cleared, so it's possible for endio and
+        * invalidatepage to do the same ordered extent accounting twice
+        * on one page.
         *
-        * Wait for IO on this page so that we can safely clear
-        * the PagePrivate2 bit and do ordered accounting
+        * So here we wait for any submitted bios to finish, so that we won't
+        * do double ordered extent accounting on the same page.
         */
        wait_on_page_writeback(page);
 
-       if (offset) {
+       /*
+        * For subpage case, we have call sites like
+        * btrfs_punch_hole_lock_range() which passes range not aligned to
+        * sectorsize.
+        * If the range doesn't cover the full page, we don't need to and
+        * shouldn't clear page extent mapped, as page->private can still
+        * record subpage dirty bits for other part of the range.
+        *
+        * For cases that can invalidate the full even the range doesn't
+        * cover the full page, like invalidating the last page, we're
+        * still safe to wait for ordered extent to finish.
+        */
+       if (!(offset == 0 && length == PAGE_SIZE)) {
                btrfs_releasepage(page, GFP_NOFS);
                return;
        }
@@ -8398,89 +8401,123 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
        if (!inode_evicting)
                lock_extent_bits(tree, page_start, page_end, &cached_state);
 
-       start = page_start;
-again:
-       ordered = btrfs_lookup_ordered_range(inode, start, page_end - start + 1);
-       if (ordered) {
-               found_ordered = true;
-               end = min(page_end,
-                         ordered->file_offset + ordered->num_bytes - 1);
+       cur = page_start;
+       while (cur < page_end) {
+               struct btrfs_ordered_extent *ordered;
+               bool delete_states;
+               u64 range_end;
+               u32 range_len;
+
+               ordered = btrfs_lookup_first_ordered_range(inode, cur,
+                                                          page_end + 1 - cur);
+               if (!ordered) {
+                       range_end = page_end;
+                       /*
+                        * No ordered extent covering this range, we are safe
+                        * to delete all extent states in the range.
+                        */
+                       delete_states = true;
+                       goto next;
+               }
+               if (ordered->file_offset > cur) {
+                       /*
+                        * There is a range between [cur, oe->file_offset) not
+                        * covered by any ordered extent.
+                        * We are safe to delete all extent states, and handle
+                        * the ordered extent in the next iteration.
+                        */
+                       range_end = ordered->file_offset - 1;
+                       delete_states = true;
+                       goto next;
+               }
+
+               range_end = min(ordered->file_offset + ordered->num_bytes - 1,
+                               page_end);
+               ASSERT(range_end + 1 - cur < U32_MAX);
+               range_len = range_end + 1 - cur;
+               if (!btrfs_page_test_ordered(fs_info, page, cur, range_len)) {
+                       /*
+                        * If Ordered (Private2) is cleared, it means endio has
+                        * already been executed for the range.
+                        * We can't delete the extent states as
+                        * btrfs_finish_ordered_io() may still use some of them.
+                        */
+                       delete_states = false;
+                       goto next;
+               }
+               btrfs_page_clear_ordered(fs_info, page, cur, range_len);
+
                /*
                 * IO on this page will never be started, so we need to account
                 * for any ordered extents now. Don't clear EXTENT_DELALLOC_NEW
                 * here, must leave that up for the ordered extent completion.
+                *
+                * This will also unlock the range for incoming
+                * btrfs_finish_ordered_io().
                 */
                if (!inode_evicting)
-                       clear_extent_bit(tree, start, end,
+                       clear_extent_bit(tree, cur, range_end,
                                         EXTENT_DELALLOC |
                                         EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
                                         EXTENT_DEFRAG, 1, 0, &cached_state);
+
+               spin_lock_irq(&inode->ordered_tree.lock);
+               set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
+               ordered->truncated_len = min(ordered->truncated_len,
+                                            cur - ordered->file_offset);
+               spin_unlock_irq(&inode->ordered_tree.lock);
+
+               if (btrfs_dec_test_ordered_pending(inode, &ordered,
+                                       cur, range_end + 1 - cur, 1)) {
+                       btrfs_finish_ordered_io(ordered);
+                       /*
+                        * The ordered extent has finished, now we're again
+                        * safe to delete all extent states of the range.
+                        */
+                       delete_states = true;
+               } else {
+                       /*
+                        * btrfs_finish_ordered_io() will get executed by endio
+                        * of other pages, thus we can't delete extent states
+                        * anymore
+                        */
+                       delete_states = false;
+               }
+next:
+               if (ordered)
+                       btrfs_put_ordered_extent(ordered);
                /*
-                * whoever cleared the private bit is responsible
-                * for the finish_ordered_io
+                * Qgroup reserved space handler
+                * Sector(s) here will be either:
+                *
+                * 1) Already written to disk or bio already finished
+                *    Then its QGROUP_RESERVED bit in io_tree is already cleared.
+                *    Qgroup will be handled by its qgroup_record then.
+                *    btrfs_qgroup_free_data() call will do nothing here.
+                *
+                * 2) Not written to disk yet
+                *    Then btrfs_qgroup_free_data() call will clear the
+                *    QGROUP_RESERVED bit of its io_tree, and free the qgroup
+                *    reserved data space.
+                *    Since the IO will never happen for this page.
                 */
-               if (TestClearPagePrivate2(page)) {
-                       spin_lock_irq(&inode->ordered_tree.lock);
-                       set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
-                       ordered->truncated_len = min(ordered->truncated_len,
-                                                    start - ordered->file_offset);
-                       spin_unlock_irq(&inode->ordered_tree.lock);
-
-                       if (btrfs_dec_test_ordered_pending(inode, &ordered,
-                                                          start,
-                                                          end - start + 1, 1)) {
-                               btrfs_finish_ordered_io(ordered);
-                               completed_ordered = true;
-                       }
-               }
-               btrfs_put_ordered_extent(ordered);
+               btrfs_qgroup_free_data(inode, NULL, cur, range_end + 1 - cur);
                if (!inode_evicting) {
-                       cached_state = NULL;
-                       lock_extent_bits(tree, start, end,
-                                        &cached_state);
+                       clear_extent_bit(tree, cur, range_end, EXTENT_LOCKED |
+                                EXTENT_DELALLOC | EXTENT_UPTODATE |
+                                EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1,
+                                delete_states, &cached_state);
                }
-
-               start = end + 1;
-               if (start < page_end)
-                       goto again;
+               cur = range_end + 1;
        }
-
        /*
-        * Qgroup reserved space handler
-        * Page here will be either
-        * 1) Already written to disk or ordered extent already submitted
-        *    Then its QGROUP_RESERVED bit in io_tree is already cleaned.
-        *    Qgroup will be handled by its qgroup_record then.
-        *    btrfs_qgroup_free_data() call will do nothing here.
-        *
-        * 2) Not written to disk yet
-        *    Then btrfs_qgroup_free_data() call will clear the QGROUP_RESERVED
-        *    bit of its io_tree, and free the qgroup reserved data space.
-        *    Since the IO will never happen for this page.
+        * We have iterated through all ordered extents of the page, the page
+        * should not have Ordered (Private2) anymore, or the above iteration
+        * did something wrong.
         */
-       btrfs_qgroup_free_data(inode, NULL, page_start, PAGE_SIZE);
-       if (!inode_evicting) {
-               bool delete = true;
-
-               /*
-                * If there's an ordered extent for this range and we have not
-                * finished it ourselves, we must leave EXTENT_DELALLOC_NEW set
-                * in the range for the ordered extent completion. We must also
-                * not delete the range, otherwise we would lose that bit (and
-                * any other bits set in the range). Make sure EXTENT_UPTODATE
-                * is cleared if we don't delete, otherwise it can lead to
-                * corruptions if the i_size is extented later.
-                */
-               if (found_ordered && !completed_ordered)
-                       delete = false;
-               clear_extent_bit(tree, page_start, page_end, EXTENT_LOCKED |
-                                EXTENT_DELALLOC | EXTENT_UPTODATE |
-                                EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1,
-                                delete, &cached_state);
-
+       ASSERT(!PageOrdered(page));
+       if (!inode_evicting)
                __btrfs_releasepage(page, GFP_NOFS);
-       }
-
        ClearPageChecked(page);
        clear_page_extent_mapped(page);
 }
@@ -8626,8 +8663,8 @@ again:
                flush_dcache_page(page);
        }
        ClearPageChecked(page);
-       set_page_dirty(page);
-       SetPageUptodate(page);
+       btrfs_page_set_dirty(fs_info, page, page_start, end + 1 - page_start);
+       btrfs_page_set_uptodate(fs_info, page, page_start, end + 1 - page_start);
 
        btrfs_set_inode_last_sub_trans(BTRFS_I(inode));
 
@@ -8661,6 +8698,7 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
        struct btrfs_trans_handle *trans;
        u64 mask = fs_info->sectorsize - 1;
        u64 min_size = btrfs_calc_metadata_size(fs_info, 1);
+       u64 extents_found = 0;
 
        if (!skip_writeback) {
                ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
@@ -8718,20 +8756,13 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
                                      min_size, false);
        BUG_ON(ret);
 
-       /*
-        * So if we truncate and then write and fsync we normally would just
-        * write the extents that changed, which is a problem if we need to
-        * first truncate that entire inode.  So set this flag so we write out
-        * all of the extents in the inode to the sync log so we're completely
-        * safe.
-        */
-       set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
        trans->block_rsv = rsv;
 
        while (1) {
                ret = btrfs_truncate_inode_items(trans, root, BTRFS_I(inode),
                                                 inode->i_size,
-                                                BTRFS_EXTENT_DATA_KEY);
+                                                BTRFS_EXTENT_DATA_KEY,
+                                                &extents_found);
                trans->block_rsv = &fs_info->trans_block_rsv;
                if (ret != -ENOSPC && ret != -EAGAIN)
                        break;
@@ -8793,6 +8824,22 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
        }
 out:
        btrfs_free_block_rsv(fs_info, rsv);
+       /*
+        * So if we truncate and then write and fsync we normally would just
+        * write the extents that changed, which is a problem if we need to
+        * first truncate that entire inode.  So set this flag so we write out
+        * all of the extents in the inode to the sync log so we're completely
+        * safe.
+        *
+        * If no extents were dropped or trimmed we don't need to force the next
+        * fsync to truncate all the inode's items from the log and re-log them
+        * all. This means the truncate operation did not change the file size,
+        * or changed it to a smaller size but there was only an implicit hole
+        * between the old i_size and the new i_size, and there were no prealloc
+        * extents beyond i_size to drop.
+        */
+       if (extents_found > 0)
+               set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
 
        return ret;
 }
@@ -10199,17 +10246,21 @@ out:
        return ret;
 }
 
-void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
+void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end)
 {
-       struct inode *inode = tree->private_data;
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
        unsigned long index = start >> PAGE_SHIFT;
        unsigned long end_index = end >> PAGE_SHIFT;
        struct page *page;
+       u32 len;
 
+       ASSERT(end + 1 - start <= U32_MAX);
+       len = end + 1 - start;
        while (index <= end_index) {
-               page = find_get_page(inode->i_mapping, index);
+               page = find_get_page(inode->vfs_inode.i_mapping, index);
                ASSERT(page); /* Pages should be in the extent_io_tree */
-               set_page_writeback(page);
+
+               btrfs_page_set_writeback(fs_info, page, start, len);
                put_page(page);
                index++;
        }
index 5dc2fd8..0ba98e0 100644 (file)
@@ -353,15 +353,55 @@ update_flags:
        return ret;
 }
 
+/*
+ * Start exclusive operation @type, return true on success
+ */
 bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
                        enum btrfs_exclusive_operation type)
 {
-       return !cmpxchg(&fs_info->exclusive_operation, BTRFS_EXCLOP_NONE, type);
+       bool ret = false;
+
+       spin_lock(&fs_info->super_lock);
+       if (fs_info->exclusive_operation == BTRFS_EXCLOP_NONE) {
+               fs_info->exclusive_operation = type;
+               ret = true;
+       }
+       spin_unlock(&fs_info->super_lock);
+
+       return ret;
+}
+
+/*
+ * Conditionally allow to enter the exclusive operation in case it's compatible
+ * with the running one.  This must be paired with btrfs_exclop_start_unlock and
+ * btrfs_exclop_finish.
+ *
+ * Compatibility:
+ * - the same type is already running
+ * - not BTRFS_EXCLOP_NONE - this is intentionally incompatible and the caller
+ *   must check the condition first that would allow none -> @type
+ */
+bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
+                                enum btrfs_exclusive_operation type)
+{
+       spin_lock(&fs_info->super_lock);
+       if (fs_info->exclusive_operation == type)
+               return true;
+
+       spin_unlock(&fs_info->super_lock);
+       return false;
+}
+
+void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info)
+{
+       spin_unlock(&fs_info->super_lock);
 }
 
 void btrfs_exclop_finish(struct btrfs_fs_info *fs_info)
 {
+       spin_lock(&fs_info->super_lock);
        WRITE_ONCE(fs_info->exclusive_operation, BTRFS_EXCLOP_NONE);
+       spin_unlock(&fs_info->super_lock);
        sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation");
 }
 
@@ -1455,7 +1495,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                if (btrfs_defrag_cancelled(fs_info)) {
                        btrfs_debug(fs_info, "defrag_file cancelled");
                        ret = -EAGAIN;
-                       break;
+                       goto error;
                }
 
                if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT,
@@ -1533,6 +1573,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                }
        }
 
+       ret = defrag_count;
+error:
        if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) {
                filemap_flush(inode->i_mapping);
                if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
@@ -1546,8 +1588,6 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
        }
 
-       ret = defrag_count;
-
 out_ra:
        if (do_compress) {
                btrfs_inode_lock(inode, 0);
@@ -1560,6 +1600,48 @@ out_ra:
        return ret;
 }
 
+/*
+ * Try to start exclusive operation @type or cancel it if it's running.
+ *
+ * Return:
+ *   0        - normal mode, newly claimed op started
+ *  >0        - normal mode, something else is running,
+ *              return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS to user space
+ * ECANCELED  - cancel mode, successful cancel
+ * ENOTCONN   - cancel mode, operation not running anymore
+ */
+static int exclop_start_or_cancel_reloc(struct btrfs_fs_info *fs_info,
+                       enum btrfs_exclusive_operation type, bool cancel)
+{
+       if (!cancel) {
+               /* Start normal op */
+               if (!btrfs_exclop_start(fs_info, type))
+                       return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+               /* Exclusive operation is now claimed */
+               return 0;
+       }
+
+       /* Cancel running op */
+       if (btrfs_exclop_start_try_lock(fs_info, type)) {
+               /*
+                * This blocks any exclop finish from setting it to NONE, so we
+                * request cancellation. Either it runs and we will wait for it,
+                * or it has finished and no waiting will happen.
+                */
+               atomic_inc(&fs_info->reloc_cancel_req);
+               btrfs_exclop_start_unlock(fs_info);
+
+               if (test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags))
+                       wait_on_bit(&fs_info->flags, BTRFS_FS_RELOC_RUNNING,
+                                   TASK_INTERRUPTIBLE);
+
+               return -ECANCELED;
+       }
+
+       /* Something else is running or none */
+       return -ENOTCONN;
+}
+
 static noinline int btrfs_ioctl_resize(struct file *file,
                                        void __user *arg)
 {
@@ -1577,6 +1659,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        char *devstr = NULL;
        int ret = 0;
        int mod = 0;
+       bool cancel;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1585,20 +1668,23 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        if (ret)
                return ret;
 
-       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_RESIZE)) {
-               mnt_drop_write_file(file);
-               return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
-       }
-
+       /*
+        * Read the arguments before checking exclusivity to be able to
+        * distinguish regular resize and cancel
+        */
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
                ret = PTR_ERR(vol_args);
-               goto out;
+               goto out_drop;
        }
-
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
-
        sizestr = vol_args->name;
+       cancel = (strcmp("cancel", sizestr) == 0);
+       ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_RESIZE, cancel);
+       if (ret)
+               goto out_free;
+       /* Exclusive operation is now claimed */
+
        devstr = strchr(sizestr, ':');
        if (devstr) {
                sizestr = devstr + 1;
@@ -1606,10 +1692,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                devstr = vol_args->name;
                ret = kstrtoull(devstr, 10, &devid);
                if (ret)
-                       goto out_free;
+                       goto out_finish;
                if (!devid) {
                        ret = -EINVAL;
-                       goto out_free;
+                       goto out_finish;
                }
                btrfs_info(fs_info, "resizing devid %llu", devid);
        }
@@ -1619,7 +1705,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                btrfs_info(fs_info, "resizer unable to find device %llu",
                           devid);
                ret = -ENODEV;
-               goto out_free;
+               goto out_finish;
        }
 
        if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
@@ -1627,7 +1713,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                           "resizer unable to apply on readonly device %llu",
                       devid);
                ret = -EPERM;
-               goto out_free;
+               goto out_finish;
        }
 
        if (!strcmp(sizestr, "max"))
@@ -1643,13 +1729,13 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                new_size = memparse(sizestr, &retptr);
                if (*retptr != '\0' || new_size == 0) {
                        ret = -EINVAL;
-                       goto out_free;
+                       goto out_finish;
                }
        }
 
        if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
                ret = -EPERM;
-               goto out_free;
+               goto out_finish;
        }
 
        old_size = btrfs_device_get_total_bytes(device);
@@ -1657,24 +1743,24 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        if (mod < 0) {
                if (new_size > old_size) {
                        ret = -EINVAL;
-                       goto out_free;
+                       goto out_finish;
                }
                new_size = old_size - new_size;
        } else if (mod > 0) {
                if (new_size > ULLONG_MAX - old_size) {
                        ret = -ERANGE;
-                       goto out_free;
+                       goto out_finish;
                }
                new_size = old_size + new_size;
        }
 
        if (new_size < SZ_256M) {
                ret = -EINVAL;
-               goto out_free;
+               goto out_finish;
        }
        if (new_size > device->bdev->bd_inode->i_size) {
                ret = -EFBIG;
-               goto out_free;
+               goto out_finish;
        }
 
        new_size = round_down(new_size, fs_info->sectorsize);
@@ -1683,7 +1769,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                trans = btrfs_start_transaction(root, 0);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
-                       goto out_free;
+                       goto out_finish;
                }
                ret = btrfs_grow_device(trans, device, new_size);
                btrfs_commit_transaction(trans);
@@ -1696,10 +1782,11 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                        "resize device %s (devid %llu) from %llu to %llu",
                        rcu_str_deref(device->name), device->devid,
                        old_size, new_size);
+out_finish:
+       btrfs_exclop_finish(fs_info);
 out_free:
        kfree(vol_args);
-out:
-       btrfs_exclop_finish(fs_info);
+out_drop:
        mnt_drop_write_file(file);
        return ret;
 }
@@ -2897,7 +2984,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                err = PTR_ERR(subvol_name_ptr);
                                goto free_parent;
                        }
-                       /* subvol_name_ptr is already NULL termined */
+                       /* subvol_name_ptr is already nul terminated */
                        subvol_name = (char *)kbasename(subvol_name_ptr);
                }
        } else {
@@ -3119,6 +3206,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ioctl_vol_args_v2 *vol_args;
        int ret;
+       bool cancel = false;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -3137,18 +3225,22 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
                ret = -EOPNOTSUPP;
                goto out;
        }
+       vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+       if (!(vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) &&
+           strcmp("cancel", vol_args->name) == 0)
+               cancel = true;
 
-       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_REMOVE)) {
-               ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
+       ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+                                          cancel);
+       if (ret)
                goto out;
-       }
+       /* Exclusive operation is now claimed */
 
-       if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
+       if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
                ret = btrfs_rm_device(fs_info, NULL, vol_args->devid);
-       } else {
-               vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+       else
                ret = btrfs_rm_device(fs_info, vol_args->name, 0);
-       }
+
        btrfs_exclop_finish(fs_info);
 
        if (!ret) {
@@ -3172,6 +3264,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ioctl_vol_args *vol_args;
        int ret;
+       bool cancel;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -3180,25 +3273,24 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        if (ret)
                return ret;
 
-       if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_REMOVE)) {
-               ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
-               goto out_drop_write;
-       }
-
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
                ret = PTR_ERR(vol_args);
-               goto out;
+               goto out_drop_write;
        }
-
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
-       ret = btrfs_rm_device(fs_info, vol_args->name, 0);
+       cancel = (strcmp("cancel", vol_args->name) == 0);
+
+       ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+                                          cancel);
+       if (ret == 0) {
+               ret = btrfs_rm_device(fs_info, vol_args->name, 0);
+               if (!ret)
+                       btrfs_info(fs_info, "disk deleted %s", vol_args->name);
+               btrfs_exclop_finish(fs_info);
+       }
 
-       if (!ret)
-               btrfs_info(fs_info, "disk deleted %s", vol_args->name);
        kfree(vol_args);
-out:
-       btrfs_exclop_finish(fs_info);
 out_drop_write:
        mnt_drop_write_file(file);
 
@@ -3551,7 +3643,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
                goto out;
        }
        transid = trans->transid;
-       ret = btrfs_commit_transaction_async(trans, 0);
+       ret = btrfs_commit_transaction_async(trans);
        if (ret) {
                btrfs_end_transaction(trans);
                return ret;
index 5fafc5e..313d9d6 100644 (file)
@@ -57,7 +57,7 @@ void btrfs_tree_read_lock(struct extent_buffer *eb)
 /*
  * Try-lock for read.
  *
- * Retrun 1 if the rwlock has been taken, 0 otherwise
+ * Return 1 if the rwlock has been taken, 0 otherwise
  */
 int btrfs_try_tree_read_lock(struct extent_buffer *eb)
 {
@@ -72,7 +72,7 @@ int btrfs_try_tree_read_lock(struct extent_buffer *eb)
 /*
  * Try-lock for write.
  *
- * Retrun 1 if the rwlock has been taken, 0 otherwise
+ * Return 1 if the rwlock has been taken, 0 otherwise
  */
 int btrfs_try_tree_write_lock(struct extent_buffer *eb)
 {
index 6c413bb..6eb41b7 100644 (file)
@@ -16,6 +16,7 @@
 #include "compression.h"
 #include "delalloc-space.h"
 #include "qgroup.h"
+#include "subpage.h"
 
 static struct kmem_cache *btrfs_ordered_extent_cache;
 
@@ -300,81 +301,142 @@ void btrfs_add_ordered_sum(struct btrfs_ordered_extent *entry,
 }
 
 /*
- * Finish IO for one ordered extent across a given range.  The range can
- * contain several ordered extents.
+ * Mark all ordered extents io inside the specified range finished.
  *
- * @found_ret:  Return the finished ordered extent
- * @file_offset: File offset for the finished IO
- *              Will also be updated to one byte past the range that is
- *              recordered as finished. This allows caller to walk forward.
- * @io_size:    Length of the finish IO range
- * @uptodate:   If the IO finished without problem
- *
- * Return true if any ordered extent is finished in the range, and update
- * @found_ret and @file_offset.
- * Return false otherwise.
+ * @page:       The invovled page for the opeartion.
+ *              For uncompressed buffered IO, the page status also needs to be
+ *              updated to indicate whether the pending ordered io is finished.
+ *              Can be NULL for direct IO and compressed write.
+ *              For these cases, callers are ensured they won't execute the
+ *              endio function twice.
+ * @finish_func: The function to be executed when all the IO of an ordered
+ *              extent are finished.
  *
- * NOTE: Although The range can cross multiple ordered extents, only one
- * ordered extent will be updated during one call. The caller is responsible to
- * iterate all ordered extents in the range.
+ * This function is called for endio, thus the range must have ordered
+ * extent(s) coveri it.
  */
-bool btrfs_dec_test_first_ordered_pending(struct btrfs_inode *inode,
-                                  struct btrfs_ordered_extent **finished_ret,
-                                  u64 *file_offset, u64 io_size, int uptodate)
+void btrfs_mark_ordered_io_finished(struct btrfs_inode *inode,
+                               struct page *page, u64 file_offset,
+                               u64 num_bytes, btrfs_func_t finish_func,
+                               bool uptodate)
 {
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
        struct btrfs_ordered_inode_tree *tree = &inode->ordered_tree;
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       struct btrfs_workqueue *wq;
        struct rb_node *node;
        struct btrfs_ordered_extent *entry = NULL;
-       bool finished = false;
        unsigned long flags;
-       u64 dec_end;
-       u64 dec_start;
-       u64 to_dec;
+       u64 cur = file_offset;
+
+       if (btrfs_is_free_space_inode(inode))
+               wq = fs_info->endio_freespace_worker;
+       else
+               wq = fs_info->endio_write_workers;
+
+       if (page)
+               ASSERT(page->mapping && page_offset(page) <= file_offset &&
+                      file_offset + num_bytes <= page_offset(page) + PAGE_SIZE);
 
        spin_lock_irqsave(&tree->lock, flags);
-       node = tree_search(tree, *file_offset);
-       if (!node)
-               goto out;
+       while (cur < file_offset + num_bytes) {
+               u64 entry_end;
+               u64 end;
+               u32 len;
 
-       entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
-       if (!in_range(*file_offset, entry->file_offset, entry->num_bytes))
-               goto out;
+               node = tree_search(tree, cur);
+               /* No ordered extents at all */
+               if (!node)
+                       break;
 
-       dec_start = max(*file_offset, entry->file_offset);
-       dec_end = min(*file_offset + io_size,
-                     entry->file_offset + entry->num_bytes);
-       *file_offset = dec_end;
-       if (dec_start > dec_end) {
-               btrfs_crit(fs_info, "bad ordering dec_start %llu end %llu",
-                          dec_start, dec_end);
-       }
-       to_dec = dec_end - dec_start;
-       if (to_dec > entry->bytes_left) {
-               btrfs_crit(fs_info,
-                          "bad ordered accounting left %llu size %llu",
-                          entry->bytes_left, to_dec);
-       }
-       entry->bytes_left -= to_dec;
-       if (!uptodate)
-               set_bit(BTRFS_ORDERED_IOERR, &entry->flags);
+               entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
+               entry_end = entry->file_offset + entry->num_bytes;
+               /*
+                * |<-- OE --->|  |
+                *                cur
+                * Go to next OE.
+                */
+               if (cur >= entry_end) {
+                       node = rb_next(node);
+                       /* No more ordered extents, exit */
+                       if (!node)
+                               break;
+                       entry = rb_entry(node, struct btrfs_ordered_extent,
+                                        rb_node);
+
+                       /* Go to next ordered extent and continue */
+                       cur = entry->file_offset;
+                       continue;
+               }
+               /*
+                * |    |<--- OE --->|
+                * cur
+                * Go to the start of OE.
+                */
+               if (cur < entry->file_offset) {
+                       cur = entry->file_offset;
+                       continue;
+               }
 
-       if (entry->bytes_left == 0) {
                /*
-                * Ensure only one caller can set the flag and finished_ret
-                * accordingly
+                * Now we are definitely inside one ordered extent.
+                *
+                * |<--- OE --->|
+                *      |
+                *      cur
                 */
-               finished = !test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
-               /* test_and_set_bit implies a barrier */
-               cond_wake_up_nomb(&entry->wait);
-       }
-out:
-       if (finished && finished_ret && entry) {
-               *finished_ret = entry;
-               refcount_inc(&entry->refs);
+               end = min(entry->file_offset + entry->num_bytes,
+                         file_offset + num_bytes) - 1;
+               ASSERT(end + 1 - cur < U32_MAX);
+               len = end + 1 - cur;
+
+               if (page) {
+                       /*
+                        * Ordered (Private2) bit indicates whether we still
+                        * have pending io unfinished for the ordered extent.
+                        *
+                        * If there's no such bit, we need to skip to next range.
+                        */
+                       if (!btrfs_page_test_ordered(fs_info, page, cur, len)) {
+                               cur += len;
+                               continue;
+                       }
+                       btrfs_page_clear_ordered(fs_info, page, cur, len);
+               }
+
+               /* Now we're fine to update the accounting */
+               if (unlikely(len > entry->bytes_left)) {
+                       WARN_ON(1);
+                       btrfs_crit(fs_info,
+"bad ordered extent accounting, root=%llu ino=%llu OE offset=%llu OE len=%llu to_dec=%u left=%llu",
+                                  inode->root->root_key.objectid,
+                                  btrfs_ino(inode),
+                                  entry->file_offset,
+                                  entry->num_bytes,
+                                  len, entry->bytes_left);
+                       entry->bytes_left = 0;
+               } else {
+                       entry->bytes_left -= len;
+               }
+
+               if (!uptodate)
+                       set_bit(BTRFS_ORDERED_IOERR, &entry->flags);
+
+               /*
+                * All the IO of the ordered extent is finished, we need to queue
+                * the finish_func to be executed.
+                */
+               if (entry->bytes_left == 0) {
+                       set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
+                       cond_wake_up(&entry->wait);
+                       refcount_inc(&entry->refs);
+                       spin_unlock_irqrestore(&tree->lock, flags);
+                       btrfs_init_work(&entry->work, finish_func, NULL, NULL);
+                       btrfs_queue_work(wq, &entry->work);
+                       spin_lock_irqsave(&tree->lock, flags);
+               }
+               cur += len;
        }
        spin_unlock_irqrestore(&tree->lock, flags);
-       return finished;
 }
 
 /*
@@ -870,6 +932,81 @@ out:
 }
 
 /*
+ * Lookup the first ordered extent that overlaps the range
+ * [@file_offset, @file_offset + @len).
+ *
+ * The difference between this and btrfs_lookup_first_ordered_extent() is
+ * that this one won't return any ordered extent that does not overlap the range.
+ * And the difference against btrfs_lookup_ordered_extent() is, this function
+ * ensures the first ordered extent gets returned.
+ */
+struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range(
+                       struct btrfs_inode *inode, u64 file_offset, u64 len)
+{
+       struct btrfs_ordered_inode_tree *tree = &inode->ordered_tree;
+       struct rb_node *node;
+       struct rb_node *cur;
+       struct rb_node *prev;
+       struct rb_node *next;
+       struct btrfs_ordered_extent *entry = NULL;
+
+       spin_lock_irq(&tree->lock);
+       node = tree->tree.rb_node;
+       /*
+        * Here we don't want to use tree_search() which will use tree->last
+        * and screw up the search order.
+        * And __tree_search() can't return the adjacent ordered extents
+        * either, thus here we do our own search.
+        */
+       while (node) {
+               entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
+
+               if (file_offset < entry->file_offset) {
+                       node = node->rb_left;
+               } else if (file_offset >= entry_end(entry)) {
+                       node = node->rb_right;
+               } else {
+                       /*
+                        * Direct hit, got an ordered extent that starts at
+                        * @file_offset
+                        */
+                       goto out;
+               }
+       }
+       if (!entry) {
+               /* Empty tree */
+               goto out;
+       }
+
+       cur = &entry->rb_node;
+       /* We got an entry around @file_offset, check adjacent entries */
+       if (entry->file_offset < file_offset) {
+               prev = cur;
+               next = rb_next(cur);
+       } else {
+               prev = rb_prev(cur);
+               next = cur;
+       }
+       if (prev) {
+               entry = rb_entry(prev, struct btrfs_ordered_extent, rb_node);
+               if (range_overlaps(entry, file_offset, len))
+                       goto out;
+       }
+       if (next) {
+               entry = rb_entry(next, struct btrfs_ordered_extent, rb_node);
+               if (range_overlaps(entry, file_offset, len))
+                       goto out;
+       }
+       /* No ordered extent in the range */
+       entry = NULL;
+out:
+       if (entry)
+               refcount_inc(&entry->refs);
+       spin_unlock_irq(&tree->lock);
+       return entry;
+}
+
+/*
  * btrfs_flush_ordered_range - Lock the passed range and ensures all pending
  * ordered extents in it are run to completion.
  *
index e60c07f..5664720 100644 (file)
@@ -172,13 +172,13 @@ btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t)
 void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry);
 void btrfs_remove_ordered_extent(struct btrfs_inode *btrfs_inode,
                                struct btrfs_ordered_extent *entry);
+void btrfs_mark_ordered_io_finished(struct btrfs_inode *inode,
+                               struct page *page, u64 file_offset,
+                               u64 num_bytes, btrfs_func_t finish_func,
+                               bool uptodate);
 bool btrfs_dec_test_ordered_pending(struct btrfs_inode *inode,
                                    struct btrfs_ordered_extent **cached,
                                    u64 file_offset, u64 io_size, int uptodate);
-bool btrfs_dec_test_first_ordered_pending(struct btrfs_inode *inode,
-                                  struct btrfs_ordered_extent **finished_ret,
-                                  u64 *file_offset, u64 io_size,
-                                  int uptodate);
 int btrfs_add_ordered_extent(struct btrfs_inode *inode, u64 file_offset,
                             u64 disk_bytenr, u64 num_bytes, u64 disk_num_bytes,
                             int type);
@@ -196,6 +196,8 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry, int wait);
 int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
 struct btrfs_ordered_extent *
 btrfs_lookup_first_ordered_extent(struct btrfs_inode *inode, u64 file_offset);
+struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range(
+                       struct btrfs_inode *inode, u64 file_offset, u64 len);
 struct btrfs_ordered_extent *btrfs_lookup_ordered_range(
                struct btrfs_inode *inode,
                u64 file_offset,
index 2dcb1cb..b1cb5a8 100644 (file)
@@ -260,6 +260,10 @@ static int prop_compression_validate(const char *value, size_t len)
        if (btrfs_compress_is_valid_type(value, len))
                return 0;
 
+       if ((len == 2 && strncmp("no", value, 2) == 0) ||
+           (len == 4 && strncmp("none", value, 4) == 0))
+               return 0;
+
        return -EINVAL;
 }
 
@@ -269,7 +273,17 @@ static int prop_compression_apply(struct inode *inode, const char *value,
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        int type;
 
+       /* Reset to defaults */
        if (len == 0) {
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
+               BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
+               return 0;
+       }
+
+       /* Set NOCOMPRESS flag */
+       if ((len == 2 && strncmp("no", value, 2) == 0) ||
+           (len == 4 && strncmp("none", value, 4) == 0)) {
                BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
                BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
                BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
@@ -348,7 +362,7 @@ static int inherit_props(struct btrfs_trans_handle *trans,
 
                /*
                 * This is not strictly necessary as the property should be
-                * valid, but in case it isn't, don't propagate it futher.
+                * valid, but in case it isn't, don't propagate it further.
                 */
                ret = h->validate(value, strlen(value));
                if (ret)
index 3ded812..07ec06d 100644 (file)
@@ -2521,7 +2521,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
        int ret = 0;
 
        /*
-        * If quotas get disabled meanwhile, the resouces need to be freed and
+        * If quotas get disabled meanwhile, the resources need to be freed and
         * we can't just exit here.
         */
        if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
@@ -3545,13 +3545,7 @@ static int try_flush_qgroup(struct btrfs_root *root)
        struct btrfs_trans_handle *trans;
        int ret;
 
-       /*
-        * Can't hold an open transaction or we run the risk of deadlocking,
-        * and can't either be under the context of a send operation (where
-        * current->journal_info is set to BTRFS_SEND_TRANS_STUB), as that
-        * would result in a crash when starting a transaction and does not
-        * make sense either (send is a read-only operation).
-        */
+       /* Can't hold an open transaction or we run the risk of deadlocking. */
        ASSERT(current->journal_info == NULL);
        if (WARN_ON(current->journal_info))
                return 0;
index 9178da0..9b08143 100644 (file)
@@ -7,6 +7,7 @@
 #include "delalloc-space.h"
 #include "reflink.h"
 #include "transaction.h"
+#include "subpage.h"
 
 #define BTRFS_MAX_DEDUPE_LEN   SZ_16M
 
@@ -52,7 +53,8 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
                               const u64 datal,
                               const u8 comp_type)
 {
-       const u64 block_size = btrfs_inode_sectorsize(inode);
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       const u32 block_size = fs_info->sectorsize;
        const u64 range_end = file_offset + block_size - 1;
        const size_t inline_size = size - btrfs_file_extent_calc_inline_size(0);
        char *data_start = inline_data + btrfs_file_extent_calc_inline_size(0);
@@ -106,10 +108,12 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
        set_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &inode->runtime_flags);
 
        if (comp_type == BTRFS_COMPRESS_NONE) {
-               memcpy_to_page(page, 0, data_start, datal);
+               memcpy_to_page(page, offset_in_page(file_offset), data_start,
+                              datal);
                flush_dcache_page(page);
        } else {
-               ret = btrfs_decompress(comp_type, data_start, page, 0,
+               ret = btrfs_decompress(comp_type, data_start, page,
+                                      offset_in_page(file_offset),
                                       inline_size, datal);
                if (ret)
                        goto out_unlock;
@@ -133,9 +137,9 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
                flush_dcache_page(page);
        }
 
-       SetPageUptodate(page);
+       btrfs_page_set_uptodate(fs_info, page, file_offset, block_size);
        ClearPageChecked(page);
-       set_page_dirty(page);
+       btrfs_page_set_dirty(fs_info, page, file_offset, block_size);
 out_unlock:
        if (page) {
                unlock_page(page);
index b70be2a..fc83159 100644 (file)
@@ -2876,11 +2876,12 @@ int setup_extent_mapping(struct inode *inode, u64 start, u64 end,
 }
 
 /*
- * Allow error injection to test balance cancellation
+ * Allow error injection to test balance/relocation cancellation
  */
 noinline int btrfs_should_cancel_balance(struct btrfs_fs_info *fs_info)
 {
        return atomic_read(&fs_info->balance_cancel_req) ||
+               atomic_read(&fs_info->reloc_cancel_req) ||
                fatal_signal_pending(current);
 }
 ALLOW_ERROR_INJECTION(btrfs_should_cancel_balance, TRUE);
@@ -3780,6 +3781,60 @@ out:
        return inode;
 }
 
+/*
+ * Mark start of chunk relocation that is cancellable. Check if the cancellation
+ * has been requested meanwhile and don't start in that case.
+ *
+ * Return:
+ *   0             success
+ *   -EINPROGRESS  operation is already in progress, that's probably a bug
+ *   -ECANCELED    cancellation request was set before the operation started
+ *   -EAGAIN       can not start because there are ongoing send operations
+ */
+static int reloc_chunk_start(struct btrfs_fs_info *fs_info)
+{
+       spin_lock(&fs_info->send_reloc_lock);
+       if (fs_info->send_in_progress) {
+               btrfs_warn_rl(fs_info,
+"cannot run relocation while send operations are in progress (%d in progress)",
+                             fs_info->send_in_progress);
+               spin_unlock(&fs_info->send_reloc_lock);
+               return -EAGAIN;
+       }
+       if (test_and_set_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags)) {
+               /* This should not happen */
+               spin_unlock(&fs_info->send_reloc_lock);
+               btrfs_err(fs_info, "reloc already running, cannot start");
+               return -EINPROGRESS;
+       }
+       spin_unlock(&fs_info->send_reloc_lock);
+
+       if (atomic_read(&fs_info->reloc_cancel_req) > 0) {
+               btrfs_info(fs_info, "chunk relocation canceled on start");
+               /*
+                * On cancel, clear all requests but let the caller mark
+                * the end after cleanup operations.
+                */
+               atomic_set(&fs_info->reloc_cancel_req, 0);
+               return -ECANCELED;
+       }
+       return 0;
+}
+
+/*
+ * Mark end of chunk relocation that is cancellable and wake any waiters.
+ */
+static void reloc_chunk_end(struct btrfs_fs_info *fs_info)
+{
+       /* Requested after start, clear bit first so any waiters can continue */
+       if (atomic_read(&fs_info->reloc_cancel_req) > 0)
+               btrfs_info(fs_info, "chunk relocation canceled during operation");
+       spin_lock(&fs_info->send_reloc_lock);
+       clear_and_wake_up_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags);
+       spin_unlock(&fs_info->send_reloc_lock);
+       atomic_set(&fs_info->reloc_cancel_req, 0);
+}
+
 static struct reloc_control *alloc_reloc_control(struct btrfs_fs_info *fs_info)
 {
        struct reloc_control *rc;
@@ -3862,6 +3917,12 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
                return -ENOMEM;
        }
 
+       ret = reloc_chunk_start(fs_info);
+       if (ret < 0) {
+               err = ret;
+               goto out_put_bg;
+       }
+
        rc->extent_root = extent_root;
        rc->block_group = bg;
 
@@ -3952,7 +4013,9 @@ out:
        if (err && rw)
                btrfs_dec_block_group_ro(rc->block_group);
        iput(rc->data_inode);
-       btrfs_put_block_group(rc->block_group);
+out_put_bg:
+       btrfs_put_block_group(bg);
+       reloc_chunk_end(fs_info);
        free_reloc_control(rc);
        return err;
 }
@@ -4073,6 +4136,12 @@ int btrfs_recover_relocation(struct btrfs_root *root)
                goto out;
        }
 
+       ret = reloc_chunk_start(fs_info);
+       if (ret < 0) {
+               err = ret;
+               goto out_end;
+       }
+
        rc->extent_root = fs_info->extent_root;
 
        set_reloc_control(rc);
@@ -4137,6 +4206,8 @@ out_clean:
                err = ret;
 out_unset:
        unset_reloc_control(rc);
+out_end:
+       reloc_chunk_end(fs_info);
        free_reloc_control(rc);
 out:
        free_reloc_roots(&reloc_roots);
index 485cda3..088641b 100644 (file)
@@ -165,6 +165,10 @@ struct scrub_ctx {
        int                     readonly;
        int                     pages_per_rd_bio;
 
+       /* State of IO submission throttling affecting the associated device */
+       ktime_t                 throttle_deadline;
+       u64                     throttle_sent;
+
        int                     is_dev_replace;
        u64                     write_pointer;
 
@@ -605,6 +609,7 @@ static noinline_for_stack struct scrub_ctx *scrub_setup_ctx(
        spin_lock_init(&sctx->list_lock);
        spin_lock_init(&sctx->stat_lock);
        init_waitqueue_head(&sctx->list_wait);
+       sctx->throttle_deadline = 0;
 
        WARN_ON(sctx->wr_curr_bio != NULL);
        mutex_init(&sctx->wr_lock);
@@ -626,7 +631,6 @@ nomem:
 static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
                                     void *warn_ctx)
 {
-       u64 isize;
        u32 nlink;
        int ret;
        int i;
@@ -662,7 +666,6 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
        eb = swarn->path->nodes[0];
        inode_item = btrfs_item_ptr(eb, swarn->path->slots[0],
                                        struct btrfs_inode_item);
-       isize = btrfs_inode_size(eb, inode_item);
        nlink = btrfs_inode_nlink(eb, inode_item);
        btrfs_release_path(swarn->path);
 
@@ -691,12 +694,12 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
         */
        for (i = 0; i < ipath->fspath->elem_cnt; ++i)
                btrfs_warn_in_rcu(fs_info,
-"%s at logical %llu on dev %s, physical %llu, root %llu, inode %llu, offset %llu, length %llu, links %u (path: %s)",
+"%s at logical %llu on dev %s, physical %llu, root %llu, inode %llu, offset %llu, length %u, links %u (path: %s)",
                                  swarn->errstr, swarn->logical,
                                  rcu_str_deref(swarn->dev->name),
                                  swarn->physical,
                                  root, inum, offset,
-                                 min(isize - offset, (u64)PAGE_SIZE), nlink,
+                                 fs_info->sectorsize, nlink,
                                  (char *)(unsigned long)ipath->fspath->val[i]);
 
        btrfs_put_root(local_root);
@@ -885,25 +888,25 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
         * read all mirrors one after the other. This includes to
         * re-read the extent or metadata block that failed (that was
         * the cause that this fixup code is called) another time,
-        * page by page this time in order to know which pages
+        * sector by sector this time in order to know which sectors
         * caused I/O errors and which ones are good (for all mirrors).
         * It is the goal to handle the situation when more than one
         * mirror contains I/O errors, but the errors do not
         * overlap, i.e. the data can be repaired by selecting the
-        * pages from those mirrors without I/O error on the
-        * particular pages. One example (with blocks >= 2 * PAGE_SIZE)
-        * would be that mirror #1 has an I/O error on the first page,
-        * the second page is good, and mirror #2 has an I/O error on
-        * the second page, but the first page is good.
-        * Then the first page of the first mirror can be repaired by
-        * taking the first page of the second mirror, and the
-        * second page of the second mirror can be repaired by
-        * copying the contents of the 2nd page of the 1st mirror.
-        * One more note: if the pages of one mirror contain I/O
+        * sectors from those mirrors without I/O error on the
+        * particular sectors. One example (with blocks >= 2 * sectorsize)
+        * would be that mirror #1 has an I/O error on the first sector,
+        * the second sector is good, and mirror #2 has an I/O error on
+        * the second sector, but the first sector is good.
+        * Then the first sector of the first mirror can be repaired by
+        * taking the first sector of the second mirror, and the
+        * second sector of the second mirror can be repaired by
+        * copying the contents of the 2nd sector of the 1st mirror.
+        * One more note: if the sectors of one mirror contain I/O
         * errors, the checksum cannot be verified. In order to get
         * the best data for repairing, the first attempt is to find
         * a mirror without I/O errors and with a validated checksum.
-        * Only if this is not possible, the pages are picked from
+        * Only if this is not possible, the sectors are picked from
         * mirrors with I/O errors without considering the checksum.
         * If the latter is the case, at the end, the checksum of the
         * repaired area is verified in order to correctly maintain
@@ -1060,26 +1063,26 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 
        /*
         * In case of I/O errors in the area that is supposed to be
-        * repaired, continue by picking good copies of those pages.
-        * Select the good pages from mirrors to rewrite bad pages from
+        * repaired, continue by picking good copies of those sectors.
+        * Select the good sectors from mirrors to rewrite bad sectors from
         * the area to fix. Afterwards verify the checksum of the block
         * that is supposed to be repaired. This verification step is
         * only done for the purpose of statistic counting and for the
         * final scrub report, whether errors remain.
         * A perfect algorithm could make use of the checksum and try
-        * all possible combinations of pages from the different mirrors
+        * all possible combinations of sectors from the different mirrors
         * until the checksum verification succeeds. For example, when
-        * the 2nd page of mirror #1 faces I/O errors, and the 2nd page
+        * the 2nd sector of mirror #1 faces I/O errors, and the 2nd sector
         * of mirror #2 is readable but the final checksum test fails,
-        * then the 2nd page of mirror #3 could be tried, whether now
+        * then the 2nd sector of mirror #3 could be tried, whether now
         * the final checksum succeeds. But this would be a rare
         * exception and is therefore not implemented. At least it is
         * avoided that the good copy is overwritten.
         * A more useful improvement would be to pick the sectors
         * without I/O error based on sector sizes (512 bytes on legacy
-        * disks) instead of on PAGE_SIZE. Then maybe 512 byte of one
+        * disks) instead of on sectorsize. Then maybe 512 byte of one
         * mirror could be repaired by taking 512 byte of a different
-        * mirror, even if other 512 byte sectors in the same PAGE_SIZE
+        * mirror, even if other 512 byte sectors in the same sectorsize
         * area are unreadable.
         */
        success = 1;
@@ -1260,7 +1263,7 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
 {
        struct scrub_ctx *sctx = original_sblock->sctx;
        struct btrfs_fs_info *fs_info = sctx->fs_info;
-       u64 length = original_sblock->page_count * PAGE_SIZE;
+       u64 length = original_sblock->page_count * fs_info->sectorsize;
        u64 logical = original_sblock->pagev[0]->logical;
        u64 generation = original_sblock->pagev[0]->generation;
        u64 flags = original_sblock->pagev[0]->flags;
@@ -1283,13 +1286,13 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
         */
 
        while (length > 0) {
-               sublen = min_t(u64, length, PAGE_SIZE);
+               sublen = min_t(u64, length, fs_info->sectorsize);
                mapped_length = sublen;
                bbio = NULL;
 
                /*
-                * with a length of PAGE_SIZE, each returned stripe
-                * represents one mirror
+                * With a length of sectorsize, each returned stripe represents
+                * one mirror
                 */
                btrfs_bio_counter_inc_blocked(fs_info);
                ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS,
@@ -1480,7 +1483,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
                bio = btrfs_io_bio_alloc(1);
                bio_set_dev(bio, spage->dev->bdev);
 
-               bio_add_page(bio, spage->page, PAGE_SIZE, 0);
+               bio_add_page(bio, spage->page, fs_info->sectorsize, 0);
                bio->bi_iter.bi_sector = spage->physical >> 9;
                bio->bi_opf = REQ_OP_READ;
 
@@ -1544,6 +1547,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
        struct scrub_page *spage_bad = sblock_bad->pagev[page_num];
        struct scrub_page *spage_good = sblock_good->pagev[page_num];
        struct btrfs_fs_info *fs_info = sblock_bad->sctx->fs_info;
+       const u32 sectorsize = fs_info->sectorsize;
 
        BUG_ON(spage_bad->page == NULL);
        BUG_ON(spage_good->page == NULL);
@@ -1563,8 +1567,8 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                bio->bi_iter.bi_sector = spage_bad->physical >> 9;
                bio->bi_opf = REQ_OP_WRITE;
 
-               ret = bio_add_page(bio, spage_good->page, PAGE_SIZE, 0);
-               if (PAGE_SIZE != ret) {
+               ret = bio_add_page(bio, spage_good->page, sectorsize, 0);
+               if (ret != sectorsize) {
                        bio_put(bio);
                        return -EIO;
                }
@@ -1642,6 +1646,7 @@ static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
 {
        struct scrub_bio *sbio;
        int ret;
+       const u32 sectorsize = sctx->fs_info->sectorsize;
 
        mutex_lock(&sctx->wr_lock);
 again:
@@ -1681,16 +1686,16 @@ again:
                bio->bi_iter.bi_sector = sbio->physical >> 9;
                bio->bi_opf = REQ_OP_WRITE;
                sbio->status = 0;
-       } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
+       } else if (sbio->physical + sbio->page_count * sectorsize !=
                   spage->physical_for_dev_replace ||
-                  sbio->logical + sbio->page_count * PAGE_SIZE !=
+                  sbio->logical + sbio->page_count * sectorsize !=
                   spage->logical) {
                scrub_wr_submit(sctx);
                goto again;
        }
 
-       ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
-       if (ret != PAGE_SIZE) {
+       ret = bio_add_page(sbio->bio, spage->page, sectorsize, 0);
+       if (ret != sectorsize) {
                if (sbio->page_count < 1) {
                        bio_put(sbio->bio);
                        sbio->bio = NULL;
@@ -1729,7 +1734,8 @@ static void scrub_wr_submit(struct scrub_ctx *sctx)
        btrfsic_submit_bio(sbio->bio);
 
        if (btrfs_is_zoned(sctx->fs_info))
-               sctx->write_pointer = sbio->physical + sbio->page_count * PAGE_SIZE;
+               sctx->write_pointer = sbio->physical + sbio->page_count *
+                       sctx->fs_info->sectorsize;
 }
 
 static void scrub_wr_bio_end_io(struct bio *bio)
@@ -1988,6 +1994,65 @@ static void scrub_page_put(struct scrub_page *spage)
        }
 }
 
+/*
+ * Throttling of IO submission, bandwidth-limit based, the timeslice is 1
+ * second.  Limit can be set via /sys/fs/UUID/devinfo/devid/scrub_speed_max.
+ */
+static void scrub_throttle(struct scrub_ctx *sctx)
+{
+       const int time_slice = 1000;
+       struct scrub_bio *sbio;
+       struct btrfs_device *device;
+       s64 delta;
+       ktime_t now;
+       u32 div;
+       u64 bwlimit;
+
+       sbio = sctx->bios[sctx->curr];
+       device = sbio->dev;
+       bwlimit = READ_ONCE(device->scrub_speed_max);
+       if (bwlimit == 0)
+               return;
+
+       /*
+        * Slice is divided into intervals when the IO is submitted, adjust by
+        * bwlimit and maximum of 64 intervals.
+        */
+       div = max_t(u32, 1, (u32)(bwlimit / (16 * 1024 * 1024)));
+       div = min_t(u32, 64, div);
+
+       /* Start new epoch, set deadline */
+       now = ktime_get();
+       if (sctx->throttle_deadline == 0) {
+               sctx->throttle_deadline = ktime_add_ms(now, time_slice / div);
+               sctx->throttle_sent = 0;
+       }
+
+       /* Still in the time to send? */
+       if (ktime_before(now, sctx->throttle_deadline)) {
+               /* If current bio is within the limit, send it */
+               sctx->throttle_sent += sbio->bio->bi_iter.bi_size;
+               if (sctx->throttle_sent <= div_u64(bwlimit, div))
+                       return;
+
+               /* We're over the limit, sleep until the rest of the slice */
+               delta = ktime_ms_delta(sctx->throttle_deadline, now);
+       } else {
+               /* New request after deadline, start new epoch */
+               delta = 0;
+       }
+
+       if (delta) {
+               long timeout;
+
+               timeout = div_u64(delta * HZ, 1000);
+               schedule_timeout_interruptible(timeout);
+       }
+
+       /* Next call will start the deadline period */
+       sctx->throttle_deadline = 0;
+}
+
 static void scrub_submit(struct scrub_ctx *sctx)
 {
        struct scrub_bio *sbio;
@@ -1995,6 +2060,8 @@ static void scrub_submit(struct scrub_ctx *sctx)
        if (sctx->curr == -1)
                return;
 
+       scrub_throttle(sctx);
+
        sbio = sctx->bios[sctx->curr];
        sctx->curr = -1;
        scrub_pending_bio_inc(sctx);
@@ -2006,6 +2073,7 @@ static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx,
 {
        struct scrub_block *sblock = spage->sblock;
        struct scrub_bio *sbio;
+       const u32 sectorsize = sctx->fs_info->sectorsize;
        int ret;
 
 again:
@@ -2044,9 +2112,9 @@ again:
                bio->bi_iter.bi_sector = sbio->physical >> 9;
                bio->bi_opf = REQ_OP_READ;
                sbio->status = 0;
-       } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
+       } else if (sbio->physical + sbio->page_count * sectorsize !=
                   spage->physical ||
-                  sbio->logical + sbio->page_count * PAGE_SIZE !=
+                  sbio->logical + sbio->page_count * sectorsize !=
                   spage->logical ||
                   sbio->dev != spage->dev) {
                scrub_submit(sctx);
@@ -2054,8 +2122,8 @@ again:
        }
 
        sbio->pagev[sbio->page_count] = spage;
-       ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
-       if (ret != PAGE_SIZE) {
+       ret = bio_add_page(sbio->bio, spage->page, sectorsize, 0);
+       if (ret != sectorsize) {
                if (sbio->page_count < 1) {
                        bio_put(sbio->bio);
                        sbio->bio = NULL;
@@ -2398,7 +2466,7 @@ static void scrub_block_complete(struct scrub_block *sblock)
        if (sblock->sparity && corrupted && !sblock->data_corrected) {
                u64 start = sblock->pagev[0]->logical;
                u64 end = sblock->pagev[sblock->page_count - 1]->logical +
-                         PAGE_SIZE;
+                         sblock->sctx->fs_info->sectorsize;
 
                ASSERT(end - start <= U32_MAX);
                scrub_parity_mark_sectors_error(sblock->sparity,
@@ -2418,7 +2486,7 @@ static void drop_csum_range(struct scrub_ctx *sctx, struct btrfs_ordered_sum *su
  * the csum into @csum.
  *
  * The search source is sctx->csum_list, which is a pre-populated list
- * storing bytenr ordered csum ranges.  We're reponsible to cleanup any range
+ * storing bytenr ordered csum ranges.  We're responsible to cleanup any range
  * that is before @logical.
  *
  * Return 0 if there is no csum for the range.
@@ -3138,28 +3206,23 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
        physical = map->stripes[num].physical;
        offset = 0;
        nstripes = div64_u64(length, map->stripe_len);
+       mirror_num = 1;
+       increment = map->stripe_len;
        if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
                offset = map->stripe_len * num;
                increment = map->stripe_len * map->num_stripes;
-               mirror_num = 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
                int factor = map->num_stripes / map->sub_stripes;
                offset = map->stripe_len * (num / map->sub_stripes);
                increment = map->stripe_len * factor;
                mirror_num = num % map->sub_stripes + 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID1_MASK) {
-               increment = map->stripe_len;
                mirror_num = num % map->num_stripes + 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
-               increment = map->stripe_len;
                mirror_num = num % map->num_stripes + 1;
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
                get_raid56_logic_offset(physical, num, map, &offset, NULL);
                increment = map->stripe_len * nr_data_stripes(map);
-               mirror_num = 1;
-       } else {
-               increment = map->stripe_len;
-               mirror_num = 1;
        }
 
        path = btrfs_alloc_path();
index bd69db7..6ac37ae 100644 (file)
@@ -2078,16 +2078,6 @@ static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
 }
 
 /*
- * Removes the entry from the list and adds it back to the end. This marks the
- * entry as recently used so that name_cache_clean_unused does not remove it.
- */
-static void name_cache_used(struct send_ctx *sctx, struct name_cache_entry *nce)
-{
-       list_del(&nce->list);
-       list_add_tail(&nce->list, &sctx->name_cache_list);
-}
-
-/*
  * Remove some entries from the beginning of name_cache_list.
  */
 static void name_cache_clean_unused(struct send_ctx *sctx)
@@ -2147,7 +2137,13 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
                        kfree(nce);
                        nce = NULL;
                } else {
-                       name_cache_used(sctx, nce);
+                       /*
+                        * Removes the entry from the list and adds it back to
+                        * the end.  This marks the entry as recently used so
+                        * that name_cache_clean_unused does not remove it.
+                        */
+                       list_move_tail(&nce->list, &sctx->name_cache_list);
+
                        *parent_ino = nce->parent_ino;
                        *parent_gen = nce->parent_gen;
                        ret = fs_path_add(dest, nce->name, nce->name_len);
@@ -4064,6 +4060,17 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
                                if (ret < 0)
                                        goto out;
                        } else {
+                               /*
+                                * If we previously orphanized a directory that
+                                * collided with a new reference that we already
+                                * processed, recompute the current path because
+                                * that directory may be part of the path.
+                                */
+                               if (orphanized_dir) {
+                                       ret = refresh_ref_path(sctx, cur);
+                                       if (ret < 0)
+                                               goto out;
+                               }
                                ret = send_unlink(sctx, cur->full_path);
                                if (ret < 0)
                                        goto out;
@@ -6507,7 +6514,7 @@ static int changed_extent(struct send_ctx *sctx,
         * updates the inode item, but it only changes the iversion (sequence
         * field in the inode item) of the inode, so if a file is deduplicated
         * the same amount of times in both the parent and send snapshots, its
-        * iversion becames the same in both snapshots, whence the inode item is
+        * iversion becomes the same in both snapshots, whence the inode item is
         * the same on both snapshots.
         */
        if (sctx->cur_ino != sctx->cmp_key->objectid)
@@ -7409,23 +7416,21 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
        if (ret)
                goto out;
 
-       mutex_lock(&fs_info->balance_mutex);
-       if (test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags)) {
-               mutex_unlock(&fs_info->balance_mutex);
+       spin_lock(&fs_info->send_reloc_lock);
+       if (test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags)) {
+               spin_unlock(&fs_info->send_reloc_lock);
                btrfs_warn_rl(fs_info,
-               "cannot run send because a balance operation is in progress");
+               "cannot run send because a relocation operation is in progress");
                ret = -EAGAIN;
                goto out;
        }
        fs_info->send_in_progress++;
-       mutex_unlock(&fs_info->balance_mutex);
+       spin_unlock(&fs_info->send_reloc_lock);
 
-       current->journal_info = BTRFS_SEND_TRANS_STUB;
        ret = send_subvol(sctx);
-       current->journal_info = NULL;
-       mutex_lock(&fs_info->balance_mutex);
+       spin_lock(&fs_info->send_reloc_lock);
        fs_info->send_in_progress--;
-       mutex_unlock(&fs_info->balance_mutex);
+       spin_unlock(&fs_info->send_reloc_lock);
        if (ret < 0)
                goto out;
 
index 2dc674b..f79bf85 100644 (file)
  *     operations, however they won't be usable until the transaction commits.
  *
  *   COMMIT_TRANS
- *     may_commit_transaction() is the ultimate arbiter on whether we commit the
- *     transaction or not.  In order to avoid constantly churning we do all the
- *     above flushing first and then commit the transaction as the last resort.
- *     However we need to take into account things like pinned space that would
- *     be freed, plus any delayed work we may not have gotten rid of in the case
- *     of metadata.
- *
- *   FORCE_COMMIT_TRANS
- *     For use by the preemptive flusher.  We use this to bypass the ticketing
- *     checks in may_commit_transaction, as we have more information about the
- *     overall state of the system and may want to commit the transaction ahead
- *     of actual ENOSPC conditions.
+ *     This will commit the transaction.  Historically we had a lot of logic
+ *     surrounding whether or not we'd commit the transaction, but this waits born
+ *     out of a pre-tickets era where we could end up committing the transaction
+ *     thousands of times in a row without making progress.  Now thanks to our
+ *     ticketing system we know if we're not making progress and can error
+ *     everybody out after a few commits rather than burning the disk hoping for
+ *     a different answer.
  *
  * OVERCOMMIT
  *
@@ -197,13 +192,6 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags)
        if (!space_info)
                return -ENOMEM;
 
-       ret = percpu_counter_init(&space_info->total_bytes_pinned, 0,
-                                GFP_KERNEL);
-       if (ret) {
-               kfree(space_info);
-               return ret;
-       }
-
        for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
                INIT_LIST_HEAD(&space_info->block_groups[i]);
        init_rwsem(&space_info->groups_sem);
@@ -389,7 +377,7 @@ again:
 
                ticket = list_first_entry(head, struct reserve_ticket, list);
 
-               /* Check and see if our ticket can be satisified now. */
+               /* Check and see if our ticket can be satisfied now. */
                if ((used + ticket->bytes <= space_info->total_bytes) ||
                    btrfs_can_overcommit(fs_info, space_info, ticket->bytes,
                                         flush)) {
@@ -495,7 +483,8 @@ static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
  */
 static void shrink_delalloc(struct btrfs_fs_info *fs_info,
                            struct btrfs_space_info *space_info,
-                           u64 to_reclaim, bool wait_ordered)
+                           u64 to_reclaim, bool wait_ordered,
+                           bool for_preempt)
 {
        struct btrfs_trans_handle *trans;
        u64 delalloc_bytes;
@@ -532,7 +521,7 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info,
         * ordered extents, otherwise we'll waste time trying to flush delalloc
         * that likely won't give us the space back we need.
         */
-       if (ordered_bytes > delalloc_bytes)
+       if (ordered_bytes > delalloc_bytes && !for_preempt)
                wait_ordered = true;
 
        loops = 0;
@@ -551,6 +540,14 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info,
                                break;
                }
 
+               /*
+                * If we are for preemption we just want a one-shot of delalloc
+                * flushing so we can stop flushing if we decide we don't need
+                * to anymore.
+                */
+               if (for_preempt)
+                       break;
+
                spin_lock(&space_info->lock);
                if (list_empty(&space_info->tickets) &&
                    list_empty(&space_info->priority_tickets)) {
@@ -566,109 +563,6 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info,
        }
 }
 
-/**
- * Possibly commit the transaction if its ok to
- *
- * @fs_info:    the filesystem
- * @space_info: space_info we are checking for commit, either data or metadata
- *
- * This will check to make sure that committing the transaction will actually
- * get us somewhere and then commit the transaction if it does.  Otherwise it
- * will return -ENOSPC.
- */
-static int may_commit_transaction(struct btrfs_fs_info *fs_info,
-                                 struct btrfs_space_info *space_info)
-{
-       struct reserve_ticket *ticket = NULL;
-       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_block_rsv;
-       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
-       struct btrfs_block_rsv *trans_rsv = &fs_info->trans_block_rsv;
-       struct btrfs_trans_handle *trans;
-       u64 reclaim_bytes = 0;
-       u64 bytes_needed = 0;
-       u64 cur_free_bytes = 0;
-
-       trans = (struct btrfs_trans_handle *)current->journal_info;
-       if (trans)
-               return -EAGAIN;
-
-       spin_lock(&space_info->lock);
-       cur_free_bytes = btrfs_space_info_used(space_info, true);
-       if (cur_free_bytes < space_info->total_bytes)
-               cur_free_bytes = space_info->total_bytes - cur_free_bytes;
-       else
-               cur_free_bytes = 0;
-
-       if (!list_empty(&space_info->priority_tickets))
-               ticket = list_first_entry(&space_info->priority_tickets,
-                                         struct reserve_ticket, list);
-       else if (!list_empty(&space_info->tickets))
-               ticket = list_first_entry(&space_info->tickets,
-                                         struct reserve_ticket, list);
-       if (ticket)
-               bytes_needed = ticket->bytes;
-
-       if (bytes_needed > cur_free_bytes)
-               bytes_needed -= cur_free_bytes;
-       else
-               bytes_needed = 0;
-       spin_unlock(&space_info->lock);
-
-       if (!bytes_needed)
-               return 0;
-
-       trans = btrfs_join_transaction(fs_info->extent_root);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
-
-       /*
-        * See if there is enough pinned space to make this reservation, or if
-        * we have block groups that are going to be freed, allowing us to
-        * possibly do a chunk allocation the next loop through.
-        */
-       if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &trans->transaction->flags) ||
-           __percpu_counter_compare(&space_info->total_bytes_pinned,
-                                    bytes_needed,
-                                    BTRFS_TOTAL_BYTES_PINNED_BATCH) >= 0)
-               goto commit;
-
-       /*
-        * See if there is some space in the delayed insertion reserve for this
-        * reservation.  If the space_info's don't match (like for DATA or
-        * SYSTEM) then just go enospc, reclaiming this space won't recover any
-        * space to satisfy those reservations.
-        */
-       if (space_info != delayed_rsv->space_info)
-               goto enospc;
-
-       spin_lock(&delayed_rsv->lock);
-       reclaim_bytes += delayed_rsv->reserved;
-       spin_unlock(&delayed_rsv->lock);
-
-       spin_lock(&delayed_refs_rsv->lock);
-       reclaim_bytes += delayed_refs_rsv->reserved;
-       spin_unlock(&delayed_refs_rsv->lock);
-
-       spin_lock(&trans_rsv->lock);
-       reclaim_bytes += trans_rsv->reserved;
-       spin_unlock(&trans_rsv->lock);
-
-       if (reclaim_bytes >= bytes_needed)
-               goto commit;
-       bytes_needed -= reclaim_bytes;
-
-       if (__percpu_counter_compare(&space_info->total_bytes_pinned,
-                                  bytes_needed,
-                                  BTRFS_TOTAL_BYTES_PINNED_BATCH) < 0)
-               goto enospc;
-
-commit:
-       return btrfs_commit_transaction(trans);
-enospc:
-       btrfs_end_transaction(trans);
-       return -ENOSPC;
-}
-
 /*
  * Try to flush some data based on policy set by @state. This is only advisory
  * and may fail for various reasons. The caller is supposed to examine the
@@ -702,7 +596,7 @@ static void flush_space(struct btrfs_fs_info *fs_info,
        case FLUSH_DELALLOC:
        case FLUSH_DELALLOC_WAIT:
                shrink_delalloc(fs_info, space_info, num_bytes,
-                               state == FLUSH_DELALLOC_WAIT);
+                               state == FLUSH_DELALLOC_WAIT, for_preempt);
                break;
        case FLUSH_DELAYED_REFS_NR:
        case FLUSH_DELAYED_REFS:
@@ -743,9 +637,7 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                btrfs_wait_on_delayed_iputs(fs_info);
                break;
        case COMMIT_TRANS:
-               ret = may_commit_transaction(fs_info, space_info);
-               break;
-       case FORCE_COMMIT_TRANS:
+               ASSERT(current->journal_info == NULL);
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
@@ -792,12 +684,14 @@ btrfs_calc_reclaim_metadata_size(struct btrfs_fs_info *fs_info,
 static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
                                    struct btrfs_space_info *space_info)
 {
+       u64 global_rsv_size = fs_info->global_block_rsv.reserved;
        u64 ordered, delalloc;
        u64 thresh = div_factor_fine(space_info->total_bytes, 98);
        u64 used;
 
        /* If we're just plain full then async reclaim just slows us down. */
-       if ((space_info->bytes_used + space_info->bytes_reserved) >= thresh)
+       if ((space_info->bytes_used + space_info->bytes_reserved +
+            global_rsv_size) >= thresh)
                return false;
 
        /*
@@ -838,8 +732,10 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
 
        thresh = calc_available_free_space(fs_info, space_info,
                                           BTRFS_RESERVE_FLUSH_ALL);
-       thresh += (space_info->total_bytes - space_info->bytes_used -
-                  space_info->bytes_reserved - space_info->bytes_readonly);
+       used = space_info->bytes_used + space_info->bytes_reserved +
+              space_info->bytes_readonly + global_rsv_size;
+       if (used < space_info->total_bytes)
+               thresh += space_info->total_bytes - used;
        thresh >>= space_info->clamp;
 
        used = space_info->bytes_pinned;
@@ -860,14 +756,20 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
         * clearly be heavy enough to warrant preemptive flushing.  In the case
         * of heavy DIO or ordered reservations, preemptive flushing will just
         * waste time and cause us to slow down.
+        *
+        * We want to make sure we truly are maxed out on ordered however, so
+        * cut ordered in half, and if it's still higher than delalloc then we
+        * can keep flushing.  This is to avoid the case where we start
+        * flushing, and now delalloc == ordered and we stop preemptively
+        * flushing when we could still have several gigs of delalloc to flush.
         */
-       ordered = percpu_counter_read_positive(&fs_info->ordered_bytes);
+       ordered = percpu_counter_read_positive(&fs_info->ordered_bytes) >> 1;
        delalloc = percpu_counter_read_positive(&fs_info->delalloc_bytes);
        if (ordered >= delalloc)
                used += fs_info->delayed_refs_rsv.reserved +
                        fs_info->delayed_block_rsv.reserved;
        else
-               used += space_info->bytes_may_use;
+               used += space_info->bytes_may_use - global_rsv_size;
 
        return (used >= thresh && !btrfs_fs_closing(fs_info) &&
                !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state));
@@ -921,7 +823,6 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info,
 {
        struct reserve_ticket *ticket;
        u64 tickets_id = space_info->tickets_id;
-       u64 first_ticket_bytes = 0;
 
        if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
                btrfs_info(fs_info, "cannot satisfy tickets, dumping space info");
@@ -937,21 +838,6 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info,
                    steal_from_global_rsv(fs_info, space_info, ticket))
                        return true;
 
-               /*
-                * may_commit_transaction will avoid committing the transaction
-                * if it doesn't feel like the space reclaimed by the commit
-                * would result in the ticket succeeding.  However if we have a
-                * smaller ticket in the queue it may be small enough to be
-                * satisified by committing the transaction, so if any
-                * subsequent ticket is smaller than the first ticket go ahead
-                * and send us back for another loop through the enospc flushing
-                * code.
-                */
-               if (first_ticket_bytes == 0)
-                       first_ticket_bytes = ticket->bytes;
-               else if (first_ticket_bytes > ticket->bytes)
-                       return true;
-
                if (btrfs_test_opt(fs_info, ENOSPC_DEBUG))
                        btrfs_info(fs_info, "failing ticket with %llu bytes",
                                   ticket->bytes);
@@ -1117,7 +1003,7 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
                           (delayed_block_rsv->reserved +
                            delayed_refs_rsv->reserved)) {
                        to_reclaim = space_info->bytes_pinned;
-                       flush = FORCE_COMMIT_TRANS;
+                       flush = COMMIT_TRANS;
                } else if (delayed_block_rsv->reserved >
                           delayed_refs_rsv->reserved) {
                        to_reclaim = delayed_block_rsv->reserved;
@@ -1171,28 +1057,9 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
  *   immediately re-usable, it comes in the form of a delayed ref, which must be
  *   run and then the transaction must be committed.
  *
- * FLUSH_DELAYED_REFS
- *   The above two cases generate delayed refs that will affect
- *   ->total_bytes_pinned.  However this counter can be inconsistent with
- *   reality if there are outstanding delayed refs.  This is because we adjust
- *   the counter based solely on the current set of delayed refs and disregard
- *   any on-disk state which might include more refs.  So for example, if we
- *   have an extent with 2 references, but we only drop 1, we'll see that there
- *   is a negative delayed ref count for the extent and assume that the space
- *   will be freed, and thus increase ->total_bytes_pinned.
- *
- *   Running the delayed refs gives us the actual real view of what will be
- *   freed at the transaction commit time.  This stage will not actually free
- *   space for us, it just makes sure that may_commit_transaction() has all of
- *   the information it needs to make the right decision.
- *
  * COMMIT_TRANS
- *   This is where we reclaim all of the pinned space generated by the previous
- *   two stages.  We will not commit the transaction if we don't think we're
- *   likely to satisfy our request, which means if our current free space +
- *   total_bytes_pinned < reservation we will not commit.  This is why the
- *   previous states are actually important, to make sure we know for sure
- *   whether committing the transaction will allow us to make progress.
+ *   This is where we reclaim all of the pinned space generated by running the
+ *   iputs
  *
  * ALLOC_CHUNK_FORCE
  *   For data we start with alloc chunk force, however we could have been full
@@ -1202,7 +1069,6 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
 static const enum btrfs_flush_state data_flush_states[] = {
        FLUSH_DELALLOC_WAIT,
        RUN_DELAYED_IPUTS,
-       FLUSH_DELAYED_REFS,
        COMMIT_TRANS,
        ALLOC_CHUNK_FORCE,
 };
@@ -1561,6 +1427,15 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info,
                    flush == BTRFS_RESERVE_FLUSH_DATA) {
                        list_add_tail(&ticket.list, &space_info->tickets);
                        if (!space_info->flush) {
+                               /*
+                                * We were forced to add a reserve ticket, so
+                                * our preemptive flushing is unable to keep
+                                * up.  Clamp down on the threshold for the
+                                * preemptive flushing in order to keep up with
+                                * the workload.
+                                */
+                               maybe_clamp_preempt(fs_info, space_info);
+
                                space_info->flush = 1;
                                trace_btrfs_trigger_flush(fs_info,
                                                          space_info->flags,
@@ -1572,14 +1447,6 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info,
                        list_add_tail(&ticket.list,
                                      &space_info->priority_tickets);
                }
-
-               /*
-                * We were forced to add a reserve ticket, so our preemptive
-                * flushing is unable to keep up.  Clamp down on the threshold
-                * for the preemptive flushing in order to keep up with the
-                * workload.
-                */
-               maybe_clamp_preempt(fs_info, space_info);
        } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
                used += orig_bytes;
                /*
@@ -1588,8 +1455,8 @@ static int __reserve_bytes(struct btrfs_fs_info *fs_info,
                 * the async reclaim as we will panic.
                 */
                if (!test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags) &&
-                   need_preemptive_reclaim(fs_info, space_info) &&
-                   !work_busy(&fs_info->preempt_reclaim_work)) {
+                   !work_busy(&fs_info->preempt_reclaim_work) &&
+                   need_preemptive_reclaim(fs_info, space_info)) {
                        trace_btrfs_trigger_flush(fs_info, space_info->flags,
                                                  orig_bytes, flush, "preempt");
                        queue_work(system_unbound_wq,
index b1a8ffb..cb50564 100644 (file)
@@ -43,18 +43,6 @@ struct btrfs_space_info {
 
        u64 flags;
 
-       /*
-        * bytes_pinned is kept in line with what is actually pinned, as in
-        * we've called update_block_group and dropped the bytes_used counter
-        * and increased the bytes_pinned counter.  However this means that
-        * bytes_pinned does not reflect the bytes that will be pinned once the
-        * delayed refs are flushed, so this counter is inc'ed every time we
-        * call btrfs_free_extent so it is a realtime count of what will be
-        * freed once the transaction is committed.  It will be zeroed every
-        * time the transaction commits.
-        */
-       struct percpu_counter total_bytes_pinned;
-
        struct list_head list;
        /* Protected by the spinlock 'lock'. */
        struct list_head ro_bgs;
@@ -157,22 +145,4 @@ static inline void btrfs_space_info_free_bytes_may_use(
 }
 int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
                             enum btrfs_reserve_flush_enum flush);
-
-static inline void __btrfs_mod_total_bytes_pinned(
-                                       struct btrfs_space_info *space_info,
-                                       s64 mod)
-{
-       percpu_counter_add_batch(&space_info->total_bytes_pinned, mod,
-                                BTRFS_TOTAL_BYTES_PINNED_BATCH);
-}
-
-static inline void btrfs_mod_total_bytes_pinned(struct btrfs_fs_info *fs_info,
-                                               u64 flags, s64 mod)
-{
-       struct btrfs_space_info *space_info = btrfs_find_space_info(fs_info, flags);
-
-       ASSERT(space_info);
-       __btrfs_mod_total_bytes_pinned(space_info, mod);
-}
-
 #endif /* BTRFS_SPACE_INFO_H */
index 2d19089..640bcd2 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/slab.h>
 #include "ctree.h"
 #include "subpage.h"
+#include "btrfs_inode.h"
 
 /*
  * Subpage (sectorsize < PAGE_SIZE) support overview:
@@ -110,10 +111,12 @@ int btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
        if (!*ret)
                return -ENOMEM;
        spin_lock_init(&(*ret)->lock);
-       if (type == BTRFS_SUBPAGE_METADATA)
+       if (type == BTRFS_SUBPAGE_METADATA) {
                atomic_set(&(*ret)->eb_refs, 0);
-       else
+       } else {
                atomic_set(&(*ret)->readers, 0);
+               atomic_set(&(*ret)->writers, 0);
+       }
        return 0;
 }
 
@@ -183,12 +186,10 @@ void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
 {
        struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
        const int nbits = len >> fs_info->sectorsize_bits;
-       int ret;
 
        btrfs_subpage_assert(fs_info, page, start, len);
 
-       ret = atomic_add_return(nbits, &subpage->readers);
-       ASSERT(ret == nbits);
+       atomic_add(nbits, &subpage->readers);
 }
 
 void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
@@ -196,10 +197,95 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
 {
        struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
        const int nbits = len >> fs_info->sectorsize_bits;
+       bool is_data;
+       bool last;
 
        btrfs_subpage_assert(fs_info, page, start, len);
+       is_data = is_data_inode(page->mapping->host);
        ASSERT(atomic_read(&subpage->readers) >= nbits);
-       if (atomic_sub_and_test(nbits, &subpage->readers))
+       last = atomic_sub_and_test(nbits, &subpage->readers);
+
+       /*
+        * For data we need to unlock the page if the last read has finished.
+        *
+        * And please don't replace @last with atomic_sub_and_test() call
+        * inside if () condition.
+        * As we want the atomic_sub_and_test() to be always executed.
+        */
+       if (is_data && last)
+               unlock_page(page);
+}
+
+static void btrfs_subpage_clamp_range(struct page *page, u64 *start, u32 *len)
+{
+       u64 orig_start = *start;
+       u32 orig_len = *len;
+
+       *start = max_t(u64, page_offset(page), orig_start);
+       *len = min_t(u64, page_offset(page) + PAGE_SIZE,
+                    orig_start + orig_len) - *start;
+}
+
+void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const int nbits = (len >> fs_info->sectorsize_bits);
+       int ret;
+
+       btrfs_subpage_assert(fs_info, page, start, len);
+
+       ASSERT(atomic_read(&subpage->readers) == 0);
+       ret = atomic_add_return(nbits, &subpage->writers);
+       ASSERT(ret == nbits);
+}
+
+bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const int nbits = (len >> fs_info->sectorsize_bits);
+
+       btrfs_subpage_assert(fs_info, page, start, len);
+
+       ASSERT(atomic_read(&subpage->writers) >= nbits);
+       return atomic_sub_and_test(nbits, &subpage->writers);
+}
+
+/*
+ * Lock a page for delalloc page writeback.
+ *
+ * Return -EAGAIN if the page is not properly initialized.
+ * Return 0 with the page locked, and writer counter updated.
+ *
+ * Even with 0 returned, the page still need extra check to make sure
+ * it's really the correct page, as the caller is using
+ * find_get_pages_contig(), which can race with page invalidating.
+ */
+int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {
+               lock_page(page);
+               return 0;
+       }
+       lock_page(page);
+       if (!PagePrivate(page) || !page->private) {
+               unlock_page(page);
+               return -EAGAIN;
+       }
+       btrfs_subpage_clamp_range(page, &start, &len);
+       btrfs_subpage_start_writer(fs_info, page, start, len);
+       return 0;
+}
+
+void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)
+               return unlock_page(page);
+       btrfs_subpage_clamp_range(page, &start, &len);
+       if (btrfs_subpage_end_and_test_writer(fs_info, page, start, len))
                unlock_page(page);
 }
 
@@ -354,6 +440,32 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
        spin_unlock_irqrestore(&subpage->lock, flags);
 }
 
+void btrfs_subpage_set_ordered(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
+       unsigned long flags;
+
+       spin_lock_irqsave(&subpage->lock, flags);
+       subpage->ordered_bitmap |= tmp;
+       SetPageOrdered(page);
+       spin_unlock_irqrestore(&subpage->lock, flags);
+}
+
+void btrfs_subpage_clear_ordered(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len)
+{
+       struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
+       const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
+       unsigned long flags;
+
+       spin_lock_irqsave(&subpage->lock, flags);
+       subpage->ordered_bitmap &= ~tmp;
+       if (subpage->ordered_bitmap == 0)
+               ClearPageOrdered(page);
+       spin_unlock_irqrestore(&subpage->lock, flags);
+}
 /*
  * Unlike set/clear which is dependent on each page status, for test all bits
  * are tested in the same way.
@@ -376,6 +488,7 @@ IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(uptodate);
 IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(error);
 IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(dirty);
 IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(writeback);
+IMPLEMENT_BTRFS_SUBPAGE_TEST_OP(ordered);
 
 /*
  * Note that, in selftests (extent-io-tests), we can have empty fs_info passed
@@ -408,6 +521,34 @@ bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info,   \
        if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)     \
                return test_page_func(page);                            \
        return btrfs_subpage_test_##name(fs_info, page, start, len);    \
+}                                                                      \
+void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info,  \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {   \
+               set_page_func(page);                                    \
+               return;                                                 \
+       }                                                               \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       btrfs_subpage_set_##name(fs_info, page, start, len);            \
+}                                                                      \
+void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {   \
+               clear_page_func(page);                                  \
+               return;                                                 \
+       }                                                               \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       btrfs_subpage_clear_##name(fs_info, page, start, len);          \
+}                                                                      \
+bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)     \
+               return test_page_func(page);                            \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       return btrfs_subpage_test_##name(fs_info, page, start, len);    \
 }
 IMPLEMENT_BTRFS_PAGE_OPS(uptodate, SetPageUptodate, ClearPageUptodate,
                         PageUptodate);
@@ -416,3 +557,5 @@ IMPLEMENT_BTRFS_PAGE_OPS(dirty, set_page_dirty, clear_page_dirty_for_io,
                         PageDirty);
 IMPLEMENT_BTRFS_PAGE_OPS(writeback, set_page_writeback, end_page_writeback,
                         PageWriteback);
+IMPLEMENT_BTRFS_PAGE_OPS(ordered, SetPageOrdered, ClearPageOrdered,
+                        PageOrdered);
index bfd626e..4d7aca8 100644 (file)
@@ -22,6 +22,14 @@ struct btrfs_subpage {
        u16 error_bitmap;
        u16 dirty_bitmap;
        u16 writeback_bitmap;
+       /*
+        * Both data and metadata needs to track how many readers are for the
+        * page.
+        * Data relies on @readers to unlock the page when last reader finished.
+        * While metadata doesn't need page unlock, it needs to prevent
+        * page::private get cleared before the last end_page_read().
+        */
+       atomic_t readers;
        union {
                /*
                 * Structures only used by metadata
@@ -32,7 +40,10 @@ struct btrfs_subpage {
                atomic_t eb_refs;
                /* Structures only used by data */
                struct {
-                       atomic_t readers;
+                       atomic_t writers;
+
+                       /* Tracke pending ordered extent in this sector */
+                       u16 ordered_bitmap;
                };
        };
 };
@@ -63,6 +74,15 @@ void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
 void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
                struct page *page, u64 start, u32 len);
 
+void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info,
+               struct page *page, u64 start, u32 len);
+
 /*
  * Template for subpage related operations.
  *
@@ -72,6 +92,10 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
  * btrfs_page_*() are for call sites where the page can either be subpage
  * specific or regular page. The function will handle both cases.
  * But the range still needs to be inside the page.
+ *
+ * btrfs_page_clamp_*() are similar to btrfs_page_*(), except the range doesn't
+ * need to be inside the page. Those functions will truncate the range
+ * automatically.
  */
 #define DECLARE_BTRFS_SUBPAGE_OPS(name)                                        \
 void btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info,     \
@@ -85,12 +109,19 @@ void btrfs_page_set_##name(const struct btrfs_fs_info *fs_info,            \
 void btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info,      \
                struct page *page, u64 start, u32 len);                 \
 bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info,       \
+               struct page *page, u64 start, u32 len);                 \
+void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info,  \
+               struct page *page, u64 start, u32 len);                 \
+void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info,        \
+               struct page *page, u64 start, u32 len);                 \
+bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
                struct page *page, u64 start, u32 len);
 
 DECLARE_BTRFS_SUBPAGE_OPS(uptodate);
 DECLARE_BTRFS_SUBPAGE_OPS(error);
 DECLARE_BTRFS_SUBPAGE_OPS(dirty);
 DECLARE_BTRFS_SUBPAGE_OPS(writeback);
+DECLARE_BTRFS_SUBPAGE_OPS(ordered);
 
 bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info,
                struct page *page, u64 start, u32 len);
index 4a396c1..d07b18b 100644 (file)
@@ -299,17 +299,6 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info = trans->fs_info;
 
        WRITE_ONCE(trans->aborted, errno);
-       /* Nothing used. The other threads that have joined this
-        * transaction may be able to continue. */
-       if (!trans->dirty && list_empty(&trans->new_bgs)) {
-               const char *errstr;
-
-               errstr = btrfs_decode_error(errno);
-               btrfs_warn(fs_info,
-                          "%s:%d: Aborting unused transaction(%s).",
-                          function, line, errstr);
-               return;
-       }
        WRITE_ONCE(trans->transaction->aborted, errno);
        /* Wake up anybody who may be waiting on this transaction */
        wake_up(&fs_info->transaction_wait);
@@ -945,8 +934,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                case Opt_check_integrity_including_extent_data:
                        btrfs_info(info,
                                   "enabling check integrity including extent data");
-                       btrfs_set_opt(info->mount_opt,
-                                     CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
+                       btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY_DATA);
                        btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
                        break;
                case Opt_check_integrity:
@@ -1527,7 +1515,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        if (btrfs_test_opt(info, SKIP_BALANCE))
                seq_puts(seq, ",skip_balance");
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(info, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
+       if (btrfs_test_opt(info, CHECK_INTEGRITY_DATA))
                seq_puts(seq, ",check_int_data");
        else if (btrfs_test_opt(info, CHECK_INTEGRITY))
                seq_puts(seq, ",check_int");
index 436ac7b..9d1d140 100644 (file)
@@ -429,7 +429,7 @@ static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj,
 {
        struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
 
-       return scnprintf(buf, PAGE_SIZE, "%lld\n",
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
                        fs_info->discard_ctl.discard_bitmap_bytes);
 }
 BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show);
@@ -451,7 +451,7 @@ static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj,
 {
        struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
 
-       return scnprintf(buf, PAGE_SIZE, "%lld\n",
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
                        fs_info->discard_ctl.discard_extent_bytes);
 }
 BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show);
@@ -665,15 +665,6 @@ static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \
 }                                                                      \
 BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field)
 
-static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj,
-                                                      struct kobj_attribute *a,
-                                                      char *buf)
-{
-       struct btrfs_space_info *sinfo = to_space_info(kobj);
-       s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned);
-       return scnprintf(buf, PAGE_SIZE, "%lld\n", val);
-}
-
 SPACE_INFO_ATTR(flags);
 SPACE_INFO_ATTR(total_bytes);
 SPACE_INFO_ATTR(bytes_used);
@@ -684,8 +675,6 @@ SPACE_INFO_ATTR(bytes_readonly);
 SPACE_INFO_ATTR(bytes_zone_unusable);
 SPACE_INFO_ATTR(disk_used);
 SPACE_INFO_ATTR(disk_total);
-BTRFS_ATTR(space_info, total_bytes_pinned,
-          btrfs_space_info_show_total_bytes_pinned);
 
 static struct attribute *space_info_attrs[] = {
        BTRFS_ATTR_PTR(space_info, flags),
@@ -698,7 +687,6 @@ static struct attribute *space_info_attrs[] = {
        BTRFS_ATTR_PTR(space_info, bytes_zone_unusable),
        BTRFS_ATTR_PTR(space_info, disk_used),
        BTRFS_ATTR_PTR(space_info, disk_total),
-       BTRFS_ATTR_PTR(space_info, total_bytes_pinned),
        NULL,
 };
 ATTRIBUTE_GROUPS(space_info);
@@ -706,7 +694,6 @@ ATTRIBUTE_GROUPS(space_info);
 static void space_info_release(struct kobject *kobj)
 {
        struct btrfs_space_info *sinfo = to_space_info(kobj);
-       percpu_counter_destroy(&sinfo->total_bytes_pinned);
        kfree(sinfo);
 }
 
@@ -1455,6 +1442,33 @@ static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
 }
 BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
 
+static ssize_t btrfs_devinfo_scrub_speed_max_show(struct kobject *kobj,
+                                            struct kobj_attribute *a,
+                                            char *buf)
+{
+       struct btrfs_device *device = container_of(kobj, struct btrfs_device,
+                                                  devid_kobj);
+
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
+                        READ_ONCE(device->scrub_speed_max));
+}
+
+static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
+                                             struct kobj_attribute *a,
+                                             const char *buf, size_t len)
+{
+       struct btrfs_device *device = container_of(kobj, struct btrfs_device,
+                                                  devid_kobj);
+       char *endptr;
+       unsigned long long limit;
+
+       limit = memparse(buf, &endptr);
+       WRITE_ONCE(device->scrub_speed_max, limit);
+       return len;
+}
+BTRFS_ATTR_RW(devid, scrub_speed_max, btrfs_devinfo_scrub_speed_max_show,
+             btrfs_devinfo_scrub_speed_max_store);
+
 static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
                                            struct kobj_attribute *a, char *buf)
 {
@@ -1468,10 +1482,40 @@ static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
 }
 BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
 
+static ssize_t btrfs_devinfo_error_stats_show(struct kobject *kobj,
+               struct kobj_attribute *a, char *buf)
+{
+       struct btrfs_device *device = container_of(kobj, struct btrfs_device,
+                                                  devid_kobj);
+
+       if (!device->dev_stats_valid)
+               return scnprintf(buf, PAGE_SIZE, "invalid\n");
+
+       /*
+        * Print all at once so we get a snapshot of all values from the same
+        * time. Keep them in sync and in order of definition of
+        * btrfs_dev_stat_values.
+        */
+       return scnprintf(buf, PAGE_SIZE,
+               "write_errs %d\n"
+               "read_errs %d\n"
+               "flush_errs %d\n"
+               "corruption_errs %d\n"
+               "generation_errs %d\n",
+               btrfs_dev_stat_read(device, BTRFS_DEV_STAT_WRITE_ERRS),
+               btrfs_dev_stat_read(device, BTRFS_DEV_STAT_READ_ERRS),
+               btrfs_dev_stat_read(device, BTRFS_DEV_STAT_FLUSH_ERRS),
+               btrfs_dev_stat_read(device, BTRFS_DEV_STAT_CORRUPTION_ERRS),
+               btrfs_dev_stat_read(device, BTRFS_DEV_STAT_GENERATION_ERRS));
+}
+BTRFS_ATTR(devid, error_stats, btrfs_devinfo_error_stats_show);
+
 static struct attribute *devid_attrs[] = {
+       BTRFS_ATTR_PTR(devid, error_stats),
        BTRFS_ATTR_PTR(devid, in_fs_metadata),
        BTRFS_ATTR_PTR(devid, missing),
        BTRFS_ATTR_PTR(devid, replace_target),
+       BTRFS_ATTR_PTR(devid, scrub_speed_max),
        BTRFS_ATTR_PTR(devid, writeable),
        NULL
 };
index c0aefe6..319fed8 100644 (file)
@@ -557,7 +557,7 @@ int btrfs_test_extent_map(void)
                {
                        /*
                         * Test a chunk with 2 data stripes one of which
-                        * interesects the physical address of the super block
+                        * intersects the physical address of the super block
                         * is correctly recognised.
                         */
                        .raid_type = BTRFS_BLOCK_GROUP_RAID1,
index f75de9f..5031823 100644 (file)
@@ -583,9 +583,6 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
        bool do_chunk_alloc = false;
        int ret;
 
-       /* Send isn't supposed to start transactions. */
-       ASSERT(current->journal_info != BTRFS_SEND_TRANS_STUB);
-
        if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                return ERR_PTR(-EROFS);
 
@@ -1406,8 +1403,10 @@ int btrfs_defrag_root(struct btrfs_root *root)
 
        while (1) {
                trans = btrfs_start_transaction(root, 0);
-               if (IS_ERR(trans))
-                       return PTR_ERR(trans);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
+               }
 
                ret = btrfs_defrag_leaves(trans, root);
 
@@ -1476,7 +1475,7 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
        ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
        if (ret) {
                btrfs_abort_transaction(trans, ret);
-               goto out;
+               return ret;
        }
 
        /*
@@ -1869,31 +1868,6 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info)
 }
 
 /*
- * wait for the current transaction commit to start and block subsequent
- * transaction joins
- */
-static void wait_current_trans_commit_start(struct btrfs_fs_info *fs_info,
-                                           struct btrfs_transaction *trans)
-{
-       wait_event(fs_info->transaction_blocked_wait,
-                  trans->state >= TRANS_STATE_COMMIT_START ||
-                  TRANS_ABORTED(trans));
-}
-
-/*
- * wait for the current transaction to start and then become unblocked.
- * caller holds ref.
- */
-static void wait_current_trans_commit_start_and_unblock(
-                                       struct btrfs_fs_info *fs_info,
-                                       struct btrfs_transaction *trans)
-{
-       wait_event(fs_info->transaction_wait,
-                  trans->state >= TRANS_STATE_UNBLOCKED ||
-                  TRANS_ABORTED(trans));
-}
-
-/*
  * commit transactions asynchronously. once btrfs_commit_transaction_async
  * returns, any subsequent transaction will not be allowed to join.
  */
@@ -1920,8 +1894,7 @@ static void do_async_commit(struct work_struct *work)
        kfree(ac);
 }
 
-int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
-                                  int wait_for_unblock)
+int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
        struct btrfs_async_commit *ac;
@@ -1953,13 +1926,13 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
                __sb_writers_release(fs_info->sb, SB_FREEZE_FS);
 
        schedule_work(&ac->work);
-
-       /* wait for transaction to start and unblock */
-       if (wait_for_unblock)
-               wait_current_trans_commit_start_and_unblock(fs_info, cur_trans);
-       else
-               wait_current_trans_commit_start(fs_info, cur_trans);
-
+       /*
+        * Wait for the current transaction commit to start and block
+        * subsequent transaction joins
+        */
+       wait_event(fs_info->transaction_blocked_wait,
+                  cur_trans->state >= TRANS_STATE_COMMIT_START ||
+                  TRANS_ABORTED(cur_trans));
        if (current->journal_info == trans)
                current->journal_info = NULL;
 
@@ -2074,14 +2047,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 
        ASSERT(refcount_read(&trans->use_count) == 1);
 
-       /*
-        * Some places just start a transaction to commit it.  We need to make
-        * sure that if this commit fails that the abort code actually marks the
-        * transaction as failed, so set trans->dirty to make the abort code do
-        * the right thing.
-        */
-       trans->dirty = true;
-
        /* Stop the commit early if ->aborted is set */
        if (TRANS_ABORTED(cur_trans)) {
                ret = cur_trans->aborted;
index 364cfbb..07d7602 100644 (file)
@@ -122,8 +122,6 @@ struct btrfs_transaction {
 
 #define TRANS_EXTWRITERS       (__TRANS_START | __TRANS_ATTACH)
 
-#define BTRFS_SEND_TRANS_STUB  ((void *)1)
-
 struct btrfs_trans_handle {
        u64 transid;
        u64 bytes_reserved;
@@ -143,7 +141,6 @@ struct btrfs_trans_handle {
        bool allocating_chunk;
        bool can_flush_pending_bgs;
        bool reloc_reserved;
-       bool dirty;
        bool in_fsync;
        struct btrfs_root *root;
        struct btrfs_fs_info *fs_info;
@@ -227,8 +224,7 @@ void btrfs_add_dead_root(struct btrfs_root *root);
 int btrfs_defrag_root(struct btrfs_root *root);
 int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root);
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans);
-int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
-                                  int wait_for_unblock);
+int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans);
 bool btrfs_should_end_transaction(struct btrfs_trans_handle *trans);
 void btrfs_throttle(struct btrfs_fs_info *fs_info);
index dbcf8bb..cab451d 100644 (file)
@@ -4468,7 +4468,8 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,
                                ret = btrfs_truncate_inode_items(trans,
                                                         root->log_root,
                                                         inode, truncate_offset,
-                                                        BTRFS_EXTENT_DATA_KEY);
+                                                        BTRFS_EXTENT_DATA_KEY,
+                                                        NULL);
                        } while (ret == -EAGAIN);
                        if (ret)
                                goto out;
@@ -5416,7 +5417,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                                          &inode->runtime_flags);
                                while(1) {
                                        ret = btrfs_truncate_inode_items(trans,
-                                               log, inode, 0, 0);
+                                               log, inode, 0, 0, NULL);
                                        if (ret != -EAGAIN)
                                                break;
                                }
@@ -5466,13 +5467,23 @@ log_extents:
        btrfs_release_path(dst_path);
        if (need_log_inode_item) {
                err = log_inode_item(trans, log, dst_path, inode);
-               if (!err && !xattrs_logged) {
+               if (err)
+                       goto out_unlock;
+               /*
+                * If we are doing a fast fsync and the inode was logged before
+                * in this transaction, we don't need to log the xattrs because
+                * they were logged before. If xattrs were added, changed or
+                * deleted since the last time we logged the inode, then we have
+                * already logged them because the inode had the runtime flag
+                * BTRFS_INODE_COPY_EVERYTHING set.
+                */
+               if (!xattrs_logged && inode->logged_trans < trans->transid) {
                        err = btrfs_log_all_xattrs(trans, root, inode, path,
                                                   dst_path);
+                       if (err)
+                               goto out_unlock;
                        btrfs_release_path(path);
                }
-               if (err)
-                       goto out_unlock;
        }
        if (fast_search) {
                ret = btrfs_log_changed_extents(trans, root, inode, dst_path,
@@ -6371,6 +6382,7 @@ next:
 error:
        if (wc.trans)
                btrfs_end_transaction(wc.trans);
+       clear_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags);
        btrfs_free_path(path);
        return ret;
 }
index 47d2705..782e167 100644 (file)
@@ -717,7 +717,7 @@ static struct btrfs_fs_devices *find_fsid_changed(
 
        /*
         * Handles the case where scanned device is part of an fs that had
-        * multiple successful changes of FSID but curently device didn't
+        * multiple successful changes of FSID but currently device didn't
         * observe it. Meaning our fsid will be different than theirs. We need
         * to handle two subcases :
         *  1 - The fs still continues to have different METADATA/FSID uuids.
@@ -1550,7 +1550,7 @@ static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
  * check to ensure dev extents are not double allocated.
  * This makes the function safe to allocate dev extents but may not report
  * correct usable device space, as device extent freed in current transaction
- * is not reported as avaiable.
+ * is not reported as available.
  */
 static int find_free_dev_extent_start(struct btrfs_device *device,
                                u64 num_bytes, u64 search_start, u64 *start,
@@ -4217,14 +4217,6 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
                                btrfs_bg_type_to_raid_name(data_target));
        }
 
-       if (fs_info->send_in_progress) {
-               btrfs_warn_rl(fs_info,
-"cannot run balance while send operations are in progress (%d in progress)",
-                             fs_info->send_in_progress);
-               ret = -EAGAIN;
-               goto out;
-       }
-
        ret = insert_balance_item(fs_info, bctl);
        if (ret && ret != -EEXIST)
                goto out;
@@ -6127,17 +6119,17 @@ static bool need_full_stripe(enum btrfs_map_op op)
  * @em:      mapping containing the logical extent
  * @op:      type of operation - write or read
  * @logical: address that we want to figure out the geometry of
- * @len:     the length of IO we are going to perform, starting at @logical
  * @io_geom: pointer used to return values
  *
  * Returns < 0 in case a chunk for the given logical address cannot be found,
  * usually shouldn't happen unless @logical is corrupted, 0 otherwise.
  */
 int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
-                         enum btrfs_map_op op, u64 logical, u64 len,
+                         enum btrfs_map_op op, u64 logical,
                          struct btrfs_io_geometry *io_geom)
 {
        struct map_lookup *map;
+       u64 len;
        u64 offset;
        u64 stripe_offset;
        u64 stripe_nr;
@@ -6152,7 +6144,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
        offset = logical - em->start;
        /* Len of a stripe in a chunk */
        stripe_len = map->stripe_len;
-       /* Stripe wher this block falls in */
+       /* Stripe where this block falls in */
        stripe_nr = div64_u64(offset, stripe_len);
        /* Offset of stripe in the chunk */
        stripe_offset = stripe_nr * stripe_len;
@@ -6243,7 +6235,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
        em = btrfs_get_chunk_map(fs_info, logical, *length);
        ASSERT(!IS_ERR(em));
 
-       ret = btrfs_get_io_geometry(fs_info, em, op, logical, *length, &geom);
+       ret = btrfs_get_io_geometry(fs_info, em, op, logical, &geom);
        if (ret < 0)
                return ret;
 
@@ -6670,8 +6662,6 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
  *
  * If devid and uuid are both specified, the match must be exact, otherwise
  * only devid is used.
- *
- * If @seed is true, traverse through the seed devices.
  */
 struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
                                       u64 devid, u8 *uuid, u8 *fsid)
@@ -7865,7 +7855,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
                ret = -EUCLEAN;
        }
 
-       /* Make sure no dev extent is beyond device bondary */
+       /* Make sure no dev extent is beyond device boundary */
        dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
        if (!dev) {
                btrfs_err(fs_info, "failed to find devid %llu", devid);
index 9c0d84e..c7fc7ca 100644 (file)
@@ -143,6 +143,9 @@ struct btrfs_device {
        struct completion kobj_unregister;
        /* For sysfs/FSID/devinfo/devid/ */
        struct kobject devid_kobj;
+
+       /* Bandwidth limit for scrub, in bytes */
+       u64 scrub_speed_max;
 };
 
 /*
@@ -443,7 +446,7 @@ int btrfs_map_sblock(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
                     u64 logical, u64 *length,
                     struct btrfs_bio **bbio_ret);
 int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map,
-                         enum btrfs_map_op op, u64 logical, u64 len,
+                         enum btrfs_map_op op, u64 logical,
                          struct btrfs_io_geometry *io_geom);
 int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
 int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
index f1f3b10..297c0b1 100644 (file)
@@ -81,7 +81,7 @@ static int sb_write_pointer(struct block_device *bdev, struct blk_zone *zones,
         *   *: Special case, no superblock is written
         *   0: Use write pointer of zones[0]
         *   1: Use write pointer of zones[1]
-        *   C: Compare super blcoks from zones[0] and zones[1], use the latest
+        *   C: Compare super blocks from zones[0] and zones[1], use the latest
         *      one determined by generation
         *   x: Invalid state
         */
@@ -433,7 +433,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device)
                }
 
                /*
-                * If zones[0] is conventional, always use the beggining of the
+                * If zones[0] is conventional, always use the beginning of the
                 * zone to record superblock. No need to validate in that case.
                 */
                if (zone_info->sb_zones[BTRFS_NR_SB_LOG_ZONES * i].type ==
@@ -1140,6 +1140,10 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
                }
 
                if (zone.type == BLK_ZONE_TYPE_CONVENTIONAL) {
+                       btrfs_err_in_rcu(fs_info,
+       "zoned: unexpected conventional zone %llu on device %s (devid %llu)",
+                               zone.start << SECTOR_SHIFT,
+                               rcu_str_deref(device->name), device->devid);
                        ret = -EIO;
                        goto out;
                }
@@ -1200,6 +1204,13 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
 
        switch (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
        case 0: /* single */
+               if (alloc_offsets[0] == WP_MISSING_DEV) {
+                       btrfs_err(fs_info,
+                       "zoned: cannot recover write pointer for zone %llu",
+                               physical);
+                       ret = -EIO;
+                       goto out;
+               }
                cache->alloc_offset = alloc_offsets[0];
                break;
        case BTRFS_BLOCK_GROUP_DUP:
@@ -1217,6 +1228,13 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
        }
 
 out:
+       if (cache->alloc_offset > fs_info->zone_size) {
+               btrfs_err(fs_info,
+                       "zoned: invalid write pointer %llu in block group %llu",
+                       cache->alloc_offset, cache->start);
+               ret = -EIO;
+       }
+
        /* An extent is allocated after the write pointer */
        if (!ret && num_conventional && last_alloc > cache->alloc_offset) {
                btrfs_err(fs_info,
@@ -1515,3 +1533,24 @@ int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
        length = wp - physical_pos;
        return btrfs_zoned_issue_zeroout(tgt_dev, physical_pos, length);
 }
+
+struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
+                                           u64 logical, u64 length)
+{
+       struct btrfs_device *device;
+       struct extent_map *em;
+       struct map_lookup *map;
+
+       em = btrfs_get_chunk_map(fs_info, logical, length);
+       if (IS_ERR(em))
+               return ERR_CAST(em);
+
+       map = em->map_lookup;
+       /* We only support single profile for now */
+       ASSERT(map->num_stripes == 1);
+       device = map->stripes[0].dev;
+
+       free_extent_map(em);
+
+       return device;
+}
index e55d325..b0ae260 100644 (file)
@@ -65,6 +65,8 @@ void btrfs_revert_meta_write_pointer(struct btrfs_block_group *cache,
 int btrfs_zoned_issue_zeroout(struct btrfs_device *device, u64 physical, u64 length);
 int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
                                  u64 physical_start, u64 physical_pos);
+struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
+                                           u64 logical, u64 length);
 #else /* CONFIG_BLK_DEV_ZONED */
 static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
                                     struct blk_zone *zone)
@@ -191,6 +193,13 @@ static inline int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev,
        return -EOPNOTSUPP;
 }
 
+static inline struct btrfs_device *btrfs_zoned_get_device(
+                                                 struct btrfs_fs_info *fs_info,
+                                                 u64 logical, u64 length)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
 #endif
 
 static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)
index 5624fae..9ba79b6 100644 (file)
@@ -668,14 +668,13 @@ out:
  * Handle lookups for the hidden .snap directory.
  */
 struct dentry *ceph_handle_snapdir(struct ceph_mds_request *req,
-                                  struct dentry *dentry, int err)
+                                  struct dentry *dentry)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
        struct inode *parent = d_inode(dentry->d_parent); /* we hold i_mutex */
 
        /* .snap dir? */
-       if (err == -ENOENT &&
-           ceph_snap(parent) == CEPH_NOSNAP &&
+       if (ceph_snap(parent) == CEPH_NOSNAP &&
            strcmp(dentry->d_name.name, fsc->mount_options->snapdir_name) == 0) {
                struct dentry *res;
                struct inode *inode = ceph_get_snapdir(parent);
@@ -742,7 +741,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
        struct ceph_mds_request *req;
-       struct dentry *res;
        int op;
        int mask;
        int err;
@@ -793,12 +791,16 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
        req->r_parent = dir;
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
        err = ceph_mdsc_do_request(mdsc, NULL, req);
-       res = ceph_handle_snapdir(req, dentry, err);
-       if (IS_ERR(res)) {
-               err = PTR_ERR(res);
-       } else {
-               dentry = res;
-               err = 0;
+       if (err == -ENOENT) {
+               struct dentry *res;
+
+               res = ceph_handle_snapdir(req, dentry);
+               if (IS_ERR(res)) {
+                       err = PTR_ERR(res);
+               } else {
+                       dentry = res;
+                       err = 0;
+               }
        }
        dentry = ceph_finish_lookup(req, dentry, err);
        ceph_mdsc_put_request(req);  /* will dput(dentry) */
index 77fc037..d51af36 100644 (file)
@@ -578,6 +578,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        struct ceph_inode_info *ci = ceph_inode(dir);
        struct inode *inode;
        struct timespec64 now;
+       struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
        struct ceph_vino vino = { .ino = req->r_deleg_ino,
                                  .snap = CEPH_NOSNAP };
 
@@ -615,8 +616,10 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
 
        ceph_file_layout_to_legacy(lo, &in.layout);
 
+       down_read(&mdsc->snap_rwsem);
        ret = ceph_fill_inode(inode, NULL, &iinfo, NULL, req->r_session,
                              req->r_fmode, NULL);
+       up_read(&mdsc->snap_rwsem);
        if (ret) {
                dout("%s failed to fill inode: %d\n", __func__, ret);
                ceph_dir_clear_complete(dir);
@@ -739,14 +742,16 @@ retry:
        err = ceph_mdsc_do_request(mdsc,
                                   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL,
                                   req);
-       dentry = ceph_handle_snapdir(req, dentry, err);
-       if (IS_ERR(dentry)) {
-               err = PTR_ERR(dentry);
-               goto out_req;
+       if (err == -ENOENT) {
+               dentry = ceph_handle_snapdir(req, dentry);
+               if (IS_ERR(dentry)) {
+                       err = PTR_ERR(dentry);
+                       goto out_req;
+               }
+               err = 0;
        }
-       err = 0;
 
-       if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
+       if (!err && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
                err = ceph_handle_notrace_create(dir, dentry);
 
        if (d_in_lookup(dentry)) {
index e1c63ad..df0c8a7 100644 (file)
@@ -777,6 +777,8 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
        umode_t mode = le32_to_cpu(info->mode);
        dev_t rdev = le32_to_cpu(info->rdev);
 
+       lockdep_assert_held(&mdsc->snap_rwsem);
+
        dout("%s %p ino %llx.%llx v %llu had %llu\n", __func__,
             inode, ceph_vinop(inode), le64_to_cpu(info->version),
             ci->i_version);
index db80d89..839e6b0 100644 (file)
@@ -1218,7 +1218,7 @@ extern const struct dentry_operations ceph_dentry_ops;
 extern loff_t ceph_make_fpos(unsigned high, unsigned off, bool hash_order);
 extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry);
 extern struct dentry *ceph_handle_snapdir(struct ceph_mds_request *req,
-                              struct dentry *dentry, int err);
+                              struct dentry *dentry);
 extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
                                         struct dentry *dentry, int err);
 
index 6ca7d16..d004554 100644 (file)
@@ -344,13 +344,9 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode,
                     offsetof(struct fscrypt_nokey_name, sha256));
        BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX);
 
-       if (hash) {
-               nokey_name.dirhash[0] = hash;
-               nokey_name.dirhash[1] = minor_hash;
-       } else {
-               nokey_name.dirhash[0] = 0;
-               nokey_name.dirhash[1] = 0;
-       }
+       nokey_name.dirhash[0] = hash;
+       nokey_name.dirhash[1] = minor_hash;
+
        if (iname->len <= sizeof(nokey_name.bytes)) {
                memcpy(nokey_name.bytes, iname->name, iname->len);
                size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]);
index 261293f..bca9c66 100644 (file)
@@ -210,15 +210,40 @@ out_unlock:
        return err;
 }
 
+/*
+ * Derive a SipHash key from the given fscrypt master key and the given
+ * application-specific information string.
+ *
+ * Note that the KDF produces a byte array, but the SipHash APIs expect the key
+ * as a pair of 64-bit words.  Therefore, on big endian CPUs we have to do an
+ * endianness swap in order to get the same results as on little endian CPUs.
+ */
+static int fscrypt_derive_siphash_key(const struct fscrypt_master_key *mk,
+                                     u8 context, const u8 *info,
+                                     unsigned int infolen, siphash_key_t *key)
+{
+       int err;
+
+       err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, context, info, infolen,
+                                 (u8 *)key, sizeof(*key));
+       if (err)
+               return err;
+
+       BUILD_BUG_ON(sizeof(*key) != 16);
+       BUILD_BUG_ON(ARRAY_SIZE(key->key) != 2);
+       le64_to_cpus(&key->key[0]);
+       le64_to_cpus(&key->key[1]);
+       return 0;
+}
+
 int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
                               const struct fscrypt_master_key *mk)
 {
        int err;
 
-       err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, HKDF_CONTEXT_DIRHASH_KEY,
-                                 ci->ci_nonce, FSCRYPT_FILE_NONCE_SIZE,
-                                 (u8 *)&ci->ci_dirhash_key,
-                                 sizeof(ci->ci_dirhash_key));
+       err = fscrypt_derive_siphash_key(mk, HKDF_CONTEXT_DIRHASH_KEY,
+                                        ci->ci_nonce, FSCRYPT_FILE_NONCE_SIZE,
+                                        &ci->ci_dirhash_key);
        if (err)
                return err;
        ci->ci_dirhash_key_initialized = true;
@@ -253,10 +278,9 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
                if (mk->mk_ino_hash_key_initialized)
                        goto unlock;
 
-               err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf,
-                                         HKDF_CONTEXT_INODE_HASH_KEY, NULL, 0,
-                                         (u8 *)&mk->mk_ino_hash_key,
-                                         sizeof(mk->mk_ino_hash_key));
+               err = fscrypt_derive_siphash_key(mk,
+                                                HKDF_CONTEXT_INODE_HASH_KEY,
+                                                NULL, 0, &mk->mk_ino_hash_key);
                if (err)
                        goto unlock;
                /* pairs with smp_load_acquire() above */
index 858b333..906af0c 100644 (file)
@@ -75,4 +75,3 @@ config EROFS_FS_ZIP
          Enable fixed-sized output compression for EROFS.
 
          If you don't want to enable compression feature, say N.
-
index aea129d..3701c72 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2019 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_FS_COMPRESS_H
 #define __EROFS_FS_COMPRESS_H
@@ -85,4 +84,3 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq,
                       struct list_head *pagepool);
 
 #endif
-
index ebac756..3787a5f 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "internal.h"
 #include <linux/prefetch.h>
@@ -315,4 +314,3 @@ const struct address_space_operations erofs_raw_access_aops = {
        .readahead = erofs_raw_access_readahead,
        .bmap = erofs_bmap,
 };
-
index 88e33ad..a5bc4b1 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2019 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "compress.h"
 #include <linux/module.h>
@@ -407,4 +406,3 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq,
                return z_erofs_shifted_transform(rq, pagepool);
        return z_erofs_decompress_generic(rq, pagepool);
 }
-
index 2776bb8..eee9b0b 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "internal.h"
 
@@ -139,4 +138,3 @@ const struct file_operations erofs_dir_fops = {
        .read           = generic_read_dir,
        .iterate_shared = erofs_readdir,
 };
-
index 8739d3a..0f8da74 100644 (file)
@@ -4,7 +4,6 @@
  *
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_FS_H
 #define __EROFS_FS_H
@@ -348,4 +347,3 @@ static inline void erofs_check_ondisk_layout_definitions(void)
 }
 
 #endif
-
index 7ed2d73..aa8a0d7 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "xattr.h"
 
@@ -374,4 +373,3 @@ const struct inode_operations erofs_fast_symlink_iops = {
        .listxattr = erofs_listxattr,
        .get_acl = erofs_get_acl,
 };
-
index f92e3e3..543c2ff 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_INTERNAL_H
 #define __EROFS_INTERNAL_H
@@ -469,4 +468,3 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
 #define EFSCORRUPTED    EUCLEAN         /* Filesystem is corrupted */
 
 #endif /* __EROFS_INTERNAL_H */
-
index 3a81e1f..a8271ce 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "xattr.h"
 
@@ -247,4 +246,3 @@ const struct inode_operations erofs_dir_iops = {
        .listxattr = erofs_listxattr,
        .get_acl = erofs_get_acl,
 };
-
index bbf3bbd..8fc6c04 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include <linux/module.h>
 #include <linux/buffer_head.h>
@@ -285,6 +284,7 @@ static int erofs_read_superblock(struct super_block *sb)
                        goto out;
        }
 
+       ret = -EINVAL;
        blkszbits = dsb->blkszbits;
        /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
        if (blkszbits != LOG_BLOCK_SIZE) {
@@ -751,4 +751,3 @@ module_exit(erofs_module_exit);
 MODULE_DESCRIPTION("Enhanced ROM File System");
 MODULE_AUTHOR("Gao Xiang, Chao Yu, Miao Xie, CONSUMER BG, HUAWEI Inc.");
 MODULE_LICENSE("GPL");
-
index a72897c..64ceb72 100644 (file)
@@ -1,8 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * A tagged pointer implementation
- *
- * Copyright (C) 2018 Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_FS_TAGPTR_H
 #define __EROFS_FS_TAGPTR_H
@@ -107,4 +105,3 @@ tagptr_init(o, cmpxchg(&ptptr->v, o.v, n.v)); })
 *ptptr; })
 
 #endif /* __EROFS_FS_TAGPTR_H */
-
index 6758c5b..bd86067 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "internal.h"
 #include <linux/pagevec.h>
@@ -278,4 +277,3 @@ void erofs_exit_shrinker(void)
        unregister_shrinker(&erofs_shrinker_info);
 }
 #endif /* !CONFIG_EROFS_FS_ZIP */
-
index 47314a2..8dd54b4 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include <linux/security.h>
 #include "xattr.h"
@@ -709,4 +708,3 @@ struct posix_acl *erofs_get_acl(struct inode *inode, int type)
        return acl;
 }
 #endif
-
index 815304b..366dcb4 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2017-2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_XATTR_H
 #define __EROFS_XATTR_H
index 78e4b59..cb4d088 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "zdata.h"
 #include "compress.h"
@@ -380,7 +379,6 @@ static int z_erofs_attach_page(struct z_erofs_collector *clt,
                               enum z_erofs_page_type type)
 {
        int ret;
-       bool occupied;
 
        /* give priority for inplaceio */
        if (clt->mode >= COLLECT_PRIMARY &&
@@ -388,8 +386,7 @@ static int z_erofs_attach_page(struct z_erofs_collector *clt,
            z_erofs_try_inplace_io(clt, page))
                return 0;
 
-       ret = z_erofs_pagevec_enqueue(&clt->vector,
-                                     page, type, &occupied);
+       ret = z_erofs_pagevec_enqueue(&clt->vector, page, type);
        clt->cl->vcnt += (unsigned int)ret;
 
        return ret ? 0 : -EAGAIN;
@@ -1471,4 +1468,3 @@ const struct address_space_operations z_erofs_aops = {
        .readpage = z_erofs_readpage,
        .readahead = z_erofs_readahead,
 };
-
index 942ee69..3a008f1 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_FS_ZDATA_H
 #define __EROFS_FS_ZDATA_H
index efaf325..f68aea4 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2018-2019 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #include "internal.h"
 #include <asm/unaligned.h>
@@ -597,4 +596,3 @@ out:
        DBG_BUGON(err < 0 && err != -ENOMEM);
        return err;
 }
-
index 1d67cbd..dfd7fe0 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (C) 2018 HUAWEI, Inc.
  *             https://www.huawei.com/
- * Created by Gao Xiang <gaoxiang25@huawei.com>
  */
 #ifndef __EROFS_FS_ZPVEC_H
 #define __EROFS_FS_ZPVEC_H
@@ -107,10 +106,8 @@ static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
 
 static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
                                           struct page *page,
-                                          enum z_erofs_page_type type,
-                                          bool *occupied)
+                                          enum z_erofs_page_type type)
 {
-       *occupied = false;
        if (!ctor->next && type)
                if (ctor->index + 1 == ctor->nr)
                        return false;
@@ -125,7 +122,6 @@ static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
        /* should remind that collector->next never equal to 1, 2 */
        if (type == (uintptr_t)ctor->next) {
                ctor->next = page;
-               *occupied = true;
        }
        ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
        return true;
@@ -154,4 +150,3 @@ z_erofs_pagevec_dequeue(struct z_erofs_pagevec_ctor *ctor,
        return tagptr_unfold_ptr(t);
 }
 #endif
-
index 18594f1..f2bcdbe 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1360,6 +1360,10 @@ int begin_new_exec(struct linux_binprm * bprm)
        WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
        flush_signal_handlers(me, 0);
 
+       retval = set_cred_ucounts(bprm->cred);
+       if (retval < 0)
+               goto out_unlock;
+
        /*
         * install the new credentials for this executable
         */
@@ -1874,7 +1878,7 @@ static int do_execveat_common(int fd, struct filename *filename,
         * whether NPROC limit is still exceeded.
         */
        if ((current->flags & PF_NPROC_EXCEEDED) &&
-           atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
+           is_ucounts_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
                retval = -EAGAIN;
                goto out_ret;
        }
index 55efd3d..926eeb9 100644 (file)
@@ -735,6 +735,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
                __SetPageUptodate(page);
                error = huge_add_to_page_cache(page, mapping, index);
                if (unlikely(error)) {
+                       restore_reserve_on_error(h, &pseudo_vma, addr, page);
                        put_page(page);
                        mutex_unlock(&hugetlb_fault_mutex_table[hash]);
                        goto out;
@@ -1445,7 +1446,7 @@ static int get_hstate_idx(int page_size_log)
  * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
  */
 struct file *hugetlb_file_setup(const char *name, size_t size,
-                               vm_flags_t acctflag, struct user_struct **user,
+                               vm_flags_t acctflag, struct ucounts **ucounts,
                                int creat_flags, int page_size_log)
 {
        struct inode *inode;
@@ -1457,20 +1458,20 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        if (hstate_idx < 0)
                return ERR_PTR(-ENODEV);
 
-       *user = NULL;
+       *ucounts = NULL;
        mnt = hugetlbfs_vfsmount[hstate_idx];
        if (!mnt)
                return ERR_PTR(-ENOENT);
 
        if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
-               *user = current_user();
-               if (user_shm_lock(size, *user)) {
+               *ucounts = current_ucounts();
+               if (user_shm_lock(size, *ucounts)) {
                        task_lock(current);
                        pr_warn_once("%s (%d): Using mlock ulimits for SHM_HUGETLB is deprecated\n",
                                current->comm, current->pid);
                        task_unlock(current);
                } else {
-                       *user = NULL;
+                       *ucounts = NULL;
                        return ERR_PTR(-EPERM);
                }
        }
@@ -1497,9 +1498,9 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
 
        iput(inode);
 out:
-       if (*user) {
-               user_shm_unlock(size, *user);
-               *user = NULL;
+       if (*ucounts) {
+               user_shm_unlock(size, *ucounts);
+               *ucounts = NULL;
        }
        return file;
 }
index 7256146..0b6cd3b 100644 (file)
@@ -1011,12 +1011,42 @@ out:
 }
 EXPORT_SYMBOL(netfs_readpage);
 
-static void netfs_clear_thp(struct page *page)
+/**
+ * netfs_skip_page_read - prep a page for writing without reading first
+ * @page: page being prepared
+ * @pos: starting position for the write
+ * @len: length of write
+ *
+ * In some cases, write_begin doesn't need to read at all:
+ * - full page write
+ * - write that lies in a page that is completely beyond EOF
+ * - write that covers the the page from start to EOF or beyond it
+ *
+ * If any of these criteria are met, then zero out the unwritten parts
+ * of the page and return true. Otherwise, return false.
+ */
+static bool netfs_skip_page_read(struct page *page, loff_t pos, size_t len)
 {
-       unsigned int i;
+       struct inode *inode = page->mapping->host;
+       loff_t i_size = i_size_read(inode);
+       size_t offset = offset_in_thp(page, pos);
+
+       /* Full page write */
+       if (offset == 0 && len >= thp_size(page))
+               return true;
+
+       /* pos beyond last page in the file */
+       if (pos - offset >= i_size)
+               goto zero_out;
+
+       /* Write that covers from the start of the page to EOF or beyond */
+       if (offset == 0 && (pos + len) >= i_size)
+               goto zero_out;
 
-       for (i = 0; i < thp_nr_pages(page); i++)
-               clear_highpage(page + i);
+       return false;
+zero_out:
+       zero_user_segments(page, 0, offset, offset + len, thp_size(page));
+       return true;
 }
 
 /**
@@ -1024,7 +1054,7 @@ static void netfs_clear_thp(struct page *page)
  * @file: The file to read from
  * @mapping: The mapping to read from
  * @pos: File position at which the write will begin
- * @len: The length of the write in this page
+ * @len: The length of the write (may extend beyond the end of the page chosen)
  * @flags: AOP_* flags
  * @_page: Where to put the resultant page
  * @_fsdata: Place for the netfs to store a cookie
@@ -1061,8 +1091,6 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
        struct inode *inode = file_inode(file);
        unsigned int debug_index = 0;
        pgoff_t index = pos >> PAGE_SHIFT;
-       int pos_in_page = pos & ~PAGE_MASK;
-       loff_t size;
        int ret;
 
        DEFINE_READAHEAD(ractl, file, NULL, mapping, index);
@@ -1090,13 +1118,8 @@ retry:
         * within the cache granule containing the EOF, in which case we need
         * to preload the granule.
         */
-       size = i_size_read(inode);
        if (!ops->is_cache_enabled(inode) &&
-           ((pos_in_page == 0 && len == thp_size(page)) ||
-            (pos >= size) ||
-            (pos_in_page == 0 && (pos + len) >= size))) {
-               netfs_clear_thp(page);
-               SetPageUptodate(page);
+           netfs_skip_page_read(page, pos, len)) {
                netfs_stat(&netfs_n_rh_write_zskip);
                goto have_page_no_wait;
        }
index 303d714..68e8d61 100644 (file)
 /* /sys/fs/<nilfs>/ */
 static struct kset *nilfs_kset;
 
-#define NILFS_SHOW_TIME(time_t_val, buf) ({ \
-               struct tm res; \
-               int count = 0; \
-               time64_to_tm(time_t_val, 0, &res); \
-               res.tm_year += 1900; \
-               res.tm_mon += 1; \
-               count = scnprintf(buf, PAGE_SIZE, \
-                                   "%ld-%.2d-%.2d %.2d:%.2d:%.2d\n", \
-                                   res.tm_year, res.tm_mon, res.tm_mday, \
-                                   res.tm_hour, res.tm_min, res.tm_sec);\
-               count; \
-})
-
 #define NILFS_DEV_INT_GROUP_OPS(name, parent_name) \
 static ssize_t nilfs_##name##_attr_show(struct kobject *kobj, \
                                        struct attribute *attr, char *buf) \
@@ -576,7 +563,7 @@ nilfs_segctor_last_seg_write_time_show(struct nilfs_segctor_attr *attr,
        ctime = nilfs->ns_ctime;
        up_read(&nilfs->ns_segctor_sem);
 
-       return NILFS_SHOW_TIME(ctime, buf);
+       return sysfs_emit(buf, "%ptTs\n", &ctime);
 }
 
 static ssize_t
@@ -604,7 +591,7 @@ nilfs_segctor_last_nongc_write_time_show(struct nilfs_segctor_attr *attr,
        nongc_ctime = nilfs->ns_nongc_ctime;
        up_read(&nilfs->ns_segctor_sem);
 
-       return NILFS_SHOW_TIME(nongc_ctime, buf);
+       return sysfs_emit(buf, "%ptTs\n", &nongc_ctime);
 }
 
 static ssize_t
@@ -724,7 +711,7 @@ nilfs_superblock_sb_write_time_show(struct nilfs_superblock_attr *attr,
        sbwtime = nilfs->ns_sbwtime;
        up_read(&nilfs->ns_sem);
 
-       return NILFS_SHOW_TIME(sbwtime, buf);
+       return sysfs_emit(buf, "%ptTs\n", &sbwtime);
 }
 
 static ssize_t
@@ -1053,6 +1040,7 @@ void nilfs_sysfs_delete_device_group(struct the_nilfs *nilfs)
        nilfs_sysfs_delete_superblock_group(nilfs);
        nilfs_sysfs_delete_segctor_group(nilfs);
        kobject_del(&nilfs->ns_dev_kobj);
+       kobject_put(&nilfs->ns_dev_kobj);
        kfree(nilfs->ns_dev_subgroups);
 }
 
index be5b6d2..64864fb 100644 (file)
@@ -471,7 +471,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                                        info_type, fanotify_info_name(info),
                                        info->name_len, buf, count);
                if (ret < 0)
-                       return ret;
+                       goto out_close_fd;
 
                buf += ret;
                count -= ret;
@@ -519,7 +519,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                                        fanotify_event_object_fh(event),
                                        info_type, dot, dot_len, buf, count);
                if (ret < 0)
-                       return ret;
+                       goto out_close_fd;
 
                buf += ret;
                count -= ret;
index 7ec5917..ee0ce8c 100644 (file)
@@ -284,7 +284,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
                collect_sigign_sigcatch(p, &ignored, &caught);
                num_threads = get_nr_threads(p);
                rcu_read_lock();  /* FIXME: is this correct? */
-               qsize = atomic_read(&__task_cred(p)->user->sigpending);
+               qsize = get_ucounts_value(task_ucounts(p), UCOUNT_RLIMIT_SIGPENDING);
                rcu_read_unlock();
                qlim = task_rlimit(p, RLIMIT_SIGPENDING);
                unlock_task_sighand(p, &flags);
index 7118ebe..9cbd915 100644 (file)
@@ -2676,7 +2676,9 @@ out:
 #ifdef CONFIG_SECURITY
 static int proc_pid_attr_open(struct inode *inode, struct file *file)
 {
-       return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS);
+       file->private_data = NULL;
+       __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS);
+       return 0;
 }
 
 static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
index 8468bae..f32878d 100644 (file)
@@ -16,7 +16,7 @@ static int loadavg_proc_show(struct seq_file *m, void *v)
 
        get_avenrun(avnrun, FIXED_1/200, 0);
 
-       seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n",
+       seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %u/%d %d\n",
                LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]),
                LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]),
                LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]),
index f25e853..6561a06 100644 (file)
@@ -200,8 +200,8 @@ static int show_stat(struct seq_file *p, void *v)
                "\nctxt %llu\n"
                "btime %llu\n"
                "processes %lu\n"
-               "procs_running %lu\n"
-               "procs_blocked %lu\n",
+               "procs_running %u\n"
+               "procs_blocked %u\n",
                nr_context_switches(),
                (unsigned long long)boottime.tv_sec,
                total_forks,
index 4bb8a34..04ce58c 100644 (file)
@@ -8,15 +8,16 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include "../../block/blk.h"
 #include <linux/blkdev.h>
 #include <linux/string.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/pstore_blk.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/init_syscalls.h>
 #include <linux/mount.h>
-#include <linux/uio.h>
 
 static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE;
 module_param(kmsg_size, long, 0400);
@@ -57,27 +58,7 @@ MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require sto
 
 /*
  * blkdev - the block device to use for pstore storage
- *
- * Usually, this will be a partition of a block device.
- *
- * blkdev accepts the following variants:
- * 1) <hex_major><hex_minor> device number in hexadecimal representation,
- *    with no leading 0x, for example b302.
- * 2) /dev/<disk_name> represents the device number of disk
- * 3) /dev/<disk_name><decimal> represents the device number
- *    of partition - device number of disk plus the partition number
- * 4) /dev/<disk_name>p<decimal> - same as the above, that form is
- *    used when disk name of partitioned disk ends on a digit.
- * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
- *    unique id of a partition if the partition table provides it.
- *    The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
- *    partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
- *    filled hex representation of the 32-bit "NT disk signature", and PP
- *    is a zero-filled hex representation of the 1-based partition number.
- * 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
- *    a partition with a known unique id.
- * 7) <major>:<minor> major and minor number of the device separated by
- *    a colon.
+ * See Documentation/admin-guide/pstore-blk.rst for details.
  */
 static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV;
 module_param_string(blkdev, blkdev, 80, 0400);
@@ -88,14 +69,8 @@ MODULE_PARM_DESC(blkdev, "block device for pstore storage");
  * during the register/unregister functions.
  */
 static DEFINE_MUTEX(pstore_blk_lock);
-static struct block_device *psblk_bdev;
-static struct pstore_zone_info *pstore_zone_info;
-
-struct bdev_info {
-       dev_t devt;
-       sector_t nr_sects;
-       sector_t start_sect;
-};
+static struct file *psblk_file;
+static struct pstore_device_info *pstore_device_info;
 
 #define check_size(name, alignsize) ({                         \
        long _##name_ = (name);                                 \
@@ -108,57 +83,63 @@ struct bdev_info {
        _##name_;                                               \
 })
 
+#define verify_size(name, alignsize, enabled) {                        \
+       long _##name_;                                          \
+       if (enabled)                                            \
+               _##name_ = check_size(name, alignsize);         \
+       else                                                    \
+               _##name_ = 0;                                   \
+       /* Synchronize module parameters with resuls. */        \
+       name = _##name_ / 1024;                                 \
+       dev->zone.name = _##name_;                              \
+}
+
 static int __register_pstore_device(struct pstore_device_info *dev)
 {
        int ret;
 
        lockdep_assert_held(&pstore_blk_lock);
 
-       if (!dev || !dev->total_size || !dev->read || !dev->write)
+       if (!dev) {
+               pr_err("NULL device info\n");
+               return -EINVAL;
+       }
+       if (!dev->zone.total_size) {
+               pr_err("zero sized device\n");
                return -EINVAL;
+       }
+       if (!dev->zone.read) {
+               pr_err("no read handler for device\n");
+               return -EINVAL;
+       }
+       if (!dev->zone.write) {
+               pr_err("no write handler for device\n");
+               return -EINVAL;
+       }
 
        /* someone already registered before */
-       if (pstore_zone_info)
+       if (pstore_device_info)
                return -EBUSY;
 
-       pstore_zone_info = kzalloc(sizeof(struct pstore_zone_info), GFP_KERNEL);
-       if (!pstore_zone_info)
-               return -ENOMEM;
-
        /* zero means not limit on which backends to attempt to store. */
        if (!dev->flags)
                dev->flags = UINT_MAX;
 
-#define verify_size(name, alignsize, enabled) {                                \
-               long _##name_;                                          \
-               if (enabled)                                            \
-                       _##name_ = check_size(name, alignsize);         \
-               else                                                    \
-                       _##name_ = 0;                                   \
-               name = _##name_ / 1024;                                 \
-               pstore_zone_info->name = _##name_;                      \
-       }
-
+       /* Copy in module parameters. */
        verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG);
        verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG);
        verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE);
        verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE);
-#undef verify_size
-
-       pstore_zone_info->total_size = dev->total_size;
-       pstore_zone_info->max_reason = max_reason;
-       pstore_zone_info->read = dev->read;
-       pstore_zone_info->write = dev->write;
-       pstore_zone_info->erase = dev->erase;
-       pstore_zone_info->panic_write = dev->panic_write;
-       pstore_zone_info->name = KBUILD_MODNAME;
-       pstore_zone_info->owner = THIS_MODULE;
-
-       ret = register_pstore_zone(pstore_zone_info);
-       if (ret) {
-               kfree(pstore_zone_info);
-               pstore_zone_info = NULL;
-       }
+       dev->zone.max_reason = max_reason;
+
+       /* Initialize required zone ownership details. */
+       dev->zone.name = KBUILD_MODNAME;
+       dev->zone.owner = THIS_MODULE;
+
+       ret = register_pstore_zone(&dev->zone);
+       if (ret == 0)
+               pstore_device_info = dev;
+
        return ret;
 }
 /**
@@ -185,10 +166,9 @@ EXPORT_SYMBOL_GPL(register_pstore_device);
 static void __unregister_pstore_device(struct pstore_device_info *dev)
 {
        lockdep_assert_held(&pstore_blk_lock);
-       if (pstore_zone_info && pstore_zone_info->read == dev->read) {
-               unregister_pstore_zone(pstore_zone_info);
-               kfree(pstore_zone_info);
-               pstore_zone_info = NULL;
+       if (pstore_device_info && pstore_device_info == dev) {
+               unregister_pstore_zone(&dev->zone);
+               pstore_device_info = NULL;
        }
 }
 
@@ -205,204 +185,59 @@ void unregister_pstore_device(struct pstore_device_info *dev)
 }
 EXPORT_SYMBOL_GPL(unregister_pstore_device);
 
-/**
- * psblk_get_bdev() - open block device
- *
- * @holder:    Exclusive holder identifier
- * @info:      Information about bdev to fill in
- *
- * Return: pointer to block device on success and others on error.
- *
- * On success, the returned block_device has reference count of one.
- */
-static struct block_device *psblk_get_bdev(void *holder,
-                                          struct bdev_info *info)
-{
-       struct block_device *bdev = ERR_PTR(-ENODEV);
-       fmode_t mode = FMODE_READ | FMODE_WRITE;
-       sector_t nr_sects;
-
-       lockdep_assert_held(&pstore_blk_lock);
-
-       if (pstore_zone_info)
-               return ERR_PTR(-EBUSY);
-
-       if (!blkdev[0])
-               return ERR_PTR(-ENODEV);
-
-       if (holder)
-               mode |= FMODE_EXCL;
-       bdev = blkdev_get_by_path(blkdev, mode, holder);
-       if (IS_ERR(bdev)) {
-               dev_t devt;
-
-               devt = name_to_dev_t(blkdev);
-               if (devt == 0)
-                       return ERR_PTR(-ENODEV);
-               bdev = blkdev_get_by_dev(devt, mode, holder);
-               if (IS_ERR(bdev))
-                       return bdev;
-       }
-
-       nr_sects = bdev_nr_sectors(bdev);
-       if (!nr_sects) {
-               pr_err("not enough space for '%s'\n", blkdev);
-               blkdev_put(bdev, mode);
-               return ERR_PTR(-ENOSPC);
-       }
-
-       if (info) {
-               info->devt = bdev->bd_dev;
-               info->nr_sects = nr_sects;
-               info->start_sect = get_start_sect(bdev);
-       }
-
-       return bdev;
-}
-
-static void psblk_put_bdev(struct block_device *bdev, void *holder)
-{
-       fmode_t mode = FMODE_READ | FMODE_WRITE;
-
-       lockdep_assert_held(&pstore_blk_lock);
-
-       if (!bdev)
-               return;
-
-       if (holder)
-               mode |= FMODE_EXCL;
-       blkdev_put(bdev, mode);
-}
-
 static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos)
 {
-       struct block_device *bdev = psblk_bdev;
-       struct file file;
-       struct kiocb kiocb;
-       struct iov_iter iter;
-       struct kvec iov = {.iov_base = buf, .iov_len = bytes};
-
-       if (!bdev)
-               return -ENODEV;
-
-       memset(&file, 0, sizeof(struct file));
-       file.f_mapping = bdev->bd_inode->i_mapping;
-       file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
-       file.f_inode = bdev->bd_inode;
-       file_ra_state_init(&file.f_ra, file.f_mapping);
-
-       init_sync_kiocb(&kiocb, &file);
-       kiocb.ki_pos = pos;
-       iov_iter_kvec(&iter, READ, &iov, 1, bytes);
-
-       return generic_file_read_iter(&kiocb, &iter);
+       return kernel_read(psblk_file, buf, bytes, &pos);
 }
 
 static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes,
                loff_t pos)
 {
-       struct block_device *bdev = psblk_bdev;
-       struct iov_iter iter;
-       struct kiocb kiocb;
-       struct file file;
-       ssize_t ret;
-       struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes};
-
-       if (!bdev)
-               return -ENODEV;
-
        /* Console/Ftrace backend may handle buffer until flush dirty zones */
        if (in_interrupt() || irqs_disabled())
                return -EBUSY;
-
-       memset(&file, 0, sizeof(struct file));
-       file.f_mapping = bdev->bd_inode->i_mapping;
-       file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
-       file.f_inode = bdev->bd_inode;
-
-       init_sync_kiocb(&kiocb, &file);
-       kiocb.ki_pos = pos;
-       iov_iter_kvec(&iter, WRITE, &iov, 1, bytes);
-
-       inode_lock(bdev->bd_inode);
-       ret = generic_write_checks(&kiocb, &iter);
-       if (ret > 0)
-               ret = generic_perform_write(&file, &iter, pos);
-       inode_unlock(bdev->bd_inode);
-
-       if (likely(ret > 0)) {
-               const struct file_operations f_op = {.fsync = blkdev_fsync};
-
-               file.f_op = &f_op;
-               kiocb.ki_pos += ret;
-               ret = generic_write_sync(&kiocb, ret);
-       }
-       return ret;
+       return kernel_write(psblk_file, buf, bytes, &pos);
 }
 
 /*
  * This takes its configuration only from the module parameters now.
- * See psblk_get_bdev() and blkdev.
  */
-static int __register_pstore_blk(void)
+static int __register_pstore_blk(struct pstore_device_info *dev,
+                                const char *devpath)
 {
-       char bdev_name[BDEVNAME_SIZE];
-       struct block_device *bdev;
-       struct pstore_device_info dev;
-       struct bdev_info binfo;
-       void *holder = blkdev;
+       struct inode *inode;
        int ret = -ENODEV;
 
        lockdep_assert_held(&pstore_blk_lock);
 
-       /* hold bdev exclusively */
-       memset(&binfo, 0, sizeof(binfo));
-       bdev = psblk_get_bdev(holder, &binfo);
-       if (IS_ERR(bdev)) {
-               pr_err("failed to open '%s'!\n", blkdev);
-               return PTR_ERR(bdev);
+       psblk_file = filp_open(devpath, O_RDWR | O_DSYNC | O_NOATIME | O_EXCL, 0);
+       if (IS_ERR(psblk_file)) {
+               ret = PTR_ERR(psblk_file);
+               pr_err("failed to open '%s': %d!\n", devpath, ret);
+               goto err;
        }
 
-       /* only allow driver matching the @blkdev */
-       if (!binfo.devt) {
-               pr_debug("no major\n");
-               ret = -ENODEV;
-               goto err_put_bdev;
+       inode = file_inode(psblk_file);
+       if (!S_ISBLK(inode->i_mode)) {
+               pr_err("'%s' is not block device!\n", devpath);
+               goto err_fput;
        }
 
-       /* psblk_bdev must be assigned before register to pstore/blk */
-       psblk_bdev = bdev;
-
-       memset(&dev, 0, sizeof(dev));
-       dev.total_size = binfo.nr_sects << SECTOR_SHIFT;
-       dev.read = psblk_generic_blk_read;
-       dev.write = psblk_generic_blk_write;
+       inode = I_BDEV(psblk_file->f_mapping->host)->bd_inode;
+       dev->zone.total_size = i_size_read(inode);
 
-       ret = __register_pstore_device(&dev);
+       ret = __register_pstore_device(dev);
        if (ret)
-               goto err_put_bdev;
+               goto err_fput;
 
-       bdevname(bdev, bdev_name);
-       pr_info("attached %s (no dedicated panic_write!)\n", bdev_name);
        return 0;
 
-err_put_bdev:
-       psblk_bdev = NULL;
-       psblk_put_bdev(bdev, holder);
-       return ret;
-}
-
-static void __unregister_pstore_blk(unsigned int major)
-{
-       struct pstore_device_info dev = { .read = psblk_generic_blk_read };
-       void *holder = blkdev;
+err_fput:
+       fput(psblk_file);
+err:
+       psblk_file = NULL;
 
-       lockdep_assert_held(&pstore_blk_lock);
-       if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) {
-               __unregister_pstore_device(&dev);
-               psblk_put_bdev(psblk_bdev, holder);
-               psblk_bdev = NULL;
-       }
+       return ret;
 }
 
 /* get information of pstore/blk */
@@ -419,13 +254,93 @@ int pstore_blk_get_config(struct pstore_blk_config *info)
 }
 EXPORT_SYMBOL_GPL(pstore_blk_get_config);
 
+
+#ifndef MODULE
+static const char devname[] = "/dev/pstore-blk";
+static __init const char *early_boot_devpath(const char *initial_devname)
+{
+       /*
+        * During early boot the real root file system hasn't been
+        * mounted yet, and no device nodes are present yet. Use the
+        * same scheme to find the device that we use for mounting
+        * the root file system.
+        */
+       dev_t dev = name_to_dev_t(initial_devname);
+
+       if (!dev) {
+               pr_err("failed to resolve '%s'!\n", initial_devname);
+               return initial_devname;
+       }
+
+       init_unlink(devname);
+       init_mknod(devname, S_IFBLK | 0600, new_encode_dev(dev));
+
+       return devname;
+}
+#else
+static inline const char *early_boot_devpath(const char *initial_devname)
+{
+       return initial_devname;
+}
+#endif
+
+static int __init __best_effort_init(void)
+{
+       struct pstore_device_info *best_effort_dev;
+       int ret;
+
+       /* No best-effort mode requested. */
+       if (!best_effort)
+               return 0;
+
+       /* Reject an empty blkdev. */
+       if (!blkdev[0]) {
+               pr_err("blkdev empty with best_effort=Y\n");
+               return -EINVAL;
+       }
+
+       best_effort_dev = kzalloc(sizeof(*best_effort_dev), GFP_KERNEL);
+       if (!best_effort_dev)
+               return -ENOMEM;
+
+       best_effort_dev->zone.read = psblk_generic_blk_read;
+       best_effort_dev->zone.write = psblk_generic_blk_write;
+
+       ret = __register_pstore_blk(best_effort_dev,
+                                   early_boot_devpath(blkdev));
+       if (ret)
+               kfree(best_effort_dev);
+       else
+               pr_info("attached %s (%zu) (no dedicated panic_write!)\n",
+                       blkdev, best_effort_dev->zone.total_size);
+
+       return ret;
+}
+
+static void __exit __best_effort_exit(void)
+{
+       /*
+        * Currently, the only user of psblk_file is best_effort, so
+        * we can assume that pstore_device_info is associated with it.
+        * Once there are "real" blk devices, there will need to be a
+        * dedicated pstore_blk_info, etc.
+        */
+       if (psblk_file) {
+               struct pstore_device_info *dev = pstore_device_info;
+
+               __unregister_pstore_device(dev);
+               kfree(dev);
+               fput(psblk_file);
+               psblk_file = NULL;
+       }
+}
+
 static int __init pstore_blk_init(void)
 {
-       int ret = 0;
+       int ret;
 
        mutex_lock(&pstore_blk_lock);
-       if (!pstore_zone_info && best_effort && blkdev[0])
-               ret = __register_pstore_blk();
+       ret = __best_effort_init();
        mutex_unlock(&pstore_blk_lock);
 
        return ret;
@@ -435,15 +350,9 @@ late_initcall(pstore_blk_init);
 static void __exit pstore_blk_exit(void)
 {
        mutex_lock(&pstore_blk_lock);
-       if (psblk_bdev)
-               __unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev));
-       else {
-               struct pstore_device_info dev = { };
-
-               if (pstore_zone_info)
-                       dev.read = pstore_zone_info->read;
-               __unregister_pstore_device(&dev);
-       }
+       __best_effort_exit();
+       /* If we've been asked to unload, unregister any remaining device. */
+       __unregister_pstore_device(pstore_device_info);
        mutex_unlock(&pstore_blk_lock);
 }
 module_exit(pstore_blk_exit);
index 017db70..3d7a35d 100644 (file)
@@ -132,6 +132,7 @@ int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
                        return IO_ERROR;
                }
                PATH_LAST_POSITION(path)--;
+               break;
 
        case ITEM_FOUND:
                break;
index 14f9228..dd7a6c6 100644 (file)
@@ -337,7 +337,7 @@ out:
        return ret;
 }
 
-static inline long userfaultfd_get_blocking_state(unsigned int flags)
+static inline unsigned int userfaultfd_get_blocking_state(unsigned int flags)
 {
        if (flags & FAULT_FLAG_INTERRUPTIBLE)
                return TASK_INTERRUPTIBLE;
@@ -370,7 +370,7 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
        struct userfaultfd_wait_queue uwq;
        vm_fault_t ret = VM_FAULT_SIGBUS;
        bool must_wait;
-       long blocking_state;
+       unsigned int blocking_state;
 
        /*
         * We don't do userfault handling for the final child pid update.
index bbfea80..e0d5cdc 100644 (file)
@@ -366,7 +366,7 @@ xfs_ag_resv_alloc_extent(
                break;
        default:
                ASSERT(0);
-               /* fall through */
+               fallthrough;
        case XFS_AG_RESV_NONE:
                field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS :
                                       XFS_TRANS_SB_FDBLOCKS;
@@ -408,7 +408,7 @@ xfs_ag_resv_free_extent(
                break;
        default:
                ASSERT(0);
-               /* fall through */
+               fallthrough;
        case XFS_AG_RESV_NONE:
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len);
                return;
index 82b7cbb..af3d5f9 100644 (file)
@@ -3174,7 +3174,7 @@ xfs_alloc_vextent(
                }
                args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
                args->type = XFS_ALLOCTYPE_NEAR_BNO;
-               /* FALLTHROUGH */
+               fallthrough;
        case XFS_ALLOCTYPE_FIRST_AG:
                /*
                 * Rotate through the allocation groups looking for a winner.
index 83ac977..747ec77 100644 (file)
@@ -282,7 +282,7 @@ xfs_da3_node_read_verify(
                                                __this_address);
                                break;
                        }
-                       /* fall through */
+                       fallthrough;
                case XFS_DA_NODE_MAGIC:
                        fa = xfs_da3_node_verify(bp);
                        if (fa)
index 7a2f9b5..f96e847 100644 (file)
@@ -86,6 +86,7 @@ xchk_superblock(
        case -ENOSYS:
        case -EFBIG:
                error = -EFSCORRUPTED;
+               fallthrough;
        default:
                break;
        }
index b5ebf1d..77d5c4a 100644 (file)
@@ -271,7 +271,7 @@ xchk_bmap_iextent_xref(
        case XFS_DATA_FORK:
                if (xfs_is_reflink_inode(info->sc->ip))
                        break;
-               /* fall through */
+               fallthrough;
        case XFS_ATTR_FORK:
                xchk_xref_is_not_shared(info->sc, agbno,
                                irec->br_blockcount);
index a94bd81..bd11723 100644 (file)
@@ -44,7 +44,7 @@ __xchk_btree_process_error(
                /* Note the badness but don't abort. */
                sc->sm->sm_flags |= errflag;
                *error = 0;
-               /* fall through */
+               fallthrough;
        default:
                if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
                        trace_xchk_ifork_btree_op_error(sc, cur, level,
index be38c96..6cc9229 100644 (file)
@@ -83,7 +83,7 @@ __xchk_process_error(
                /* Note the badness but don't abort. */
                sc->sm->sm_flags |= errflag;
                *error = 0;
-               /* fall through */
+               fallthrough;
        default:
                trace_xchk_op_error(sc, agno, bno, *error,
                                ret_ip);
@@ -136,7 +136,7 @@ __xchk_fblock_process_error(
                /* Note the badness but don't abort. */
                sc->sm->sm_flags |= errflag;
                *error = 0;
-               /* fall through */
+               fallthrough;
        default:
                trace_xchk_file_op_error(sc, whichfork, offset, *error,
                                ret_ip);
@@ -696,7 +696,7 @@ xchk_get_inode(
                if (error)
                        return -ENOENT;
                error = -EFSCORRUPTED;
-               /* fall through */
+               fallthrough;
        default:
                trace_xchk_op_error(sc,
                                XFS_INO_TO_AGNO(mp, sc->sm->sm_ino),
index 653f328..9f0dbb4 100644 (file)
@@ -47,7 +47,7 @@ xchk_da_process_error(
                /* Note the badness but don't abort. */
                sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
                *error = 0;
-               /* fall through */
+               fallthrough;
        default:
                trace_xchk_file_op_error(sc, ds->dargs.whichfork,
                                xfs_dir2_da_to_db(ds->dargs.geo,
index c2857d8..b8202dd 100644 (file)
@@ -947,7 +947,7 @@ xrep_ino_dqattach(
                        xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP);
                if (XFS_IS_PQUOTA_ON(sc->mp) && !sc->ip->i_pdquot)
                        xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ);
-               /* fall through */
+               fallthrough;
        case -ESRCH:
                error = 0;
                break;
index 0936f3a..2988efa 100644 (file)
@@ -286,7 +286,7 @@ xfs_bmap_count_blocks(
                 */
                *count += btblocks - 1;
 
-               /* fall through */
+               fallthrough;
        case XFS_DINODE_FMT_EXTENTS:
                *nextents = xfs_bmap_count_leaves(ifp, count);
                break;
index 465fd9e..1da59bd 100644 (file)
@@ -84,7 +84,7 @@ xfs_fs_encode_fh(
        case FILEID_INO32_GEN_PARENT:
                fid->i32.parent_ino = XFS_I(parent)->i_ino;
                fid->i32.parent_gen = parent->i_generation;
-               /*FALLTHRU*/
+               fallthrough;
        case FILEID_INO32_GEN:
                fid->i32.ino = XFS_I(inode)->i_ino;
                fid->i32.gen = inode->i_generation;
@@ -92,7 +92,7 @@ xfs_fs_encode_fh(
        case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
                fid64->parent_ino = XFS_I(parent)->i_ino;
                fid64->parent_gen = parent->i_generation;
-               /*FALLTHRU*/
+               fallthrough;
        case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
                fid64->ino = XFS_I(inode)->i_ino;
                fid64->gen = inode->i_generation;
index 396ef36..3c0749a 100644 (file)
@@ -863,7 +863,7 @@ xfs_break_layouts(
                        error = xfs_break_dax_layouts(inode, &retry);
                        if (error || retry)
                                break;
-                       /* fall through */
+                       fallthrough;
                case BREAK_WRITE:
                        error = xfs_break_leased_layouts(inode, iolock, &retry);
                        break;
index e4c2da4..1db99a9 100644 (file)
@@ -877,7 +877,7 @@ xfs_init_new_inode(
                        xfs_inode_inherit_flags(ip, pip);
                if (pip && (pip->i_diflags2 & XFS_DIFLAG2_ANY))
                        xfs_inode_inherit_flags2(ip, pip);
-               /* FALLTHROUGH */
+               fallthrough;
        case S_IFLNK:
                ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
                ip->i_df.if_bytes = 0;
index 1fe4c1f..7b1796c 100644 (file)
@@ -558,7 +558,7 @@ xfs_ioc_attrmulti_one(
        case ATTR_OP_REMOVE:
                value = NULL;
                *len = 0;
-               /* fall through */
+               fallthrough;
        case ATTR_OP_SET:
                error = mnt_want_write_file(parfilp);
                if (error)
@@ -1511,7 +1511,7 @@ xfs_ioc_getbmap(
        switch (cmd) {
        case XFS_IOC_GETBMAPA:
                bmx.bmv_iflags = BMV_IF_ATTRFORK;
-               /*FALLTHRU*/
+               fallthrough;
        case XFS_IOC_GETBMAP:
                /* struct getbmap is a strict subset of struct getbmapx. */
                recsize = sizeof(struct getbmap);
index d154f42..d8cd258 100644 (file)
@@ -1036,7 +1036,7 @@ retry:
                        prealloc_blocks = 0;
                        goto retry;
                }
-               /*FALLTHRU*/
+               fallthrough;
        default:
                goto out_unlock;
        }
index c19a82a..a002425 100644 (file)
@@ -2626,6 +2626,7 @@ xlog_covered_state(
        case XLOG_STATE_COVER_IDLE:
                if (iclogs_changed == 1)
                        return XLOG_STATE_COVER_IDLE;
+               fallthrough;
        case XLOG_STATE_COVER_NEED:
        case XLOG_STATE_COVER_NEED2:
                break;
index 9aced0a..d11d032 100644 (file)
@@ -294,7 +294,7 @@ xfs_trans_read_buf_map(
        default:
                if (tp && (tp->t_flags & XFS_TRANS_DIRTY))
                        xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
-               /* fall through */
+               fallthrough;
        case -ENOMEM:
        case -EAGAIN:
                return error;
index 888b6cf..bc45af5 100644 (file)
@@ -27,17 +27,13 @@ atomic_read(const atomic_t *v)
        instrument_atomic_read(v, sizeof(*v));
        return arch_atomic_read(v);
 }
-#define atomic_read atomic_read
 
-#if defined(arch_atomic_read_acquire)
 static __always_inline int
 atomic_read_acquire(const atomic_t *v)
 {
        instrument_atomic_read(v, sizeof(*v));
        return arch_atomic_read_acquire(v);
 }
-#define atomic_read_acquire atomic_read_acquire
-#endif
 
 static __always_inline void
 atomic_set(atomic_t *v, int i)
@@ -45,17 +41,13 @@ atomic_set(atomic_t *v, int i)
        instrument_atomic_write(v, sizeof(*v));
        arch_atomic_set(v, i);
 }
-#define atomic_set atomic_set
 
-#if defined(arch_atomic_set_release)
 static __always_inline void
 atomic_set_release(atomic_t *v, int i)
 {
        instrument_atomic_write(v, sizeof(*v));
        arch_atomic_set_release(v, i);
 }
-#define atomic_set_release atomic_set_release
-#endif
 
 static __always_inline void
 atomic_add(int i, atomic_t *v)
@@ -63,87 +55,62 @@ atomic_add(int i, atomic_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_add(i, v);
 }
-#define atomic_add atomic_add
 
-#if !defined(arch_atomic_add_return_relaxed) || defined(arch_atomic_add_return)
 static __always_inline int
 atomic_add_return(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return(i, v);
 }
-#define atomic_add_return atomic_add_return
-#endif
 
-#if defined(arch_atomic_add_return_acquire)
 static __always_inline int
 atomic_add_return_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_acquire(i, v);
 }
-#define atomic_add_return_acquire atomic_add_return_acquire
-#endif
 
-#if defined(arch_atomic_add_return_release)
 static __always_inline int
 atomic_add_return_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_release(i, v);
 }
-#define atomic_add_return_release atomic_add_return_release
-#endif
 
-#if defined(arch_atomic_add_return_relaxed)
 static __always_inline int
 atomic_add_return_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_return_relaxed(i, v);
 }
-#define atomic_add_return_relaxed atomic_add_return_relaxed
-#endif
 
-#if !defined(arch_atomic_fetch_add_relaxed) || defined(arch_atomic_fetch_add)
 static __always_inline int
 atomic_fetch_add(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add(i, v);
 }
-#define atomic_fetch_add atomic_fetch_add
-#endif
 
-#if defined(arch_atomic_fetch_add_acquire)
 static __always_inline int
 atomic_fetch_add_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_acquire(i, v);
 }
-#define atomic_fetch_add_acquire atomic_fetch_add_acquire
-#endif
 
-#if defined(arch_atomic_fetch_add_release)
 static __always_inline int
 atomic_fetch_add_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_release(i, v);
 }
-#define atomic_fetch_add_release atomic_fetch_add_release
-#endif
 
-#if defined(arch_atomic_fetch_add_relaxed)
 static __always_inline int
 atomic_fetch_add_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_relaxed(i, v);
 }
-#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
-#endif
 
 static __always_inline void
 atomic_sub(int i, atomic_t *v)
@@ -151,267 +118,188 @@ atomic_sub(int i, atomic_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_sub(i, v);
 }
-#define atomic_sub atomic_sub
 
-#if !defined(arch_atomic_sub_return_relaxed) || defined(arch_atomic_sub_return)
 static __always_inline int
 atomic_sub_return(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return(i, v);
 }
-#define atomic_sub_return atomic_sub_return
-#endif
 
-#if defined(arch_atomic_sub_return_acquire)
 static __always_inline int
 atomic_sub_return_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_acquire(i, v);
 }
-#define atomic_sub_return_acquire atomic_sub_return_acquire
-#endif
 
-#if defined(arch_atomic_sub_return_release)
 static __always_inline int
 atomic_sub_return_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_release(i, v);
 }
-#define atomic_sub_return_release atomic_sub_return_release
-#endif
 
-#if defined(arch_atomic_sub_return_relaxed)
 static __always_inline int
 atomic_sub_return_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_return_relaxed(i, v);
 }
-#define atomic_sub_return_relaxed atomic_sub_return_relaxed
-#endif
 
-#if !defined(arch_atomic_fetch_sub_relaxed) || defined(arch_atomic_fetch_sub)
 static __always_inline int
 atomic_fetch_sub(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub(i, v);
 }
-#define atomic_fetch_sub atomic_fetch_sub
-#endif
 
-#if defined(arch_atomic_fetch_sub_acquire)
 static __always_inline int
 atomic_fetch_sub_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_acquire(i, v);
 }
-#define atomic_fetch_sub_acquire atomic_fetch_sub_acquire
-#endif
 
-#if defined(arch_atomic_fetch_sub_release)
 static __always_inline int
 atomic_fetch_sub_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_release(i, v);
 }
-#define atomic_fetch_sub_release atomic_fetch_sub_release
-#endif
 
-#if defined(arch_atomic_fetch_sub_relaxed)
 static __always_inline int
 atomic_fetch_sub_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_sub_relaxed(i, v);
 }
-#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
-#endif
 
-#if defined(arch_atomic_inc)
 static __always_inline void
 atomic_inc(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_inc(v);
 }
-#define atomic_inc atomic_inc
-#endif
 
-#if defined(arch_atomic_inc_return)
 static __always_inline int
 atomic_inc_return(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return(v);
 }
-#define atomic_inc_return atomic_inc_return
-#endif
 
-#if defined(arch_atomic_inc_return_acquire)
 static __always_inline int
 atomic_inc_return_acquire(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_acquire(v);
 }
-#define atomic_inc_return_acquire atomic_inc_return_acquire
-#endif
 
-#if defined(arch_atomic_inc_return_release)
 static __always_inline int
 atomic_inc_return_release(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_release(v);
 }
-#define atomic_inc_return_release atomic_inc_return_release
-#endif
 
-#if defined(arch_atomic_inc_return_relaxed)
 static __always_inline int
 atomic_inc_return_relaxed(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_return_relaxed(v);
 }
-#define atomic_inc_return_relaxed atomic_inc_return_relaxed
-#endif
 
-#if defined(arch_atomic_fetch_inc)
 static __always_inline int
 atomic_fetch_inc(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc(v);
 }
-#define atomic_fetch_inc atomic_fetch_inc
-#endif
 
-#if defined(arch_atomic_fetch_inc_acquire)
 static __always_inline int
 atomic_fetch_inc_acquire(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_acquire(v);
 }
-#define atomic_fetch_inc_acquire atomic_fetch_inc_acquire
-#endif
 
-#if defined(arch_atomic_fetch_inc_release)
 static __always_inline int
 atomic_fetch_inc_release(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_release(v);
 }
-#define atomic_fetch_inc_release atomic_fetch_inc_release
-#endif
 
-#if defined(arch_atomic_fetch_inc_relaxed)
 static __always_inline int
 atomic_fetch_inc_relaxed(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_inc_relaxed(v);
 }
-#define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed
-#endif
 
-#if defined(arch_atomic_dec)
 static __always_inline void
 atomic_dec(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_dec(v);
 }
-#define atomic_dec atomic_dec
-#endif
 
-#if defined(arch_atomic_dec_return)
 static __always_inline int
 atomic_dec_return(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return(v);
 }
-#define atomic_dec_return atomic_dec_return
-#endif
 
-#if defined(arch_atomic_dec_return_acquire)
 static __always_inline int
 atomic_dec_return_acquire(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_acquire(v);
 }
-#define atomic_dec_return_acquire atomic_dec_return_acquire
-#endif
 
-#if defined(arch_atomic_dec_return_release)
 static __always_inline int
 atomic_dec_return_release(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_release(v);
 }
-#define atomic_dec_return_release atomic_dec_return_release
-#endif
 
-#if defined(arch_atomic_dec_return_relaxed)
 static __always_inline int
 atomic_dec_return_relaxed(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_return_relaxed(v);
 }
-#define atomic_dec_return_relaxed atomic_dec_return_relaxed
-#endif
 
-#if defined(arch_atomic_fetch_dec)
 static __always_inline int
 atomic_fetch_dec(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec(v);
 }
-#define atomic_fetch_dec atomic_fetch_dec
-#endif
 
-#if defined(arch_atomic_fetch_dec_acquire)
 static __always_inline int
 atomic_fetch_dec_acquire(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_acquire(v);
 }
-#define atomic_fetch_dec_acquire atomic_fetch_dec_acquire
-#endif
 
-#if defined(arch_atomic_fetch_dec_release)
 static __always_inline int
 atomic_fetch_dec_release(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_release(v);
 }
-#define atomic_fetch_dec_release atomic_fetch_dec_release
-#endif
 
-#if defined(arch_atomic_fetch_dec_relaxed)
 static __always_inline int
 atomic_fetch_dec_relaxed(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_dec_relaxed(v);
 }
-#define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed
-#endif
 
 static __always_inline void
 atomic_and(int i, atomic_t *v)
@@ -419,97 +307,69 @@ atomic_and(int i, atomic_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_and(i, v);
 }
-#define atomic_and atomic_and
 
-#if !defined(arch_atomic_fetch_and_relaxed) || defined(arch_atomic_fetch_and)
 static __always_inline int
 atomic_fetch_and(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and(i, v);
 }
-#define atomic_fetch_and atomic_fetch_and
-#endif
 
-#if defined(arch_atomic_fetch_and_acquire)
 static __always_inline int
 atomic_fetch_and_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_acquire(i, v);
 }
-#define atomic_fetch_and_acquire atomic_fetch_and_acquire
-#endif
 
-#if defined(arch_atomic_fetch_and_release)
 static __always_inline int
 atomic_fetch_and_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_release(i, v);
 }
-#define atomic_fetch_and_release atomic_fetch_and_release
-#endif
 
-#if defined(arch_atomic_fetch_and_relaxed)
 static __always_inline int
 atomic_fetch_and_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_and_relaxed(i, v);
 }
-#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
-#endif
 
-#if defined(arch_atomic_andnot)
 static __always_inline void
 atomic_andnot(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_andnot(i, v);
 }
-#define atomic_andnot atomic_andnot
-#endif
 
-#if defined(arch_atomic_fetch_andnot)
 static __always_inline int
 atomic_fetch_andnot(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot(i, v);
 }
-#define atomic_fetch_andnot atomic_fetch_andnot
-#endif
 
-#if defined(arch_atomic_fetch_andnot_acquire)
 static __always_inline int
 atomic_fetch_andnot_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_acquire(i, v);
 }
-#define atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire
-#endif
 
-#if defined(arch_atomic_fetch_andnot_release)
 static __always_inline int
 atomic_fetch_andnot_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_release(i, v);
 }
-#define atomic_fetch_andnot_release atomic_fetch_andnot_release
-#endif
 
-#if defined(arch_atomic_fetch_andnot_relaxed)
 static __always_inline int
 atomic_fetch_andnot_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_andnot_relaxed(i, v);
 }
-#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed
-#endif
 
 static __always_inline void
 atomic_or(int i, atomic_t *v)
@@ -517,47 +377,34 @@ atomic_or(int i, atomic_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_or(i, v);
 }
-#define atomic_or atomic_or
 
-#if !defined(arch_atomic_fetch_or_relaxed) || defined(arch_atomic_fetch_or)
 static __always_inline int
 atomic_fetch_or(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or(i, v);
 }
-#define atomic_fetch_or atomic_fetch_or
-#endif
 
-#if defined(arch_atomic_fetch_or_acquire)
 static __always_inline int
 atomic_fetch_or_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_acquire(i, v);
 }
-#define atomic_fetch_or_acquire atomic_fetch_or_acquire
-#endif
 
-#if defined(arch_atomic_fetch_or_release)
 static __always_inline int
 atomic_fetch_or_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_release(i, v);
 }
-#define atomic_fetch_or_release atomic_fetch_or_release
-#endif
 
-#if defined(arch_atomic_fetch_or_relaxed)
 static __always_inline int
 atomic_fetch_or_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_or_relaxed(i, v);
 }
-#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed
-#endif
 
 static __always_inline void
 atomic_xor(int i, atomic_t *v)
@@ -565,129 +412,91 @@ atomic_xor(int i, atomic_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic_xor(i, v);
 }
-#define atomic_xor atomic_xor
 
-#if !defined(arch_atomic_fetch_xor_relaxed) || defined(arch_atomic_fetch_xor)
 static __always_inline int
 atomic_fetch_xor(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor(i, v);
 }
-#define atomic_fetch_xor atomic_fetch_xor
-#endif
 
-#if defined(arch_atomic_fetch_xor_acquire)
 static __always_inline int
 atomic_fetch_xor_acquire(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_acquire(i, v);
 }
-#define atomic_fetch_xor_acquire atomic_fetch_xor_acquire
-#endif
 
-#if defined(arch_atomic_fetch_xor_release)
 static __always_inline int
 atomic_fetch_xor_release(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_release(i, v);
 }
-#define atomic_fetch_xor_release atomic_fetch_xor_release
-#endif
 
-#if defined(arch_atomic_fetch_xor_relaxed)
 static __always_inline int
 atomic_fetch_xor_relaxed(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_xor_relaxed(i, v);
 }
-#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
-#endif
 
-#if !defined(arch_atomic_xchg_relaxed) || defined(arch_atomic_xchg)
 static __always_inline int
 atomic_xchg(atomic_t *v, int i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg(v, i);
 }
-#define atomic_xchg atomic_xchg
-#endif
 
-#if defined(arch_atomic_xchg_acquire)
 static __always_inline int
 atomic_xchg_acquire(atomic_t *v, int i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_acquire(v, i);
 }
-#define atomic_xchg_acquire atomic_xchg_acquire
-#endif
 
-#if defined(arch_atomic_xchg_release)
 static __always_inline int
 atomic_xchg_release(atomic_t *v, int i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_release(v, i);
 }
-#define atomic_xchg_release atomic_xchg_release
-#endif
 
-#if defined(arch_atomic_xchg_relaxed)
 static __always_inline int
 atomic_xchg_relaxed(atomic_t *v, int i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_xchg_relaxed(v, i);
 }
-#define atomic_xchg_relaxed atomic_xchg_relaxed
-#endif
 
-#if !defined(arch_atomic_cmpxchg_relaxed) || defined(arch_atomic_cmpxchg)
 static __always_inline int
 atomic_cmpxchg(atomic_t *v, int old, int new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg(v, old, new);
 }
-#define atomic_cmpxchg atomic_cmpxchg
-#endif
 
-#if defined(arch_atomic_cmpxchg_acquire)
 static __always_inline int
 atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_acquire(v, old, new);
 }
-#define atomic_cmpxchg_acquire atomic_cmpxchg_acquire
-#endif
 
-#if defined(arch_atomic_cmpxchg_release)
 static __always_inline int
 atomic_cmpxchg_release(atomic_t *v, int old, int new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_release(v, old, new);
 }
-#define atomic_cmpxchg_release atomic_cmpxchg_release
-#endif
 
-#if defined(arch_atomic_cmpxchg_relaxed)
 static __always_inline int
 atomic_cmpxchg_relaxed(atomic_t *v, int old, int new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_cmpxchg_relaxed(v, old, new);
 }
-#define atomic_cmpxchg_relaxed atomic_cmpxchg_relaxed
-#endif
 
-#if defined(arch_atomic_try_cmpxchg)
 static __always_inline bool
 atomic_try_cmpxchg(atomic_t *v, int *old, int new)
 {
@@ -695,10 +504,7 @@ atomic_try_cmpxchg(atomic_t *v, int *old, int new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg(v, old, new);
 }
-#define atomic_try_cmpxchg atomic_try_cmpxchg
-#endif
 
-#if defined(arch_atomic_try_cmpxchg_acquire)
 static __always_inline bool
 atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
 {
@@ -706,10 +512,7 @@ atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_acquire(v, old, new);
 }
-#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg_acquire
-#endif
 
-#if defined(arch_atomic_try_cmpxchg_release)
 static __always_inline bool
 atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
 {
@@ -717,10 +520,7 @@ atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_release(v, old, new);
 }
-#define atomic_try_cmpxchg_release atomic_try_cmpxchg_release
-#endif
 
-#if defined(arch_atomic_try_cmpxchg_relaxed)
 static __always_inline bool
 atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
 {
@@ -728,108 +528,76 @@ atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic_try_cmpxchg_relaxed(v, old, new);
 }
-#define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg_relaxed
-#endif
 
-#if defined(arch_atomic_sub_and_test)
 static __always_inline bool
 atomic_sub_and_test(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_sub_and_test(i, v);
 }
-#define atomic_sub_and_test atomic_sub_and_test
-#endif
 
-#if defined(arch_atomic_dec_and_test)
 static __always_inline bool
 atomic_dec_and_test(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_and_test(v);
 }
-#define atomic_dec_and_test atomic_dec_and_test
-#endif
 
-#if defined(arch_atomic_inc_and_test)
 static __always_inline bool
 atomic_inc_and_test(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_and_test(v);
 }
-#define atomic_inc_and_test atomic_inc_and_test
-#endif
 
-#if defined(arch_atomic_add_negative)
 static __always_inline bool
 atomic_add_negative(int i, atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_negative(i, v);
 }
-#define atomic_add_negative atomic_add_negative
-#endif
 
-#if defined(arch_atomic_fetch_add_unless)
 static __always_inline int
 atomic_fetch_add_unless(atomic_t *v, int a, int u)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_fetch_add_unless(v, a, u);
 }
-#define atomic_fetch_add_unless atomic_fetch_add_unless
-#endif
 
-#if defined(arch_atomic_add_unless)
 static __always_inline bool
 atomic_add_unless(atomic_t *v, int a, int u)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_add_unless(v, a, u);
 }
-#define atomic_add_unless atomic_add_unless
-#endif
 
-#if defined(arch_atomic_inc_not_zero)
 static __always_inline bool
 atomic_inc_not_zero(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_not_zero(v);
 }
-#define atomic_inc_not_zero atomic_inc_not_zero
-#endif
 
-#if defined(arch_atomic_inc_unless_negative)
 static __always_inline bool
 atomic_inc_unless_negative(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_inc_unless_negative(v);
 }
-#define atomic_inc_unless_negative atomic_inc_unless_negative
-#endif
 
-#if defined(arch_atomic_dec_unless_positive)
 static __always_inline bool
 atomic_dec_unless_positive(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_unless_positive(v);
 }
-#define atomic_dec_unless_positive atomic_dec_unless_positive
-#endif
 
-#if defined(arch_atomic_dec_if_positive)
 static __always_inline int
 atomic_dec_if_positive(atomic_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic_dec_if_positive(v);
 }
-#define atomic_dec_if_positive atomic_dec_if_positive
-#endif
 
 static __always_inline s64
 atomic64_read(const atomic64_t *v)
@@ -837,17 +605,13 @@ atomic64_read(const atomic64_t *v)
        instrument_atomic_read(v, sizeof(*v));
        return arch_atomic64_read(v);
 }
-#define atomic64_read atomic64_read
 
-#if defined(arch_atomic64_read_acquire)
 static __always_inline s64
 atomic64_read_acquire(const atomic64_t *v)
 {
        instrument_atomic_read(v, sizeof(*v));
        return arch_atomic64_read_acquire(v);
 }
-#define atomic64_read_acquire atomic64_read_acquire
-#endif
 
 static __always_inline void
 atomic64_set(atomic64_t *v, s64 i)
@@ -855,17 +619,13 @@ atomic64_set(atomic64_t *v, s64 i)
        instrument_atomic_write(v, sizeof(*v));
        arch_atomic64_set(v, i);
 }
-#define atomic64_set atomic64_set
 
-#if defined(arch_atomic64_set_release)
 static __always_inline void
 atomic64_set_release(atomic64_t *v, s64 i)
 {
        instrument_atomic_write(v, sizeof(*v));
        arch_atomic64_set_release(v, i);
 }
-#define atomic64_set_release atomic64_set_release
-#endif
 
 static __always_inline void
 atomic64_add(s64 i, atomic64_t *v)
@@ -873,87 +633,62 @@ atomic64_add(s64 i, atomic64_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_add(i, v);
 }
-#define atomic64_add atomic64_add
 
-#if !defined(arch_atomic64_add_return_relaxed) || defined(arch_atomic64_add_return)
 static __always_inline s64
 atomic64_add_return(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return(i, v);
 }
-#define atomic64_add_return atomic64_add_return
-#endif
 
-#if defined(arch_atomic64_add_return_acquire)
 static __always_inline s64
 atomic64_add_return_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_acquire(i, v);
 }
-#define atomic64_add_return_acquire atomic64_add_return_acquire
-#endif
 
-#if defined(arch_atomic64_add_return_release)
 static __always_inline s64
 atomic64_add_return_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_release(i, v);
 }
-#define atomic64_add_return_release atomic64_add_return_release
-#endif
 
-#if defined(arch_atomic64_add_return_relaxed)
 static __always_inline s64
 atomic64_add_return_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_return_relaxed(i, v);
 }
-#define atomic64_add_return_relaxed atomic64_add_return_relaxed
-#endif
 
-#if !defined(arch_atomic64_fetch_add_relaxed) || defined(arch_atomic64_fetch_add)
 static __always_inline s64
 atomic64_fetch_add(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add(i, v);
 }
-#define atomic64_fetch_add atomic64_fetch_add
-#endif
 
-#if defined(arch_atomic64_fetch_add_acquire)
 static __always_inline s64
 atomic64_fetch_add_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_acquire(i, v);
 }
-#define atomic64_fetch_add_acquire atomic64_fetch_add_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_add_release)
 static __always_inline s64
 atomic64_fetch_add_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_release(i, v);
 }
-#define atomic64_fetch_add_release atomic64_fetch_add_release
-#endif
 
-#if defined(arch_atomic64_fetch_add_relaxed)
 static __always_inline s64
 atomic64_fetch_add_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_relaxed(i, v);
 }
-#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
-#endif
 
 static __always_inline void
 atomic64_sub(s64 i, atomic64_t *v)
@@ -961,267 +696,188 @@ atomic64_sub(s64 i, atomic64_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_sub(i, v);
 }
-#define atomic64_sub atomic64_sub
 
-#if !defined(arch_atomic64_sub_return_relaxed) || defined(arch_atomic64_sub_return)
 static __always_inline s64
 atomic64_sub_return(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return(i, v);
 }
-#define atomic64_sub_return atomic64_sub_return
-#endif
 
-#if defined(arch_atomic64_sub_return_acquire)
 static __always_inline s64
 atomic64_sub_return_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_acquire(i, v);
 }
-#define atomic64_sub_return_acquire atomic64_sub_return_acquire
-#endif
 
-#if defined(arch_atomic64_sub_return_release)
 static __always_inline s64
 atomic64_sub_return_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_release(i, v);
 }
-#define atomic64_sub_return_release atomic64_sub_return_release
-#endif
 
-#if defined(arch_atomic64_sub_return_relaxed)
 static __always_inline s64
 atomic64_sub_return_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_return_relaxed(i, v);
 }
-#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
-#endif
 
-#if !defined(arch_atomic64_fetch_sub_relaxed) || defined(arch_atomic64_fetch_sub)
 static __always_inline s64
 atomic64_fetch_sub(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub(i, v);
 }
-#define atomic64_fetch_sub atomic64_fetch_sub
-#endif
 
-#if defined(arch_atomic64_fetch_sub_acquire)
 static __always_inline s64
 atomic64_fetch_sub_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_acquire(i, v);
 }
-#define atomic64_fetch_sub_acquire atomic64_fetch_sub_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_sub_release)
 static __always_inline s64
 atomic64_fetch_sub_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_release(i, v);
 }
-#define atomic64_fetch_sub_release atomic64_fetch_sub_release
-#endif
 
-#if defined(arch_atomic64_fetch_sub_relaxed)
 static __always_inline s64
 atomic64_fetch_sub_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_sub_relaxed(i, v);
 }
-#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
-#endif
 
-#if defined(arch_atomic64_inc)
 static __always_inline void
 atomic64_inc(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_inc(v);
 }
-#define atomic64_inc atomic64_inc
-#endif
 
-#if defined(arch_atomic64_inc_return)
 static __always_inline s64
 atomic64_inc_return(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return(v);
 }
-#define atomic64_inc_return atomic64_inc_return
-#endif
 
-#if defined(arch_atomic64_inc_return_acquire)
 static __always_inline s64
 atomic64_inc_return_acquire(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_acquire(v);
 }
-#define atomic64_inc_return_acquire atomic64_inc_return_acquire
-#endif
 
-#if defined(arch_atomic64_inc_return_release)
 static __always_inline s64
 atomic64_inc_return_release(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_release(v);
 }
-#define atomic64_inc_return_release atomic64_inc_return_release
-#endif
 
-#if defined(arch_atomic64_inc_return_relaxed)
 static __always_inline s64
 atomic64_inc_return_relaxed(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_return_relaxed(v);
 }
-#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
-#endif
 
-#if defined(arch_atomic64_fetch_inc)
 static __always_inline s64
 atomic64_fetch_inc(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc(v);
 }
-#define atomic64_fetch_inc atomic64_fetch_inc
-#endif
 
-#if defined(arch_atomic64_fetch_inc_acquire)
 static __always_inline s64
 atomic64_fetch_inc_acquire(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_acquire(v);
 }
-#define atomic64_fetch_inc_acquire atomic64_fetch_inc_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_inc_release)
 static __always_inline s64
 atomic64_fetch_inc_release(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_release(v);
 }
-#define atomic64_fetch_inc_release atomic64_fetch_inc_release
-#endif
 
-#if defined(arch_atomic64_fetch_inc_relaxed)
 static __always_inline s64
 atomic64_fetch_inc_relaxed(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_inc_relaxed(v);
 }
-#define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed
-#endif
 
-#if defined(arch_atomic64_dec)
 static __always_inline void
 atomic64_dec(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_dec(v);
 }
-#define atomic64_dec atomic64_dec
-#endif
 
-#if defined(arch_atomic64_dec_return)
 static __always_inline s64
 atomic64_dec_return(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return(v);
 }
-#define atomic64_dec_return atomic64_dec_return
-#endif
 
-#if defined(arch_atomic64_dec_return_acquire)
 static __always_inline s64
 atomic64_dec_return_acquire(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_acquire(v);
 }
-#define atomic64_dec_return_acquire atomic64_dec_return_acquire
-#endif
 
-#if defined(arch_atomic64_dec_return_release)
 static __always_inline s64
 atomic64_dec_return_release(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_release(v);
 }
-#define atomic64_dec_return_release atomic64_dec_return_release
-#endif
 
-#if defined(arch_atomic64_dec_return_relaxed)
 static __always_inline s64
 atomic64_dec_return_relaxed(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_return_relaxed(v);
 }
-#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
-#endif
 
-#if defined(arch_atomic64_fetch_dec)
 static __always_inline s64
 atomic64_fetch_dec(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec(v);
 }
-#define atomic64_fetch_dec atomic64_fetch_dec
-#endif
 
-#if defined(arch_atomic64_fetch_dec_acquire)
 static __always_inline s64
 atomic64_fetch_dec_acquire(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_acquire(v);
 }
-#define atomic64_fetch_dec_acquire atomic64_fetch_dec_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_dec_release)
 static __always_inline s64
 atomic64_fetch_dec_release(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_release(v);
 }
-#define atomic64_fetch_dec_release atomic64_fetch_dec_release
-#endif
 
-#if defined(arch_atomic64_fetch_dec_relaxed)
 static __always_inline s64
 atomic64_fetch_dec_relaxed(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_dec_relaxed(v);
 }
-#define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed
-#endif
 
 static __always_inline void
 atomic64_and(s64 i, atomic64_t *v)
@@ -1229,97 +885,69 @@ atomic64_and(s64 i, atomic64_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_and(i, v);
 }
-#define atomic64_and atomic64_and
 
-#if !defined(arch_atomic64_fetch_and_relaxed) || defined(arch_atomic64_fetch_and)
 static __always_inline s64
 atomic64_fetch_and(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and(i, v);
 }
-#define atomic64_fetch_and atomic64_fetch_and
-#endif
 
-#if defined(arch_atomic64_fetch_and_acquire)
 static __always_inline s64
 atomic64_fetch_and_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_acquire(i, v);
 }
-#define atomic64_fetch_and_acquire atomic64_fetch_and_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_and_release)
 static __always_inline s64
 atomic64_fetch_and_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_release(i, v);
 }
-#define atomic64_fetch_and_release atomic64_fetch_and_release
-#endif
 
-#if defined(arch_atomic64_fetch_and_relaxed)
 static __always_inline s64
 atomic64_fetch_and_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_and_relaxed(i, v);
 }
-#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
-#endif
 
-#if defined(arch_atomic64_andnot)
 static __always_inline void
 atomic64_andnot(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_andnot(i, v);
 }
-#define atomic64_andnot atomic64_andnot
-#endif
 
-#if defined(arch_atomic64_fetch_andnot)
 static __always_inline s64
 atomic64_fetch_andnot(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot(i, v);
 }
-#define atomic64_fetch_andnot atomic64_fetch_andnot
-#endif
 
-#if defined(arch_atomic64_fetch_andnot_acquire)
 static __always_inline s64
 atomic64_fetch_andnot_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_acquire(i, v);
 }
-#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_andnot_release)
 static __always_inline s64
 atomic64_fetch_andnot_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_release(i, v);
 }
-#define atomic64_fetch_andnot_release atomic64_fetch_andnot_release
-#endif
 
-#if defined(arch_atomic64_fetch_andnot_relaxed)
 static __always_inline s64
 atomic64_fetch_andnot_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_andnot_relaxed(i, v);
 }
-#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed
-#endif
 
 static __always_inline void
 atomic64_or(s64 i, atomic64_t *v)
@@ -1327,47 +955,34 @@ atomic64_or(s64 i, atomic64_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_or(i, v);
 }
-#define atomic64_or atomic64_or
 
-#if !defined(arch_atomic64_fetch_or_relaxed) || defined(arch_atomic64_fetch_or)
 static __always_inline s64
 atomic64_fetch_or(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or(i, v);
 }
-#define atomic64_fetch_or atomic64_fetch_or
-#endif
 
-#if defined(arch_atomic64_fetch_or_acquire)
 static __always_inline s64
 atomic64_fetch_or_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_acquire(i, v);
 }
-#define atomic64_fetch_or_acquire atomic64_fetch_or_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_or_release)
 static __always_inline s64
 atomic64_fetch_or_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_release(i, v);
 }
-#define atomic64_fetch_or_release atomic64_fetch_or_release
-#endif
 
-#if defined(arch_atomic64_fetch_or_relaxed)
 static __always_inline s64
 atomic64_fetch_or_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_or_relaxed(i, v);
 }
-#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed
-#endif
 
 static __always_inline void
 atomic64_xor(s64 i, atomic64_t *v)
@@ -1375,129 +990,91 @@ atomic64_xor(s64 i, atomic64_t *v)
        instrument_atomic_read_write(v, sizeof(*v));
        arch_atomic64_xor(i, v);
 }
-#define atomic64_xor atomic64_xor
 
-#if !defined(arch_atomic64_fetch_xor_relaxed) || defined(arch_atomic64_fetch_xor)
 static __always_inline s64
 atomic64_fetch_xor(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor(i, v);
 }
-#define atomic64_fetch_xor atomic64_fetch_xor
-#endif
 
-#if defined(arch_atomic64_fetch_xor_acquire)
 static __always_inline s64
 atomic64_fetch_xor_acquire(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_acquire(i, v);
 }
-#define atomic64_fetch_xor_acquire atomic64_fetch_xor_acquire
-#endif
 
-#if defined(arch_atomic64_fetch_xor_release)
 static __always_inline s64
 atomic64_fetch_xor_release(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_release(i, v);
 }
-#define atomic64_fetch_xor_release atomic64_fetch_xor_release
-#endif
 
-#if defined(arch_atomic64_fetch_xor_relaxed)
 static __always_inline s64
 atomic64_fetch_xor_relaxed(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_xor_relaxed(i, v);
 }
-#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
-#endif
 
-#if !defined(arch_atomic64_xchg_relaxed) || defined(arch_atomic64_xchg)
 static __always_inline s64
 atomic64_xchg(atomic64_t *v, s64 i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg(v, i);
 }
-#define atomic64_xchg atomic64_xchg
-#endif
 
-#if defined(arch_atomic64_xchg_acquire)
 static __always_inline s64
 atomic64_xchg_acquire(atomic64_t *v, s64 i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_acquire(v, i);
 }
-#define atomic64_xchg_acquire atomic64_xchg_acquire
-#endif
 
-#if defined(arch_atomic64_xchg_release)
 static __always_inline s64
 atomic64_xchg_release(atomic64_t *v, s64 i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_release(v, i);
 }
-#define atomic64_xchg_release atomic64_xchg_release
-#endif
 
-#if defined(arch_atomic64_xchg_relaxed)
 static __always_inline s64
 atomic64_xchg_relaxed(atomic64_t *v, s64 i)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_xchg_relaxed(v, i);
 }
-#define atomic64_xchg_relaxed atomic64_xchg_relaxed
-#endif
 
-#if !defined(arch_atomic64_cmpxchg_relaxed) || defined(arch_atomic64_cmpxchg)
 static __always_inline s64
 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg(v, old, new);
 }
-#define atomic64_cmpxchg atomic64_cmpxchg
-#endif
 
-#if defined(arch_atomic64_cmpxchg_acquire)
 static __always_inline s64
 atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_acquire(v, old, new);
 }
-#define atomic64_cmpxchg_acquire atomic64_cmpxchg_acquire
-#endif
 
-#if defined(arch_atomic64_cmpxchg_release)
 static __always_inline s64
 atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_release(v, old, new);
 }
-#define atomic64_cmpxchg_release atomic64_cmpxchg_release
-#endif
 
-#if defined(arch_atomic64_cmpxchg_relaxed)
 static __always_inline s64
 atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_cmpxchg_relaxed(v, old, new);
 }
-#define atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed
-#endif
 
-#if defined(arch_atomic64_try_cmpxchg)
 static __always_inline bool
 atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
 {
@@ -1505,10 +1082,7 @@ atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg(v, old, new);
 }
-#define atomic64_try_cmpxchg atomic64_try_cmpxchg
-#endif
 
-#if defined(arch_atomic64_try_cmpxchg_acquire)
 static __always_inline bool
 atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
 {
@@ -1516,10 +1090,7 @@ atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_acquire(v, old, new);
 }
-#define atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg_acquire
-#endif
 
-#if defined(arch_atomic64_try_cmpxchg_release)
 static __always_inline bool
 atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
 {
@@ -1527,10 +1098,7 @@ atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_release(v, old, new);
 }
-#define atomic64_try_cmpxchg_release atomic64_try_cmpxchg_release
-#endif
 
-#if defined(arch_atomic64_try_cmpxchg_relaxed)
 static __always_inline bool
 atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
 {
@@ -1538,218 +1106,161 @@ atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
        instrument_atomic_read_write(old, sizeof(*old));
        return arch_atomic64_try_cmpxchg_relaxed(v, old, new);
 }
-#define atomic64_try_cmpxchg_relaxed atomic64_try_cmpxchg_relaxed
-#endif
 
-#if defined(arch_atomic64_sub_and_test)
 static __always_inline bool
 atomic64_sub_and_test(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_sub_and_test(i, v);
 }
-#define atomic64_sub_and_test atomic64_sub_and_test
-#endif
 
-#if defined(arch_atomic64_dec_and_test)
 static __always_inline bool
 atomic64_dec_and_test(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_and_test(v);
 }
-#define atomic64_dec_and_test atomic64_dec_and_test
-#endif
 
-#if defined(arch_atomic64_inc_and_test)
 static __always_inline bool
 atomic64_inc_and_test(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_and_test(v);
 }
-#define atomic64_inc_and_test atomic64_inc_and_test
-#endif
 
-#if defined(arch_atomic64_add_negative)
 static __always_inline bool
 atomic64_add_negative(s64 i, atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_negative(i, v);
 }
-#define atomic64_add_negative atomic64_add_negative
-#endif
 
-#if defined(arch_atomic64_fetch_add_unless)
 static __always_inline s64
 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_fetch_add_unless(v, a, u);
 }
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
-#endif
 
-#if defined(arch_atomic64_add_unless)
 static __always_inline bool
 atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_add_unless(v, a, u);
 }
-#define atomic64_add_unless atomic64_add_unless
-#endif
 
-#if defined(arch_atomic64_inc_not_zero)
 static __always_inline bool
 atomic64_inc_not_zero(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_not_zero(v);
 }
-#define atomic64_inc_not_zero atomic64_inc_not_zero
-#endif
 
-#if defined(arch_atomic64_inc_unless_negative)
 static __always_inline bool
 atomic64_inc_unless_negative(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_inc_unless_negative(v);
 }
-#define atomic64_inc_unless_negative atomic64_inc_unless_negative
-#endif
 
-#if defined(arch_atomic64_dec_unless_positive)
 static __always_inline bool
 atomic64_dec_unless_positive(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_unless_positive(v);
 }
-#define atomic64_dec_unless_positive atomic64_dec_unless_positive
-#endif
 
-#if defined(arch_atomic64_dec_if_positive)
 static __always_inline s64
 atomic64_dec_if_positive(atomic64_t *v)
 {
        instrument_atomic_read_write(v, sizeof(*v));
        return arch_atomic64_dec_if_positive(v);
 }
-#define atomic64_dec_if_positive atomic64_dec_if_positive
-#endif
 
-#if !defined(arch_xchg_relaxed) || defined(arch_xchg)
 #define xchg(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_xchg(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_xchg_acquire)
 #define xchg_acquire(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_xchg_acquire(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_xchg_release)
 #define xchg_release(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_xchg_release(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_xchg_relaxed)
 #define xchg_relaxed(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_xchg_relaxed(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if !defined(arch_cmpxchg_relaxed) || defined(arch_cmpxchg)
 #define cmpxchg(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg_acquire)
 #define cmpxchg_acquire(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg_acquire(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg_release)
 #define cmpxchg_release(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg_release(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg_relaxed)
 #define cmpxchg_relaxed(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg_relaxed(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if !defined(arch_cmpxchg64_relaxed) || defined(arch_cmpxchg64)
 #define cmpxchg64(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg64(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg64_acquire)
 #define cmpxchg64_acquire(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg64_acquire(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg64_release)
 #define cmpxchg64_release(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg64_release(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_cmpxchg64_relaxed)
 #define cmpxchg64_relaxed(ptr, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
        instrument_atomic_write(__ai_ptr, sizeof(*__ai_ptr)); \
        arch_cmpxchg64_relaxed(__ai_ptr, __VA_ARGS__); \
 })
-#endif
 
-#if !defined(arch_try_cmpxchg_relaxed) || defined(arch_try_cmpxchg)
 #define try_cmpxchg(ptr, oldp, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
@@ -1758,9 +1269,7 @@ atomic64_dec_if_positive(atomic64_t *v)
        instrument_atomic_write(__ai_oldp, sizeof(*__ai_oldp)); \
        arch_try_cmpxchg(__ai_ptr, __ai_oldp, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_try_cmpxchg_acquire)
 #define try_cmpxchg_acquire(ptr, oldp, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
@@ -1769,9 +1278,7 @@ atomic64_dec_if_positive(atomic64_t *v)
        instrument_atomic_write(__ai_oldp, sizeof(*__ai_oldp)); \
        arch_try_cmpxchg_acquire(__ai_ptr, __ai_oldp, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_try_cmpxchg_release)
 #define try_cmpxchg_release(ptr, oldp, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
@@ -1780,9 +1287,7 @@ atomic64_dec_if_positive(atomic64_t *v)
        instrument_atomic_write(__ai_oldp, sizeof(*__ai_oldp)); \
        arch_try_cmpxchg_release(__ai_ptr, __ai_oldp, __VA_ARGS__); \
 })
-#endif
 
-#if defined(arch_try_cmpxchg_relaxed)
 #define try_cmpxchg_relaxed(ptr, oldp, ...) \
 ({ \
        typeof(ptr) __ai_ptr = (ptr); \
@@ -1791,7 +1296,6 @@ atomic64_dec_if_positive(atomic64_t *v)
        instrument_atomic_write(__ai_oldp, sizeof(*__ai_oldp)); \
        arch_try_cmpxchg_relaxed(__ai_ptr, __ai_oldp, __VA_ARGS__); \
 })
-#endif
 
 #define cmpxchg_local(ptr, ...) \
 ({ \
@@ -1830,4 +1334,4 @@ atomic64_dec_if_positive(atomic64_t *v)
 })
 
 #endif /* _ASM_GENERIC_ATOMIC_INSTRUMENTED_H */
-// 4bec382e44520f4d8267e42620054db26a659ea3
+// 1d7c3a25aca5c7fb031c307be4c3d24c7b48fcd5
index 11f96f4..04b8be9 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
- * Generic C implementation of atomic counter operations. Usable on
- * UP systems only. Do not include in machine independent code.
+ * Generic C implementation of atomic counter operations. Do not include in
+ * machine independent code.
  *
  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #include <asm/cmpxchg.h>
 #include <asm/barrier.h>
 
-/*
- * atomic_$op() - $op integer to atomic variable
- * @i: integer value to $op
- * @v: pointer to the atomic variable
- *
- * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use
- * smp_mb__{before,after}_atomic().
- */
-
-/*
- * atomic_$op_return() - $op interer to atomic variable and returns the result
- * @i: integer value to $op
- * @v: pointer to the atomic variable
- *
- * Atomically $ops @i to @v. Does imply a full memory barrier.
- */
-
 #ifdef CONFIG_SMP
 
 /* we can build all atomic primitives from cmpxchg */
 
 #define ATOMIC_OP(op, c_op)                                            \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void generic_atomic_##op(int i, atomic_t *v)             \
 {                                                                      \
        int c, old;                                                     \
                                                                        \
        c = v->counter;                                                 \
-       while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
+       while ((old = arch_cmpxchg(&v->counter, c, c c_op i)) != c)     \
                c = old;                                                \
 }
 
 #define ATOMIC_OP_RETURN(op, c_op)                                     \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int generic_atomic_##op##_return(int i, atomic_t *v)     \
 {                                                                      \
        int c, old;                                                     \
                                                                        \
        c = v->counter;                                                 \
-       while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
+       while ((old = arch_cmpxchg(&v->counter, c, c c_op i)) != c)     \
                c = old;                                                \
                                                                        \
        return c c_op i;                                                \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op)                                      \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int generic_atomic_fetch_##op(int i, atomic_t *v)                \
 {                                                                      \
        int c, old;                                                     \
                                                                        \
        c = v->counter;                                                 \
-       while ((old = cmpxchg(&v->counter, c, c c_op i)) != c)          \
+       while ((old = arch_cmpxchg(&v->counter, c, c c_op i)) != c)     \
                c = old;                                                \
                                                                        \
        return c;                                                       \
@@ -72,7 +55,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                       \
 #include <linux/irqflags.h>
 
 #define ATOMIC_OP(op, c_op)                                            \
-static inline void atomic_##op(int i, atomic_t *v)                     \
+static inline void generic_atomic_##op(int i, atomic_t *v)             \
 {                                                                      \
        unsigned long flags;                                            \
                                                                        \
@@ -82,7 +65,7 @@ static inline void atomic_##op(int i, atomic_t *v)                    \
 }
 
 #define ATOMIC_OP_RETURN(op, c_op)                                     \
-static inline int atomic_##op##_return(int i, atomic_t *v)             \
+static inline int generic_atomic_##op##_return(int i, atomic_t *v)     \
 {                                                                      \
        unsigned long flags;                                            \
        int ret;                                                        \
@@ -95,7 +78,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
 }
 
 #define ATOMIC_FETCH_OP(op, c_op)                                      \
-static inline int atomic_fetch_##op(int i, atomic_t *v)                        \
+static inline int generic_atomic_fetch_##op(int i, atomic_t *v)                \
 {                                                                      \
        unsigned long flags;                                            \
        int ret;                                                        \
@@ -110,87 +93,44 @@ static inline int atomic_fetch_##op(int i, atomic_t *v)                    \
 
 #endif /* CONFIG_SMP */
 
-#ifndef atomic_add_return
 ATOMIC_OP_RETURN(add, +)
-#endif
-
-#ifndef atomic_sub_return
 ATOMIC_OP_RETURN(sub, -)
-#endif
 
-#ifndef atomic_fetch_add
 ATOMIC_FETCH_OP(add, +)
-#endif
-
-#ifndef atomic_fetch_sub
 ATOMIC_FETCH_OP(sub, -)
-#endif
-
-#ifndef atomic_fetch_and
 ATOMIC_FETCH_OP(and, &)
-#endif
-
-#ifndef atomic_fetch_or
 ATOMIC_FETCH_OP(or, |)
-#endif
-
-#ifndef atomic_fetch_xor
 ATOMIC_FETCH_OP(xor, ^)
-#endif
 
-#ifndef atomic_and
+ATOMIC_OP(add, +)
+ATOMIC_OP(sub, -)
 ATOMIC_OP(and, &)
-#endif
-
-#ifndef atomic_or
 ATOMIC_OP(or, |)
-#endif
-
-#ifndef atomic_xor
 ATOMIC_OP(xor, ^)
-#endif
 
 #undef ATOMIC_FETCH_OP
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
 
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-/**
- * atomic_read - read atomic variable
- * @v: pointer of type atomic_t
- *
- * Atomically reads the value of @v.
- */
-#ifndef atomic_read
-#define atomic_read(v) READ_ONCE((v)->counter)
-#endif
-
-/**
- * atomic_set - set atomic variable
- * @v: pointer of type atomic_t
- * @i: required value
- *
- * Atomically sets the value of @v to @i.
- */
-#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
+#define arch_atomic_add_return                 generic_atomic_add_return
+#define arch_atomic_sub_return                 generic_atomic_sub_return
 
-#include <linux/irqflags.h>
+#define arch_atomic_fetch_add                  generic_atomic_fetch_add
+#define arch_atomic_fetch_sub                  generic_atomic_fetch_sub
+#define arch_atomic_fetch_and                  generic_atomic_fetch_and
+#define arch_atomic_fetch_or                   generic_atomic_fetch_or
+#define arch_atomic_fetch_xor                  generic_atomic_fetch_xor
 
-static inline void atomic_add(int i, atomic_t *v)
-{
-       atomic_add_return(i, v);
-}
+#define arch_atomic_add                                generic_atomic_add
+#define arch_atomic_sub                                generic_atomic_sub
+#define arch_atomic_and                                generic_atomic_and
+#define arch_atomic_or                         generic_atomic_or
+#define arch_atomic_xor                                generic_atomic_xor
 
-static inline void atomic_sub(int i, atomic_t *v)
-{
-       atomic_sub_return(i, v);
-}
+#define arch_atomic_read(v)                    READ_ONCE((v)->counter)
+#define arch_atomic_set(v, i)                  WRITE_ONCE(((v)->counter), (i))
 
-#define atomic_xchg(ptr, v)            (xchg(&(ptr)->counter, (v)))
-#define atomic_cmpxchg(v, old, new)    (cmpxchg(&((v)->counter), (old), (new)))
+#define arch_atomic_xchg(ptr, v)               (arch_xchg(&(ptr)->counter, (v)))
+#define arch_atomic_cmpxchg(v, old, new)       (arch_cmpxchg(&((v)->counter), (old), (new)))
 
 #endif /* __ASM_GENERIC_ATOMIC_H */
index 370f01d..100d24b 100644 (file)
@@ -15,19 +15,17 @@ typedef struct {
 
 #define ATOMIC64_INIT(i)       { (i) }
 
-extern s64 atomic64_read(const atomic64_t *v);
-extern void atomic64_set(atomic64_t *v, s64 i);
-
-#define atomic64_set_release(v, i)     atomic64_set((v), (i))
+extern s64 generic_atomic64_read(const atomic64_t *v);
+extern void generic_atomic64_set(atomic64_t *v, s64 i);
 
 #define ATOMIC64_OP(op)                                                        \
-extern void     atomic64_##op(s64 a, atomic64_t *v);
+extern void generic_atomic64_##op(s64 a, atomic64_t *v);
 
 #define ATOMIC64_OP_RETURN(op)                                         \
-extern s64 atomic64_##op##_return(s64 a, atomic64_t *v);
+extern s64 generic_atomic64_##op##_return(s64 a, atomic64_t *v);
 
 #define ATOMIC64_FETCH_OP(op)                                          \
-extern s64 atomic64_fetch_##op(s64 a, atomic64_t *v);
+extern s64 generic_atomic64_fetch_##op(s64 a, atomic64_t *v);
 
 #define ATOMIC64_OPS(op)       ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op)
 
@@ -46,11 +44,32 @@ ATOMIC64_OPS(xor)
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
-extern s64 atomic64_dec_if_positive(atomic64_t *v);
-#define atomic64_dec_if_positive atomic64_dec_if_positive
-extern s64 atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n);
-extern s64 atomic64_xchg(atomic64_t *v, s64 new);
-extern s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u);
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
+extern s64 generic_atomic64_dec_if_positive(atomic64_t *v);
+extern s64 generic_atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n);
+extern s64 generic_atomic64_xchg(atomic64_t *v, s64 new);
+extern s64 generic_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u);
+
+#define arch_atomic64_read             generic_atomic64_read
+#define arch_atomic64_set              generic_atomic64_set
+#define arch_atomic64_set_release      generic_atomic64_set
+
+#define arch_atomic64_add              generic_atomic64_add
+#define arch_atomic64_add_return       generic_atomic64_add_return
+#define arch_atomic64_fetch_add                generic_atomic64_fetch_add
+#define arch_atomic64_sub              generic_atomic64_sub
+#define arch_atomic64_sub_return       generic_atomic64_sub_return
+#define arch_atomic64_fetch_sub                generic_atomic64_fetch_sub
+
+#define arch_atomic64_and              generic_atomic64_and
+#define arch_atomic64_fetch_and                generic_atomic64_fetch_and
+#define arch_atomic64_or               generic_atomic64_or
+#define arch_atomic64_fetch_or         generic_atomic64_fetch_or
+#define arch_atomic64_xor              generic_atomic64_xor
+#define arch_atomic64_fetch_xor                generic_atomic64_fetch_xor
+
+#define arch_atomic64_dec_if_positive  generic_atomic64_dec_if_positive
+#define arch_atomic64_cmpxchg          generic_atomic64_cmpxchg
+#define arch_atomic64_xchg             generic_atomic64_xchg
+#define arch_atomic64_fetch_add_unless generic_atomic64_fetch_add_unless
 
 #endif  /*  _ASM_GENERIC_ATOMIC64_H  */
index f17f14f..380cdc8 100644 (file)
@@ -12,7 +12,7 @@ extern unsigned long wrong_size_cmpxchg(volatile void *ptr)
  * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned
  * long parameter, supporting various types of architectures.
  */
-static inline unsigned long __cmpxchg_local_generic(volatile void *ptr,
+static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
                unsigned long old, unsigned long new, int size)
 {
        unsigned long flags, prev;
@@ -51,7 +51,7 @@ static inline unsigned long __cmpxchg_local_generic(volatile void *ptr,
 /*
  * Generic version of __cmpxchg64_local. Takes an u64 parameter.
  */
-static inline u64 __cmpxchg64_local_generic(volatile void *ptr,
+static inline u64 __generic_cmpxchg64_local(volatile void *ptr,
                u64 old, u64 new)
 {
        u64 prev;
index 9a24510..dca4419 100644 (file)
 #include <linux/types.h>
 #include <linux/irqflags.h>
 
-#ifndef xchg
-
 /*
  * This function doesn't exist, so you'll get a linker error if
  * something tries to do an invalidly-sized xchg().
  */
-extern void __xchg_called_with_bad_pointer(void);
+extern void __generic_xchg_called_with_bad_pointer(void);
 
 static inline
-unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
 {
        unsigned long ret, flags;
 
@@ -75,35 +73,43 @@ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 #endif /* CONFIG_64BIT */
 
        default:
-               __xchg_called_with_bad_pointer();
+               __generic_xchg_called_with_bad_pointer();
                return x;
        }
 }
 
-#define xchg(ptr, x) ({                                                        \
-       ((__typeof__(*(ptr)))                                           \
-               __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));     \
+#define generic_xchg(ptr, x) ({                                                        \
+       ((__typeof__(*(ptr)))                                                   \
+               __generic_xchg((unsigned long)(x), (ptr), sizeof(*(ptr))));     \
 })
 
-#endif /* xchg */
-
 /*
  * Atomic compare and exchange.
  */
 #include <asm-generic/cmpxchg-local.h>
 
-#ifndef cmpxchg_local
-#define cmpxchg_local(ptr, o, n) ({                                           \
-       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
-                       (unsigned long)(n), sizeof(*(ptr))));                  \
+#define generic_cmpxchg_local(ptr, o, n) ({                                    \
+       ((__typeof__(*(ptr)))__generic_cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))));                   \
 })
+
+#define generic_cmpxchg64_local(ptr, o, n) \
+       __generic_cmpxchg64_local((ptr), (o), (n))
+
+
+#ifndef arch_xchg
+#define arch_xchg              generic_xchg
+#endif
+
+#ifndef arch_cmpxchg_local
+#define arch_cmpxchg_local     generic_cmpxchg_local
 #endif
 
-#ifndef cmpxchg64_local
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+#ifndef arch_cmpxchg64_local
+#define arch_cmpxchg64_local   generic_cmpxchg64_local
 #endif
 
-#define cmpxchg(ptr, o, n)     cmpxchg_local((ptr), (o), (n))
-#define cmpxchg64(ptr, o, n)   cmpxchg64_local((ptr), (o), (n))
+#define arch_cmpxchg           arch_cmpxchg_local
+#define arch_cmpxchg64         arch_cmpxchg64_local
 
 #endif /* __ASM_GENERIC_CMPXCHG_H */
index 515c3fb..56348a5 100644 (file)
@@ -194,6 +194,7 @@ enum HV_GENERIC_SET_FORMAT {
 #define HV_STATUS_INVALID_HYPERCALL_INPUT      3
 #define HV_STATUS_INVALID_ALIGNMENT            4
 #define HV_STATUS_INVALID_PARAMETER            5
+#define HV_STATUS_ACCESS_DENIED                        6
 #define HV_STATUS_OPERATION_DENIED             8
 #define HV_STATUS_INSUFFICIENT_MEMORY          11
 #define HV_STATUS_INVALID_PORT_ID              17
index d683f5e..b4d43a4 100644 (file)
@@ -29,7 +29,7 @@ static __always_inline void preempt_count_set(int pc)
 } while (0)
 
 #define init_idle_preempt_count(p, cpu) do { \
-       task_thread_info(p)->preempt_count = PREEMPT_ENABLED; \
+       task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \
 } while (0)
 
 static __always_inline void set_preempt_need_resched(void)
index c395238..9b435ca 100644 (file)
@@ -27,6 +27,7 @@ struct samsung_pwm_variant {
 };
 
 void samsung_pwm_clocksource_init(void __iomem *base,
-               unsigned int *irqs, struct samsung_pwm_variant *variant);
+                                 unsigned int *irqs,
+                                 const struct samsung_pwm_variant *variant);
 
 #endif /* __CLOCKSOURCE_SAMSUNG_PWM_H */
index 4c61dad..f6da8a1 100644 (file)
@@ -74,6 +74,7 @@
 #define OMAP_TIMER_ERRATA_I103_I767                    0x80000000
 
 struct timer_regs {
+       u32 ocp_cfg;
        u32 tidr;
        u32 tier;
        u32 twer;
index e728469..5af914c 100644 (file)
@@ -490,7 +490,7 @@ static inline void aead_request_set_callback(struct aead_request *req,
  * The memory structure for cipher operation has the following structure:
  *
  * - AEAD encryption input:  assoc data || plaintext
- * - AEAD encryption output: assoc data || cipherntext || auth tag
+ * - AEAD encryption output: assoc data || ciphertext || auth tag
  * - AEAD decryption input:  assoc data || ciphertext || auth tag
  * - AEAD decryption output: assoc data || plaintext
  *
index 86f0748..5f6841c 100644 (file)
@@ -96,6 +96,15 @@ struct scatter_walk {
        unsigned int offset;
 };
 
+struct crypto_attr_alg {
+       char name[CRYPTO_MAX_ALG_NAME];
+};
+
+struct crypto_attr_type {
+       u32 type;
+       u32 mask;
+};
+
 void crypto_mod_put(struct crypto_alg *alg);
 
 int crypto_register_template(struct crypto_template *tmpl);
@@ -118,7 +127,6 @@ void *crypto_spawn_tfm2(struct crypto_spawn *spawn);
 struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
 int crypto_check_attr_type(struct rtattr **tb, u32 type, u32 *mask_ret);
 const char *crypto_attr_alg_name(struct rtattr *rta);
-int crypto_attr_u32(struct rtattr *rta, u32 *num);
 int crypto_inst_setname(struct crypto_instance *inst, const char *name,
                        struct crypto_alg *alg);
 
index 3f06e40..26cac19 100644 (file)
@@ -28,7 +28,7 @@
  * of a failed backlog request
  * crypto-engine, in head position to keep order
  * @list: link with the global crypto engine list
- * @queue_lock: spinlock to syncronise access to request queue
+ * @queue_lock: spinlock to synchronise access to request queue
  * @queue: the crypto queue of the engine
  * @rt: whether this queue is set to run as a realtime task
  * @prepare_crypt_hardware: a request will soon arrive from the queue
index b2bc1e4..f140e46 100644 (file)
@@ -458,7 +458,7 @@ int crypto_ahash_finup(struct ahash_request *req);
  *
  * Return:
  * 0           if the message digest was successfully calculated;
- * -EINPROGRESS        if data is feeded into hardware (DMA) or queued for later;
+ * -EINPROGRESS        if data is fed into hardware (DMA) or queued for later;
  * -EBUSY      if queue is full and request should be resubmitted later;
  * other < 0   if an error occurred
  */
index 0a288dd..2580614 100644 (file)
@@ -75,13 +75,7 @@ void crypto_unregister_ahashes(struct ahash_alg *algs, int count);
 int ahash_register_instance(struct crypto_template *tmpl,
                            struct ahash_instance *inst);
 
-int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-                   unsigned int keylen);
-
-static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
-{
-       return alg->setkey != shash_no_setkey;
-}
+bool crypto_shash_alg_has_setkey(struct shash_alg *alg);
 
 static inline bool crypto_shash_alg_needs_key(struct shash_alg *alg)
 {
index ec62118..e602d84 100644 (file)
@@ -72,6 +72,9 @@ struct vgic_global {
        bool                    has_gicv4;
        bool                    has_gicv4_1;
 
+       /* Pseudo GICv3 from outer space */
+       bool                    no_hw_deactivation;
+
        /* GIC system register CPU interface */
        struct static_key_false gicv3_cpuif;
 
@@ -89,6 +92,26 @@ enum vgic_irq_config {
        VGIC_CONFIG_LEVEL
 };
 
+/*
+ * Per-irq ops overriding some common behavious.
+ *
+ * Always called in non-preemptible section and the functions can use
+ * kvm_arm_get_running_vcpu() to get the vcpu pointer for private IRQs.
+ */
+struct irq_ops {
+       /* Per interrupt flags for special-cased interrupts */
+       unsigned long flags;
+
+#define VGIC_IRQ_SW_RESAMPLE   BIT(0)  /* Clear the active state for resampling */
+
+       /*
+        * Callback function pointer to in-kernel devices that can tell us the
+        * state of the input level of mapped level-triggered IRQ faster than
+        * peaking into the physical GIC.
+        */
+       bool (*get_input_level)(int vintid);
+};
+
 struct vgic_irq {
        raw_spinlock_t irq_lock;        /* Protects the content of the struct */
        struct list_head lpi_list;      /* Used to link all LPIs together */
@@ -126,21 +149,17 @@ struct vgic_irq {
        u8 group;                       /* 0 == group 0, 1 == group 1 */
        enum vgic_irq_config config;    /* Level or edge */
 
-       /*
-        * Callback function pointer to in-kernel devices that can tell us the
-        * state of the input level of mapped level-triggered IRQ faster than
-        * peaking into the physical GIC.
-        *
-        * Always called in non-preemptible section and the functions can use
-        * kvm_arm_get_running_vcpu() to get the vcpu pointer for private
-        * IRQs.
-        */
-       bool (*get_input_level)(int vintid);
+       struct irq_ops *ops;
 
        void *owner;                    /* Opaque pointer to reserve an interrupt
                                           for in-kernel devices. */
 };
 
+static inline bool vgic_irq_needs_resampling(struct vgic_irq *irq)
+{
+       return irq->ops && (irq->ops->flags & VGIC_IRQ_SW_RESAMPLE);
+}
+
 struct vgic_register_region;
 struct vgic_its;
 
@@ -352,7 +371,7 @@ void kvm_vgic_init_cpu_hardware(void);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
                        bool level, void *owner);
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
-                         u32 vintid, bool (*get_input_level)(int vindid));
+                         u32 vintid, struct irq_ops *ops);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid);
 
index f180240..11e555c 100644 (file)
@@ -37,7 +37,6 @@ bool topology_scale_freq_invariant(void);
 enum scale_freq_source {
        SCALE_FREQ_SOURCE_CPUFREQ = 0,
        SCALE_FREQ_SOURCE_ARCH,
-       SCALE_FREQ_SOURCE_CPPC,
 };
 
 struct scale_freq_data {
index 6861489..7d1cabe 100644 (file)
@@ -63,6 +63,9 @@
 #define ARM_SMCCC_VERSION_1_0          0x10000
 #define ARM_SMCCC_VERSION_1_1          0x10001
 #define ARM_SMCCC_VERSION_1_2          0x10002
+#define ARM_SMCCC_VERSION_1_3          0x10003
+
+#define ARM_SMCCC_1_3_SVE_HINT         0x10000
 
 #define ARM_SMCCC_VERSION_FUNC_ID                                      \
        ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
@@ -216,6 +219,8 @@ u32 arm_smccc_get_version(void);
 
 void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);
 
+extern u64 smccc_has_sve_hint;
+
 /**
  * struct arm_smccc_res - Result from SMC/HVC call
  * @a0-a3 result values from registers 0 to 3
@@ -227,6 +232,61 @@ struct arm_smccc_res {
        unsigned long a3;
 };
 
+#ifdef CONFIG_ARM64
+/**
+ * struct arm_smccc_1_2_regs - Arguments for or Results from SMC/HVC call
+ * @a0-a17 argument values from registers 0 to 17
+ */
+struct arm_smccc_1_2_regs {
+       unsigned long a0;
+       unsigned long a1;
+       unsigned long a2;
+       unsigned long a3;
+       unsigned long a4;
+       unsigned long a5;
+       unsigned long a6;
+       unsigned long a7;
+       unsigned long a8;
+       unsigned long a9;
+       unsigned long a10;
+       unsigned long a11;
+       unsigned long a12;
+       unsigned long a13;
+       unsigned long a14;
+       unsigned long a15;
+       unsigned long a16;
+       unsigned long a17;
+};
+
+/**
+ * arm_smccc_1_2_hvc() - make HVC calls
+ * @args: arguments passed via struct arm_smccc_1_2_regs
+ * @res: result values via struct arm_smccc_1_2_regs
+ *
+ * This function is used to make HVC calls following SMC Calling Convention
+ * v1.2 or above. The content of the supplied param are copied from the
+ * structure to registers prior to the HVC instruction. The return values
+ * are updated with the content from registers on return from the HVC
+ * instruction.
+ */
+asmlinkage void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args,
+                                 struct arm_smccc_1_2_regs *res);
+
+/**
+ * arm_smccc_1_2_smc() - make SMC calls
+ * @args: arguments passed via struct arm_smccc_1_2_regs
+ * @res: result values via struct arm_smccc_1_2_regs
+ *
+ * This function is used to make SMC calls following SMC Calling Convention
+ * v1.2 or above. The content of the supplied param are copied from the
+ * structure to registers prior to the SMC instruction. The return values
+ * are updated with the content from registers on return from the SMC
+ * instruction.
+ */
+asmlinkage void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
+                                 struct arm_smccc_1_2_regs *res);
+#endif
+
 /**
  * struct arm_smccc_quirk - Contains quirk information
  * @id: quirk identification
@@ -241,6 +301,15 @@ struct arm_smccc_quirk {
 };
 
 /**
+ * __arm_smccc_sve_check() - Set the SVE hint bit when doing SMC calls
+ *
+ * Sets the SMCCC hint bit to indicate if there is live state in the SVE
+ * registers, this modifies x0 in place and should never be called from C
+ * code.
+ */
+asmlinkage unsigned long __arm_smccc_sve_check(unsigned long x0);
+
+/**
  * __arm_smccc_smc() - make SMC calls
  * @a0-a7: arguments passed in registers 0 to 7
  * @res: result values from registers 0 to 3
@@ -297,6 +366,20 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
 
 #endif
 
+/* nVHE hypervisor doesn't have a current thread so needs separate checks */
+#if defined(CONFIG_ARM64_SVE) && !defined(__KVM_NVHE_HYPERVISOR__)
+
+#define SMCCC_SVE_CHECK ALTERNATIVE("nop \n",  "bl __arm_smccc_sve_check \n", \
+                                   ARM64_SVE)
+#define smccc_sve_clobbers "x16", "x30", "cc",
+
+#else
+
+#define SMCCC_SVE_CHECK
+#define smccc_sve_clobbers
+
+#endif
+
 #define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
 
 #define __count_args(...)                                              \
@@ -364,7 +447,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
 
 #define ___constraints(count)                                          \
        : __constraint_read_ ## count                                   \
-       : "memory"
+       : smccc_sve_clobbers "memory"
 #define __constraints(count)   ___constraints(count)
 
 /*
@@ -379,7 +462,8 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
                register unsigned long r2 asm("r2");                    \
                register unsigned long r3 asm("r3");                    \
                __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \
-               asm volatile(inst "\n" :                                \
+               asm volatile(SMCCC_SVE_CHECK                            \
+                            inst "\n" :                                \
                             "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \
                             __constraints(__count_args(__VA_ARGS__))); \
                if (___res)                                             \
index 6e67ade..1b44f40 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef __LINUX_ATA_H__
 #define __LINUX_ATA_H__
 
-#include <linux/kernel.h>
+#include <linux/bits.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
diff --git a/include/linux/atomic-fallback.h b/include/linux/atomic-fallback.h
deleted file mode 100644 (file)
index 2a3f55d..0000000
+++ /dev/null
@@ -1,2595 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-// Generated by scripts/atomic/gen-atomic-fallback.sh
-// DO NOT MODIFY THIS FILE DIRECTLY
-
-#ifndef _LINUX_ATOMIC_FALLBACK_H
-#define _LINUX_ATOMIC_FALLBACK_H
-
-#include <linux/compiler.h>
-
-#ifndef xchg_relaxed
-#define xchg_acquire xchg
-#define xchg_release xchg
-#define xchg_relaxed xchg
-#else /* xchg_relaxed */
-
-#ifndef xchg_acquire
-#define xchg_acquire(...) \
-       __atomic_op_acquire(xchg, __VA_ARGS__)
-#endif
-
-#ifndef xchg_release
-#define xchg_release(...) \
-       __atomic_op_release(xchg, __VA_ARGS__)
-#endif
-
-#ifndef xchg
-#define xchg(...) \
-       __atomic_op_fence(xchg, __VA_ARGS__)
-#endif
-
-#endif /* xchg_relaxed */
-
-#ifndef cmpxchg_relaxed
-#define cmpxchg_acquire cmpxchg
-#define cmpxchg_release cmpxchg
-#define cmpxchg_relaxed cmpxchg
-#else /* cmpxchg_relaxed */
-
-#ifndef cmpxchg_acquire
-#define cmpxchg_acquire(...) \
-       __atomic_op_acquire(cmpxchg, __VA_ARGS__)
-#endif
-
-#ifndef cmpxchg_release
-#define cmpxchg_release(...) \
-       __atomic_op_release(cmpxchg, __VA_ARGS__)
-#endif
-
-#ifndef cmpxchg
-#define cmpxchg(...) \
-       __atomic_op_fence(cmpxchg, __VA_ARGS__)
-#endif
-
-#endif /* cmpxchg_relaxed */
-
-#ifndef cmpxchg64_relaxed
-#define cmpxchg64_acquire cmpxchg64
-#define cmpxchg64_release cmpxchg64
-#define cmpxchg64_relaxed cmpxchg64
-#else /* cmpxchg64_relaxed */
-
-#ifndef cmpxchg64_acquire
-#define cmpxchg64_acquire(...) \
-       __atomic_op_acquire(cmpxchg64, __VA_ARGS__)
-#endif
-
-#ifndef cmpxchg64_release
-#define cmpxchg64_release(...) \
-       __atomic_op_release(cmpxchg64, __VA_ARGS__)
-#endif
-
-#ifndef cmpxchg64
-#define cmpxchg64(...) \
-       __atomic_op_fence(cmpxchg64, __VA_ARGS__)
-#endif
-
-#endif /* cmpxchg64_relaxed */
-
-#ifndef try_cmpxchg_relaxed
-#ifdef try_cmpxchg
-#define try_cmpxchg_acquire try_cmpxchg
-#define try_cmpxchg_release try_cmpxchg
-#define try_cmpxchg_relaxed try_cmpxchg
-#endif /* try_cmpxchg */
-
-#ifndef try_cmpxchg
-#define try_cmpxchg(_ptr, _oldp, _new) \
-({ \
-       typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \
-       ___r = cmpxchg((_ptr), ___o, (_new)); \
-       if (unlikely(___r != ___o)) \
-               *___op = ___r; \
-       likely(___r == ___o); \
-})
-#endif /* try_cmpxchg */
-
-#ifndef try_cmpxchg_acquire
-#define try_cmpxchg_acquire(_ptr, _oldp, _new) \
-({ \
-       typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \
-       ___r = cmpxchg_acquire((_ptr), ___o, (_new)); \
-       if (unlikely(___r != ___o)) \
-               *___op = ___r; \
-       likely(___r == ___o); \
-})
-#endif /* try_cmpxchg_acquire */
-
-#ifndef try_cmpxchg_release
-#define try_cmpxchg_release(_ptr, _oldp, _new) \
-({ \
-       typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \
-       ___r = cmpxchg_release((_ptr), ___o, (_new)); \
-       if (unlikely(___r != ___o)) \
-               *___op = ___r; \
-       likely(___r == ___o); \
-})
-#endif /* try_cmpxchg_release */
-
-#ifndef try_cmpxchg_relaxed
-#define try_cmpxchg_relaxed(_ptr, _oldp, _new) \
-({ \
-       typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \
-       ___r = cmpxchg_relaxed((_ptr), ___o, (_new)); \
-       if (unlikely(___r != ___o)) \
-               *___op = ___r; \
-       likely(___r == ___o); \
-})
-#endif /* try_cmpxchg_relaxed */
-
-#else /* try_cmpxchg_relaxed */
-
-#ifndef try_cmpxchg_acquire
-#define try_cmpxchg_acquire(...) \
-       __atomic_op_acquire(try_cmpxchg, __VA_ARGS__)
-#endif
-
-#ifndef try_cmpxchg_release
-#define try_cmpxchg_release(...) \
-       __atomic_op_release(try_cmpxchg, __VA_ARGS__)
-#endif
-
-#ifndef try_cmpxchg
-#define try_cmpxchg(...) \
-       __atomic_op_fence(try_cmpxchg, __VA_ARGS__)
-#endif
-
-#endif /* try_cmpxchg_relaxed */
-
-#define arch_atomic_read atomic_read
-#define arch_atomic_read_acquire atomic_read_acquire
-
-#ifndef atomic_read_acquire
-static __always_inline int
-atomic_read_acquire(const atomic_t *v)
-{
-       return smp_load_acquire(&(v)->counter);
-}
-#define atomic_read_acquire atomic_read_acquire
-#endif
-
-#define arch_atomic_set atomic_set
-#define arch_atomic_set_release atomic_set_release
-
-#ifndef atomic_set_release
-static __always_inline void
-atomic_set_release(atomic_t *v, int i)
-{
-       smp_store_release(&(v)->counter, i);
-}
-#define atomic_set_release atomic_set_release
-#endif
-
-#define arch_atomic_add atomic_add
-
-#define arch_atomic_add_return atomic_add_return
-#define arch_atomic_add_return_acquire atomic_add_return_acquire
-#define arch_atomic_add_return_release atomic_add_return_release
-#define arch_atomic_add_return_relaxed atomic_add_return_relaxed
-
-#ifndef atomic_add_return_relaxed
-#define atomic_add_return_acquire atomic_add_return
-#define atomic_add_return_release atomic_add_return
-#define atomic_add_return_relaxed atomic_add_return
-#else /* atomic_add_return_relaxed */
-
-#ifndef atomic_add_return_acquire
-static __always_inline int
-atomic_add_return_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_add_return_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_add_return_acquire atomic_add_return_acquire
-#endif
-
-#ifndef atomic_add_return_release
-static __always_inline int
-atomic_add_return_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_add_return_relaxed(i, v);
-}
-#define atomic_add_return_release atomic_add_return_release
-#endif
-
-#ifndef atomic_add_return
-static __always_inline int
-atomic_add_return(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_add_return_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_add_return atomic_add_return
-#endif
-
-#endif /* atomic_add_return_relaxed */
-
-#define arch_atomic_fetch_add atomic_fetch_add
-#define arch_atomic_fetch_add_acquire atomic_fetch_add_acquire
-#define arch_atomic_fetch_add_release atomic_fetch_add_release
-#define arch_atomic_fetch_add_relaxed atomic_fetch_add_relaxed
-
-#ifndef atomic_fetch_add_relaxed
-#define atomic_fetch_add_acquire atomic_fetch_add
-#define atomic_fetch_add_release atomic_fetch_add
-#define atomic_fetch_add_relaxed atomic_fetch_add
-#else /* atomic_fetch_add_relaxed */
-
-#ifndef atomic_fetch_add_acquire
-static __always_inline int
-atomic_fetch_add_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_add_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_add_acquire atomic_fetch_add_acquire
-#endif
-
-#ifndef atomic_fetch_add_release
-static __always_inline int
-atomic_fetch_add_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_add_relaxed(i, v);
-}
-#define atomic_fetch_add_release atomic_fetch_add_release
-#endif
-
-#ifndef atomic_fetch_add
-static __always_inline int
-atomic_fetch_add(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_add_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_add atomic_fetch_add
-#endif
-
-#endif /* atomic_fetch_add_relaxed */
-
-#define arch_atomic_sub atomic_sub
-
-#define arch_atomic_sub_return atomic_sub_return
-#define arch_atomic_sub_return_acquire atomic_sub_return_acquire
-#define arch_atomic_sub_return_release atomic_sub_return_release
-#define arch_atomic_sub_return_relaxed atomic_sub_return_relaxed
-
-#ifndef atomic_sub_return_relaxed
-#define atomic_sub_return_acquire atomic_sub_return
-#define atomic_sub_return_release atomic_sub_return
-#define atomic_sub_return_relaxed atomic_sub_return
-#else /* atomic_sub_return_relaxed */
-
-#ifndef atomic_sub_return_acquire
-static __always_inline int
-atomic_sub_return_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_sub_return_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_sub_return_acquire atomic_sub_return_acquire
-#endif
-
-#ifndef atomic_sub_return_release
-static __always_inline int
-atomic_sub_return_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_sub_return_relaxed(i, v);
-}
-#define atomic_sub_return_release atomic_sub_return_release
-#endif
-
-#ifndef atomic_sub_return
-static __always_inline int
-atomic_sub_return(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_sub_return_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_sub_return atomic_sub_return
-#endif
-
-#endif /* atomic_sub_return_relaxed */
-
-#define arch_atomic_fetch_sub atomic_fetch_sub
-#define arch_atomic_fetch_sub_acquire atomic_fetch_sub_acquire
-#define arch_atomic_fetch_sub_release atomic_fetch_sub_release
-#define arch_atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
-
-#ifndef atomic_fetch_sub_relaxed
-#define atomic_fetch_sub_acquire atomic_fetch_sub
-#define atomic_fetch_sub_release atomic_fetch_sub
-#define atomic_fetch_sub_relaxed atomic_fetch_sub
-#else /* atomic_fetch_sub_relaxed */
-
-#ifndef atomic_fetch_sub_acquire
-static __always_inline int
-atomic_fetch_sub_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_sub_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_sub_acquire atomic_fetch_sub_acquire
-#endif
-
-#ifndef atomic_fetch_sub_release
-static __always_inline int
-atomic_fetch_sub_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_sub_relaxed(i, v);
-}
-#define atomic_fetch_sub_release atomic_fetch_sub_release
-#endif
-
-#ifndef atomic_fetch_sub
-static __always_inline int
-atomic_fetch_sub(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_sub_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_sub atomic_fetch_sub
-#endif
-
-#endif /* atomic_fetch_sub_relaxed */
-
-#define arch_atomic_inc atomic_inc
-
-#ifndef atomic_inc
-static __always_inline void
-atomic_inc(atomic_t *v)
-{
-       atomic_add(1, v);
-}
-#define atomic_inc atomic_inc
-#endif
-
-#define arch_atomic_inc_return atomic_inc_return
-#define arch_atomic_inc_return_acquire atomic_inc_return_acquire
-#define arch_atomic_inc_return_release atomic_inc_return_release
-#define arch_atomic_inc_return_relaxed atomic_inc_return_relaxed
-
-#ifndef atomic_inc_return_relaxed
-#ifdef atomic_inc_return
-#define atomic_inc_return_acquire atomic_inc_return
-#define atomic_inc_return_release atomic_inc_return
-#define atomic_inc_return_relaxed atomic_inc_return
-#endif /* atomic_inc_return */
-
-#ifndef atomic_inc_return
-static __always_inline int
-atomic_inc_return(atomic_t *v)
-{
-       return atomic_add_return(1, v);
-}
-#define atomic_inc_return atomic_inc_return
-#endif
-
-#ifndef atomic_inc_return_acquire
-static __always_inline int
-atomic_inc_return_acquire(atomic_t *v)
-{
-       return atomic_add_return_acquire(1, v);
-}
-#define atomic_inc_return_acquire atomic_inc_return_acquire
-#endif
-
-#ifndef atomic_inc_return_release
-static __always_inline int
-atomic_inc_return_release(atomic_t *v)
-{
-       return atomic_add_return_release(1, v);
-}
-#define atomic_inc_return_release atomic_inc_return_release
-#endif
-
-#ifndef atomic_inc_return_relaxed
-static __always_inline int
-atomic_inc_return_relaxed(atomic_t *v)
-{
-       return atomic_add_return_relaxed(1, v);
-}
-#define atomic_inc_return_relaxed atomic_inc_return_relaxed
-#endif
-
-#else /* atomic_inc_return_relaxed */
-
-#ifndef atomic_inc_return_acquire
-static __always_inline int
-atomic_inc_return_acquire(atomic_t *v)
-{
-       int ret = atomic_inc_return_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_inc_return_acquire atomic_inc_return_acquire
-#endif
-
-#ifndef atomic_inc_return_release
-static __always_inline int
-atomic_inc_return_release(atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_inc_return_relaxed(v);
-}
-#define atomic_inc_return_release atomic_inc_return_release
-#endif
-
-#ifndef atomic_inc_return
-static __always_inline int
-atomic_inc_return(atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_inc_return_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_inc_return atomic_inc_return
-#endif
-
-#endif /* atomic_inc_return_relaxed */
-
-#define arch_atomic_fetch_inc atomic_fetch_inc
-#define arch_atomic_fetch_inc_acquire atomic_fetch_inc_acquire
-#define arch_atomic_fetch_inc_release atomic_fetch_inc_release
-#define arch_atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed
-
-#ifndef atomic_fetch_inc_relaxed
-#ifdef atomic_fetch_inc
-#define atomic_fetch_inc_acquire atomic_fetch_inc
-#define atomic_fetch_inc_release atomic_fetch_inc
-#define atomic_fetch_inc_relaxed atomic_fetch_inc
-#endif /* atomic_fetch_inc */
-
-#ifndef atomic_fetch_inc
-static __always_inline int
-atomic_fetch_inc(atomic_t *v)
-{
-       return atomic_fetch_add(1, v);
-}
-#define atomic_fetch_inc atomic_fetch_inc
-#endif
-
-#ifndef atomic_fetch_inc_acquire
-static __always_inline int
-atomic_fetch_inc_acquire(atomic_t *v)
-{
-       return atomic_fetch_add_acquire(1, v);
-}
-#define atomic_fetch_inc_acquire atomic_fetch_inc_acquire
-#endif
-
-#ifndef atomic_fetch_inc_release
-static __always_inline int
-atomic_fetch_inc_release(atomic_t *v)
-{
-       return atomic_fetch_add_release(1, v);
-}
-#define atomic_fetch_inc_release atomic_fetch_inc_release
-#endif
-
-#ifndef atomic_fetch_inc_relaxed
-static __always_inline int
-atomic_fetch_inc_relaxed(atomic_t *v)
-{
-       return atomic_fetch_add_relaxed(1, v);
-}
-#define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed
-#endif
-
-#else /* atomic_fetch_inc_relaxed */
-
-#ifndef atomic_fetch_inc_acquire
-static __always_inline int
-atomic_fetch_inc_acquire(atomic_t *v)
-{
-       int ret = atomic_fetch_inc_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_inc_acquire atomic_fetch_inc_acquire
-#endif
-
-#ifndef atomic_fetch_inc_release
-static __always_inline int
-atomic_fetch_inc_release(atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_inc_relaxed(v);
-}
-#define atomic_fetch_inc_release atomic_fetch_inc_release
-#endif
-
-#ifndef atomic_fetch_inc
-static __always_inline int
-atomic_fetch_inc(atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_inc_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_inc atomic_fetch_inc
-#endif
-
-#endif /* atomic_fetch_inc_relaxed */
-
-#define arch_atomic_dec atomic_dec
-
-#ifndef atomic_dec
-static __always_inline void
-atomic_dec(atomic_t *v)
-{
-       atomic_sub(1, v);
-}
-#define atomic_dec atomic_dec
-#endif
-
-#define arch_atomic_dec_return atomic_dec_return
-#define arch_atomic_dec_return_acquire atomic_dec_return_acquire
-#define arch_atomic_dec_return_release atomic_dec_return_release
-#define arch_atomic_dec_return_relaxed atomic_dec_return_relaxed
-
-#ifndef atomic_dec_return_relaxed
-#ifdef atomic_dec_return
-#define atomic_dec_return_acquire atomic_dec_return
-#define atomic_dec_return_release atomic_dec_return
-#define atomic_dec_return_relaxed atomic_dec_return
-#endif /* atomic_dec_return */
-
-#ifndef atomic_dec_return
-static __always_inline int
-atomic_dec_return(atomic_t *v)
-{
-       return atomic_sub_return(1, v);
-}
-#define atomic_dec_return atomic_dec_return
-#endif
-
-#ifndef atomic_dec_return_acquire
-static __always_inline int
-atomic_dec_return_acquire(atomic_t *v)
-{
-       return atomic_sub_return_acquire(1, v);
-}
-#define atomic_dec_return_acquire atomic_dec_return_acquire
-#endif
-
-#ifndef atomic_dec_return_release
-static __always_inline int
-atomic_dec_return_release(atomic_t *v)
-{
-       return atomic_sub_return_release(1, v);
-}
-#define atomic_dec_return_release atomic_dec_return_release
-#endif
-
-#ifndef atomic_dec_return_relaxed
-static __always_inline int
-atomic_dec_return_relaxed(atomic_t *v)
-{
-       return atomic_sub_return_relaxed(1, v);
-}
-#define atomic_dec_return_relaxed atomic_dec_return_relaxed
-#endif
-
-#else /* atomic_dec_return_relaxed */
-
-#ifndef atomic_dec_return_acquire
-static __always_inline int
-atomic_dec_return_acquire(atomic_t *v)
-{
-       int ret = atomic_dec_return_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_dec_return_acquire atomic_dec_return_acquire
-#endif
-
-#ifndef atomic_dec_return_release
-static __always_inline int
-atomic_dec_return_release(atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_dec_return_relaxed(v);
-}
-#define atomic_dec_return_release atomic_dec_return_release
-#endif
-
-#ifndef atomic_dec_return
-static __always_inline int
-atomic_dec_return(atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_dec_return_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_dec_return atomic_dec_return
-#endif
-
-#endif /* atomic_dec_return_relaxed */
-
-#define arch_atomic_fetch_dec atomic_fetch_dec
-#define arch_atomic_fetch_dec_acquire atomic_fetch_dec_acquire
-#define arch_atomic_fetch_dec_release atomic_fetch_dec_release
-#define arch_atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed
-
-#ifndef atomic_fetch_dec_relaxed
-#ifdef atomic_fetch_dec
-#define atomic_fetch_dec_acquire atomic_fetch_dec
-#define atomic_fetch_dec_release atomic_fetch_dec
-#define atomic_fetch_dec_relaxed atomic_fetch_dec
-#endif /* atomic_fetch_dec */
-
-#ifndef atomic_fetch_dec
-static __always_inline int
-atomic_fetch_dec(atomic_t *v)
-{
-       return atomic_fetch_sub(1, v);
-}
-#define atomic_fetch_dec atomic_fetch_dec
-#endif
-
-#ifndef atomic_fetch_dec_acquire
-static __always_inline int
-atomic_fetch_dec_acquire(atomic_t *v)
-{
-       return atomic_fetch_sub_acquire(1, v);
-}
-#define atomic_fetch_dec_acquire atomic_fetch_dec_acquire
-#endif
-
-#ifndef atomic_fetch_dec_release
-static __always_inline int
-atomic_fetch_dec_release(atomic_t *v)
-{
-       return atomic_fetch_sub_release(1, v);
-}
-#define atomic_fetch_dec_release atomic_fetch_dec_release
-#endif
-
-#ifndef atomic_fetch_dec_relaxed
-static __always_inline int
-atomic_fetch_dec_relaxed(atomic_t *v)
-{
-       return atomic_fetch_sub_relaxed(1, v);
-}
-#define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed
-#endif
-
-#else /* atomic_fetch_dec_relaxed */
-
-#ifndef atomic_fetch_dec_acquire
-static __always_inline int
-atomic_fetch_dec_acquire(atomic_t *v)
-{
-       int ret = atomic_fetch_dec_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_dec_acquire atomic_fetch_dec_acquire
-#endif
-
-#ifndef atomic_fetch_dec_release
-static __always_inline int
-atomic_fetch_dec_release(atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_dec_relaxed(v);
-}
-#define atomic_fetch_dec_release atomic_fetch_dec_release
-#endif
-
-#ifndef atomic_fetch_dec
-static __always_inline int
-atomic_fetch_dec(atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_dec_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_dec atomic_fetch_dec
-#endif
-
-#endif /* atomic_fetch_dec_relaxed */
-
-#define arch_atomic_and atomic_and
-
-#define arch_atomic_fetch_and atomic_fetch_and
-#define arch_atomic_fetch_and_acquire atomic_fetch_and_acquire
-#define arch_atomic_fetch_and_release atomic_fetch_and_release
-#define arch_atomic_fetch_and_relaxed atomic_fetch_and_relaxed
-
-#ifndef atomic_fetch_and_relaxed
-#define atomic_fetch_and_acquire atomic_fetch_and
-#define atomic_fetch_and_release atomic_fetch_and
-#define atomic_fetch_and_relaxed atomic_fetch_and
-#else /* atomic_fetch_and_relaxed */
-
-#ifndef atomic_fetch_and_acquire
-static __always_inline int
-atomic_fetch_and_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_and_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_and_acquire atomic_fetch_and_acquire
-#endif
-
-#ifndef atomic_fetch_and_release
-static __always_inline int
-atomic_fetch_and_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_and_relaxed(i, v);
-}
-#define atomic_fetch_and_release atomic_fetch_and_release
-#endif
-
-#ifndef atomic_fetch_and
-static __always_inline int
-atomic_fetch_and(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_and_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_and atomic_fetch_and
-#endif
-
-#endif /* atomic_fetch_and_relaxed */
-
-#define arch_atomic_andnot atomic_andnot
-
-#ifndef atomic_andnot
-static __always_inline void
-atomic_andnot(int i, atomic_t *v)
-{
-       atomic_and(~i, v);
-}
-#define atomic_andnot atomic_andnot
-#endif
-
-#define arch_atomic_fetch_andnot atomic_fetch_andnot
-#define arch_atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire
-#define arch_atomic_fetch_andnot_release atomic_fetch_andnot_release
-#define arch_atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed
-
-#ifndef atomic_fetch_andnot_relaxed
-#ifdef atomic_fetch_andnot
-#define atomic_fetch_andnot_acquire atomic_fetch_andnot
-#define atomic_fetch_andnot_release atomic_fetch_andnot
-#define atomic_fetch_andnot_relaxed atomic_fetch_andnot
-#endif /* atomic_fetch_andnot */
-
-#ifndef atomic_fetch_andnot
-static __always_inline int
-atomic_fetch_andnot(int i, atomic_t *v)
-{
-       return atomic_fetch_and(~i, v);
-}
-#define atomic_fetch_andnot atomic_fetch_andnot
-#endif
-
-#ifndef atomic_fetch_andnot_acquire
-static __always_inline int
-atomic_fetch_andnot_acquire(int i, atomic_t *v)
-{
-       return atomic_fetch_and_acquire(~i, v);
-}
-#define atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire
-#endif
-
-#ifndef atomic_fetch_andnot_release
-static __always_inline int
-atomic_fetch_andnot_release(int i, atomic_t *v)
-{
-       return atomic_fetch_and_release(~i, v);
-}
-#define atomic_fetch_andnot_release atomic_fetch_andnot_release
-#endif
-
-#ifndef atomic_fetch_andnot_relaxed
-static __always_inline int
-atomic_fetch_andnot_relaxed(int i, atomic_t *v)
-{
-       return atomic_fetch_and_relaxed(~i, v);
-}
-#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed
-#endif
-
-#else /* atomic_fetch_andnot_relaxed */
-
-#ifndef atomic_fetch_andnot_acquire
-static __always_inline int
-atomic_fetch_andnot_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_andnot_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire
-#endif
-
-#ifndef atomic_fetch_andnot_release
-static __always_inline int
-atomic_fetch_andnot_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_andnot_relaxed(i, v);
-}
-#define atomic_fetch_andnot_release atomic_fetch_andnot_release
-#endif
-
-#ifndef atomic_fetch_andnot
-static __always_inline int
-atomic_fetch_andnot(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_andnot_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_andnot atomic_fetch_andnot
-#endif
-
-#endif /* atomic_fetch_andnot_relaxed */
-
-#define arch_atomic_or atomic_or
-
-#define arch_atomic_fetch_or atomic_fetch_or
-#define arch_atomic_fetch_or_acquire atomic_fetch_or_acquire
-#define arch_atomic_fetch_or_release atomic_fetch_or_release
-#define arch_atomic_fetch_or_relaxed atomic_fetch_or_relaxed
-
-#ifndef atomic_fetch_or_relaxed
-#define atomic_fetch_or_acquire atomic_fetch_or
-#define atomic_fetch_or_release atomic_fetch_or
-#define atomic_fetch_or_relaxed atomic_fetch_or
-#else /* atomic_fetch_or_relaxed */
-
-#ifndef atomic_fetch_or_acquire
-static __always_inline int
-atomic_fetch_or_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_or_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_or_acquire atomic_fetch_or_acquire
-#endif
-
-#ifndef atomic_fetch_or_release
-static __always_inline int
-atomic_fetch_or_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_or_relaxed(i, v);
-}
-#define atomic_fetch_or_release atomic_fetch_or_release
-#endif
-
-#ifndef atomic_fetch_or
-static __always_inline int
-atomic_fetch_or(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_or_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_or atomic_fetch_or
-#endif
-
-#endif /* atomic_fetch_or_relaxed */
-
-#define arch_atomic_xor atomic_xor
-
-#define arch_atomic_fetch_xor atomic_fetch_xor
-#define arch_atomic_fetch_xor_acquire atomic_fetch_xor_acquire
-#define arch_atomic_fetch_xor_release atomic_fetch_xor_release
-#define arch_atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
-
-#ifndef atomic_fetch_xor_relaxed
-#define atomic_fetch_xor_acquire atomic_fetch_xor
-#define atomic_fetch_xor_release atomic_fetch_xor
-#define atomic_fetch_xor_relaxed atomic_fetch_xor
-#else /* atomic_fetch_xor_relaxed */
-
-#ifndef atomic_fetch_xor_acquire
-static __always_inline int
-atomic_fetch_xor_acquire(int i, atomic_t *v)
-{
-       int ret = atomic_fetch_xor_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_fetch_xor_acquire atomic_fetch_xor_acquire
-#endif
-
-#ifndef atomic_fetch_xor_release
-static __always_inline int
-atomic_fetch_xor_release(int i, atomic_t *v)
-{
-       __atomic_release_fence();
-       return atomic_fetch_xor_relaxed(i, v);
-}
-#define atomic_fetch_xor_release atomic_fetch_xor_release
-#endif
-
-#ifndef atomic_fetch_xor
-static __always_inline int
-atomic_fetch_xor(int i, atomic_t *v)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_fetch_xor_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_fetch_xor atomic_fetch_xor
-#endif
-
-#endif /* atomic_fetch_xor_relaxed */
-
-#define arch_atomic_xchg atomic_xchg
-#define arch_atomic_xchg_acquire atomic_xchg_acquire
-#define arch_atomic_xchg_release atomic_xchg_release
-#define arch_atomic_xchg_relaxed atomic_xchg_relaxed
-
-#ifndef atomic_xchg_relaxed
-#define atomic_xchg_acquire atomic_xchg
-#define atomic_xchg_release atomic_xchg
-#define atomic_xchg_relaxed atomic_xchg
-#else /* atomic_xchg_relaxed */
-
-#ifndef atomic_xchg_acquire
-static __always_inline int
-atomic_xchg_acquire(atomic_t *v, int i)
-{
-       int ret = atomic_xchg_relaxed(v, i);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_xchg_acquire atomic_xchg_acquire
-#endif
-
-#ifndef atomic_xchg_release
-static __always_inline int
-atomic_xchg_release(atomic_t *v, int i)
-{
-       __atomic_release_fence();
-       return atomic_xchg_relaxed(v, i);
-}
-#define atomic_xchg_release atomic_xchg_release
-#endif
-
-#ifndef atomic_xchg
-static __always_inline int
-atomic_xchg(atomic_t *v, int i)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_xchg_relaxed(v, i);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_xchg atomic_xchg
-#endif
-
-#endif /* atomic_xchg_relaxed */
-
-#define arch_atomic_cmpxchg atomic_cmpxchg
-#define arch_atomic_cmpxchg_acquire atomic_cmpxchg_acquire
-#define arch_atomic_cmpxchg_release atomic_cmpxchg_release
-#define arch_atomic_cmpxchg_relaxed atomic_cmpxchg_relaxed
-
-#ifndef atomic_cmpxchg_relaxed
-#define atomic_cmpxchg_acquire atomic_cmpxchg
-#define atomic_cmpxchg_release atomic_cmpxchg
-#define atomic_cmpxchg_relaxed atomic_cmpxchg
-#else /* atomic_cmpxchg_relaxed */
-
-#ifndef atomic_cmpxchg_acquire
-static __always_inline int
-atomic_cmpxchg_acquire(atomic_t *v, int old, int new)
-{
-       int ret = atomic_cmpxchg_relaxed(v, old, new);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_cmpxchg_acquire atomic_cmpxchg_acquire
-#endif
-
-#ifndef atomic_cmpxchg_release
-static __always_inline int
-atomic_cmpxchg_release(atomic_t *v, int old, int new)
-{
-       __atomic_release_fence();
-       return atomic_cmpxchg_relaxed(v, old, new);
-}
-#define atomic_cmpxchg_release atomic_cmpxchg_release
-#endif
-
-#ifndef atomic_cmpxchg
-static __always_inline int
-atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-       int ret;
-       __atomic_pre_full_fence();
-       ret = atomic_cmpxchg_relaxed(v, old, new);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_cmpxchg atomic_cmpxchg
-#endif
-
-#endif /* atomic_cmpxchg_relaxed */
-
-#define arch_atomic_try_cmpxchg atomic_try_cmpxchg
-#define arch_atomic_try_cmpxchg_acquire atomic_try_cmpxchg_acquire
-#define arch_atomic_try_cmpxchg_release atomic_try_cmpxchg_release
-#define arch_atomic_try_cmpxchg_relaxed atomic_try_cmpxchg_relaxed
-
-#ifndef atomic_try_cmpxchg_relaxed
-#ifdef atomic_try_cmpxchg
-#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg
-#define atomic_try_cmpxchg_release atomic_try_cmpxchg
-#define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg
-#endif /* atomic_try_cmpxchg */
-
-#ifndef atomic_try_cmpxchg
-static __always_inline bool
-atomic_try_cmpxchg(atomic_t *v, int *old, int new)
-{
-       int r, o = *old;
-       r = atomic_cmpxchg(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic_try_cmpxchg atomic_try_cmpxchg
-#endif
-
-#ifndef atomic_try_cmpxchg_acquire
-static __always_inline bool
-atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
-{
-       int r, o = *old;
-       r = atomic_cmpxchg_acquire(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg_acquire
-#endif
-
-#ifndef atomic_try_cmpxchg_release
-static __always_inline bool
-atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
-{
-       int r, o = *old;
-       r = atomic_cmpxchg_release(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic_try_cmpxchg_release atomic_try_cmpxchg_release
-#endif
-
-#ifndef atomic_try_cmpxchg_relaxed
-static __always_inline bool
-atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
-{
-       int r, o = *old;
-       r = atomic_cmpxchg_relaxed(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic_try_cmpxchg_relaxed atomic_try_cmpxchg_relaxed
-#endif
-
-#else /* atomic_try_cmpxchg_relaxed */
-
-#ifndef atomic_try_cmpxchg_acquire
-static __always_inline bool
-atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
-{
-       bool ret = atomic_try_cmpxchg_relaxed(v, old, new);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic_try_cmpxchg_acquire atomic_try_cmpxchg_acquire
-#endif
-
-#ifndef atomic_try_cmpxchg_release
-static __always_inline bool
-atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
-{
-       __atomic_release_fence();
-       return atomic_try_cmpxchg_relaxed(v, old, new);
-}
-#define atomic_try_cmpxchg_release atomic_try_cmpxchg_release
-#endif
-
-#ifndef atomic_try_cmpxchg
-static __always_inline bool
-atomic_try_cmpxchg(atomic_t *v, int *old, int new)
-{
-       bool ret;
-       __atomic_pre_full_fence();
-       ret = atomic_try_cmpxchg_relaxed(v, old, new);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic_try_cmpxchg atomic_try_cmpxchg
-#endif
-
-#endif /* atomic_try_cmpxchg_relaxed */
-
-#define arch_atomic_sub_and_test atomic_sub_and_test
-
-#ifndef atomic_sub_and_test
-/**
- * atomic_sub_and_test - subtract value from variable and test result
- * @i: integer value to subtract
- * @v: pointer of type atomic_t
- *
- * Atomically subtracts @i from @v and returns
- * true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-atomic_sub_and_test(int i, atomic_t *v)
-{
-       return atomic_sub_return(i, v) == 0;
-}
-#define atomic_sub_and_test atomic_sub_and_test
-#endif
-
-#define arch_atomic_dec_and_test atomic_dec_and_test
-
-#ifndef atomic_dec_and_test
-/**
- * atomic_dec_and_test - decrement and test
- * @v: pointer of type atomic_t
- *
- * Atomically decrements @v by 1 and
- * returns true if the result is 0, or false for all other
- * cases.
- */
-static __always_inline bool
-atomic_dec_and_test(atomic_t *v)
-{
-       return atomic_dec_return(v) == 0;
-}
-#define atomic_dec_and_test atomic_dec_and_test
-#endif
-
-#define arch_atomic_inc_and_test atomic_inc_and_test
-
-#ifndef atomic_inc_and_test
-/**
- * atomic_inc_and_test - increment and test
- * @v: pointer of type atomic_t
- *
- * Atomically increments @v by 1
- * and returns true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-atomic_inc_and_test(atomic_t *v)
-{
-       return atomic_inc_return(v) == 0;
-}
-#define atomic_inc_and_test atomic_inc_and_test
-#endif
-
-#define arch_atomic_add_negative atomic_add_negative
-
-#ifndef atomic_add_negative
-/**
- * atomic_add_negative - add and test if negative
- * @i: integer value to add
- * @v: pointer of type atomic_t
- *
- * Atomically adds @i to @v and returns true
- * if the result is negative, or false when
- * result is greater than or equal to zero.
- */
-static __always_inline bool
-atomic_add_negative(int i, atomic_t *v)
-{
-       return atomic_add_return(i, v) < 0;
-}
-#define atomic_add_negative atomic_add_negative
-#endif
-
-#define arch_atomic_fetch_add_unless atomic_fetch_add_unless
-
-#ifndef atomic_fetch_add_unless
-/**
- * atomic_fetch_add_unless - add unless the number is already a given value
- * @v: pointer of type atomic_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, so long as @v was not already @u.
- * Returns original value of @v
- */
-static __always_inline int
-atomic_fetch_add_unless(atomic_t *v, int a, int u)
-{
-       int c = atomic_read(v);
-
-       do {
-               if (unlikely(c == u))
-                       break;
-       } while (!atomic_try_cmpxchg(v, &c, c + a));
-
-       return c;
-}
-#define atomic_fetch_add_unless atomic_fetch_add_unless
-#endif
-
-#define arch_atomic_add_unless atomic_add_unless
-
-#ifndef atomic_add_unless
-/**
- * atomic_add_unless - add unless the number is already a given value
- * @v: pointer of type atomic_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, if @v was not already @u.
- * Returns true if the addition was done.
- */
-static __always_inline bool
-atomic_add_unless(atomic_t *v, int a, int u)
-{
-       return atomic_fetch_add_unless(v, a, u) != u;
-}
-#define atomic_add_unless atomic_add_unless
-#endif
-
-#define arch_atomic_inc_not_zero atomic_inc_not_zero
-
-#ifndef atomic_inc_not_zero
-/**
- * atomic_inc_not_zero - increment unless the number is zero
- * @v: pointer of type atomic_t
- *
- * Atomically increments @v by 1, if @v is non-zero.
- * Returns true if the increment was done.
- */
-static __always_inline bool
-atomic_inc_not_zero(atomic_t *v)
-{
-       return atomic_add_unless(v, 1, 0);
-}
-#define atomic_inc_not_zero atomic_inc_not_zero
-#endif
-
-#define arch_atomic_inc_unless_negative atomic_inc_unless_negative
-
-#ifndef atomic_inc_unless_negative
-static __always_inline bool
-atomic_inc_unless_negative(atomic_t *v)
-{
-       int c = atomic_read(v);
-
-       do {
-               if (unlikely(c < 0))
-                       return false;
-       } while (!atomic_try_cmpxchg(v, &c, c + 1));
-
-       return true;
-}
-#define atomic_inc_unless_negative atomic_inc_unless_negative
-#endif
-
-#define arch_atomic_dec_unless_positive atomic_dec_unless_positive
-
-#ifndef atomic_dec_unless_positive
-static __always_inline bool
-atomic_dec_unless_positive(atomic_t *v)
-{
-       int c = atomic_read(v);
-
-       do {
-               if (unlikely(c > 0))
-                       return false;
-       } while (!atomic_try_cmpxchg(v, &c, c - 1));
-
-       return true;
-}
-#define atomic_dec_unless_positive atomic_dec_unless_positive
-#endif
-
-#define arch_atomic_dec_if_positive atomic_dec_if_positive
-
-#ifndef atomic_dec_if_positive
-static __always_inline int
-atomic_dec_if_positive(atomic_t *v)
-{
-       int dec, c = atomic_read(v);
-
-       do {
-               dec = c - 1;
-               if (unlikely(dec < 0))
-                       break;
-       } while (!atomic_try_cmpxchg(v, &c, dec));
-
-       return dec;
-}
-#define atomic_dec_if_positive atomic_dec_if_positive
-#endif
-
-#ifdef CONFIG_GENERIC_ATOMIC64
-#include <asm-generic/atomic64.h>
-#endif
-
-#define arch_atomic64_read atomic64_read
-#define arch_atomic64_read_acquire atomic64_read_acquire
-
-#ifndef atomic64_read_acquire
-static __always_inline s64
-atomic64_read_acquire(const atomic64_t *v)
-{
-       return smp_load_acquire(&(v)->counter);
-}
-#define atomic64_read_acquire atomic64_read_acquire
-#endif
-
-#define arch_atomic64_set atomic64_set
-#define arch_atomic64_set_release atomic64_set_release
-
-#ifndef atomic64_set_release
-static __always_inline void
-atomic64_set_release(atomic64_t *v, s64 i)
-{
-       smp_store_release(&(v)->counter, i);
-}
-#define atomic64_set_release atomic64_set_release
-#endif
-
-#define arch_atomic64_add atomic64_add
-
-#define arch_atomic64_add_return atomic64_add_return
-#define arch_atomic64_add_return_acquire atomic64_add_return_acquire
-#define arch_atomic64_add_return_release atomic64_add_return_release
-#define arch_atomic64_add_return_relaxed atomic64_add_return_relaxed
-
-#ifndef atomic64_add_return_relaxed
-#define atomic64_add_return_acquire atomic64_add_return
-#define atomic64_add_return_release atomic64_add_return
-#define atomic64_add_return_relaxed atomic64_add_return
-#else /* atomic64_add_return_relaxed */
-
-#ifndef atomic64_add_return_acquire
-static __always_inline s64
-atomic64_add_return_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_add_return_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_add_return_acquire atomic64_add_return_acquire
-#endif
-
-#ifndef atomic64_add_return_release
-static __always_inline s64
-atomic64_add_return_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_add_return_relaxed(i, v);
-}
-#define atomic64_add_return_release atomic64_add_return_release
-#endif
-
-#ifndef atomic64_add_return
-static __always_inline s64
-atomic64_add_return(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_add_return_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_add_return atomic64_add_return
-#endif
-
-#endif /* atomic64_add_return_relaxed */
-
-#define arch_atomic64_fetch_add atomic64_fetch_add
-#define arch_atomic64_fetch_add_acquire atomic64_fetch_add_acquire
-#define arch_atomic64_fetch_add_release atomic64_fetch_add_release
-#define arch_atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
-
-#ifndef atomic64_fetch_add_relaxed
-#define atomic64_fetch_add_acquire atomic64_fetch_add
-#define atomic64_fetch_add_release atomic64_fetch_add
-#define atomic64_fetch_add_relaxed atomic64_fetch_add
-#else /* atomic64_fetch_add_relaxed */
-
-#ifndef atomic64_fetch_add_acquire
-static __always_inline s64
-atomic64_fetch_add_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_add_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_add_acquire atomic64_fetch_add_acquire
-#endif
-
-#ifndef atomic64_fetch_add_release
-static __always_inline s64
-atomic64_fetch_add_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_add_relaxed(i, v);
-}
-#define atomic64_fetch_add_release atomic64_fetch_add_release
-#endif
-
-#ifndef atomic64_fetch_add
-static __always_inline s64
-atomic64_fetch_add(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_add_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_add atomic64_fetch_add
-#endif
-
-#endif /* atomic64_fetch_add_relaxed */
-
-#define arch_atomic64_sub atomic64_sub
-
-#define arch_atomic64_sub_return atomic64_sub_return
-#define arch_atomic64_sub_return_acquire atomic64_sub_return_acquire
-#define arch_atomic64_sub_return_release atomic64_sub_return_release
-#define arch_atomic64_sub_return_relaxed atomic64_sub_return_relaxed
-
-#ifndef atomic64_sub_return_relaxed
-#define atomic64_sub_return_acquire atomic64_sub_return
-#define atomic64_sub_return_release atomic64_sub_return
-#define atomic64_sub_return_relaxed atomic64_sub_return
-#else /* atomic64_sub_return_relaxed */
-
-#ifndef atomic64_sub_return_acquire
-static __always_inline s64
-atomic64_sub_return_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_sub_return_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_sub_return_acquire atomic64_sub_return_acquire
-#endif
-
-#ifndef atomic64_sub_return_release
-static __always_inline s64
-atomic64_sub_return_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_sub_return_relaxed(i, v);
-}
-#define atomic64_sub_return_release atomic64_sub_return_release
-#endif
-
-#ifndef atomic64_sub_return
-static __always_inline s64
-atomic64_sub_return(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_sub_return_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_sub_return atomic64_sub_return
-#endif
-
-#endif /* atomic64_sub_return_relaxed */
-
-#define arch_atomic64_fetch_sub atomic64_fetch_sub
-#define arch_atomic64_fetch_sub_acquire atomic64_fetch_sub_acquire
-#define arch_atomic64_fetch_sub_release atomic64_fetch_sub_release
-#define arch_atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
-
-#ifndef atomic64_fetch_sub_relaxed
-#define atomic64_fetch_sub_acquire atomic64_fetch_sub
-#define atomic64_fetch_sub_release atomic64_fetch_sub
-#define atomic64_fetch_sub_relaxed atomic64_fetch_sub
-#else /* atomic64_fetch_sub_relaxed */
-
-#ifndef atomic64_fetch_sub_acquire
-static __always_inline s64
-atomic64_fetch_sub_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_sub_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_sub_acquire atomic64_fetch_sub_acquire
-#endif
-
-#ifndef atomic64_fetch_sub_release
-static __always_inline s64
-atomic64_fetch_sub_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_sub_relaxed(i, v);
-}
-#define atomic64_fetch_sub_release atomic64_fetch_sub_release
-#endif
-
-#ifndef atomic64_fetch_sub
-static __always_inline s64
-atomic64_fetch_sub(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_sub_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_sub atomic64_fetch_sub
-#endif
-
-#endif /* atomic64_fetch_sub_relaxed */
-
-#define arch_atomic64_inc atomic64_inc
-
-#ifndef atomic64_inc
-static __always_inline void
-atomic64_inc(atomic64_t *v)
-{
-       atomic64_add(1, v);
-}
-#define atomic64_inc atomic64_inc
-#endif
-
-#define arch_atomic64_inc_return atomic64_inc_return
-#define arch_atomic64_inc_return_acquire atomic64_inc_return_acquire
-#define arch_atomic64_inc_return_release atomic64_inc_return_release
-#define arch_atomic64_inc_return_relaxed atomic64_inc_return_relaxed
-
-#ifndef atomic64_inc_return_relaxed
-#ifdef atomic64_inc_return
-#define atomic64_inc_return_acquire atomic64_inc_return
-#define atomic64_inc_return_release atomic64_inc_return
-#define atomic64_inc_return_relaxed atomic64_inc_return
-#endif /* atomic64_inc_return */
-
-#ifndef atomic64_inc_return
-static __always_inline s64
-atomic64_inc_return(atomic64_t *v)
-{
-       return atomic64_add_return(1, v);
-}
-#define atomic64_inc_return atomic64_inc_return
-#endif
-
-#ifndef atomic64_inc_return_acquire
-static __always_inline s64
-atomic64_inc_return_acquire(atomic64_t *v)
-{
-       return atomic64_add_return_acquire(1, v);
-}
-#define atomic64_inc_return_acquire atomic64_inc_return_acquire
-#endif
-
-#ifndef atomic64_inc_return_release
-static __always_inline s64
-atomic64_inc_return_release(atomic64_t *v)
-{
-       return atomic64_add_return_release(1, v);
-}
-#define atomic64_inc_return_release atomic64_inc_return_release
-#endif
-
-#ifndef atomic64_inc_return_relaxed
-static __always_inline s64
-atomic64_inc_return_relaxed(atomic64_t *v)
-{
-       return atomic64_add_return_relaxed(1, v);
-}
-#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
-#endif
-
-#else /* atomic64_inc_return_relaxed */
-
-#ifndef atomic64_inc_return_acquire
-static __always_inline s64
-atomic64_inc_return_acquire(atomic64_t *v)
-{
-       s64 ret = atomic64_inc_return_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_inc_return_acquire atomic64_inc_return_acquire
-#endif
-
-#ifndef atomic64_inc_return_release
-static __always_inline s64
-atomic64_inc_return_release(atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_inc_return_relaxed(v);
-}
-#define atomic64_inc_return_release atomic64_inc_return_release
-#endif
-
-#ifndef atomic64_inc_return
-static __always_inline s64
-atomic64_inc_return(atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_inc_return_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_inc_return atomic64_inc_return
-#endif
-
-#endif /* atomic64_inc_return_relaxed */
-
-#define arch_atomic64_fetch_inc atomic64_fetch_inc
-#define arch_atomic64_fetch_inc_acquire atomic64_fetch_inc_acquire
-#define arch_atomic64_fetch_inc_release atomic64_fetch_inc_release
-#define arch_atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed
-
-#ifndef atomic64_fetch_inc_relaxed
-#ifdef atomic64_fetch_inc
-#define atomic64_fetch_inc_acquire atomic64_fetch_inc
-#define atomic64_fetch_inc_release atomic64_fetch_inc
-#define atomic64_fetch_inc_relaxed atomic64_fetch_inc
-#endif /* atomic64_fetch_inc */
-
-#ifndef atomic64_fetch_inc
-static __always_inline s64
-atomic64_fetch_inc(atomic64_t *v)
-{
-       return atomic64_fetch_add(1, v);
-}
-#define atomic64_fetch_inc atomic64_fetch_inc
-#endif
-
-#ifndef atomic64_fetch_inc_acquire
-static __always_inline s64
-atomic64_fetch_inc_acquire(atomic64_t *v)
-{
-       return atomic64_fetch_add_acquire(1, v);
-}
-#define atomic64_fetch_inc_acquire atomic64_fetch_inc_acquire
-#endif
-
-#ifndef atomic64_fetch_inc_release
-static __always_inline s64
-atomic64_fetch_inc_release(atomic64_t *v)
-{
-       return atomic64_fetch_add_release(1, v);
-}
-#define atomic64_fetch_inc_release atomic64_fetch_inc_release
-#endif
-
-#ifndef atomic64_fetch_inc_relaxed
-static __always_inline s64
-atomic64_fetch_inc_relaxed(atomic64_t *v)
-{
-       return atomic64_fetch_add_relaxed(1, v);
-}
-#define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed
-#endif
-
-#else /* atomic64_fetch_inc_relaxed */
-
-#ifndef atomic64_fetch_inc_acquire
-static __always_inline s64
-atomic64_fetch_inc_acquire(atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_inc_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_inc_acquire atomic64_fetch_inc_acquire
-#endif
-
-#ifndef atomic64_fetch_inc_release
-static __always_inline s64
-atomic64_fetch_inc_release(atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_inc_relaxed(v);
-}
-#define atomic64_fetch_inc_release atomic64_fetch_inc_release
-#endif
-
-#ifndef atomic64_fetch_inc
-static __always_inline s64
-atomic64_fetch_inc(atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_inc_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_inc atomic64_fetch_inc
-#endif
-
-#endif /* atomic64_fetch_inc_relaxed */
-
-#define arch_atomic64_dec atomic64_dec
-
-#ifndef atomic64_dec
-static __always_inline void
-atomic64_dec(atomic64_t *v)
-{
-       atomic64_sub(1, v);
-}
-#define atomic64_dec atomic64_dec
-#endif
-
-#define arch_atomic64_dec_return atomic64_dec_return
-#define arch_atomic64_dec_return_acquire atomic64_dec_return_acquire
-#define arch_atomic64_dec_return_release atomic64_dec_return_release
-#define arch_atomic64_dec_return_relaxed atomic64_dec_return_relaxed
-
-#ifndef atomic64_dec_return_relaxed
-#ifdef atomic64_dec_return
-#define atomic64_dec_return_acquire atomic64_dec_return
-#define atomic64_dec_return_release atomic64_dec_return
-#define atomic64_dec_return_relaxed atomic64_dec_return
-#endif /* atomic64_dec_return */
-
-#ifndef atomic64_dec_return
-static __always_inline s64
-atomic64_dec_return(atomic64_t *v)
-{
-       return atomic64_sub_return(1, v);
-}
-#define atomic64_dec_return atomic64_dec_return
-#endif
-
-#ifndef atomic64_dec_return_acquire
-static __always_inline s64
-atomic64_dec_return_acquire(atomic64_t *v)
-{
-       return atomic64_sub_return_acquire(1, v);
-}
-#define atomic64_dec_return_acquire atomic64_dec_return_acquire
-#endif
-
-#ifndef atomic64_dec_return_release
-static __always_inline s64
-atomic64_dec_return_release(atomic64_t *v)
-{
-       return atomic64_sub_return_release(1, v);
-}
-#define atomic64_dec_return_release atomic64_dec_return_release
-#endif
-
-#ifndef atomic64_dec_return_relaxed
-static __always_inline s64
-atomic64_dec_return_relaxed(atomic64_t *v)
-{
-       return atomic64_sub_return_relaxed(1, v);
-}
-#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
-#endif
-
-#else /* atomic64_dec_return_relaxed */
-
-#ifndef atomic64_dec_return_acquire
-static __always_inline s64
-atomic64_dec_return_acquire(atomic64_t *v)
-{
-       s64 ret = atomic64_dec_return_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_dec_return_acquire atomic64_dec_return_acquire
-#endif
-
-#ifndef atomic64_dec_return_release
-static __always_inline s64
-atomic64_dec_return_release(atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_dec_return_relaxed(v);
-}
-#define atomic64_dec_return_release atomic64_dec_return_release
-#endif
-
-#ifndef atomic64_dec_return
-static __always_inline s64
-atomic64_dec_return(atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_dec_return_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_dec_return atomic64_dec_return
-#endif
-
-#endif /* atomic64_dec_return_relaxed */
-
-#define arch_atomic64_fetch_dec atomic64_fetch_dec
-#define arch_atomic64_fetch_dec_acquire atomic64_fetch_dec_acquire
-#define arch_atomic64_fetch_dec_release atomic64_fetch_dec_release
-#define arch_atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed
-
-#ifndef atomic64_fetch_dec_relaxed
-#ifdef atomic64_fetch_dec
-#define atomic64_fetch_dec_acquire atomic64_fetch_dec
-#define atomic64_fetch_dec_release atomic64_fetch_dec
-#define atomic64_fetch_dec_relaxed atomic64_fetch_dec
-#endif /* atomic64_fetch_dec */
-
-#ifndef atomic64_fetch_dec
-static __always_inline s64
-atomic64_fetch_dec(atomic64_t *v)
-{
-       return atomic64_fetch_sub(1, v);
-}
-#define atomic64_fetch_dec atomic64_fetch_dec
-#endif
-
-#ifndef atomic64_fetch_dec_acquire
-static __always_inline s64
-atomic64_fetch_dec_acquire(atomic64_t *v)
-{
-       return atomic64_fetch_sub_acquire(1, v);
-}
-#define atomic64_fetch_dec_acquire atomic64_fetch_dec_acquire
-#endif
-
-#ifndef atomic64_fetch_dec_release
-static __always_inline s64
-atomic64_fetch_dec_release(atomic64_t *v)
-{
-       return atomic64_fetch_sub_release(1, v);
-}
-#define atomic64_fetch_dec_release atomic64_fetch_dec_release
-#endif
-
-#ifndef atomic64_fetch_dec_relaxed
-static __always_inline s64
-atomic64_fetch_dec_relaxed(atomic64_t *v)
-{
-       return atomic64_fetch_sub_relaxed(1, v);
-}
-#define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed
-#endif
-
-#else /* atomic64_fetch_dec_relaxed */
-
-#ifndef atomic64_fetch_dec_acquire
-static __always_inline s64
-atomic64_fetch_dec_acquire(atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_dec_relaxed(v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_dec_acquire atomic64_fetch_dec_acquire
-#endif
-
-#ifndef atomic64_fetch_dec_release
-static __always_inline s64
-atomic64_fetch_dec_release(atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_dec_relaxed(v);
-}
-#define atomic64_fetch_dec_release atomic64_fetch_dec_release
-#endif
-
-#ifndef atomic64_fetch_dec
-static __always_inline s64
-atomic64_fetch_dec(atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_dec_relaxed(v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_dec atomic64_fetch_dec
-#endif
-
-#endif /* atomic64_fetch_dec_relaxed */
-
-#define arch_atomic64_and atomic64_and
-
-#define arch_atomic64_fetch_and atomic64_fetch_and
-#define arch_atomic64_fetch_and_acquire atomic64_fetch_and_acquire
-#define arch_atomic64_fetch_and_release atomic64_fetch_and_release
-#define arch_atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
-
-#ifndef atomic64_fetch_and_relaxed
-#define atomic64_fetch_and_acquire atomic64_fetch_and
-#define atomic64_fetch_and_release atomic64_fetch_and
-#define atomic64_fetch_and_relaxed atomic64_fetch_and
-#else /* atomic64_fetch_and_relaxed */
-
-#ifndef atomic64_fetch_and_acquire
-static __always_inline s64
-atomic64_fetch_and_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_and_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_and_acquire atomic64_fetch_and_acquire
-#endif
-
-#ifndef atomic64_fetch_and_release
-static __always_inline s64
-atomic64_fetch_and_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_and_relaxed(i, v);
-}
-#define atomic64_fetch_and_release atomic64_fetch_and_release
-#endif
-
-#ifndef atomic64_fetch_and
-static __always_inline s64
-atomic64_fetch_and(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_and_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_and atomic64_fetch_and
-#endif
-
-#endif /* atomic64_fetch_and_relaxed */
-
-#define arch_atomic64_andnot atomic64_andnot
-
-#ifndef atomic64_andnot
-static __always_inline void
-atomic64_andnot(s64 i, atomic64_t *v)
-{
-       atomic64_and(~i, v);
-}
-#define atomic64_andnot atomic64_andnot
-#endif
-
-#define arch_atomic64_fetch_andnot atomic64_fetch_andnot
-#define arch_atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire
-#define arch_atomic64_fetch_andnot_release atomic64_fetch_andnot_release
-#define arch_atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed
-
-#ifndef atomic64_fetch_andnot_relaxed
-#ifdef atomic64_fetch_andnot
-#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot
-#define atomic64_fetch_andnot_release atomic64_fetch_andnot
-#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot
-#endif /* atomic64_fetch_andnot */
-
-#ifndef atomic64_fetch_andnot
-static __always_inline s64
-atomic64_fetch_andnot(s64 i, atomic64_t *v)
-{
-       return atomic64_fetch_and(~i, v);
-}
-#define atomic64_fetch_andnot atomic64_fetch_andnot
-#endif
-
-#ifndef atomic64_fetch_andnot_acquire
-static __always_inline s64
-atomic64_fetch_andnot_acquire(s64 i, atomic64_t *v)
-{
-       return atomic64_fetch_and_acquire(~i, v);
-}
-#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire
-#endif
-
-#ifndef atomic64_fetch_andnot_release
-static __always_inline s64
-atomic64_fetch_andnot_release(s64 i, atomic64_t *v)
-{
-       return atomic64_fetch_and_release(~i, v);
-}
-#define atomic64_fetch_andnot_release atomic64_fetch_andnot_release
-#endif
-
-#ifndef atomic64_fetch_andnot_relaxed
-static __always_inline s64
-atomic64_fetch_andnot_relaxed(s64 i, atomic64_t *v)
-{
-       return atomic64_fetch_and_relaxed(~i, v);
-}
-#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed
-#endif
-
-#else /* atomic64_fetch_andnot_relaxed */
-
-#ifndef atomic64_fetch_andnot_acquire
-static __always_inline s64
-atomic64_fetch_andnot_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_andnot_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire
-#endif
-
-#ifndef atomic64_fetch_andnot_release
-static __always_inline s64
-atomic64_fetch_andnot_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_andnot_relaxed(i, v);
-}
-#define atomic64_fetch_andnot_release atomic64_fetch_andnot_release
-#endif
-
-#ifndef atomic64_fetch_andnot
-static __always_inline s64
-atomic64_fetch_andnot(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_andnot_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_andnot atomic64_fetch_andnot
-#endif
-
-#endif /* atomic64_fetch_andnot_relaxed */
-
-#define arch_atomic64_or atomic64_or
-
-#define arch_atomic64_fetch_or atomic64_fetch_or
-#define arch_atomic64_fetch_or_acquire atomic64_fetch_or_acquire
-#define arch_atomic64_fetch_or_release atomic64_fetch_or_release
-#define arch_atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed
-
-#ifndef atomic64_fetch_or_relaxed
-#define atomic64_fetch_or_acquire atomic64_fetch_or
-#define atomic64_fetch_or_release atomic64_fetch_or
-#define atomic64_fetch_or_relaxed atomic64_fetch_or
-#else /* atomic64_fetch_or_relaxed */
-
-#ifndef atomic64_fetch_or_acquire
-static __always_inline s64
-atomic64_fetch_or_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_or_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_or_acquire atomic64_fetch_or_acquire
-#endif
-
-#ifndef atomic64_fetch_or_release
-static __always_inline s64
-atomic64_fetch_or_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_or_relaxed(i, v);
-}
-#define atomic64_fetch_or_release atomic64_fetch_or_release
-#endif
-
-#ifndef atomic64_fetch_or
-static __always_inline s64
-atomic64_fetch_or(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_or_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_or atomic64_fetch_or
-#endif
-
-#endif /* atomic64_fetch_or_relaxed */
-
-#define arch_atomic64_xor atomic64_xor
-
-#define arch_atomic64_fetch_xor atomic64_fetch_xor
-#define arch_atomic64_fetch_xor_acquire atomic64_fetch_xor_acquire
-#define arch_atomic64_fetch_xor_release atomic64_fetch_xor_release
-#define arch_atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
-
-#ifndef atomic64_fetch_xor_relaxed
-#define atomic64_fetch_xor_acquire atomic64_fetch_xor
-#define atomic64_fetch_xor_release atomic64_fetch_xor
-#define atomic64_fetch_xor_relaxed atomic64_fetch_xor
-#else /* atomic64_fetch_xor_relaxed */
-
-#ifndef atomic64_fetch_xor_acquire
-static __always_inline s64
-atomic64_fetch_xor_acquire(s64 i, atomic64_t *v)
-{
-       s64 ret = atomic64_fetch_xor_relaxed(i, v);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_fetch_xor_acquire atomic64_fetch_xor_acquire
-#endif
-
-#ifndef atomic64_fetch_xor_release
-static __always_inline s64
-atomic64_fetch_xor_release(s64 i, atomic64_t *v)
-{
-       __atomic_release_fence();
-       return atomic64_fetch_xor_relaxed(i, v);
-}
-#define atomic64_fetch_xor_release atomic64_fetch_xor_release
-#endif
-
-#ifndef atomic64_fetch_xor
-static __always_inline s64
-atomic64_fetch_xor(s64 i, atomic64_t *v)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_fetch_xor_relaxed(i, v);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_fetch_xor atomic64_fetch_xor
-#endif
-
-#endif /* atomic64_fetch_xor_relaxed */
-
-#define arch_atomic64_xchg atomic64_xchg
-#define arch_atomic64_xchg_acquire atomic64_xchg_acquire
-#define arch_atomic64_xchg_release atomic64_xchg_release
-#define arch_atomic64_xchg_relaxed atomic64_xchg_relaxed
-
-#ifndef atomic64_xchg_relaxed
-#define atomic64_xchg_acquire atomic64_xchg
-#define atomic64_xchg_release atomic64_xchg
-#define atomic64_xchg_relaxed atomic64_xchg
-#else /* atomic64_xchg_relaxed */
-
-#ifndef atomic64_xchg_acquire
-static __always_inline s64
-atomic64_xchg_acquire(atomic64_t *v, s64 i)
-{
-       s64 ret = atomic64_xchg_relaxed(v, i);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_xchg_acquire atomic64_xchg_acquire
-#endif
-
-#ifndef atomic64_xchg_release
-static __always_inline s64
-atomic64_xchg_release(atomic64_t *v, s64 i)
-{
-       __atomic_release_fence();
-       return atomic64_xchg_relaxed(v, i);
-}
-#define atomic64_xchg_release atomic64_xchg_release
-#endif
-
-#ifndef atomic64_xchg
-static __always_inline s64
-atomic64_xchg(atomic64_t *v, s64 i)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_xchg_relaxed(v, i);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_xchg atomic64_xchg
-#endif
-
-#endif /* atomic64_xchg_relaxed */
-
-#define arch_atomic64_cmpxchg atomic64_cmpxchg
-#define arch_atomic64_cmpxchg_acquire atomic64_cmpxchg_acquire
-#define arch_atomic64_cmpxchg_release atomic64_cmpxchg_release
-#define arch_atomic64_cmpxchg_relaxed atomic64_cmpxchg_relaxed
-
-#ifndef atomic64_cmpxchg_relaxed
-#define atomic64_cmpxchg_acquire atomic64_cmpxchg
-#define atomic64_cmpxchg_release atomic64_cmpxchg
-#define atomic64_cmpxchg_relaxed atomic64_cmpxchg
-#else /* atomic64_cmpxchg_relaxed */
-
-#ifndef atomic64_cmpxchg_acquire
-static __always_inline s64
-atomic64_cmpxchg_acquire(atomic64_t *v, s64 old, s64 new)
-{
-       s64 ret = atomic64_cmpxchg_relaxed(v, old, new);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_cmpxchg_acquire atomic64_cmpxchg_acquire
-#endif
-
-#ifndef atomic64_cmpxchg_release
-static __always_inline s64
-atomic64_cmpxchg_release(atomic64_t *v, s64 old, s64 new)
-{
-       __atomic_release_fence();
-       return atomic64_cmpxchg_relaxed(v, old, new);
-}
-#define atomic64_cmpxchg_release atomic64_cmpxchg_release
-#endif
-
-#ifndef atomic64_cmpxchg
-static __always_inline s64
-atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
-{
-       s64 ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_cmpxchg_relaxed(v, old, new);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_cmpxchg atomic64_cmpxchg
-#endif
-
-#endif /* atomic64_cmpxchg_relaxed */
-
-#define arch_atomic64_try_cmpxchg atomic64_try_cmpxchg
-#define arch_atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg_acquire
-#define arch_atomic64_try_cmpxchg_release atomic64_try_cmpxchg_release
-#define arch_atomic64_try_cmpxchg_relaxed atomic64_try_cmpxchg_relaxed
-
-#ifndef atomic64_try_cmpxchg_relaxed
-#ifdef atomic64_try_cmpxchg
-#define atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg
-#define atomic64_try_cmpxchg_release atomic64_try_cmpxchg
-#define atomic64_try_cmpxchg_relaxed atomic64_try_cmpxchg
-#endif /* atomic64_try_cmpxchg */
-
-#ifndef atomic64_try_cmpxchg
-static __always_inline bool
-atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
-{
-       s64 r, o = *old;
-       r = atomic64_cmpxchg(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic64_try_cmpxchg atomic64_try_cmpxchg
-#endif
-
-#ifndef atomic64_try_cmpxchg_acquire
-static __always_inline bool
-atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
-{
-       s64 r, o = *old;
-       r = atomic64_cmpxchg_acquire(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg_acquire
-#endif
-
-#ifndef atomic64_try_cmpxchg_release
-static __always_inline bool
-atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
-{
-       s64 r, o = *old;
-       r = atomic64_cmpxchg_release(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic64_try_cmpxchg_release atomic64_try_cmpxchg_release
-#endif
-
-#ifndef atomic64_try_cmpxchg_relaxed
-static __always_inline bool
-atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
-{
-       s64 r, o = *old;
-       r = atomic64_cmpxchg_relaxed(v, o, new);
-       if (unlikely(r != o))
-               *old = r;
-       return likely(r == o);
-}
-#define atomic64_try_cmpxchg_relaxed atomic64_try_cmpxchg_relaxed
-#endif
-
-#else /* atomic64_try_cmpxchg_relaxed */
-
-#ifndef atomic64_try_cmpxchg_acquire
-static __always_inline bool
-atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
-{
-       bool ret = atomic64_try_cmpxchg_relaxed(v, old, new);
-       __atomic_acquire_fence();
-       return ret;
-}
-#define atomic64_try_cmpxchg_acquire atomic64_try_cmpxchg_acquire
-#endif
-
-#ifndef atomic64_try_cmpxchg_release
-static __always_inline bool
-atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
-{
-       __atomic_release_fence();
-       return atomic64_try_cmpxchg_relaxed(v, old, new);
-}
-#define atomic64_try_cmpxchg_release atomic64_try_cmpxchg_release
-#endif
-
-#ifndef atomic64_try_cmpxchg
-static __always_inline bool
-atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
-{
-       bool ret;
-       __atomic_pre_full_fence();
-       ret = atomic64_try_cmpxchg_relaxed(v, old, new);
-       __atomic_post_full_fence();
-       return ret;
-}
-#define atomic64_try_cmpxchg atomic64_try_cmpxchg
-#endif
-
-#endif /* atomic64_try_cmpxchg_relaxed */
-
-#define arch_atomic64_sub_and_test atomic64_sub_and_test
-
-#ifndef atomic64_sub_and_test
-/**
- * atomic64_sub_and_test - subtract value from variable and test result
- * @i: integer value to subtract
- * @v: pointer of type atomic64_t
- *
- * Atomically subtracts @i from @v and returns
- * true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-atomic64_sub_and_test(s64 i, atomic64_t *v)
-{
-       return atomic64_sub_return(i, v) == 0;
-}
-#define atomic64_sub_and_test atomic64_sub_and_test
-#endif
-
-#define arch_atomic64_dec_and_test atomic64_dec_and_test
-
-#ifndef atomic64_dec_and_test
-/**
- * atomic64_dec_and_test - decrement and test
- * @v: pointer of type atomic64_t
- *
- * Atomically decrements @v by 1 and
- * returns true if the result is 0, or false for all other
- * cases.
- */
-static __always_inline bool
-atomic64_dec_and_test(atomic64_t *v)
-{
-       return atomic64_dec_return(v) == 0;
-}
-#define atomic64_dec_and_test atomic64_dec_and_test
-#endif
-
-#define arch_atomic64_inc_and_test atomic64_inc_and_test
-
-#ifndef atomic64_inc_and_test
-/**
- * atomic64_inc_and_test - increment and test
- * @v: pointer of type atomic64_t
- *
- * Atomically increments @v by 1
- * and returns true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-atomic64_inc_and_test(atomic64_t *v)
-{
-       return atomic64_inc_return(v) == 0;
-}
-#define atomic64_inc_and_test atomic64_inc_and_test
-#endif
-
-#define arch_atomic64_add_negative atomic64_add_negative
-
-#ifndef atomic64_add_negative
-/**
- * atomic64_add_negative - add and test if negative
- * @i: integer value to add
- * @v: pointer of type atomic64_t
- *
- * Atomically adds @i to @v and returns true
- * if the result is negative, or false when
- * result is greater than or equal to zero.
- */
-static __always_inline bool
-atomic64_add_negative(s64 i, atomic64_t *v)
-{
-       return atomic64_add_return(i, v) < 0;
-}
-#define atomic64_add_negative atomic64_add_negative
-#endif
-
-#define arch_atomic64_fetch_add_unless atomic64_fetch_add_unless
-
-#ifndef atomic64_fetch_add_unless
-/**
- * atomic64_fetch_add_unless - add unless the number is already a given value
- * @v: pointer of type atomic64_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, so long as @v was not already @u.
- * Returns original value of @v
- */
-static __always_inline s64
-atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
-{
-       s64 c = atomic64_read(v);
-
-       do {
-               if (unlikely(c == u))
-                       break;
-       } while (!atomic64_try_cmpxchg(v, &c, c + a));
-
-       return c;
-}
-#define atomic64_fetch_add_unless atomic64_fetch_add_unless
-#endif
-
-#define arch_atomic64_add_unless atomic64_add_unless
-
-#ifndef atomic64_add_unless
-/**
- * atomic64_add_unless - add unless the number is already a given value
- * @v: pointer of type atomic64_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, if @v was not already @u.
- * Returns true if the addition was done.
- */
-static __always_inline bool
-atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
-{
-       return atomic64_fetch_add_unless(v, a, u) != u;
-}
-#define atomic64_add_unless atomic64_add_unless
-#endif
-
-#define arch_atomic64_inc_not_zero atomic64_inc_not_zero
-
-#ifndef atomic64_inc_not_zero
-/**
- * atomic64_inc_not_zero - increment unless the number is zero
- * @v: pointer of type atomic64_t
- *
- * Atomically increments @v by 1, if @v is non-zero.
- * Returns true if the increment was done.
- */
-static __always_inline bool
-atomic64_inc_not_zero(atomic64_t *v)
-{
-       return atomic64_add_unless(v, 1, 0);
-}
-#define atomic64_inc_not_zero atomic64_inc_not_zero
-#endif
-
-#define arch_atomic64_inc_unless_negative atomic64_inc_unless_negative
-
-#ifndef atomic64_inc_unless_negative
-static __always_inline bool
-atomic64_inc_unless_negative(atomic64_t *v)
-{
-       s64 c = atomic64_read(v);
-
-       do {
-               if (unlikely(c < 0))
-                       return false;
-       } while (!atomic64_try_cmpxchg(v, &c, c + 1));
-
-       return true;
-}
-#define atomic64_inc_unless_negative atomic64_inc_unless_negative
-#endif
-
-#define arch_atomic64_dec_unless_positive atomic64_dec_unless_positive
-
-#ifndef atomic64_dec_unless_positive
-static __always_inline bool
-atomic64_dec_unless_positive(atomic64_t *v)
-{
-       s64 c = atomic64_read(v);
-
-       do {
-               if (unlikely(c > 0))
-                       return false;
-       } while (!atomic64_try_cmpxchg(v, &c, c - 1));
-
-       return true;
-}
-#define atomic64_dec_unless_positive atomic64_dec_unless_positive
-#endif
-
-#define arch_atomic64_dec_if_positive atomic64_dec_if_positive
-
-#ifndef atomic64_dec_if_positive
-static __always_inline s64
-atomic64_dec_if_positive(atomic64_t *v)
-{
-       s64 dec, c = atomic64_read(v);
-
-       do {
-               dec = c - 1;
-               if (unlikely(dec < 0))
-                       break;
-       } while (!atomic64_try_cmpxchg(v, &c, dec));
-
-       return dec;
-}
-#define atomic64_dec_if_positive atomic64_dec_if_positive
-#endif
-
-#endif /* _LINUX_ATOMIC_FALLBACK_H */
-// d78e6c293c661c15188f0ec05bce45188c8d5892
index 571a110..ed1d3ff 100644 (file)
        __ret;                                                          \
 })
 
-#ifdef ARCH_ATOMIC
 #include <linux/atomic-arch-fallback.h>
 #include <asm-generic/atomic-instrumented.h>
-#else
-#include <linux/atomic-fallback.h>
-#endif
 
 #include <asm-generic/atomic-long.h>
 
index 71b5d48..6b138fa 100644 (file)
@@ -50,7 +50,7 @@ struct ceph_auth_client_ops {
         * another request.
         */
        int (*build_request)(struct ceph_auth_client *ac, void *buf, void *end);
-       int (*handle_reply)(struct ceph_auth_client *ac, int result,
+       int (*handle_reply)(struct ceph_auth_client *ac, u64 global_id,
                            void *buf, void *end, u8 *session_key,
                            int *session_key_len, u8 *con_secret,
                            int *con_secret_len);
@@ -104,6 +104,8 @@ struct ceph_auth_client {
        struct mutex mutex;
 };
 
+void ceph_auth_set_global_id(struct ceph_auth_client *ac, u64 global_id);
+
 struct ceph_auth_client *ceph_auth_init(const char *name,
                                        const struct ceph_crypto_key *key,
                                        const int *con_modes);
index d6ab416..1d42d4b 100644 (file)
@@ -43,6 +43,8 @@ struct module;
  * @shift:             Cycle to nanosecond divisor (power of two)
  * @max_idle_ns:       Maximum idle time permitted by the clocksource (nsecs)
  * @maxadj:            Maximum adjustment value to mult (~11%)
+ * @uncertainty_margin:        Maximum uncertainty in nanoseconds per half second.
+ *                     Zero says to use default WATCHDOG_THRESHOLD.
  * @archdata:          Optional arch-specific data
  * @max_cycles:                Maximum safe cycle value which won't overflow on
  *                     multiplication
@@ -98,6 +100,7 @@ struct clocksource {
        u32                     shift;
        u64                     max_idle_ns;
        u32                     maxadj;
+       u32                     uncertainty_margin;
 #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
        struct arch_clocksource_data archdata;
 #endif
@@ -137,7 +140,7 @@ struct clocksource {
 #define CLOCK_SOURCE_UNSTABLE                  0x40
 #define CLOCK_SOURCE_SUSPEND_NONSTOP           0x80
 #define CLOCK_SOURCE_RESELECT                  0x100
-
+#define CLOCK_SOURCE_VERIFY_PERCPU             0x200
 /* simplify initialization of mask field */
 #define CLOCKSOURCE_MASK(bits) GENMASK_ULL((bits) - 1, 0)
 
@@ -288,4 +291,7 @@ static inline void timer_probe(void) {}
 #define TIMER_ACPI_DECLARE(name, table_id, fn)         \
        ACPI_DECLARE_PROBE_ENTRY(timer, name, table_id, 0, NULL, 0, fn)
 
+extern ulong max_cswd_read_retries;
+void clocksource_verify_percpu(struct clocksource *cs);
+
 #endif /* _LINUX_CLOCKSOURCE_H */
index df5b405..7704790 100644 (file)
@@ -115,18 +115,24 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  * The __COUNTER__ based labels are a hack to make each instance of the macros
  * unique, to convince GCC not to merge duplicate inline asm statements.
  */
-#define annotate_reachable() ({                                                \
-       asm volatile("%c0:\n\t"                                         \
+#define __stringify_label(n) #n
+
+#define __annotate_reachable(c) ({                                     \
+       asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.reachable\n\t"              \
-                    ".long %c0b - .\n\t"                               \
-                    ".popsection\n\t" : : "i" (__COUNTER__));          \
+                    ".long " __stringify_label(c) "b - .\n\t"          \
+                    ".popsection\n\t");                                \
 })
-#define annotate_unreachable() ({                                      \
-       asm volatile("%c0:\n\t"                                         \
+#define annotate_reachable() __annotate_reachable(__COUNTER__)
+
+#define __annotate_unreachable(c) ({                                   \
+       asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.unreachable\n\t"            \
-                    ".long %c0b - .\n\t"                               \
-                    ".popsection\n\t" : : "i" (__COUNTER__));          \
+                    ".long " __stringify_label(c) "b - .\n\t"          \
+                    ".popsection\n\t");                                \
 })
+#define annotate_unreachable() __annotate_unreachable(__COUNTER__)
+
 #define ASM_UNREACHABLE                                                        \
        "999:\n\t"                                                      \
        ".pushsection .discard.unreachable\n\t"                         \
index 1497132..fcbc688 100644 (file)
@@ -143,6 +143,7 @@ struct cred {
 #endif
        struct user_struct *user;       /* real user ID subscription */
        struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
+       struct ucounts *ucounts;
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
        /* RCU deletion */
        union {
@@ -169,6 +170,7 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
 extern int set_create_files_as(struct cred *, struct inode *);
 extern int cred_fscmp(const struct cred *, const struct cred *);
 extern void __init cred_init(void);
+extern int set_cred_ucounts(struct cred *);
 
 /*
  * check for validity of credentials
@@ -369,6 +371,7 @@ static inline void put_cred(const struct cred *_cred)
 
 #define task_uid(task)         (task_cred_xxx((task), uid))
 #define task_euid(task)                (task_cred_xxx((task), euid))
+#define task_ucounts(task)     (task_cred_xxx((task), ucounts))
 
 #define current_cred_xxx(xxx)                  \
 ({                                             \
@@ -385,6 +388,7 @@ static inline void put_cred(const struct cred *_cred)
 #define current_fsgid()        (current_cred_xxx(fsgid))
 #define current_cap()          (current_cred_xxx(cap_effective))
 #define current_user()         (current_cred_xxx(user))
+#define current_ucounts()      (current_cred_xxx(ucounts))
 
 extern struct user_namespace init_user_ns;
 #ifdef CONFIG_USER_NS
index da5e0d7..855869e 100644 (file)
@@ -643,32 +643,6 @@ struct crypto_comp {
        struct crypto_tfm base;
 };
 
-enum {
-       CRYPTOA_UNSPEC,
-       CRYPTOA_ALG,
-       CRYPTOA_TYPE,
-       CRYPTOA_U32,
-       __CRYPTOA_MAX,
-};
-
-#define CRYPTOA_MAX (__CRYPTOA_MAX - 1)
-
-/* Maximum number of (rtattr) parameters for each template. */
-#define CRYPTO_MAX_ATTRS 32
-
-struct crypto_attr_alg {
-       char name[CRYPTO_MAX_ALG_NAME];
-};
-
-struct crypto_attr_type {
-       u32 type;
-       u32 mask;
-};
-
-struct crypto_attr_u32 {
-       u32 num;
-};
-
 /* 
  * Transform user interface.
  */
index 2915f56..edb5c18 100644 (file)
@@ -27,8 +27,10 @@ extern int debug_locks_off(void);
        int __ret = 0;                                                  \
                                                                        \
        if (!oops_in_progress && unlikely(c)) {                         \
+               instrumentation_begin();                                \
                if (debug_locks_off() && !debug_locks_silent)           \
                        WARN(1, "DEBUG_LOCKS_WARN_ON(%s)", #c);         \
+               instrumentation_end();                                  \
                __ret = 1;                                              \
        }                                                               \
        __ret;                                                          \
index 21651f9..af7e6eb 100644 (file)
@@ -58,16 +58,22 @@ struct task_delay_info {
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/jump_label.h>
 
 #ifdef CONFIG_TASK_DELAY_ACCT
+DECLARE_STATIC_KEY_FALSE(delayacct_key);
 extern int delayacct_on;       /* Delay accounting turned on/off */
 extern struct kmem_cache *delayacct_cache;
 extern void delayacct_init(void);
+
+extern int sysctl_delayacct(struct ctl_table *table, int write, void *buffer,
+                           size_t *lenp, loff_t *ppos);
+
 extern void __delayacct_tsk_init(struct task_struct *);
 extern void __delayacct_tsk_exit(struct task_struct *);
 extern void __delayacct_blkio_start(void);
 extern void __delayacct_blkio_end(struct task_struct *);
-extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *);
+extern int delayacct_add_tsk(struct taskstats *, struct task_struct *);
 extern __u64 __delayacct_blkio_ticks(struct task_struct *);
 extern void __delayacct_freepages_start(void);
 extern void __delayacct_freepages_end(void);
@@ -114,6 +120,9 @@ static inline void delayacct_tsk_free(struct task_struct *tsk)
 
 static inline void delayacct_blkio_start(void)
 {
+       if (!static_branch_unlikely(&delayacct_key))
+               return;
+
        delayacct_set_flag(current, DELAYACCT_PF_BLKIO);
        if (current->delays)
                __delayacct_blkio_start();
@@ -121,19 +130,14 @@ static inline void delayacct_blkio_start(void)
 
 static inline void delayacct_blkio_end(struct task_struct *p)
 {
+       if (!static_branch_unlikely(&delayacct_key))
+               return;
+
        if (p->delays)
                __delayacct_blkio_end(p);
        delayacct_clear_flag(p, DELAYACCT_PF_BLKIO);
 }
 
-static inline int delayacct_add_tsk(struct taskstats *d,
-                                       struct task_struct *tsk)
-{
-       if (!delayacct_on || !tsk->delays)
-               return 0;
-       return __delayacct_add_tsk(d, tsk);
-}
-
 static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk)
 {
        if (tsk->delays)
index 6f00955..82d3d46 100644 (file)
@@ -236,7 +236,7 @@ do {                                                                        \
  * using WARN/WARN_ONCE to include file/line information and a backtrace.
  */
 #define dev_WARN(dev, format, arg...) \
-       WARN(1, "%s %s: " format, dev_driver_string(dev), dev_name(dev), ## arg);
+       WARN(1, "%s %s: " format, dev_driver_string(dev), dev_name(dev), ## arg)
 
 #define dev_WARN_ONCE(dev, condition, format, arg...) \
        WARN_ONCE(condition, "%s %s: " format, \
index f1a0004..959cb9d 100644 (file)
@@ -399,7 +399,7 @@ struct dev_links_info {
  *             along with subsystem-level and driver-level callbacks.
  * @em_pd:     device's energy model performance domain
  * @pins:      For device pin management.
- *             See Documentation/driver-api/pinctl.rst for details.
+ *             See Documentation/driver-api/pin-control.rst for details.
  * @msi_list:  Hosts MSI descriptors
  * @msi_domain: The generic MSI domain this device is using.
  * @numa_node: NUMA node this device is close to.
index 757fc60..3f221db 100644 (file)
@@ -91,6 +91,8 @@ void em_dev_unregister_perf_domain(struct device *dev);
  * @pd         : performance domain for which energy has to be estimated
  * @max_util   : highest utilization among CPUs of the domain
  * @sum_util   : sum of the utilization of all CPUs in the domain
+ * @allowed_cpu_cap    : maximum allowed CPU capacity for the @pd, which
+                         might reflect reduced frequency (due to thermal)
  *
  * This function must be used only for CPU devices. There is no validation,
  * i.e. if the EM is a CPU type and has cpumask allocated. It is called from
@@ -100,7 +102,8 @@ void em_dev_unregister_perf_domain(struct device *dev);
  * a capacity state satisfying the max utilization of the domain.
  */
 static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
-                               unsigned long max_util, unsigned long sum_util)
+                               unsigned long max_util, unsigned long sum_util,
+                               unsigned long allowed_cpu_cap)
 {
        unsigned long freq, scale_cpu;
        struct em_perf_state *ps;
@@ -112,11 +115,17 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
        /*
         * In order to predict the performance state, map the utilization of
         * the most utilized CPU of the performance domain to a requested
-        * frequency, like schedutil.
+        * frequency, like schedutil. Take also into account that the real
+        * frequency might be set lower (due to thermal capping). Thus, clamp
+        * max utilization to the allowed CPU capacity before calculating
+        * effective frequency.
         */
        cpu = cpumask_first(to_cpumask(pd->cpus));
        scale_cpu = arch_scale_cpu_capacity(cpu);
        ps = &pd->table[pd->nr_perf_states - 1];
+
+       max_util = map_util_perf(max_util);
+       max_util = min(max_util, allowed_cpu_cap);
        freq = map_util_freq(max_util, ps->frequency, scale_cpu);
 
        /*
@@ -209,7 +218,8 @@ static inline struct em_perf_domain *em_pd_get(struct device *dev)
        return NULL;
 }
 static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
-                       unsigned long max_util, unsigned long sum_util)
+                       unsigned long max_util, unsigned long sum_util,
+                       unsigned long allowed_cpu_cap)
 {
        return 0;
 }
index 8302bc2..4c374be 100644 (file)
@@ -23,18 +23,25 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
                                             struct integrity_iint_cache *iint);
 extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr);
 extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
-extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
+extern int evm_inode_setxattr(struct user_namespace *mnt_userns,
+                             struct dentry *dentry, const char *name,
                              const void *value, size_t size);
 extern void evm_inode_post_setxattr(struct dentry *dentry,
                                    const char *xattr_name,
                                    const void *xattr_value,
                                    size_t xattr_value_len);
-extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
+extern int evm_inode_removexattr(struct user_namespace *mnt_userns,
+                                struct dentry *dentry, const char *xattr_name);
 extern void evm_inode_post_removexattr(struct dentry *dentry,
                                       const char *xattr_name);
 extern int evm_inode_init_security(struct inode *inode,
                                   const struct xattr *xattr_array,
                                   struct xattr *evm);
+extern bool evm_revalidate_status(const char *xattr_name);
+extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
+extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
+                                    int buffer_size, char type,
+                                    bool canonical_fmt);
 #ifdef CONFIG_FS_POSIX_ACL
 extern int posix_xattr_acl(const char *xattrname);
 #else
@@ -71,7 +78,8 @@ static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
        return;
 }
 
-static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
+static inline int evm_inode_setxattr(struct user_namespace *mnt_userns,
+                                    struct dentry *dentry, const char *name,
                                     const void *value, size_t size)
 {
        return 0;
@@ -85,7 +93,8 @@ static inline void evm_inode_post_setxattr(struct dentry *dentry,
        return;
 }
 
-static inline int evm_inode_removexattr(struct dentry *dentry,
+static inline int evm_inode_removexattr(struct user_namespace *mnt_userns,
+                                       struct dentry *dentry,
                                        const char *xattr_name)
 {
        return 0;
@@ -104,5 +113,22 @@ static inline int evm_inode_init_security(struct inode *inode,
        return 0;
 }
 
+static inline bool evm_revalidate_status(const char *xattr_name)
+{
+       return false;
+}
+
+static inline int evm_protected_xattr_if_enabled(const char *req_xattr_name)
+{
+       return false;
+}
+
+static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
+                                           int buffer_size, char type,
+                                           bool canonical_fmt)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif /* CONFIG_EVM */
 #endif /* LINUX_EVM_H */
index 11da8af..e6102df 100644 (file)
@@ -53,8 +53,10 @@ struct vm_area_struct;
 #define ___GFP_HARDWALL                0x100000u
 #define ___GFP_THISNODE                0x200000u
 #define ___GFP_ACCOUNT         0x400000u
+#define ___GFP_ZEROTAGS                0x800000u
+#define ___GFP_SKIP_KASAN_POISON       0x1000000u
 #ifdef CONFIG_LOCKDEP
-#define ___GFP_NOLOCKDEP       0x800000u
+#define ___GFP_NOLOCKDEP       0x2000000u
 #else
 #define ___GFP_NOLOCKDEP       0
 #endif
@@ -229,16 +231,25 @@ struct vm_area_struct;
  * %__GFP_COMP address compound page metadata.
  *
  * %__GFP_ZERO returns a zeroed page on success.
+ *
+ * %__GFP_ZEROTAGS returns a page with zeroed memory tags on success, if
+ * __GFP_ZERO is set.
+ *
+ * %__GFP_SKIP_KASAN_POISON returns a page which does not need to be poisoned
+ * on deallocation. Typically used for userspace pages. Currently only has an
+ * effect in HW tags mode.
  */
 #define __GFP_NOWARN   ((__force gfp_t)___GFP_NOWARN)
 #define __GFP_COMP     ((__force gfp_t)___GFP_COMP)
 #define __GFP_ZERO     ((__force gfp_t)___GFP_ZERO)
+#define __GFP_ZEROTAGS ((__force gfp_t)___GFP_ZEROTAGS)
+#define __GFP_SKIP_KASAN_POISON        ((__force gfp_t)___GFP_SKIP_KASAN_POISON)
 
 /* Disable lockdep for GFP context tracking */
 #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP)
 
 /* Room for N __GFP_FOO bits */
-#define __GFP_BITS_SHIFT (23 + IS_ENABLED(CONFIG_LOCKDEP))
+#define __GFP_BITS_SHIFT (25 + IS_ENABLED(CONFIG_LOCKDEP))
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /**
@@ -319,7 +330,8 @@ struct vm_area_struct;
 #define GFP_DMA                __GFP_DMA
 #define GFP_DMA32      __GFP_DMA32
 #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
-#define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE)
+#define GFP_HIGHUSER_MOVABLE   (GFP_HIGHUSER | __GFP_MOVABLE | \
+                        __GFP_SKIP_KASAN_POISON)
 #define GFP_TRANSHUGE_LIGHT    ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
                         __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM)
 #define GFP_TRANSHUGE  (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)
index 832b49b..8c6e8e9 100644 (file)
@@ -152,28 +152,24 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
 }
 #endif
 
-#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE
 /**
- * __alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA with caller-specified movable GFP flags
- * @movableflags: The GFP flags related to the pages future ability to move like __GFP_MOVABLE
+ * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
  * @vma: The VMA the page is to be allocated for
  * @vaddr: The virtual address the page will be inserted into
  *
- * This function will allocate a page for a VMA but the caller is expected
- * to specify via movableflags whether the page will be movable in the
- * future or not
+ * This function will allocate a page for a VMA that the caller knows will
+ * be able to migrate in the future using move_pages() or reclaimed
  *
  * An architecture may override this function by defining
- * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE and providing their own
+ * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE and providing their own
  * implementation.
  */
 static inline struct page *
-__alloc_zeroed_user_highpage(gfp_t movableflags,
-                       struct vm_area_struct *vma,
-                       unsigned long vaddr)
+alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+                                  unsigned long vaddr)
 {
-       struct page *page = alloc_page_vma(GFP_HIGHUSER | movableflags,
-                       vma, vaddr);
+       struct page *page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
 
        if (page)
                clear_user_highpage(page, vaddr);
@@ -182,21 +178,6 @@ __alloc_zeroed_user_highpage(gfp_t movableflags,
 }
 #endif
 
-/**
- * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
- * @vma: The VMA the page is to be allocated for
- * @vaddr: The virtual address the page will be inserted into
- *
- * This function will allocate a page for a VMA that the caller knows will
- * be able to migrate in the future using move_pages() or reclaimed
- */
-static inline struct page *
-alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
-                                       unsigned long vaddr)
-{
-       return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
-}
-
 static inline void clear_highpage(struct page *page)
 {
        void *kaddr = kmap_atomic(page);
@@ -204,6 +185,14 @@ static inline void clear_highpage(struct page *page)
        kunmap_atomic(kaddr);
 }
 
+#ifndef __HAVE_ARCH_TAG_CLEAR_HIGHPAGE
+
+static inline void tag_clear_highpage(struct page *page)
+{
+}
+
+#endif
+
 /*
  * If we pass in a base or tail page, we can zero up to PAGE_SIZE.
  * If we pass in a head page, we can zero up to the size of the compound page.
index 9626fda..2a8ebe6 100644 (file)
@@ -286,6 +286,7 @@ struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr,
 vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t orig_pmd);
 
 extern struct page *huge_zero_page;
+extern unsigned long huge_zero_pfn;
 
 static inline bool is_huge_zero_page(struct page *page)
 {
@@ -294,7 +295,7 @@ static inline bool is_huge_zero_page(struct page *page)
 
 static inline bool is_huge_zero_pmd(pmd_t pmd)
 {
-       return is_huge_zero_page(pmd_page(pmd));
+       return READ_ONCE(huge_zero_pfn) == pmd_pfn(pmd) && pmd_present(pmd);
 }
 
 static inline bool is_huge_zero_pud(pud_t pud)
@@ -440,6 +441,11 @@ static inline bool is_huge_zero_page(struct page *page)
        return false;
 }
 
+static inline bool is_huge_zero_pmd(pmd_t pmd)
+{
+       return false;
+}
+
 static inline bool is_huge_zero_pud(pud_t pud)
 {
        return false;
index b92f25c..8ba79dc 100644 (file)
@@ -149,6 +149,7 @@ bool hugetlb_reserve_pages(struct inode *inode, long from, long to,
 long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
                                                long freed);
 bool isolate_huge_page(struct page *page, struct list_head *list);
+int get_hwpoison_huge_page(struct page *page, bool *hugetlb);
 void putback_active_hugepage(struct page *page);
 void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
 void free_huge_page(struct page *page);
@@ -339,6 +340,11 @@ static inline bool isolate_huge_page(struct page *page, struct list_head *list)
        return false;
 }
 
+static inline int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+{
+       return 0;
+}
+
 static inline void putback_active_hugepage(struct page *page)
 {
 }
@@ -445,7 +451,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
 extern const struct file_operations hugetlbfs_file_operations;
 extern const struct vm_operations_struct hugetlb_vm_ops;
 struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
-                               struct user_struct **user, int creat_flags,
+                               struct ucounts **ucounts, int creat_flags,
                                int page_size_log);
 
 static inline bool is_file_hugepages(struct file *file)
@@ -465,7 +471,7 @@ static inline struct hstate *hstate_inode(struct inode *i)
 #define is_file_hugepages(file)                        false
 static inline struct file *
 hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
-               struct user_struct **user, int creat_flags,
+               struct ucounts **ucounts, int creat_flags,
                int page_size_log)
 {
        return ERR_PTR(-ENOSYS);
@@ -604,6 +610,8 @@ struct page *alloc_huge_page_vma(struct hstate *h, struct vm_area_struct *vma,
                                unsigned long address);
 int huge_add_to_page_cache(struct page *page, struct address_space *mapping,
                        pgoff_t idx);
+void restore_reserve_on_error(struct hstate *h, struct vm_area_struct *vma,
+                               unsigned long address, struct page *page);
 
 /* arch callback */
 int __init __alloc_bootmem_huge_page(struct hstate *h);
@@ -733,17 +741,6 @@ static inline int hstate_index(struct hstate *h)
        return h - hstates;
 }
 
-pgoff_t __basepage_index(struct page *page);
-
-/* Return page->index in PAGE_SIZE units */
-static inline pgoff_t basepage_index(struct page *page)
-{
-       if (!PageCompound(page))
-               return page->index;
-
-       return __basepage_index(page);
-}
-
 extern int dissolve_free_huge_page(struct page *page);
 extern int dissolve_free_huge_pages(unsigned long start_pfn,
                                    unsigned long end_pfn);
@@ -980,11 +977,6 @@ static inline int hstate_index(struct hstate *h)
        return 0;
 }
 
-static inline pgoff_t basepage_index(struct page *page)
-{
-       return page->index;
-}
-
 static inline int dissolve_free_huge_page(struct page *page)
 {
        return 0;
index d1e59db..2e859d2 100644 (file)
@@ -181,6 +181,10 @@ struct hv_ring_buffer_info {
         * being freed while the ring buffer is being accessed.
         */
        struct mutex ring_buffer_mutex;
+
+       /* Buffer that holds a copy of an incoming host packet */
+       void *pkt_buffer;
+       u32 pkt_buffer_size;
 };
 
 
@@ -790,7 +794,11 @@ struct vmbus_requestor {
 
 #define VMBUS_NO_RQSTOR U64_MAX
 #define VMBUS_RQST_ERROR (U64_MAX - 1)
+/* NetVSC-specific */
 #define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2)
+/* StorVSC-specific */
+#define VMBUS_RQST_INIT (U64_MAX - 2)
+#define VMBUS_RQST_RESET (U64_MAX - 3)
 
 struct vmbus_device {
        u16  dev_type;
@@ -799,6 +807,8 @@ struct vmbus_device {
        bool allowed_in_isolated;
 };
 
+#define VMBUS_DEFAULT_MAX_PKT_SIZE 4096
+
 struct vmbus_channel {
        struct list_head listentry;
 
@@ -1018,13 +1028,21 @@ struct vmbus_channel {
        u32 fuzz_testing_interrupt_delay;
        u32 fuzz_testing_message_delay;
 
+       /* callback to generate a request ID from a request address */
+       u64 (*next_request_id_callback)(struct vmbus_channel *channel, u64 rqst_addr);
+       /* callback to retrieve a request address from a request ID */
+       u64 (*request_addr_callback)(struct vmbus_channel *channel, u64 rqst_id);
+
        /* request/transaction ids for VMBus */
        struct vmbus_requestor requestor;
        u32 rqstor_size;
+
+       /* The max size of a packet on this channel */
+       u32 max_pkt_size;
 };
 
-u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr);
-u64 vmbus_request_addr(struct vmbus_requestor *rqstor, u64 trans_id);
+u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr);
+u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id);
 
 static inline bool is_hvsock_channel(const struct vmbus_channel *c)
 {
@@ -1663,31 +1681,54 @@ static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
 
 
 struct vmpacket_descriptor *
+hv_pkt_iter_first_raw(struct vmbus_channel *channel);
+
+struct vmpacket_descriptor *
 hv_pkt_iter_first(struct vmbus_channel *channel);
 
 struct vmpacket_descriptor *
 __hv_pkt_iter_next(struct vmbus_channel *channel,
-                  const struct vmpacket_descriptor *pkt);
+                  const struct vmpacket_descriptor *pkt,
+                  bool copy);
 
 void hv_pkt_iter_close(struct vmbus_channel *channel);
 
-/*
- * Get next packet descriptor from iterator
- * If at end of list, return NULL and update host.
- */
 static inline struct vmpacket_descriptor *
-hv_pkt_iter_next(struct vmbus_channel *channel,
-                const struct vmpacket_descriptor *pkt)
+hv_pkt_iter_next_pkt(struct vmbus_channel *channel,
+                    const struct vmpacket_descriptor *pkt,
+                    bool copy)
 {
        struct vmpacket_descriptor *nxt;
 
-       nxt = __hv_pkt_iter_next(channel, pkt);
+       nxt = __hv_pkt_iter_next(channel, pkt, copy);
        if (!nxt)
                hv_pkt_iter_close(channel);
 
        return nxt;
 }
 
+/*
+ * Get next packet descriptor without copying it out of the ring buffer
+ * If at end of list, return NULL and update host.
+ */
+static inline struct vmpacket_descriptor *
+hv_pkt_iter_next_raw(struct vmbus_channel *channel,
+                    const struct vmpacket_descriptor *pkt)
+{
+       return hv_pkt_iter_next_pkt(channel, pkt, false);
+}
+
+/*
+ * Get next packet descriptor from iterator
+ * If at end of list, return NULL and update host.
+ */
+static inline struct vmpacket_descriptor *
+hv_pkt_iter_next(struct vmbus_channel *channel,
+                const struct vmpacket_descriptor *pkt)
+{
+       return hv_pkt_iter_next_pkt(channel, pkt, true);
+}
+
 #define foreach_vmbus_pkt(pkt, channel) \
        for (pkt = hv_pkt_iter_first(channel); pkt; \
            pkt = hv_pkt_iter_next(channel, pkt))
diff --git a/include/linux/ide.h b/include/linux/ide.h
deleted file mode 100644 (file)
index 2c30068..0000000
+++ /dev/null
@@ -1,1623 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _IDE_H
-#define _IDE_H
-/*
- *  linux/include/linux/ide.h
- *
- *  Copyright (C) 1994-2002  Linus Torvalds & authors
- */
-
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/ata.h>
-#include <linux/blk-mq.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/bio.h>
-#include <linux/pci.h>
-#include <linux/completion.h>
-#include <linux/pm.h>
-#include <linux/mutex.h>
-/* for request_sense */
-#include <linux/cdrom.h>
-#include <scsi/scsi_cmnd.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-/*
- * Probably not wise to fiddle with these
- */
-#define SUPPORT_VLB_SYNC 1
-#define IDE_DEFAULT_MAX_FAILURES       1
-#define ERROR_MAX      8       /* Max read/write errors per sector */
-#define ERROR_RESET    3       /* Reset controller every 4th retry */
-#define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
-
-struct device;
-
-/* values for ide_request.type */
-enum ata_priv_type {
-       ATA_PRIV_MISC,
-       ATA_PRIV_TASKFILE,
-       ATA_PRIV_PC,
-       ATA_PRIV_SENSE,         /* sense request */
-       ATA_PRIV_PM_SUSPEND,    /* suspend request */
-       ATA_PRIV_PM_RESUME,     /* resume request */
-};
-
-struct ide_request {
-       struct scsi_request sreq;
-       u8 sense[SCSI_SENSE_BUFFERSIZE];
-       u8 type;
-       void *special;
-};
-
-static inline struct ide_request *ide_req(struct request *rq)
-{
-       return blk_mq_rq_to_pdu(rq);
-}
-
-static inline bool ata_misc_request(struct request *rq)
-{
-       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_MISC;
-}
-
-static inline bool ata_taskfile_request(struct request *rq)
-{
-       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_TASKFILE;
-}
-
-static inline bool ata_pc_request(struct request *rq)
-{
-       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_PC;
-}
-
-static inline bool ata_sense_request(struct request *rq)
-{
-       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_SENSE;
-}
-
-static inline bool ata_pm_request(struct request *rq)
-{
-       return blk_rq_is_private(rq) &&
-               (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND ||
-                ide_req(rq)->type == ATA_PRIV_PM_RESUME);
-}
-
-/* Error codes returned in result to the higher part of the driver. */
-enum {
-       IDE_DRV_ERROR_GENERAL   = 101,
-       IDE_DRV_ERROR_FILEMARK  = 102,
-       IDE_DRV_ERROR_EOD       = 103,
-};
-
-/*
- * Definitions for accessing IDE controller registers
- */
-#define IDE_NR_PORTS           (10)
-
-struct ide_io_ports {
-       unsigned long   data_addr;
-
-       union {
-               unsigned long error_addr;       /*   read:  error */
-               unsigned long feature_addr;     /*  write: feature */
-       };
-
-       unsigned long   nsect_addr;
-       unsigned long   lbal_addr;
-       unsigned long   lbam_addr;
-       unsigned long   lbah_addr;
-
-       unsigned long   device_addr;
-
-       union {
-               unsigned long status_addr;      /*  read: status  */
-               unsigned long command_addr;     /* write: command */
-       };
-
-       unsigned long   ctl_addr;
-
-       unsigned long   irq_addr;
-};
-
-#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
-
-#define BAD_R_STAT     (ATA_BUSY | ATA_ERR)
-#define BAD_W_STAT     (BAD_R_STAT | ATA_DF)
-#define BAD_STAT       (BAD_R_STAT | ATA_DRQ)
-#define DRIVE_READY    (ATA_DRDY | ATA_DSC)
-
-#define BAD_CRC                (ATA_ABORTED | ATA_ICRC)
-
-#define SATA_NR_PORTS          (3)     /* 16 possible ?? */
-
-#define SATA_STATUS_OFFSET     (0)
-#define SATA_ERROR_OFFSET      (1)
-#define SATA_CONTROL_OFFSET    (2)
-
-/*
- * Our Physical Region Descriptor (PRD) table should be large enough
- * to handle the biggest I/O request we are likely to see.  Since requests
- * can have no more than 256 sectors, and since the typical blocksize is
- * two or more sectors, we could get by with a limit of 128 entries here for
- * the usual worst case.  Most requests seem to include some contiguous blocks,
- * further reducing the number of table entries required.
- *
- * The driver reverts to PIO mode for individual requests that exceed
- * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
- * 100% of all crazy scenarios here is not necessary.
- *
- * As it turns out though, we must allocate a full 4KB page for this,
- * so the two PRD tables (ide0 & ide1) will each get half of that,
- * allowing each to have about 256 entries (8 bytes each) from this.
- */
-#define PRD_BYTES       8
-#define PRD_ENTRIES    256
-
-/*
- * Some more useful definitions
- */
-#define PARTN_BITS     6       /* number of minor dev bits for partitions */
-#define MAX_DRIVES     2       /* per interface; 2 assumed by lots of code */
-
-/*
- * Timeouts for various operations:
- */
-enum {
-       /* spec allows up to 20ms, but CF cards and SSD drives need more */
-       WAIT_DRQ        = 1 * HZ,       /* 1s */
-       /* some laptops are very slow */
-       WAIT_READY      = 5 * HZ,       /* 5s */
-       /* should be less than 3ms (?), if all ATAPI CD is closed at boot */
-       WAIT_PIDENTIFY  = 10 * HZ,      /* 10s */
-       /* worst case when spinning up */
-       WAIT_WORSTCASE  = 30 * HZ,      /* 30s */
-       /* maximum wait for an IRQ to happen */
-       WAIT_CMD        = 10 * HZ,      /* 10s */
-       /* Some drives require a longer IRQ timeout. */
-       WAIT_FLOPPY_CMD = 50 * HZ,      /* 50s */
-       /*
-        * Some drives (for example, Seagate STT3401A Travan) require a very
-        * long timeout, because they don't return an interrupt or clear their
-        * BSY bit until after the command completes (even retension commands).
-        */
-       WAIT_TAPE_CMD   = 900 * HZ,     /* 900s */
-       /* minimum sleep time */
-       WAIT_MIN_SLEEP  = HZ / 50,      /* 20ms */
-};
-
-/*
- * Op codes for special requests to be handled by ide_special_rq().
- * Values should be in the range of 0x20 to 0x3f.
- */
-#define REQ_DRIVE_RESET                0x20
-#define REQ_DEVSET_EXEC                0x21
-#define REQ_PARK_HEADS         0x22
-#define REQ_UNPARK_HEADS       0x23
-
-/*
- * hwif_chipset_t is used to keep track of the specific hardware
- * chipset used by each IDE interface, if known.
- */
-enum {         ide_unknown,    ide_generic,    ide_pci,
-               ide_cmd640,     ide_dtc2278,    ide_ali14xx,
-               ide_qd65xx,     ide_umc8672,    ide_ht6560b,
-               ide_4drives,    ide_pmac,       ide_acorn,
-               ide_au1xxx,     ide_palm3710
-};
-
-typedef u8 hwif_chipset_t;
-
-/*
- * Structure to hold all information about the location of this port
- */
-struct ide_hw {
-       union {
-               struct ide_io_ports     io_ports;
-               unsigned long           io_ports_array[IDE_NR_PORTS];
-       };
-
-       int             irq;                    /* our irq number */
-       struct device   *dev, *parent;
-       unsigned long   config;
-};
-
-static inline void ide_std_init_ports(struct ide_hw *hw,
-                                     unsigned long io_addr,
-                                     unsigned long ctl_addr)
-{
-       unsigned int i;
-
-       for (i = 0; i <= 7; i++)
-               hw->io_ports_array[i] = io_addr++;
-
-       hw->io_ports.ctl_addr = ctl_addr;
-}
-
-#define MAX_HWIFS      10
-
-/*
- * Now for the data we need to maintain per-drive:  ide_drive_t
- */
-
-#define ide_scsi       0x21
-#define ide_disk       0x20
-#define ide_optical    0x7
-#define ide_cdrom      0x5
-#define ide_tape       0x1
-#define ide_floppy     0x0
-
-/*
- * Special Driver Flags
- */
-enum {
-       IDE_SFLAG_SET_GEOMETRY          = BIT(0),
-       IDE_SFLAG_RECALIBRATE           = BIT(1),
-       IDE_SFLAG_SET_MULTMODE          = BIT(2),
-};
-
-/*
- * Status returned from various ide_ functions
- */
-typedef enum {
-       ide_stopped,    /* no drive operation was started */
-       ide_started,    /* a drive operation was started, handler was set */
-} ide_startstop_t;
-
-enum {
-       IDE_VALID_ERROR                 = BIT(1),
-       IDE_VALID_FEATURE               = IDE_VALID_ERROR,
-       IDE_VALID_NSECT                 = BIT(2),
-       IDE_VALID_LBAL                  = BIT(3),
-       IDE_VALID_LBAM                  = BIT(4),
-       IDE_VALID_LBAH                  = BIT(5),
-       IDE_VALID_DEVICE                = BIT(6),
-       IDE_VALID_LBA                   = IDE_VALID_LBAL |
-                                         IDE_VALID_LBAM |
-                                         IDE_VALID_LBAH,
-       IDE_VALID_OUT_TF                = IDE_VALID_FEATURE |
-                                         IDE_VALID_NSECT |
-                                         IDE_VALID_LBA,
-       IDE_VALID_IN_TF                 = IDE_VALID_NSECT |
-                                         IDE_VALID_LBA,
-       IDE_VALID_OUT_HOB               = IDE_VALID_OUT_TF,
-       IDE_VALID_IN_HOB                = IDE_VALID_ERROR |
-                                         IDE_VALID_NSECT |
-                                         IDE_VALID_LBA,
-};
-
-enum {
-       IDE_TFLAG_LBA48                 = BIT(0),
-       IDE_TFLAG_WRITE                 = BIT(1),
-       IDE_TFLAG_CUSTOM_HANDLER        = BIT(2),
-       IDE_TFLAG_DMA_PIO_FALLBACK      = BIT(3),
-       /* force 16-bit I/O operations */
-       IDE_TFLAG_IO_16BIT              = BIT(4),
-       /* struct ide_cmd was allocated using kmalloc() */
-       IDE_TFLAG_DYN                   = BIT(5),
-       IDE_TFLAG_FS                    = BIT(6),
-       IDE_TFLAG_MULTI_PIO             = BIT(7),
-       IDE_TFLAG_SET_XFER              = BIT(8),
-};
-
-enum {
-       IDE_FTFLAG_FLAGGED              = BIT(0),
-       IDE_FTFLAG_SET_IN_FLAGS         = BIT(1),
-       IDE_FTFLAG_OUT_DATA             = BIT(2),
-       IDE_FTFLAG_IN_DATA              = BIT(3),
-};
-
-struct ide_taskfile {
-       u8      data;           /* 0: data byte (for TASKFILE ioctl) */
-       union {                 /* 1: */
-               u8 error;       /*  read: error */
-               u8 feature;     /* write: feature */
-       };
-       u8      nsect;          /* 2: number of sectors */
-       u8      lbal;           /* 3: LBA low */
-       u8      lbam;           /* 4: LBA mid */
-       u8      lbah;           /* 5: LBA high */
-       u8      device;         /* 6: device select */
-       union {                 /* 7: */
-               u8 status;      /*  read: status */
-               u8 command;     /* write: command */
-       };
-};
-
-struct ide_cmd {
-       struct ide_taskfile     tf;
-       struct ide_taskfile     hob;
-       struct {
-               struct {
-                       u8              tf;
-                       u8              hob;
-               } out, in;
-       } valid;
-
-       u16                     tf_flags;
-       u8                      ftf_flags;      /* for TASKFILE ioctl */
-       int                     protocol;
-
-       int                     sg_nents;         /* number of sg entries */
-       int                     orig_sg_nents;
-       int                     sg_dma_direction; /* DMA transfer direction */
-
-       unsigned int            nbytes;
-       unsigned int            nleft;
-       unsigned int            last_xfer_len;
-
-       struct scatterlist      *cursg;
-       unsigned int            cursg_ofs;
-
-       struct request          *rq;            /* copy of request */
-};
-
-/* ATAPI packet command flags */
-enum {
-       /* set when an error is considered normal - no retry (ide-tape) */
-       PC_FLAG_ABORT                   = BIT(0),
-       PC_FLAG_SUPPRESS_ERROR          = BIT(1),
-       PC_FLAG_WAIT_FOR_DSC            = BIT(2),
-       PC_FLAG_DMA_OK                  = BIT(3),
-       PC_FLAG_DMA_IN_PROGRESS         = BIT(4),
-       PC_FLAG_DMA_ERROR               = BIT(5),
-       PC_FLAG_WRITING                 = BIT(6),
-};
-
-#define ATAPI_WAIT_PC          (60 * HZ)
-
-struct ide_atapi_pc {
-       /* actual packet bytes */
-       u8 c[12];
-       /* incremented on each retry */
-       int retries;
-       int error;
-
-       /* bytes to transfer */
-       int req_xfer;
-
-       /* the corresponding request */
-       struct request *rq;
-
-       unsigned long flags;
-
-       /*
-        * those are more or less driver-specific and some of them are subject
-        * to change/removal later.
-        */
-       unsigned long timeout;
-};
-
-struct ide_devset;
-struct ide_driver;
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-struct ide_acpi_drive_link;
-struct ide_acpi_hwif_link;
-#endif
-
-struct ide_drive_s;
-
-struct ide_disk_ops {
-       int             (*check)(struct ide_drive_s *, const char *);
-       int             (*get_capacity)(struct ide_drive_s *);
-       void            (*unlock_native_capacity)(struct ide_drive_s *);
-       void            (*setup)(struct ide_drive_s *);
-       void            (*flush)(struct ide_drive_s *);
-       int             (*init_media)(struct ide_drive_s *, struct gendisk *);
-       int             (*set_doorlock)(struct ide_drive_s *, struct gendisk *,
-                                       int);
-       ide_startstop_t (*do_request)(struct ide_drive_s *, struct request *,
-                                     sector_t);
-       int             (*ioctl)(struct ide_drive_s *, struct block_device *,
-                                fmode_t, unsigned int, unsigned long);
-       int             (*compat_ioctl)(struct ide_drive_s *, struct block_device *,
-                                       fmode_t, unsigned int, unsigned long);
-};
-
-/* ATAPI device flags */
-enum {
-       IDE_AFLAG_DRQ_INTERRUPT         = BIT(0),
-
-       /* ide-cd */
-       /* Drive cannot eject the disc. */
-       IDE_AFLAG_NO_EJECT              = BIT(1),
-       /* Drive is a pre ATAPI 1.2 drive. */
-       IDE_AFLAG_PRE_ATAPI12           = BIT(2),
-       /* TOC addresses are in BCD. */
-       IDE_AFLAG_TOCADDR_AS_BCD        = BIT(3),
-       /* TOC track numbers are in BCD. */
-       IDE_AFLAG_TOCTRACKS_AS_BCD      = BIT(4),
-       /* Saved TOC information is current. */
-       IDE_AFLAG_TOC_VALID             = BIT(6),
-       /* We think that the drive door is locked. */
-       IDE_AFLAG_DOOR_LOCKED           = BIT(7),
-       /* SET_CD_SPEED command is unsupported. */
-       IDE_AFLAG_NO_SPEED_SELECT       = BIT(8),
-       IDE_AFLAG_VERTOS_300_SSD        = BIT(9),
-       IDE_AFLAG_VERTOS_600_ESD        = BIT(10),
-       IDE_AFLAG_SANYO_3CD             = BIT(11),
-       IDE_AFLAG_FULL_CAPS_PAGE        = BIT(12),
-       IDE_AFLAG_PLAY_AUDIO_OK         = BIT(13),
-       IDE_AFLAG_LE_SPEED_FIELDS       = BIT(14),
-
-       /* ide-floppy */
-       /* Avoid commands not supported in Clik drive */
-       IDE_AFLAG_CLIK_DRIVE            = BIT(15),
-       /* Requires BH algorithm for packets */
-       IDE_AFLAG_ZIP_DRIVE             = BIT(16),
-       /* Supports format progress report */
-       IDE_AFLAG_SRFP                  = BIT(17),
-
-       /* ide-tape */
-       IDE_AFLAG_IGNORE_DSC            = BIT(18),
-       /* 0 When the tape position is unknown */
-       IDE_AFLAG_ADDRESS_VALID         = BIT(19),
-       /* Device already opened */
-       IDE_AFLAG_BUSY                  = BIT(20),
-       /* Attempt to auto-detect the current user block size */
-       IDE_AFLAG_DETECT_BS             = BIT(21),
-       /* Currently on a filemark */
-       IDE_AFLAG_FILEMARK              = BIT(22),
-       /* 0 = no tape is loaded, so we don't rewind after ejecting */
-       IDE_AFLAG_MEDIUM_PRESENT        = BIT(23),
-
-       IDE_AFLAG_NO_AUTOCLOSE          = BIT(24),
-};
-
-/* device flags */
-enum {
-       /* restore settings after device reset */
-       IDE_DFLAG_KEEP_SETTINGS         = BIT(0),
-       /* device is using DMA for read/write */
-       IDE_DFLAG_USING_DMA             = BIT(1),
-       /* okay to unmask other IRQs */
-       IDE_DFLAG_UNMASK                = BIT(2),
-       /* don't attempt flushes */
-       IDE_DFLAG_NOFLUSH               = BIT(3),
-       /* DSC overlap */
-       IDE_DFLAG_DSC_OVERLAP           = BIT(4),
-       /* give potential excess bandwidth */
-       IDE_DFLAG_NICE1                 = BIT(5),
-       /* device is physically present */
-       IDE_DFLAG_PRESENT               = BIT(6),
-       /* disable Host Protected Area */
-       IDE_DFLAG_NOHPA                 = BIT(7),
-       /* id read from device (synthetic if not set) */
-       IDE_DFLAG_ID_READ               = BIT(8),
-       IDE_DFLAG_NOPROBE               = BIT(9),
-       /* need to do check_media_change() */
-       IDE_DFLAG_REMOVABLE             = BIT(10),
-       IDE_DFLAG_FORCED_GEOM           = BIT(12),
-       /* disallow setting unmask bit */
-       IDE_DFLAG_NO_UNMASK             = BIT(13),
-       /* disallow enabling 32-bit I/O */
-       IDE_DFLAG_NO_IO_32BIT           = BIT(14),
-       /* for removable only: door lock/unlock works */
-       IDE_DFLAG_DOORLOCKING           = BIT(15),
-       /* disallow DMA */
-       IDE_DFLAG_NODMA                 = BIT(16),
-       /* powermanagement told us not to do anything, so sleep nicely */
-       IDE_DFLAG_BLOCKED               = BIT(17),
-       /* sleeping & sleep field valid */
-       IDE_DFLAG_SLEEPING              = BIT(18),
-       IDE_DFLAG_POST_RESET            = BIT(19),
-       IDE_DFLAG_UDMA33_WARNED         = BIT(20),
-       IDE_DFLAG_LBA48                 = BIT(21),
-       /* status of write cache */
-       IDE_DFLAG_WCACHE                = BIT(22),
-       /* used for ignoring ATA_DF */
-       IDE_DFLAG_NOWERR                = BIT(23),
-       /* retrying in PIO */
-       IDE_DFLAG_DMA_PIO_RETRY         = BIT(24),
-       IDE_DFLAG_LBA                   = BIT(25),
-       /* don't unload heads */
-       IDE_DFLAG_NO_UNLOAD             = BIT(26),
-       /* heads unloaded, please don't reset port */
-       IDE_DFLAG_PARKED                = BIT(27),
-       IDE_DFLAG_MEDIA_CHANGED         = BIT(28),
-       /* write protect */
-       IDE_DFLAG_WP                    = BIT(29),
-       IDE_DFLAG_FORMAT_IN_PROGRESS    = BIT(30),
-       IDE_DFLAG_NIEN_QUIRK            = BIT(31),
-};
-
-struct ide_drive_s {
-       char            name[4];        /* drive name, such as "hda" */
-        char            driver_req[10];        /* requests specific driver */
-
-       struct request_queue    *queue; /* request queue */
-
-       bool (*prep_rq)(struct ide_drive_s *, struct request *);
-
-       struct blk_mq_tag_set   tag_set;
-
-       struct request          *rq;    /* current request */
-       void            *driver_data;   /* extra driver data */
-       u16                     *id;    /* identification info */
-#ifdef CONFIG_IDE_PROC_FS
-       struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
-       const struct ide_proc_devset *settings; /* /proc/ide/ drive settings */
-#endif
-       struct hwif_s           *hwif;  /* actually (ide_hwif_t *) */
-
-       const struct ide_disk_ops *disk_ops;
-
-       unsigned long dev_flags;
-
-       unsigned long sleep;            /* sleep until this time */
-       unsigned long timeout;          /* max time to wait for irq */
-
-       u8      special_flags;          /* special action flags */
-
-       u8      select;                 /* basic drive/head select reg value */
-       u8      retry_pio;              /* retrying dma capable host in pio */
-       u8      waiting_for_dma;        /* dma currently in progress */
-       u8      dma;                    /* atapi dma flag */
-
-        u8     init_speed;     /* transfer rate set at boot */
-        u8     current_speed;  /* current transfer rate set */
-       u8      desired_speed;  /* desired transfer rate set */
-       u8      pio_mode;       /* for ->set_pio_mode _only_ */
-       u8      dma_mode;       /* for ->set_dma_mode _only_ */
-       u8      dn;             /* now wide spread use */
-       u8      acoustic;       /* acoustic management */
-       u8      media;          /* disk, cdrom, tape, floppy, ... */
-       u8      ready_stat;     /* min status value for drive ready */
-       u8      mult_count;     /* current multiple sector setting */
-       u8      mult_req;       /* requested multiple sector setting */
-       u8      io_32bit;       /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-       u8      bad_wstat;      /* used for ignoring ATA_DF */
-       u8      head;           /* "real" number of heads */
-       u8      sect;           /* "real" sectors per track */
-       u8      bios_head;      /* BIOS/fdisk/LILO number of heads */
-       u8      bios_sect;      /* BIOS/fdisk/LILO sectors per track */
-
-       /* delay this long before sending packet command */
-       u8 pc_delay;
-
-       unsigned int    bios_cyl;       /* BIOS/fdisk/LILO number of cyls */
-       unsigned int    cyl;            /* "real" number of cyls */
-       void            *drive_data;    /* used by set_pio_mode/dev_select() */
-       unsigned int    failures;       /* current failure count */
-       unsigned int    max_failures;   /* maximum allowed failure count */
-       u64             probed_capacity;/* initial/native media capacity */
-       u64             capacity64;     /* total number of sectors */
-
-       int             lun;            /* logical unit */
-       int             crc_count;      /* crc counter to reduce drive speed */
-
-       unsigned long   debug_mask;     /* debugging levels switch */
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-       struct ide_acpi_drive_link *acpidata;
-#endif
-       struct list_head list;
-       struct device   gendev;
-       struct completion gendev_rel_comp;      /* to deal with device release() */
-
-       /* current packet command */
-       struct ide_atapi_pc *pc;
-
-       /* last failed packet command */
-       struct ide_atapi_pc *failed_pc;
-
-       /* callback for packet commands */
-       int  (*pc_callback)(struct ide_drive_s *, int);
-
-       ide_startstop_t (*irq_handler)(struct ide_drive_s *);
-
-       unsigned long atapi_flags;
-
-       struct ide_atapi_pc request_sense_pc;
-
-       /* current sense rq and buffer */
-       bool sense_rq_armed;
-       bool sense_rq_active;
-       struct request *sense_rq;
-       struct request_sense sense_data;
-
-       /* async sense insertion */
-       struct work_struct rq_work;
-       struct list_head rq_list;
-};
-
-typedef struct ide_drive_s ide_drive_t;
-
-#define to_ide_device(dev)             container_of(dev, ide_drive_t, gendev)
-
-#define to_ide_drv(obj, cont_type)     \
-       container_of(obj, struct cont_type, dev)
-
-#define ide_drv_g(disk, cont_type)     \
-       container_of((disk)->private_data, struct cont_type, driver)
-
-struct ide_port_info;
-
-struct ide_tp_ops {
-       void    (*exec_command)(struct hwif_s *, u8);
-       u8      (*read_status)(struct hwif_s *);
-       u8      (*read_altstatus)(struct hwif_s *);
-       void    (*write_devctl)(struct hwif_s *, u8);
-
-       void    (*dev_select)(ide_drive_t *);
-       void    (*tf_load)(ide_drive_t *, struct ide_taskfile *, u8);
-       void    (*tf_read)(ide_drive_t *, struct ide_taskfile *, u8);
-
-       void    (*input_data)(ide_drive_t *, struct ide_cmd *,
-                             void *, unsigned int);
-       void    (*output_data)(ide_drive_t *, struct ide_cmd *,
-                              void *, unsigned int);
-};
-
-extern const struct ide_tp_ops default_tp_ops;
-
-/**
- * struct ide_port_ops - IDE port operations
- *
- * @init_dev:          host specific initialization of a device
- * @set_pio_mode:      routine to program host for PIO mode
- * @set_dma_mode:      routine to program host for DMA mode
- * @reset_poll:                chipset polling based on hba specifics
- * @pre_reset:         chipset specific changes to default for device-hba resets
- * @resetproc:         routine to reset controller after a disk reset
- * @maskproc:          special host masking for drive selection
- * @quirkproc:         check host's drive quirk list
- * @clear_irq:         clear IRQ
- *
- * @mdma_filter:       filter MDMA modes
- * @udma_filter:       filter UDMA modes
- *
- * @cable_detect:      detect cable type
- */
-struct ide_port_ops {
-       void    (*init_dev)(ide_drive_t *);
-       void    (*set_pio_mode)(struct hwif_s *, ide_drive_t *);
-       void    (*set_dma_mode)(struct hwif_s *, ide_drive_t *);
-       blk_status_t (*reset_poll)(ide_drive_t *);
-       void    (*pre_reset)(ide_drive_t *);
-       void    (*resetproc)(ide_drive_t *);
-       void    (*maskproc)(ide_drive_t *, int);
-       void    (*quirkproc)(ide_drive_t *);
-       void    (*clear_irq)(ide_drive_t *);
-       int     (*test_irq)(struct hwif_s *);
-
-       u8      (*mdma_filter)(ide_drive_t *);
-       u8      (*udma_filter)(ide_drive_t *);
-
-       u8      (*cable_detect)(struct hwif_s *);
-};
-
-struct ide_dma_ops {
-       void    (*dma_host_set)(struct ide_drive_s *, int);
-       int     (*dma_setup)(struct ide_drive_s *, struct ide_cmd *);
-       void    (*dma_start)(struct ide_drive_s *);
-       int     (*dma_end)(struct ide_drive_s *);
-       int     (*dma_test_irq)(struct ide_drive_s *);
-       void    (*dma_lost_irq)(struct ide_drive_s *);
-       /* below ones are optional */
-       int     (*dma_check)(struct ide_drive_s *, struct ide_cmd *);
-       int     (*dma_timer_expiry)(struct ide_drive_s *);
-       void    (*dma_clear)(struct ide_drive_s *);
-       /*
-        * The following method is optional and only required to be
-        * implemented for the SFF-8038i compatible controllers.
-        */
-       u8      (*dma_sff_read_status)(struct hwif_s *);
-};
-
-enum {
-       IDE_PFLAG_PROBING               = BIT(0),
-};
-
-struct ide_host;
-
-typedef struct hwif_s {
-       struct hwif_s *mate;            /* other hwif from same PCI chip */
-       struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
-
-       struct ide_host *host;
-
-       char name[6];                   /* name of interface, eg. "ide0" */
-
-       struct ide_io_ports     io_ports;
-
-       unsigned long   sata_scr[SATA_NR_PORTS];
-
-       ide_drive_t     *devices[MAX_DRIVES + 1];
-
-       unsigned long   port_flags;
-
-       u8 major;       /* our major number */
-       u8 index;       /* 0 for ide0; 1 for ide1; ... */
-       u8 channel;     /* for dual-port chips: 0=primary, 1=secondary */
-
-       u32 host_flags;
-
-       u8 pio_mask;
-
-       u8 ultra_mask;
-       u8 mwdma_mask;
-       u8 swdma_mask;
-
-       u8 cbl;         /* cable type */
-
-       hwif_chipset_t chipset; /* sub-module for tuning.. */
-
-       struct device *dev;
-
-       void (*rw_disk)(ide_drive_t *, struct request *);
-
-       const struct ide_tp_ops         *tp_ops;
-       const struct ide_port_ops       *port_ops;
-       const struct ide_dma_ops        *dma_ops;
-
-       /* dma physical region descriptor table (cpu view) */
-       unsigned int    *dmatable_cpu;
-       /* dma physical region descriptor table (dma view) */
-       dma_addr_t      dmatable_dma;
-
-       /* maximum number of PRD table entries */
-       int prd_max_nents;
-       /* PRD entry size in bytes */
-       int prd_ent_size;
-
-       /* Scatter-gather list used to build the above */
-       struct scatterlist *sg_table;
-       int sg_max_nents;               /* Maximum number of entries in it */
-
-       struct ide_cmd cmd;             /* current command */
-
-       int             rqsize;         /* max sectors per request */
-       int             irq;            /* our irq number */
-
-       unsigned long   dma_base;       /* base addr for dma ports */
-
-       unsigned long   config_data;    /* for use by chipset-specific code */
-       unsigned long   select_data;    /* for use by chipset-specific code */
-
-       unsigned long   extra_base;     /* extra addr for dma ports */
-       unsigned        extra_ports;    /* number of extra dma ports */
-
-       unsigned        present    : 1; /* this interface exists */
-       unsigned        busy       : 1; /* serializes devices on a port */
-
-       struct device           gendev;
-       struct device           *portdev;
-
-       struct completion gendev_rel_comp; /* To deal with device release() */
-
-       void            *hwif_data;     /* extra hwif data */
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-       struct ide_acpi_hwif_link *acpidata;
-#endif
-
-       /* IRQ handler, if active */
-       ide_startstop_t (*handler)(ide_drive_t *);
-
-       /* BOOL: polling active & poll_timeout field valid */
-       unsigned int polling : 1;
-
-       /* current drive */
-       ide_drive_t *cur_dev;
-
-       /* current request */
-       struct request *rq;
-
-       /* failsafe timer */
-       struct timer_list timer;
-       /* timeout value during long polls */
-       unsigned long poll_timeout;
-       /* queried upon timeouts */
-       int (*expiry)(ide_drive_t *);
-
-       int req_gen;
-       int req_gen_timer;
-
-       spinlock_t lock;
-} ____cacheline_internodealigned_in_smp ide_hwif_t;
-
-#define MAX_HOST_PORTS 4
-
-struct ide_host {
-       ide_hwif_t      *ports[MAX_HOST_PORTS + 1];
-       unsigned int    n_ports;
-       struct device   *dev[2];
-
-       int             (*init_chipset)(struct pci_dev *);
-
-       void            (*get_lock)(irq_handler_t, void *);
-       void            (*release_lock)(void);
-
-       irq_handler_t   irq_handler;
-
-       unsigned long   host_flags;
-
-       int             irq_flags;
-
-       void            *host_priv;
-       ide_hwif_t      *cur_port;      /* for hosts requiring serialization */
-
-       /* used for hosts requiring serialization */
-       volatile unsigned long  host_busy;
-};
-
-#define IDE_HOST_BUSY 0
-
-/*
- *  internal ide interrupt handler type
- */
-typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
-typedef int (ide_expiry_t)(ide_drive_t *);
-
-/* used by ide-cd, ide-floppy, etc. */
-typedef void (xfer_func_t)(ide_drive_t *, struct ide_cmd *, void *, unsigned);
-
-extern struct mutex ide_setting_mtx;
-
-/*
- * configurable drive settings
- */
-
-#define DS_SYNC        BIT(0)
-
-struct ide_devset {
-       int             (*get)(ide_drive_t *);
-       int             (*set)(ide_drive_t *, int);
-       unsigned int    flags;
-};
-
-#define __DEVSET(_flags, _get, _set) { \
-       .flags  = _flags, \
-       .get    = _get, \
-       .set    = _set, \
-}
-
-#define ide_devset_get(name, field) \
-static int get_##name(ide_drive_t *drive) \
-{ \
-       return drive->field; \
-}
-
-#define ide_devset_set(name, field) \
-static int set_##name(ide_drive_t *drive, int arg) \
-{ \
-       drive->field = arg; \
-       return 0; \
-}
-
-#define ide_devset_get_flag(name, flag) \
-static int get_##name(ide_drive_t *drive) \
-{ \
-       return !!(drive->dev_flags & flag); \
-}
-
-#define ide_devset_set_flag(name, flag) \
-static int set_##name(ide_drive_t *drive, int arg) \
-{ \
-       if (arg) \
-               drive->dev_flags |= flag; \
-       else \
-               drive->dev_flags &= ~flag; \
-       return 0; \
-}
-
-#define __IDE_DEVSET(_name, _flags, _get, _set) \
-const struct ide_devset ide_devset_##_name = \
-       __DEVSET(_flags, _get, _set)
-
-#define IDE_DEVSET(_name, _flags, _get, _set) \
-static __IDE_DEVSET(_name, _flags, _get, _set)
-
-#define ide_devset_rw(_name, _func) \
-IDE_DEVSET(_name, 0, get_##_func, set_##_func)
-
-#define ide_devset_w(_name, _func) \
-IDE_DEVSET(_name, 0, NULL, set_##_func)
-
-#define ide_ext_devset_rw(_name, _func) \
-__IDE_DEVSET(_name, 0, get_##_func, set_##_func)
-
-#define ide_ext_devset_rw_sync(_name, _func) \
-__IDE_DEVSET(_name, DS_SYNC, get_##_func, set_##_func)
-
-#define ide_decl_devset(_name) \
-extern const struct ide_devset ide_devset_##_name
-
-ide_decl_devset(io_32bit);
-ide_decl_devset(keepsettings);
-ide_decl_devset(pio_mode);
-ide_decl_devset(unmaskirq);
-ide_decl_devset(using_dma);
-
-#ifdef CONFIG_IDE_PROC_FS
-/*
- * /proc/ide interface
- */
-
-#define ide_devset_rw_field(_name, _field) \
-ide_devset_get(_name, _field); \
-ide_devset_set(_name, _field); \
-IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
-
-#define ide_devset_ro_field(_name, _field) \
-ide_devset_get(_name, _field); \
-IDE_DEVSET(_name, 0, get_##_name, NULL)
-
-#define ide_devset_rw_flag(_name, _field) \
-ide_devset_get_flag(_name, _field); \
-ide_devset_set_flag(_name, _field); \
-IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
-
-struct ide_proc_devset {
-       const char              *name;
-       const struct ide_devset *setting;
-       int                     min, max;
-       int                     (*mulf)(ide_drive_t *);
-       int                     (*divf)(ide_drive_t *);
-};
-
-#define __IDE_PROC_DEVSET(_name, _min, _max, _mulf, _divf) { \
-       .name = __stringify(_name), \
-       .setting = &ide_devset_##_name, \
-       .min = _min, \
-       .max = _max, \
-       .mulf = _mulf, \
-       .divf = _divf, \
-}
-
-#define IDE_PROC_DEVSET(_name, _min, _max) \
-__IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL)
-
-typedef struct {
-       const char      *name;
-       umode_t         mode;
-       int (*show)(struct seq_file *, void *);
-} ide_proc_entry_t;
-
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void ide_proc_register_port(ide_hwif_t *);
-void ide_proc_port_register_devices(ide_hwif_t *);
-void ide_proc_unregister_device(ide_drive_t *);
-void ide_proc_unregister_port(ide_hwif_t *);
-void ide_proc_register_driver(ide_drive_t *, struct ide_driver *);
-void ide_proc_unregister_driver(ide_drive_t *, struct ide_driver *);
-
-int ide_capacity_proc_show(struct seq_file *m, void *v);
-int ide_geometry_proc_show(struct seq_file *m, void *v);
-#else
-static inline void proc_ide_create(void) { ; }
-static inline void proc_ide_destroy(void) { ; }
-static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; }
-static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
-static inline void ide_proc_register_driver(ide_drive_t *drive,
-                                           struct ide_driver *driver) { ; }
-static inline void ide_proc_unregister_driver(ide_drive_t *drive,
-                                             struct ide_driver *driver) { ; }
-#endif
-
-enum {
-       /* enter/exit functions */
-       IDE_DBG_FUNC =                  BIT(0),
-       /* sense key/asc handling */
-       IDE_DBG_SENSE =                 BIT(1),
-       /* packet commands handling */
-       IDE_DBG_PC =                    BIT(2),
-       /* request handling */
-       IDE_DBG_RQ =                    BIT(3),
-       /* driver probing/setup */
-       IDE_DBG_PROBE =                 BIT(4),
-};
-
-/* DRV_NAME has to be defined in the driver before using the macro below */
-#define __ide_debug_log(lvl, fmt, args...)                             \
-{                                                                      \
-       if (unlikely(drive->debug_mask & lvl))                          \
-               printk(KERN_INFO DRV_NAME ": %s: " fmt "\n",            \
-                                         __func__, ## args);           \
-}
-
-/*
- * Power Management state machine (rq->pm->pm_step).
- *
- * For each step, the core calls ide_start_power_step() first.
- * This can return:
- *     - ide_stopped : In this case, the core calls us back again unless
- *                     step have been set to ide_power_state_completed.
- *     - ide_started : In this case, the channel is left busy until an
- *                     async event (interrupt) occurs.
- * Typically, ide_start_power_step() will issue a taskfile request with
- * do_rw_taskfile().
- *
- * Upon reception of the interrupt, the core will call ide_complete_power_step()
- * with the error code if any. This routine should update the step value
- * and return. It should not start a new request. The core will call
- * ide_start_power_step() for the new step value, unless step have been
- * set to IDE_PM_COMPLETED.
- */
-enum {
-       IDE_PM_START_SUSPEND,
-       IDE_PM_FLUSH_CACHE      = IDE_PM_START_SUSPEND,
-       IDE_PM_STANDBY,
-
-       IDE_PM_START_RESUME,
-       IDE_PM_RESTORE_PIO      = IDE_PM_START_RESUME,
-       IDE_PM_IDLE,
-       IDE_PM_RESTORE_DMA,
-
-       IDE_PM_COMPLETED,
-};
-
-int generic_ide_suspend(struct device *, pm_message_t);
-int generic_ide_resume(struct device *);
-
-void ide_complete_power_step(ide_drive_t *, struct request *);
-ide_startstop_t ide_start_power_step(ide_drive_t *, struct request *);
-void ide_complete_pm_rq(ide_drive_t *, struct request *);
-void ide_check_pm_state(ide_drive_t *, struct request *);
-
-/*
- * Subdrivers support.
- *
- * The gendriver.owner field should be set to the module owner of this driver.
- * The gendriver.name field should be set to the name of this driver
- */
-struct ide_driver {
-       const char                      *version;
-       ide_startstop_t (*do_request)(ide_drive_t *, struct request *, sector_t);
-       struct device_driver    gen_driver;
-       int             (*probe)(ide_drive_t *);
-       void            (*remove)(ide_drive_t *);
-       void            (*resume)(ide_drive_t *);
-       void            (*shutdown)(ide_drive_t *);
-#ifdef CONFIG_IDE_PROC_FS
-       ide_proc_entry_t *              (*proc_entries)(ide_drive_t *);
-       const struct ide_proc_devset *  (*proc_devsets)(ide_drive_t *);
-#endif
-};
-
-#define to_ide_driver(drv) container_of(drv, struct ide_driver, gen_driver)
-
-int ide_device_get(ide_drive_t *);
-void ide_device_put(ide_drive_t *);
-
-struct ide_ioctl_devset {
-       unsigned int    get_ioctl;
-       unsigned int    set_ioctl;
-       const struct ide_devset *setting;
-};
-
-int ide_setting_ioctl(ide_drive_t *, struct block_device *, unsigned int,
-                     unsigned long, const struct ide_ioctl_devset *);
-
-int generic_ide_ioctl(ide_drive_t *, struct block_device *, unsigned, unsigned long);
-
-extern int ide_vlb_clk;
-extern int ide_pci_clk;
-
-int ide_end_rq(ide_drive_t *, struct request *, blk_status_t, unsigned int);
-void ide_kill_rq(ide_drive_t *, struct request *);
-void ide_insert_request_head(ide_drive_t *, struct request *);
-
-void __ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
-void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int);
-
-void ide_execute_command(ide_drive_t *, struct ide_cmd *, ide_handler_t *,
-                        unsigned int);
-
-void ide_pad_transfer(ide_drive_t *, int, int);
-
-ide_startstop_t ide_error(ide_drive_t *, const char *, u8);
-
-void ide_fix_driveid(u16 *);
-
-extern void ide_fixstring(u8 *, const int, const int);
-
-int ide_busy_sleep(ide_drive_t *, unsigned long, int);
-
-int __ide_wait_stat(ide_drive_t *, u8, u8, unsigned long, u8 *);
-int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
-
-ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *);
-ide_startstop_t ide_do_devset(ide_drive_t *, struct request *);
-
-extern ide_startstop_t ide_do_reset (ide_drive_t *);
-
-extern int ide_devset_execute(ide_drive_t *drive,
-                             const struct ide_devset *setting, int arg);
-
-void ide_complete_cmd(ide_drive_t *, struct ide_cmd *, u8, u8);
-int ide_complete_rq(ide_drive_t *, blk_status_t, unsigned int);
-
-void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd);
-void ide_tf_dump(const char *, struct ide_cmd *);
-
-void ide_exec_command(ide_hwif_t *, u8);
-u8 ide_read_status(ide_hwif_t *);
-u8 ide_read_altstatus(ide_hwif_t *);
-void ide_write_devctl(ide_hwif_t *, u8);
-
-void ide_dev_select(ide_drive_t *);
-void ide_tf_load(ide_drive_t *, struct ide_taskfile *, u8);
-void ide_tf_read(ide_drive_t *, struct ide_taskfile *, u8);
-
-void ide_input_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
-void ide_output_data(ide_drive_t *, struct ide_cmd *, void *, unsigned int);
-
-void SELECT_MASK(ide_drive_t *, int);
-
-u8 ide_read_error(ide_drive_t *);
-void ide_read_bcount_and_ireason(ide_drive_t *, u16 *, u8 *);
-
-int ide_check_ireason(ide_drive_t *, struct request *, int, int, int);
-
-int ide_check_atapi_device(ide_drive_t *, const char *);
-
-void ide_init_pc(struct ide_atapi_pc *);
-
-/* Disk head parking */
-extern wait_queue_head_t ide_park_wq;
-ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
-                     char *buf);
-ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
-                      const char *buf, size_t len);
-
-/*
- * Special requests for ide-tape block device strategy routine.
- *
- * In order to service a character device command, we add special requests to
- * the tail of our block device request queue and wait for their completion.
- */
-enum {
-       REQ_IDETAPE_PC1         = BIT(0), /* packet command (first stage) */
-       REQ_IDETAPE_PC2         = BIT(1), /* packet command (second stage) */
-       REQ_IDETAPE_READ        = BIT(2),
-       REQ_IDETAPE_WRITE       = BIT(3),
-};
-
-int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *,
-                     void *, unsigned int);
-
-int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
-int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
-int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
-void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
-void ide_retry_pc(ide_drive_t *drive);
-
-void ide_prep_sense(ide_drive_t *drive, struct request *rq);
-int ide_queue_sense_rq(ide_drive_t *drive, void *special);
-
-int ide_cd_expiry(ide_drive_t *);
-
-int ide_cd_get_xferlen(struct request *);
-
-ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_cmd *);
-
-ide_startstop_t do_rw_taskfile(ide_drive_t *, struct ide_cmd *);
-
-void ide_pio_bytes(ide_drive_t *, struct ide_cmd *, unsigned int, unsigned int);
-
-void ide_finish_cmd(ide_drive_t *, struct ide_cmd *, u8);
-
-int ide_raw_taskfile(ide_drive_t *, struct ide_cmd *, u8 *, u16);
-int ide_no_data_taskfile(ide_drive_t *, struct ide_cmd *);
-
-int ide_taskfile_ioctl(ide_drive_t *, unsigned long);
-
-int ide_dev_read_id(ide_drive_t *, u8, u16 *, int);
-
-extern int ide_driveid_update(ide_drive_t *);
-extern int ide_config_drive_speed(ide_drive_t *, u8);
-extern u8 eighty_ninty_three (ide_drive_t *);
-extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
-
-extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout);
-
-extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
-
-extern void ide_timer_expiry(struct timer_list *t);
-extern irqreturn_t ide_intr(int irq, void *dev_id);
-extern blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);
-extern blk_status_t ide_issue_rq(ide_drive_t *, struct request *, bool);
-extern void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq);
-
-void ide_init_disk(struct gendisk *, ide_drive_t *);
-
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
-#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
-#else
-#define ide_pci_register_driver(d) pci_register_driver(d)
-#endif
-
-static inline int ide_pci_is_in_compatibility_mode(struct pci_dev *dev)
-{
-       if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5)
-               return 1;
-       return 0;
-}
-
-void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *,
-                        struct ide_hw *, struct ide_hw **);
-void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-int ide_pci_set_master(struct pci_dev *, const char *);
-unsigned long ide_pci_dma_base(ide_hwif_t *, const struct ide_port_info *);
-int ide_pci_check_simplex(ide_hwif_t *, const struct ide_port_info *);
-int ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *);
-#else
-static inline int ide_hwif_setup_dma(ide_hwif_t *hwif,
-                                    const struct ide_port_info *d)
-{
-       return -EINVAL;
-}
-#endif
-
-struct ide_pci_enablebit {
-       u8      reg;    /* byte pci reg holding the enable-bit */
-       u8      mask;   /* mask to isolate the enable-bit */
-       u8      val;    /* value of masked reg when "enabled" */
-};
-
-enum {
-       /* Uses ISA control ports not PCI ones. */
-       IDE_HFLAG_ISA_PORTS             = BIT(0),
-       /* single port device */
-       IDE_HFLAG_SINGLE                = BIT(1),
-       /* don't use legacy PIO blacklist */
-       IDE_HFLAG_PIO_NO_BLACKLIST      = BIT(2),
-       /* set for the second port of QD65xx */
-       IDE_HFLAG_QD_2ND_PORT           = BIT(3),
-       /* use PIO8/9 for prefetch off/on */
-       IDE_HFLAG_ABUSE_PREFETCH        = BIT(4),
-       /* use PIO6/7 for fast-devsel off/on */
-       IDE_HFLAG_ABUSE_FAST_DEVSEL     = BIT(5),
-       /* use 100-102 and 200-202 PIO values to set DMA modes */
-       IDE_HFLAG_ABUSE_DMA_MODES       = BIT(6),
-       /*
-        * keep DMA setting when programming PIO mode, may be used only
-        * for hosts which have separate PIO and DMA timings (ie. PMAC)
-        */
-       IDE_HFLAG_SET_PIO_MODE_KEEP_DMA = BIT(7),
-       /* program host for the transfer mode after programming device */
-       IDE_HFLAG_POST_SET_MODE         = BIT(8),
-       /* don't program host/device for the transfer mode ("smart" hosts) */
-       IDE_HFLAG_NO_SET_MODE           = BIT(9),
-       /* trust BIOS for programming chipset/device for DMA */
-       IDE_HFLAG_TRUST_BIOS_FOR_DMA    = BIT(10),
-       /* host is CS5510/CS5520 */
-       IDE_HFLAG_CS5520                = BIT(11),
-       /* ATAPI DMA is unsupported */
-       IDE_HFLAG_NO_ATAPI_DMA          = BIT(12),
-       /* set if host is a "non-bootable" controller */
-       IDE_HFLAG_NON_BOOTABLE          = BIT(13),
-       /* host doesn't support DMA */
-       IDE_HFLAG_NO_DMA                = BIT(14),
-       /* check if host is PCI IDE device before allowing DMA */
-       IDE_HFLAG_NO_AUTODMA            = BIT(15),
-       /* host uses MMIO */
-       IDE_HFLAG_MMIO                  = BIT(16),
-       /* no LBA48 */
-       IDE_HFLAG_NO_LBA48              = BIT(17),
-       /* no LBA48 DMA */
-       IDE_HFLAG_NO_LBA48_DMA          = BIT(18),
-       /* data FIFO is cleared by an error */
-       IDE_HFLAG_ERROR_STOPS_FIFO      = BIT(19),
-       /* serialize ports */
-       IDE_HFLAG_SERIALIZE             = BIT(20),
-       /* host is DTC2278 */
-       IDE_HFLAG_DTC2278               = BIT(21),
-       /* 4 devices on a single set of I/O ports */
-       IDE_HFLAG_4DRIVES               = BIT(22),
-       /* host is TRM290 */
-       IDE_HFLAG_TRM290                = BIT(23),
-       /* use 32-bit I/O ops */
-       IDE_HFLAG_IO_32BIT              = BIT(24),
-       /* unmask IRQs */
-       IDE_HFLAG_UNMASK_IRQS           = BIT(25),
-       IDE_HFLAG_BROKEN_ALTSTATUS      = BIT(26),
-       /* serialize ports if DMA is possible (for sl82c105) */
-       IDE_HFLAG_SERIALIZE_DMA         = BIT(27),
-       /* force host out of "simplex" mode */
-       IDE_HFLAG_CLEAR_SIMPLEX         = BIT(28),
-       /* DSC overlap is unsupported */
-       IDE_HFLAG_NO_DSC                = BIT(29),
-       /* never use 32-bit I/O ops */
-       IDE_HFLAG_NO_IO_32BIT           = BIT(30),
-       /* never unmask IRQs */
-       IDE_HFLAG_NO_UNMASK_IRQS        = BIT(31),
-};
-
-#ifdef CONFIG_BLK_DEV_OFFBOARD
-# define IDE_HFLAG_OFF_BOARD   0
-#else
-# define IDE_HFLAG_OFF_BOARD   IDE_HFLAG_NON_BOOTABLE
-#endif
-
-struct ide_port_info {
-       char                    *name;
-
-       int                     (*init_chipset)(struct pci_dev *);
-
-       void                    (*get_lock)(irq_handler_t, void *);
-       void                    (*release_lock)(void);
-
-       void                    (*init_iops)(ide_hwif_t *);
-       void                    (*init_hwif)(ide_hwif_t *);
-       int                     (*init_dma)(ide_hwif_t *,
-                                           const struct ide_port_info *);
-
-       const struct ide_tp_ops         *tp_ops;
-       const struct ide_port_ops       *port_ops;
-       const struct ide_dma_ops        *dma_ops;
-
-       struct ide_pci_enablebit        enablebits[2];
-
-       hwif_chipset_t          chipset;
-
-       u16                     max_sectors;    /* if < than the default one */
-
-       u32                     host_flags;
-
-       int                     irq_flags;
-
-       u8                      pio_mask;
-       u8                      swdma_mask;
-       u8                      mwdma_mask;
-       u8                      udma_mask;
-};
-
-/*
- * State information carried for REQ_TYPE_ATA_PM_SUSPEND and REQ_TYPE_ATA_PM_RESUME
- * requests.
- */
-struct ide_pm_state {
-       /* PM state machine step value, currently driver specific */
-       int     pm_step;
-       /* requested PM state value (S1, S2, S3, S4, ...) */
-       u32     pm_state;
-       void*   data;           /* for driver use */
-};
-
-
-int ide_pci_init_one(struct pci_dev *, const struct ide_port_info *, void *);
-int ide_pci_init_two(struct pci_dev *, struct pci_dev *,
-                    const struct ide_port_info *, void *);
-void ide_pci_remove(struct pci_dev *);
-
-#ifdef CONFIG_PM
-int ide_pci_suspend(struct pci_dev *, pm_message_t);
-int ide_pci_resume(struct pci_dev *);
-#else
-#define ide_pci_suspend NULL
-#define ide_pci_resume NULL
-#endif
-
-void ide_map_sg(ide_drive_t *, struct ide_cmd *);
-void ide_init_sg_cmd(struct ide_cmd *, unsigned int);
-
-#define BAD_DMA_DRIVE          0
-#define GOOD_DMA_DRIVE         1
-
-struct drive_list_entry {
-       const char *id_model;
-       const char *id_firmware;
-};
-
-int ide_in_drive_list(u16 *, const struct drive_list_entry *);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-int ide_dma_good_drive(ide_drive_t *);
-int __ide_dma_bad_drive(ide_drive_t *);
-
-u8 ide_find_dma_mode(ide_drive_t *, u8);
-
-static inline u8 ide_max_dma_mode(ide_drive_t *drive)
-{
-       return ide_find_dma_mode(drive, XFER_UDMA_6);
-}
-
-void ide_dma_off_quietly(ide_drive_t *);
-void ide_dma_off(ide_drive_t *);
-void ide_dma_on(ide_drive_t *);
-int ide_set_dma(ide_drive_t *);
-void ide_check_dma_crc(ide_drive_t *);
-ide_startstop_t ide_dma_intr(ide_drive_t *);
-
-int ide_allocate_dma_engine(ide_hwif_t *);
-void ide_release_dma_engine(ide_hwif_t *);
-
-int ide_dma_prepare(ide_drive_t *, struct ide_cmd *);
-void ide_dma_unmap_sg(ide_drive_t *, struct ide_cmd *);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
-int config_drive_for_dma(ide_drive_t *);
-int ide_build_dmatable(ide_drive_t *, struct ide_cmd *);
-void ide_dma_host_set(ide_drive_t *, int);
-int ide_dma_setup(ide_drive_t *, struct ide_cmd *);
-extern void ide_dma_start(ide_drive_t *);
-int ide_dma_end(ide_drive_t *);
-int ide_dma_test_irq(ide_drive_t *);
-int ide_dma_sff_timer_expiry(ide_drive_t *);
-u8 ide_dma_sff_read_status(ide_hwif_t *);
-extern const struct ide_dma_ops sff_dma_ops;
-#else
-static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
-#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
-
-void ide_dma_lost_irq(ide_drive_t *);
-ide_startstop_t ide_dma_timeout_retry(ide_drive_t *, int);
-
-#else
-static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
-static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
-static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; }
-static inline void ide_dma_off(ide_drive_t *drive) { ; }
-static inline void ide_dma_on(ide_drive_t *drive) { ; }
-static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
-static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
-static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
-static inline ide_startstop_t ide_dma_intr(ide_drive_t *drive) { return ide_stopped; }
-static inline ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { return ide_stopped; }
-static inline void ide_release_dma_engine(ide_hwif_t *hwif) { ; }
-static inline int ide_dma_prepare(ide_drive_t *drive,
-                                 struct ide_cmd *cmd) { return 1; }
-static inline void ide_dma_unmap_sg(ide_drive_t *drive,
-                                   struct ide_cmd *cmd) { ; }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-#ifdef CONFIG_BLK_DEV_IDEACPI
-int ide_acpi_init(void);
-bool ide_port_acpi(ide_hwif_t *hwif);
-extern int ide_acpi_exec_tfs(ide_drive_t *drive);
-extern void ide_acpi_get_timing(ide_hwif_t *hwif);
-extern void ide_acpi_push_timing(ide_hwif_t *hwif);
-void ide_acpi_init_port(ide_hwif_t *);
-void ide_acpi_port_init_devices(ide_hwif_t *);
-extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
-#else
-static inline int ide_acpi_init(void) { return 0; }
-static inline bool ide_port_acpi(ide_hwif_t *hwif) { return 0; }
-static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
-static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
-static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
-static inline void ide_acpi_init_port(ide_hwif_t *hwif) { ; }
-static inline void ide_acpi_port_init_devices(ide_hwif_t *hwif) { ; }
-static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
-#endif
-
-void ide_check_nien_quirk_list(ide_drive_t *);
-void ide_undecoded_slave(ide_drive_t *);
-
-void ide_port_apply_params(ide_hwif_t *);
-int ide_sysfs_register_port(ide_hwif_t *);
-
-struct ide_host *ide_host_alloc(const struct ide_port_info *, struct ide_hw **,
-                               unsigned int);
-void ide_host_free(struct ide_host *);
-int ide_host_register(struct ide_host *, const struct ide_port_info *,
-                     struct ide_hw **);
-int ide_host_add(const struct ide_port_info *, struct ide_hw **, unsigned int,
-                struct ide_host **);
-void ide_host_remove(struct ide_host *);
-int ide_legacy_device_add(const struct ide_port_info *, unsigned long);
-void ide_port_unregister_devices(ide_hwif_t *);
-void ide_port_scan(ide_hwif_t *);
-
-static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
-{
-       return hwif->hwif_data;
-}
-
-static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
-{
-       hwif->hwif_data = data;
-}
-
-u64 ide_get_lba_addr(struct ide_cmd *, int);
-u8 ide_dump_status(ide_drive_t *, const char *, u8);
-
-struct ide_timing {
-       u8  mode;
-       u8  setup;      /* t1 */
-       u16 act8b;      /* t2 for 8-bit io */
-       u16 rec8b;      /* t2i for 8-bit io */
-       u16 cyc8b;      /* t0 for 8-bit io */
-       u16 active;     /* t2 or tD */
-       u16 recover;    /* t2i or tK */
-       u16 cycle;      /* t0 */
-       u16 udma;       /* t2CYCTYP/2 */
-};
-
-enum {
-       IDE_TIMING_SETUP        = BIT(0),
-       IDE_TIMING_ACT8B        = BIT(1),
-       IDE_TIMING_REC8B        = BIT(2),
-       IDE_TIMING_CYC8B        = BIT(3),
-       IDE_TIMING_8BIT         = IDE_TIMING_ACT8B | IDE_TIMING_REC8B |
-                                 IDE_TIMING_CYC8B,
-       IDE_TIMING_ACTIVE       = BIT(4),
-       IDE_TIMING_RECOVER      = BIT(5),
-       IDE_TIMING_CYCLE        = BIT(6),
-       IDE_TIMING_UDMA         = BIT(7),
-       IDE_TIMING_ALL          = IDE_TIMING_SETUP | IDE_TIMING_8BIT |
-                                 IDE_TIMING_ACTIVE | IDE_TIMING_RECOVER |
-                                 IDE_TIMING_CYCLE | IDE_TIMING_UDMA,
-};
-
-struct ide_timing *ide_timing_find_mode(u8);
-u16 ide_pio_cycle_time(ide_drive_t *, u8);
-void ide_timing_merge(struct ide_timing *, struct ide_timing *,
-                     struct ide_timing *, unsigned int);
-int ide_timing_compute(ide_drive_t *, u8, struct ide_timing *, int, int);
-
-#ifdef CONFIG_IDE_XFER_MODE
-int ide_scan_pio_blacklist(char *);
-const char *ide_xfer_verbose(u8);
-int ide_pio_need_iordy(ide_drive_t *, const u8);
-int ide_set_pio_mode(ide_drive_t *, u8);
-int ide_set_dma_mode(ide_drive_t *, u8);
-void ide_set_pio(ide_drive_t *, u8);
-int ide_set_xfer_rate(ide_drive_t *, u8);
-#else
-static inline void ide_set_pio(ide_drive_t *drive, u8 pio) { ; }
-static inline int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { return -1; }
-#endif
-
-static inline void ide_set_max_pio(ide_drive_t *drive)
-{
-       ide_set_pio(drive, 255);
-}
-
-char *ide_media_string(ide_drive_t *);
-
-extern const struct attribute_group *ide_dev_groups[];
-extern struct bus_type ide_bus_type;
-extern struct class *ide_port_class;
-
-static inline void ide_dump_identify(u8 *id)
-{
-       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0);
-}
-
-static inline int hwif_to_node(ide_hwif_t *hwif)
-{
-       return hwif->dev ? dev_to_node(hwif->dev) : -1;
-}
-
-static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive)
-{
-       ide_drive_t *peer = drive->hwif->devices[(drive->dn ^ 1) & 1];
-
-       return (peer->dev_flags & IDE_DFLAG_PRESENT) ? peer : NULL;
-}
-
-static inline void *ide_get_drivedata(ide_drive_t *drive)
-{
-       return drive->drive_data;
-}
-
-static inline void ide_set_drivedata(ide_drive_t *drive, void *data)
-{
-       drive->drive_data = data;
-}
-
-#define ide_port_for_each_dev(i, dev, port) \
-       for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++)
-
-#define ide_port_for_each_present_dev(i, dev, port) \
-       for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++) \
-               if ((dev)->dev_flags & IDE_DFLAG_PRESENT)
-
-#define ide_host_for_each_port(i, port, host) \
-       for ((i) = 0; ((port) = (host)->ports[i]) || (i) < MAX_HOST_PORTS; (i)++)
-
-
-#endif /* _IDE_H */
index 93e2ad6..fa2cd8c 100644 (file)
@@ -4,13 +4,16 @@
 
 #if defined(CONFIG_DEBUG_ENTRY) && defined(CONFIG_STACK_VALIDATION)
 
+#include <linux/stringify.h>
+
 /* Begin/end of an instrumentation safe region */
-#define instrumentation_begin() ({                                     \
-       asm volatile("%c0: nop\n\t"                                             \
+#define __instrumentation_begin(c) ({                                  \
+       asm volatile(__stringify(c) ": nop\n\t"                         \
                     ".pushsection .discard.instr_begin\n\t"            \
-                    ".long %c0b - .\n\t"                               \
-                    ".popsection\n\t" : : "i" (__COUNTER__));          \
+                    ".long " __stringify(c) "b - .\n\t"                \
+                    ".popsection\n\t");                                \
 })
+#define instrumentation_begin() __instrumentation_begin(__COUNTER__)
 
 /*
  * Because instrumentation_{begin,end}() can nest, objtool validation considers
  * To avoid this, have _end() be a NOP instruction, this ensures it will be
  * part of the condition block and does not escape.
  */
-#define instrumentation_end() ({                                       \
-       asm volatile("%c0: nop\n\t"                                     \
+#define __instrumentation_end(c) ({                                    \
+       asm volatile(__stringify(c) ": nop\n\t"                         \
                     ".pushsection .discard.instr_end\n\t"              \
-                    ".long %c0b - .\n\t"                               \
-                    ".popsection\n\t" : : "i" (__COUNTER__));          \
+                    ".long " __stringify(c) "b - .\n\t"                \
+                    ".popsection\n\t");                                \
 })
+#define instrumentation_end() __instrumentation_end(__COUNTER__)
 #else
 # define instrumentation_begin()       do { } while(0)
 # define instrumentation_end()         do { } while(0)
index 2271939..2ea0f2f 100644 (file)
@@ -13,6 +13,7 @@ enum integrity_status {
        INTEGRITY_PASS = 0,
        INTEGRITY_PASS_IMMUTABLE,
        INTEGRITY_FAIL,
+       INTEGRITY_FAIL_IMMUTABLE,
        INTEGRITY_NOLABEL,
        INTEGRITY_NOXATTRS,
        INTEGRITY_UNKNOWN,
index 4777850..2ed65b0 100644 (file)
@@ -64,6 +64,8 @@
  * IRQF_NO_AUTOEN - Don't enable IRQ or NMI automatically when users request it.
  *                Users will enable it explicitly by enable_irq() or enable_nmi()
  *                later.
+ * IRQF_NO_DEBUG - Exclude from runnaway detection for IPI and similar handlers,
+ *                depends on IRQF_PERCPU.
  */
 #define IRQF_SHARED            0x00000080
 #define IRQF_PROBE_SHARED      0x00000100
@@ -78,6 +80,7 @@
 #define IRQF_EARLY_RESUME      0x00020000
 #define IRQF_COND_SUSPEND      0x00040000
 #define IRQF_NO_AUTOEN         0x00080000
+#define IRQF_NO_DEBUG          0x00100000
 
 #define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
@@ -319,39 +322,8 @@ struct irq_affinity_desc {
 
 extern cpumask_var_t irq_default_affinity;
 
-/* Internal implementation. Use the helpers below */
-extern int __irq_set_affinity(unsigned int irq, const struct cpumask *cpumask,
-                             bool force);
-
-/**
- * irq_set_affinity - Set the irq affinity of a given irq
- * @irq:       Interrupt to set affinity
- * @cpumask:   cpumask
- *
- * Fails if cpumask does not contain an online CPU
- */
-static inline int
-irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
-{
-       return __irq_set_affinity(irq, cpumask, false);
-}
-
-/**
- * irq_force_affinity - Force the irq affinity of a given irq
- * @irq:       Interrupt to set affinity
- * @cpumask:   cpumask
- *
- * Same as irq_set_affinity, but without checking the mask against
- * online cpus.
- *
- * Solely for low level cpu hotplug code, where we need to make per
- * cpu interrupts affine before the cpu becomes online.
- */
-static inline int
-irq_force_affinity(unsigned int irq, const struct cpumask *cpumask)
-{
-       return __irq_set_affinity(irq, cpumask, true);
-}
+extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask);
+extern int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask);
 
 extern int irq_can_set_affinity(unsigned int irq);
 extern int irq_select_affinity(unsigned int irq);
index 31b347c..8e9a9ae 100644 (file)
@@ -72,6 +72,7 @@ enum irqchip_irq_state;
  *                               mechanism and from core side polling.
  * IRQ_DISABLE_UNLAZY          - Disable lazy irq disable
  * IRQ_HIDDEN                  - Don't show up in /proc/interrupts
+ * IRQ_NO_DEBUG                        - Exclude from note_interrupt() debugging
  */
 enum {
        IRQ_TYPE_NONE           = 0x00000000,
@@ -99,6 +100,7 @@ enum {
        IRQ_IS_POLLED           = (1 << 18),
        IRQ_DISABLE_UNLAZY      = (1 << 19),
        IRQ_HIDDEN              = (1 << 20),
+       IRQ_NO_DEBUG            = (1 << 21),
 };
 
 #define IRQF_MODIFY_MASK       \
index fa8c045..1177f3a 100644 (file)
@@ -7,8 +7,7 @@
 #ifndef __LINUX_IRQCHIP_ARM_GIC_COMMON_H
 #define __LINUX_IRQCHIP_ARM_GIC_COMMON_H
 
-#include <linux/types.h>
-#include <linux/ioport.h>
+#include <linux/irqchip/arm-vgic-info.h>
 
 #define GICD_INT_DEF_PRI               0xa0
 #define GICD_INT_DEF_PRI_X4            ((GICD_INT_DEF_PRI << 24) |\
                                        (GICD_INT_DEF_PRI << 8) |\
                                        GICD_INT_DEF_PRI)
 
-enum gic_type {
-       GIC_V2,
-       GIC_V3,
-};
-
-struct gic_kvm_info {
-       /* GIC type */
-       enum gic_type   type;
-       /* Virtual CPU interface */
-       struct resource vcpu;
-       /* Interrupt number */
-       unsigned int    maint_irq;
-       /* Virtual control interface */
-       struct resource vctrl;
-       /* vlpi support */
-       bool            has_v4;
-       /* rvpeid support */
-       bool            has_v4_1;
-};
-
-const struct gic_kvm_info *gic_get_kvm_info(void);
-
 struct irq_domain;
 struct fwnode_handle;
 int gicv2m_init(struct fwnode_handle *parent_handle,
diff --git a/include/linux/irqchip/arm-vgic-info.h b/include/linux/irqchip/arm-vgic-info.h
new file mode 100644 (file)
index 0000000..a75b2c7
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * include/linux/irqchip/arm-vgic-info.h
+ *
+ * Copyright (C) 2016 ARM Limited, All Rights Reserved.
+ */
+#ifndef __LINUX_IRQCHIP_ARM_VGIC_INFO_H
+#define __LINUX_IRQCHIP_ARM_VGIC_INFO_H
+
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+enum gic_type {
+       /* Full GICv2 */
+       GIC_V2,
+       /* Full GICv3, optionally with v2 compat */
+       GIC_V3,
+};
+
+struct gic_kvm_info {
+       /* GIC type */
+       enum gic_type   type;
+       /* Virtual CPU interface */
+       struct resource vcpu;
+       /* Interrupt number */
+       unsigned int    maint_irq;
+       /* No interrupt mask, no need to use the above field */
+       bool            no_maint_irq_mask;
+       /* Virtual control interface */
+       struct resource vctrl;
+       /* vlpi support */
+       bool            has_v4;
+       /* rvpeid support */
+       bool            has_v4_1;
+       /* Deactivation impared, subpar stuff */
+       bool            no_hw_deactivation;
+};
+
+#ifdef CONFIG_KVM
+void vgic_set_kvm_info(const struct gic_kvm_info *info);
+#else
+static inline void vgic_set_kvm_info(const struct gic_kvm_info *info) {}
+#endif
+
+#endif
index df46512..59aea39 100644 (file)
@@ -158,25 +158,21 @@ static inline void generic_handle_irq_desc(struct irq_desc *desc)
        desc->handle_irq(desc);
 }
 
+int handle_irq_desc(struct irq_desc *desc);
 int generic_handle_irq(unsigned int irq);
 
-#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+#ifdef CONFIG_IRQ_DOMAIN
 /*
  * Convert a HW interrupt number to a logical one using a IRQ domain,
  * and handle the result interrupt number. Return -EINVAL if
- * conversion failed. Providing a NULL domain indicates that the
- * conversion has already been done.
+ * conversion failed.
  */
-int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
-                       bool lookup, struct pt_regs *regs);
+int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
 
-static inline int handle_domain_irq(struct irq_domain *domain,
-                                   unsigned int hwirq, struct pt_regs *regs)
-{
-       return __handle_domain_irq(domain, hwirq, true, regs);
-}
+#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+int handle_domain_irq(struct irq_domain *domain,
+                     unsigned int hwirq, struct pt_regs *regs);
 
-#ifdef CONFIG_IRQ_DOMAIN
 int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
                      struct pt_regs *regs);
 #endif
index 62a8e3d..23e4ee5 100644 (file)
@@ -41,13 +41,11 @@ struct fwnode_handle;
 struct irq_domain;
 struct irq_chip;
 struct irq_data;
+struct irq_desc;
 struct cpumask;
 struct seq_file;
 struct irq_affinity_desc;
 
-/* Number of irqs reserved for a legacy isa controller */
-#define NUM_ISA_INTERRUPTS     16
-
 #define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16
 
 /**
@@ -152,11 +150,10 @@ struct irq_domain_chip_generic;
  * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
  *
  * Revmap data, used internally by irq_domain
- * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
- *                         support direct mapping
- * @revmap_size: Size of the linear map table @linear_revmap[]
+ * @revmap_size: Size of the linear map table @revmap[]
  * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
- * @linear_revmap: Linear table of hwirq->virq reverse mappings
+ * @revmap_mutex: Lock for the revmap
+ * @revmap: Linear table of irq_data pointers
  */
 struct irq_domain {
        struct list_head link;
@@ -176,11 +173,10 @@ struct irq_domain {
 
        /* reverse map data. The linear map gets appended to the irq_domain */
        irq_hw_number_t hwirq_max;
-       unsigned int revmap_direct_max_irq;
        unsigned int revmap_size;
        struct radix_tree_root revmap_tree;
-       struct mutex revmap_tree_mutex;
-       unsigned int linear_revmap[];
+       struct mutex revmap_mutex;
+       struct irq_data __rcu *revmap[];
 };
 
 /* Irq domain flags */
@@ -210,6 +206,9 @@ enum {
         */
        IRQ_DOMAIN_MSI_NOMASK_QUIRK     = (1 << 6),
 
+       /* Irq domain doesn't translate anything */
+       IRQ_DOMAIN_FLAG_NO_MAP          = (1 << 7),
+
        /*
         * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
         * for implementation specific purposes and ignored by the
@@ -348,6 +347,8 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
 {
        return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
 }
+
+#ifdef CONFIG_IRQ_DOMAIN_NOMAP
 static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
                                         unsigned int max_irq,
                                         const struct irq_domain_ops *ops,
@@ -355,14 +356,10 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod
 {
        return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data);
 }
-static inline struct irq_domain *irq_domain_add_legacy_isa(
-                               struct device_node *of_node,
-                               const struct irq_domain_ops *ops,
-                               void *host_data)
-{
-       return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
-                                    host_data);
-}
+
+extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
+#endif
+
 static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
                                         const struct irq_domain_ops *ops,
                                         void *host_data)
@@ -405,25 +402,37 @@ static inline unsigned int irq_create_mapping(struct irq_domain *host,
        return irq_create_mapping_affinity(host, hwirq, NULL);
 }
 
+extern struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
+                                             irq_hw_number_t hwirq,
+                                             unsigned int *irq);
+
+static inline struct irq_desc *irq_resolve_mapping(struct irq_domain *domain,
+                                                  irq_hw_number_t hwirq)
+{
+       return __irq_resolve_mapping(domain, hwirq, NULL);
+}
 
 /**
- * irq_linear_revmap() - Find a linux irq from a hw irq number.
+ * irq_find_mapping() - Find a linux irq from a hw irq number.
  * @domain: domain owning this hardware interrupt
  * @hwirq: hardware irq number in that domain space
- *
- * This is a fast path alternative to irq_find_mapping() that can be
- * called directly by irq controller code to save a handful of
- * instructions. It is always safe to call, but won't find irqs mapped
- * using the radix tree.
  */
+static inline unsigned int irq_find_mapping(struct irq_domain *domain,
+                                           irq_hw_number_t hwirq)
+{
+       unsigned int irq;
+
+       if (__irq_resolve_mapping(domain, hwirq, &irq))
+               return irq;
+
+       return 0;
+}
+
 static inline unsigned int irq_linear_revmap(struct irq_domain *domain,
                                             irq_hw_number_t hwirq)
 {
-       return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0;
+       return irq_find_mapping(domain, hwirq);
 }
-extern unsigned int irq_find_mapping(struct irq_domain *host,
-                                    irq_hw_number_t hwirq);
-extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
 
 extern const struct irq_domain_ops irq_domain_simple_ops;
 
index 05f5554..48b9b2a 100644 (file)
@@ -171,9 +171,21 @@ static inline bool jump_entry_is_init(const struct jump_entry *entry)
        return (unsigned long)entry->key & 2UL;
 }
 
-static inline void jump_entry_set_init(struct jump_entry *entry)
+static inline void jump_entry_set_init(struct jump_entry *entry, bool set)
 {
-       entry->key |= 2;
+       if (set)
+               entry->key |= 2;
+       else
+               entry->key &= ~2;
+}
+
+static inline int jump_entry_size(struct jump_entry *entry)
+{
+#ifdef JUMP_LABEL_NOP_SIZE
+       return JUMP_LABEL_NOP_SIZE;
+#else
+       return arch_jump_entry_size(entry);
+#endif
 }
 
 #endif
index b1678a6..a1c7ce5 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _LINUX_KASAN_H
 #define _LINUX_KASAN_H
 
+#include <linux/bug.h>
 #include <linux/static_key.h>
 #include <linux/types.h>
 
@@ -79,14 +80,6 @@ static inline void kasan_disable_current(void) {}
 
 #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
 
-#ifdef CONFIG_KASAN
-
-struct kasan_cache {
-       int alloc_meta_offset;
-       int free_meta_offset;
-       bool is_kmalloc;
-};
-
 #ifdef CONFIG_KASAN_HW_TAGS
 
 DECLARE_STATIC_KEY_FALSE(kasan_flag_enabled);
@@ -101,11 +94,14 @@ static inline bool kasan_has_integrated_init(void)
        return kasan_enabled();
 }
 
+void kasan_alloc_pages(struct page *page, unsigned int order, gfp_t flags);
+void kasan_free_pages(struct page *page, unsigned int order);
+
 #else /* CONFIG_KASAN_HW_TAGS */
 
 static inline bool kasan_enabled(void)
 {
-       return true;
+       return IS_ENABLED(CONFIG_KASAN);
 }
 
 static inline bool kasan_has_integrated_init(void)
@@ -113,8 +109,30 @@ static inline bool kasan_has_integrated_init(void)
        return false;
 }
 
+static __always_inline void kasan_alloc_pages(struct page *page,
+                                             unsigned int order, gfp_t flags)
+{
+       /* Only available for integrated init. */
+       BUILD_BUG();
+}
+
+static __always_inline void kasan_free_pages(struct page *page,
+                                            unsigned int order)
+{
+       /* Only available for integrated init. */
+       BUILD_BUG();
+}
+
 #endif /* CONFIG_KASAN_HW_TAGS */
 
+#ifdef CONFIG_KASAN
+
+struct kasan_cache {
+       int alloc_meta_offset;
+       int free_meta_offset;
+       bool is_kmalloc;
+};
+
 slab_flags_t __kasan_never_merge(void);
 static __always_inline slab_flags_t kasan_never_merge(void)
 {
@@ -130,20 +148,20 @@ static __always_inline void kasan_unpoison_range(const void *addr, size_t size)
                __kasan_unpoison_range(addr, size);
 }
 
-void __kasan_alloc_pages(struct page *page, unsigned int order, bool init);
-static __always_inline void kasan_alloc_pages(struct page *page,
+void __kasan_poison_pages(struct page *page, unsigned int order, bool init);
+static __always_inline void kasan_poison_pages(struct page *page,
                                                unsigned int order, bool init)
 {
        if (kasan_enabled())
-               __kasan_alloc_pages(page, order, init);
+               __kasan_poison_pages(page, order, init);
 }
 
-void __kasan_free_pages(struct page *page, unsigned int order, bool init);
-static __always_inline void kasan_free_pages(struct page *page,
-                                               unsigned int order, bool init)
+void __kasan_unpoison_pages(struct page *page, unsigned int order, bool init);
+static __always_inline void kasan_unpoison_pages(struct page *page,
+                                                unsigned int order, bool init)
 {
        if (kasan_enabled())
-               __kasan_free_pages(page, order, init);
+               __kasan_unpoison_pages(page, order, init);
 }
 
 void __kasan_cache_create(struct kmem_cache *cache, unsigned int *size,
@@ -285,21 +303,15 @@ void kasan_restore_multi_shot(bool enabled);
 
 #else /* CONFIG_KASAN */
 
-static inline bool kasan_enabled(void)
-{
-       return false;
-}
-static inline bool kasan_has_integrated_init(void)
-{
-       return false;
-}
 static inline slab_flags_t kasan_never_merge(void)
 {
        return 0;
 }
 static inline void kasan_unpoison_range(const void *address, size_t size) {}
-static inline void kasan_alloc_pages(struct page *page, unsigned int order, bool init) {}
-static inline void kasan_free_pages(struct page *page, unsigned int order, bool init) {}
+static inline void kasan_poison_pages(struct page *page, unsigned int order,
+                                     bool init) {}
+static inline void kasan_unpoison_pages(struct page *page, unsigned int order,
+                                       bool init) {}
 static inline void kasan_cache_create(struct kmem_cache *cache,
                                      unsigned int *size,
                                      slab_flags_t *flags) {}
index 1883a4a..523ffc7 100644 (file)
@@ -54,8 +54,6 @@ struct kretprobe_instance;
 typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
 typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
                                       unsigned long flags);
-typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
-                                      int trapnr);
 typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
                                    struct pt_regs *);
 
@@ -83,12 +81,6 @@ struct kprobe {
        /* Called after addr is executed, unless... */
        kprobe_post_handler_t post_handler;
 
-       /*
-        * ... called if executing addr causes a fault (eg. page fault).
-        * Return 1 if it handled fault, otherwise kernel will see it.
-        */
-       kprobe_fault_handler_t fault_handler;
-
        /* Saved opcode (which has been replaced with breakpoint) */
        kprobe_opcode_t opcode;
 
index 2484ed9..d9133d6 100644 (file)
@@ -33,6 +33,8 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                                          unsigned int cpu,
                                          const char *namefmt);
 
+void set_kthread_struct(struct task_struct *p);
+
 void kthread_set_per_cpu(struct task_struct *k, int cpu);
 bool kthread_is_per_cpu(struct task_struct *k);
 
index 8583ed3..ae7735b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/rcuwait.h>
 #include <linux/refcount.h>
 #include <linux/nospec.h>
+#include <linux/notifier.h>
 #include <asm/signal.h>
 
 #include <linux/kvm.h>
@@ -304,7 +305,6 @@ struct kvm_vcpu {
        struct pid __rcu *pid;
        int sigset_active;
        sigset_t sigset;
-       struct kvm_vcpu_stat stat;
        unsigned int halt_poll_ns;
        bool valid_wakeup;
 
@@ -341,6 +341,8 @@ struct kvm_vcpu {
        bool preempted;
        bool ready;
        struct kvm_vcpu_arch arch;
+       struct kvm_vcpu_stat stat;
+       char stats_id[KVM_STATS_NAME_SIZE];
        struct kvm_dirty_ring dirty_ring;
 };
 
@@ -523,6 +525,15 @@ struct kvm {
 #endif /* KVM_HAVE_MMU_RWLOCK */
 
        struct mutex slots_lock;
+
+       /*
+        * Protects the arch-specific fields of struct kvm_memory_slots in
+        * use by the VM. To be used under the slots_lock (above) or in a
+        * kvm->srcu critical section where acquiring the slots_lock would
+        * lead to deadlock with the synchronize_srcu in
+        * install_new_memslots.
+        */
+       struct mutex slots_arch_lock;
        struct mm_struct *mm; /* userspace tied to this vm */
        struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
        struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
@@ -585,6 +596,11 @@ struct kvm {
        pid_t userspace_pid;
        unsigned int max_halt_poll_ns;
        u32 dirty_ring_size;
+
+#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
+       struct notifier_block pm_notifier;
+#endif
+       char stats_id[KVM_STATS_NAME_SIZE];
 };
 
 #define kvm_err(fmt, ...) \
@@ -998,6 +1014,10 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
+int kvm_arch_pm_notifier(struct kvm *kvm, unsigned long state);
+#endif
+
 #ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS
 void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);
 #endif
@@ -1244,26 +1264,104 @@ enum kvm_stat_kind {
 
 struct kvm_stat_data {
        struct kvm *kvm;
-       struct kvm_stats_debugfs_item *dbgfs_item;
-};
-
-struct kvm_stats_debugfs_item {
-       const char *name;
-       int offset;
+       const struct _kvm_stats_desc *desc;
        enum kvm_stat_kind kind;
-       int mode;
 };
 
-#define KVM_DBGFS_GET_MODE(dbgfs_item)                                         \
-       ((dbgfs_item)->mode ? (dbgfs_item)->mode : 0644)
+struct _kvm_stats_desc {
+       struct kvm_stats_desc desc;
+       char name[KVM_STATS_NAME_SIZE];
+};
 
-#define VM_STAT(n, x, ...)                                                     \
-       { n, offsetof(struct kvm, stat.x), KVM_STAT_VM, ## __VA_ARGS__ }
-#define VCPU_STAT(n, x, ...)                                                   \
-       { n, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU, ## __VA_ARGS__ }
+#define STATS_DESC_COMMON(type, unit, base, exp)                              \
+       .flags = type | unit | base |                                          \
+                BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) |              \
+                BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) |              \
+                BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK),               \
+       .exponent = exp,                                                       \
+       .size = 1
+
+#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp)                    \
+       {                                                                      \
+               {                                                              \
+                       STATS_DESC_COMMON(type, unit, base, exp),              \
+                       .offset = offsetof(struct kvm_vm_stat, generic.stat)   \
+               },                                                             \
+               .name = #stat,                                                 \
+       }
+#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp)                  \
+       {                                                                      \
+               {                                                              \
+                       STATS_DESC_COMMON(type, unit, base, exp),              \
+                       .offset = offsetof(struct kvm_vcpu_stat, generic.stat) \
+               },                                                             \
+               .name = #stat,                                                 \
+       }
+#define VM_STATS_DESC(stat, type, unit, base, exp)                            \
+       {                                                                      \
+               {                                                              \
+                       STATS_DESC_COMMON(type, unit, base, exp),              \
+                       .offset = offsetof(struct kvm_vm_stat, stat)           \
+               },                                                             \
+               .name = #stat,                                                 \
+       }
+#define VCPU_STATS_DESC(stat, type, unit, base, exp)                          \
+       {                                                                      \
+               {                                                              \
+                       STATS_DESC_COMMON(type, unit, base, exp),              \
+                       .offset = offsetof(struct kvm_vcpu_stat, stat)         \
+               },                                                             \
+               .name = #stat,                                                 \
+       }
+/* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */
+#define STATS_DESC(SCOPE, stat, type, unit, base, exp)                        \
+       SCOPE##_STATS_DESC(stat, type, unit, base, exp)
+
+#define STATS_DESC_CUMULATIVE(SCOPE, name, unit, base, exponent)              \
+       STATS_DESC(SCOPE, name, KVM_STATS_TYPE_CUMULATIVE, unit, base, exponent)
+#define STATS_DESC_INSTANT(SCOPE, name, unit, base, exponent)                 \
+       STATS_DESC(SCOPE, name, KVM_STATS_TYPE_INSTANT, unit, base, exponent)
+#define STATS_DESC_PEAK(SCOPE, name, unit, base, exponent)                    \
+       STATS_DESC(SCOPE, name, KVM_STATS_TYPE_PEAK, unit, base, exponent)
+
+/* Cumulative counter, read/write */
+#define STATS_DESC_COUNTER(SCOPE, name)                                               \
+       STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_NONE,                \
+               KVM_STATS_BASE_POW10, 0)
+/* Instantaneous counter, read only */
+#define STATS_DESC_ICOUNTER(SCOPE, name)                                      \
+       STATS_DESC_INSTANT(SCOPE, name, KVM_STATS_UNIT_NONE,                   \
+               KVM_STATS_BASE_POW10, 0)
+/* Peak counter, read/write */
+#define STATS_DESC_PCOUNTER(SCOPE, name)                                      \
+       STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_NONE,                      \
+               KVM_STATS_BASE_POW10, 0)
+
+/* Cumulative time in nanosecond */
+#define STATS_DESC_TIME_NSEC(SCOPE, name)                                     \
+       STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS,             \
+               KVM_STATS_BASE_POW10, -9)
+
+#define KVM_GENERIC_VM_STATS()                                                \
+       STATS_DESC_COUNTER(VM_GENERIC, remote_tlb_flush)
+
+#define KVM_GENERIC_VCPU_STATS()                                              \
+       STATS_DESC_COUNTER(VCPU_GENERIC, halt_successful_poll),                \
+       STATS_DESC_COUNTER(VCPU_GENERIC, halt_attempted_poll),                 \
+       STATS_DESC_COUNTER(VCPU_GENERIC, halt_poll_invalid),                   \
+       STATS_DESC_COUNTER(VCPU_GENERIC, halt_wakeup),                         \
+       STATS_DESC_TIME_NSEC(VCPU_GENERIC, halt_poll_success_ns),              \
+       STATS_DESC_TIME_NSEC(VCPU_GENERIC, halt_poll_fail_ns)
 
-extern struct kvm_stats_debugfs_item debugfs_entries[];
 extern struct dentry *kvm_debugfs_dir;
+ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
+                      const struct _kvm_stats_desc *desc,
+                      void *stats, size_t size_stats,
+                      char __user *user_buffer, size_t size, loff_t *offset);
+extern const struct kvm_stats_header kvm_vm_stats_header;
+extern const struct _kvm_stats_desc kvm_vm_stats_desc[];
+extern const struct kvm_stats_header kvm_vcpu_stats_header;
+extern const struct _kvm_stats_desc kvm_vcpu_stats_desc[];
 
 #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
 static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
index a7580f6..ed6a985 100644 (file)
@@ -76,5 +76,19 @@ struct kvm_mmu_memory_cache {
 };
 #endif
 
+struct kvm_vm_stat_generic {
+       u64 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat_generic {
+       u64 halt_successful_poll;
+       u64 halt_attempted_poll;
+       u64 halt_poll_invalid;
+       u64 halt_wakeup;
+       u64 halt_poll_success_ns;
+       u64 halt_poll_fail_ns;
+};
+
+#define KVM_STATS_NAME_SIZE    48
 
 #endif /* __KVM_TYPES_H__ */
index 5f550eb..3fcd242 100644 (file)
@@ -1397,25 +1397,28 @@ extern struct device_attribute *ata_common_sdev_attrs[];
        ATA_SCSI_COMPAT_IOCTL                                   \
        .queuecommand           = ata_scsi_queuecmd,            \
        .dma_need_drain         = ata_scsi_dma_need_drain,      \
-       .can_queue              = ATA_DEF_QUEUE,                \
-       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,             \
        .this_id                = ATA_SHT_THIS_ID,              \
        .emulated               = ATA_SHT_EMULATED,             \
        .proc_name              = drv_name,                     \
-       .slave_configure        = ata_scsi_slave_config,        \
        .slave_destroy          = ata_scsi_slave_destroy,       \
        .bios_param             = ata_std_bios_param,           \
        .unlock_native_capacity = ata_scsi_unlock_native_capacity
 
-#define ATA_BASE_SHT(drv_name)                                 \
+#define ATA_SUBBASE_SHT(drv_name)                              \
        __ATA_BASE_SHT(drv_name),                               \
+       .can_queue              = ATA_DEF_QUEUE,                \
+       .tag_alloc_policy       = BLK_TAG_ALLOC_RR,             \
+       .slave_configure        = ata_scsi_slave_config
+
+#define ATA_BASE_SHT(drv_name)                                 \
+       ATA_SUBBASE_SHT(drv_name),                              \
        .sdev_attrs             = ata_common_sdev_attrs
 
 #ifdef CONFIG_SATA_HOST
 extern struct device_attribute *ata_ncq_sdev_attrs[];
 
 #define ATA_NCQ_SHT(drv_name)                                  \
-       __ATA_BASE_SHT(drv_name),                               \
+       ATA_SUBBASE_SHT(drv_name),                              \
        .sdev_attrs             = ata_ncq_sdev_attrs,           \
        .change_queue_depth     = ata_scsi_change_queue_depth
 #endif
index 2ec9ff5..3e726ac 100644 (file)
@@ -52,7 +52,7 @@ enum lockdep_lock_type {
  * NR_LOCKDEP_CACHING_CLASSES ... Number of classes
  * cached in the instance of lockdep_map
  *
- * Currently main class (subclass == 0) and signle depth subclass
+ * Currently main class (subclass == 0) and single depth subclass
  * are cached in lockdep_map. This optimization is mainly targeting
  * on rq->lock. double_rq_lock() acquires this highly competitive with
  * single depth.
index 66deb1f..2928f03 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_MATH64_H
 
 #include <linux/types.h>
+#include <linux/math.h>
 #include <vdso/math64.h>
 #include <asm/div64.h>
 
@@ -234,6 +235,24 @@ static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift)
 
 #endif
 
+#ifndef mul_s64_u64_shr
+static inline u64 mul_s64_u64_shr(s64 a, u64 b, unsigned int shift)
+{
+       u64 ret;
+
+       /*
+        * Extract the sign before the multiplication and put it back
+        * afterwards if needed.
+        */
+       ret = mul_u64_u64_shr(abs(a), b, shift);
+
+       if (a < 0)
+               ret = -((s64) ret);
+
+       return ret;
+}
+#endif /* mul_s64_u64_shr */
+
 #ifndef mul_u64_u32_div
 static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor)
 {
index 601cbbc..32e3470 100644 (file)
@@ -31,7 +31,7 @@ struct pinctrl_map;
  * @irq_flags:     Mode for primary IRQ (defaults to active low)
  * @gpio_base:     Base GPIO number
  * @gpio_configs:   Array of GPIO configurations (See
- *                 Documentation/driver-api/pinctl.rst)
+ *                 Documentation/driver-api/pin-control.rst)
  * @n_gpio_configs: Number of entries in gpio_configs
  * @gpsw:          General purpose switch mode setting. Depends on the external
  *                 hardware connected to the switch. (See the SW1_MODE field
index c5a11b7..68578e2 100644 (file)
@@ -6,12 +6,9 @@
 #ifndef __MFD_MT6358_CORE_H__
 #define __MFD_MT6358_CORE_H__
 
-#define MT6358_REG_WIDTH 16
-
 struct irq_top_t {
        int hwirq_base;
        unsigned int num_int_regs;
-       unsigned int num_int_bits;
        unsigned int en_reg;
        unsigned int en_reg_shift;
        unsigned int sta_reg;
@@ -25,6 +22,7 @@ struct pmic_irq_data {
        unsigned short top_int_status_reg;
        bool *enable_hwirq;
        bool *cache_hwirq;
+       const struct irq_top_t *pmic_ints;
 };
 
 enum mt6358_irq_top_status_shift {
@@ -146,8 +144,8 @@ enum mt6358_irq_numbers {
 {      \
        .hwirq_base = MT6358_IRQ_##sp##_BASE,   \
        .num_int_regs = \
-               ((MT6358_IRQ_##sp##_BITS - 1) / MT6358_REG_WIDTH) + 1,  \
-       .num_int_bits = MT6358_IRQ_##sp##_BITS, \
+               ((MT6358_IRQ_##sp##_BITS - 1) / \
+               MTK_PMIC_REG_WIDTH) + 1,        \
        .en_reg = MT6358_##sp##_TOP_INT_CON0,   \
        .en_reg_shift = 0x6,    \
        .sta_reg = MT6358_##sp##_TOP_INT_STATUS0,       \
diff --git a/include/linux/mfd/mt6359/core.h b/include/linux/mfd/mt6359/core.h
new file mode 100644 (file)
index 0000000..8d29886
--- /dev/null
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6359_CORE_H__
+#define __MFD_MT6359_CORE_H__
+
+enum mt6359_irq_top_status_shift {
+       MT6359_BUCK_TOP = 0,
+       MT6359_LDO_TOP,
+       MT6359_PSC_TOP,
+       MT6359_SCK_TOP,
+       MT6359_BM_TOP,
+       MT6359_HK_TOP,
+       MT6359_AUD_TOP = 7,
+       MT6359_MISC_TOP,
+};
+
+enum mt6359_irq_numbers {
+       MT6359_IRQ_VCORE_OC = 1,
+       MT6359_IRQ_VGPU11_OC,
+       MT6359_IRQ_VGPU12_OC,
+       MT6359_IRQ_VMODEM_OC,
+       MT6359_IRQ_VPROC1_OC,
+       MT6359_IRQ_VPROC2_OC,
+       MT6359_IRQ_VS1_OC,
+       MT6359_IRQ_VS2_OC,
+       MT6359_IRQ_VPA_OC = 9,
+       MT6359_IRQ_VFE28_OC = 16,
+       MT6359_IRQ_VXO22_OC,
+       MT6359_IRQ_VRF18_OC,
+       MT6359_IRQ_VRF12_OC,
+       MT6359_IRQ_VEFUSE_OC,
+       MT6359_IRQ_VCN33_1_OC,
+       MT6359_IRQ_VCN33_2_OC,
+       MT6359_IRQ_VCN13_OC,
+       MT6359_IRQ_VCN18_OC,
+       MT6359_IRQ_VA09_OC,
+       MT6359_IRQ_VCAMIO_OC,
+       MT6359_IRQ_VA12_OC,
+       MT6359_IRQ_VAUX18_OC,
+       MT6359_IRQ_VAUD18_OC,
+       MT6359_IRQ_VIO18_OC,
+       MT6359_IRQ_VSRAM_PROC1_OC,
+       MT6359_IRQ_VSRAM_PROC2_OC,
+       MT6359_IRQ_VSRAM_OTHERS_OC,
+       MT6359_IRQ_VSRAM_MD_OC,
+       MT6359_IRQ_VEMC_OC,
+       MT6359_IRQ_VSIM1_OC,
+       MT6359_IRQ_VSIM2_OC,
+       MT6359_IRQ_VUSB_OC,
+       MT6359_IRQ_VRFCK_OC,
+       MT6359_IRQ_VBBCK_OC,
+       MT6359_IRQ_VBIF28_OC,
+       MT6359_IRQ_VIBR_OC,
+       MT6359_IRQ_VIO28_OC,
+       MT6359_IRQ_VM18_OC,
+       MT6359_IRQ_VUFS_OC = 45,
+       MT6359_IRQ_PWRKEY = 48,
+       MT6359_IRQ_HOMEKEY,
+       MT6359_IRQ_PWRKEY_R,
+       MT6359_IRQ_HOMEKEY_R,
+       MT6359_IRQ_NI_LBAT_INT,
+       MT6359_IRQ_CHRDET_EDGE = 53,
+       MT6359_IRQ_RTC = 64,
+       MT6359_IRQ_FG_BAT_H = 80,
+       MT6359_IRQ_FG_BAT_L,
+       MT6359_IRQ_FG_CUR_H,
+       MT6359_IRQ_FG_CUR_L,
+       MT6359_IRQ_FG_ZCV = 84,
+       MT6359_IRQ_FG_N_CHARGE_L = 87,
+       MT6359_IRQ_FG_IAVG_H,
+       MT6359_IRQ_FG_IAVG_L = 89,
+       MT6359_IRQ_FG_DISCHARGE = 91,
+       MT6359_IRQ_FG_CHARGE,
+       MT6359_IRQ_BATON_LV = 96,
+       MT6359_IRQ_BATON_BAT_IN = 98,
+       MT6359_IRQ_BATON_BAT_OU,
+       MT6359_IRQ_BIF = 100,
+       MT6359_IRQ_BAT_H = 112,
+       MT6359_IRQ_BAT_L,
+       MT6359_IRQ_BAT2_H,
+       MT6359_IRQ_BAT2_L,
+       MT6359_IRQ_BAT_TEMP_H,
+       MT6359_IRQ_BAT_TEMP_L,
+       MT6359_IRQ_THR_H,
+       MT6359_IRQ_THR_L,
+       MT6359_IRQ_AUXADC_IMP,
+       MT6359_IRQ_NAG_C_DLTV = 121,
+       MT6359_IRQ_AUDIO = 128,
+       MT6359_IRQ_ACCDET = 133,
+       MT6359_IRQ_ACCDET_EINT0,
+       MT6359_IRQ_ACCDET_EINT1,
+       MT6359_IRQ_SPI_CMD_ALERT = 144,
+       MT6359_IRQ_NR,
+};
+
+#define MT6359_IRQ_BUCK_BASE MT6359_IRQ_VCORE_OC
+#define MT6359_IRQ_LDO_BASE MT6359_IRQ_VFE28_OC
+#define MT6359_IRQ_PSC_BASE MT6359_IRQ_PWRKEY
+#define MT6359_IRQ_SCK_BASE MT6359_IRQ_RTC
+#define MT6359_IRQ_BM_BASE MT6359_IRQ_FG_BAT_H
+#define MT6359_IRQ_HK_BASE MT6359_IRQ_BAT_H
+#define MT6359_IRQ_AUD_BASE MT6359_IRQ_AUDIO
+#define MT6359_IRQ_MISC_BASE MT6359_IRQ_SPI_CMD_ALERT
+
+#define MT6359_IRQ_BUCK_BITS (MT6359_IRQ_VPA_OC - MT6359_IRQ_BUCK_BASE + 1)
+#define MT6359_IRQ_LDO_BITS (MT6359_IRQ_VUFS_OC - MT6359_IRQ_LDO_BASE + 1)
+#define MT6359_IRQ_PSC_BITS    \
+       (MT6359_IRQ_CHRDET_EDGE - MT6359_IRQ_PSC_BASE + 1)
+#define MT6359_IRQ_SCK_BITS (MT6359_IRQ_RTC - MT6359_IRQ_SCK_BASE + 1)
+#define MT6359_IRQ_BM_BITS (MT6359_IRQ_BIF - MT6359_IRQ_BM_BASE + 1)
+#define MT6359_IRQ_HK_BITS (MT6359_IRQ_NAG_C_DLTV - MT6359_IRQ_HK_BASE + 1)
+#define MT6359_IRQ_AUD_BITS    \
+       (MT6359_IRQ_ACCDET_EINT1 - MT6359_IRQ_AUD_BASE + 1)
+#define MT6359_IRQ_MISC_BITS   \
+       (MT6359_IRQ_SPI_CMD_ALERT - MT6359_IRQ_MISC_BASE + 1)
+
+#define MT6359_TOP_GEN(sp)     \
+{      \
+       .hwirq_base = MT6359_IRQ_##sp##_BASE,   \
+       .num_int_regs = \
+               ((MT6359_IRQ_##sp##_BITS - 1) / \
+               MTK_PMIC_REG_WIDTH) + 1,        \
+       .en_reg = MT6359_##sp##_TOP_INT_CON0,   \
+       .en_reg_shift = 0x6,    \
+       .sta_reg = MT6359_##sp##_TOP_INT_STATUS0,       \
+       .sta_reg_shift = 0x2,   \
+       .top_offset = MT6359_##sp##_TOP,        \
+}
+
+#endif /* __MFD_MT6359_CORE_H__ */
diff --git a/include/linux/mfd/mt6359/registers.h b/include/linux/mfd/mt6359/registers.h
new file mode 100644 (file)
index 0000000..2135c96
--- /dev/null
@@ -0,0 +1,529 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6359_REGISTERS_H__
+#define __MFD_MT6359_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6359_SWCID                         0xa
+#define MT6359_MISC_TOP_INT_CON0             0x188
+#define MT6359_MISC_TOP_INT_STATUS0          0x194
+#define MT6359_TOP_INT_STATUS0               0x19e
+#define MT6359_SCK_TOP_INT_CON0              0x528
+#define MT6359_SCK_TOP_INT_STATUS0           0x534
+#define MT6359_EOSC_CALI_CON0                0x53a
+#define MT6359_EOSC_CALI_CON1                0x53c
+#define MT6359_RTC_MIX_CON0                  0x53e
+#define MT6359_RTC_MIX_CON1                  0x540
+#define MT6359_RTC_MIX_CON2                  0x542
+#define MT6359_RTC_DSN_ID                    0x580
+#define MT6359_RTC_DSN_REV0                  0x582
+#define MT6359_RTC_DBI                       0x584
+#define MT6359_RTC_DXI                       0x586
+#define MT6359_RTC_BBPU                      0x588
+#define MT6359_RTC_IRQ_STA                   0x58a
+#define MT6359_RTC_IRQ_EN                    0x58c
+#define MT6359_RTC_CII_EN                    0x58e
+#define MT6359_RTC_AL_MASK                   0x590
+#define MT6359_RTC_TC_SEC                    0x592
+#define MT6359_RTC_TC_MIN                    0x594
+#define MT6359_RTC_TC_HOU                    0x596
+#define MT6359_RTC_TC_DOM                    0x598
+#define MT6359_RTC_TC_DOW                    0x59a
+#define MT6359_RTC_TC_MTH                    0x59c
+#define MT6359_RTC_TC_YEA                    0x59e
+#define MT6359_RTC_AL_SEC                    0x5a0
+#define MT6359_RTC_AL_MIN                    0x5a2
+#define MT6359_RTC_AL_HOU                    0x5a4
+#define MT6359_RTC_AL_DOM                    0x5a6
+#define MT6359_RTC_AL_DOW                    0x5a8
+#define MT6359_RTC_AL_MTH                    0x5aa
+#define MT6359_RTC_AL_YEA                    0x5ac
+#define MT6359_RTC_OSC32CON                  0x5ae
+#define MT6359_RTC_POWERKEY1                 0x5b0
+#define MT6359_RTC_POWERKEY2                 0x5b2
+#define MT6359_RTC_PDN1                      0x5b4
+#define MT6359_RTC_PDN2                      0x5b6
+#define MT6359_RTC_SPAR0                     0x5b8
+#define MT6359_RTC_SPAR1                     0x5ba
+#define MT6359_RTC_PROT                      0x5bc
+#define MT6359_RTC_DIFF                      0x5be
+#define MT6359_RTC_CALI                      0x5c0
+#define MT6359_RTC_WRTGR                     0x5c2
+#define MT6359_RTC_CON                       0x5c4
+#define MT6359_RTC_SEC_CTRL                  0x5c6
+#define MT6359_RTC_INT_CNT                   0x5c8
+#define MT6359_RTC_SEC_DAT0                  0x5ca
+#define MT6359_RTC_SEC_DAT1                  0x5cc
+#define MT6359_RTC_SEC_DAT2                  0x5ce
+#define MT6359_RTC_SEC_DSN_ID                0x600
+#define MT6359_RTC_SEC_DSN_REV0              0x602
+#define MT6359_RTC_SEC_DBI                   0x604
+#define MT6359_RTC_SEC_DXI                   0x606
+#define MT6359_RTC_TC_SEC_SEC                0x608
+#define MT6359_RTC_TC_MIN_SEC                0x60a
+#define MT6359_RTC_TC_HOU_SEC                0x60c
+#define MT6359_RTC_TC_DOM_SEC                0x60e
+#define MT6359_RTC_TC_DOW_SEC                0x610
+#define MT6359_RTC_TC_MTH_SEC                0x612
+#define MT6359_RTC_TC_YEA_SEC                0x614
+#define MT6359_RTC_SEC_CK_PDN                0x616
+#define MT6359_RTC_SEC_WRTGR                 0x618
+#define MT6359_PSC_TOP_INT_CON0              0x910
+#define MT6359_PSC_TOP_INT_STATUS0           0x91c
+#define MT6359_BM_TOP_INT_CON0               0xc32
+#define MT6359_BM_TOP_INT_CON1               0xc38
+#define MT6359_BM_TOP_INT_STATUS0            0xc4a
+#define MT6359_BM_TOP_INT_STATUS1            0xc4c
+#define MT6359_HK_TOP_INT_CON0               0xf92
+#define MT6359_HK_TOP_INT_STATUS0            0xf9e
+#define MT6359_BUCK_TOP_INT_CON0             0x1418
+#define MT6359_BUCK_TOP_INT_STATUS0          0x1424
+#define MT6359_BUCK_VPU_CON0                 0x1488
+#define MT6359_BUCK_VPU_DBG0                 0x14a6
+#define MT6359_BUCK_VPU_DBG1                 0x14a8
+#define MT6359_BUCK_VPU_ELR0                 0x14ac
+#define MT6359_BUCK_VCORE_CON0               0x1508
+#define MT6359_BUCK_VCORE_DBG0               0x1526
+#define MT6359_BUCK_VCORE_DBG1               0x1528
+#define MT6359_BUCK_VCORE_SSHUB_CON0         0x152a
+#define MT6359_BUCK_VCORE_ELR0               0x1534
+#define MT6359_BUCK_VGPU11_CON0              0x1588
+#define MT6359_BUCK_VGPU11_DBG0              0x15a6
+#define MT6359_BUCK_VGPU11_DBG1              0x15a8
+#define MT6359_BUCK_VGPU11_ELR0              0x15ac
+#define MT6359_BUCK_VMODEM_CON0              0x1688
+#define MT6359_BUCK_VMODEM_DBG0              0x16a6
+#define MT6359_BUCK_VMODEM_DBG1              0x16a8
+#define MT6359_BUCK_VMODEM_ELR0              0x16ae
+#define MT6359_BUCK_VPROC1_CON0              0x1708
+#define MT6359_BUCK_VPROC1_DBG0              0x1726
+#define MT6359_BUCK_VPROC1_DBG1              0x1728
+#define MT6359_BUCK_VPROC1_ELR0              0x172e
+#define MT6359_BUCK_VPROC2_CON0              0x1788
+#define MT6359_BUCK_VPROC2_DBG0              0x17a6
+#define MT6359_BUCK_VPROC2_DBG1              0x17a8
+#define MT6359_BUCK_VPROC2_ELR0              0x17b2
+#define MT6359_BUCK_VS1_CON0                 0x1808
+#define MT6359_BUCK_VS1_DBG0                 0x1826
+#define MT6359_BUCK_VS1_DBG1                 0x1828
+#define MT6359_BUCK_VS1_ELR0                 0x1834
+#define MT6359_BUCK_VS2_CON0                 0x1888
+#define MT6359_BUCK_VS2_DBG0                 0x18a6
+#define MT6359_BUCK_VS2_DBG1                 0x18a8
+#define MT6359_BUCK_VS2_ELR0                 0x18b4
+#define MT6359_BUCK_VPA_CON0                 0x1908
+#define MT6359_BUCK_VPA_CON1                 0x190e
+#define MT6359_BUCK_VPA_CFG0                 0x1910
+#define MT6359_BUCK_VPA_CFG1                 0x1912
+#define MT6359_BUCK_VPA_DBG0                 0x1914
+#define MT6359_BUCK_VPA_DBG1                 0x1916
+#define MT6359_VGPUVCORE_ANA_CON2            0x198e
+#define MT6359_VGPUVCORE_ANA_CON13           0x19a4
+#define MT6359_VPROC1_ANA_CON3               0x19b2
+#define MT6359_VPROC2_ANA_CON3               0x1a0e
+#define MT6359_VMODEM_ANA_CON3               0x1a1a
+#define MT6359_VPU_ANA_CON3                  0x1a26
+#define MT6359_VS1_ANA_CON0                  0x1a2c
+#define MT6359_VS2_ANA_CON0                  0x1a34
+#define MT6359_VPA_ANA_CON0                  0x1a3c
+#define MT6359_LDO_TOP_INT_CON0              0x1b14
+#define MT6359_LDO_TOP_INT_CON1              0x1b1a
+#define MT6359_LDO_TOP_INT_STATUS0           0x1b28
+#define MT6359_LDO_TOP_INT_STATUS1           0x1b2a
+#define MT6359_LDO_VSRAM_PROC1_ELR           0x1b40
+#define MT6359_LDO_VSRAM_PROC2_ELR           0x1b42
+#define MT6359_LDO_VSRAM_OTHERS_ELR          0x1b44
+#define MT6359_LDO_VSRAM_MD_ELR              0x1b46
+#define MT6359_LDO_VFE28_CON0                0x1b88
+#define MT6359_LDO_VFE28_MON                 0x1b8a
+#define MT6359_LDO_VXO22_CON0                0x1b98
+#define MT6359_LDO_VXO22_MON                 0x1b9a
+#define MT6359_LDO_VRF18_CON0                0x1ba8
+#define MT6359_LDO_VRF18_MON                 0x1baa
+#define MT6359_LDO_VRF12_CON0                0x1bb8
+#define MT6359_LDO_VRF12_MON                 0x1bba
+#define MT6359_LDO_VEFUSE_CON0               0x1bc8
+#define MT6359_LDO_VEFUSE_MON                0x1bca
+#define MT6359_LDO_VCN33_1_CON0              0x1bd8
+#define MT6359_LDO_VCN33_1_MON               0x1bda
+#define MT6359_LDO_VCN33_1_MULTI_SW          0x1be8
+#define MT6359_LDO_VCN33_2_CON0              0x1c08
+#define MT6359_LDO_VCN33_2_MON               0x1c0a
+#define MT6359_LDO_VCN33_2_MULTI_SW          0x1c18
+#define MT6359_LDO_VCN13_CON0                0x1c1a
+#define MT6359_LDO_VCN13_MON                 0x1c1c
+#define MT6359_LDO_VCN18_CON0                0x1c2a
+#define MT6359_LDO_VCN18_MON                 0x1c2c
+#define MT6359_LDO_VA09_CON0                 0x1c3a
+#define MT6359_LDO_VA09_MON                  0x1c3c
+#define MT6359_LDO_VCAMIO_CON0               0x1c4a
+#define MT6359_LDO_VCAMIO_MON                0x1c4c
+#define MT6359_LDO_VA12_CON0                 0x1c5a
+#define MT6359_LDO_VA12_MON                  0x1c5c
+#define MT6359_LDO_VAUX18_CON0               0x1c88
+#define MT6359_LDO_VAUX18_MON                0x1c8a
+#define MT6359_LDO_VAUD18_CON0               0x1c98
+#define MT6359_LDO_VAUD18_MON                0x1c9a
+#define MT6359_LDO_VIO18_CON0                0x1ca8
+#define MT6359_LDO_VIO18_MON                 0x1caa
+#define MT6359_LDO_VEMC_CON0                 0x1cb8
+#define MT6359_LDO_VEMC_MON                  0x1cba
+#define MT6359_LDO_VSIM1_CON0                0x1cc8
+#define MT6359_LDO_VSIM1_MON                 0x1cca
+#define MT6359_LDO_VSIM2_CON0                0x1cd8
+#define MT6359_LDO_VSIM2_MON                 0x1cda
+#define MT6359_LDO_VUSB_CON0                 0x1d08
+#define MT6359_LDO_VUSB_MON                  0x1d0a
+#define MT6359_LDO_VUSB_MULTI_SW             0x1d18
+#define MT6359_LDO_VRFCK_CON0                0x1d1a
+#define MT6359_LDO_VRFCK_MON                 0x1d1c
+#define MT6359_LDO_VBBCK_CON0                0x1d2a
+#define MT6359_LDO_VBBCK_MON                 0x1d2c
+#define MT6359_LDO_VBIF28_CON0               0x1d3a
+#define MT6359_LDO_VBIF28_MON                0x1d3c
+#define MT6359_LDO_VIBR_CON0                 0x1d4a
+#define MT6359_LDO_VIBR_MON                  0x1d4c
+#define MT6359_LDO_VIO28_CON0                0x1d5a
+#define MT6359_LDO_VIO28_MON                 0x1d5c
+#define MT6359_LDO_VM18_CON0                 0x1d88
+#define MT6359_LDO_VM18_MON                  0x1d8a
+#define MT6359_LDO_VUFS_CON0                 0x1d98
+#define MT6359_LDO_VUFS_MON                  0x1d9a
+#define MT6359_LDO_VSRAM_PROC1_CON0          0x1e88
+#define MT6359_LDO_VSRAM_PROC1_MON           0x1e8a
+#define MT6359_LDO_VSRAM_PROC1_VOSEL1        0x1e8e
+#define MT6359_LDO_VSRAM_PROC2_CON0          0x1ea6
+#define MT6359_LDO_VSRAM_PROC2_MON           0x1ea8
+#define MT6359_LDO_VSRAM_PROC2_VOSEL1        0x1eac
+#define MT6359_LDO_VSRAM_OTHERS_CON0         0x1f08
+#define MT6359_LDO_VSRAM_OTHERS_MON          0x1f0a
+#define MT6359_LDO_VSRAM_OTHERS_VOSEL1       0x1f0e
+#define MT6359_LDO_VSRAM_OTHERS_SSHUB        0x1f26
+#define MT6359_LDO_VSRAM_MD_CON0             0x1f2c
+#define MT6359_LDO_VSRAM_MD_MON              0x1f2e
+#define MT6359_LDO_VSRAM_MD_VOSEL1           0x1f32
+#define MT6359_VFE28_ANA_CON0                0x1f88
+#define MT6359_VAUX18_ANA_CON0               0x1f8c
+#define MT6359_VUSB_ANA_CON0                 0x1f90
+#define MT6359_VBIF28_ANA_CON0               0x1f94
+#define MT6359_VCN33_1_ANA_CON0              0x1f98
+#define MT6359_VCN33_2_ANA_CON0              0x1f9c
+#define MT6359_VEMC_ANA_CON0                 0x1fa0
+#define MT6359_VSIM1_ANA_CON0                0x1fa4
+#define MT6359_VSIM2_ANA_CON0                0x1fa8
+#define MT6359_VIO28_ANA_CON0                0x1fac
+#define MT6359_VIBR_ANA_CON0                 0x1fb0
+#define MT6359_VRF18_ANA_CON0                0x2008
+#define MT6359_VEFUSE_ANA_CON0               0x200c
+#define MT6359_VCN18_ANA_CON0                0x2010
+#define MT6359_VCAMIO_ANA_CON0               0x2014
+#define MT6359_VAUD18_ANA_CON0               0x2018
+#define MT6359_VIO18_ANA_CON0                0x201c
+#define MT6359_VM18_ANA_CON0                 0x2020
+#define MT6359_VUFS_ANA_CON0                 0x2024
+#define MT6359_VRF12_ANA_CON0                0x202a
+#define MT6359_VCN13_ANA_CON0                0x202e
+#define MT6359_VA09_ANA_CON0                 0x2032
+#define MT6359_VA12_ANA_CON0                 0x2036
+#define MT6359_VXO22_ANA_CON0                0x2088
+#define MT6359_VRFCK_ANA_CON0                0x208c
+#define MT6359_VBBCK_ANA_CON0                0x2094
+#define MT6359_AUD_TOP_INT_CON0              0x2328
+#define MT6359_AUD_TOP_INT_STATUS0           0x2334
+
+#define MT6359_RG_BUCK_VPU_EN_ADDR             MT6359_BUCK_VPU_CON0
+#define MT6359_RG_BUCK_VPU_LP_ADDR             MT6359_BUCK_VPU_CON0
+#define MT6359_RG_BUCK_VPU_LP_SHIFT            1
+#define MT6359_DA_VPU_VOSEL_ADDR               MT6359_BUCK_VPU_DBG0
+#define MT6359_DA_VPU_VOSEL_MASK               0x7F
+#define MT6359_DA_VPU_VOSEL_SHIFT              0
+#define MT6359_DA_VPU_EN_ADDR                  MT6359_BUCK_VPU_DBG1
+#define MT6359_RG_BUCK_VPU_VOSEL_ADDR          MT6359_BUCK_VPU_ELR0
+#define MT6359_RG_BUCK_VPU_VOSEL_MASK          0x7F
+#define MT6359_RG_BUCK_VPU_VOSEL_SHIFT         0
+#define MT6359_RG_BUCK_VCORE_EN_ADDR           MT6359_BUCK_VCORE_CON0
+#define MT6359_RG_BUCK_VCORE_LP_ADDR           MT6359_BUCK_VCORE_CON0
+#define MT6359_RG_BUCK_VCORE_LP_SHIFT          1
+#define MT6359_DA_VCORE_VOSEL_ADDR             MT6359_BUCK_VCORE_DBG0
+#define MT6359_DA_VCORE_VOSEL_MASK             0x7F
+#define MT6359_DA_VCORE_VOSEL_SHIFT            0
+#define MT6359_DA_VCORE_EN_ADDR                MT6359_BUCK_VCORE_DBG1
+#define MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR     MT6359_BUCK_VCORE_SSHUB_CON0
+#define MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR  MT6359_BUCK_VCORE_SSHUB_CON0
+#define MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_MASK  0x7F
+#define MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT 4
+#define MT6359_RG_BUCK_VCORE_VOSEL_ADDR        MT6359_BUCK_VCORE_ELR0
+#define MT6359_RG_BUCK_VCORE_VOSEL_MASK        0x7F
+#define MT6359_RG_BUCK_VCORE_VOSEL_SHIFT       0
+#define MT6359_RG_BUCK_VGPU11_EN_ADDR          MT6359_BUCK_VGPU11_CON0
+#define MT6359_RG_BUCK_VGPU11_LP_ADDR          MT6359_BUCK_VGPU11_CON0
+#define MT6359_RG_BUCK_VGPU11_LP_SHIFT         1
+#define MT6359_DA_VGPU11_VOSEL_ADDR            MT6359_BUCK_VGPU11_DBG0
+#define MT6359_DA_VGPU11_VOSEL_MASK            0x7F
+#define MT6359_DA_VGPU11_VOSEL_SHIFT           0
+#define MT6359_DA_VGPU11_EN_ADDR               MT6359_BUCK_VGPU11_DBG1
+#define MT6359_RG_BUCK_VGPU11_VOSEL_ADDR       MT6359_BUCK_VGPU11_ELR0
+#define MT6359_RG_BUCK_VGPU11_VOSEL_MASK       0x7F
+#define MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT      0
+#define MT6359_RG_BUCK_VMODEM_EN_ADDR          MT6359_BUCK_VMODEM_CON0
+#define MT6359_RG_BUCK_VMODEM_LP_ADDR          MT6359_BUCK_VMODEM_CON0
+#define MT6359_RG_BUCK_VMODEM_LP_SHIFT         1
+#define MT6359_DA_VMODEM_VOSEL_ADDR            MT6359_BUCK_VMODEM_DBG0
+#define MT6359_DA_VMODEM_VOSEL_MASK            0x7F
+#define MT6359_DA_VMODEM_VOSEL_SHIFT           0
+#define MT6359_DA_VMODEM_EN_ADDR               MT6359_BUCK_VMODEM_DBG1
+#define MT6359_RG_BUCK_VMODEM_VOSEL_ADDR       MT6359_BUCK_VMODEM_ELR0
+#define MT6359_RG_BUCK_VMODEM_VOSEL_MASK       0x7F
+#define MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT      0
+#define MT6359_RG_BUCK_VPROC1_EN_ADDR          MT6359_BUCK_VPROC1_CON0
+#define MT6359_RG_BUCK_VPROC1_LP_ADDR          MT6359_BUCK_VPROC1_CON0
+#define MT6359_RG_BUCK_VPROC1_LP_SHIFT         1
+#define MT6359_DA_VPROC1_VOSEL_ADDR            MT6359_BUCK_VPROC1_DBG0
+#define MT6359_DA_VPROC1_VOSEL_MASK            0x7F
+#define MT6359_DA_VPROC1_VOSEL_SHIFT           0
+#define MT6359_DA_VPROC1_EN_ADDR               MT6359_BUCK_VPROC1_DBG1
+#define MT6359_RG_BUCK_VPROC1_VOSEL_ADDR       MT6359_BUCK_VPROC1_ELR0
+#define MT6359_RG_BUCK_VPROC1_VOSEL_MASK       0x7F
+#define MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT      0
+#define MT6359_RG_BUCK_VPROC2_EN_ADDR          MT6359_BUCK_VPROC2_CON0
+#define MT6359_RG_BUCK_VPROC2_LP_ADDR          MT6359_BUCK_VPROC2_CON0
+#define MT6359_RG_BUCK_VPROC2_LP_SHIFT         1
+#define MT6359_DA_VPROC2_VOSEL_ADDR            MT6359_BUCK_VPROC2_DBG0
+#define MT6359_DA_VPROC2_VOSEL_MASK            0x7F
+#define MT6359_DA_VPROC2_VOSEL_SHIFT           0
+#define MT6359_DA_VPROC2_EN_ADDR               MT6359_BUCK_VPROC2_DBG1
+#define MT6359_RG_BUCK_VPROC2_VOSEL_ADDR       MT6359_BUCK_VPROC2_ELR0
+#define MT6359_RG_BUCK_VPROC2_VOSEL_MASK       0x7F
+#define MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT      0
+#define MT6359_RG_BUCK_VS1_EN_ADDR             MT6359_BUCK_VS1_CON0
+#define MT6359_RG_BUCK_VS1_LP_ADDR             MT6359_BUCK_VS1_CON0
+#define MT6359_RG_BUCK_VS1_LP_SHIFT            1
+#define MT6359_DA_VS1_VOSEL_ADDR               MT6359_BUCK_VS1_DBG0
+#define MT6359_DA_VS1_VOSEL_MASK               0x7F
+#define MT6359_DA_VS1_VOSEL_SHIFT              0
+#define MT6359_DA_VS1_EN_ADDR                  MT6359_BUCK_VS1_DBG1
+#define MT6359_RG_BUCK_VS1_VOSEL_ADDR          MT6359_BUCK_VS1_ELR0
+#define MT6359_RG_BUCK_VS1_VOSEL_MASK          0x7F
+#define MT6359_RG_BUCK_VS1_VOSEL_SHIFT         0
+#define MT6359_RG_BUCK_VS2_EN_ADDR             MT6359_BUCK_VS2_CON0
+#define MT6359_RG_BUCK_VS2_LP_ADDR             MT6359_BUCK_VS2_CON0
+#define MT6359_RG_BUCK_VS2_LP_SHIFT            1
+#define MT6359_DA_VS2_VOSEL_ADDR               MT6359_BUCK_VS2_DBG0
+#define MT6359_DA_VS2_VOSEL_MASK               0x7F
+#define MT6359_DA_VS2_VOSEL_SHIFT              0
+#define MT6359_DA_VS2_EN_ADDR                  MT6359_BUCK_VS2_DBG1
+#define MT6359_RG_BUCK_VS2_VOSEL_ADDR          MT6359_BUCK_VS2_ELR0
+#define MT6359_RG_BUCK_VS2_VOSEL_MASK          0x7F
+#define MT6359_RG_BUCK_VS2_VOSEL_SHIFT         0
+#define MT6359_RG_BUCK_VPA_EN_ADDR             MT6359_BUCK_VPA_CON0
+#define MT6359_RG_BUCK_VPA_LP_ADDR             MT6359_BUCK_VPA_CON0
+#define MT6359_RG_BUCK_VPA_LP_SHIFT            1
+#define MT6359_RG_BUCK_VPA_VOSEL_ADDR          MT6359_BUCK_VPA_CON1
+#define MT6359_RG_BUCK_VPA_VOSEL_MASK          0x3F
+#define MT6359_RG_BUCK_VPA_VOSEL_SHIFT         0
+#define MT6359_DA_VPA_VOSEL_ADDR               MT6359_BUCK_VPA_DBG0
+#define MT6359_DA_VPA_VOSEL_MASK               0x3F
+#define MT6359_DA_VPA_VOSEL_SHIFT              0
+#define MT6359_DA_VPA_EN_ADDR                  MT6359_BUCK_VPA_DBG1
+#define MT6359_RG_VGPU11_FCCM_ADDR             MT6359_VGPUVCORE_ANA_CON2
+#define MT6359_RG_VGPU11_FCCM_SHIFT            9
+#define MT6359_RG_VCORE_FCCM_ADDR              MT6359_VGPUVCORE_ANA_CON13
+#define MT6359_RG_VCORE_FCCM_SHIFT             5
+#define MT6359_RG_VPROC1_FCCM_ADDR             MT6359_VPROC1_ANA_CON3
+#define MT6359_RG_VPROC1_FCCM_SHIFT            1
+#define MT6359_RG_VPROC2_FCCM_ADDR             MT6359_VPROC2_ANA_CON3
+#define MT6359_RG_VPROC2_FCCM_SHIFT            1
+#define MT6359_RG_VMODEM_FCCM_ADDR             MT6359_VMODEM_ANA_CON3
+#define MT6359_RG_VMODEM_FCCM_SHIFT            1
+#define MT6359_RG_VPU_FCCM_ADDR                MT6359_VPU_ANA_CON3
+#define MT6359_RG_VPU_FCCM_SHIFT               1
+#define MT6359_RG_VS1_FPWM_ADDR                MT6359_VS1_ANA_CON0
+#define MT6359_RG_VS1_FPWM_SHIFT               3
+#define MT6359_RG_VS2_FPWM_ADDR                MT6359_VS2_ANA_CON0
+#define MT6359_RG_VS2_FPWM_SHIFT               3
+#define MT6359_RG_VPA_MODESET_ADDR             MT6359_VPA_ANA_CON0
+#define MT6359_RG_VPA_MODESET_SHIFT            1
+#define MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR   MT6359_LDO_VSRAM_PROC1_ELR
+#define MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK   0x7F
+#define MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT  0
+#define MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR   MT6359_LDO_VSRAM_PROC2_ELR
+#define MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK   0x7F
+#define MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT  0
+#define MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR  MT6359_LDO_VSRAM_OTHERS_ELR
+#define MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK  0x7F
+#define MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT 0
+#define MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR      MT6359_LDO_VSRAM_MD_ELR
+#define MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK      0x7F
+#define MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT     0
+#define MT6359_RG_LDO_VFE28_EN_ADDR            MT6359_LDO_VFE28_CON0
+#define MT6359_DA_VFE28_B_EN_ADDR              MT6359_LDO_VFE28_MON
+#define MT6359_RG_LDO_VXO22_EN_ADDR            MT6359_LDO_VXO22_CON0
+#define MT6359_RG_LDO_VXO22_EN_SHIFT           0
+#define MT6359_DA_VXO22_B_EN_ADDR              MT6359_LDO_VXO22_MON
+#define MT6359_RG_LDO_VRF18_EN_ADDR            MT6359_LDO_VRF18_CON0
+#define MT6359_RG_LDO_VRF18_EN_SHIFT           0
+#define MT6359_DA_VRF18_B_EN_ADDR              MT6359_LDO_VRF18_MON
+#define MT6359_RG_LDO_VRF12_EN_ADDR            MT6359_LDO_VRF12_CON0
+#define MT6359_RG_LDO_VRF12_EN_SHIFT           0
+#define MT6359_DA_VRF12_B_EN_ADDR              MT6359_LDO_VRF12_MON
+#define MT6359_RG_LDO_VEFUSE_EN_ADDR           MT6359_LDO_VEFUSE_CON0
+#define MT6359_RG_LDO_VEFUSE_EN_SHIFT          0
+#define MT6359_DA_VEFUSE_B_EN_ADDR             MT6359_LDO_VEFUSE_MON
+#define MT6359_RG_LDO_VCN33_1_EN_0_ADDR        MT6359_LDO_VCN33_1_CON0
+#define MT6359_RG_LDO_VCN33_1_EN_0_MASK        0x1
+#define MT6359_RG_LDO_VCN33_1_EN_0_SHIFT       0
+#define MT6359_DA_VCN33_1_B_EN_ADDR            MT6359_LDO_VCN33_1_MON
+#define MT6359_RG_LDO_VCN33_1_EN_1_ADDR        MT6359_LDO_VCN33_1_MULTI_SW
+#define MT6359_RG_LDO_VCN33_1_EN_1_SHIFT       15
+#define MT6359_RG_LDO_VCN33_2_EN_0_ADDR        MT6359_LDO_VCN33_2_CON0
+#define MT6359_RG_LDO_VCN33_2_EN_0_SHIFT       0
+#define MT6359_DA_VCN33_2_B_EN_ADDR            MT6359_LDO_VCN33_2_MON
+#define MT6359_RG_LDO_VCN33_2_EN_1_ADDR        MT6359_LDO_VCN33_2_MULTI_SW
+#define MT6359_RG_LDO_VCN33_2_EN_1_MASK        0x1
+#define MT6359_RG_LDO_VCN33_2_EN_1_SHIFT       15
+#define MT6359_RG_LDO_VCN13_EN_ADDR            MT6359_LDO_VCN13_CON0
+#define MT6359_RG_LDO_VCN13_EN_SHIFT           0
+#define MT6359_DA_VCN13_B_EN_ADDR              MT6359_LDO_VCN13_MON
+#define MT6359_RG_LDO_VCN18_EN_ADDR            MT6359_LDO_VCN18_CON0
+#define MT6359_DA_VCN18_B_EN_ADDR              MT6359_LDO_VCN18_MON
+#define MT6359_RG_LDO_VA09_EN_ADDR             MT6359_LDO_VA09_CON0
+#define MT6359_RG_LDO_VA09_EN_SHIFT            0
+#define MT6359_DA_VA09_B_EN_ADDR               MT6359_LDO_VA09_MON
+#define MT6359_RG_LDO_VCAMIO_EN_ADDR           MT6359_LDO_VCAMIO_CON0
+#define MT6359_RG_LDO_VCAMIO_EN_SHIFT          0
+#define MT6359_DA_VCAMIO_B_EN_ADDR             MT6359_LDO_VCAMIO_MON
+#define MT6359_RG_LDO_VA12_EN_ADDR             MT6359_LDO_VA12_CON0
+#define MT6359_RG_LDO_VA12_EN_SHIFT            0
+#define MT6359_DA_VA12_B_EN_ADDR               MT6359_LDO_VA12_MON
+#define MT6359_RG_LDO_VAUX18_EN_ADDR           MT6359_LDO_VAUX18_CON0
+#define MT6359_DA_VAUX18_B_EN_ADDR             MT6359_LDO_VAUX18_MON
+#define MT6359_RG_LDO_VAUD18_EN_ADDR           MT6359_LDO_VAUD18_CON0
+#define MT6359_DA_VAUD18_B_EN_ADDR             MT6359_LDO_VAUD18_MON
+#define MT6359_RG_LDO_VIO18_EN_ADDR            MT6359_LDO_VIO18_CON0
+#define MT6359_RG_LDO_VIO18_EN_SHIFT           0
+#define MT6359_DA_VIO18_B_EN_ADDR              MT6359_LDO_VIO18_MON
+#define MT6359_RG_LDO_VEMC_EN_ADDR             MT6359_LDO_VEMC_CON0
+#define MT6359_RG_LDO_VEMC_EN_SHIFT            0
+#define MT6359_DA_VEMC_B_EN_ADDR               MT6359_LDO_VEMC_MON
+#define MT6359_RG_LDO_VSIM1_EN_ADDR            MT6359_LDO_VSIM1_CON0
+#define MT6359_RG_LDO_VSIM1_EN_SHIFT           0
+#define MT6359_DA_VSIM1_B_EN_ADDR              MT6359_LDO_VSIM1_MON
+#define MT6359_RG_LDO_VSIM2_EN_ADDR            MT6359_LDO_VSIM2_CON0
+#define MT6359_RG_LDO_VSIM2_EN_SHIFT           0
+#define MT6359_DA_VSIM2_B_EN_ADDR              MT6359_LDO_VSIM2_MON
+#define MT6359_RG_LDO_VUSB_EN_0_ADDR           MT6359_LDO_VUSB_CON0
+#define MT6359_RG_LDO_VUSB_EN_0_MASK           0x1
+#define MT6359_RG_LDO_VUSB_EN_0_SHIFT          0
+#define MT6359_DA_VUSB_B_EN_ADDR               MT6359_LDO_VUSB_MON
+#define MT6359_RG_LDO_VUSB_EN_1_ADDR           MT6359_LDO_VUSB_MULTI_SW
+#define MT6359_RG_LDO_VUSB_EN_1_MASK           0x1
+#define MT6359_RG_LDO_VUSB_EN_1_SHIFT          15
+#define MT6359_RG_LDO_VRFCK_EN_ADDR            MT6359_LDO_VRFCK_CON0
+#define MT6359_RG_LDO_VRFCK_EN_SHIFT           0
+#define MT6359_DA_VRFCK_B_EN_ADDR              MT6359_LDO_VRFCK_MON
+#define MT6359_RG_LDO_VBBCK_EN_ADDR            MT6359_LDO_VBBCK_CON0
+#define MT6359_RG_LDO_VBBCK_EN_SHIFT           0
+#define MT6359_DA_VBBCK_B_EN_ADDR              MT6359_LDO_VBBCK_MON
+#define MT6359_RG_LDO_VBIF28_EN_ADDR           MT6359_LDO_VBIF28_CON0
+#define MT6359_DA_VBIF28_B_EN_ADDR             MT6359_LDO_VBIF28_MON
+#define MT6359_RG_LDO_VIBR_EN_ADDR             MT6359_LDO_VIBR_CON0
+#define MT6359_RG_LDO_VIBR_EN_SHIFT            0
+#define MT6359_DA_VIBR_B_EN_ADDR               MT6359_LDO_VIBR_MON
+#define MT6359_RG_LDO_VIO28_EN_ADDR            MT6359_LDO_VIO28_CON0
+#define MT6359_RG_LDO_VIO28_EN_SHIFT           0
+#define MT6359_DA_VIO28_B_EN_ADDR              MT6359_LDO_VIO28_MON
+#define MT6359_RG_LDO_VM18_EN_ADDR             MT6359_LDO_VM18_CON0
+#define MT6359_RG_LDO_VM18_EN_SHIFT            0
+#define MT6359_DA_VM18_B_EN_ADDR               MT6359_LDO_VM18_MON
+#define MT6359_RG_LDO_VUFS_EN_ADDR             MT6359_LDO_VUFS_CON0
+#define MT6359_RG_LDO_VUFS_EN_SHIFT               0
+#define MT6359_DA_VUFS_B_EN_ADDR               MT6359_LDO_VUFS_MON
+#define MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR      MT6359_LDO_VSRAM_PROC1_CON0
+#define MT6359_DA_VSRAM_PROC1_B_EN_ADDR        MT6359_LDO_VSRAM_PROC1_MON
+#define MT6359_DA_VSRAM_PROC1_VOSEL_ADDR       MT6359_LDO_VSRAM_PROC1_VOSEL1
+#define MT6359_DA_VSRAM_PROC1_VOSEL_MASK       0x7F
+#define MT6359_DA_VSRAM_PROC1_VOSEL_SHIFT      8
+#define MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR      MT6359_LDO_VSRAM_PROC2_CON0
+#define MT6359_DA_VSRAM_PROC2_B_EN_ADDR        MT6359_LDO_VSRAM_PROC2_MON
+#define MT6359_DA_VSRAM_PROC2_VOSEL_ADDR       MT6359_LDO_VSRAM_PROC2_VOSEL1
+#define MT6359_DA_VSRAM_PROC2_VOSEL_MASK       0x7F
+#define MT6359_DA_VSRAM_PROC2_VOSEL_SHIFT      8
+#define MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR     MT6359_LDO_VSRAM_OTHERS_CON0
+#define MT6359_DA_VSRAM_OTHERS_B_EN_ADDR       MT6359_LDO_VSRAM_OTHERS_MON
+#define MT6359_DA_VSRAM_OTHERS_VOSEL_ADDR      MT6359_LDO_VSRAM_OTHERS_VOSEL1
+#define MT6359_DA_VSRAM_OTHERS_VOSEL_MASK      0x7F
+#define MT6359_DA_VSRAM_OTHERS_VOSEL_SHIFT     8
+#define MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR     MT6359_LDO_VSRAM_OTHERS_SSHUB
+#define MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR  MT6359_LDO_VSRAM_OTHERS_SSHUB
+#define MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK  0x7F
+#define MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT 1
+#define MT6359_RG_LDO_VSRAM_MD_EN_ADDR         MT6359_LDO_VSRAM_MD_CON0
+#define MT6359_DA_VSRAM_MD_B_EN_ADDR           MT6359_LDO_VSRAM_MD_MON
+#define MT6359_DA_VSRAM_MD_VOSEL_ADDR          MT6359_LDO_VSRAM_MD_VOSEL1
+#define MT6359_DA_VSRAM_MD_VOSEL_MASK          0x7F
+#define MT6359_DA_VSRAM_MD_VOSEL_SHIFT         8
+#define MT6359_RG_VCN33_1_VOSEL_ADDR           MT6359_VCN33_1_ANA_CON0
+#define MT6359_RG_VCN33_1_VOSEL_MASK           0xF
+#define MT6359_RG_VCN33_1_VOSEL_SHIFT          8
+#define MT6359_RG_VCN33_2_VOSEL_ADDR           MT6359_VCN33_2_ANA_CON0
+#define MT6359_RG_VCN33_2_VOSEL_MASK           0xF
+#define MT6359_RG_VCN33_2_VOSEL_SHIFT          8
+#define MT6359_RG_VEMC_VOSEL_ADDR              MT6359_VEMC_ANA_CON0
+#define MT6359_RG_VEMC_VOSEL_MASK              0xF
+#define MT6359_RG_VEMC_VOSEL_SHIFT             8
+#define MT6359_RG_VSIM1_VOSEL_ADDR             MT6359_VSIM1_ANA_CON0
+#define MT6359_RG_VSIM1_VOSEL_MASK             0xF
+#define MT6359_RG_VSIM1_VOSEL_SHIFT            8
+#define MT6359_RG_VSIM2_VOSEL_ADDR             MT6359_VSIM2_ANA_CON0
+#define MT6359_RG_VSIM2_VOSEL_MASK             0xF
+#define MT6359_RG_VSIM2_VOSEL_SHIFT            8
+#define MT6359_RG_VIO28_VOSEL_ADDR             MT6359_VIO28_ANA_CON0
+#define MT6359_RG_VIO28_VOSEL_MASK             0xF
+#define MT6359_RG_VIO28_VOSEL_SHIFT            8
+#define MT6359_RG_VIBR_VOSEL_ADDR              MT6359_VIBR_ANA_CON0
+#define MT6359_RG_VIBR_VOSEL_MASK              0xF
+#define MT6359_RG_VIBR_VOSEL_SHIFT             8
+#define MT6359_RG_VRF18_VOSEL_ADDR             MT6359_VRF18_ANA_CON0
+#define MT6359_RG_VRF18_VOSEL_MASK             0xF
+#define MT6359_RG_VRF18_VOSEL_SHIFT            8
+#define MT6359_RG_VEFUSE_VOSEL_ADDR            MT6359_VEFUSE_ANA_CON0
+#define MT6359_RG_VEFUSE_VOSEL_MASK            0xF
+#define MT6359_RG_VEFUSE_VOSEL_SHIFT           8
+#define MT6359_RG_VCAMIO_VOSEL_ADDR            MT6359_VCAMIO_ANA_CON0
+#define MT6359_RG_VCAMIO_VOSEL_MASK            0xF
+#define MT6359_RG_VCAMIO_VOSEL_SHIFT           8
+#define MT6359_RG_VIO18_VOSEL_ADDR             MT6359_VIO18_ANA_CON0
+#define MT6359_RG_VIO18_VOSEL_MASK             0xF
+#define MT6359_RG_VIO18_VOSEL_SHIFT            8
+#define MT6359_RG_VM18_VOSEL_ADDR              MT6359_VM18_ANA_CON0
+#define MT6359_RG_VM18_VOSEL_MASK              0xF
+#define MT6359_RG_VM18_VOSEL_SHIFT             8
+#define MT6359_RG_VUFS_VOSEL_ADDR              MT6359_VUFS_ANA_CON0
+#define MT6359_RG_VUFS_VOSEL_MASK              0xF
+#define MT6359_RG_VUFS_VOSEL_SHIFT             8
+#define MT6359_RG_VRF12_VOSEL_ADDR             MT6359_VRF12_ANA_CON0
+#define MT6359_RG_VRF12_VOSEL_MASK             0xF
+#define MT6359_RG_VRF12_VOSEL_SHIFT            8
+#define MT6359_RG_VCN13_VOSEL_ADDR             MT6359_VCN13_ANA_CON0
+#define MT6359_RG_VCN13_VOSEL_MASK             0xF
+#define MT6359_RG_VCN13_VOSEL_SHIFT            8
+#define MT6359_RG_VA09_VOSEL_ADDR              MT6359_VA09_ANA_CON0
+#define MT6359_RG_VA09_VOSEL_MASK              0xF
+#define MT6359_RG_VA09_VOSEL_SHIFT             8
+#define MT6359_RG_VA12_VOSEL_ADDR              MT6359_VA12_ANA_CON0
+#define MT6359_RG_VA12_VOSEL_MASK              0xF
+#define MT6359_RG_VA12_VOSEL_SHIFT             8
+#define MT6359_RG_VXO22_VOSEL_ADDR             MT6359_VXO22_ANA_CON0
+#define MT6359_RG_VXO22_VOSEL_MASK             0xF
+#define MT6359_RG_VXO22_VOSEL_SHIFT            8
+#define MT6359_RG_VRFCK_VOSEL_ADDR             MT6359_VRFCK_ANA_CON0
+#define MT6359_RG_VRFCK_VOSEL_MASK             0xF
+#define MT6359_RG_VRFCK_VOSEL_SHIFT            8
+#define MT6359_RG_VBBCK_VOSEL_ADDR             MT6359_VBBCK_ANA_CON0
+#define MT6359_RG_VBBCK_VOSEL_MASK             0xF
+#define MT6359_RG_VBBCK_VOSEL_SHIFT            8
+
+#endif /* __MFD_MT6359_REGISTERS_H__ */
diff --git a/include/linux/mfd/mt6359p/registers.h b/include/linux/mfd/mt6359p/registers.h
new file mode 100644 (file)
index 0000000..3d97c18
--- /dev/null
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6359P_REGISTERS_H__
+#define __MFD_MT6359P_REGISTERS_H__
+
+#define MT6359P_CHIP_VER 0x5930
+
+/* PMIC Registers */
+#define MT6359P_HWCID                         0x8
+#define MT6359P_TOP_TRAP                      0x50
+#define MT6359P_TOP_TMA_KEY                   0x3a8
+#define MT6359P_BUCK_VCORE_ELR_NUM            0x152a
+#define MT6359P_BUCK_VCORE_ELR0               0x152c
+#define MT6359P_BUCK_VGPU11_SSHUB_CON0        0x15aa
+#define MT6359P_BUCK_VGPU11_ELR0              0x15b4
+#define MT6359P_LDO_VSRAM_PROC1_ELR           0x1b44
+#define MT6359P_LDO_VSRAM_PROC2_ELR           0x1b46
+#define MT6359P_LDO_VSRAM_OTHERS_ELR          0x1b48
+#define MT6359P_LDO_VSRAM_MD_ELR              0x1b4a
+#define MT6359P_LDO_VEMC_ELR_0                0x1b4c
+#define MT6359P_LDO_VFE28_CON0                0x1b88
+#define MT6359P_LDO_VFE28_MON                 0x1b8c
+#define MT6359P_LDO_VXO22_CON0                0x1b9a
+#define MT6359P_LDO_VXO22_MON                 0x1b9e
+#define MT6359P_LDO_VRF18_CON0                0x1bac
+#define MT6359P_LDO_VRF18_MON                 0x1bb0
+#define MT6359P_LDO_VRF12_CON0                0x1bbe
+#define MT6359P_LDO_VRF12_MON                 0x1bc2
+#define MT6359P_LDO_VEFUSE_CON0               0x1bd0
+#define MT6359P_LDO_VEFUSE_MON                0x1bd4
+#define MT6359P_LDO_VCN33_1_CON0              0x1be2
+#define MT6359P_LDO_VCN33_1_MON               0x1be6
+#define MT6359P_LDO_VCN33_1_MULTI_SW          0x1bf4
+#define MT6359P_LDO_VCN33_2_CON0              0x1c08
+#define MT6359P_LDO_VCN33_2_MON               0x1c0c
+#define MT6359P_LDO_VCN33_2_MULTI_SW          0x1c1a
+#define MT6359P_LDO_VCN13_CON0                0x1c1c
+#define MT6359P_LDO_VCN13_MON                 0x1c20
+#define MT6359P_LDO_VCN18_CON0                0x1c2e
+#define MT6359P_LDO_VCN18_MON                 0x1c32
+#define MT6359P_LDO_VA09_CON0                 0x1c40
+#define MT6359P_LDO_VA09_MON                  0x1c44
+#define MT6359P_LDO_VCAMIO_CON0               0x1c52
+#define MT6359P_LDO_VCAMIO_MON                0x1c56
+#define MT6359P_LDO_VA12_CON0                 0x1c64
+#define MT6359P_LDO_VA12_MON                  0x1c68
+#define MT6359P_LDO_VAUX18_CON0               0x1c88
+#define MT6359P_LDO_VAUX18_MON                0x1c8c
+#define MT6359P_LDO_VAUD18_CON0               0x1c9a
+#define MT6359P_LDO_VAUD18_MON                0x1c9e
+#define MT6359P_LDO_VIO18_CON0                0x1cac
+#define MT6359P_LDO_VIO18_MON                 0x1cb0
+#define MT6359P_LDO_VEMC_CON0                 0x1cbe
+#define MT6359P_LDO_VEMC_MON                  0x1cc2
+#define MT6359P_LDO_VSIM1_CON0                0x1cd0
+#define MT6359P_LDO_VSIM1_MON                 0x1cd4
+#define MT6359P_LDO_VSIM2_CON0                0x1ce2
+#define MT6359P_LDO_VSIM2_MON                 0x1ce6
+#define MT6359P_LDO_VUSB_CON0                 0x1d08
+#define MT6359P_LDO_VUSB_MON                  0x1d0c
+#define MT6359P_LDO_VUSB_MULTI_SW             0x1d1a
+#define MT6359P_LDO_VRFCK_CON0                0x1d1c
+#define MT6359P_LDO_VRFCK_MON                 0x1d20
+#define MT6359P_LDO_VBBCK_CON0                0x1d2e
+#define MT6359P_LDO_VBBCK_MON                 0x1d32
+#define MT6359P_LDO_VBIF28_CON0               0x1d40
+#define MT6359P_LDO_VBIF28_MON                0x1d44
+#define MT6359P_LDO_VIBR_CON0                 0x1d52
+#define MT6359P_LDO_VIBR_MON                  0x1d56
+#define MT6359P_LDO_VIO28_CON0                0x1d64
+#define MT6359P_LDO_VIO28_MON                 0x1d68
+#define MT6359P_LDO_VM18_CON0                 0x1d88
+#define MT6359P_LDO_VM18_MON                  0x1d8c
+#define MT6359P_LDO_VUFS_CON0                 0x1d9a
+#define MT6359P_LDO_VUFS_MON                  0x1d9e
+#define MT6359P_LDO_VSRAM_PROC1_CON0          0x1e88
+#define MT6359P_LDO_VSRAM_PROC1_MON           0x1e8c
+#define MT6359P_LDO_VSRAM_PROC1_VOSEL1        0x1e90
+#define MT6359P_LDO_VSRAM_PROC2_CON0          0x1ea8
+#define MT6359P_LDO_VSRAM_PROC2_MON           0x1eac
+#define MT6359P_LDO_VSRAM_PROC2_VOSEL1        0x1eb0
+#define MT6359P_LDO_VSRAM_OTHERS_CON0         0x1f08
+#define MT6359P_LDO_VSRAM_OTHERS_MON          0x1f0c
+#define MT6359P_LDO_VSRAM_OTHERS_VOSEL1       0x1f10
+#define MT6359P_LDO_VSRAM_OTHERS_SSHUB        0x1f28
+#define MT6359P_LDO_VSRAM_MD_CON0             0x1f2e
+#define MT6359P_LDO_VSRAM_MD_MON              0x1f32
+#define MT6359P_LDO_VSRAM_MD_VOSEL1           0x1f36
+#define MT6359P_VFE28_ANA_CON0                0x1f88
+#define MT6359P_VAUX18_ANA_CON0               0x1f8c
+#define MT6359P_VUSB_ANA_CON0                 0x1f90
+#define MT6359P_VBIF28_ANA_CON0               0x1f94
+#define MT6359P_VCN33_1_ANA_CON0              0x1f98
+#define MT6359P_VCN33_2_ANA_CON0              0x1f9c
+#define MT6359P_VEMC_ANA_CON0                 0x1fa0
+#define MT6359P_VSIM1_ANA_CON0                0x1fa2
+#define MT6359P_VSIM2_ANA_CON0                0x1fa6
+#define MT6359P_VIO28_ANA_CON0                0x1faa
+#define MT6359P_VIBR_ANA_CON0                 0x1fae
+#define MT6359P_VFE28_ELR_4                   0x1fc0
+#define MT6359P_VRF18_ANA_CON0                0x2008
+#define MT6359P_VEFUSE_ANA_CON0               0x200c
+#define MT6359P_VCN18_ANA_CON0                0x2010
+#define MT6359P_VCAMIO_ANA_CON0               0x2014
+#define MT6359P_VAUD18_ANA_CON0               0x2018
+#define MT6359P_VIO18_ANA_CON0                0x201c
+#define MT6359P_VM18_ANA_CON0                 0x2020
+#define MT6359P_VUFS_ANA_CON0                 0x2024
+#define MT6359P_VRF12_ANA_CON0                0x202a
+#define MT6359P_VCN13_ANA_CON0                0x202e
+#define MT6359P_VA09_ANA_CON0                 0x2032
+#define MT6359P_VRF18_ELR_3                   0x204e
+#define MT6359P_VXO22_ANA_CON0                0x2088
+#define MT6359P_VRFCK_ANA_CON0                0x208c
+#define MT6359P_VBBCK_ANA_CON0                0x2096
+
+#define MT6359P_RG_BUCK_VCORE_VOSEL_ADDR         MT6359P_BUCK_VCORE_ELR0
+#define MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR     MT6359P_BUCK_VGPU11_SSHUB_CON0
+#define MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR        MT6359P_BUCK_VGPU11_ELR0
+#define MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR  MT6359P_BUCK_VGPU11_SSHUB_CON0
+#define MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_MASK  0x7F
+#define MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_SHIFT 4
+#define MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR    MT6359P_LDO_VSRAM_PROC1_ELR
+#define MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR    MT6359P_LDO_VSRAM_PROC2_ELR
+#define MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR   MT6359P_LDO_VSRAM_OTHERS_ELR
+#define MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR       MT6359P_LDO_VSRAM_MD_ELR
+#define MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR         MT6359P_LDO_VEMC_ELR_0
+#define MT6359P_RG_LDO_VEMC_VOSEL_0_MASK         0xF
+#define MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT        0
+#define MT6359P_RG_LDO_VFE28_EN_ADDR             MT6359P_LDO_VFE28_CON0
+#define MT6359P_DA_VFE28_B_EN_ADDR               MT6359P_LDO_VFE28_MON
+#define MT6359P_RG_LDO_VXO22_EN_ADDR             MT6359P_LDO_VXO22_CON0
+#define MT6359P_RG_LDO_VXO22_EN_SHIFT            0
+#define MT6359P_DA_VXO22_B_EN_ADDR               MT6359P_LDO_VXO22_MON
+#define MT6359P_RG_LDO_VRF18_EN_ADDR             MT6359P_LDO_VRF18_CON0
+#define MT6359P_RG_LDO_VRF18_EN_SHIFT            0
+#define MT6359P_DA_VRF18_B_EN_ADDR               MT6359P_LDO_VRF18_MON
+#define MT6359P_RG_LDO_VRF12_EN_ADDR             MT6359P_LDO_VRF12_CON0
+#define MT6359P_RG_LDO_VRF12_EN_SHIFT            0
+#define MT6359P_DA_VRF12_B_EN_ADDR               MT6359P_LDO_VRF12_MON
+#define MT6359P_RG_LDO_VEFUSE_EN_ADDR            MT6359P_LDO_VEFUSE_CON0
+#define MT6359P_RG_LDO_VEFUSE_EN_SHIFT           0
+#define MT6359P_DA_VEFUSE_B_EN_ADDR              MT6359P_LDO_VEFUSE_MON
+#define MT6359P_RG_LDO_VCN33_1_EN_0_ADDR         MT6359P_LDO_VCN33_1_CON0
+#define MT6359P_DA_VCN33_1_B_EN_ADDR             MT6359P_LDO_VCN33_1_MON
+#define MT6359P_RG_LDO_VCN33_1_EN_1_ADDR         MT6359P_LDO_VCN33_1_MULTI_SW
+#define MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT        15
+#define MT6359P_RG_LDO_VCN33_2_EN_0_ADDR         MT6359P_LDO_VCN33_2_CON0
+#define MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT        0
+#define MT6359P_DA_VCN33_2_B_EN_ADDR             MT6359P_LDO_VCN33_2_MON
+#define MT6359P_RG_LDO_VCN33_2_EN_1_ADDR         MT6359P_LDO_VCN33_2_MULTI_SW
+#define MT6359P_RG_LDO_VCN13_EN_ADDR             MT6359P_LDO_VCN13_CON0
+#define MT6359P_RG_LDO_VCN13_EN_SHIFT            0
+#define MT6359P_DA_VCN13_B_EN_ADDR               MT6359P_LDO_VCN13_MON
+#define MT6359P_RG_LDO_VCN18_EN_ADDR             MT6359P_LDO_VCN18_CON0
+#define MT6359P_DA_VCN18_B_EN_ADDR               MT6359P_LDO_VCN18_MON
+#define MT6359P_RG_LDO_VA09_EN_ADDR              MT6359P_LDO_VA09_CON0
+#define MT6359P_RG_LDO_VA09_EN_SHIFT             0
+#define MT6359P_DA_VA09_B_EN_ADDR                MT6359P_LDO_VA09_MON
+#define MT6359P_RG_LDO_VCAMIO_EN_ADDR            MT6359P_LDO_VCAMIO_CON0
+#define MT6359P_RG_LDO_VCAMIO_EN_SHIFT           0
+#define MT6359P_DA_VCAMIO_B_EN_ADDR              MT6359P_LDO_VCAMIO_MON
+#define MT6359P_RG_LDO_VA12_EN_ADDR              MT6359P_LDO_VA12_CON0
+#define MT6359P_RG_LDO_VA12_EN_SHIFT             0
+#define MT6359P_DA_VA12_B_EN_ADDR                MT6359P_LDO_VA12_MON
+#define MT6359P_RG_LDO_VAUX18_EN_ADDR            MT6359P_LDO_VAUX18_CON0
+#define MT6359P_DA_VAUX18_B_EN_ADDR              MT6359P_LDO_VAUX18_MON
+#define MT6359P_RG_LDO_VAUD18_EN_ADDR            MT6359P_LDO_VAUD18_CON0
+#define MT6359P_DA_VAUD18_B_EN_ADDR              MT6359P_LDO_VAUD18_MON
+#define MT6359P_RG_LDO_VIO18_EN_ADDR             MT6359P_LDO_VIO18_CON0
+#define MT6359P_RG_LDO_VIO18_EN_SHIFT            0
+#define MT6359P_DA_VIO18_B_EN_ADDR               MT6359P_LDO_VIO18_MON
+#define MT6359P_RG_LDO_VEMC_EN_ADDR              MT6359P_LDO_VEMC_CON0
+#define MT6359P_RG_LDO_VEMC_EN_SHIFT             0
+#define MT6359P_DA_VEMC_B_EN_ADDR                MT6359P_LDO_VEMC_MON
+#define MT6359P_RG_LDO_VSIM1_EN_ADDR             MT6359P_LDO_VSIM1_CON0
+#define MT6359P_RG_LDO_VSIM1_EN_SHIFT            0
+#define MT6359P_DA_VSIM1_B_EN_ADDR               MT6359P_LDO_VSIM1_MON
+#define MT6359P_RG_LDO_VSIM2_EN_ADDR             MT6359P_LDO_VSIM2_CON0
+#define MT6359P_RG_LDO_VSIM2_EN_SHIFT            0
+#define MT6359P_DA_VSIM2_B_EN_ADDR               MT6359P_LDO_VSIM2_MON
+#define MT6359P_RG_LDO_VUSB_EN_0_ADDR            MT6359P_LDO_VUSB_CON0
+#define MT6359P_DA_VUSB_B_EN_ADDR                MT6359P_LDO_VUSB_MON
+#define MT6359P_RG_LDO_VUSB_EN_1_ADDR            MT6359P_LDO_VUSB_MULTI_SW
+#define MT6359P_RG_LDO_VRFCK_EN_ADDR             MT6359P_LDO_VRFCK_CON0
+#define MT6359P_RG_LDO_VRFCK_EN_SHIFT            0
+#define MT6359P_DA_VRFCK_B_EN_ADDR               MT6359P_LDO_VRFCK_MON
+#define MT6359P_RG_LDO_VBBCK_EN_ADDR             MT6359P_LDO_VBBCK_CON0
+#define MT6359P_RG_LDO_VBBCK_EN_SHIFT            0
+#define MT6359P_DA_VBBCK_B_EN_ADDR               MT6359P_LDO_VBBCK_MON
+#define MT6359P_RG_LDO_VBIF28_EN_ADDR            MT6359P_LDO_VBIF28_CON0
+#define MT6359P_DA_VBIF28_B_EN_ADDR              MT6359P_LDO_VBIF28_MON
+#define MT6359P_RG_LDO_VIBR_EN_ADDR              MT6359P_LDO_VIBR_CON0
+#define MT6359P_RG_LDO_VIBR_EN_SHIFT             0
+#define MT6359P_DA_VIBR_B_EN_ADDR                MT6359P_LDO_VIBR_MON
+#define MT6359P_RG_LDO_VIO28_EN_ADDR             MT6359P_LDO_VIO28_CON0
+#define MT6359P_RG_LDO_VIO28_EN_SHIFT            0
+#define MT6359P_DA_VIO28_B_EN_ADDR               MT6359P_LDO_VIO28_MON
+#define MT6359P_RG_LDO_VM18_EN_ADDR              MT6359P_LDO_VM18_CON0
+#define MT6359P_RG_LDO_VM18_EN_SHIFT             0
+#define MT6359P_DA_VM18_B_EN_ADDR                MT6359P_LDO_VM18_MON
+#define MT6359P_RG_LDO_VUFS_EN_ADDR              MT6359P_LDO_VUFS_CON0
+#define MT6359P_RG_LDO_VUFS_EN_SHIFT             0
+#define MT6359P_DA_VUFS_B_EN_ADDR                MT6359P_LDO_VUFS_MON
+#define MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR       MT6359P_LDO_VSRAM_PROC1_CON0
+#define MT6359P_DA_VSRAM_PROC1_B_EN_ADDR         MT6359P_LDO_VSRAM_PROC1_MON
+#define MT6359P_DA_VSRAM_PROC1_VOSEL_ADDR        MT6359P_LDO_VSRAM_PROC1_VOSEL1
+#define MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR       MT6359P_LDO_VSRAM_PROC2_CON0
+#define MT6359P_DA_VSRAM_PROC2_B_EN_ADDR         MT6359P_LDO_VSRAM_PROC2_MON
+#define MT6359P_DA_VSRAM_PROC2_VOSEL_ADDR        MT6359P_LDO_VSRAM_PROC2_VOSEL1
+#define MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR      MT6359P_LDO_VSRAM_OTHERS_CON0
+#define MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR        MT6359P_LDO_VSRAM_OTHERS_MON
+#define MT6359P_DA_VSRAM_OTHERS_VOSEL_ADDR       MT6359P_LDO_VSRAM_OTHERS_VOSEL1
+#define MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR    MT6359P_LDO_VSRAM_OTHERS_SSHUB
+#define MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR MT6359P_LDO_VSRAM_OTHERS_SSHUB
+#define MT6359P_RG_LDO_VSRAM_MD_EN_ADDR          MT6359P_LDO_VSRAM_MD_CON0
+#define MT6359P_DA_VSRAM_MD_B_EN_ADDR            MT6359P_LDO_VSRAM_MD_MON
+#define MT6359P_DA_VSRAM_MD_VOSEL_ADDR           MT6359P_LDO_VSRAM_MD_VOSEL1
+#define MT6359P_RG_VCN33_1_VOSEL_ADDR            MT6359P_VCN33_1_ANA_CON0
+#define MT6359P_RG_VCN33_2_VOSEL_ADDR            MT6359P_VCN33_2_ANA_CON0
+#define MT6359P_RG_VEMC_VOSEL_ADDR               MT6359P_VEMC_ANA_CON0
+#define MT6359P_RG_VSIM1_VOSEL_ADDR              MT6359P_VSIM1_ANA_CON0
+#define MT6359P_RG_VSIM2_VOSEL_ADDR              MT6359P_VSIM2_ANA_CON0
+#define MT6359P_RG_VIO28_VOSEL_ADDR              MT6359P_VIO28_ANA_CON0
+#define MT6359P_RG_VIBR_VOSEL_ADDR               MT6359P_VIBR_ANA_CON0
+#define MT6359P_RG_VRF18_VOSEL_ADDR              MT6359P_VRF18_ANA_CON0
+#define MT6359P_RG_VEFUSE_VOSEL_ADDR             MT6359P_VEFUSE_ANA_CON0
+#define MT6359P_RG_VCAMIO_VOSEL_ADDR             MT6359P_VCAMIO_ANA_CON0
+#define MT6359P_RG_VIO18_VOSEL_ADDR              MT6359P_VIO18_ANA_CON0
+#define MT6359P_RG_VM18_VOSEL_ADDR               MT6359P_VM18_ANA_CON0
+#define MT6359P_RG_VUFS_VOSEL_ADDR               MT6359P_VUFS_ANA_CON0
+#define MT6359P_RG_VRF12_VOSEL_ADDR              MT6359P_VRF12_ANA_CON0
+#define MT6359P_RG_VCN13_VOSEL_ADDR              MT6359P_VCN13_ANA_CON0
+#define MT6359P_RG_VA09_VOSEL_ADDR               MT6359P_VRF18_ELR_3
+#define MT6359P_RG_VA12_VOSEL_ADDR               MT6359P_VFE28_ELR_4
+#define MT6359P_RG_VXO22_VOSEL_ADDR              MT6359P_VXO22_ANA_CON0
+#define MT6359P_RG_VRFCK_VOSEL_ADDR              MT6359P_VRFCK_ANA_CON0
+#define MT6359P_RG_VBBCK_VOSEL_ADDR              MT6359P_VBBCK_ANA_CON0
+#define MT6359P_RG_VBBCK_VOSEL_MASK              0xF
+#define MT6359P_RG_VBBCK_VOSEL_SHIFT             4
+#define MT6359P_VM_MODE_ADDR                     MT6359P_TOP_TRAP
+#define MT6359P_TMA_KEY_ADDR                     MT6359P_TOP_TMA_KEY
+
+#define TMA_KEY 0x9CA6
+
+#endif /* __MFD_MT6359P_REGISTERS_H__ */
index 9492685..56f210e 100644 (file)
@@ -13,6 +13,7 @@
 enum chip_id {
        MT6323_CHIP_ID = 0x23,
        MT6358_CHIP_ID = 0x58,
+       MT6359_CHIP_ID = 0x59,
        MT6391_CHIP_ID = 0x91,
        MT6397_CHIP_ID = 0x97,
 };
index c3748b5..068ae1c 100644 (file)
@@ -36,6 +36,7 @@
 #define RTC_AL_MASK_DOW                BIT(4)
 
 #define RTC_TC_SEC             0x000a
+#define RTC_TC_MTH_MASK        0x000f
 /* Min, Hour, Dom... register offset to RTC_TC_SEC */
 #define RTC_OFFSET_SEC         0
 #define RTC_OFFSET_MIN         1
index 020a8f7..f8902bc 100644 (file)
@@ -542,6 +542,10 @@ struct mlx5_core_roce {
 enum {
        MLX5_PRIV_FLAGS_DISABLE_IB_ADEV = 1 << 0,
        MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV = 1 << 1,
+       /* Set during device detach to block any further devices
+        * creation/deletion on drivers rescan. Unset during device attach.
+        */
+       MLX5_PRIV_FLAGS_DETACH = 1 << 2,
 };
 
 struct mlx5_adev {
index 028f442..60ffeb6 100644 (file)
@@ -85,4 +85,5 @@ mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev,
                         struct mlx5_hairpin_params *params);
 
 void mlx5_core_hairpin_destroy(struct mlx5_hairpin *pair);
+void mlx5_core_hairpin_clear_dead_peer(struct mlx5_hairpin *hp);
 #endif /* __TRANSOBJ_H__ */
index c274f75..01ecf9e 100644 (file)
@@ -1709,8 +1709,8 @@ extern bool can_do_mlock(void);
 #else
 static inline bool can_do_mlock(void) { return false; }
 #endif
-extern int user_shm_lock(size_t, struct user_struct *);
-extern void user_shm_unlock(size_t, struct user_struct *);
+extern int user_shm_lock(size_t, struct ucounts *);
+extern void user_shm_unlock(size_t, struct ucounts *);
 
 /*
  * Parameter block passed down to zap_pte_range in exceptional cases.
@@ -1719,6 +1719,7 @@ struct zap_details {
        struct address_space *check_mapping;    /* Check page->mapping if set */
        pgoff_t first_index;                    /* Lowest page->index to unmap */
        pgoff_t last_index;                     /* Highest page->index to unmap */
+       struct page *single_page;               /* Locked page to be unmapped */
 };
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
@@ -1766,6 +1767,7 @@ extern vm_fault_t handle_mm_fault(struct vm_area_struct *vma,
 extern int fixup_user_fault(struct mm_struct *mm,
                            unsigned long address, unsigned int fault_flags,
                            bool *unlocked);
+void unmap_mapping_page(struct page *page);
 void unmap_mapping_pages(struct address_space *mapping,
                pgoff_t start, pgoff_t nr, bool even_cows);
 void unmap_mapping_range(struct address_space *mapping,
@@ -1786,6 +1788,7 @@ static inline int fixup_user_fault(struct mm_struct *mm, unsigned long address,
        BUG();
        return -EFAULT;
 }
+static inline void unmap_mapping_page(struct page *page) { }
 static inline void unmap_mapping_pages(struct address_space *mapping,
                pgoff_t start, pgoff_t nr, bool even_cows) { }
 static inline void unmap_mapping_range(struct address_space *mapping,
index f9ad35d..74e6c06 100644 (file)
@@ -139,6 +139,8 @@ struct sd_scr {
        unsigned char           cmds;
 #define SD_SCR_CMD20_SUPPORT   (1<<0)
 #define SD_SCR_CMD23_SUPPORT   (1<<1)
+#define SD_SCR_CMD48_SUPPORT   (1<<2)
+#define SD_SCR_CMD58_SUPPORT   (1<<3)
 };
 
 struct sd_ssr {
@@ -189,6 +191,25 @@ struct sd_switch_caps {
 #define SD_MAX_CURRENT_800     (1 << SD_SET_CURRENT_LIMIT_800)
 };
 
+struct sd_ext_reg {
+       u8                      fno;
+       u8                      page;
+       u16                     offset;
+       u8                      rev;
+       u8                      feature_enabled;
+       u8                      feature_support;
+/* Power Management Function. */
+#define SD_EXT_POWER_OFF_NOTIFY        (1<<0)
+#define SD_EXT_POWER_SUSTENANCE        (1<<1)
+#define SD_EXT_POWER_DOWN_MODE (1<<2)
+/* Performance Enhancement Function. */
+#define SD_EXT_PERF_FX_EVENT   (1<<0)
+#define SD_EXT_PERF_CARD_MAINT (1<<1)
+#define SD_EXT_PERF_HOST_MAINT (1<<2)
+#define SD_EXT_PERF_CACHE      (1<<3)
+#define SD_EXT_PERF_CMD_QUEUE  (1<<4)
+};
+
 struct sdio_cccr {
        unsigned int            sdio_vsn;
        unsigned int            sd_vsn;
@@ -290,6 +311,8 @@ struct mmc_card {
        struct sd_scr           scr;            /* extra SD information */
        struct sd_ssr           ssr;            /* yet more SD information */
        struct sd_switch_caps   sw_caps;        /* switch (CMD6) caps */
+       struct sd_ext_reg       ext_power;      /* SD extension reg for PM */
+       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
 
        unsigned int            sdio_funcs;     /* number of SDIO functions */
        atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
index c7e7b43..0abd47e 100644 (file)
@@ -632,6 +632,6 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data)
 }
 
 int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
-int mmc_abort_tuning(struct mmc_host *host, u32 opcode);
+int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
 
 #endif /* LINUX_MMC_HOST_H */
index 2236aa5..6727576 100644 (file)
 #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
 #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
 
+  /* class 11 */
+#define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
+#define SD_WRITE_EXTR_SINGLE     49   /* adtc [31:0]             R1  */
+
 /* OCR bit definitions */
 #define SD_OCR_S18R            (1 << 24)    /* 1.8V switching request */
 #define SD_ROCR_S18A           SD_OCR_S18R  /* 1.8V switching accepted by card */
index 6bb92f2..6988956 100644 (file)
@@ -170,6 +170,28 @@ struct spinand_op;
 struct spinand_device;
 
 #define SPINAND_MAX_ID_LEN     4
+/*
+ * For erase, write and read operation, we got the following timings :
+ * tBERS (erase) 1ms to 4ms
+ * tPROG 300us to 400us
+ * tREAD 25us to 100us
+ * In order to minimize latency, the min value is divided by 4 for the
+ * initial delay, and dividing by 20 for the poll delay.
+ * For reset, 5us/10us/500us if the device is respectively
+ * reading/programming/erasing when the RESET occurs. Since we always
+ * issue a RESET when the device is IDLE, 5us is selected for both initial
+ * and poll delay.
+ */
+#define SPINAND_READ_INITIAL_DELAY_US  6
+#define SPINAND_READ_POLL_DELAY_US     5
+#define SPINAND_RESET_INITIAL_DELAY_US 5
+#define SPINAND_RESET_POLL_DELAY_US    5
+#define SPINAND_WRITE_INITIAL_DELAY_US 75
+#define SPINAND_WRITE_POLL_DELAY_US    15
+#define SPINAND_ERASE_INITIAL_DELAY_US 250
+#define SPINAND_ERASE_POLL_DELAY_US    50
+
+#define SPINAND_WAITRDY_TIMEOUT_MS     400
 
 /**
  * struct spinand_id - SPI NAND id structure
index 04a34c0..40e2c50 100644 (file)
@@ -138,6 +138,9 @@ enum pageflags {
 #ifdef CONFIG_64BIT
        PG_arch_2,
 #endif
+#ifdef CONFIG_KASAN_HW_TAGS
+       PG_skip_kasan_poison,
+#endif
        __NR_PAGEFLAGS,
 
        /* Filesystems */
@@ -443,6 +446,12 @@ TESTCLEARFLAG(Young, young, PF_ANY)
 PAGEFLAG(Idle, idle, PF_ANY)
 #endif
 
+#ifdef CONFIG_KASAN_HW_TAGS
+PAGEFLAG(SkipKASanPoison, skip_kasan_poison, PF_HEAD)
+#else
+PAGEFLAG_FALSE(SkipKASanPoison)
+#endif
+
 /*
  * PageReported() is used to track reported free pages within the Buddy
  * allocator. We can use the non-atomic version of the test and set
index e89df44..0f1b34d 100644 (file)
@@ -516,7 +516,7 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
 }
 
 /*
- * Get index of the page with in radix-tree
+ * Get index of the page within radix-tree (but not for hugetlb pages).
  * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE)
  */
 static inline pgoff_t page_to_index(struct page *page)
@@ -535,15 +535,16 @@ static inline pgoff_t page_to_index(struct page *page)
        return pgoff;
 }
 
+extern pgoff_t hugetlb_basepage_index(struct page *page);
+
 /*
- * Get the offset in PAGE_SIZE.
- * (TODO: hugepage should have ->index in PAGE_SIZE)
+ * Get the offset in PAGE_SIZE (even for hugetlb pages).
+ * (TODO: hugetlb pages should have ->index in PAGE_SIZE)
  */
 static inline pgoff_t page_to_pgoff(struct page *page)
 {
-       if (unlikely(PageHeadHuge(page)))
-               return page->index << compound_order(page);
-
+       if (unlikely(PageHuge(page)))
+               return hugetlb_basepage_index(page);
        return page_to_index(page);
 }
 
index 4c3fa52..4bac183 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_M60H_DF_F3 0x144b
 #define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
 #define PCI_DEVICE_ID_AMD_19H_DF_F3    0x1653
+#define PCI_DEVICE_ID_AMD_19H_M50H_DF_F3 0x166d
 #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_DEVICE_ID_DELL_RAC4                0x0012
 #define PCI_DEVICE_ID_DELL_PERC5       0x0015
 
+#define PCI_SUBVENDOR_ID_DELL          0x1028
+
 #define PCI_VENDOR_ID_MATROX           0x102B
 #define PCI_DEVICE_ID_MATROX_MGA_2     0x0518
 #define PCI_DEVICE_ID_MATROX_MIL       0x0519
index f5a6a2f..2d510ad 100644 (file)
@@ -1576,6 +1576,12 @@ static struct perf_pmu_events_attr _var = {                                  \
        .event_str      = _str,                                             \
 };
 
+#define PMU_EVENT_ATTR_ID(_name, _show, _id)                           \
+       (&((struct perf_pmu_events_attr[]) {                            \
+               { .attr = __ATTR(_name, 0444, _show, NULL),             \
+                 .id = _id, }                                          \
+       })[0].attr.attr)
+
 #define PMU_FORMAT_ATTR(_name, _format)                                        \
 static ssize_t                                                         \
 _name##_show(struct device *dev,                                       \
index e18ab3d..5a96602 100644 (file)
@@ -89,7 +89,7 @@ struct pinctrl_map;
  *     it.
  * @PIN_CONFIG_OUTPUT: this will configure the pin as an output and drive a
  *     value on the line. Use argument 1 to indicate high level, argument 0 to
- *     indicate low level. (Please see Documentation/driver-api/pinctl.rst,
+ *     indicate low level. (Please see Documentation/driver-api/pin-control.rst,
  *     section "GPIO mode pitfalls" for a discussion around this parameter.)
  * @PIN_CONFIG_PERSIST_STATE: retain pin state across sleep or controller reset
  * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
diff --git a/include/linux/platform_data/spi-ath79.h b/include/linux/platform_data/spi-ath79.h
deleted file mode 100644 (file)
index 81a388f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *  Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller
- *
- *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
- */
-
-#ifndef _ATH79_SPI_PLATFORM_H
-#define _ATH79_SPI_PLATFORM_H
-
-struct ath79_spi_platform_data {
-       unsigned        bus_num;
-       unsigned        num_chipselect;
-};
-
-#endif /* _ATH79_SPI_PLATFORM_H */
index a632900..e5cbb68 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Platform profile sysfs interface
  *
- * See Documentation/ABI/testing/sysfs-platform_profile.rst for more
+ * See Documentation/userspace-api/sysfs-platform_profile.rst for more
  * information.
  */
 
index dfcfbce..21a0577 100644 (file)
@@ -198,6 +198,7 @@ struct generic_pm_domain_data {
        struct notifier_block *power_nb;
        int cpu;
        unsigned int performance_state;
+       unsigned int rpm_pstate;
        ktime_t next_wakeup;
        void *data;
 };
index 6c08a08..aab8b35 100644 (file)
@@ -380,6 +380,9 @@ static inline int pm_runtime_get(struct device *dev)
  * The possible return values of this function are the same as for
  * pm_runtime_resume() and the runtime PM usage counter of @dev remains
  * incremented in all cases, even if it returns an error code.
+ * Consider using pm_runtime_resume_and_get() instead of it, especially
+ * if its return value is checked by the caller, as this is likely to result
+ * in cleaner code.
  */
 static inline int pm_runtime_get_sync(struct device *dev)
 {
index 12cbbf3..fa9f081 100644 (file)
  */
 #define PMBUS_NO_CAPABILITY                    BIT(2)
 
+/*
+ * PMBUS_READ_STATUS_AFTER_FAILED_CHECK
+ *
+ * Some PMBus chips end up in an undefined state when trying to read an
+ * unsupported register. For such chips, it is necessary to reset the
+ * chip pmbus controller to a known state after a failed register check.
+ * This can be done by reading a known register. By setting this flag the
+ * driver will try to read the STATUS register after each failed
+ * register check. This read may fail, but it will put the chip in a
+ * known state.
+ */
+#define PMBUS_READ_STATUS_AFTER_FAILED_CHECK   BIT(3)
+
+/*
+ * PMBUS_NO_WRITE_PROTECT
+ *
+ * Some PMBus chips respond with invalid data when reading the WRITE_PROTECT
+ * register. For such chips, this flag should be set so that the PMBus core
+ * driver doesn't use the WRITE_PROTECT command to determine its behavior.
+ */
+#define PMBUS_NO_WRITE_PROTECT                 BIT(4)
+
+/*
+ * PMBUS_USE_COEFFICIENTS_CMD
+ *
+ * When this flag is set the PMBus core driver will use the COEFFICIENTS
+ * register to initialize the coefficients for the direct mode format.
+ */
+#define PMBUS_USE_COEFFICIENTS_CMD             BIT(5)
+
 struct pmbus_platform_data {
        u32 flags;              /* Device specific flags */
 
index bbf4b4a..056d313 100644 (file)
@@ -111,7 +111,7 @@ static inline u32 __seed(u32 x, u32 m)
  */
 static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
 {
-       u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
+       u32 i = ((seed >> 32) ^ (seed << 10) ^ seed) & 0xffffffffUL;
 
        state->s1 = __seed(i,   2U);
        state->s2 = __seed(i,   8U);
index fe7eb23..1790a55 100644 (file)
@@ -282,6 +282,47 @@ static inline void printk_safe_flush_on_panic(void)
 }
 #endif
 
+#ifdef CONFIG_SMP
+extern int __printk_cpu_trylock(void);
+extern void __printk_wait_on_cpu_lock(void);
+extern void __printk_cpu_unlock(void);
+
+/**
+ * printk_cpu_lock_irqsave() - Acquire the printk cpu-reentrant spinning
+ *                             lock and disable interrupts.
+ * @flags: Stack-allocated storage for saving local interrupt state,
+ *         to be passed to printk_cpu_unlock_irqrestore().
+ *
+ * If the lock is owned by another CPU, spin until it becomes available.
+ * Interrupts are restored while spinning.
+ */
+#define printk_cpu_lock_irqsave(flags)         \
+       for (;;) {                              \
+               local_irq_save(flags);          \
+               if (__printk_cpu_trylock())     \
+                       break;                  \
+               local_irq_restore(flags);       \
+               __printk_wait_on_cpu_lock();    \
+       }
+
+/**
+ * printk_cpu_unlock_irqrestore() - Release the printk cpu-reentrant spinning
+ *                                  lock and restore interrupts.
+ * @flags: Caller's saved interrupt state, from printk_cpu_lock_irqsave().
+ */
+#define printk_cpu_unlock_irqrestore(flags)    \
+       do {                                    \
+               __printk_cpu_unlock();          \
+               local_irq_restore(flags);       \
+       } while (0)                             \
+
+#else
+
+#define printk_cpu_lock_irqsave(flags) ((void)flags)
+#define printk_cpu_unlock_irqrestore(flags) ((void)flags)
+
+#endif /* CONFIG_SMP */
+
 extern int kptr_restrict;
 
 /**
index 99564f9..924ca07 100644 (file)
 /**
  * struct pstore_device_info - back-end pstore/blk driver structure.
  *
- * @total_size: The total size in bytes pstore/blk can use. It must be greater
- *             than 4096 and be multiple of 4096.
  * @flags:     Refer to macro starting with PSTORE_FLAGS defined in
  *             linux/pstore.h. It means what front-ends this device support.
  *             Zero means all backends for compatible.
- * @read:      The general read operation. Both of the function parameters
- *             @size and @offset are relative value to bock device (not the
- *             whole disk).
- *             On success, the number of bytes should be returned, others
- *             means error.
- * @write:     The same as @read, but the following error number:
- *             -EBUSY means try to write again later.
- *             -ENOMSG means to try next zone.
- * @erase:     The general erase operation for device with special removing
- *             job. Both of the function parameters @size and @offset are
- *             relative value to storage.
- *             Return 0 on success and others on failure.
- * @panic_write:The write operation only used for panic case. It's optional
- *             if you do not care panic log. The parameters are relative
- *             value to storage.
- *             On success, the number of bytes should be returned, others
- *             excluding -ENOMSG mean error. -ENOMSG means to try next zone.
+ * @zone:      The struct pstore_zone_info details.
+ *
  */
 struct pstore_device_info {
-       unsigned long total_size;
        unsigned int flags;
-       pstore_zone_read_op read;
-       pstore_zone_write_op write;
-       pstore_zone_erase_op erase;
-       pstore_zone_write_op panic_write;
+       struct pstore_zone_info zone;
 };
 
 int  register_pstore_device(struct pstore_device_info *dev);
index 0d47fd3..51d7f1b 100644 (file)
@@ -235,7 +235,7 @@ extern int ptp_clock_index(struct ptp_clock *ptp);
  * @ppm:    Parts per million, but with a 16 bit binary fractional field
  */
 
-extern s32 scaled_ppm_to_ppb(long ppm);
+extern long scaled_ppm_to_ppb(long ppm);
 
 /**
  * ptp_find_pin() - obtain the pin index of a given auxiliary function
index 7f73b26..a3fec2d 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ * Copyright (C) 2003 Russell King, All Rights Reserved.
  *
  * This driver supports the following PXA CPU/SSP ports:-
  *
@@ -11,8 +11,8 @@
  *       PXA3xx     SSP1, SSP2, SSP3, SSP4
  */
 
-#ifndef __LINUX_SSP_H
-#define __LINUX_SSP_H
+#ifndef __LINUX_PXA2XX_SSP_H
+#define __LINUX_PXA2XX_SSP_H
 
 #include <linux/bits.h>
 #include <linux/compiler_types.h>
@@ -38,7 +38,6 @@ struct device_node;
 #define SSDR           (0x10)  /* SSP Data Write/Data Read Register */
 
 #define SSTO           (0x28)  /* SSP Time Out Register */
-#define DDS_RATE       (0x28)  /* SSP DDS Clock Rate Register (Intel Quark) */
 #define SSPSP          (0x2C)  /* SSP Programmable Serial Protocol */
 #define SSTSA          (0x30)  /* SSP Tx Timeslot Active */
 #define SSRSA          (0x34)  /* SSP Rx Timeslot Active */
@@ -60,7 +59,7 @@ struct device_node;
 /* PXA27x, PXA3xx */
 #define SSCR0_EDSS     BIT(20)         /* Extended data size select */
 #define SSCR0_NCS      BIT(21)         /* Network clock select */
-#define SSCR0_RIM      BIT(22)         /* Receive FIFO overrrun interrupt mask */
+#define SSCR0_RIM      BIT(22)         /* Receive FIFO overrun interrupt mask */
 #define SSCR0_TUM      BIT(23)         /* Transmit FIFO underrun interrupt mask */
 #define SSCR0_FRDC     GENMASK(26, 24) /* Frame rate divider control (mask) */
 #define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame [1..8] */
@@ -105,6 +104,9 @@ struct device_node;
 #define CE4100_SSCR1_RFT       GENMASK(11, 10) /* Receive FIFO Threshold (mask) */
 #define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10)      /* level [1..4] */
 
+/* Intel Quark X1000 */
+#define DDS_RATE               0x28             /* SSP DDS Clock Rate Register */
+
 /* QUARK_X1000 SSCR0 bit definition */
 #define QUARK_X1000_SSCR0_DSS          GENMASK(4, 0)   /* Data Size Select (mask) */
 #define QUARK_X1000_SSCR0_DataSize(x)  ((x) - 1)       /* Data Size Select [4..32] */
@@ -124,7 +126,7 @@ struct device_node;
 #define QUARK_X1000_SSCR1_EFWR BIT(16)         /* Enable FIFO Write/Read */
 #define QUARK_X1000_SSCR1_STRF BIT(17)         /* Select FIFO or EFWR */
 
-/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
+/* Extra bits in PXA255, PXA26x and PXA27x SSP ports */
 #define SSCR0_TISSP            (1 << 4)        /* TI Sync Serial Protocol */
 #define SSCR0_PSP              (3 << 4)        /* PSP - Programmable Serial Protocol */
 
@@ -181,6 +183,21 @@ struct device_node;
 #define SSACD_ACPS(x)          ((x) << 4)      /* Audio clock PLL select */
 #define SSACD_SCDX8            BIT(7)          /* SYSCLK division ratio select */
 
+/* Intel Merrifield SSP */
+#define SFIFOL                 0x68            /* FIFO level */
+#define SFIFOTT                        0x6c            /* FIFO trigger threshold */
+
+#define RX_THRESH_MRFLD_DFLT   16
+#define TX_THRESH_MRFLD_DFLT   16
+
+#define SFIFOL_TFL_MASK                GENMASK(15, 0)  /* Transmit FIFO Level mask */
+#define SFIFOL_RFL_MASK                GENMASK(31, 16) /* Receive FIFO Level mask */
+
+#define SFIFOTT_TFT            GENMASK(15, 0)  /* Transmit FIFO Threshold (mask) */
+#define SFIFOTT_TxThresh(x)    (((x) - 1) << 0)        /* TX FIFO trigger threshold / level */
+#define SFIFOTT_RFT            GENMASK(31, 16) /* Receive FIFO Threshold (mask) */
+#define SFIFOTT_RxThresh(x)    (((x) - 1) << 16)       /* RX FIFO trigger threshold / level */
+
 /* LPSS SSP */
 #define SSITF                  0x44            /* TX FIFO trigger level */
 #define SSITF_TxHiThresh(x)    (((x) - 1) << 0)
@@ -203,8 +220,10 @@ enum pxa_ssp_type {
        MMP2_SSP,
        PXA910_SSP,
        CE4100_SSP,
+       MRFLD_SSP,
        QUARK_X1000_SSP,
-       LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */
+       /* Keep LPSS types sorted with lpss_platforms[] */
+       LPSS_LPT_SSP,
        LPSS_BYT_SSP,
        LPSS_BSW_SSP,
        LPSS_SPT_SSP,
@@ -252,6 +271,22 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
        return __raw_readl(dev->mmio_base + reg);
 }
 
+static inline void pxa_ssp_enable(struct ssp_device *ssp)
+{
+       u32 sscr0;
+
+       sscr0 = pxa_ssp_read_reg(ssp, SSCR0) | SSCR0_SSE;
+       pxa_ssp_write_reg(ssp, SSCR0, sscr0);
+}
+
+static inline void pxa_ssp_disable(struct ssp_device *ssp)
+{
+       u32 sscr0;
+
+       sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~SSCR0_SSE;
+       pxa_ssp_write_reg(ssp, SSCR0, sscr0);
+}
+
 #if IS_ENABLED(CONFIG_PXA_SSP)
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 void pxa_ssp_free(struct ssp_device *);
@@ -270,4 +305,4 @@ static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n,
 static inline void pxa_ssp_free(struct ssp_device *ssp) {}
 #endif
 
-#endif
+#endif /* __LINUX_PXA2XX_SSP_H */
index 3734cd8..af907a3 100644 (file)
@@ -79,6 +79,7 @@ extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
 
 extern void orderly_poweroff(bool force);
 extern void orderly_reboot(void);
+void hw_protection_shutdown(const char *reason, int ms_until_forced);
 
 /*
  * Emergency restart, callable from an interrupt handler.
index f87a11a..f5f08dd 100644 (file)
@@ -27,6 +27,7 @@ struct device_node;
 struct i2c_client;
 struct i3c_device;
 struct irq_domain;
+struct mdio_device;
 struct slim_device;
 struct spi_device;
 struct spmi_device;
@@ -502,6 +503,7 @@ typedef void (*regmap_hw_free_context)(void *context);
  *     DEFAULT, BIG is assumed.
  * @max_raw_read: Max raw read size that can be used on the bus.
  * @max_raw_write: Max raw write size that can be used on the bus.
+ * @free_on_exit: kfree this on exit of regmap
  */
 struct regmap_bus {
        bool fast_io;
@@ -519,6 +521,7 @@ struct regmap_bus {
        enum regmap_endian val_format_endian_default;
        size_t max_raw_read;
        size_t max_raw_write;
+       bool free_on_exit;
 };
 
 /*
@@ -538,6 +541,10 @@ struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
                                 const struct regmap_config *config,
                                 struct lock_class_key *lock_key,
                                 const char *lock_name);
+struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,
+                                const struct regmap_config *config,
+                                struct lock_class_key *lock_key,
+                                const char *lock_name);
 struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
                                  const struct regmap_config *config,
                                  struct lock_class_key *lock_key,
@@ -594,6 +601,10 @@ struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
                                      const struct regmap_config *config,
                                      struct lock_class_key *lock_key,
                                      const char *lock_name);
+struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,
+                                     const struct regmap_config *config,
+                                     struct lock_class_key *lock_key,
+                                     const char *lock_name);
 struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
                                       const struct regmap_config *config,
                                       struct lock_class_key *lock_key,
@@ -698,6 +709,19 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                i2c, config)
 
 /**
+ * regmap_init_mdio() - Initialise register map
+ *
+ * @mdio_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+#define regmap_init_mdio(mdio_dev, config)                             \
+       __regmap_lockdep_wrapper(__regmap_init_mdio, #config,           \
+                               mdio_dev, config)
+
+/**
  * regmap_init_sccb() - Initialise register map
  *
  * @i2c: Device that will be interacted with
@@ -889,6 +913,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                i2c, config)
 
 /**
+ * devm_regmap_init_mdio() - Initialise managed register map
+ *
+ * @mdio_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_mdio(mdio_dev, config)                                \
+       __regmap_lockdep_wrapper(__devm_regmap_init_mdio, #config,      \
+                               mdio_dev, config)
+
+/**
  * devm_regmap_init_sccb() - Initialise managed register map
  *
  * @i2c: Device that will be interacted with
@@ -1411,6 +1449,7 @@ struct regmap_irq_sub_irq_map {
  * @not_fixed_stride: Used when chip peripherals are not laid out with fixed
  *                   stride. Must be used with sub_reg_offsets containing the
  *                   offsets to each peripheral.
+ * @status_invert: Inverted status register: cleared bits are active interrupts.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
@@ -1463,6 +1502,7 @@ struct regmap_irq_chip {
        bool type_in_mask:1;
        bool clear_on_unmask:1;
        bool not_fixed_stride:1;
+       bool status_invert:1;
 
        int num_regs;
 
index 20e84a8..f72ca73 100644 (file)
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE            0x400
 #define REGULATOR_EVENT_ABORT_DISABLE          0x800
 #define REGULATOR_EVENT_ENABLE                 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN     0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN      0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN      0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN         0x10000
+#define REGULATOR_EVENT_WARN_MASK              0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL                   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP              BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN     BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN      BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN      BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN         BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
index 5f86824..73291f2 100644 (file)
@@ -52,7 +52,6 @@ struct regulator_coupler {
 
 #ifdef CONFIG_REGULATOR
 int regulator_coupler_register(struct regulator_coupler *coupler);
-const char *rdev_get_name(struct regulator_dev *rdev);
 int regulator_check_consumers(struct regulator_dev *rdev,
                              int *min_uV, int *max_uV,
                              suspend_state_t state);
@@ -69,10 +68,6 @@ static inline int regulator_coupler_register(struct regulator_coupler *coupler)
 {
        return 0;
 }
-static inline const char *rdev_get_name(struct regulator_dev *rdev)
-{
-       return NULL;
-}
 static inline int regulator_check_consumers(struct regulator_dev *rdev,
                                            int *min_uV, int *max_uV,
                                            suspend_state_t state)
index 4ea520c..4aec203 100644 (file)
@@ -40,6 +40,15 @@ enum regulator_status {
        REGULATOR_STATUS_UNDEFINED,
 };
 
+enum regulator_detection_severity {
+       /* Hardware shut down voltage outputs if condition is detected */
+       REGULATOR_SEVERITY_PROT,
+       /* Hardware is probably damaged/inoperable */
+       REGULATOR_SEVERITY_ERR,
+       /* Hardware is still recoverable but recovery action must be taken */
+       REGULATOR_SEVERITY_WARN,
+};
+
 /* Initialize struct linear_range for regulators */
 #define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV)  \
 {                                                                      \
@@ -78,8 +87,25 @@ enum regulator_status {
  * @get_current_limit: Get the configured limit for a current-limited regulator.
  * @set_input_current_limit: Configure an input limit.
  *
- * @set_over_current_protection: Support capability of automatically shutting
- *                               down when detecting an over current event.
+ * @set_over_current_protection: Support enabling of and setting limits for over
+ *     current situation detection. Detection can be configured for three
+ *     levels of severity.
+ *     REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s).
+ *     REGULATOR_SEVERITY_ERR should indicate that over-current situation is
+ *             caused by an unrecoverable error but HW does not perform
+ *             automatic shut down.
+ *     REGULATOR_SEVERITY_WARN should indicate situation where hardware is
+ *             still believed to not be damaged but that a board sepcific
+ *             recovery action is needed. If lim_uA is 0 the limit should not
+ *             be changed but the detection should just be enabled/disabled as
+ *             is requested.
+ * @set_over_voltage_protection: Support enabling of and setting limits for over
+ *     voltage situation detection. Detection can be configured for same
+ *     severities as over current protection.
+ * @set_under_voltage_protection: Support enabling of and setting limits for
+ *     under situation detection.
+ * @set_thermal_protection: Support enabling of and setting limits for over
+ *     temperature situation detection.
  *
  * @set_active_discharge: Set active discharge enable/disable of regulators.
  *
@@ -143,8 +169,15 @@ struct regulator_ops {
        int (*get_current_limit) (struct regulator_dev *);
 
        int (*set_input_current_limit) (struct regulator_dev *, int lim_uA);
-       int (*set_over_current_protection) (struct regulator_dev *);
-       int (*set_active_discharge) (struct regulator_dev *, bool enable);
+       int (*set_over_current_protection)(struct regulator_dev *, int lim_uA,
+                                          int severity, bool enable);
+       int (*set_over_voltage_protection)(struct regulator_dev *, int lim_uV,
+                                          int severity, bool enable);
+       int (*set_under_voltage_protection)(struct regulator_dev *, int lim_uV,
+                                           int severity, bool enable);
+       int (*set_thermal_protection)(struct regulator_dev *, int lim,
+                                     int severity, bool enable);
+       int (*set_active_discharge)(struct regulator_dev *, bool enable);
 
        /* enable/disable regulator */
        int (*enable) (struct regulator_dev *);
@@ -413,6 +446,128 @@ struct regulator_config {
        struct gpio_desc *ena_gpiod;
 };
 
+/**
+ * struct regulator_err_state - regulator error/notification status
+ *
+ * @rdev:              Regulator which status the struct indicates.
+ * @notifs:            Events which have occurred on the regulator.
+ * @errors:            Errors which are active on the regulator.
+ * @possible_errs:     Errors which can be signaled (by given IRQ).
+ */
+struct regulator_err_state {
+       struct regulator_dev *rdev;
+       unsigned long notifs;
+       unsigned long errors;
+       int possible_errs;
+};
+
+/**
+ * struct regulator_irq_data - regulator error/notification status date
+ *
+ * @states:    Status structs for each of the associated regulators.
+ * @num_states:        Amount of associated regulators.
+ * @data:      Driver data pointer given at regulator_irq_desc.
+ * @opaque:    Value storage for IC driver. Core does not update this. ICs
+ *             may want to store status register value here at map_event and
+ *             compare contents at 'renable' callback to see if new problems
+ *             have been added to status. If that is the case it may be
+ *             desirable to return REGULATOR_ERROR_CLEARED and not
+ *             REGULATOR_ERROR_ON to allow IRQ fire again and to generate
+ *             notifications also for the new issues.
+ *
+ * This structure is passed to 'map_event' and 'renable' callbacks for
+ * reporting regulator status to core.
+ */
+struct regulator_irq_data {
+       struct regulator_err_state *states;
+       int num_states;
+       void *data;
+       long opaque;
+};
+
+/**
+ * struct regulator_irq_desc - notification sender for IRQ based events.
+ *
+ * @name:      The visible name for the IRQ
+ * @fatal_cnt: If this IRQ is used to signal HW damaging condition it may be
+ *             best to shut-down regulator(s) or reboot the SOC if error
+ *             handling is repeatedly failing. If fatal_cnt is given the IRQ
+ *             handling is aborted if it fails for fatal_cnt times and die()
+ *             callback (if populated) or BUG() is called to try to prevent
+ *             further damage.
+ * @reread_ms: The time which is waited before attempting to re-read status
+ *             at the worker if IC reading fails. Immediate re-read is done
+ *             if time is not specified.
+ * @irq_off_ms:        The time which IRQ is kept disabled before re-evaluating the
+ *             status for devices which keep IRQ disabled for duration of the
+ *             error. If this is not given the IRQ is left enabled and renable
+ *             is not called.
+ * @skip_off:  If set to true the IRQ handler will attempt to check if any of
+ *             the associated regulators are enabled prior to taking other
+ *             actions. If no regulators are enabled and this is set to true
+ *             a spurious IRQ is assumed and IRQ_NONE is returned.
+ * @high_prio: Boolean to indicate that high priority WQ should be used.
+ * @data:      Driver private data pointer which will be passed as such to
+ *             the renable, map_event and die callbacks in regulator_irq_data.
+ * @die:       Protection callback. If IC status reading or recovery actions
+ *             fail fatal_cnt times this callback or BUG() is called. This
+ *             callback should implement a final protection attempt like
+ *             disabling the regulator. If protection succeeded this may
+ *             return 0. If anything else is returned the core assumes final
+ *             protection failed and calls BUG() as a last resort.
+ * @map_event: Driver callback to map IRQ status into regulator devices with
+ *             events / errors. NOTE: callback MUST initialize both the
+ *             errors and notifs for all rdevs which it signals having
+ *             active events as core does not clean the map data.
+ *             REGULATOR_FAILED_RETRY can be returned to indicate that the
+ *             status reading from IC failed. If this is repeated for
+ *             fatal_cnt times the core will call die() callback or BUG()
+ *             as a last resort to protect the HW.
+ * @renable:   Optional callback to check status (if HW supports that) before
+ *             re-enabling IRQ. If implemented this should clear the error
+ *             flags so that errors fetched by regulator_get_error_flags()
+ *             are updated. If callback is not implemented then errors are
+ *             assumed to be cleared and IRQ is re-enabled.
+ *             REGULATOR_FAILED_RETRY can be returned to
+ *             indicate that the status reading from IC failed. If this is
+ *             repeated for 'fatal_cnt' times the core will call die()
+ *             callback or BUG() as a last resort to protect the HW.
+ *             Returning zero indicates that the problem in HW has been solved
+ *             and IRQ will be re-enabled. Returning REGULATOR_ERROR_ON
+ *             indicates the error condition is still active and keeps IRQ
+ *             disabled. Please note that returning REGULATOR_ERROR_ON does
+ *             not retrigger evaluating what events are active or resending
+ *             notifications. If this is needed you probably want to return
+ *             zero and allow IRQ to retrigger causing events to be
+ *             re-evaluated and re-sent.
+ *
+ * This structure is used for registering regulator IRQ notification helper.
+ */
+struct regulator_irq_desc {
+       const char *name;
+       int irq_flags;
+       int fatal_cnt;
+       int reread_ms;
+       int irq_off_ms;
+       bool skip_off;
+       bool high_prio;
+       void *data;
+
+       int (*die)(struct regulator_irq_data *rid);
+       int (*map_event)(int irq, struct regulator_irq_data *rid,
+                         unsigned long *dev_mask);
+       int (*renable)(struct regulator_irq_data *rid);
+};
+
+/*
+ * Return values for regulator IRQ helpers.
+ */
+enum {
+       REGULATOR_ERROR_CLEARED,
+       REGULATOR_FAILED_RETRY,
+       REGULATOR_ERROR_ON,
+};
+
 /*
  * struct coupling_desc
  *
@@ -477,6 +632,9 @@ struct regulator_dev {
 
        /* time when this regulator was disabled last time */
        ktime_t last_off;
+       int cached_err;
+       bool use_cached_err;
+       spinlock_t err_lock;
 };
 
 struct regulator_dev *
@@ -491,6 +649,16 @@ void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev);
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
+void *devm_regulator_irq_helper(struct device *dev,
+                               const struct regulator_irq_desc *d, int irq,
+                               int irq_flags, int common_errs,
+                               int *per_rdev_errs, struct regulator_dev **rdev,
+                               int rdev_amount);
+void *regulator_irq_helper(struct device *dev,
+                          const struct regulator_irq_desc *d, int irq,
+                          int irq_flags, int common_errs, int *per_rdev_errs,
+                          struct regulator_dev **rdev, int rdev_amount);
+void regulator_irq_helper_cancel(void **handle);
 
 void *rdev_get_drvdata(struct regulator_dev *rdev);
 struct device *rdev_get_dev(struct regulator_dev *rdev);
@@ -540,6 +708,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev,
 int regulator_get_current_limit_regmap(struct regulator_dev *rdev);
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay);
+int regulator_sync_voltage_rdev(struct regulator_dev *rdev);
 
 /*
  * Helper functions intended to be used by regulator drivers prior registering
@@ -550,4 +719,14 @@ int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc,
 
 int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
                                       unsigned int selector);
+
+#ifdef CONFIG_REGULATOR
+const char *rdev_get_name(struct regulator_dev *rdev);
+#else
+static inline const char *rdev_get_name(struct regulator_dev *rdev)
+{
+       return NULL;
+}
+#endif
+
 #endif
index 8a56f03..68b4a51 100644 (file)
@@ -83,6 +83,14 @@ struct regulator_state {
        bool changeable;
 };
 
+#define REGULATOR_NOTIF_LIMIT_DISABLE -1
+#define REGULATOR_NOTIF_LIMIT_ENABLE -2
+struct notification_limit {
+       int prot;
+       int err;
+       int warn;
+};
+
 /**
  * struct regulation_constraints - regulator operating constraints.
  *
@@ -100,6 +108,11 @@ struct regulator_state {
  * @ilim_uA: Maximum input current.
  * @system_load: Load that isn't captured by any consumer requests.
  *
+ * @over_curr_limits:          Limits for acting on over current.
+ * @over_voltage_limits:       Limits for acting on over voltage.
+ * @under_voltage_limits:      Limits for acting on under voltage.
+ * @temp_limits:               Limits for acting on over temperature.
+
  * @max_spread: Max possible spread between coupled regulators
  * @max_uV_step: Max possible step change in voltage
  * @valid_modes_mask: Mask of modes which may be configured by consumers.
@@ -116,6 +129,11 @@ struct regulator_state {
  * @pull_down: Enable pull down when regulator is disabled.
  * @over_current_protection: Auto disable on over current event.
  *
+ * @over_current_detection: Configure over current limits.
+ * @over_voltage_detection: Configure over voltage limits.
+ * @under_voltage_detection: Configure under voltage limits.
+ * @over_temp_detection: Configure over temperature limits.
+ *
  * @input_uV: Input voltage for regulator when supplied by another regulator.
  *
  * @state_disk: State for regulator when system is suspended in disk mode.
@@ -172,6 +190,10 @@ struct regulation_constraints {
        struct regulator_state state_disk;
        struct regulator_state state_mem;
        struct regulator_state state_standby;
+       struct notification_limit over_curr_limits;
+       struct notification_limit over_voltage_limits;
+       struct notification_limit under_voltage_limits;
+       struct notification_limit temp_limits;
        suspend_state_t initial_state; /* suspend state to set at init */
 
        /* mode to set on startup */
@@ -193,6 +215,10 @@ struct regulation_constraints {
        unsigned soft_start:1;  /* ramp voltage slowly */
        unsigned pull_down:1;   /* pull down resistor when regulator off */
        unsigned over_current_protection:1; /* auto disable on over current */
+       unsigned over_current_detection:1; /* notify on over current */
+       unsigned over_voltage_detection:1; /* notify on over voltage */
+       unsigned under_voltage_detection:1; /* notify on under voltage */
+       unsigned over_temp_detection:1; /* notify on over temperature */
 };
 
 /**
diff --git a/include/linux/regulator/mt6359-regulator.h b/include/linux/regulator/mt6359-regulator.h
new file mode 100644 (file)
index 0000000..6d6e5a5
--- /dev/null
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __LINUX_REGULATOR_MT6359_H
+#define __LINUX_REGULATOR_MT6359_H
+
+enum {
+       MT6359_ID_VS1 = 0,
+       MT6359_ID_VGPU11,
+       MT6359_ID_VMODEM,
+       MT6359_ID_VPU,
+       MT6359_ID_VCORE,
+       MT6359_ID_VS2,
+       MT6359_ID_VPA,
+       MT6359_ID_VPROC2,
+       MT6359_ID_VPROC1,
+       MT6359_ID_VCORE_SSHUB,
+       MT6359_ID_VGPU11_SSHUB = MT6359_ID_VCORE_SSHUB,
+       MT6359_ID_VAUD18 = 10,
+       MT6359_ID_VSIM1,
+       MT6359_ID_VIBR,
+       MT6359_ID_VRF12,
+       MT6359_ID_VUSB,
+       MT6359_ID_VSRAM_PROC2,
+       MT6359_ID_VIO18,
+       MT6359_ID_VCAMIO,
+       MT6359_ID_VCN18,
+       MT6359_ID_VFE28,
+       MT6359_ID_VCN13,
+       MT6359_ID_VCN33_1_BT,
+       MT6359_ID_VCN33_1_WIFI,
+       MT6359_ID_VAUX18,
+       MT6359_ID_VSRAM_OTHERS,
+       MT6359_ID_VEFUSE,
+       MT6359_ID_VXO22,
+       MT6359_ID_VRFCK,
+       MT6359_ID_VBIF28,
+       MT6359_ID_VIO28,
+       MT6359_ID_VEMC,
+       MT6359_ID_VCN33_2_BT,
+       MT6359_ID_VCN33_2_WIFI,
+       MT6359_ID_VA12,
+       MT6359_ID_VA09,
+       MT6359_ID_VRF18,
+       MT6359_ID_VSRAM_MD,
+       MT6359_ID_VUFS,
+       MT6359_ID_VM18,
+       MT6359_ID_VBBCK,
+       MT6359_ID_VSRAM_PROC1,
+       MT6359_ID_VSIM2,
+       MT6359_ID_VSRAM_OTHERS_SSHUB,
+       MT6359_ID_RG_MAX,
+};
+
+#define MT6359_MAX_REGULATOR   MT6359_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6359_H */
index def5c62..8d04e7d 100644 (file)
@@ -91,6 +91,7 @@ enum ttu_flags {
 
        TTU_SPLIT_HUGE_PMD      = 0x4,  /* split huge PMD if any */
        TTU_IGNORE_MLOCK        = 0x8,  /* ignore mlock */
+       TTU_SYNC                = 0x10, /* avoid racy checks with PVMW_SYNC */
        TTU_IGNORE_HWPOISON     = 0x20, /* corrupted page is recoverable */
        TTU_BATCH_FLUSH         = 0x40, /* Batch TLB flushes where possible
                                         * and caller guarantees they will
index 28a98fc..ec8d07d 100644 (file)
@@ -113,11 +113,13 @@ struct task_group;
                                         __TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \
                                         TASK_PARKED)
 
-#define task_is_traced(task)           ((task->state & __TASK_TRACED) != 0)
+#define task_is_running(task)          (READ_ONCE((task)->__state) == TASK_RUNNING)
 
-#define task_is_stopped(task)          ((task->state & __TASK_STOPPED) != 0)
+#define task_is_traced(task)           ((READ_ONCE(task->__state) & __TASK_TRACED) != 0)
 
-#define task_is_stopped_or_traced(task)        ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
+#define task_is_stopped(task)          ((READ_ONCE(task->__state) & __TASK_STOPPED) != 0)
+
+#define task_is_stopped_or_traced(task)        ((READ_ONCE(task->__state) & (__TASK_STOPPED | __TASK_TRACED)) != 0)
 
 #ifdef CONFIG_DEBUG_ATOMIC_SLEEP
 
@@ -132,14 +134,14 @@ struct task_group;
        do {                                                    \
                WARN_ON_ONCE(is_special_task_state(state_value));\
                current->task_state_change = _THIS_IP_;         \
-               current->state = (state_value);                 \
+               WRITE_ONCE(current->__state, (state_value));    \
        } while (0)
 
 #define set_current_state(state_value)                         \
        do {                                                    \
                WARN_ON_ONCE(is_special_task_state(state_value));\
                current->task_state_change = _THIS_IP_;         \
-               smp_store_mb(current->state, (state_value));    \
+               smp_store_mb(current->__state, (state_value));  \
        } while (0)
 
 #define set_special_state(state_value)                                 \
@@ -148,7 +150,7 @@ struct task_group;
                WARN_ON_ONCE(!is_special_task_state(state_value));      \
                raw_spin_lock_irqsave(&current->pi_lock, flags);        \
                current->task_state_change = _THIS_IP_;                 \
-               current->state = (state_value);                         \
+               WRITE_ONCE(current->__state, (state_value));            \
                raw_spin_unlock_irqrestore(&current->pi_lock, flags);   \
        } while (0)
 #else
@@ -190,10 +192,10 @@ struct task_group;
  * Also see the comments of try_to_wake_up().
  */
 #define __set_current_state(state_value)                               \
-       current->state = (state_value)
+       WRITE_ONCE(current->__state, (state_value))
 
 #define set_current_state(state_value)                                 \
-       smp_store_mb(current->state, (state_value))
+       smp_store_mb(current->__state, (state_value))
 
 /*
  * set_special_state() should be used for those states when the blocking task
@@ -205,12 +207,14 @@ struct task_group;
        do {                                                            \
                unsigned long flags; /* may shadow */                   \
                raw_spin_lock_irqsave(&current->pi_lock, flags);        \
-               current->state = (state_value);                         \
+               WRITE_ONCE(current->__state, (state_value));            \
                raw_spin_unlock_irqrestore(&current->pi_lock, flags);   \
        } while (0)
 
 #endif
 
+#define get_current_state()    READ_ONCE(current->__state)
+
 /* Task command name length: */
 #define TASK_COMM_LEN                  16
 
@@ -662,8 +666,7 @@ struct task_struct {
         */
        struct thread_info              thread_info;
 #endif
-       /* -1 unrunnable, 0 runnable, >0 stopped: */
-       volatile long                   state;
+       unsigned int                    __state;
 
        /*
         * This begins the randomizable portion of task_struct. Only
@@ -708,10 +711,17 @@ struct task_struct {
        const struct sched_class        *sched_class;
        struct sched_entity             se;
        struct sched_rt_entity          rt;
+       struct sched_dl_entity          dl;
+
+#ifdef CONFIG_SCHED_CORE
+       struct rb_node                  core_node;
+       unsigned long                   core_cookie;
+       unsigned int                    core_occupation;
+#endif
+
 #ifdef CONFIG_CGROUP_SCHED
        struct task_group               *sched_task_group;
 #endif
-       struct sched_dl_entity          dl;
 
 #ifdef CONFIG_UCLAMP_TASK
        /*
@@ -997,7 +1007,6 @@ struct task_struct {
        /* Signal handlers: */
        struct signal_struct            *signal;
        struct sighand_struct __rcu             *sighand;
-       struct sigqueue                 *sigqueue_cache;
        sigset_t                        blocked;
        sigset_t                        real_blocked;
        /* Restored if set_restore_sigmask() was used: */
@@ -1521,7 +1530,7 @@ static inline pid_t task_pgrp_nr(struct task_struct *tsk)
 
 static inline unsigned int task_state_index(struct task_struct *tsk)
 {
-       unsigned int tsk_state = READ_ONCE(tsk->state);
+       unsigned int tsk_state = READ_ONCE(tsk->__state);
        unsigned int state = (tsk_state | tsk->exit_state) & TASK_REPORT;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(TASK_REPORT_MAX);
@@ -1829,10 +1838,10 @@ static __always_inline void scheduler_ipi(void)
         */
        preempt_fold_need_resched();
 }
-extern unsigned long wait_task_inactive(struct task_struct *, long match_state);
+extern unsigned long wait_task_inactive(struct task_struct *, unsigned int match_state);
 #else
 static inline void scheduler_ipi(void) { }
-static inline unsigned long wait_task_inactive(struct task_struct *p, long match_state)
+static inline unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
 {
        return 1;
 }
@@ -2019,6 +2028,8 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
 
 #endif /* CONFIG_SMP */
 
+extern bool sched_task_on_rq(struct task_struct *p);
+
 /*
  * In order to reduce various lock holder preemption latencies provide an
  * interface to see if a vCPU is currently running or not.
@@ -2180,4 +2191,14 @@ int sched_trace_rq_nr_running(struct rq *rq);
 
 const struct cpumask *sched_trace_rd_span(struct root_domain *rd);
 
+#ifdef CONFIG_SCHED_CORE
+extern void sched_core_free(struct task_struct *tsk);
+extern void sched_core_fork(struct task_struct *p);
+extern int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type,
+                               unsigned long uaddr);
+#else
+static inline void sched_core_free(struct task_struct *tsk) { }
+static inline void sched_core_fork(struct task_struct *p) { }
+#endif
+
 #endif
index 6205578..bdd31ab 100644 (file)
@@ -26,7 +26,7 @@ bool cpufreq_this_cpu_can_update(struct cpufreq_policy *policy);
 static inline unsigned long map_util_freq(unsigned long util,
                                        unsigned long freq, unsigned long cap)
 {
-       return (freq + (freq >> 2)) * util / cap;
+       return freq * util / cap;
 }
 
 static inline unsigned long map_util_perf(unsigned long util)
index ae51f45..b5035af 100644 (file)
@@ -14,7 +14,7 @@ extern void dump_cpu_task(int cpu);
 /*
  * Only dump TASK_* tasks. (0 for all tasks)
  */
-extern void show_state_filter(unsigned long state_filter);
+extern void show_state_filter(unsigned int state_filter);
 
 static inline void show_state(void)
 {
index 34b21e9..57bde66 100644 (file)
@@ -91,6 +91,16 @@ SD_FLAG(SD_WAKE_AFFINE, SDF_SHARED_CHILD)
 SD_FLAG(SD_ASYM_CPUCAPACITY, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
 
 /*
+ * Domain members have different CPU capacities spanning all unique CPU
+ * capacity values.
+ *
+ * SHARED_PARENT: Set from the topmost domain down to the first domain where
+ *               all available CPU capacities are visible
+ * NEEDS_GROUPS: Per-CPU capacity is asymmetric between groups.
+ */
+SD_FLAG(SD_ASYM_CPUCAPACITY_FULL, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
+
+/*
  * Domain members share CPU capacity (i.e. SMT)
  *
  * SHARED_CHILD: Set from the base domain up until spanned CPUs no longer share
index 7f4278f..c9cf678 100644 (file)
@@ -382,7 +382,7 @@ static inline int fatal_signal_pending(struct task_struct *p)
        return task_sigpending(p) && __fatal_signal_pending(p);
 }
 
-static inline int signal_pending_state(long state, struct task_struct *p)
+static inline int signal_pending_state(unsigned int state, struct task_struct *p)
 {
        if (!(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL)))
                return 0;
index 5682864..0108a38 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_SCHED_STAT_H
 
 #include <linux/percpu.h>
+#include <linux/kconfig.h>
 
 /*
  * Various counters maintained by the scheduler and fork(),
@@ -16,21 +17,14 @@ extern unsigned long total_forks;
 extern int nr_threads;
 DECLARE_PER_CPU(unsigned long, process_counts);
 extern int nr_processes(void);
-extern unsigned long nr_running(void);
+extern unsigned int nr_running(void);
 extern bool single_task_running(void);
-extern unsigned long nr_iowait(void);
-extern unsigned long nr_iowait_cpu(int cpu);
+extern unsigned int nr_iowait(void);
+extern unsigned int nr_iowait_cpu(int cpu);
 
 static inline int sched_info_on(void)
 {
-#ifdef CONFIG_SCHEDSTATS
-       return 1;
-#elif defined(CONFIG_TASK_DELAY_ACCT)
-       extern int delayacct_on;
-       return delayacct_on;
-#else
-       return 0;
-#endif
+       return IS_ENABLED(CONFIG_SCHED_INFO);
 }
 
 #ifdef CONFIG_SCHEDSTATS
index 3632c5d..2462f7d 100644 (file)
  */
 struct user_struct {
        refcount_t __count;     /* reference count */
-       atomic_t processes;     /* How many processes does this user have? */
-       atomic_t sigpending;    /* How many pending signals does this user have? */
 #ifdef CONFIG_EPOLL
        atomic_long_t epoll_watches; /* The number of file descriptors currently watched */
 #endif
-#ifdef CONFIG_POSIX_MQUEUE
-       /* protected by mq_lock */
-       unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
-#endif
-       unsigned long locked_shm; /* How many pages of mlocked shm ? */
        unsigned long unix_inflight;    /* How many files in flight in unix sockets */
        atomic_long_t pipe_bufs;  /* how many pages are allocated in pipe buffers */
 
index 528718e..835ee87 100644 (file)
@@ -14,7 +14,7 @@
  * @sched_clock_mask:   Bitmask for two's complement subtraction of non 64bit
  *                     clocks.
  * @read_sched_clock:  Current clock source (or dummy source when suspended).
- * @mult:              Multipler for scaled math conversion.
+ * @mult:              Multiplier for scaled math conversion.
  * @shift:             Shift value for scaled math conversion.
  *
  * Care must be taken when updating this structure; it is read by
index f61e34f..37ded6b 100644 (file)
@@ -182,9 +182,9 @@ static inline void seqcount_lockdep_reader_access(const seqcount_t *s)
 
 #define seqcount_raw_spinlock_init(s, lock)    seqcount_LOCKNAME_init(s, lock, raw_spinlock)
 #define seqcount_spinlock_init(s, lock)                seqcount_LOCKNAME_init(s, lock, spinlock)
-#define seqcount_rwlock_init(s, lock)          seqcount_LOCKNAME_init(s, lock, rwlock);
-#define seqcount_mutex_init(s, lock)           seqcount_LOCKNAME_init(s, lock, mutex);
-#define seqcount_ww_mutex_init(s, lock)                seqcount_LOCKNAME_init(s, lock, ww_mutex);
+#define seqcount_rwlock_init(s, lock)          seqcount_LOCKNAME_init(s, lock, rwlock)
+#define seqcount_mutex_init(s, lock)           seqcount_LOCKNAME_init(s, lock, mutex)
+#define seqcount_ww_mutex_init(s, lock)                seqcount_LOCKNAME_init(s, lock, ww_mutex)
 
 /*
  * SEQCOUNT_LOCKNAME() - Instantiate seqcount_LOCKNAME_t and helpers
index d82b6f3..aa77dcd 100644 (file)
@@ -65,7 +65,7 @@ extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
 extern int shmem_zero_setup(struct vm_area_struct *);
 extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
                unsigned long len, unsigned long pgoff, unsigned long flags);
-extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
+extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
 #ifdef CONFIG_SHMEM
 extern const struct address_space_operations shmem_aops;
 static inline bool shmem_mapping(struct address_space *mapping)
index 201f88e..5160fd4 100644 (file)
@@ -267,7 +267,6 @@ static inline void init_sigpending(struct sigpending *sig)
 }
 
 extern void flush_sigqueue(struct sigpending *queue);
-extern void exit_task_sigqueue_cache(struct task_struct *tsk);
 
 /* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
 static inline int valid_signal(unsigned long sig)
index 68e06c7..34cb28b 100644 (file)
@@ -13,6 +13,8 @@ typedef struct kernel_siginfo {
        __SIGINFO;
 } kernel_siginfo_t;
 
+struct ucounts;
+
 /*
  * Real Time signals may be queued.
  */
@@ -21,7 +23,7 @@ struct sigqueue {
        struct list_head list;
        int flags;
        kernel_siginfo_t info;
-       struct user_struct *user;
+       struct ucounts *ucounts;
 };
 
 /* flags values. */
index b8fc5c5..0d8e3dc 100644 (file)
@@ -438,6 +438,4 @@ extern int __sys_socketpair(int family, int type, int protocol,
                            int __user *usockvec);
 extern int __sys_shutdown_sock(struct socket *sock, int how);
 extern int __sys_shutdown(int fd, int how);
-
-extern struct ns_common *get_net_ns(struct ns_common *ns);
 #endif /* _LINUX_SOCKET_H */
index 31f00c7..eaab121 100644 (file)
@@ -2,8 +2,10 @@
 /*
  * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
  */
-#ifndef __linux_pxa2xx_spi_h
-#define __linux_pxa2xx_spi_h
+#ifndef __LINUX_SPI_PXA2XX_SPI_H
+#define __LINUX_SPI_PXA2XX_SPI_H
+
+#include <linux/types.h>
 
 #include <linux/pxa2xx_ssp.h>
 
 
 struct dma_chan;
 
-/* device.platform_data for SSP controller devices */
+/*
+ * The platform data for SSP controller devices
+ * (resides in device.platform_data).
+ */
 struct pxa2xx_spi_controller {
        u16 num_chipselect;
        u8 enable_dma;
@@ -28,8 +33,11 @@ struct pxa2xx_spi_controller {
        struct ssp_device ssp;
 };
 
-/* spi_board_info.controller_data for SPI slave devices,
- * copied to spi_device.platform_data ... mostly for dma tuning
+/*
+ * The controller specific data for SPI slave devices
+ * (resides in spi_board_info.controller_data),
+ * copied to spi_device.platform_data ... mostly for
+ * DMA tuning.
  */
 struct pxa2xx_spi_chip {
        u8 tx_threshold;
@@ -49,4 +57,5 @@ struct pxa2xx_spi_chip {
 extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info);
 
 #endif
-#endif
+
+#endif /* __LINUX_SPI_PXA2XX_SPI_H */
index 2b65c9e..85e2ff7 100644 (file)
@@ -250,6 +250,9 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
  *               the currently mapped area), and the caller of
  *               spi_mem_dirmap_write() is responsible for calling it again in
  *               this case.
+ * @poll_status: poll memory device status until (status & mask) == match or
+ *               when the timeout has expired. It fills the data buffer with
+ *               the last status value.
  *
  * This interface should be implemented by SPI controllers providing an
  * high-level interface to execute SPI memory operation, which is usually the
@@ -274,6 +277,12 @@ struct spi_controller_mem_ops {
                               u64 offs, size_t len, void *buf);
        ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc,
                                u64 offs, size_t len, const void *buf);
+       int (*poll_status)(struct spi_mem *mem,
+                          const struct spi_mem_op *op,
+                          u16 mask, u16 match,
+                          unsigned long initial_delay_us,
+                          unsigned long polling_rate_us,
+                          unsigned long timeout_ms);
 };
 
 /**
@@ -369,6 +378,13 @@ devm_spi_mem_dirmap_create(struct device *dev, struct spi_mem *mem,
 void devm_spi_mem_dirmap_destroy(struct device *dev,
                                 struct spi_mem_dirmap_desc *desc);
 
+int spi_mem_poll_status(struct spi_mem *mem,
+                       const struct spi_mem_op *op,
+                       u16 mask, u16 match,
+                       unsigned long initial_delay_us,
+                       unsigned long polling_delay_us,
+                       u16 timeout_ms);
+
 int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
                                       struct module *owner);
 
index 74239d6..97b8d12 100644 (file)
@@ -299,6 +299,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
                driver_unregister(&sdrv->driver);
 }
 
+extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
+
 /* use a define to avoid include chaining to get THIS_MODULE */
 #define spi_register_driver(driver) \
        __spi_register_driver(THIS_MODULE, driver)
@@ -586,6 +588,7 @@ struct spi_controller {
        bool                    (*can_dma)(struct spi_controller *ctlr,
                                           struct spi_device *spi,
                                           struct spi_transfer *xfer);
+       struct device *dma_map_dev;
 
        /*
         * These hooks are for drivers that want to use the generic
@@ -1108,11 +1111,6 @@ static inline void spi_message_free(struct spi_message *m)
        kfree(m);
 }
 
-extern int spi_set_cs_timing(struct spi_device *spi,
-                            struct spi_delay *setup,
-                            struct spi_delay *hold,
-                            struct spi_delay *inactive);
-
 extern int spi_setup(struct spi_device *spi);
 extern int spi_async(struct spi_device *spi, struct spi_message *message);
 extern int spi_async_locked(struct spi_device *spi,
index d9b7c91..6430a94 100644 (file)
 #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
 #define SWP_OFFSET_MASK        ((1UL << SWP_TYPE_SHIFT) - 1)
 
+/* Clear all flags but only keep swp_entry_t related information */
+static inline pte_t pte_swp_clear_flags(pte_t pte)
+{
+       if (pte_swp_soft_dirty(pte))
+               pte = pte_swp_clear_soft_dirty(pte);
+       if (pte_swp_uffd_wp(pte))
+               pte = pte_swp_clear_uffd_wp(pte);
+       return pte;
+}
+
 /*
  * Store a type+offset into a swp_entry_t in an arch-independent format
  */
@@ -66,10 +76,7 @@ static inline swp_entry_t pte_to_swp_entry(pte_t pte)
 {
        swp_entry_t arch_entry;
 
-       if (pte_swp_soft_dirty(pte))
-               pte = pte_swp_clear_soft_dirty(pte);
-       if (pte_swp_uffd_wp(pte))
-               pte = pte_swp_clear_uffd_wp(pte);
+       pte = pte_swp_clear_flags(pte);
        arch_entry = __pte_to_swp_entry(pte);
        return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
 }
index 1a0ff88..bfd571f 100644 (file)
@@ -186,13 +186,17 @@ static inline bool tick_nohz_full_enabled(void)
        return tick_nohz_full_running;
 }
 
-static inline bool tick_nohz_full_cpu(int cpu)
-{
-       if (!tick_nohz_full_enabled())
-               return false;
-
-       return cpumask_test_cpu(cpu, tick_nohz_full_mask);
-}
+/*
+ * Check if a CPU is part of the nohz_full subset. Arrange for evaluating
+ * the cpu expression (typically smp_processor_id()) _after_ the static
+ * key.
+ */
+#define tick_nohz_full_cpu(_cpu) ({                                    \
+       bool __ret = false;                                             \
+       if (tick_nohz_full_enabled())                                   \
+               __ret = cpumask_test_cpu((_cpu), tick_nohz_full_mask);  \
+       __ret;                                                          \
+})
 
 static inline void tick_nohz_full_add_cpus_to(struct cpumask *mask)
 {
@@ -208,7 +212,7 @@ extern void tick_nohz_dep_set_task(struct task_struct *tsk,
                                   enum tick_dep_bits bit);
 extern void tick_nohz_dep_clear_task(struct task_struct *tsk,
                                     enum tick_dep_bits bit);
-extern void tick_nohz_dep_set_signal(struct signal_struct *signal,
+extern void tick_nohz_dep_set_signal(struct task_struct *tsk,
                                     enum tick_dep_bits bit);
 extern void tick_nohz_dep_clear_signal(struct signal_struct *signal,
                                       enum tick_dep_bits bit);
@@ -253,11 +257,11 @@ static inline void tick_dep_clear_task(struct task_struct *tsk,
        if (tick_nohz_full_enabled())
                tick_nohz_dep_clear_task(tsk, bit);
 }
-static inline void tick_dep_set_signal(struct signal_struct *signal,
+static inline void tick_dep_set_signal(struct task_struct *tsk,
                                       enum tick_dep_bits bit)
 {
        if (tick_nohz_full_enabled())
-               tick_nohz_dep_set_signal(signal, bit);
+               tick_nohz_dep_set_signal(tsk, bit);
 }
 static inline void tick_dep_clear_signal(struct signal_struct *signal,
                                         enum tick_dep_bits bit)
@@ -285,7 +289,7 @@ static inline void tick_dep_set_task(struct task_struct *tsk,
                                     enum tick_dep_bits bit) { }
 static inline void tick_dep_clear_task(struct task_struct *tsk,
                                       enum tick_dep_bits bit) { }
-static inline void tick_dep_set_signal(struct signal_struct *signal,
+static inline void tick_dep_set_signal(struct task_struct *tsk,
                                       enum tick_dep_bits bit) { }
 static inline void tick_dep_clear_signal(struct signal_struct *signal,
                                         enum tick_dep_bits bit) { }
index 1d08dbb..eb70cab 100644 (file)
@@ -54,9 +54,15 @@ enum ucount_type {
        UCOUNT_FANOTIFY_GROUPS,
        UCOUNT_FANOTIFY_MARKS,
 #endif
+       UCOUNT_RLIMIT_NPROC,
+       UCOUNT_RLIMIT_MSGQUEUE,
+       UCOUNT_RLIMIT_SIGPENDING,
+       UCOUNT_RLIMIT_MEMLOCK,
        UCOUNT_COUNTS,
 };
 
+#define MAX_PER_NAMESPACE_UCOUNTS UCOUNT_RLIMIT_NPROC
+
 struct user_namespace {
        struct uid_gid_map      uid_map;
        struct uid_gid_map      gid_map;
@@ -92,23 +98,42 @@ struct user_namespace {
        struct ctl_table_header *sysctls;
 #endif
        struct ucounts          *ucounts;
-       int ucount_max[UCOUNT_COUNTS];
+       long ucount_max[UCOUNT_COUNTS];
 } __randomize_layout;
 
 struct ucounts {
        struct hlist_node node;
        struct user_namespace *ns;
        kuid_t uid;
-       int count;
-       atomic_t ucount[UCOUNT_COUNTS];
+       atomic_t count;
+       atomic_long_t ucount[UCOUNT_COUNTS];
 };
 
 extern struct user_namespace init_user_ns;
+extern struct ucounts init_ucounts;
 
 bool setup_userns_sysctls(struct user_namespace *ns);
 void retire_userns_sysctls(struct user_namespace *ns);
 struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
 void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
+struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
+struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
+void put_ucounts(struct ucounts *ucounts);
+
+static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type type)
+{
+       return atomic_long_read(&ucounts->ucount[type]);
+}
+
+long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
+bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
+bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
+
+static inline void set_rlimit_ucount_max(struct user_namespace *ns,
+               enum ucount_type type, unsigned long max)
+{
+       ns->ucount_max[type] = max <= LONG_MAX ? max : LONG_MAX;
+}
 
 #ifdef CONFIG_USER_NS
 
index 4d668ab..bfaaf0b 100644 (file)
@@ -135,6 +135,7 @@ extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
                        const void *caller);
 void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask,
                int node, const void *caller);
+void *vmalloc_no_huge(unsigned long size);
 
 extern void vfree(const void *addr);
 extern void vfree_atomic(const void *addr);
index b4cb2ef..53c0038 100644 (file)
@@ -19,6 +19,7 @@
 #define V4L2_CID_MPEG_VIDEO_HEVC_SPS           (V4L2_CID_CODEC_BASE + 1008)
 #define V4L2_CID_MPEG_VIDEO_HEVC_PPS           (V4L2_CID_CODEC_BASE + 1009)
 #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS  (V4L2_CID_CODEC_BASE + 1010)
+#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012)
 #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE   (V4L2_CID_CODEC_BASE + 1015)
 #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE    (V4L2_CID_CODEC_BASE + 1016)
 
@@ -26,6 +27,7 @@
 #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
 #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
 #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
+#define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124
 
 enum v4l2_mpeg_video_hevc_decode_mode {
        V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
@@ -75,13 +77,12 @@ struct v4l2_ctrl_hevc_sps {
        __u8    num_short_term_ref_pic_sets;
        __u8    num_long_term_ref_pics_sps;
        __u8    chroma_format_idc;
-
-       __u8    padding;
+       __u8    sps_max_sub_layers_minus1;
 
        __u64   flags;
 };
 
-#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT             (1ULL << 0)
+#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED     (1ULL << 0)
 #define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT                 (1ULL << 1)
 #define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED            (1ULL << 2)
 #define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT                  (1ULL << 3)
@@ -100,10 +101,14 @@ struct v4l2_ctrl_hevc_sps {
 #define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER       (1ULL << 16)
 #define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT          (1ULL << 17)
 #define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18)
+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT   (1ULL << 19)
+#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING                     (1ULL << 20)
 
 struct v4l2_ctrl_hevc_pps {
        /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */
        __u8    num_extra_slice_header_bits;
+       __u8    num_ref_idx_l0_default_active_minus1;
+       __u8    num_ref_idx_l1_default_active_minus1;
        __s8    init_qp_minus26;
        __u8    diff_cu_qp_delta_depth;
        __s8    pps_cb_qp_offset;
@@ -160,6 +165,7 @@ struct v4l2_hevc_pred_weight_table {
 #define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV             (1ULL << 6)
 #define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7)
 #define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT    (1ULL << 9)
 
 struct v4l2_ctrl_hevc_slice_params {
        __u32   bit_size;
@@ -190,18 +196,10 @@ struct v4l2_ctrl_hevc_slice_params {
        __u8    pic_struct;
 
        /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-       __u8    num_active_dpb_entries;
        __u8    ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
        __u8    ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
 
-       __u8    num_rps_poc_st_curr_before;
-       __u8    num_rps_poc_st_curr_after;
-       __u8    num_rps_poc_lt_curr;
-
-       __u8    padding;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-       struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    padding[5];
 
        /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */
        struct v4l2_hevc_pred_weight_table pred_weight_table;
@@ -209,4 +207,34 @@ struct v4l2_ctrl_hevc_slice_params {
        __u64   flags;
 };
 
+#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC           0x1
+#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC            0x2
+#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR  0x4
+
+struct v4l2_ctrl_hevc_decode_params {
+       __s32   pic_order_cnt_val;
+       __u8    num_active_dpb_entries;
+       struct  v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    num_poc_st_curr_before;
+       __u8    num_poc_st_curr_after;
+       __u8    num_poc_lt_curr;
+       __u8    poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u64   flags;
+};
+
+/*  MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */
+#define V4L2_CID_CODEC_HANTRO_BASE                             (V4L2_CTRL_CLASS_CODEC | 0x1200)
+/*
+ * V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP -
+ * the number of data (in bits) to skip in the
+ * slice segment header.
+ * If non-IDR, the bits to be skipped go from syntax element "pic_output_flag"
+ * to before syntax element "slice_temporal_mvp_enabled_flag".
+ * If IDR, the skipped bits are just "pic_output_flag"
+ * (separate_colour_plane_flag is not supported).
+ */
+#define V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (V4L2_CID_CODEC_HANTRO_BASE + 0)
+
 #endif
index b35ea60..2ab54d4 100644 (file)
@@ -19,7 +19,7 @@
 
 struct usb_device;
 
-#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_USB)
+#if defined(CONFIG_MEDIA_CONTROLLER) && IS_ENABLED(CONFIG_USB)
 /**
  * media_device_usb_allocate() - Allocate and return struct &media device
  *
diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h
deleted file mode 100644 (file)
index 2a4ae67..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * These are the MPEG2 state controls for use with stateless MPEG-2
- * codec drivers.
- *
- * It turns out that these structs are not stable yet and will undergo
- * more changes. So keep them private until they are stable and ready to
- * become part of the official public API.
- */
-
-#ifndef _MPEG2_CTRLS_H_
-#define _MPEG2_CTRLS_H_
-
-#define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS         (V4L2_CID_CODEC_BASE+250)
-#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION         (V4L2_CID_CODEC_BASE+251)
-
-/* enum v4l2_ctrl_type type values */
-#define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0103
-#define        V4L2_CTRL_TYPE_MPEG2_QUANTIZATION 0x0104
-
-#define V4L2_MPEG2_PICTURE_CODING_TYPE_I       1
-#define V4L2_MPEG2_PICTURE_CODING_TYPE_P       2
-#define V4L2_MPEG2_PICTURE_CODING_TYPE_B       3
-#define V4L2_MPEG2_PICTURE_CODING_TYPE_D       4
-
-struct v4l2_mpeg2_sequence {
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */
-       __u16   horizontal_size;
-       __u16   vertical_size;
-       __u32   vbv_buffer_size;
-
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */
-       __u16   profile_and_level_indication;
-       __u8    progressive_sequence;
-       __u8    chroma_format;
-};
-
-struct v4l2_mpeg2_picture {
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */
-       __u8    picture_coding_type;
-
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture coding extension */
-       __u8    f_code[2][2];
-       __u8    intra_dc_precision;
-       __u8    picture_structure;
-       __u8    top_field_first;
-       __u8    frame_pred_frame_dct;
-       __u8    concealment_motion_vectors;
-       __u8    q_scale_type;
-       __u8    intra_vlc_format;
-       __u8    alternate_scan;
-       __u8    repeat_first_field;
-       __u16   progressive_frame;
-};
-
-struct v4l2_ctrl_mpeg2_slice_params {
-       __u32   bit_size;
-       __u32   data_bit_offset;
-       __u64   backward_ref_ts;
-       __u64   forward_ref_ts;
-
-       struct v4l2_mpeg2_sequence sequence;
-       struct v4l2_mpeg2_picture picture;
-
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Slice */
-       __u32   quantiser_scale_code;
-};
-
-struct v4l2_ctrl_mpeg2_quantization {
-       /* ISO/IEC 13818-2, ITU-T Rec. H.262: Quant matrix extension */
-       __u8    load_intra_quantiser_matrix;
-       __u8    load_non_intra_quantiser_matrix;
-       __u8    load_chroma_intra_quantiser_matrix;
-       __u8    load_chroma_non_intra_quantiser_matrix;
-
-       __u8    intra_quantiser_matrix[64];
-       __u8    non_intra_quantiser_matrix[64];
-       __u8    chroma_intra_quantiser_matrix[64];
-       __u8    chroma_non_intra_quantiser_matrix[64];
-};
-
-#endif
index b5585d1..793b543 100644 (file)
@@ -231,6 +231,7 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_CEC                       "rc-cec"
 #define RC_MAP_CINERGY                   "rc-cinergy"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
+#define RC_MAP_CT_90405                  "rc-ct-90405"
 #define RC_MAP_D680_DMB                  "rc-d680-dmb"
 #define RC_MAP_DELOCK_61959              "rc-delock-61959"
 #define RC_MAP_DIB0700_NEC_TABLE         "rc-dib0700-nec"
@@ -312,7 +313,6 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_SNAPSTREAM_FIREFLY        "rc-snapstream-firefly"
 #define RC_MAP_STREAMZAP                 "rc-streamzap"
 #define RC_MAP_SU3000                    "rc-su3000"
-#define RC_MAP_TANGO                     "rc-tango"
 #define RC_MAP_TANIX_TX3MINI             "rc-tanix-tx3mini"
 #define RC_MAP_TANIX_TX5MAX              "rc-tanix-tx5max"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
index a5953b8..575b59f 100644 (file)
@@ -17,7 +17,6 @@
  * Include the stateless codec compound control definitions.
  * This will move to the public headers once this API is fully stable.
  */
-#include <media/mpeg2-ctrls.h>
 #include <media/hevc-ctrls.h>
 
 /* forward references */
@@ -40,8 +39,9 @@ struct video_device;
  * @p_u16:                     Pointer to a 16-bit unsigned value.
  * @p_u32:                     Pointer to a 32-bit unsigned value.
  * @p_char:                    Pointer to a string.
- * @p_mpeg2_slice_params:      Pointer to a MPEG2 slice parameters structure.
- * @p_mpeg2_quantization:      Pointer to a MPEG2 quantization data structure.
+ * @p_mpeg2_sequence:          Pointer to a MPEG2 sequence structure.
+ * @p_mpeg2_picture:           Pointer to a MPEG2 picture structure.
+ * @p_mpeg2_quantisation:      Pointer to a MPEG2 quantisation data structure.
  * @p_fwht_params:             Pointer to a FWHT stateless parameters structure.
  * @p_h264_sps:                        Pointer to a struct v4l2_ctrl_h264_sps.
  * @p_h264_pps:                        Pointer to a struct v4l2_ctrl_h264_pps.
@@ -66,8 +66,9 @@ union v4l2_ctrl_ptr {
        u16 *p_u16;
        u32 *p_u32;
        char *p_char;
-       struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
-       struct v4l2_ctrl_mpeg2_quantization *p_mpeg2_quantization;
+       struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
+       struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
+       struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quantisation;
        struct v4l2_ctrl_fwht_params *p_fwht_params;
        struct v4l2_ctrl_h264_sps *p_h264_sps;
        struct v4l2_ctrl_h264_pps *p_h264_pps;
index d0e9a5b..95f8bfd 100644 (file)
@@ -162,6 +162,9 @@ struct v4l2_subdev_io_pin_config {
  * @s_gpio: set GPIO pins. Very simple right now, might need to be extended with
  *     a direction argument if needed.
  *
+ * @command: called by in-kernel drivers in order to call functions internal
+ *        to subdev drivers driver that have a separate callback.
+ *
  * @ioctl: called at the end of ioctl() syscall handler at the V4L2 core.
  *        used to provide support for private ioctls used on the driver.
  *
@@ -193,6 +196,7 @@ struct v4l2_subdev_core_ops {
        int (*load_fw)(struct v4l2_subdev *sd);
        int (*reset)(struct v4l2_subdev *sd, u32 val);
        int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
+       long (*command)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
        long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
 #ifdef CONFIG_COMPAT
        long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd,
@@ -624,6 +628,19 @@ struct v4l2_subdev_pad_config {
 };
 
 /**
+ * struct v4l2_subdev_state - Used for storing subdev state information.
+ *
+ * @pads: &struct v4l2_subdev_pad_config array
+ *
+ * This structure only needs to be passed to the pad op if the 'which' field
+ * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For
+ * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL.
+ */
+struct v4l2_subdev_state {
+       struct v4l2_subdev_pad_config *pads;
+};
+
+/**
  * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations
  *
  * @init_cfg: initialize the pad config to default values
@@ -687,27 +704,27 @@ struct v4l2_subdev_pad_config {
  */
 struct v4l2_subdev_pad_ops {
        int (*init_cfg)(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_pad_config *cfg);
+                       struct v4l2_subdev_state *state);
        int (*enum_mbus_code)(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *state,
                              struct v4l2_subdev_mbus_code_enum *code);
        int (*enum_frame_size)(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *state,
                               struct v4l2_subdev_frame_size_enum *fse);
        int (*enum_frame_interval)(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *state,
                                   struct v4l2_subdev_frame_interval_enum *fie);
        int (*get_fmt)(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *state,
                       struct v4l2_subdev_format *format);
        int (*set_fmt)(struct v4l2_subdev *sd,
-                      struct v4l2_subdev_pad_config *cfg,
+                      struct v4l2_subdev_state *state,
                       struct v4l2_subdev_format *format);
        int (*get_selection)(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *state,
                             struct v4l2_subdev_selection *sel);
        int (*set_selection)(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *state,
                             struct v4l2_subdev_selection *sel);
        int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
        int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
@@ -918,14 +935,14 @@ struct v4l2_subdev {
  * struct v4l2_subdev_fh - Used for storing subdev information per file handle
  *
  * @vfh: pointer to &struct v4l2_fh
- * @pad: pointer to &struct v4l2_subdev_pad_config
+ * @state: pointer to &struct v4l2_subdev_state
  * @owner: module pointer to the owner of this file handle
  */
 struct v4l2_subdev_fh {
        struct v4l2_fh vfh;
        struct module *owner;
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-       struct v4l2_subdev_pad_config *pad;
+       struct v4l2_subdev_state *state;
 #endif
 };
 
@@ -945,17 +962,17 @@ struct v4l2_subdev_fh {
  *     &struct v4l2_subdev_pad_config->try_fmt
  *
  * @sd: pointer to &struct v4l2_subdev
- * @cfg: pointer to &struct v4l2_subdev_pad_config array.
- * @pad: index of the pad in the @cfg array.
+ * @state: pointer to &struct v4l2_subdev_state
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array
  */
 static inline struct v4l2_mbus_framefmt *
 v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_state *state,
                           unsigned int pad)
 {
        if (WARN_ON(pad >= sd->entity.num_pads))
                pad = 0;
-       return &cfg[pad].try_fmt;
+       return &state->pads[pad].try_fmt;
 }
 
 /**
@@ -963,17 +980,17 @@ v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
  *     &struct v4l2_subdev_pad_config->try_crop
  *
  * @sd: pointer to &struct v4l2_subdev
- * @cfg: pointer to &struct v4l2_subdev_pad_config array.
- * @pad: index of the pad in the @cfg array.
+ * @state: pointer to &struct v4l2_subdev_state.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
  */
 static inline struct v4l2_rect *
 v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *state,
                         unsigned int pad)
 {
        if (WARN_ON(pad >= sd->entity.num_pads))
                pad = 0;
-       return &cfg[pad].try_crop;
+       return &state->pads[pad].try_crop;
 }
 
 /**
@@ -981,17 +998,17 @@ v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
  *     &struct v4l2_subdev_pad_config->try_compose
  *
  * @sd: pointer to &struct v4l2_subdev
- * @cfg: pointer to &struct v4l2_subdev_pad_config array.
- * @pad: index of the pad in the @cfg array.
+ * @state: pointer to &struct v4l2_subdev_state.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
  */
 static inline struct v4l2_rect *
 v4l2_subdev_get_try_compose(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *state,
                            unsigned int pad)
 {
        if (WARN_ON(pad >= sd->entity.num_pads))
                pad = 0;
-       return &cfg[pad].try_compose;
+       return &state->pads[pad].try_compose;
 }
 
 #endif
@@ -1093,20 +1110,21 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
 int v4l2_subdev_link_validate(struct media_link *link);
 
 /**
- * v4l2_subdev_alloc_pad_config - Allocates memory for pad config
+ * v4l2_subdev_alloc_state - allocate v4l2_subdev_state
+ *
+ * @sd: pointer to &struct v4l2_subdev for which the state is being allocated.
  *
- * @sd: pointer to struct v4l2_subdev
+ * Must call v4l2_subdev_free_state() when state is no longer needed.
  */
-struct
-v4l2_subdev_pad_config *v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd);
+struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd);
 
 /**
- * v4l2_subdev_free_pad_config - Frees memory allocated by
- *     v4l2_subdev_alloc_pad_config().
+ * v4l2_subdev_free_state - free a v4l2_subdev_state
  *
- * @cfg: pointer to &struct v4l2_subdev_pad_config
+ * @state: v4l2_subdev_state to be freed.
  */
-void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg);
+void v4l2_subdev_free_state(struct v4l2_subdev_state *state);
+
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 /**
index c203047..b66585e 100644 (file)
@@ -262,6 +262,22 @@ int __must_check vb2_queue_init_name(struct vb2_queue *q, const char *name);
 void vb2_queue_release(struct vb2_queue *q);
 
 /**
+ * vb2_queue_change_type() - change the type of an inactive vb2_queue
+ * @q:         pointer to &struct vb2_queue with videobuf2 queue.
+ * @type:      the type to change to (V4L2_BUF_TYPE_VIDEO_*)
+ *
+ * This function changes the type of the vb2_queue. This is only possible
+ * if the queue is not busy (i.e. no buffers have been allocated).
+ *
+ * vb2_queue_change_type() can be used to support multiple buffer types using
+ * the same queue. The driver can implement v4l2_ioctl_ops.vidioc_reqbufs and
+ * v4l2_ioctl_ops.vidioc_create_bufs functions and call vb2_queue_change_type()
+ * before calling vb2_ioctl_reqbufs() or vb2_ioctl_create_bufs(), and thus
+ * "lock" the buffer type until the buffers have been released.
+ */
+int vb2_queue_change_type(struct vb2_queue *q, unsigned int type);
+
+/**
  * vb2_poll() - implements poll userspace operation
  * @q:         pointer to &struct vb2_queue with videobuf2 queue.
  * @file:      file argument passed to the poll file operation handler
index 445b66c..e89530d 100644 (file)
@@ -5537,7 +5537,7 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
  *
  * This function iterates over the interfaces associated with a given
  * hardware that are currently active and calls the callback for them.
- * This version can only be used while holding the RTNL.
+ * This version can only be used while holding the wiphy mutex.
  *
  * @hw: the hardware struct of which the interfaces should be iterated over
  * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
@@ -6392,7 +6392,12 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
 
 /**
  * ieee80211_parse_tx_radiotap - Sanity-check and parse the radiotap header
- *                              of injected frames
+ *                              of injected frames.
+ *
+ * To accurately parse and take into account rate and retransmission fields,
+ * you must initialize the chandef field in the ieee80211_tx_info structure
+ * of the skb before calling this function.
+ *
  * @skb: packet injected by userspace
  * @dev: the &struct device of this 802.11 device
  */
index fa58871..bdc0459 100644 (file)
@@ -184,6 +184,9 @@ struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns,
 void net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid);
 
 void net_ns_barrier(void);
+
+struct ns_common *get_net_ns(struct ns_common *ns);
+struct net *get_net_ns_by_fd(int fd);
 #else /* CONFIG_NET_NS */
 #include <linux/sched.h>
 #include <linux/nsproxy.h>
@@ -203,13 +206,22 @@ static inline void net_ns_get_ownership(const struct net *net,
 }
 
 static inline void net_ns_barrier(void) {}
+
+static inline struct ns_common *get_net_ns(struct ns_common *ns)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline struct net *get_net_ns_by_fd(int fd)
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif /* CONFIG_NET_NS */
 
 
 extern struct list_head net_namespace_list;
 
 struct net *get_net_ns_by_pid(pid_t pid);
-struct net *get_net_ns_by_fd(int fd);
 
 #ifdef CONFIG_SYSCTL
 void ipx_register_sysctl(void);
index 0e962d8..7a7058f 100644 (file)
@@ -1934,7 +1934,8 @@ static inline u32 net_tx_rndhash(void)
 
 static inline void sk_set_txhash(struct sock *sk)
 {
-       sk->sk_txhash = net_tx_rndhash();
+       /* This pairs with READ_ONCE() in skb_set_hash_from_sk() */
+       WRITE_ONCE(sk->sk_txhash, net_tx_rndhash());
 }
 
 static inline bool sk_rethink_txhash(struct sock *sk)
@@ -2206,9 +2207,12 @@ static inline void sock_poll_wait(struct file *filp, struct socket *sock,
 
 static inline void skb_set_hash_from_sk(struct sk_buff *skb, struct sock *sk)
 {
-       if (sk->sk_txhash) {
+       /* This pairs with WRITE_ONCE() in sk_set_txhash() */
+       u32 txhash = READ_ONCE(sk->sk_txhash);
+
+       if (txhash) {
                skb->l4_hash = 1;
-               skb->hash = sk->sk_txhash;
+               skb->hash = txhash;
        }
 }
 
@@ -2266,8 +2270,13 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk);
 static inline int sock_error(struct sock *sk)
 {
        int err;
-       if (likely(!sk->sk_err))
+
+       /* Avoid an atomic operation for the common case.
+        * This is racy since another cpu/thread can change sk_err under us.
+        */
+       if (likely(data_race(!sk->sk_err)))
                return 0;
+
        err = xchg(&sk->sk_err, 0);
        return -err;
 }
index a41dd8a..c723731 100644 (file)
@@ -99,8 +99,7 @@ struct btrfs_space_info;
        EM( ALLOC_CHUNK,                "ALLOC_CHUNK")                  \
        EM( ALLOC_CHUNK_FORCE,          "ALLOC_CHUNK_FORCE")            \
        EM( RUN_DELAYED_IPUTS,          "RUN_DELAYED_IPUTS")            \
-       EM( COMMIT_TRANS,               "COMMIT_TRANS")                 \
-       EMe(FORCE_COMMIT_TRANS,         "FORCE_COMMIT_TRANS")
+       EMe(COMMIT_TRANS,               "COMMIT_TRANS")
 
 /*
  * First define the enums in the above macros to be exported to userspace via
@@ -654,34 +653,30 @@ DEFINE_EVENT(btrfs__writepage, __extent_writepage,
 
 TRACE_EVENT(btrfs_writepage_end_io_hook,
 
-       TP_PROTO(const struct page *page, u64 start, u64 end, int uptodate),
+       TP_PROTO(const struct btrfs_inode *inode, u64 start, u64 end,
+                int uptodate),
 
-       TP_ARGS(page, start, end, uptodate),
+       TP_ARGS(inode, start, end, uptodate),
 
        TP_STRUCT__entry_btrfs(
                __field(        u64,     ino            )
-               __field(        unsigned long, index    )
                __field(        u64,     start          )
                __field(        u64,     end            )
                __field(        int,     uptodate       )
                __field(        u64,    root_objectid   )
        ),
 
-       TP_fast_assign_btrfs(btrfs_sb(page->mapping->host->i_sb),
-               __entry->ino    = btrfs_ino(BTRFS_I(page->mapping->host));
-               __entry->index  = page->index;
+       TP_fast_assign_btrfs(inode->root->fs_info,
+               __entry->ino    = btrfs_ino(inode);
                __entry->start  = start;
                __entry->end    = end;
                __entry->uptodate = uptodate;
-               __entry->root_objectid  =
-                        BTRFS_I(page->mapping->host)->root->root_key.objectid;
+               __entry->root_objectid = inode->root->root_key.objectid;
        ),
 
-       TP_printk_btrfs("root=%llu(%s) ino=%llu page_index=%lu start=%llu "
-                 "end=%llu uptodate=%d",
+       TP_printk_btrfs("root=%llu(%s) ino=%llu start=%llu end=%llu uptodate=%d",
                  show_root_type(__entry->root_objectid),
-                 __entry->ino, __entry->index,
-                 __entry->start,
+                 __entry->ino, __entry->start,
                  __entry->end, __entry->uptodate)
 );
 
index 629c7a0..390270e 100644 (file)
 #define IF_HAVE_PG_ARCH_2(flag,string)
 #endif
 
+#ifdef CONFIG_KASAN_HW_TAGS
+#define IF_HAVE_PG_SKIP_KASAN_POISON(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_SKIP_KASAN_POISON(flag,string)
+#endif
+
 #define __def_pageflag_names                                           \
        {1UL << PG_locked,              "locked"        },              \
        {1UL << PG_waiters,             "waiters"       },              \
@@ -112,7 +118,8 @@ IF_HAVE_PG_UNCACHED(PG_uncached,    "uncached"      )               \
 IF_HAVE_PG_HWPOISON(PG_hwpoison,       "hwpoison"      )               \
 IF_HAVE_PG_IDLE(PG_young,              "young"         )               \
 IF_HAVE_PG_IDLE(PG_idle,               "idle"          )               \
-IF_HAVE_PG_ARCH_2(PG_arch_2,           "arch_2"        )
+IF_HAVE_PG_ARCH_2(PG_arch_2,           "arch_2"        )               \
+IF_HAVE_PG_SKIP_KASAN_POISON(PG_skip_kasan_poison, "skip_kasan_poison")
 
 #define show_page_flags(flags)                                         \
        (flags) ? __print_flags(flags, "|",                             \
index 0dd9171..c0d9844 100644 (file)
@@ -42,6 +42,63 @@ DEFINE_EVENT(spi_controller, spi_controller_busy,
 
 );
 
+TRACE_EVENT(spi_setup,
+       TP_PROTO(struct spi_device *spi, int status),
+       TP_ARGS(spi, status),
+
+       TP_STRUCT__entry(
+               __field(int, bus_num)
+               __field(int, chip_select)
+               __field(unsigned long, mode)
+               __field(unsigned int, bits_per_word)
+               __field(unsigned int, max_speed_hz)
+               __field(int, status)
+       ),
+
+       TP_fast_assign(
+               __entry->bus_num = spi->controller->bus_num;
+               __entry->chip_select = spi->chip_select;
+               __entry->mode = spi->mode;
+               __entry->bits_per_word = spi->bits_per_word;
+               __entry->max_speed_hz = spi->max_speed_hz;
+               __entry->status = status;
+       ),
+
+       TP_printk("spi%d.%d setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d",
+                 __entry->bus_num, __entry->chip_select,
+                 (__entry->mode & SPI_MODE_X_MASK),
+                 (__entry->mode & SPI_CS_HIGH) ? "cs_high, " : "",
+                 (__entry->mode & SPI_LSB_FIRST) ? "lsb, " : "",
+                 (__entry->mode & SPI_3WIRE) ? "3wire, " : "",
+                 (__entry->mode & SPI_LOOP) ? "loopback, " : "",
+                 __entry->bits_per_word, __entry->max_speed_hz,
+                 __entry->status)
+);
+
+TRACE_EVENT(spi_set_cs,
+       TP_PROTO(struct spi_device *spi, bool enable),
+       TP_ARGS(spi, enable),
+
+       TP_STRUCT__entry(
+               __field(int, bus_num)
+               __field(int, chip_select)
+               __field(unsigned long, mode)
+               __field(bool, enable)
+       ),
+
+       TP_fast_assign(
+               __entry->bus_num = spi->controller->bus_num;
+               __entry->chip_select = spi->chip_select;
+               __entry->mode = spi->mode;
+               __entry->enable = enable;
+       ),
+
+       TP_printk("spi%d.%d %s%s",
+                 __entry->bus_num, __entry->chip_select,
+                 __entry->enable ? "activate" : "deactivate",
+                 (__entry->mode & SPI_CS_HIGH) ? ", cs_high" : "")
+);
+
 DECLARE_EVENT_CLASS(spi_message,
 
        TP_PROTO(struct spi_message *msg),
index 6de5a7f..d2a9420 100644 (file)
@@ -863,8 +863,7 @@ __SYSCALL(__NR_process_madvise, sys_process_madvise)
 __SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2)
 #define __NR_mount_setattr 442
 __SYSCALL(__NR_mount_setattr, sys_mount_setattr)
-#define __NR_quotactl_path 443
-__SYSCALL(__NR_quotactl_path, sys_quotactl_path)
+/* 443 is reserved for quotactl_path */
 
 #define __NR_landlock_create_ruleset 444
 __SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset)
index 5df7300..22cd037 100644 (file)
@@ -154,7 +154,7 @@ struct btrfs_scrub_progress {
        __u64 tree_bytes_scrubbed;      /* # of tree bytes scrubbed */
        __u64 read_errors;              /* # of read errors encountered (EIO) */
        __u64 csum_errors;              /* # of failed csum checks */
-       __u64 verify_errors;            /* # of occurences, where the metadata
+       __u64 verify_errors;            /* # of occurrences, where the metadata
                                         * of a tree block did not match the
                                         * expected values, like generation or
                                         * logical */
@@ -174,7 +174,7 @@ struct btrfs_scrub_progress {
        __u64 last_physical;            /* last physical address scrubbed. In
                                         * case a scrub was aborted, this can
                                         * be used to restart the scrub */
-       __u64 unverified_errors;        /* # of occurences where a read for a
+       __u64 unverified_errors;        /* # of occurrences where a read for a
                                         * full (64k) bio failed, but the re-
                                         * check succeeded for each 4k piece.
                                         * Intermittent error. */
index 58d7cff..ccdb40f 100644 (file)
@@ -59,7 +59,7 @@
 /* for storing balance parameters in the root tree */
 #define BTRFS_BALANCE_OBJECTID -4ULL
 
-/* orhpan objectid for tracking unlinked/truncated files */
+/* orphan objectid for tracking unlinked/truncated files */
 #define BTRFS_ORPHAN_OBJECTID -5ULL
 
 /* does write ahead logging to speed up fsyncs */
 #define BTRFS_PERSISTENT_ITEM_KEY      249
 
 /*
- * Persistantly stores the device replace state in the device tree.
+ * Persistently stores the device replace state in the device tree.
  * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0).
  */
 #define BTRFS_DEV_REPLACE_KEY  250
index 3759002..c3baaea 100644 (file)
@@ -1665,7 +1665,7 @@ static inline void cec_ops_report_current_latency(const struct cec_msg *msg,
        if (*audio_out_compensated == 3 && msg->len >= 7)
                *audio_out_delay = msg->msg[6];
        else
-               *audio_out_delay = 0;
+               *audio_out_delay = 1;
 }
 
 static inline void cec_msg_request_current_latency(struct cec_msg *msg,
index a89eb0a..235e5b2 100644 (file)
@@ -21,6 +21,7 @@
 #define FUTEX_WAKE_BITSET      10
 #define FUTEX_WAIT_REQUEUE_PI  11
 #define FUTEX_CMP_REQUEUE_PI   12
+#define FUTEX_LOCK_PI2         13
 
 #define FUTEX_PRIVATE_FLAG     128
 #define FUTEX_CLOCK_REALTIME   256
@@ -32,6 +33,7 @@
 #define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
 #define FUTEX_WAKE_OP_PRIVATE  (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
 #define FUTEX_LOCK_PI_PRIVATE  (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_LOCK_PI2_PRIVATE (FUTEX_LOCK_PI2 | FUTEX_PRIVATE_FLAG)
 #define FUTEX_UNLOCK_PI_PRIVATE        (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
 #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
 #define FUTEX_WAIT_BITSET_PRIVATE      (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
index 7d66876..d1b3270 100644 (file)
@@ -289,6 +289,9 @@ struct sockaddr_in {
 /* Address indicating an error return. */
 #define        INADDR_NONE             ((unsigned long int) 0xffffffff)
 
+/* Dummy address for src of ICMP replies if no real address is set (RFC7600). */
+#define        INADDR_DUMMY            ((unsigned long int) 0xc0000008)
+
 /* Network number for local host loopback. */
 #define        IN_LOOPBACKNET          127
 
index 79d9c44..d9e4aab 100644 (file)
@@ -280,6 +280,9 @@ struct kvm_xen_exit {
 /* Encounter unexpected vm-exit reason */
 #define KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON      4
 
+/* Flags that describe what fields in emulation_failure hold valid data. */
+#define KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES (1ULL << 0)
+
 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {
        /* in */
@@ -383,6 +386,25 @@ struct kvm_run {
                        __u32 ndata;
                        __u64 data[16];
                } internal;
+               /*
+                * KVM_INTERNAL_ERROR_EMULATION
+                *
+                * "struct emulation_failure" is an overlay of "struct internal"
+                * that is used for the KVM_INTERNAL_ERROR_EMULATION sub-type of
+                * KVM_EXIT_INTERNAL_ERROR.  Note, unlike other internal error
+                * sub-types, this struct is ABI!  It also needs to be backwards
+                * compatible with "struct internal".  Take special care that
+                * "ndata" is correct, that new fields are enumerated in "flags",
+                * and that each flag enumerates fields that are 64-bit aligned
+                * and sized (so that ndata+internal.data[] is valid/accurate).
+                */
+               struct {
+                       __u32 suberror;
+                       __u32 ndata;
+                       __u64 flags;
+                       __u8  insn_size;
+                       __u8  insn_bytes[15];
+               } emulation_failure;
                /* KVM_EXIT_OSI */
                struct {
                        __u64 gprs[32];
@@ -1083,6 +1105,13 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_SGX_ATTRIBUTE 196
 #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 197
 #define KVM_CAP_PTP_KVM 198
+#define KVM_CAP_HYPERV_ENFORCE_CPUID 199
+#define KVM_CAP_SREGS2 200
+#define KVM_CAP_EXIT_HYPERCALL 201
+#define KVM_CAP_PPC_RPT_INVALIDATE 202
+#define KVM_CAP_BINARY_STATS_FD 203
+#define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204
+#define KVM_CAP_ARM_MTE 205
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1428,6 +1457,7 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_PMU_EVENT_FILTER */
 #define KVM_SET_PMU_EVENT_FILTER  _IOW(KVMIO,  0xb2, struct kvm_pmu_event_filter)
 #define KVM_PPC_SVM_OFF                  _IO(KVMIO,  0xb3)
+#define KVM_ARM_MTE_COPY_TAGS    _IOR(KVMIO,  0xb4, struct kvm_arm_copy_mte_tags)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE        _IOWR(KVMIO,  0xe0, struct kvm_create_device)
@@ -1621,6 +1651,9 @@ struct kvm_xen_hvm_attr {
 #define KVM_XEN_VCPU_GET_ATTR  _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
 #define KVM_XEN_VCPU_SET_ATTR  _IOW(KVMIO,  0xcb, struct kvm_xen_vcpu_attr)
 
+#define KVM_GET_SREGS2             _IOR(KVMIO,  0xcc, struct kvm_sregs2)
+#define KVM_SET_SREGS2             _IOW(KVMIO,  0xcd, struct kvm_sregs2)
+
 struct kvm_xen_vcpu_attr {
        __u16 type;
        __u16 pad[3];
@@ -1899,4 +1932,76 @@ struct kvm_dirty_gfn {
 #define KVM_BUS_LOCK_DETECTION_OFF             (1 << 0)
 #define KVM_BUS_LOCK_DETECTION_EXIT            (1 << 1)
 
+/**
+ * struct kvm_stats_header - Header of per vm/vcpu binary statistics data.
+ * @flags: Some extra information for header, always 0 for now.
+ * @name_size: The size in bytes of the memory which contains statistics
+ *             name string including trailing '\0'. The memory is allocated
+ *             at the send of statistics descriptor.
+ * @num_desc: The number of statistics the vm or vcpu has.
+ * @id_offset: The offset of the vm/vcpu stats' id string in the file pointed
+ *             by vm/vcpu stats fd.
+ * @desc_offset: The offset of the vm/vcpu stats' descriptor block in the file
+ *               pointd by vm/vcpu stats fd.
+ * @data_offset: The offset of the vm/vcpu stats' data block in the file
+ *               pointed by vm/vcpu stats fd.
+ *
+ * This is the header userspace needs to read from stats fd before any other
+ * readings. It is used by userspace to discover all the information about the
+ * vm/vcpu's binary statistics.
+ * Userspace reads this header from the start of the vm/vcpu's stats fd.
+ */
+struct kvm_stats_header {
+       __u32 flags;
+       __u32 name_size;
+       __u32 num_desc;
+       __u32 id_offset;
+       __u32 desc_offset;
+       __u32 data_offset;
+};
+
+#define KVM_STATS_TYPE_SHIFT           0
+#define KVM_STATS_TYPE_MASK            (0xF << KVM_STATS_TYPE_SHIFT)
+#define KVM_STATS_TYPE_CUMULATIVE      (0x0 << KVM_STATS_TYPE_SHIFT)
+#define KVM_STATS_TYPE_INSTANT         (0x1 << KVM_STATS_TYPE_SHIFT)
+#define KVM_STATS_TYPE_PEAK            (0x2 << KVM_STATS_TYPE_SHIFT)
+#define KVM_STATS_TYPE_MAX             KVM_STATS_TYPE_PEAK
+
+#define KVM_STATS_UNIT_SHIFT           4
+#define KVM_STATS_UNIT_MASK            (0xF << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_NONE            (0x0 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
+
+#define KVM_STATS_BASE_SHIFT           8
+#define KVM_STATS_BASE_MASK            (0xF << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_POW10           (0x0 << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_POW2            (0x1 << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_MAX             KVM_STATS_BASE_POW2
+
+/**
+ * struct kvm_stats_desc - Descriptor of a KVM statistics.
+ * @flags: Annotations of the stats, like type, unit, etc.
+ * @exponent: Used together with @flags to determine the unit.
+ * @size: The number of data items for this stats.
+ *        Every data item is of type __u64.
+ * @offset: The offset of the stats to the start of stat structure in
+ *          struture kvm or kvm_vcpu.
+ * @unused: Unused field for future usage. Always 0 for now.
+ * @name: The name string for the stats. Its size is indicated by the
+ *        &kvm_stats_header->name_size.
+ */
+struct kvm_stats_desc {
+       __u32 flags;
+       __s16 exponent;
+       __u16 size;
+       __u32 offset;
+       __u32 unused;
+       char name[];
+};
+
+#define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
+
 #endif /* __LINUX_KVM_H */
index 8b86609..960c7e9 100644 (file)
@@ -29,6 +29,7 @@
 #define KVM_HC_CLOCK_PAIRING           9
 #define KVM_HC_SEND_IPI                10
 #define KVM_HC_SCHED_YIELD             11
+#define KVM_HC_MAP_GPA_RANGE           12
 
 /*
  * hypercalls use architecture specific
index c45a4ea..9919f20 100644 (file)
@@ -1,7 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 /*
  * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
  */
 
 #ifndef _LINUX_LIRC_H
index 18a9f59..967d9c5 100644 (file)
@@ -259,4 +259,12 @@ struct prctl_mm_map {
 #define PR_PAC_SET_ENABLED_KEYS                60
 #define PR_PAC_GET_ENABLED_KEYS                61
 
+/* Request the scheduler to share a core */
+#define PR_SCHED_CORE                  62
+# define PR_SCHED_CORE_GET             0
+# define PR_SCHED_CORE_CREATE          1 /* create unique core_sched cookie */
+# define PR_SCHED_CORE_SHARE_TO                2 /* push core_sched cookie to pid */
+# define PR_SCHED_CORE_SHARE_FROM      3 /* pull core_sched cookie to pid */
+# define PR_SCHED_CORE_MAX             4
+
 #endif /* _LINUX_PRCTL_H */
index 6ba18b8..7807425 100644 (file)
@@ -115,6 +115,7 @@ struct seccomp_notif_resp {
 
 /* valid flags for seccomp_notif_addfd */
 #define SECCOMP_ADDFD_FLAG_SETFD       (1UL << 0) /* Specify remote fd */
+#define SECCOMP_ADDFD_FLAG_SEND                (1UL << 1) /* Addfd and return it, atomically */
 
 /**
  * struct seccomp_notif_addfd
index bafbeb1..650480f 100644 (file)
@@ -80,8 +80,8 @@
                                      struct uffdio_zeropage)
 #define UFFDIO_WRITEPROTECT    _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \
                                      struct uffdio_writeprotect)
-#define UFFDIO_CONTINUE                _IOR(UFFDIO, _UFFDIO_CONTINUE,  \
-                                    struct uffdio_continue)
+#define UFFDIO_CONTINUE                _IOWR(UFFDIO, _UFFDIO_CONTINUE, \
+                                     struct uffdio_continue)
 
 /* read() structure */
 struct uffd_msg {
index d43bec5..fdf97a6 100644 (file)
@@ -50,6 +50,7 @@
 #ifndef __LINUX_V4L2_CONTROLS_H
 #define __LINUX_V4L2_CONTROLS_H
 
+#include <linux/const.h>
 #include <linux/types.h>
 
 /* Control classes */
@@ -1602,30 +1603,30 @@ struct v4l2_ctrl_h264_decode_params {
 #define V4L2_FWHT_VERSION                      3
 
 /* Set if this is an interlaced format */
-#define V4L2_FWHT_FL_IS_INTERLACED             BIT(0)
+#define V4L2_FWHT_FL_IS_INTERLACED             _BITUL(0)
 /* Set if this is a bottom-first (NTSC) interlaced format */
-#define V4L2_FWHT_FL_IS_BOTTOM_FIRST           BIT(1)
+#define V4L2_FWHT_FL_IS_BOTTOM_FIRST           _BITUL(1)
 /* Set if each 'frame' contains just one field */
-#define V4L2_FWHT_FL_IS_ALTERNATE              BIT(2)
+#define V4L2_FWHT_FL_IS_ALTERNATE              _BITUL(2)
 /*
  * If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this
  * 'frame' is the bottom field, else it is the top field.
  */
-#define V4L2_FWHT_FL_IS_BOTTOM_FIELD           BIT(3)
+#define V4L2_FWHT_FL_IS_BOTTOM_FIELD           _BITUL(3)
 /* Set if the Y' plane is uncompressed */
-#define V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED      BIT(4)
+#define V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED      _BITUL(4)
 /* Set if the Cb plane is uncompressed */
-#define V4L2_FWHT_FL_CB_IS_UNCOMPRESSED                BIT(5)
+#define V4L2_FWHT_FL_CB_IS_UNCOMPRESSED                _BITUL(5)
 /* Set if the Cr plane is uncompressed */
-#define V4L2_FWHT_FL_CR_IS_UNCOMPRESSED                BIT(6)
+#define V4L2_FWHT_FL_CR_IS_UNCOMPRESSED                _BITUL(6)
 /* Set if the chroma plane is full height, if cleared it is half height */
-#define V4L2_FWHT_FL_CHROMA_FULL_HEIGHT                BIT(7)
+#define V4L2_FWHT_FL_CHROMA_FULL_HEIGHT                _BITUL(7)
 /* Set if the chroma plane is full width, if cleared it is half width */
-#define V4L2_FWHT_FL_CHROMA_FULL_WIDTH         BIT(8)
+#define V4L2_FWHT_FL_CHROMA_FULL_WIDTH         _BITUL(8)
 /* Set if the alpha plane is uncompressed */
-#define V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED     BIT(9)
+#define V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED     _BITUL(9)
 /* Set if this is an I Frame */
-#define V4L2_FWHT_FL_I_FRAME                   BIT(10)
+#define V4L2_FWHT_FL_I_FRAME                   _BITUL(10)
 
 /* A 4-values flag - the number of components - 1 */
 #define V4L2_FWHT_FL_COMPONENTS_NUM_MSK                GENMASK(18, 16)
@@ -1862,6 +1863,118 @@ struct v4l2_ctrl_vp8_frame {
        __u64 flags;
 };
 
+/* Stateless MPEG-2 controls */
+
+#define V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE        0x01
+
+#define V4L2_CID_STATELESS_MPEG2_SEQUENCE (V4L2_CID_CODEC_STATELESS_BASE+220)
+/**
+ * struct v4l2_ctrl_mpeg2_sequence - MPEG-2 sequence header
+ *
+ * All the members on this structure match the sequence header and sequence
+ * extension syntaxes as specified by the MPEG-2 specification.
+ *
+ * Fields horizontal_size, vertical_size and vbv_buffer_size are a
+ * combination of respective _value and extension syntax elements,
+ * as described in section 6.3.3 "Sequence header".
+ *
+ * @horizontal_size: combination of elements horizontal_size_value and
+ * horizontal_size_extension.
+ * @vertical_size: combination of elements vertical_size_value and
+ * vertical_size_extension.
+ * @vbv_buffer_size: combination of elements vbv_buffer_size_value and
+ * vbv_buffer_size_extension.
+ * @profile_and_level_indication: see MPEG-2 specification.
+ * @chroma_format: see MPEG-2 specification.
+ * @flags: see V4L2_MPEG2_SEQ_FLAG_{}.
+ */
+struct v4l2_ctrl_mpeg2_sequence {
+       __u16   horizontal_size;
+       __u16   vertical_size;
+       __u32   vbv_buffer_size;
+       __u16   profile_and_level_indication;
+       __u8    chroma_format;
+       __u8    flags;
+};
+
+#define V4L2_MPEG2_PIC_CODING_TYPE_I                   1
+#define V4L2_MPEG2_PIC_CODING_TYPE_P                   2
+#define V4L2_MPEG2_PIC_CODING_TYPE_B                   3
+#define V4L2_MPEG2_PIC_CODING_TYPE_D                   4
+
+#define V4L2_MPEG2_PIC_TOP_FIELD                       0x1
+#define V4L2_MPEG2_PIC_BOTTOM_FIELD                    0x2
+#define V4L2_MPEG2_PIC_FRAME                           0x3
+
+#define V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST            0x0001
+#define V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT             0x0002
+#define V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV             0x0004
+#define V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE               0x0008
+#define V4L2_MPEG2_PIC_FLAG_INTRA_VLC                  0x0010
+#define V4L2_MPEG2_PIC_FLAG_ALT_SCAN                   0x0020
+#define V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST               0x0040
+#define V4L2_MPEG2_PIC_FLAG_PROGRESSIVE                        0x0080
+
+#define V4L2_CID_STATELESS_MPEG2_PICTURE (V4L2_CID_CODEC_STATELESS_BASE+221)
+/**
+ * struct v4l2_ctrl_mpeg2_picture - MPEG-2 picture header
+ *
+ * All the members on this structure match the picture header and picture
+ * coding extension syntaxes as specified by the MPEG-2 specification.
+ *
+ * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as
+ * reference for backward prediction.
+ * @forward_ref_ts: timestamp of the V4L2 capture buffer to use as
+ * reference for forward prediction. These timestamp refers to the
+ * timestamp field in struct v4l2_buffer. Use v4l2_timeval_to_ns()
+ * to convert the struct timeval to a __u64.
+ * @flags: see V4L2_MPEG2_PIC_FLAG_{}.
+ * @f_code: see MPEG-2 specification.
+ * @picture_coding_type: see MPEG-2 specification.
+ * @picture_structure: see V4L2_MPEG2_PIC_{}_FIELD.
+ * @intra_dc_precision: see MPEG-2 specification.
+ * @reserved: padding field. Should be zeroed by applications.
+ */
+struct v4l2_ctrl_mpeg2_picture {
+       __u64   backward_ref_ts;
+       __u64   forward_ref_ts;
+       __u32   flags;
+       __u8    f_code[2][2];
+       __u8    picture_coding_type;
+       __u8    picture_structure;
+       __u8    intra_dc_precision;
+       __u8    reserved[5];
+};
+
+#define V4L2_CID_STATELESS_MPEG2_QUANTISATION (V4L2_CID_CODEC_STATELESS_BASE+222)
+/**
+ * struct v4l2_ctrl_mpeg2_quantisation - MPEG-2 quantisation
+ *
+ * Quantisation matrices as specified by section 6.3.7
+ * "Quant matrix extension".
+ *
+ * @intra_quantiser_matrix: The quantisation matrix coefficients
+ * for intra-coded frames, in zigzag scanning order. It is relevant
+ * for both luma and chroma components, although it can be superseded
+ * by the chroma-specific matrix for non-4:2:0 YUV formats.
+ * @non_intra_quantiser_matrix: The quantisation matrix coefficients
+ * for non-intra-coded frames, in zigzag scanning order. It is relevant
+ * for both luma and chroma components, although it can be superseded
+ * by the chroma-specific matrix for non-4:2:0 YUV formats.
+ * @chroma_intra_quantiser_matrix: The quantisation matrix coefficients
+ * for the chominance component of intra-coded frames, in zigzag scanning
+ * order. Only relevant for 4:2:2 and 4:4:4 YUV formats.
+ * @chroma_non_intra_quantiser_matrix: The quantisation matrix coefficients
+ * for the chrominance component of non-intra-coded frames, in zigzag scanning
+ * order. Only relevant for 4:2:2 and 4:4:4 YUV formats.
+ */
+struct v4l2_ctrl_mpeg2_quantisation {
+       __u8    intra_quantiser_matrix[64];
+       __u8    non_intra_quantiser_matrix[64];
+       __u8    chroma_intra_quantiser_matrix[64];
+       __u8    chroma_non_intra_quantiser_matrix[64];
+};
+
 #define V4L2_CID_COLORIMETRY_CLASS_BASE        (V4L2_CTRL_CLASS_COLORIMETRY | 0x900)
 #define V4L2_CID_COLORIMETRY_CLASS     (V4L2_CTRL_CLASS_COLORIMETRY | 1)
 
index 311a01c..9260791 100644 (file)
@@ -1747,6 +1747,9 @@ struct v4l2_ext_control {
                struct v4l2_ctrl_h264_decode_params __user *p_h264_decode_params;
                struct v4l2_ctrl_fwht_params __user *p_fwht_params;
                struct v4l2_ctrl_vp8_frame __user *p_vp8_frame;
+               struct v4l2_ctrl_mpeg2_sequence __user *p_mpeg2_sequence;
+               struct v4l2_ctrl_mpeg2_picture __user *p_mpeg2_picture;
+               struct v4l2_ctrl_mpeg2_quantisation __user *p_mpeg2_quantisation;
                void __user *ptr;
        };
 } __attribute__ ((packed));
@@ -1807,6 +1810,10 @@ enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_FWHT_PARAMS          = 0x0220,
 
        V4L2_CTRL_TYPE_VP8_FRAME            = 0x0240,
+
+       V4L2_CTRL_TYPE_MPEG2_QUANTISATION   = 0x0250,
+       V4L2_CTRL_TYPE_MPEG2_SEQUENCE       = 0x0251,
+       V4L2_CTRL_TYPE_MPEG2_PICTURE        = 0x0252,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
index 8b08c2e..562f2ef 100644 (file)
@@ -71,7 +71,7 @@ struct task_struct init_task
        .thread_info    = INIT_THREAD_INFO(init_task),
        .stack_refcount = REFCOUNT_INIT(1),
 #endif
-       .state          = 0,
+       .__state        = 0,
        .stack          = init_stack,
        .usage          = REFCOUNT_INIT(2),
        .flags          = PF_KTHREAD,
index e9c42a1..3593585 100644 (file)
@@ -692,6 +692,7 @@ noinline void __ref rest_init(void)
         */
        rcu_read_lock();
        tsk = find_task_by_pid_ns(pid, &init_pid_ns);
+       tsk->flags |= PF_NO_SETAFFINITY;
        set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
        rcu_read_unlock();
 
@@ -941,11 +942,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
         * time - but meanwhile we still have a functioning scheduler.
         */
        sched_init();
-       /*
-        * Disable preemption - early bootup scheduling is extremely
-        * fragile until we cpu_idle() for the first time.
-        */
-       preempt_disable();
+
        if (WARN(!irqs_disabled(),
                 "Interrupts were enabled *very* early, fixing it\n"))
                local_irq_disable();
@@ -1444,6 +1441,11 @@ static int __ref kernel_init(void *unused)
 {
        int ret;
 
+       /*
+        * Wait until kthreadd is all set-up.
+        */
+       wait_for_completion(&kthreadd_done);
+
        kernel_init_freeable();
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
@@ -1524,11 +1526,6 @@ void __init console_on_rootfs(void)
 
 static noinline void __init kernel_init_freeable(void)
 {
-       /*
-        * Wait until kthreadd is all set-up.
-        */
-       wait_for_completion(&kthreadd_done);
-
        /* Now the scheduler is fully set up and can do blocking allocations */
        gfp_allowed_mask = __GFP_BITS_MASK;
 
index 4e4e611..5becca9 100644 (file)
@@ -144,7 +144,7 @@ struct mqueue_inode_info {
        struct pid *notify_owner;
        u32 notify_self_exec_id;
        struct user_namespace *notify_user_ns;
-       struct user_struct *user;       /* user who created, for accounting */
+       struct ucounts *ucounts;        /* user who created, for accounting */
        struct sock *notify_sock;
        struct sk_buff *notify_cookie;
 
@@ -292,7 +292,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
                struct ipc_namespace *ipc_ns, umode_t mode,
                struct mq_attr *attr)
 {
-       struct user_struct *u = current_user();
        struct inode *inode;
        int ret = -ENOMEM;
 
@@ -321,7 +320,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
                info->notify_owner = NULL;
                info->notify_user_ns = NULL;
                info->qsize = 0;
-               info->user = NULL;      /* set when all is ok */
+               info->ucounts = NULL;   /* set when all is ok */
                info->msg_tree = RB_ROOT;
                info->msg_tree_rightmost = NULL;
                info->node_cache = NULL;
@@ -371,19 +370,23 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
                if (mq_bytes + mq_treesize < mq_bytes)
                        goto out_inode;
                mq_bytes += mq_treesize;
-               spin_lock(&mq_lock);
-               if (u->mq_bytes + mq_bytes < u->mq_bytes ||
-                   u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
+               info->ucounts = get_ucounts(current_ucounts());
+               if (info->ucounts) {
+                       long msgqueue;
+
+                       spin_lock(&mq_lock);
+                       msgqueue = inc_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
+                       if (msgqueue == LONG_MAX || msgqueue > rlimit(RLIMIT_MSGQUEUE)) {
+                               dec_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
+                               spin_unlock(&mq_lock);
+                               put_ucounts(info->ucounts);
+                               info->ucounts = NULL;
+                               /* mqueue_evict_inode() releases info->messages */
+                               ret = -EMFILE;
+                               goto out_inode;
+                       }
                        spin_unlock(&mq_lock);
-                       /* mqueue_evict_inode() releases info->messages */
-                       ret = -EMFILE;
-                       goto out_inode;
                }
-               u->mq_bytes += mq_bytes;
-               spin_unlock(&mq_lock);
-
-               /* all is ok */
-               info->user = get_uid(u);
        } else if (S_ISDIR(mode)) {
                inc_nlink(inode);
                /* Some things misbehave if size == 0 on a directory */
@@ -497,7 +500,6 @@ static void mqueue_free_inode(struct inode *inode)
 static void mqueue_evict_inode(struct inode *inode)
 {
        struct mqueue_inode_info *info;
-       struct user_struct *user;
        struct ipc_namespace *ipc_ns;
        struct msg_msg *msg, *nmsg;
        LIST_HEAD(tmp_msg);
@@ -520,8 +522,7 @@ static void mqueue_evict_inode(struct inode *inode)
                free_msg(msg);
        }
 
-       user = info->user;
-       if (user) {
+       if (info->ucounts) {
                unsigned long mq_bytes, mq_treesize;
 
                /* Total amount of bytes accounted for the mqueue */
@@ -533,7 +534,7 @@ static void mqueue_evict_inode(struct inode *inode)
                                          info->attr.mq_msgsize);
 
                spin_lock(&mq_lock);
-               user->mq_bytes -= mq_bytes;
+               dec_rlimit_ucounts(info->ucounts, UCOUNT_RLIMIT_MSGQUEUE, mq_bytes);
                /*
                 * get_ns_from_inode() ensures that the
                 * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns
@@ -543,7 +544,8 @@ static void mqueue_evict_inode(struct inode *inode)
                if (ipc_ns)
                        ipc_ns->mq_queues_count--;
                spin_unlock(&mq_lock);
-               free_uid(user);
+               put_ucounts(info->ucounts);
+               info->ucounts = NULL;
        }
        if (ipc_ns)
                put_ipc_ns(ipc_ns);
index febd88d..003234f 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -60,7 +60,7 @@ struct shmid_kernel /* private to the kernel */
        time64_t                shm_ctim;
        struct pid              *shm_cprid;
        struct pid              *shm_lprid;
-       struct user_struct      *mlock_user;
+       struct ucounts          *mlock_ucounts;
 
        /* The task created the shm object.  NULL if the task is dead. */
        struct task_struct      *shm_creator;
@@ -286,10 +286,10 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
        shm_rmid(ns, shp);
        shm_unlock(shp);
        if (!is_file_hugepages(shm_file))
-               shmem_lock(shm_file, 0, shp->mlock_user);
-       else if (shp->mlock_user)
+               shmem_lock(shm_file, 0, shp->mlock_ucounts);
+       else if (shp->mlock_ucounts)
                user_shm_unlock(i_size_read(file_inode(shm_file)),
-                               shp->mlock_user);
+                               shp->mlock_ucounts);
        fput(shm_file);
        ipc_update_pid(&shp->shm_cprid, NULL);
        ipc_update_pid(&shp->shm_lprid, NULL);
@@ -625,7 +625,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 
        shp->shm_perm.key = key;
        shp->shm_perm.mode = (shmflg & S_IRWXUGO);
-       shp->mlock_user = NULL;
+       shp->mlock_ucounts = NULL;
 
        shp->shm_perm.security = NULL;
        error = security_shm_alloc(&shp->shm_perm);
@@ -650,7 +650,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                if (shmflg & SHM_NORESERVE)
                        acctflag = VM_NORESERVE;
                file = hugetlb_file_setup(name, hugesize, acctflag,
-                                 &shp->mlock_user, HUGETLB_SHMFS_INODE,
+                                 &shp->mlock_ucounts, HUGETLB_SHMFS_INODE,
                                (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
        } else {
                /*
@@ -698,8 +698,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 no_id:
        ipc_update_pid(&shp->shm_cprid, NULL);
        ipc_update_pid(&shp->shm_lprid, NULL);
-       if (is_file_hugepages(file) && shp->mlock_user)
-               user_shm_unlock(size, shp->mlock_user);
+       if (is_file_hugepages(file) && shp->mlock_ucounts)
+               user_shm_unlock(size, shp->mlock_ucounts);
        fput(file);
        ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
        return error;
@@ -1105,12 +1105,12 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
                goto out_unlock0;
 
        if (cmd == SHM_LOCK) {
-               struct user_struct *user = current_user();
+               struct ucounts *ucounts = current_ucounts();
 
-               err = shmem_lock(shm_file, 1, user);
+               err = shmem_lock(shm_file, 1, ucounts);
                if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
                        shp->shm_perm.mode |= SHM_LOCKED;
-                       shp->mlock_user = user;
+                       shp->mlock_ucounts = ucounts;
                }
                goto out_unlock0;
        }
@@ -1118,9 +1118,9 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
        /* SHM_UNLOCK */
        if (!(shp->shm_perm.mode & SHM_LOCKED))
                goto out_unlock0;
-       shmem_lock(shm_file, 0, shp->mlock_user);
+       shmem_lock(shm_file, 0, shp->mlock_ucounts);
        shp->shm_perm.mode &= ~SHM_LOCKED;
-       shp->mlock_user = NULL;
+       shp->mlock_ucounts = NULL;
        get_file(shm_file);
        ipc_unlock_object(&shp->shm_perm);
        rcu_read_unlock();
index 4160173..bd7c414 100644 (file)
@@ -99,3 +99,23 @@ config PREEMPT_DYNAMIC
 
          Interesting if you want the same pre-built kernel should be used for
          both Server and Desktop workloads.
+
+config SCHED_CORE
+       bool "Core Scheduling for SMT"
+       default y
+       depends on SCHED_SMT
+       help
+         This option permits Core Scheduling, a means of coordinated task
+         selection across SMT siblings. When enabled -- see
+         prctl(PR_SCHED_CORE) -- task selection ensures that all SMT siblings
+         will execute a task from the same 'core group', forcing idle when no
+         matching task is found.
+
+         Use of this feature includes:
+          - mitigation of some (not all) SMT side channels;
+          - limiting SMT interference to improve determinism and/or performance.
+
+         SCHED_CORE is default enabled when SCHED_SMT is enabled -- when
+         unused there should be no impact on performance.
+
+
index 94ba516..c6a2757 100644 (file)
@@ -6483,6 +6483,27 @@ struct bpf_sanitize_info {
        bool mask_to_left;
 };
 
+static struct bpf_verifier_state *
+sanitize_speculative_path(struct bpf_verifier_env *env,
+                         const struct bpf_insn *insn,
+                         u32 next_idx, u32 curr_idx)
+{
+       struct bpf_verifier_state *branch;
+       struct bpf_reg_state *regs;
+
+       branch = push_stack(env, next_idx, curr_idx, true);
+       if (branch && insn) {
+               regs = branch->frame[branch->curframe]->regs;
+               if (BPF_SRC(insn->code) == BPF_K) {
+                       mark_reg_unknown(env, regs, insn->dst_reg);
+               } else if (BPF_SRC(insn->code) == BPF_X) {
+                       mark_reg_unknown(env, regs, insn->dst_reg);
+                       mark_reg_unknown(env, regs, insn->src_reg);
+               }
+       }
+       return branch;
+}
+
 static int sanitize_ptr_alu(struct bpf_verifier_env *env,
                            struct bpf_insn *insn,
                            const struct bpf_reg_state *ptr_reg,
@@ -6566,12 +6587,26 @@ do_sim:
                tmp = *dst_reg;
                *dst_reg = *ptr_reg;
        }
-       ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
+       ret = sanitize_speculative_path(env, NULL, env->insn_idx + 1,
+                                       env->insn_idx);
        if (!ptr_is_dst_reg && ret)
                *dst_reg = tmp;
        return !ret ? REASON_STACK : 0;
 }
 
+static void sanitize_mark_insn_seen(struct bpf_verifier_env *env)
+{
+       struct bpf_verifier_state *vstate = env->cur_state;
+
+       /* If we simulate paths under speculation, we don't update the
+        * insn as 'seen' such that when we verify unreachable paths in
+        * the non-speculative domain, sanitize_dead_code() can still
+        * rewrite/sanitize them.
+        */
+       if (!vstate->speculative)
+               env->insn_aux_data[env->insn_idx].seen = env->pass_cnt;
+}
+
 static int sanitize_err(struct bpf_verifier_env *env,
                        const struct bpf_insn *insn, int reason,
                        const struct bpf_reg_state *off_reg,
@@ -8750,14 +8785,28 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
                if (err)
                        return err;
        }
+
        if (pred == 1) {
-               /* only follow the goto, ignore fall-through */
+               /* Only follow the goto, ignore fall-through. If needed, push
+                * the fall-through branch for simulation under speculative
+                * execution.
+                */
+               if (!env->bypass_spec_v1 &&
+                   !sanitize_speculative_path(env, insn, *insn_idx + 1,
+                                              *insn_idx))
+                       return -EFAULT;
                *insn_idx += insn->off;
                return 0;
        } else if (pred == 0) {
-               /* only follow fall-through branch, since
-                * that's where the program will go
+               /* Only follow the fall-through branch, since that's where the
+                * program will go. If needed, push the goto branch for
+                * simulation under speculative execution.
                 */
+               if (!env->bypass_spec_v1 &&
+                   !sanitize_speculative_path(env, insn,
+                                              *insn_idx + insn->off + 1,
+                                              *insn_idx))
+                       return -EFAULT;
                return 0;
        }
 
@@ -10630,7 +10679,7 @@ static int do_check(struct bpf_verifier_env *env)
                }
 
                regs = cur_regs(env);
-               env->insn_aux_data[env->insn_idx].seen = env->pass_cnt;
+               sanitize_mark_insn_seen(env);
                prev_insn_idx = env->insn_idx;
 
                if (class == BPF_ALU || class == BPF_ALU64) {
@@ -10857,7 +10906,7 @@ process_bpf_exit:
                                        return err;
 
                                env->insn_idx++;
-                               env->insn_aux_data[env->insn_idx].seen = env->pass_cnt;
+                               sanitize_mark_insn_seen(env);
                        } else {
                                verbose(env, "invalid BPF_LD mode\n");
                                return -EINVAL;
@@ -11366,6 +11415,7 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
 {
        struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
        struct bpf_insn *insn = new_prog->insnsi;
+       u32 old_seen = old_data[off].seen;
        u32 prog_len;
        int i;
 
@@ -11386,7 +11436,8 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
        memcpy(new_data + off + cnt - 1, old_data + off,
               sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
        for (i = off; i < off + cnt - 1; i++) {
-               new_data[i].seen = env->pass_cnt;
+               /* Expand insni[off]'s seen count to the patched range. */
+               new_data[i].seen = old_seen;
                new_data[i].zext_dst = insn_has_def32(env, insn + i);
        }
        env->insn_aux_data = new_data;
@@ -12710,6 +12761,9 @@ static void free_states(struct bpf_verifier_env *env)
  * insn_aux_data was touched. These variables are compared to clear temporary
  * data from failed pass. For testing and experiments do_check_common() can be
  * run multiple times even when prior attempt to verify is unsuccessful.
+ *
+ * Note that special handling is needed on !env->bypass_spec_v1 if this is
+ * ever called outside of error path with subsequent program rejection.
  */
 static void sanitize_insn_aux_data(struct bpf_verifier_env *env)
 {
index 1f274d7..ee93b6e 100644 (file)
@@ -713,7 +713,7 @@ int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry)
 
        css_task_iter_start(&cgrp->self, 0, &it);
        while ((tsk = css_task_iter_next(&it))) {
-               switch (tsk->state) {
+               switch (READ_ONCE(tsk->__state)) {
                case TASK_RUNNING:
                        stats->nr_running++;
                        break;
index e538518..804b847 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/relay.h>
 #include <linux/slab.h>
 #include <linux/percpu-rwsem.h>
+#include <linux/cpuset.h>
 
 #include <trace/events/power.h>
 #define CREATE_TRACE_POINTS
@@ -873,6 +874,52 @@ void __init cpuhp_threads_init(void)
        kthread_unpark(this_cpu_read(cpuhp_state.thread));
 }
 
+/*
+ *
+ * Serialize hotplug trainwrecks outside of the cpu_hotplug_lock
+ * protected region.
+ *
+ * The operation is still serialized against concurrent CPU hotplug via
+ * cpu_add_remove_lock, i.e. CPU map protection.  But it is _not_
+ * serialized against other hotplug related activity like adding or
+ * removing of state callbacks and state instances, which invoke either the
+ * startup or the teardown callback of the affected state.
+ *
+ * This is required for subsystems which are unfixable vs. CPU hotplug and
+ * evade lock inversion problems by scheduling work which has to be
+ * completed _before_ cpu_up()/_cpu_down() returns.
+ *
+ * Don't even think about adding anything to this for any new code or even
+ * drivers. It's only purpose is to keep existing lock order trainwrecks
+ * working.
+ *
+ * For cpu_down() there might be valid reasons to finish cleanups which are
+ * not required to be done under cpu_hotplug_lock, but that's a different
+ * story and would be not invoked via this.
+ */
+static void cpu_up_down_serialize_trainwrecks(bool tasks_frozen)
+{
+       /*
+        * cpusets delegate hotplug operations to a worker to "solve" the
+        * lock order problems. Wait for the worker, but only if tasks are
+        * _not_ frozen (suspend, hibernate) as that would wait forever.
+        *
+        * The wait is required because otherwise the hotplug operation
+        * returns with inconsistent state, which could even be observed in
+        * user space when a new CPU is brought up. The CPU plug uevent
+        * would be delivered and user space reacting on it would fail to
+        * move tasks to the newly plugged CPU up to the point where the
+        * work has finished because up to that point the newly plugged CPU
+        * is not assignable in cpusets/cgroups. On unplug that's not
+        * necessarily a visible issue, but it is still inconsistent state,
+        * which is the real problem which needs to be "fixed". This can't
+        * prevent the transient state between scheduling the work and
+        * returning from waiting for it.
+        */
+       if (!tasks_frozen)
+               cpuset_wait_for_hotplug();
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 #ifndef arch_clear_mm_cpumask_cpu
 #define arch_clear_mm_cpumask_cpu(cpu, mm) cpumask_clear_cpu(cpu, mm_cpumask(mm))
@@ -961,7 +1008,7 @@ static int takedown_cpu(unsigned int cpu)
        int err;
 
        /* Park the smpboot threads */
-       kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread);
+       kthread_park(st->thread);
 
        /*
         * Prevent irq alloc/free while the dying cpu reorganizes the
@@ -977,7 +1024,7 @@ static int takedown_cpu(unsigned int cpu)
                /* CPU refused to die */
                irq_unlock_sparse();
                /* Unpark the hotplug thread so we can rollback there */
-               kthread_unpark(per_cpu_ptr(&cpuhp_state, cpu)->thread);
+               kthread_unpark(st->thread);
                return err;
        }
        BUG_ON(cpu_online(cpu));
@@ -1108,6 +1155,7 @@ out:
         */
        lockup_detector_cleanup();
        arch_smt_update();
+       cpu_up_down_serialize_trainwrecks(tasks_frozen);
        return ret;
 }
 
@@ -1302,6 +1350,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
 out:
        cpus_write_unlock();
        arch_smt_update();
+       cpu_up_down_serialize_trainwrecks(tasks_frozen);
        return ret;
 }
 
index 825284b..684a606 100644 (file)
@@ -464,6 +464,7 @@ static int __init crash_save_vmcoreinfo_init(void)
        VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
        VMCOREINFO_STRUCT_SIZE(mem_section);
        VMCOREINFO_OFFSET(mem_section, section_mem_map);
+       VMCOREINFO_NUMBER(SECTION_SIZE_BITS);
        VMCOREINFO_NUMBER(MAX_PHYSMEM_BITS);
 #endif
        VMCOREINFO_STRUCT_SIZE(page);
index e1d274c..e6fd2b3 100644 (file)
@@ -60,6 +60,7 @@ struct cred init_cred = {
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
+       .ucounts                = &init_ucounts,
 };
 
 static inline void set_cred_subscribers(struct cred *cred, int n)
@@ -119,6 +120,8 @@ static void put_cred_rcu(struct rcu_head *rcu)
        if (cred->group_info)
                put_group_info(cred->group_info);
        free_uid(cred->user);
+       if (cred->ucounts)
+               put_ucounts(cred->ucounts);
        put_user_ns(cred->user_ns);
        kmem_cache_free(cred_jar, cred);
 }
@@ -222,6 +225,7 @@ struct cred *cred_alloc_blank(void)
 #ifdef CONFIG_DEBUG_CREDENTIALS
        new->magic = CRED_MAGIC;
 #endif
+       new->ucounts = get_ucounts(&init_ucounts);
 
        if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
@@ -284,6 +288,11 @@ struct cred *prepare_creds(void)
 
        if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
+
+       new->ucounts = get_ucounts(new->ucounts);
+       if (!new->ucounts)
+               goto error;
+
        validate_creds(new);
        return new;
 
@@ -351,7 +360,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
                kdebug("share_creds(%p{%d,%d})",
                       p->cred, atomic_read(&p->cred->usage),
                       read_cred_subscribers(p->cred));
-               atomic_inc(&p->cred->user->processes);
+               inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
                return 0;
        }
 
@@ -363,6 +372,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
                ret = create_user_ns(new);
                if (ret < 0)
                        goto error_put;
+               ret = set_cred_ucounts(new);
+               if (ret < 0)
+                       goto error_put;
        }
 
 #ifdef CONFIG_KEYS
@@ -384,8 +396,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
        }
 #endif
 
-       atomic_inc(&new->user->processes);
        p->cred = p->real_cred = get_cred(new);
+       inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
        alter_cred_subscribers(new, 2);
        validate_creds(new);
        return 0;
@@ -485,12 +497,12 @@ int commit_creds(struct cred *new)
         * in set_user().
         */
        alter_cred_subscribers(new, 2);
-       if (new->user != old->user)
-               atomic_inc(&new->user->processes);
+       if (new->user != old->user || new->user_ns != old->user_ns)
+               inc_rlimit_ucounts(new->ucounts, UCOUNT_RLIMIT_NPROC, 1);
        rcu_assign_pointer(task->real_cred, new);
        rcu_assign_pointer(task->cred, new);
        if (new->user != old->user)
-               atomic_dec(&old->user->processes);
+               dec_rlimit_ucounts(old->ucounts, UCOUNT_RLIMIT_NPROC, 1);
        alter_cred_subscribers(old, -2);
 
        /* send notifications */
@@ -653,6 +665,31 @@ int cred_fscmp(const struct cred *a, const struct cred *b)
 }
 EXPORT_SYMBOL(cred_fscmp);
 
+int set_cred_ucounts(struct cred *new)
+{
+       struct task_struct *task = current;
+       const struct cred *old = task->real_cred;
+       struct ucounts *old_ucounts = new->ucounts;
+
+       if (new->user == old->user && new->user_ns == old->user_ns)
+               return 0;
+
+       /*
+        * This optimization is needed because alloc_ucounts() uses locks
+        * for table lookups.
+        */
+       if (old_ucounts && old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
+               return 0;
+
+       if (!(new->ucounts = alloc_ucounts(new->user_ns, new->euid)))
+               return -EAGAIN;
+
+       if (old_ucounts)
+               put_ucounts(old_ucounts);
+
+       return 0;
+}
+
 /*
  * initialise the credentials stuff
  */
@@ -719,6 +756,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
 
+       new->ucounts = get_ucounts(new->ucounts);
+       if (!new->ucounts)
+               goto error;
+
        put_cred(old);
        validate_creds(new);
        return new;
index 1baa96a..622410c 100644 (file)
@@ -2488,7 +2488,6 @@ static void kdb_sysinfo(struct sysinfo *val)
 static int kdb_summary(int argc, const char **argv)
 {
        time64_t now;
-       struct tm tm;
        struct sysinfo val;
 
        if (argc)
@@ -2502,13 +2501,7 @@ static int kdb_summary(int argc, const char **argv)
        kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
 
        now = __ktime_get_real_seconds();
-       time64_to_tm(now, 0, &tm);
-       kdb_printf("date       %04ld-%02d-%02d %02d:%02d:%02d "
-                  "tz_minuteswest %d\n",
-               1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
-               tm.tm_hour, tm.tm_min, tm.tm_sec,
-               sys_tz.tz_minuteswest);
-
+       kdb_printf("date       %ptTs tz_minuteswest %d\n", &now, sys_tz.tz_minuteswest);
        kdb_sysinfo(&val);
        kdb_printf("uptime     ");
        if (val.uptime > (24*60*60)) {
index 91bb666..9f50d22 100644 (file)
@@ -609,23 +609,25 @@ unsigned long kdb_task_state_string(const char *s)
  */
 char kdb_task_state_char (const struct task_struct *p)
 {
-       int cpu;
-       char state;
+       unsigned int p_state;
        unsigned long tmp;
+       char state;
+       int cpu;
 
        if (!p ||
            copy_from_kernel_nofault(&tmp, (char *)p, sizeof(unsigned long)))
                return 'E';
 
        cpu = kdb_process_cpu(p);
-       state = (p->state == 0) ? 'R' :
-               (p->state < 0) ? 'U' :
-               (p->state & TASK_UNINTERRUPTIBLE) ? 'D' :
-               (p->state & TASK_STOPPED) ? 'T' :
-               (p->state & TASK_TRACED) ? 'C' :
+       p_state = READ_ONCE(p->__state);
+       state = (p_state == 0) ? 'R' :
+               (p_state < 0) ? 'U' :
+               (p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
+               (p_state & TASK_STOPPED) ? 'T' :
+               (p_state & TASK_TRACED) ? 'C' :
                (p->exit_state & EXIT_ZOMBIE) ? 'Z' :
                (p->exit_state & EXIT_DEAD) ? 'E' :
-               (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?';
+               (p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
        if (is_idle_task(p)) {
                /* Idle task.  Is it really idle, apart from the kdb
                 * interrupt? */
index 2772575..51530d5 100644 (file)
@@ -7,30 +7,64 @@
 #include <linux/sched.h>
 #include <linux/sched/task.h>
 #include <linux/sched/cputime.h>
+#include <linux/sched/clock.h>
 #include <linux/slab.h>
 #include <linux/taskstats.h>
-#include <linux/time.h>
 #include <linux/sysctl.h>
 #include <linux/delayacct.h>
 #include <linux/module.h>
 
-int delayacct_on __read_mostly = 1;    /* Delay accounting turned on/off */
-EXPORT_SYMBOL_GPL(delayacct_on);
+DEFINE_STATIC_KEY_FALSE(delayacct_key);
+int delayacct_on __read_mostly;        /* Delay accounting turned on/off */
 struct kmem_cache *delayacct_cache;
 
-static int __init delayacct_setup_disable(char *str)
+static void set_delayacct(bool enabled)
 {
-       delayacct_on = 0;
+       if (enabled) {
+               static_branch_enable(&delayacct_key);
+               delayacct_on = 1;
+       } else {
+               delayacct_on = 0;
+               static_branch_disable(&delayacct_key);
+       }
+}
+
+static int __init delayacct_setup_enable(char *str)
+{
+       delayacct_on = 1;
        return 1;
 }
-__setup("nodelayacct", delayacct_setup_disable);
+__setup("delayacct", delayacct_setup_enable);
 
 void delayacct_init(void)
 {
        delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT);
        delayacct_tsk_init(&init_task);
+       set_delayacct(delayacct_on);
 }
 
+#ifdef CONFIG_PROC_SYSCTL
+int sysctl_delayacct(struct ctl_table *table, int write, void *buffer,
+                    size_t *lenp, loff_t *ppos)
+{
+       int state = delayacct_on;
+       struct ctl_table t;
+       int err;
+
+       if (write && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       t = *table;
+       t.data = &state;
+       err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
+       if (err < 0)
+               return err;
+       if (write)
+               set_delayacct(state);
+       return err;
+}
+#endif
+
 void __delayacct_tsk_init(struct task_struct *tsk)
 {
        tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL);
@@ -42,10 +76,9 @@ void __delayacct_tsk_init(struct task_struct *tsk)
  * Finish delay accounting for a statistic using its timestamps (@start),
  * accumalator (@total) and @count
  */
-static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total,
-                         u32 *count)
+static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, u32 *count)
 {
-       s64 ns = ktime_get_ns() - *start;
+       s64 ns = local_clock() - *start;
        unsigned long flags;
 
        if (ns > 0) {
@@ -58,7 +91,7 @@ static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total,
 
 void __delayacct_blkio_start(void)
 {
-       current->delays->blkio_start = ktime_get_ns();
+       current->delays->blkio_start = local_clock();
 }
 
 /*
@@ -82,7 +115,7 @@ void __delayacct_blkio_end(struct task_struct *p)
        delayacct_end(&delays->lock, &delays->blkio_start, total, count);
 }
 
-int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
+int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
 {
        u64 utime, stime, stimescaled, utimescaled;
        unsigned long long t2, t3;
@@ -117,6 +150,9 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
        d->cpu_run_virtual_total =
                (tmp < (s64)d->cpu_run_virtual_total) ? 0 : tmp;
 
+       if (!tsk->delays)
+               return 0;
+
        /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
 
        raw_spin_lock_irqsave(&tsk->delays->lock, flags);
@@ -151,21 +187,20 @@ __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
 
 void __delayacct_freepages_start(void)
 {
-       current->delays->freepages_start = ktime_get_ns();
+       current->delays->freepages_start = local_clock();
 }
 
 void __delayacct_freepages_end(void)
 {
-       delayacct_end(
-               &current->delays->lock,
-               &current->delays->freepages_start,
-               &current->delays->freepages_delay,
-               &current->delays->freepages_count);
+       delayacct_end(&current->delays->lock,
+                     &current->delays->freepages_start,
+                     &current->delays->freepages_delay,
+                     &current->delays->freepages_count);
 }
 
 void __delayacct_thrashing_start(void)
 {
-       current->delays->thrashing_start = ktime_get_ns();
+       current->delays->thrashing_start = local_clock();
 }
 
 void __delayacct_thrashing_end(void)
index 8ca7d50..e50df8d 100644 (file)
@@ -335,6 +335,14 @@ void __init swiotlb_exit(void)
 }
 
 /*
+ * Return the offset into a iotlb slot required to keep the device happy.
+ */
+static unsigned int swiotlb_align_offset(struct device *dev, u64 addr)
+{
+       return addr & dma_get_min_align_mask(dev) & (IO_TLB_SIZE - 1);
+}
+
+/*
  * Bounce: copy the swiotlb buffer from or back to the original dma location
  */
 static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size,
@@ -346,10 +354,17 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
        size_t alloc_size = mem->slots[index].alloc_size;
        unsigned long pfn = PFN_DOWN(orig_addr);
        unsigned char *vaddr = phys_to_virt(tlb_addr);
+       unsigned int tlb_offset;
 
        if (orig_addr == INVALID_PHYS_ADDR)
                return;
 
+       tlb_offset = (tlb_addr & (IO_TLB_SIZE - 1)) -
+                    swiotlb_align_offset(dev, orig_addr);
+
+       orig_addr += tlb_offset;
+       alloc_size -= tlb_offset;
+
        if (size > alloc_size) {
                dev_WARN_ONCE(dev, 1,
                        "Buffer overflow detected. Allocation size: %zu. Mapping size: %zu.\n",
@@ -391,14 +406,6 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
 #define slot_addr(start, idx)  ((start) + ((idx) << IO_TLB_SHIFT))
 
 /*
- * Return the offset into a iotlb slot required to keep the device happy.
- */
-static unsigned int swiotlb_align_offset(struct device *dev, u64 addr)
-{
-       return addr & dma_get_min_align_mask(dev) & (IO_TLB_SIZE - 1);
-}
-
-/*
  * Carefully handle integer overflow which can occur when boundary_mask == ~0UL.
  */
 static inline unsigned long get_max_slots(unsigned long boundary_mask)
index fe88d6e..4576413 100644 (file)
@@ -132,6 +132,7 @@ task_function_call(struct task_struct *p, remote_function_f func, void *info)
 
 /**
  * cpu_function_call - call a function on the cpu
+ * @cpu:       target cpu to queue this function
  * @func:      the function to be called
  * @info:      the function call argument
  *
@@ -3821,9 +3822,16 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
                                        struct task_struct *task)
 {
        struct perf_cpu_context *cpuctx;
-       struct pmu *pmu = ctx->pmu;
+       struct pmu *pmu;
 
        cpuctx = __get_cpu_context(ctx);
+
+       /*
+        * HACK: for HETEROGENEOUS the task context might have switched to a
+        * different PMU, force (re)set the context,
+        */
+       pmu = ctx->pmu = cpuctx->ctx.pmu;
+
        if (cpuctx->task_ctx == ctx) {
                if (cpuctx->sched_cb_usage)
                        __perf_pmu_sched_task(cpuctx, true);
@@ -6669,10 +6677,10 @@ out:
        return data->aux_size;
 }
 
-long perf_pmu_snapshot_aux(struct perf_buffer *rb,
-                          struct perf_event *event,
-                          struct perf_output_handle *handle,
-                          unsigned long size)
+static long perf_pmu_snapshot_aux(struct perf_buffer *rb,
+                                 struct perf_event *event,
+                                 struct perf_output_handle *handle,
+                                 unsigned long size)
 {
        unsigned long flags;
        long ret;
@@ -8682,13 +8690,12 @@ static void perf_event_switch(struct task_struct *task,
                },
        };
 
-       if (!sched_in && task->state == TASK_RUNNING)
+       if (!sched_in && task->on_rq) {
                switch_event.event_id.header.misc |=
                                PERF_RECORD_MISC_SWITCH_OUT_PREEMPT;
+       }
 
-       perf_iterate_sb(perf_event_switch_output,
-                      &switch_event,
-                      NULL);
+       perf_iterate_sb(perf_event_switch_output, &switch_event, NULL);
 }
 
 /*
@@ -11919,6 +11926,7 @@ again:
  * @pid:               target pid
  * @cpu:               target cpu
  * @group_fd:          group leader event fd
+ * @flags:             perf event open flags
  */
 SYSCALL_DEFINE5(perf_event_open,
                struct perf_event_attr __user *, attr_uptr,
@@ -12375,6 +12383,8 @@ err_fd:
  * @attr: attributes of the counter to create
  * @cpu: cpu in which the counter is bound
  * @task: task to profile (NULL for percpu)
+ * @overflow_handler: callback to trigger when we hit the event
+ * @context: context data could be used in overflow_handler callback
  */
 struct perf_event *
 perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
index b48d703..8359734 100644 (file)
@@ -451,6 +451,7 @@ int register_perf_hw_breakpoint(struct perf_event *bp)
  * register_user_hw_breakpoint - register a hardware breakpoint for user space
  * @attr: breakpoint attributes
  * @triggered: callback to trigger when we hit the breakpoint
+ * @context: context data could be used in the triggered callback
  * @tsk: pointer to 'task_struct' of the process to which the address belongs
  */
 struct perf_event *
@@ -550,6 +551,7 @@ EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
  * register_wide_hw_breakpoint - register a wide breakpoint in the kernel
  * @attr: breakpoint attributes
  * @triggered: callback to trigger when we hit the breakpoint
+ * @context: context data could be used in the triggered callback
  *
  * @return a set of per_cpu pointers to perf events
  */
index 6addc97..a481ef6 100644 (file)
@@ -453,6 +453,7 @@ static int update_ref_ctr(struct uprobe *uprobe, struct mm_struct *mm,
  * that have fixed length instructions.
  *
  * uprobe_write_opcode - write the opcode at a given virtual address.
+ * @auprobe: arch specific probepoint information.
  * @mm: the probed process address space.
  * @vaddr: the virtual address to store the opcode.
  * @opcode: opcode to be written at @vaddr.
index fd1c041..9a89e7f 100644 (file)
@@ -162,7 +162,6 @@ static void __exit_signal(struct task_struct *tsk)
                flush_sigqueue(&sig->shared_pending);
                tty_kref_put(tty);
        }
-       exit_task_sigqueue_cache(tsk);
 }
 
 static void delayed_put_task_struct(struct rcu_head *rhp)
@@ -189,7 +188,7 @@ repeat:
        /* don't need to get the RCU readlock here - the process is dead and
         * can't be modifying its own credentials. But shut RCU-lockdep up */
        rcu_read_lock();
-       atomic_dec(&__task_cred(p)->user->processes);
+       dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
        rcu_read_unlock();
 
        cgroup_release(p);
index dc06afd..b4386ff 100644 (file)
@@ -425,7 +425,7 @@ static int memcg_charge_kernel_stack(struct task_struct *tsk)
 
 static void release_task_stack(struct task_struct *tsk)
 {
-       if (WARN_ON(tsk->state != TASK_DEAD))
+       if (WARN_ON(READ_ONCE(tsk->__state) != TASK_DEAD))
                return;  /* Better to leak the stack than to free prematurely */
 
        account_kernel_stack(tsk, -1);
@@ -742,6 +742,7 @@ void __put_task_struct(struct task_struct *tsk)
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
        put_signal_struct(tsk->signal);
+       sched_core_free(tsk);
 
        if (!profile_handoff_task(tsk))
                free_task(tsk);
@@ -824,9 +825,14 @@ void __init fork_init(void)
        init_task.signal->rlim[RLIMIT_SIGPENDING] =
                init_task.signal->rlim[RLIMIT_NPROC];
 
-       for (i = 0; i < UCOUNT_COUNTS; i++)
+       for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++)
                init_user_ns.ucount_max[i] = max_threads/2;
 
+       set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_NPROC, task_rlimit(&init_task, RLIMIT_NPROC));
+       set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MSGQUEUE, task_rlimit(&init_task, RLIMIT_MSGQUEUE));
+       set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_SIGPENDING, task_rlimit(&init_task, RLIMIT_SIGPENDING));
+       set_rlimit_ucount_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, task_rlimit(&init_task, RLIMIT_MEMLOCK));
+
 #ifdef CONFIG_VMAP_STACK
        cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
                          NULL, free_vm_stack_cache);
@@ -1977,8 +1983,7 @@ static __latent_entropy struct task_struct *copy_process(
        DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
        retval = -EAGAIN;
-       if (atomic_read(&p->real_cred->user->processes) >=
-                       task_rlimit(p, RLIMIT_NPROC)) {
+       if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
                if (p->real_cred->user != INIT_USER &&
                    !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
                        goto bad_fork_free;
@@ -1999,7 +2004,7 @@ static __latent_entropy struct task_struct *copy_process(
                goto bad_fork_cleanup_count;
 
        delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
-       p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER | PF_IDLE);
+       p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER | PF_IDLE | PF_NO_SETAFFINITY);
        p->flags |= PF_FORKNOEXEC;
        INIT_LIST_HEAD(&p->children);
        INIT_LIST_HEAD(&p->sibling);
@@ -2008,7 +2013,6 @@ static __latent_entropy struct task_struct *copy_process(
        spin_lock_init(&p->alloc_lock);
 
        init_sigpending(&p->pending);
-       p->sigqueue_cache = NULL;
 
        p->utime = p->stime = p->gtime = 0;
 #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
@@ -2250,6 +2254,8 @@ static __latent_entropy struct task_struct *copy_process(
 
        klp_copy_process(p);
 
+       sched_core_fork(p);
+
        spin_lock(&current->sighand->siglock);
 
        /*
@@ -2337,6 +2343,7 @@ static __latent_entropy struct task_struct *copy_process(
        return p;
 
 bad_fork_cancel_cgroup:
+       sched_core_free(p);
        spin_unlock(&current->sighand->siglock);
        write_unlock_irq(&tasklist_lock);
        cgroup_cancel_fork(p, args);
@@ -2385,10 +2392,10 @@ bad_fork_cleanup_threadgroup_lock:
 #endif
        delayacct_tsk_free(p);
 bad_fork_cleanup_count:
-       atomic_dec(&p->cred->user->processes);
+       dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
        exit_creds(p);
 bad_fork_free:
-       p->state = TASK_DEAD;
+       WRITE_ONCE(p->__state, TASK_DEAD);
        put_task_stack(p);
        delayed_free_task(p);
 fork_out:
@@ -2408,7 +2415,7 @@ static inline void init_idle_pids(struct task_struct *idle)
        }
 }
 
-struct task_struct *fork_idle(int cpu)
+struct task_struct * __init fork_idle(int cpu)
 {
        struct task_struct *task;
        struct kernel_clone_args args = {
@@ -2998,6 +3005,12 @@ int ksys_unshare(unsigned long unshare_flags)
        if (err)
                goto bad_unshare_cleanup_cred;
 
+       if (new_cred) {
+               err = set_cred_ucounts(new_cred);
+               if (err)
+                       goto bad_unshare_cleanup_cred;
+       }
+
        if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
                if (do_sysvsem) {
                        /*
index dc520f0..45ab36f 100644 (file)
@@ -58,7 +58,7 @@ bool __refrigerator(bool check_kthr_stop)
        /* Hmm, should we be allowed to suspend when there are realtime
           processes around? */
        bool was_frozen = false;
-       long save = current->state;
+       unsigned int save = get_current_state();
 
        pr_debug("%s entered refrigerator\n", current->comm);
 
index 4938a00..2ecb075 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/jhash.h>
 #include <linux/pagemap.h>
 #include <linux/syscalls.h>
-#include <linux/hugetlb.h>
 #include <linux/freezer.h>
 #include <linux/memblock.h>
 #include <linux/fault-inject.h>
@@ -650,7 +649,7 @@ again:
 
                key->both.offset |= FUT_OFF_INODE; /* inode-based key */
                key->shared.i_seq = get_inode_sequence_number(inode);
-               key->shared.pgoff = basepage_index(tail);
+               key->shared.pgoff = page_to_pgoff(tail);
                rcu_read_unlock();
        }
 
@@ -1728,12 +1727,9 @@ retry_private:
                                return ret;
                }
 
-               if (!(flags & FLAGS_SHARED)) {
-                       cond_resched();
-                       goto retry_private;
-               }
-
                cond_resched();
+               if (!(flags & FLAGS_SHARED))
+                       goto retry_private;
                goto retry;
        }
 
@@ -1874,7 +1870,7 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
         * If the caller intends to requeue more than 1 waiter to pifutex,
         * force futex_lock_pi_atomic() to set the FUTEX_WAITERS bit now,
         * as we have means to handle the possible fault.  If not, don't set
-        * the bit unecessarily as it will force the subsequent unlock to enter
+        * the bit unnecessarily as it will force the subsequent unlock to enter
         * the kernel.
         */
        top_waiter = futex_top_waiter(hb1, key1);
@@ -2103,7 +2099,7 @@ retry_private:
                        continue;
 
                /*
-                * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always
+                * FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI should always
                 * be paired with each other and no other futex ops.
                 *
                 * We should never be requeueing a futex_q with a pi_state,
@@ -2318,7 +2314,7 @@ retry:
 }
 
 /*
- * PI futexes can not be requeued and must remove themself from the
+ * PI futexes can not be requeued and must remove themselves from the
  * hash bucket. The hash bucket lock (i.e. lock_ptr) is held.
  */
 static void unqueue_me_pi(struct futex_q *q)
@@ -2786,7 +2782,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
        if (refill_pi_state_cache())
                return -ENOMEM;
 
-       to = futex_setup_timer(time, &timeout, FLAGS_CLOCKRT, 0);
+       to = futex_setup_timer(time, &timeout, flags, 0);
 
 retry:
        ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE);
@@ -2903,7 +2899,7 @@ no_block:
         */
        res = fixup_owner(uaddr, &q, !ret);
        /*
-        * If fixup_owner() returned an error, proprogate that.  If it acquired
+        * If fixup_owner() returned an error, propagate that.  If it acquired
         * the lock, clear our -ETIMEDOUT or -EINTR.
         */
        if (res)
@@ -3280,7 +3276,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                 */
                res = fixup_owner(uaddr2, &q, !ret);
                /*
-                * If fixup_owner() returned an error, proprogate that.  If it
+                * If fixup_owner() returned an error, propagate that.  If it
                 * acquired the lock, clear -ETIMEDOUT or -EINTR.
                 */
                if (res)
@@ -3678,7 +3674,7 @@ void futex_exec_release(struct task_struct *tsk)
 {
        /*
         * The state handling is done for consistency, but in the case of
-        * exec() there is no way to prevent futher damage as the PID stays
+        * exec() there is no way to prevent further damage as the PID stays
         * the same. But for the unlikely and arguably buggy case that a
         * futex is held on exec(), this provides at least as much state
         * consistency protection which is possible.
@@ -3710,12 +3706,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 
        if (op & FUTEX_CLOCK_REALTIME) {
                flags |= FLAGS_CLOCKRT;
-               if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
+               if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI &&
+                   cmd != FUTEX_LOCK_PI2)
                        return -ENOSYS;
        }
 
        switch (cmd) {
        case FUTEX_LOCK_PI:
+       case FUTEX_LOCK_PI2:
        case FUTEX_UNLOCK_PI:
        case FUTEX_TRYLOCK_PI:
        case FUTEX_WAIT_REQUEUE_PI:
@@ -3742,6 +3740,9 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
        case FUTEX_WAKE_OP:
                return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
        case FUTEX_LOCK_PI:
+               flags |= FLAGS_CLOCKRT;
+               fallthrough;
+       case FUTEX_LOCK_PI2:
                return futex_lock_pi(uaddr, flags, timeout, 0);
        case FUTEX_UNLOCK_PI:
                return futex_unlock_pi(uaddr, flags);
@@ -3762,6 +3763,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd)
        switch (cmd) {
        case FUTEX_WAIT:
        case FUTEX_LOCK_PI:
+       case FUTEX_LOCK_PI2:
        case FUTEX_WAIT_BITSET:
        case FUTEX_WAIT_REQUEUE_PI:
                return true;
index 396ebae..b0ce8b3 100644 (file)
@@ -196,7 +196,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
                        last_break = jiffies;
                }
                /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
-               if (t->state == TASK_UNINTERRUPTIBLE)
+               if (READ_ONCE(t->__state) == TASK_UNINTERRUPTIBLE)
                        check_hung_task(t, timeout);
        }
  unlock:
index d79ef24..fbc54c2 100644 (file)
@@ -70,6 +70,11 @@ config IRQ_DOMAIN_HIERARCHY
        bool
        select IRQ_DOMAIN
 
+# Support for obsolete non-mapping irq domains
+config IRQ_DOMAIN_NOMAP
+       bool
+       select IRQ_DOMAIN
+
 # Support for hierarchical fasteoi+edge and fasteoi+level handlers
 config IRQ_FASTEOI_HIERARCHY_HANDLERS
        bool
index 8cc8e57..7f04c7d 100644 (file)
@@ -481,7 +481,7 @@ void handle_nested_irq(unsigned int irq)
        for_each_action_of_desc(desc, action)
                action_ret |= action->thread_fn(action->irq, action->dev_id);
 
-       if (!noirqdebug)
+       if (!irq_settings_no_debug(desc))
                note_interrupt(desc, action_ret);
 
        raw_spin_lock_irq(&desc->lock);
index 762a928..221d80c 100644 (file)
@@ -197,7 +197,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
 
        add_interrupt_randomness(desc->irq_data.irq, flags);
 
-       if (!noirqdebug)
+       if (!irq_settings_no_debug(desc))
                note_interrupt(desc, retval);
        return retval;
 }
index 4a617d7..f4dd518 100644 (file)
@@ -632,14 +632,8 @@ void irq_init_desc(unsigned int irq)
 
 #endif /* !CONFIG_SPARSE_IRQ */
 
-/**
- * generic_handle_irq - Invoke the handler for a particular irq
- * @irq:       The irq number to handle
- *
- */
-int generic_handle_irq(unsigned int irq)
+int handle_irq_desc(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_data *data;
 
        if (!desc)
@@ -652,11 +646,40 @@ int generic_handle_irq(unsigned int irq)
        generic_handle_irq_desc(desc);
        return 0;
 }
+EXPORT_SYMBOL_GPL(handle_irq_desc);
+
+/**
+ * generic_handle_irq - Invoke the handler for a particular irq
+ * @irq:       The irq number to handle
+ *
+ */
+int generic_handle_irq(unsigned int irq)
+{
+       return handle_irq_desc(irq_to_desc(irq));
+}
 EXPORT_SYMBOL_GPL(generic_handle_irq);
 
+#ifdef CONFIG_IRQ_DOMAIN
+/**
+ * generic_handle_domain_irq - Invoke the handler for a HW irq belonging
+ *                             to a domain, usually for a non-root interrupt
+ *                             controller
+ * @domain:    The domain where to perform the lookup
+ * @hwirq:     The HW irq number to convert to a logical one
+ *
+ * Returns:    0 on success, or -EINVAL if conversion has failed
+ *
+ */
+int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
+{
+       return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
+}
+EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
+
 #ifdef CONFIG_HANDLE_DOMAIN_IRQ
 /**
- * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain
+ * handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
+ *                     usually for a root interrupt controller
  * @domain:    The domain where to perform the lookup
  * @hwirq:     The HW irq number to convert to a logical one
  * @lookup:    Whether to perform the domain lookup or not
@@ -664,37 +687,27 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
  *
  * Returns:    0 on success, or -EINVAL if conversion has failed
  */
-int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
-                       bool lookup, struct pt_regs *regs)
+int handle_domain_irq(struct irq_domain *domain,
+                     unsigned int hwirq, struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       unsigned int irq = hwirq;
+       struct irq_desc *desc;
        int ret = 0;
 
        irq_enter();
 
-#ifdef CONFIG_IRQ_DOMAIN
-       if (lookup)
-               irq = irq_find_mapping(domain, hwirq);
-#endif
-
-       /*
-        * Some hardware gives randomly wrong interrupts.  Rather
-        * than crashing, do something sensible.
-        */
-       if (unlikely(!irq || irq >= nr_irqs)) {
-               ack_bad_irq(irq);
+       /* The irqdomain code provides boundary checks */
+       desc = irq_resolve_mapping(domain, hwirq);
+       if (likely(desc))
+               handle_irq_desc(desc);
+       else
                ret = -EINVAL;
-       } else {
-               generic_handle_irq(irq);
-       }
 
        irq_exit();
        set_irq_regs(old_regs);
        return ret;
 }
 
-#ifdef CONFIG_IRQ_DOMAIN
 /**
  * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
  * @domain:    The domain where to perform the lookup
@@ -709,7 +722,7 @@ int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
                      struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       unsigned int irq;
+       struct irq_desc *desc;
        int ret = 0;
 
        /*
@@ -717,14 +730,14 @@ int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
         */
        WARN_ON(!in_nmi());
 
-       irq = irq_find_mapping(domain, hwirq);
+       desc = irq_resolve_mapping(domain, hwirq);
 
        /*
         * ack_bad_irq is not NMI-safe, just report
         * an invalid interrupt.
         */
-       if (likely(irq))
-               generic_handle_irq(irq);
+       if (likely(desc))
+               handle_irq_desc(desc);
        else
                ret = -EINVAL;
 
index 6284443..51c483c 100644 (file)
@@ -146,7 +146,11 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
 
        static atomic_t unknown_domains;
 
-       domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
+       if (WARN_ON((size && direct_max) ||
+                   (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max)))
+               return NULL;
+
+       domain = kzalloc_node(struct_size(domain, revmap, size),
                              GFP_KERNEL, of_node_to_nid(to_of_node(fwnode)));
        if (!domain)
                return NULL;
@@ -209,12 +213,18 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
 
        /* Fill structure */
        INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
-       mutex_init(&domain->revmap_tree_mutex);
+       mutex_init(&domain->revmap_mutex);
        domain->ops = ops;
        domain->host_data = host_data;
        domain->hwirq_max = hwirq_max;
+
+       if (direct_max) {
+               size = direct_max;
+               domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP;
+       }
+
        domain->revmap_size = size;
-       domain->revmap_direct_max_irq = direct_max;
+
        irq_domain_check_hierarchy(domain);
 
        mutex_lock(&irq_domain_mutex);
@@ -482,29 +492,39 @@ struct irq_domain *irq_get_default_host(void)
        return irq_default_domain;
 }
 
+static bool irq_domain_is_nomap(struct irq_domain *domain)
+{
+       return IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) &&
+              (domain->flags & IRQ_DOMAIN_FLAG_NO_MAP);
+}
+
 static void irq_domain_clear_mapping(struct irq_domain *domain,
                                     irq_hw_number_t hwirq)
 {
-       if (hwirq < domain->revmap_size) {
-               domain->linear_revmap[hwirq] = 0;
-       } else {
-               mutex_lock(&domain->revmap_tree_mutex);
+       if (irq_domain_is_nomap(domain))
+               return;
+
+       mutex_lock(&domain->revmap_mutex);
+       if (hwirq < domain->revmap_size)
+               rcu_assign_pointer(domain->revmap[hwirq], NULL);
+       else
                radix_tree_delete(&domain->revmap_tree, hwirq);
-               mutex_unlock(&domain->revmap_tree_mutex);
-       }
+       mutex_unlock(&domain->revmap_mutex);
 }
 
 static void irq_domain_set_mapping(struct irq_domain *domain,
                                   irq_hw_number_t hwirq,
                                   struct irq_data *irq_data)
 {
-       if (hwirq < domain->revmap_size) {
-               domain->linear_revmap[hwirq] = irq_data->irq;
-       } else {
-               mutex_lock(&domain->revmap_tree_mutex);
+       if (irq_domain_is_nomap(domain))
+               return;
+
+       mutex_lock(&domain->revmap_mutex);
+       if (hwirq < domain->revmap_size)
+               rcu_assign_pointer(domain->revmap[hwirq], irq_data);
+       else
                radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
-               mutex_unlock(&domain->revmap_tree_mutex);
-       }
+       mutex_unlock(&domain->revmap_mutex);
 }
 
 static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
@@ -604,6 +624,7 @@ void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 }
 EXPORT_SYMBOL_GPL(irq_domain_associate_many);
 
+#ifdef CONFIG_IRQ_DOMAIN_NOMAP
 /**
  * irq_create_direct_mapping() - Allocate an irq for direct mapping
  * @domain: domain to allocate the irq for or NULL for default domain
@@ -628,9 +649,9 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
                pr_debug("create_direct virq allocation failed\n");
                return 0;
        }
-       if (virq >= domain->revmap_direct_max_irq) {
+       if (virq >= domain->revmap_size) {
                pr_err("ERROR: no free irqs available below %i maximum\n",
-                       domain->revmap_direct_max_irq);
+                       domain->revmap_size);
                irq_free_desc(virq);
                return 0;
        }
@@ -644,6 +665,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
        return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
+#endif
 
 /**
  * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
@@ -862,37 +884,53 @@ void irq_dispose_mapping(unsigned int virq)
 EXPORT_SYMBOL_GPL(irq_dispose_mapping);
 
 /**
- * irq_find_mapping() - Find a linux irq from a hw irq number.
+ * __irq_resolve_mapping() - Find a linux irq from a hw irq number.
  * @domain: domain owning this hardware interrupt
  * @hwirq: hardware irq number in that domain space
+ * @irq: optional pointer to return the Linux irq if required
+ *
+ * Returns the interrupt descriptor.
  */
-unsigned int irq_find_mapping(struct irq_domain *domain,
-                             irq_hw_number_t hwirq)
+struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain,
+                                      irq_hw_number_t hwirq,
+                                      unsigned int *irq)
 {
+       struct irq_desc *desc = NULL;
        struct irq_data *data;
 
        /* Look for default domain if necessary */
        if (domain == NULL)
                domain = irq_default_domain;
        if (domain == NULL)
-               return 0;
+               return desc;
+
+       if (irq_domain_is_nomap(domain)) {
+               if (hwirq < domain->revmap_size) {
+                       data = irq_domain_get_irq_data(domain, hwirq);
+                       if (data && data->hwirq == hwirq)
+                               desc = irq_data_to_desc(data);
+               }
 
-       if (hwirq < domain->revmap_direct_max_irq) {
-               data = irq_domain_get_irq_data(domain, hwirq);
-               if (data && data->hwirq == hwirq)
-                       return hwirq;
+               return desc;
        }
 
+       rcu_read_lock();
        /* Check if the hwirq is in the linear revmap. */
        if (hwirq < domain->revmap_size)
-               return domain->linear_revmap[hwirq];
+               data = rcu_dereference(domain->revmap[hwirq]);
+       else
+               data = radix_tree_lookup(&domain->revmap_tree, hwirq);
+
+       if (likely(data)) {
+               desc = irq_data_to_desc(data);
+               if (irq)
+                       *irq = data->irq;
+       }
 
-       rcu_read_lock();
-       data = radix_tree_lookup(&domain->revmap_tree, hwirq);
        rcu_read_unlock();
-       return data ? data->irq : 0;
+       return desc;
 }
-EXPORT_SYMBOL_GPL(irq_find_mapping);
+EXPORT_SYMBOL_GPL(__irq_resolve_mapping);
 
 /**
  * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
@@ -1468,15 +1506,20 @@ static void irq_domain_fix_revmap(struct irq_data *d)
 {
        void __rcu **slot;
 
-       if (d->hwirq < d->domain->revmap_size)
-               return; /* Not using radix tree. */
+       if (irq_domain_is_nomap(d->domain))
+               return;
 
        /* Fix up the revmap. */
-       mutex_lock(&d->domain->revmap_tree_mutex);
-       slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq);
-       if (slot)
-               radix_tree_replace_slot(&d->domain->revmap_tree, slot, d);
-       mutex_unlock(&d->domain->revmap_tree_mutex);
+       mutex_lock(&d->domain->revmap_mutex);
+       if (d->hwirq < d->domain->revmap_size) {
+               /* Not using radix tree */
+               rcu_assign_pointer(d->domain->revmap[d->hwirq], d);
+       } else {
+               slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq);
+               if (slot)
+                       radix_tree_replace_slot(&d->domain->revmap_tree, slot, d);
+       }
+       mutex_unlock(&d->domain->revmap_mutex);
 }
 
 /**
@@ -1828,8 +1871,7 @@ static void
 irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind)
 {
        seq_printf(m, "%*sname:   %s\n", ind, "", d->name);
-       seq_printf(m, "%*ssize:   %u\n", ind + 1, "",
-                  d->revmap_size + d->revmap_direct_max_irq);
+       seq_printf(m, "%*ssize:   %u\n", ind + 1, "", d->revmap_size);
        seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount);
        seq_printf(m, "%*sflags:  0x%08x\n", ind +1 , "", d->flags);
        if (d->ops && d->ops->debug_show)
index 4c14356..ef30b47 100644 (file)
@@ -441,7 +441,8 @@ out_unlock:
        return ret;
 }
 
-int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
+static int __irq_set_affinity(unsigned int irq, const struct cpumask *mask,
+                             bool force)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
@@ -456,6 +457,36 @@ int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
        return ret;
 }
 
+/**
+ * irq_set_affinity - Set the irq affinity of a given irq
+ * @irq:       Interrupt to set affinity
+ * @cpumask:   cpumask
+ *
+ * Fails if cpumask does not contain an online CPU
+ */
+int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+{
+       return __irq_set_affinity(irq, cpumask, false);
+}
+EXPORT_SYMBOL_GPL(irq_set_affinity);
+
+/**
+ * irq_force_affinity - Force the irq affinity of a given irq
+ * @irq:       Interrupt to set affinity
+ * @cpumask:   cpumask
+ *
+ * Same as irq_set_affinity, but without checking the mask against
+ * online cpus.
+ *
+ * Solely for low level cpu hotplug code, where we need to make per
+ * cpu interrupts affine before the cpu becomes online.
+ */
+int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask)
+{
+       return __irq_set_affinity(irq, cpumask, true);
+}
+EXPORT_SYMBOL_GPL(irq_force_affinity);
+
 int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m)
 {
        unsigned long flags;
@@ -1686,8 +1717,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                if (new->flags & IRQF_PERCPU) {
                        irqd_set(&desc->irq_data, IRQD_PER_CPU);
                        irq_settings_set_per_cpu(desc);
+                       if (new->flags & IRQF_NO_DEBUG)
+                               irq_settings_set_no_debug(desc);
                }
 
+               if (noirqdebug)
+                       irq_settings_set_no_debug(desc);
+
                if (new->flags & IRQF_ONESHOT)
                        desc->istate |= IRQS_ONESHOT;
 
index 403378b..7b7efb1 100644 (file)
@@ -18,6 +18,7 @@ enum {
        _IRQ_IS_POLLED          = IRQ_IS_POLLED,
        _IRQ_DISABLE_UNLAZY     = IRQ_DISABLE_UNLAZY,
        _IRQ_HIDDEN             = IRQ_HIDDEN,
+       _IRQ_NO_DEBUG           = IRQ_NO_DEBUG,
        _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
 };
 
@@ -33,6 +34,7 @@ enum {
 #define IRQ_IS_POLLED          GOT_YOU_MORON
 #define IRQ_DISABLE_UNLAZY     GOT_YOU_MORON
 #define IRQ_HIDDEN             GOT_YOU_MORON
+#define IRQ_NO_DEBUG           GOT_YOU_MORON
 #undef IRQF_MODIFY_MASK
 #define IRQF_MODIFY_MASK       GOT_YOU_MORON
 
@@ -174,3 +176,13 @@ static inline bool irq_settings_is_hidden(struct irq_desc *desc)
 {
        return desc->status_use_accessors & _IRQ_HIDDEN;
 }
+
+static inline void irq_settings_set_no_debug(struct irq_desc *desc)
+{
+       desc->status_use_accessors |= _IRQ_NO_DEBUG;
+}
+
+static inline bool irq_settings_no_debug(struct irq_desc *desc)
+{
+       return desc->status_use_accessors & _IRQ_NO_DEBUG;
+}
index ba39fbb..bdb0681 100644 (file)
@@ -309,7 +309,7 @@ EXPORT_SYMBOL_GPL(jump_label_rate_limit);
 static int addr_conflict(struct jump_entry *entry, void *start, void *end)
 {
        if (jump_entry_code(entry) <= (unsigned long)end &&
-           jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE > (unsigned long)start)
+           jump_entry_code(entry) + jump_entry_size(entry) > (unsigned long)start)
                return 1;
 
        return 0;
@@ -483,13 +483,14 @@ void __init jump_label_init(void)
 
        for (iter = iter_start; iter < iter_stop; iter++) {
                struct static_key *iterk;
+               bool in_init;
 
                /* rewrite NOPs */
                if (jump_label_type(iter) == JUMP_LABEL_NOP)
                        arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
 
-               if (init_section_contains((void *)jump_entry_code(iter), 1))
-                       jump_entry_set_init(iter);
+               in_init = init_section_contains((void *)jump_entry_code(iter), 1);
+               jump_entry_set_init(iter, in_init);
 
                iterk = jump_entry_key(iter);
                if (iterk == key)
@@ -634,9 +635,10 @@ static int jump_label_add_module(struct module *mod)
 
        for (iter = iter_start; iter < iter_stop; iter++) {
                struct static_key *iterk;
+               bool in_init;
 
-               if (within_module_init(jump_entry_code(iter), mod))
-                       jump_entry_set_init(iter);
+               in_init = within_module_init(jump_entry_code(iter), mod);
+               jump_entry_set_init(iter, in_init);
 
                iterk = jump_entry_key(iter);
                if (iterk == key)
index 13dce3c..56016e8 100644 (file)
@@ -460,7 +460,7 @@ static void set_other_info_task_blocking(unsigned long *flags,
         * We may be instrumenting a code-path where current->state is already
         * something other than TASK_RUNNING.
         */
-       const bool is_running = current->state == TASK_RUNNING;
+       const bool is_running = task_is_running(current);
        /*
         * To avoid deadlock in case we are in an interrupt here and this is a
         * race with a task on the same CPU (KCSAN_INTERRUPT_WATCHER), provide a
index 745f08f..e41385a 100644 (file)
@@ -1183,23 +1183,6 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
 }
 NOKPROBE_SYMBOL(aggr_post_handler);
 
-static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
-                             int trapnr)
-{
-       struct kprobe *cur = __this_cpu_read(kprobe_instance);
-
-       /*
-        * if we faulted "during" the execution of a user specified
-        * probe handler, invoke just that probe's fault handler
-        */
-       if (cur && cur->fault_handler) {
-               if (cur->fault_handler(cur, regs, trapnr))
-                       return 1;
-       }
-       return 0;
-}
-NOKPROBE_SYMBOL(aggr_fault_handler);
-
 /* Walks the list and increments nmissed count for multiprobe case */
 void kprobes_inc_nmissed_count(struct kprobe *p)
 {
@@ -1330,7 +1313,6 @@ static void init_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
        ap->addr = p->addr;
        ap->flags = p->flags & ~KPROBE_FLAG_OPTIMIZED;
        ap->pre_handler = aggr_pre_handler;
-       ap->fault_handler = aggr_fault_handler;
        /* We don't care the kprobe which has gone. */
        if (p->post_handler && !kprobe_gone(p))
                ap->post_handler = aggr_post_handler;
@@ -2014,7 +1996,6 @@ int register_kretprobe(struct kretprobe *rp)
 
        rp->kp.pre_handler = pre_handler_kretprobe;
        rp->kp.post_handler = NULL;
-       rp->kp.fault_handler = NULL;
 
        /* Pre-allocate memory for max kretprobe instances */
        if (rp->maxactive <= 0) {
index fe3f2a4..6b0a30a 100644 (file)
@@ -68,16 +68,6 @@ enum KTHREAD_BITS {
        KTHREAD_SHOULD_PARK,
 };
 
-static inline void set_kthread_struct(void *kthread)
-{
-       /*
-        * We abuse ->set_child_tid to avoid the new member and because it
-        * can't be wrongly copied by copy_process(). We also rely on fact
-        * that the caller can't exec, so PF_KTHREAD can't be cleared.
-        */
-       current->set_child_tid = (__force void __user *)kthread;
-}
-
 static inline struct kthread *to_kthread(struct task_struct *k)
 {
        WARN_ON(!(k->flags & PF_KTHREAD));
@@ -103,6 +93,22 @@ static inline struct kthread *__to_kthread(struct task_struct *p)
        return kthread;
 }
 
+void set_kthread_struct(struct task_struct *p)
+{
+       struct kthread *kthread;
+
+       if (__to_kthread(p))
+               return;
+
+       kthread = kzalloc(sizeof(*kthread), GFP_KERNEL);
+       /*
+        * We abuse ->set_child_tid to avoid the new member and because it
+        * can't be wrongly copied by copy_process(). We also rely on fact
+        * that the caller can't exec, so PF_KTHREAD can't be cleared.
+        */
+       p->set_child_tid = (__force void __user *)kthread;
+}
+
 void free_kthread_struct(struct task_struct *k)
 {
        struct kthread *kthread;
@@ -272,8 +278,8 @@ static int kthread(void *_create)
        struct kthread *self;
        int ret;
 
-       self = kzalloc(sizeof(*self), GFP_KERNEL);
-       set_kthread_struct(self);
+       set_kthread_struct(current);
+       self = to_kthread(current);
 
        /* If user was SIGKILLed, I release the structure. */
        done = xchg(&create->done, NULL);
@@ -451,7 +457,7 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
 }
 EXPORT_SYMBOL(kthread_create_on_node);
 
-static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mask, long state)
+static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mask, unsigned int state)
 {
        unsigned long flags;
 
@@ -467,7 +473,7 @@ static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mas
        raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 }
 
-static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state)
+static void __kthread_bind(struct task_struct *p, unsigned int cpu, unsigned int state)
 {
        __kthread_bind_mask(p, cpumask_of(cpu), state);
 }
@@ -1093,8 +1099,38 @@ void kthread_flush_work(struct kthread_work *work)
 EXPORT_SYMBOL_GPL(kthread_flush_work);
 
 /*
- * This function removes the work from the worker queue. Also it makes sure
- * that it won't get queued later via the delayed work's timer.
+ * Make sure that the timer is neither set nor running and could
+ * not manipulate the work list_head any longer.
+ *
+ * The function is called under worker->lock. The lock is temporary
+ * released but the timer can't be set again in the meantime.
+ */
+static void kthread_cancel_delayed_work_timer(struct kthread_work *work,
+                                             unsigned long *flags)
+{
+       struct kthread_delayed_work *dwork =
+               container_of(work, struct kthread_delayed_work, work);
+       struct kthread_worker *worker = work->worker;
+
+       /*
+        * del_timer_sync() must be called to make sure that the timer
+        * callback is not running. The lock must be temporary released
+        * to avoid a deadlock with the callback. In the meantime,
+        * any queuing is blocked by setting the canceling counter.
+        */
+       work->canceling++;
+       raw_spin_unlock_irqrestore(&worker->lock, *flags);
+       del_timer_sync(&dwork->timer);
+       raw_spin_lock_irqsave(&worker->lock, *flags);
+       work->canceling--;
+}
+
+/*
+ * This function removes the work from the worker queue.
+ *
+ * It is called under worker->lock. The caller must make sure that
+ * the timer used by delayed work is not running, e.g. by calling
+ * kthread_cancel_delayed_work_timer().
  *
  * The work might still be in use when this function finishes. See the
  * current_work proceed by the worker.
@@ -1102,28 +1138,8 @@ EXPORT_SYMBOL_GPL(kthread_flush_work);
  * Return: %true if @work was pending and successfully canceled,
  *     %false if @work was not pending
  */
-static bool __kthread_cancel_work(struct kthread_work *work, bool is_dwork,
-                                 unsigned long *flags)
+static bool __kthread_cancel_work(struct kthread_work *work)
 {
-       /* Try to cancel the timer if exists. */
-       if (is_dwork) {
-               struct kthread_delayed_work *dwork =
-                       container_of(work, struct kthread_delayed_work, work);
-               struct kthread_worker *worker = work->worker;
-
-               /*
-                * del_timer_sync() must be called to make sure that the timer
-                * callback is not running. The lock must be temporary released
-                * to avoid a deadlock with the callback. In the meantime,
-                * any queuing is blocked by setting the canceling counter.
-                */
-               work->canceling++;
-               raw_spin_unlock_irqrestore(&worker->lock, *flags);
-               del_timer_sync(&dwork->timer);
-               raw_spin_lock_irqsave(&worker->lock, *flags);
-               work->canceling--;
-       }
-
        /*
         * Try to remove the work from a worker list. It might either
         * be from worker->work_list or from worker->delayed_work_list.
@@ -1176,11 +1192,23 @@ bool kthread_mod_delayed_work(struct kthread_worker *worker,
        /* Work must not be used with >1 worker, see kthread_queue_work() */
        WARN_ON_ONCE(work->worker != worker);
 
-       /* Do not fight with another command that is canceling this work. */
+       /*
+        * Temporary cancel the work but do not fight with another command
+        * that is canceling the work as well.
+        *
+        * It is a bit tricky because of possible races with another
+        * mod_delayed_work() and cancel_delayed_work() callers.
+        *
+        * The timer must be canceled first because worker->lock is released
+        * when doing so. But the work can be removed from the queue (list)
+        * only when it can be queued again so that the return value can
+        * be used for reference counting.
+        */
+       kthread_cancel_delayed_work_timer(work, &flags);
        if (work->canceling)
                goto out;
+       ret = __kthread_cancel_work(work);
 
-       ret = __kthread_cancel_work(work, true, &flags);
 fast_queue:
        __kthread_queue_delayed_work(worker, dwork, delay);
 out:
@@ -1202,7 +1230,10 @@ static bool __kthread_cancel_work_sync(struct kthread_work *work, bool is_dwork)
        /* Work must not be used with >1 worker, see kthread_queue_work(). */
        WARN_ON_ONCE(work->worker != worker);
 
-       ret = __kthread_cancel_work(work, is_dwork, &flags);
+       if (is_dwork)
+               kthread_cancel_delayed_work_timer(work, &flags);
+
+       ret = __kthread_cancel_work(work);
 
        if (worker->current_work != work)
                goto out_fast;
index 7641bd4..e97d080 100644 (file)
@@ -760,7 +760,7 @@ static void lockdep_print_held_locks(struct task_struct *p)
         * It's not reliable to print a task's held locks if it's not sleeping
         * and it's not the current task.
         */
-       if (p->state == TASK_RUNNING && p != current)
+       if (p != current && task_is_running(p))
                return;
        for (i = 0; i < depth; i++) {
                printk(" #%d: ", i);
@@ -843,7 +843,7 @@ static int count_matching_names(struct lock_class *new_class)
 }
 
 /* used from NMI context -- must be lockless */
-static __always_inline struct lock_class *
+static noinstr struct lock_class *
 look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
 {
        struct lockdep_subclass_key *key;
@@ -851,12 +851,14 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
        struct lock_class *class;
 
        if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
+               instrumentation_begin();
                debug_locks_off();
                printk(KERN_ERR
                        "BUG: looking up invalid subclass: %u\n", subclass);
                printk(KERN_ERR
                        "turning off the locking correctness validator.\n");
                dump_stack();
+               instrumentation_end();
                return NULL;
        }
 
@@ -2304,7 +2306,56 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 }
 
 /*
- * printk the shortest lock dependencies from @start to @end in reverse order:
+ * Dependency path printing:
+ *
+ * After BFS we get a lock dependency path (linked via ->parent of lock_list),
+ * printing out each lock in the dependency path will help on understanding how
+ * the deadlock could happen. Here are some details about dependency path
+ * printing:
+ *
+ * 1)  A lock_list can be either forwards or backwards for a lock dependency,
+ *     for a lock dependency A -> B, there are two lock_lists:
+ *
+ *     a)      lock_list in the ->locks_after list of A, whose ->class is B and
+ *             ->links_to is A. In this case, we can say the lock_list is
+ *             "A -> B" (forwards case).
+ *
+ *     b)      lock_list in the ->locks_before list of B, whose ->class is A
+ *             and ->links_to is B. In this case, we can say the lock_list is
+ *             "B <- A" (bacwards case).
+ *
+ *     The ->trace of both a) and b) point to the call trace where B was
+ *     acquired with A held.
+ *
+ * 2)  A "helper" lock_list is introduced during BFS, this lock_list doesn't
+ *     represent a certain lock dependency, it only provides an initial entry
+ *     for BFS. For example, BFS may introduce a "helper" lock_list whose
+ *     ->class is A, as a result BFS will search all dependencies starting with
+ *     A, e.g. A -> B or A -> C.
+ *
+ *     The notation of a forwards helper lock_list is like "-> A", which means
+ *     we should search the forwards dependencies starting with "A", e.g A -> B
+ *     or A -> C.
+ *
+ *     The notation of a bacwards helper lock_list is like "<- B", which means
+ *     we should search the backwards dependencies ending with "B", e.g.
+ *     B <- A or B <- C.
+ */
+
+/*
+ * printk the shortest lock dependencies from @root to @leaf in reverse order.
+ *
+ * We have a lock dependency path as follow:
+ *
+ *    @root                                                                 @leaf
+ *      |                                                                     |
+ *      V                                                                     V
+ *               ->parent                                   ->parent
+ * | lock_list | <--------- | lock_list | ... | lock_list  | <--------- | lock_list |
+ * |    -> L1  |            | L1 -> L2  | ... |Ln-2 -> Ln-1|            | Ln-1 -> Ln|
+ *
+ * , so it's natural that we start from @leaf and print every ->class and
+ * ->trace until we reach the @root.
  */
 static void __used
 print_shortest_lock_dependencies(struct lock_list *leaf,
@@ -2332,6 +2383,61 @@ print_shortest_lock_dependencies(struct lock_list *leaf,
        } while (entry && (depth >= 0));
 }
 
+/*
+ * printk the shortest lock dependencies from @leaf to @root.
+ *
+ * We have a lock dependency path (from a backwards search) as follow:
+ *
+ *    @leaf                                                                 @root
+ *      |                                                                     |
+ *      V                                                                     V
+ *               ->parent                                   ->parent
+ * | lock_list | ---------> | lock_list | ... | lock_list  | ---------> | lock_list |
+ * | L2 <- L1  |            | L3 <- L2  | ... | Ln <- Ln-1 |            |    <- Ln  |
+ *
+ * , so when we iterate from @leaf to @root, we actually print the lock
+ * dependency path L1 -> L2 -> .. -> Ln in the non-reverse order.
+ *
+ * Another thing to notice here is that ->class of L2 <- L1 is L1, while the
+ * ->trace of L2 <- L1 is the call trace of L2, in fact we don't have the call
+ * trace of L1 in the dependency path, which is alright, because most of the
+ * time we can figure out where L1 is held from the call trace of L2.
+ */
+static void __used
+print_shortest_lock_dependencies_backwards(struct lock_list *leaf,
+                                          struct lock_list *root)
+{
+       struct lock_list *entry = leaf;
+       const struct lock_trace *trace = NULL;
+       int depth;
+
+       /*compute depth from generated tree by BFS*/
+       depth = get_lock_depth(leaf);
+
+       do {
+               print_lock_class_header(entry->class, depth);
+               if (trace) {
+                       printk("%*s ... acquired at:\n", depth, "");
+                       print_lock_trace(trace, 2);
+                       printk("\n");
+               }
+
+               /*
+                * Record the pointer to the trace for the next lock_list
+                * entry, see the comments for the function.
+                */
+               trace = entry->trace;
+
+               if (depth == 0 && (entry != root)) {
+                       printk("lockdep:%s bad path found in chain graph\n", __func__);
+                       break;
+               }
+
+               entry = get_lock_parent(entry);
+               depth--;
+       } while (entry && (depth >= 0));
+}
+
 static void
 print_irq_lock_scenario(struct lock_list *safe_entry,
                        struct lock_list *unsafe_entry,
@@ -2446,10 +2552,7 @@ print_bad_irq_dependency(struct task_struct *curr,
        lockdep_print_held_locks(curr);
 
        pr_warn("\nthe dependencies between %s-irq-safe lock and the holding lock:\n", irqclass);
-       prev_root->trace = save_trace();
-       if (!prev_root->trace)
-               return;
-       print_shortest_lock_dependencies(backwards_entry, prev_root);
+       print_shortest_lock_dependencies_backwards(backwards_entry, prev_root);
 
        pr_warn("\nthe dependencies between the lock to be acquired");
        pr_warn(" and %s-irq-unsafe lock:\n", irqclass);
@@ -2667,8 +2770,18 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
         * Step 3: we found a bad match! Now retrieve a lock from the backward
         * list whose usage mask matches the exclusive usage mask from the
         * lock found on the forward list.
+        *
+        * Note, we should only keep the LOCKF_ENABLED_IRQ_ALL bits, considering
+        * the follow case:
+        *
+        * When trying to add A -> B to the graph, we find that there is a
+        * hardirq-safe L, that L -> ... -> A, and another hardirq-unsafe M,
+        * that B -> ... -> M. However M is **softirq-safe**, if we use exact
+        * invert bits of M's usage_mask, we will find another lock N that is
+        * **softirq-unsafe** and N -> ... -> A, however N -> .. -> M will not
+        * cause a inversion deadlock.
         */
-       backward_mask = original_mask(target_entry1->class->usage_mask);
+       backward_mask = original_mask(target_entry1->class->usage_mask & LOCKF_ENABLED_IRQ_ALL);
 
        ret = find_usage_backwards(&this, backward_mask, &target_entry);
        if (bfs_error(ret)) {
@@ -2718,7 +2831,7 @@ static inline bool usage_skip(struct lock_list *entry, void *mask)
  * <target> or not. If it can, <src> -> <target> dependency is already
  * in the graph.
  *
- * Return BFS_RMATCH if it does, or BFS_RMATCH if it does not, return BFS_E* if
+ * Return BFS_RMATCH if it does, or BFS_RNOMATCH if it does not, return BFS_E* if
  * any error appears in the bfs search.
  */
 static noinline enum bfs_result
@@ -4577,7 +4690,7 @@ static int check_wait_context(struct task_struct *curr, struct held_lock *next)
        u8 curr_inner;
        int depth;
 
-       if (!curr->lockdep_depth || !next_inner || next->trylock)
+       if (!next_inner || next->trylock)
                return 0;
 
        if (!next_outer)
index 013e1b0..d2df5e6 100644 (file)
@@ -923,7 +923,7 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter,
  * Lock a mutex (possibly interruptible), slowpath:
  */
 static __always_inline int __sched
-__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
+__mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclass,
                    struct lockdep_map *nest_lock, unsigned long ip,
                    struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
 {
@@ -1098,14 +1098,14 @@ err_early_kill:
 }
 
 static int __sched
-__mutex_lock(struct mutex *lock, long state, unsigned int subclass,
+__mutex_lock(struct mutex *lock, unsigned int state, unsigned int subclass,
             struct lockdep_map *nest_lock, unsigned long ip)
 {
        return __mutex_lock_common(lock, state, subclass, nest_lock, ip, NULL, false);
 }
 
 static int __sched
-__ww_mutex_lock(struct mutex *lock, long state, unsigned int subclass,
+__ww_mutex_lock(struct mutex *lock, unsigned int state, unsigned int subclass,
                struct lockdep_map *nest_lock, unsigned long ip,
                struct ww_acquire_ctx *ww_ctx)
 {
index 4068181..b5d9bb5 100644 (file)
@@ -1135,7 +1135,7 @@ void __sched rt_mutex_init_waiter(struct rt_mutex_waiter *waiter)
  *
  * Must be called with lock->wait_lock held and interrupts disabled
  */
-static int __sched __rt_mutex_slowlock(struct rt_mutex *lock, int state,
+static int __sched __rt_mutex_slowlock(struct rt_mutex *lock, unsigned int state,
                                       struct hrtimer_sleeper *timeout,
                                       struct rt_mutex_waiter *waiter)
 {
@@ -1190,7 +1190,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock,
 /*
  * Slow path lock function:
  */
-static int __sched rt_mutex_slowlock(struct rt_mutex *lock, int state,
+static int __sched rt_mutex_slowlock(struct rt_mutex *lock, unsigned int state,
                                     struct hrtimer_sleeper *timeout,
                                     enum rtmutex_chainwalk chwalk)
 {
index 809b001..16bfbb1 100644 (file)
@@ -889,7 +889,7 @@ rwsem_spin_on_owner(struct rw_semaphore *sem)
  * Wait for the read lock to be granted
  */
 static struct rw_semaphore __sched *
-rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, int state)
+rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int state)
 {
        long adjustment = -RWSEM_READER_BIAS;
        long rcnt = (count >> RWSEM_READER_SHIFT);
index 7e78dfa..927d46c 100644 (file)
@@ -266,9 +266,18 @@ static void module_assert_mutex_or_preempt(void)
 #endif
 }
 
+#ifdef CONFIG_MODULE_SIG
 static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
 module_param(sig_enforce, bool_enable_only, 0644);
 
+void set_module_sig_enforced(void)
+{
+       sig_enforce = true;
+}
+#else
+#define sig_enforce false
+#endif
+
 /*
  * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
  * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
@@ -279,11 +288,6 @@ bool is_module_sig_enforced(void)
 }
 EXPORT_SYMBOL(is_module_sig_enforced);
 
-void set_module_sig_enforced(void)
-{
-       sig_enforce = true;
-}
-
 /* Block module loading/unloading? */
 int modules_disabled = 0;
 core_param(nomodule, modules_disabled, bint, 0);
index 6bfe3ea..a127796 100644 (file)
@@ -98,20 +98,20 @@ config PM_STD_PARTITION
        default ""
        help
          The default resume partition is the partition that the suspend-
-         to-disk implementation will look for a suspended disk image. 
+         to-disk implementation will look for a suspended disk image.
 
-         The partition specified here will be different for almost every user. 
+         The partition specified here will be different for almost every user.
          It should be a valid swap partition (at least for now) that is turned
-         on before suspending. 
+         on before suspending.
 
          The partition specified can be overridden by specifying:
 
-               resume=/dev/<other device> 
+               resume=/dev/<other device>
 
-         which will set the resume partition to the device specified. 
+         which will set the resume partition to the device specified.
 
          Note there is currently not a way to specify which device to save the
-         suspended image to. It will simply pick the first available swap 
+         suspended image to. It will simply pick the first available swap
          device.
 
 config PM_SLEEP
index 50cc635..37401c9 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * drivers/power/process.c - Functions for starting/stopping processes on 
+ * drivers/power/process.c - Functions for starting/stopping processes on
  *                           suspend transitions.
  *
  * Originally from swsusp.
index 1a221dc..f7a9860 100644 (file)
@@ -331,7 +331,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
  *
  * Memory bitmap is a structure consisting of many linked lists of
  * objects.  The main list's elements are of type struct zone_bitmap
- * and each of them corresonds to one zone.  For each zone bitmap
+ * and each of them corresponds to one zone.  For each zone bitmap
  * object there is a list of objects of type struct bm_block that
  * represent each blocks of bitmap in which information is stored.
  *
@@ -1146,7 +1146,7 @@ int create_basic_memory_bitmaps(void)
  Free_second_object:
        kfree(bm2);
  Free_first_bitmap:
-       memory_bm_free(bm1, PG_UNSAFE_CLEAR);
+       memory_bm_free(bm1, PG_UNSAFE_CLEAR);
  Free_first_object:
        kfree(bm1);
        return -ENOMEM;
@@ -1500,7 +1500,7 @@ static struct memory_bitmap copy_bm;
 /**
  * swsusp_free - Free pages allocated for hibernation image.
  *
- * Image pages are alocated before snapshot creation, so they need to be
+ * Image pages are allocated before snapshot creation, so they need to be
  * released after resume.
  */
 void swsusp_free(void)
@@ -2326,7 +2326,7 @@ static struct memory_bitmap *safe_highmem_bm;
  * (@nr_highmem_p points to the variable containing the number of highmem image
  * pages).  The pages that are "safe" (ie. will not be overwritten when the
  * hibernation image is restored entirely) have the corresponding bits set in
- * @bm (it must be unitialized).
+ * @bm (it must be uninitialized).
  *
  * NOTE: This function should not be called if there are no highmem image pages.
  */
@@ -2483,7 +2483,7 @@ static inline void free_highmem_data(void) {}
 
 /**
  * prepare_image - Make room for loading hibernation image.
- * @new_bm: Unitialized memory bitmap structure.
+ * @new_bm: Uninitialized memory bitmap structure.
  * @bm: Memory bitmap with unsafe pages marked.
  *
  * Use @bm to mark the pages that will be overwritten in the process of
index bea3cb8..3cb89ba 100644 (file)
@@ -1125,7 +1125,7 @@ struct dec_data {
 };
 
 /**
- * Deompression function that runs in its own thread.
+ * Decompression function that runs in its own thread.
  */
 static int lzo_decompress_threadfn(void *data)
 {
index 421c355..142a58d 100644 (file)
@@ -3531,3 +3531,119 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter)
 EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
 
 #endif
+
+#ifdef CONFIG_SMP
+static atomic_t printk_cpulock_owner = ATOMIC_INIT(-1);
+static atomic_t printk_cpulock_nested = ATOMIC_INIT(0);
+
+/**
+ * __printk_wait_on_cpu_lock() - Busy wait until the printk cpu-reentrant
+ *                               spinning lock is not owned by any CPU.
+ *
+ * Context: Any context.
+ */
+void __printk_wait_on_cpu_lock(void)
+{
+       do {
+               cpu_relax();
+       } while (atomic_read(&printk_cpulock_owner) != -1);
+}
+EXPORT_SYMBOL(__printk_wait_on_cpu_lock);
+
+/**
+ * __printk_cpu_trylock() - Try to acquire the printk cpu-reentrant
+ *                          spinning lock.
+ *
+ * If no processor has the lock, the calling processor takes the lock and
+ * becomes the owner. If the calling processor is already the owner of the
+ * lock, this function succeeds immediately.
+ *
+ * Context: Any context. Expects interrupts to be disabled.
+ * Return: 1 on success, otherwise 0.
+ */
+int __printk_cpu_trylock(void)
+{
+       int cpu;
+       int old;
+
+       cpu = smp_processor_id();
+
+       /*
+        * Guarantee loads and stores from this CPU when it is the lock owner
+        * are _not_ visible to the previous lock owner. This pairs with
+        * __printk_cpu_unlock:B.
+        *
+        * Memory barrier involvement:
+        *
+        * If __printk_cpu_trylock:A reads from __printk_cpu_unlock:B, then
+        * __printk_cpu_unlock:A can never read from __printk_cpu_trylock:B.
+        *
+        * Relies on:
+        *
+        * RELEASE from __printk_cpu_unlock:A to __printk_cpu_unlock:B
+        * of the previous CPU
+        *    matching
+        * ACQUIRE from __printk_cpu_trylock:A to __printk_cpu_trylock:B
+        * of this CPU
+        */
+       old = atomic_cmpxchg_acquire(&printk_cpulock_owner, -1,
+                                    cpu); /* LMM(__printk_cpu_trylock:A) */
+       if (old == -1) {
+               /*
+                * This CPU is now the owner and begins loading/storing
+                * data: LMM(__printk_cpu_trylock:B)
+                */
+               return 1;
+
+       } else if (old == cpu) {
+               /* This CPU is already the owner. */
+               atomic_inc(&printk_cpulock_nested);
+               return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(__printk_cpu_trylock);
+
+/**
+ * __printk_cpu_unlock() - Release the printk cpu-reentrant spinning lock.
+ *
+ * The calling processor must be the owner of the lock.
+ *
+ * Context: Any context. Expects interrupts to be disabled.
+ */
+void __printk_cpu_unlock(void)
+{
+       if (atomic_read(&printk_cpulock_nested)) {
+               atomic_dec(&printk_cpulock_nested);
+               return;
+       }
+
+       /*
+        * This CPU is finished loading/storing data:
+        * LMM(__printk_cpu_unlock:A)
+        */
+
+       /*
+        * Guarantee loads and stores from this CPU when it was the
+        * lock owner are visible to the next lock owner. This pairs
+        * with __printk_cpu_trylock:A.
+        *
+        * Memory barrier involvement:
+        *
+        * If __printk_cpu_trylock:A reads from __printk_cpu_unlock:B,
+        * then __printk_cpu_trylock:B reads from __printk_cpu_unlock:A.
+        *
+        * Relies on:
+        *
+        * RELEASE from __printk_cpu_unlock:A to __printk_cpu_unlock:B
+        * of this CPU
+        *    matching
+        * ACQUIRE from __printk_cpu_trylock:A to __printk_cpu_trylock:B
+        * of the next CPU
+        */
+       atomic_set_release(&printk_cpulock_owner,
+                          -1); /* LMM(__printk_cpu_unlock:B) */
+}
+EXPORT_SYMBOL(__printk_cpu_unlock);
+#endif /* CONFIG_SMP */
index 7a14146..9423218 100644 (file)
@@ -391,6 +391,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        /* No obstacles. */
        return vprintk_default(fmt, args);
 }
+EXPORT_SYMBOL(vprintk);
 
 void __init printk_safe_init(void)
 {
@@ -411,4 +412,3 @@ void __init printk_safe_init(void)
        /* Flush pending messages that did not have scheduled IRQ works. */
        printk_safe_flush();
 }
-EXPORT_SYMBOL(vprintk);
index 2997ca6..f8589bf 100644 (file)
@@ -197,7 +197,7 @@ static bool ptrace_freeze_traced(struct task_struct *task)
        spin_lock_irq(&task->sighand->siglock);
        if (task_is_traced(task) && !looks_like_a_spurious_pid(task) &&
            !__fatal_signal_pending(task)) {
-               task->state = __TASK_TRACED;
+               WRITE_ONCE(task->__state, __TASK_TRACED);
                ret = true;
        }
        spin_unlock_irq(&task->sighand->siglock);
@@ -207,7 +207,7 @@ static bool ptrace_freeze_traced(struct task_struct *task)
 
 static void ptrace_unfreeze_traced(struct task_struct *task)
 {
-       if (task->state != __TASK_TRACED)
+       if (READ_ONCE(task->__state) != __TASK_TRACED)
                return;
 
        WARN_ON(!task->ptrace || task->parent != current);
@@ -217,11 +217,11 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
         * Recheck state under the lock to close this race.
         */
        spin_lock_irq(&task->sighand->siglock);
-       if (task->state == __TASK_TRACED) {
+       if (READ_ONCE(task->__state) == __TASK_TRACED) {
                if (__fatal_signal_pending(task))
                        wake_up_state(task, __TASK_TRACED);
                else
-                       task->state = TASK_TRACED;
+                       WRITE_ONCE(task->__state, TASK_TRACED);
        }
        spin_unlock_irq(&task->sighand->siglock);
 }
@@ -256,7 +256,7 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
         */
        read_lock(&tasklist_lock);
        if (child->ptrace && child->parent == current) {
-               WARN_ON(child->state == __TASK_TRACED);
+               WARN_ON(READ_ONCE(child->__state) == __TASK_TRACED);
                /*
                 * child->sighand can't be NULL, release_task()
                 * does ptrace_unlink() before __exit_signal().
@@ -273,7 +273,7 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
                         * ptrace_stop() changes ->state back to TASK_RUNNING,
                         * so we should not worry about leaking __TASK_TRACED.
                         */
-                       WARN_ON(child->state == __TASK_TRACED);
+                       WARN_ON(READ_ONCE(child->__state) == __TASK_TRACED);
                        ret = -ESRCH;
                }
        }
index 29d2f4c..194b9c1 100644 (file)
@@ -1831,10 +1831,10 @@ rcu_torture_stats_print(void)
                srcutorture_get_gp_data(cur_ops->ttype, srcu_ctlp,
                                        &flags, &gp_seq);
                wtp = READ_ONCE(writer_task);
-               pr_alert("??? Writer stall state %s(%d) g%lu f%#x ->state %#lx cpu %d\n",
+               pr_alert("??? Writer stall state %s(%d) g%lu f%#x ->state %#x cpu %d\n",
                         rcu_torture_writer_state_getname(),
                         rcu_torture_writer_state, gp_seq, flags,
-                        wtp == NULL ? ~0UL : wtp->state,
+                        wtp == NULL ? ~0U : wtp->__state,
                         wtp == NULL ? -1 : (int)task_cpu(wtp));
                if (!splatted && wtp) {
                        sched_show_task(wtp);
index ad0156b..4d69620 100644 (file)
@@ -2768,7 +2768,7 @@ EXPORT_SYMBOL_GPL(rcu_bind_current_to_nocb);
 #ifdef CONFIG_SMP
 static char *show_rcu_should_be_on_cpu(struct task_struct *tsp)
 {
-       return tsp && tsp->state == TASK_RUNNING && !tsp->on_cpu ? "!" : "";
+       return tsp && task_is_running(tsp) && !tsp->on_cpu ? "!" : "";
 }
 #else // #ifdef CONFIG_SMP
 static char *show_rcu_should_be_on_cpu(struct task_struct *tsp)
index 59b95cc..acb2288 100644 (file)
@@ -460,12 +460,12 @@ static void rcu_check_gp_kthread_starvation(void)
 
        if (rcu_is_gp_kthread_starving(&j)) {
                cpu = gpk ? task_cpu(gpk) : -1;
-               pr_err("%s kthread starved for %ld jiffies! g%ld f%#x %s(%d) ->state=%#lx ->cpu=%d\n",
+               pr_err("%s kthread starved for %ld jiffies! g%ld f%#x %s(%d) ->state=%#x ->cpu=%d\n",
                       rcu_state.name, j,
                       (long)rcu_seq_current(&rcu_state.gp_seq),
                       data_race(rcu_state.gp_flags),
                       gp_state_getname(rcu_state.gp_state), rcu_state.gp_state,
-                      gpk ? gpk->state : ~0, cpu);
+                      gpk ? gpk->__state : ~0, cpu);
                if (gpk) {
                        pr_err("\tUnless %s kthread gets sufficient CPU time, OOM is now expected behavior.\n", rcu_state.name);
                        pr_err("RCU grace-period kthread stack dump:\n");
@@ -503,12 +503,12 @@ static void rcu_check_gp_kthread_expired_fqs_timer(void)
            time_after(jiffies, jiffies_fqs + RCU_STALL_MIGHT_MIN) &&
            gpk && !READ_ONCE(gpk->on_rq)) {
                cpu = task_cpu(gpk);
-               pr_err("%s kthread timer wakeup didn't happen for %ld jiffies! g%ld f%#x %s(%d) ->state=%#lx\n",
+               pr_err("%s kthread timer wakeup didn't happen for %ld jiffies! g%ld f%#x %s(%d) ->state=%#x\n",
                       rcu_state.name, (jiffies - jiffies_fqs),
                       (long)rcu_seq_current(&rcu_state.gp_seq),
                       data_race(rcu_state.gp_flags),
                       gp_state_getname(RCU_GP_WAIT_FQS), RCU_GP_WAIT_FQS,
-                      gpk->state);
+                      gpk->__state);
                pr_err("\tPossible timer handling issue on cpu=%d timer-softirq=%u\n",
                       cpu, kstat_softirqs_cpu(TIMER_SOFTIRQ, cpu));
        }
@@ -735,9 +735,9 @@ void show_rcu_gp_kthreads(void)
        ja = j - data_race(rcu_state.gp_activity);
        jr = j - data_race(rcu_state.gp_req_activity);
        jw = j - data_race(rcu_state.gp_wake_time);
-       pr_info("%s: wait state: %s(%d) ->state: %#lx delta ->gp_activity %lu ->gp_req_activity %lu ->gp_wake_time %lu ->gp_wake_seq %ld ->gp_seq %ld ->gp_seq_needed %ld ->gp_flags %#x\n",
+       pr_info("%s: wait state: %s(%d) ->state: %#x delta ->gp_activity %lu ->gp_req_activity %lu ->gp_wake_time %lu ->gp_wake_seq %ld ->gp_seq %ld ->gp_seq_needed %ld ->gp_flags %#x\n",
                rcu_state.name, gp_state_getname(rcu_state.gp_state),
-               rcu_state.gp_state, t ? t->state : 0x1ffffL,
+               rcu_state.gp_state, t ? t->__state : 0x1ffff,
                ja, jr, jw, (long)data_race(rcu_state.gp_wake_seq),
                (long)data_race(rcu_state.gp_seq),
                (long)data_race(rcu_get_root()->gp_seq_needed),
index a6ad5eb..f7440c0 100644 (file)
@@ -7,6 +7,7 @@
 
 #define pr_fmt(fmt)    "reboot: " fmt
 
+#include <linux/atomic.h>
 #include <linux/ctype.h>
 #include <linux/export.h>
 #include <linux/kexec.h>
@@ -518,6 +519,84 @@ void orderly_reboot(void)
 }
 EXPORT_SYMBOL_GPL(orderly_reboot);
 
+/**
+ * hw_failure_emergency_poweroff_func - emergency poweroff work after a known delay
+ * @work: work_struct associated with the emergency poweroff function
+ *
+ * This function is called in very critical situations to force
+ * a kernel poweroff after a configurable timeout value.
+ */
+static void hw_failure_emergency_poweroff_func(struct work_struct *work)
+{
+       /*
+        * We have reached here after the emergency shutdown waiting period has
+        * expired. This means orderly_poweroff has not been able to shut off
+        * the system for some reason.
+        *
+        * Try to shut down the system immediately using kernel_power_off
+        * if populated
+        */
+       pr_emerg("Hardware protection timed-out. Trying forced poweroff\n");
+       kernel_power_off();
+
+       /*
+        * Worst of the worst case trigger emergency restart
+        */
+       pr_emerg("Hardware protection shutdown failed. Trying emergency restart\n");
+       emergency_restart();
+}
+
+static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work,
+                           hw_failure_emergency_poweroff_func);
+
+/**
+ * hw_failure_emergency_poweroff - Trigger an emergency system poweroff
+ *
+ * This may be called from any critical situation to trigger a system shutdown
+ * after a given period of time. If time is negative this is not scheduled.
+ */
+static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
+{
+       if (poweroff_delay_ms <= 0)
+               return;
+       schedule_delayed_work(&hw_failure_emergency_poweroff_work,
+                             msecs_to_jiffies(poweroff_delay_ms));
+}
+
+/**
+ * hw_protection_shutdown - Trigger an emergency system poweroff
+ *
+ * @reason:            Reason of emergency shutdown to be printed.
+ * @ms_until_forced:   Time to wait for orderly shutdown before tiggering a
+ *                     forced shudown. Negative value disables the forced
+ *                     shutdown.
+ *
+ * Initiate an emergency system shutdown in order to protect hardware from
+ * further damage. Usage examples include a thermal protection or a voltage or
+ * current regulator failures.
+ * NOTE: The request is ignored if protection shutdown is already pending even
+ * if the previous request has given a large timeout for forced shutdown.
+ * Can be called from any context.
+ */
+void hw_protection_shutdown(const char *reason, int ms_until_forced)
+{
+       static atomic_t allow_proceed = ATOMIC_INIT(1);
+
+       pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason);
+
+       /* Shutdown should be initiated only once. */
+       if (!atomic_dec_and_test(&allow_proceed))
+               return;
+
+       /*
+        * Queue a backup emergency shutdown in the event of
+        * orderly_poweroff failure
+        */
+       hw_failure_emergency_poweroff(ms_until_forced);
+       orderly_poweroff(true);
+}
+EXPORT_SYMBOL_GPL(hw_protection_shutdown);
+
 static int __init reboot_setup(char *str)
 {
        for (;;) {
index 5fc9c9b..978fcfc 100644 (file)
@@ -36,3 +36,4 @@ obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
 obj-$(CONFIG_MEMBARRIER) += membarrier.o
 obj-$(CONFIG_CPU_ISOLATION) += isolation.o
 obj-$(CONFIG_PSI) += psi.o
+obj-$(CONFIG_SCHED_CORE) += core_sched.o
index 5226cc2..cf16f8f 100644 (file)
@@ -84,6 +84,272 @@ unsigned int sysctl_sched_rt_period = 1000000;
 
 __read_mostly int scheduler_running;
 
+#ifdef CONFIG_SCHED_CORE
+
+DEFINE_STATIC_KEY_FALSE(__sched_core_enabled);
+
+/* kernel prio, less is more */
+static inline int __task_prio(struct task_struct *p)
+{
+       if (p->sched_class == &stop_sched_class) /* trumps deadline */
+               return -2;
+
+       if (rt_prio(p->prio)) /* includes deadline */
+               return p->prio; /* [-1, 99] */
+
+       if (p->sched_class == &idle_sched_class)
+               return MAX_RT_PRIO + NICE_WIDTH; /* 140 */
+
+       return MAX_RT_PRIO + MAX_NICE; /* 120, squash fair */
+}
+
+/*
+ * l(a,b)
+ * le(a,b) := !l(b,a)
+ * g(a,b)  := l(b,a)
+ * ge(a,b) := !l(a,b)
+ */
+
+/* real prio, less is less */
+static inline bool prio_less(struct task_struct *a, struct task_struct *b, bool in_fi)
+{
+
+       int pa = __task_prio(a), pb = __task_prio(b);
+
+       if (-pa < -pb)
+               return true;
+
+       if (-pb < -pa)
+               return false;
+
+       if (pa == -1) /* dl_prio() doesn't work because of stop_class above */
+               return !dl_time_before(a->dl.deadline, b->dl.deadline);
+
+       if (pa == MAX_RT_PRIO + MAX_NICE)       /* fair */
+               return cfs_prio_less(a, b, in_fi);
+
+       return false;
+}
+
+static inline bool __sched_core_less(struct task_struct *a, struct task_struct *b)
+{
+       if (a->core_cookie < b->core_cookie)
+               return true;
+
+       if (a->core_cookie > b->core_cookie)
+               return false;
+
+       /* flip prio, so high prio is leftmost */
+       if (prio_less(b, a, task_rq(a)->core->core_forceidle))
+               return true;
+
+       return false;
+}
+
+#define __node_2_sc(node) rb_entry((node), struct task_struct, core_node)
+
+static inline bool rb_sched_core_less(struct rb_node *a, const struct rb_node *b)
+{
+       return __sched_core_less(__node_2_sc(a), __node_2_sc(b));
+}
+
+static inline int rb_sched_core_cmp(const void *key, const struct rb_node *node)
+{
+       const struct task_struct *p = __node_2_sc(node);
+       unsigned long cookie = (unsigned long)key;
+
+       if (cookie < p->core_cookie)
+               return -1;
+
+       if (cookie > p->core_cookie)
+               return 1;
+
+       return 0;
+}
+
+void sched_core_enqueue(struct rq *rq, struct task_struct *p)
+{
+       rq->core->core_task_seq++;
+
+       if (!p->core_cookie)
+               return;
+
+       rb_add(&p->core_node, &rq->core_tree, rb_sched_core_less);
+}
+
+void sched_core_dequeue(struct rq *rq, struct task_struct *p)
+{
+       rq->core->core_task_seq++;
+
+       if (!sched_core_enqueued(p))
+               return;
+
+       rb_erase(&p->core_node, &rq->core_tree);
+       RB_CLEAR_NODE(&p->core_node);
+}
+
+/*
+ * Find left-most (aka, highest priority) task matching @cookie.
+ */
+static struct task_struct *sched_core_find(struct rq *rq, unsigned long cookie)
+{
+       struct rb_node *node;
+
+       node = rb_find_first((void *)cookie, &rq->core_tree, rb_sched_core_cmp);
+       /*
+        * The idle task always matches any cookie!
+        */
+       if (!node)
+               return idle_sched_class.pick_task(rq);
+
+       return __node_2_sc(node);
+}
+
+static struct task_struct *sched_core_next(struct task_struct *p, unsigned long cookie)
+{
+       struct rb_node *node = &p->core_node;
+
+       node = rb_next(node);
+       if (!node)
+               return NULL;
+
+       p = container_of(node, struct task_struct, core_node);
+       if (p->core_cookie != cookie)
+               return NULL;
+
+       return p;
+}
+
+/*
+ * Magic required such that:
+ *
+ *     raw_spin_rq_lock(rq);
+ *     ...
+ *     raw_spin_rq_unlock(rq);
+ *
+ * ends up locking and unlocking the _same_ lock, and all CPUs
+ * always agree on what rq has what lock.
+ *
+ * XXX entirely possible to selectively enable cores, don't bother for now.
+ */
+
+static DEFINE_MUTEX(sched_core_mutex);
+static atomic_t sched_core_count;
+static struct cpumask sched_core_mask;
+
+static void __sched_core_flip(bool enabled)
+{
+       int cpu, t, i;
+
+       cpus_read_lock();
+
+       /*
+        * Toggle the online cores, one by one.
+        */
+       cpumask_copy(&sched_core_mask, cpu_online_mask);
+       for_each_cpu(cpu, &sched_core_mask) {
+               const struct cpumask *smt_mask = cpu_smt_mask(cpu);
+
+               i = 0;
+               local_irq_disable();
+               for_each_cpu(t, smt_mask) {
+                       /* supports up to SMT8 */
+                       raw_spin_lock_nested(&cpu_rq(t)->__lock, i++);
+               }
+
+               for_each_cpu(t, smt_mask)
+                       cpu_rq(t)->core_enabled = enabled;
+
+               for_each_cpu(t, smt_mask)
+                       raw_spin_unlock(&cpu_rq(t)->__lock);
+               local_irq_enable();
+
+               cpumask_andnot(&sched_core_mask, &sched_core_mask, smt_mask);
+       }
+
+       /*
+        * Toggle the offline CPUs.
+        */
+       cpumask_copy(&sched_core_mask, cpu_possible_mask);
+       cpumask_andnot(&sched_core_mask, &sched_core_mask, cpu_online_mask);
+
+       for_each_cpu(cpu, &sched_core_mask)
+               cpu_rq(cpu)->core_enabled = enabled;
+
+       cpus_read_unlock();
+}
+
+static void sched_core_assert_empty(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               WARN_ON_ONCE(!RB_EMPTY_ROOT(&cpu_rq(cpu)->core_tree));
+}
+
+static void __sched_core_enable(void)
+{
+       static_branch_enable(&__sched_core_enabled);
+       /*
+        * Ensure all previous instances of raw_spin_rq_*lock() have finished
+        * and future ones will observe !sched_core_disabled().
+        */
+       synchronize_rcu();
+       __sched_core_flip(true);
+       sched_core_assert_empty();
+}
+
+static void __sched_core_disable(void)
+{
+       sched_core_assert_empty();
+       __sched_core_flip(false);
+       static_branch_disable(&__sched_core_enabled);
+}
+
+void sched_core_get(void)
+{
+       if (atomic_inc_not_zero(&sched_core_count))
+               return;
+
+       mutex_lock(&sched_core_mutex);
+       if (!atomic_read(&sched_core_count))
+               __sched_core_enable();
+
+       smp_mb__before_atomic();
+       atomic_inc(&sched_core_count);
+       mutex_unlock(&sched_core_mutex);
+}
+
+static void __sched_core_put(struct work_struct *work)
+{
+       if (atomic_dec_and_mutex_lock(&sched_core_count, &sched_core_mutex)) {
+               __sched_core_disable();
+               mutex_unlock(&sched_core_mutex);
+       }
+}
+
+void sched_core_put(void)
+{
+       static DECLARE_WORK(_work, __sched_core_put);
+
+       /*
+        * "There can be only one"
+        *
+        * Either this is the last one, or we don't actually need to do any
+        * 'work'. If it is the last *again*, we rely on
+        * WORK_STRUCT_PENDING_BIT.
+        */
+       if (!atomic_add_unless(&sched_core_count, -1, 1))
+               schedule_work(&_work);
+}
+
+#else /* !CONFIG_SCHED_CORE */
+
+static inline void sched_core_enqueue(struct rq *rq, struct task_struct *p) { }
+static inline void sched_core_dequeue(struct rq *rq, struct task_struct *p) { }
+
+#endif /* CONFIG_SCHED_CORE */
+
 /*
  * part of the period that we allow rt tasks to run in us.
  * default: 0.95s
@@ -184,6 +450,79 @@ int sysctl_sched_rt_runtime = 950000;
  *
  */
 
+void raw_spin_rq_lock_nested(struct rq *rq, int subclass)
+{
+       raw_spinlock_t *lock;
+
+       /* Matches synchronize_rcu() in __sched_core_enable() */
+       preempt_disable();
+       if (sched_core_disabled()) {
+               raw_spin_lock_nested(&rq->__lock, subclass);
+               /* preempt_count *MUST* be > 1 */
+               preempt_enable_no_resched();
+               return;
+       }
+
+       for (;;) {
+               lock = __rq_lockp(rq);
+               raw_spin_lock_nested(lock, subclass);
+               if (likely(lock == __rq_lockp(rq))) {
+                       /* preempt_count *MUST* be > 1 */
+                       preempt_enable_no_resched();
+                       return;
+               }
+               raw_spin_unlock(lock);
+       }
+}
+
+bool raw_spin_rq_trylock(struct rq *rq)
+{
+       raw_spinlock_t *lock;
+       bool ret;
+
+       /* Matches synchronize_rcu() in __sched_core_enable() */
+       preempt_disable();
+       if (sched_core_disabled()) {
+               ret = raw_spin_trylock(&rq->__lock);
+               preempt_enable();
+               return ret;
+       }
+
+       for (;;) {
+               lock = __rq_lockp(rq);
+               ret = raw_spin_trylock(lock);
+               if (!ret || (likely(lock == __rq_lockp(rq)))) {
+                       preempt_enable();
+                       return ret;
+               }
+               raw_spin_unlock(lock);
+       }
+}
+
+void raw_spin_rq_unlock(struct rq *rq)
+{
+       raw_spin_unlock(rq_lockp(rq));
+}
+
+#ifdef CONFIG_SMP
+/*
+ * double_rq_lock - safely lock two runqueues
+ */
+void double_rq_lock(struct rq *rq1, struct rq *rq2)
+{
+       lockdep_assert_irqs_disabled();
+
+       if (rq_order_less(rq2, rq1))
+               swap(rq1, rq2);
+
+       raw_spin_rq_lock(rq1);
+       if (__rq_lockp(rq1) == __rq_lockp(rq2))
+               return;
+
+       raw_spin_rq_lock_nested(rq2, SINGLE_DEPTH_NESTING);
+}
+#endif
+
 /*
  * __task_rq_lock - lock the rq @p resides on.
  */
@@ -196,12 +535,12 @@ struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf)
 
        for (;;) {
                rq = task_rq(p);
-               raw_spin_lock(&rq->lock);
+               raw_spin_rq_lock(rq);
                if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
                        rq_pin_lock(rq, rf);
                        return rq;
                }
-               raw_spin_unlock(&rq->lock);
+               raw_spin_rq_unlock(rq);
 
                while (unlikely(task_on_rq_migrating(p)))
                        cpu_relax();
@@ -220,7 +559,7 @@ struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
        for (;;) {
                raw_spin_lock_irqsave(&p->pi_lock, rf->flags);
                rq = task_rq(p);
-               raw_spin_lock(&rq->lock);
+               raw_spin_rq_lock(rq);
                /*
                 *      move_queued_task()              task_rq_lock()
                 *
@@ -242,7 +581,7 @@ struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
                        rq_pin_lock(rq, rf);
                        return rq;
                }
-               raw_spin_unlock(&rq->lock);
+               raw_spin_rq_unlock(rq);
                raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
 
                while (unlikely(task_on_rq_migrating(p)))
@@ -312,7 +651,7 @@ void update_rq_clock(struct rq *rq)
 {
        s64 delta;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        if (rq->clock_update_flags & RQCF_ACT_SKIP)
                return;
@@ -585,7 +924,6 @@ void wake_up_q(struct wake_q_head *head)
                struct task_struct *task;
 
                task = container_of(node, struct task_struct, wake_q);
-               BUG_ON(!task);
                /* Task can safely be re-inserted now: */
                node = node->next;
                task->wake_q.next = NULL;
@@ -611,7 +949,7 @@ void resched_curr(struct rq *rq)
        struct task_struct *curr = rq->curr;
        int cpu;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        if (test_tsk_need_resched(curr))
                return;
@@ -635,10 +973,10 @@ void resched_cpu(int cpu)
        struct rq *rq = cpu_rq(cpu);
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&rq->lock, flags);
+       raw_spin_rq_lock_irqsave(rq, flags);
        if (cpu_online(cpu) || cpu == smp_processor_id())
                resched_curr(rq);
-       raw_spin_unlock_irqrestore(&rq->lock, flags);
+       raw_spin_rq_unlock_irqrestore(rq, flags);
 }
 
 #ifdef CONFIG_SMP
@@ -1065,9 +1403,10 @@ static void uclamp_sync_util_min_rt_default(void)
 static inline struct uclamp_se
 uclamp_tg_restrict(struct task_struct *p, enum uclamp_id clamp_id)
 {
+       /* Copy by value as we could modify it */
        struct uclamp_se uc_req = p->uclamp_req[clamp_id];
 #ifdef CONFIG_UCLAMP_TASK_GROUP
-       struct uclamp_se uc_max;
+       unsigned int tg_min, tg_max, value;
 
        /*
         * Tasks in autogroups or root task group will be
@@ -1078,9 +1417,11 @@ uclamp_tg_restrict(struct task_struct *p, enum uclamp_id clamp_id)
        if (task_group(p) == &root_task_group)
                return uc_req;
 
-       uc_max = task_group(p)->uclamp[clamp_id];
-       if (uc_req.value > uc_max.value || !uc_req.user_defined)
-               return uc_max;
+       tg_min = task_group(p)->uclamp[UCLAMP_MIN].value;
+       tg_max = task_group(p)->uclamp[UCLAMP_MAX].value;
+       value = uc_req.value;
+       value = clamp(value, tg_min, tg_max);
+       uclamp_se_set(&uc_req, value, false);
 #endif
 
        return uc_req;
@@ -1137,7 +1478,7 @@ static inline void uclamp_rq_inc_id(struct rq *rq, struct task_struct *p,
        struct uclamp_se *uc_se = &p->uclamp[clamp_id];
        struct uclamp_bucket *bucket;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        /* Update task effective clamp */
        p->uclamp[clamp_id] = uclamp_eff_get(p, clamp_id);
@@ -1177,7 +1518,7 @@ static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
        unsigned int bkt_clamp;
        unsigned int rq_clamp;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        /*
         * If sched_uclamp_used was enabled after task @p was enqueued,
@@ -1279,8 +1620,9 @@ static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p)
 }
 
 static inline void
-uclamp_update_active(struct task_struct *p, enum uclamp_id clamp_id)
+uclamp_update_active(struct task_struct *p)
 {
+       enum uclamp_id clamp_id;
        struct rq_flags rf;
        struct rq *rq;
 
@@ -1300,9 +1642,11 @@ uclamp_update_active(struct task_struct *p, enum uclamp_id clamp_id)
         * affecting a valid clamp bucket, the next time it's enqueued,
         * it will already see the updated clamp bucket value.
         */
-       if (p->uclamp[clamp_id].active) {
-               uclamp_rq_dec_id(rq, p, clamp_id);
-               uclamp_rq_inc_id(rq, p, clamp_id);
+       for_each_clamp_id(clamp_id) {
+               if (p->uclamp[clamp_id].active) {
+                       uclamp_rq_dec_id(rq, p, clamp_id);
+                       uclamp_rq_inc_id(rq, p, clamp_id);
+               }
        }
 
        task_rq_unlock(rq, p, &rf);
@@ -1310,20 +1654,14 @@ uclamp_update_active(struct task_struct *p, enum uclamp_id clamp_id)
 
 #ifdef CONFIG_UCLAMP_TASK_GROUP
 static inline void
-uclamp_update_active_tasks(struct cgroup_subsys_state *css,
-                          unsigned int clamps)
+uclamp_update_active_tasks(struct cgroup_subsys_state *css)
 {
-       enum uclamp_id clamp_id;
        struct css_task_iter it;
        struct task_struct *p;
 
        css_task_iter_start(css, 0, &it);
-       while ((p = css_task_iter_next(&it))) {
-               for_each_clamp_id(clamp_id) {
-                       if ((0x1 << clamp_id) & clamps)
-                               uclamp_update_active(p, clamp_id);
-               }
-       }
+       while ((p = css_task_iter_next(&it)))
+               uclamp_update_active(p);
        css_task_iter_end(&it);
 }
 
@@ -1590,27 +1928,38 @@ static inline void uclamp_post_fork(struct task_struct *p) { }
 static inline void init_uclamp(void) { }
 #endif /* CONFIG_UCLAMP_TASK */
 
+bool sched_task_on_rq(struct task_struct *p)
+{
+       return task_on_rq_queued(p);
+}
+
 static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
 {
        if (!(flags & ENQUEUE_NOCLOCK))
                update_rq_clock(rq);
 
        if (!(flags & ENQUEUE_RESTORE)) {
-               sched_info_queued(rq, p);
+               sched_info_enqueue(rq, p);
                psi_enqueue(p, flags & ENQUEUE_WAKEUP);
        }
 
        uclamp_rq_inc(rq, p);
        p->sched_class->enqueue_task(rq, p, flags);
+
+       if (sched_core_enabled(rq))
+               sched_core_enqueue(rq, p);
 }
 
 static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
 {
+       if (sched_core_enabled(rq))
+               sched_core_dequeue(rq, p);
+
        if (!(flags & DEQUEUE_NOCLOCK))
                update_rq_clock(rq);
 
        if (!(flags & DEQUEUE_SAVE)) {
-               sched_info_dequeued(rq, p);
+               sched_info_dequeue(rq, p);
                psi_dequeue(p, flags & DEQUEUE_SLEEP);
        }
 
@@ -1850,7 +2199,7 @@ static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
 static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
                                   struct task_struct *p, int new_cpu)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        deactivate_task(rq, p, DEQUEUE_NOCLOCK);
        set_task_cpu(p, new_cpu);
@@ -1916,7 +2265,6 @@ static int migration_cpu_stop(void *data)
        struct migration_arg *arg = data;
        struct set_affinity_pending *pending = arg->pending;
        struct task_struct *p = arg->task;
-       int dest_cpu = arg->dest_cpu;
        struct rq *rq = this_rq();
        bool complete = false;
        struct rq_flags rf;
@@ -1954,19 +2302,15 @@ static int migration_cpu_stop(void *data)
                if (pending) {
                        p->migration_pending = NULL;
                        complete = true;
-               }
 
-               if (dest_cpu < 0) {
                        if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask))
                                goto out;
-
-                       dest_cpu = cpumask_any_distribute(&p->cpus_mask);
                }
 
                if (task_on_rq_queued(p))
-                       rq = __migrate_task(rq, &rf, p, dest_cpu);
+                       rq = __migrate_task(rq, &rf, p, arg->dest_cpu);
                else
-                       p->wake_cpu = dest_cpu;
+                       p->wake_cpu = arg->dest_cpu;
 
                /*
                 * XXX __migrate_task() can fail, at which point we might end
@@ -2024,7 +2368,7 @@ int push_cpu_stop(void *arg)
        struct task_struct *p = arg;
 
        raw_spin_lock_irq(&p->pi_lock);
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
 
        if (task_rq(p) != rq)
                goto out_unlock;
@@ -2054,7 +2398,7 @@ int push_cpu_stop(void *arg)
 
 out_unlock:
        rq->push_busy = false;
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
        raw_spin_unlock_irq(&p->pi_lock);
 
        put_task_struct(p);
@@ -2107,7 +2451,7 @@ __do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask, u32
                 * Because __kthread_bind() calls this on blocked tasks without
                 * holding rq->lock.
                 */
-               lockdep_assert_held(&rq->lock);
+               lockdep_assert_rq_held(rq);
                dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);
        }
        if (running)
@@ -2249,7 +2593,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                        init_completion(&my_pending.done);
                        my_pending.arg = (struct migration_arg) {
                                .task = p,
-                               .dest_cpu = -1,         /* any */
+                               .dest_cpu = dest_cpu,
                                .pending = &my_pending,
                        };
 
@@ -2257,6 +2601,15 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                } else {
                        pending = p->migration_pending;
                        refcount_inc(&pending->refs);
+                       /*
+                        * Affinity has changed, but we've already installed a
+                        * pending. migration_cpu_stop() *must* see this, else
+                        * we risk a completion of the pending despite having a
+                        * task on a disallowed CPU.
+                        *
+                        * Serialized by p->pi_lock, so this is safe.
+                        */
+                       pending->arg.dest_cpu = dest_cpu;
                }
        }
        pending = p->migration_pending;
@@ -2277,7 +2630,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                return -EINVAL;
        }
 
-       if (task_running(rq, p) || p->state == TASK_WAKING) {
+       if (task_running(rq, p) || READ_ONCE(p->__state) == TASK_WAKING) {
                /*
                 * MIGRATE_ENABLE gets here because 'p == current', but for
                 * anything else we cannot do is_migration_disabled(), punt
@@ -2420,19 +2773,20 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
 void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 {
 #ifdef CONFIG_SCHED_DEBUG
+       unsigned int state = READ_ONCE(p->__state);
+
        /*
         * We should never call set_task_cpu() on a blocked task,
         * ttwu() will sort out the placement.
         */
-       WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
-                       !p->on_rq);
+       WARN_ON_ONCE(state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq);
 
        /*
         * Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING,
         * because schedstat_wait_{start,end} rebase migrating task's wait_start
         * time relying on p->on_rq.
         */
-       WARN_ON_ONCE(p->state == TASK_RUNNING &&
+       WARN_ON_ONCE(state == TASK_RUNNING &&
                     p->sched_class == &fair_sched_class &&
                     (p->on_rq && !task_on_rq_migrating(p)));
 
@@ -2448,7 +2802,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
         * task_rq_lock().
         */
        WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
-                                     lockdep_is_held(&task_rq(p)->lock)));
+                                     lockdep_is_held(__rq_lockp(task_rq(p)))));
 #endif
        /*
         * Clearly, migrating tasks to offline CPUs is a fairly daft thing.
@@ -2604,7 +2958,7 @@ out:
  * smp_call_function() if an IPI is sent by the same process we are
  * waiting to become inactive.
  */
-unsigned long wait_task_inactive(struct task_struct *p, long match_state)
+unsigned long wait_task_inactive(struct task_struct *p, unsigned int match_state)
 {
        int running, queued;
        struct rq_flags rf;
@@ -2632,7 +2986,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                 * is actually now running somewhere else!
                 */
                while (task_running(rq, p)) {
-                       if (match_state && unlikely(p->state != match_state))
+                       if (match_state && unlikely(READ_ONCE(p->__state) != match_state))
                                return 0;
                        cpu_relax();
                }
@@ -2647,7 +3001,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                running = task_running(rq, p);
                queued = task_on_rq_queued(p);
                ncsw = 0;
-               if (!match_state || p->state == match_state)
+               if (!match_state || READ_ONCE(p->__state) == match_state)
                        ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
                task_rq_unlock(rq, p, &rf);
 
@@ -2956,7 +3310,7 @@ static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags,
                           struct rq_flags *rf)
 {
        check_preempt_curr(rq, p, wake_flags);
-       p->state = TASK_RUNNING;
+       WRITE_ONCE(p->__state, TASK_RUNNING);
        trace_sched_wakeup(p);
 
 #ifdef CONFIG_SMP
@@ -2979,6 +3333,9 @@ static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags,
                if (rq->avg_idle > max)
                        rq->avg_idle = max;
 
+               rq->wake_stamp = jiffies;
+               rq->wake_avg_idle = rq->avg_idle / 2;
+
                rq->idle_stamp = 0;
        }
 #endif
@@ -2990,7 +3347,7 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
 {
        int en_flags = ENQUEUE_WAKEUP | ENQUEUE_NOCLOCK;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        if (p->sched_contributes_to_load)
                rq->nr_uninterruptible--;
@@ -3345,12 +3702,12 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
                 *  - we're serialized against set_special_state() by virtue of
                 *    it disabling IRQs (this allows not taking ->pi_lock).
                 */
-               if (!(p->state & state))
+               if (!(READ_ONCE(p->__state) & state))
                        goto out;
 
                success = 1;
                trace_sched_waking(p);
-               p->state = TASK_RUNNING;
+               WRITE_ONCE(p->__state, TASK_RUNNING);
                trace_sched_wakeup(p);
                goto out;
        }
@@ -3363,7 +3720,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
         */
        raw_spin_lock_irqsave(&p->pi_lock, flags);
        smp_mb__after_spinlock();
-       if (!(p->state & state))
+       if (!(READ_ONCE(p->__state) & state))
                goto unlock;
 
        trace_sched_waking(p);
@@ -3429,7 +3786,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
         * TASK_WAKING such that we can unlock p->pi_lock before doing the
         * enqueue, such as ttwu_queue_wakelist().
         */
-       p->state = TASK_WAKING;
+       WRITE_ONCE(p->__state, TASK_WAKING);
 
        /*
         * If the owning (remote) CPU is still in the middle of schedule() with
@@ -3522,7 +3879,7 @@ bool try_invoke_on_locked_down_task(struct task_struct *p, bool (*func)(struct t
                        ret = func(p, arg);
                rq_unlock(rq, &rf);
        } else {
-               switch (p->state) {
+               switch (READ_ONCE(p->__state)) {
                case TASK_RUNNING:
                case TASK_WAKING:
                        break;
@@ -3648,7 +4005,6 @@ int sysctl_numa_balancing(struct ctl_table *table, int write,
 #ifdef CONFIG_SCHEDSTATS
 
 DEFINE_STATIC_KEY_FALSE(sched_schedstats);
-static bool __initdata __sched_schedstats = false;
 
 static void set_schedstats(bool enabled)
 {
@@ -3672,16 +4028,11 @@ static int __init setup_schedstats(char *str)
        if (!str)
                goto out;
 
-       /*
-        * This code is called before jump labels have been set up, so we can't
-        * change the static branch directly just yet.  Instead set a temporary
-        * variable so init_schedstats() can do it later.
-        */
        if (!strcmp(str, "enable")) {
-               __sched_schedstats = true;
+               set_schedstats(true);
                ret = 1;
        } else if (!strcmp(str, "disable")) {
-               __sched_schedstats = false;
+               set_schedstats(false);
                ret = 1;
        }
 out:
@@ -3692,11 +4043,6 @@ out:
 }
 __setup("schedstats=", setup_schedstats);
 
-static void __init init_schedstats(void)
-{
-       set_schedstats(__sched_schedstats);
-}
-
 #ifdef CONFIG_PROC_SYSCTL
 int sysctl_schedstats(struct ctl_table *table, int write, void *buffer,
                size_t *lenp, loff_t *ppos)
@@ -3718,8 +4064,6 @@ int sysctl_schedstats(struct ctl_table *table, int write, void *buffer,
        return err;
 }
 #endif /* CONFIG_PROC_SYSCTL */
-#else  /* !CONFIG_SCHEDSTATS */
-static inline void init_schedstats(void) {}
 #endif /* CONFIG_SCHEDSTATS */
 
 /*
@@ -3735,7 +4079,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
         * nobody will actually run it, and a signal or other external
         * event cannot wake it up and insert it on the runqueue either.
         */
-       p->state = TASK_NEW;
+       p->__state = TASK_NEW;
 
        /*
         * Make sure we do not leak PI boosting priority to the child.
@@ -3841,7 +4185,7 @@ void wake_up_new_task(struct task_struct *p)
        struct rq *rq;
 
        raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
-       p->state = TASK_RUNNING;
+       WRITE_ONCE(p->__state, TASK_RUNNING);
 #ifdef CONFIG_SMP
        /*
         * Fork balancing, do it here and not earlier because:
@@ -4001,7 +4345,7 @@ static void do_balance_callbacks(struct rq *rq, struct callback_head *head)
        void (*func)(struct rq *rq);
        struct callback_head *next;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        while (head) {
                func = (void (*)(struct rq *))head->func;
@@ -4024,7 +4368,7 @@ static inline struct callback_head *splice_balance_callbacks(struct rq *rq)
 {
        struct callback_head *head = rq->balance_callback;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        if (head)
                rq->balance_callback = NULL;
 
@@ -4041,9 +4385,9 @@ static inline void balance_callbacks(struct rq *rq, struct callback_head *head)
        unsigned long flags;
 
        if (unlikely(head)) {
-               raw_spin_lock_irqsave(&rq->lock, flags);
+               raw_spin_rq_lock_irqsave(rq, flags);
                do_balance_callbacks(rq, head);
-               raw_spin_unlock_irqrestore(&rq->lock, flags);
+               raw_spin_rq_unlock_irqrestore(rq, flags);
        }
 }
 
@@ -4074,10 +4418,10 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf
         * do an early lockdep release here:
         */
        rq_unpin_lock(rq, rf);
-       spin_release(&rq->lock.dep_map, _THIS_IP_);
+       spin_release(&__rq_lockp(rq)->dep_map, _THIS_IP_);
 #ifdef CONFIG_DEBUG_SPINLOCK
        /* this is a valid case when another task releases the spinlock */
-       rq->lock.owner = next;
+       rq_lockp(rq)->owner = next;
 #endif
 }
 
@@ -4088,9 +4432,9 @@ static inline void finish_lock_switch(struct rq *rq)
         * fix up the runqueue lock - which gets 'carried over' from
         * prev into current:
         */
-       spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
+       spin_acquire(&__rq_lockp(rq)->dep_map, 0, 0, _THIS_IP_);
        __balance_callbacks(rq);
-       raw_spin_unlock_irq(&rq->lock);
+       raw_spin_rq_unlock_irq(rq);
 }
 
 /*
@@ -4203,10 +4547,11 @@ static struct rq *finish_task_switch(struct task_struct *prev)
         * running on another CPU and we could rave with its RUNNING -> DEAD
         * transition, resulting in a double drop.
         */
-       prev_state = prev->state;
+       prev_state = READ_ONCE(prev->__state);
        vtime_task_switch(prev);
        perf_event_task_sched_in(prev, current);
        finish_task(prev);
+       tick_nohz_task_switch();
        finish_lock_switch(rq);
        finish_arch_post_lock_switch();
        kcov_finish_switch(current);
@@ -4252,7 +4597,6 @@ static struct rq *finish_task_switch(struct task_struct *prev)
                put_task_struct_rcu_user(prev);
        }
 
-       tick_nohz_task_switch();
        return rq;
 }
 
@@ -4348,9 +4692,9 @@ context_switch(struct rq *rq, struct task_struct *prev,
  * externally visible scheduler statistics: current number of runnable
  * threads, total number of context switches performed since bootup.
  */
-unsigned long nr_running(void)
+unsigned int nr_running(void)
 {
-       unsigned long i, sum = 0;
+       unsigned int i, sum = 0;
 
        for_each_online_cpu(i)
                sum += cpu_rq(i)->nr_running;
@@ -4395,7 +4739,7 @@ unsigned long long nr_context_switches(void)
  * it does become runnable.
  */
 
-unsigned long nr_iowait_cpu(int cpu)
+unsigned int nr_iowait_cpu(int cpu)
 {
        return atomic_read(&cpu_rq(cpu)->nr_iowait);
 }
@@ -4430,9 +4774,9 @@ unsigned long nr_iowait_cpu(int cpu)
  * Task CPU affinities can make all that even more 'interesting'.
  */
 
-unsigned long nr_iowait(void)
+unsigned int nr_iowait(void)
 {
-       unsigned long i, sum = 0;
+       unsigned int i, sum = 0;
 
        for_each_possible_cpu(i)
                sum += nr_iowait_cpu(i);
@@ -4897,7 +5241,7 @@ static inline void schedule_debug(struct task_struct *prev, bool preempt)
 #endif
 
 #ifdef CONFIG_DEBUG_ATOMIC_SLEEP
-       if (!preempt && prev->state && prev->non_block_count) {
+       if (!preempt && READ_ONCE(prev->__state) && prev->non_block_count) {
                printk(KERN_ERR "BUG: scheduling in a non-blocking section: %s/%d/%i\n",
                        prev->comm, prev->pid, prev->non_block_count);
                dump_stack();
@@ -4943,7 +5287,7 @@ static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
  * Pick up the highest-prio task:
  */
 static inline struct task_struct *
-pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
+__pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 {
        const struct sched_class *class;
        struct task_struct *p;
@@ -4961,7 +5305,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
                if (unlikely(p == RETRY_TASK))
                        goto restart;
 
-               /* Assumes fair_sched_class->next == idle_sched_class */
+               /* Assume the next prioritized class is idle_sched_class */
                if (!p) {
                        put_prev_task(rq, prev);
                        p = pick_next_task_idle(rq);
@@ -4983,6 +5327,455 @@ restart:
        BUG();
 }
 
+#ifdef CONFIG_SCHED_CORE
+static inline bool is_task_rq_idle(struct task_struct *t)
+{
+       return (task_rq(t)->idle == t);
+}
+
+static inline bool cookie_equals(struct task_struct *a, unsigned long cookie)
+{
+       return is_task_rq_idle(a) || (a->core_cookie == cookie);
+}
+
+static inline bool cookie_match(struct task_struct *a, struct task_struct *b)
+{
+       if (is_task_rq_idle(a) || is_task_rq_idle(b))
+               return true;
+
+       return a->core_cookie == b->core_cookie;
+}
+
+// XXX fairness/fwd progress conditions
+/*
+ * Returns
+ * - NULL if there is no runnable task for this class.
+ * - the highest priority task for this runqueue if it matches
+ *   rq->core->core_cookie or its priority is greater than max.
+ * - Else returns idle_task.
+ */
+static struct task_struct *
+pick_task(struct rq *rq, const struct sched_class *class, struct task_struct *max, bool in_fi)
+{
+       struct task_struct *class_pick, *cookie_pick;
+       unsigned long cookie = rq->core->core_cookie;
+
+       class_pick = class->pick_task(rq);
+       if (!class_pick)
+               return NULL;
+
+       if (!cookie) {
+               /*
+                * If class_pick is tagged, return it only if it has
+                * higher priority than max.
+                */
+               if (max && class_pick->core_cookie &&
+                   prio_less(class_pick, max, in_fi))
+                       return idle_sched_class.pick_task(rq);
+
+               return class_pick;
+       }
+
+       /*
+        * If class_pick is idle or matches cookie, return early.
+        */
+       if (cookie_equals(class_pick, cookie))
+               return class_pick;
+
+       cookie_pick = sched_core_find(rq, cookie);
+
+       /*
+        * If class > max && class > cookie, it is the highest priority task on
+        * the core (so far) and it must be selected, otherwise we must go with
+        * the cookie pick in order to satisfy the constraint.
+        */
+       if (prio_less(cookie_pick, class_pick, in_fi) &&
+           (!max || prio_less(max, class_pick, in_fi)))
+               return class_pick;
+
+       return cookie_pick;
+}
+
+extern void task_vruntime_update(struct rq *rq, struct task_struct *p, bool in_fi);
+
+static struct task_struct *
+pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
+{
+       struct task_struct *next, *max = NULL;
+       const struct sched_class *class;
+       const struct cpumask *smt_mask;
+       bool fi_before = false;
+       int i, j, cpu, occ = 0;
+       bool need_sync;
+
+       if (!sched_core_enabled(rq))
+               return __pick_next_task(rq, prev, rf);
+
+       cpu = cpu_of(rq);
+
+       /* Stopper task is switching into idle, no need core-wide selection. */
+       if (cpu_is_offline(cpu)) {
+               /*
+                * Reset core_pick so that we don't enter the fastpath when
+                * coming online. core_pick would already be migrated to
+                * another cpu during offline.
+                */
+               rq->core_pick = NULL;
+               return __pick_next_task(rq, prev, rf);
+       }
+
+       /*
+        * If there were no {en,de}queues since we picked (IOW, the task
+        * pointers are all still valid), and we haven't scheduled the last
+        * pick yet, do so now.
+        *
+        * rq->core_pick can be NULL if no selection was made for a CPU because
+        * it was either offline or went offline during a sibling's core-wide
+        * selection. In this case, do a core-wide selection.
+        */
+       if (rq->core->core_pick_seq == rq->core->core_task_seq &&
+           rq->core->core_pick_seq != rq->core_sched_seq &&
+           rq->core_pick) {
+               WRITE_ONCE(rq->core_sched_seq, rq->core->core_pick_seq);
+
+               next = rq->core_pick;
+               if (next != prev) {
+                       put_prev_task(rq, prev);
+                       set_next_task(rq, next);
+               }
+
+               rq->core_pick = NULL;
+               return next;
+       }
+
+       put_prev_task_balance(rq, prev, rf);
+
+       smt_mask = cpu_smt_mask(cpu);
+       need_sync = !!rq->core->core_cookie;
+
+       /* reset state */
+       rq->core->core_cookie = 0UL;
+       if (rq->core->core_forceidle) {
+               need_sync = true;
+               fi_before = true;
+               rq->core->core_forceidle = false;
+       }
+
+       /*
+        * core->core_task_seq, core->core_pick_seq, rq->core_sched_seq
+        *
+        * @task_seq guards the task state ({en,de}queues)
+        * @pick_seq is the @task_seq we did a selection on
+        * @sched_seq is the @pick_seq we scheduled
+        *
+        * However, preemptions can cause multiple picks on the same task set.
+        * 'Fix' this by also increasing @task_seq for every pick.
+        */
+       rq->core->core_task_seq++;
+
+       /*
+        * Optimize for common case where this CPU has no cookies
+        * and there are no cookied tasks running on siblings.
+        */
+       if (!need_sync) {
+               for_each_class(class) {
+                       next = class->pick_task(rq);
+                       if (next)
+                               break;
+               }
+
+               if (!next->core_cookie) {
+                       rq->core_pick = NULL;
+                       /*
+                        * For robustness, update the min_vruntime_fi for
+                        * unconstrained picks as well.
+                        */
+                       WARN_ON_ONCE(fi_before);
+                       task_vruntime_update(rq, next, false);
+                       goto done;
+               }
+       }
+
+       for_each_cpu(i, smt_mask) {
+               struct rq *rq_i = cpu_rq(i);
+
+               rq_i->core_pick = NULL;
+
+               if (i != cpu)
+                       update_rq_clock(rq_i);
+       }
+
+       /*
+        * Try and select tasks for each sibling in descending sched_class
+        * order.
+        */
+       for_each_class(class) {
+again:
+               for_each_cpu_wrap(i, smt_mask, cpu) {
+                       struct rq *rq_i = cpu_rq(i);
+                       struct task_struct *p;
+
+                       if (rq_i->core_pick)
+                               continue;
+
+                       /*
+                        * If this sibling doesn't yet have a suitable task to
+                        * run; ask for the most eligible task, given the
+                        * highest priority task already selected for this
+                        * core.
+                        */
+                       p = pick_task(rq_i, class, max, fi_before);
+                       if (!p)
+                               continue;
+
+                       if (!is_task_rq_idle(p))
+                               occ++;
+
+                       rq_i->core_pick = p;
+                       if (rq_i->idle == p && rq_i->nr_running) {
+                               rq->core->core_forceidle = true;
+                               if (!fi_before)
+                                       rq->core->core_forceidle_seq++;
+                       }
+
+                       /*
+                        * If this new candidate is of higher priority than the
+                        * previous; and they're incompatible; we need to wipe
+                        * the slate and start over. pick_task makes sure that
+                        * p's priority is more than max if it doesn't match
+                        * max's cookie.
+                        *
+                        * NOTE: this is a linear max-filter and is thus bounded
+                        * in execution time.
+                        */
+                       if (!max || !cookie_match(max, p)) {
+                               struct task_struct *old_max = max;
+
+                               rq->core->core_cookie = p->core_cookie;
+                               max = p;
+
+                               if (old_max) {
+                                       rq->core->core_forceidle = false;
+                                       for_each_cpu(j, smt_mask) {
+                                               if (j == i)
+                                                       continue;
+
+                                               cpu_rq(j)->core_pick = NULL;
+                                       }
+                                       occ = 1;
+                                       goto again;
+                               }
+                       }
+               }
+       }
+
+       rq->core->core_pick_seq = rq->core->core_task_seq;
+       next = rq->core_pick;
+       rq->core_sched_seq = rq->core->core_pick_seq;
+
+       /* Something should have been selected for current CPU */
+       WARN_ON_ONCE(!next);
+
+       /*
+        * Reschedule siblings
+        *
+        * NOTE: L1TF -- at this point we're no longer running the old task and
+        * sending an IPI (below) ensures the sibling will no longer be running
+        * their task. This ensures there is no inter-sibling overlap between
+        * non-matching user state.
+        */
+       for_each_cpu(i, smt_mask) {
+               struct rq *rq_i = cpu_rq(i);
+
+               /*
+                * An online sibling might have gone offline before a task
+                * could be picked for it, or it might be offline but later
+                * happen to come online, but its too late and nothing was
+                * picked for it.  That's Ok - it will pick tasks for itself,
+                * so ignore it.
+                */
+               if (!rq_i->core_pick)
+                       continue;
+
+               /*
+                * Update for new !FI->FI transitions, or if continuing to be in !FI:
+                * fi_before     fi      update?
+                *  0            0       1
+                *  0            1       1
+                *  1            0       1
+                *  1            1       0
+                */
+               if (!(fi_before && rq->core->core_forceidle))
+                       task_vruntime_update(rq_i, rq_i->core_pick, rq->core->core_forceidle);
+
+               rq_i->core_pick->core_occupation = occ;
+
+               if (i == cpu) {
+                       rq_i->core_pick = NULL;
+                       continue;
+               }
+
+               /* Did we break L1TF mitigation requirements? */
+               WARN_ON_ONCE(!cookie_match(next, rq_i->core_pick));
+
+               if (rq_i->curr == rq_i->core_pick) {
+                       rq_i->core_pick = NULL;
+                       continue;
+               }
+
+               resched_curr(rq_i);
+       }
+
+done:
+       set_next_task(rq, next);
+       return next;
+}
+
+static bool try_steal_cookie(int this, int that)
+{
+       struct rq *dst = cpu_rq(this), *src = cpu_rq(that);
+       struct task_struct *p;
+       unsigned long cookie;
+       bool success = false;
+
+       local_irq_disable();
+       double_rq_lock(dst, src);
+
+       cookie = dst->core->core_cookie;
+       if (!cookie)
+               goto unlock;
+
+       if (dst->curr != dst->idle)
+               goto unlock;
+
+       p = sched_core_find(src, cookie);
+       if (p == src->idle)
+               goto unlock;
+
+       do {
+               if (p == src->core_pick || p == src->curr)
+                       goto next;
+
+               if (!cpumask_test_cpu(this, &p->cpus_mask))
+                       goto next;
+
+               if (p->core_occupation > dst->idle->core_occupation)
+                       goto next;
+
+               p->on_rq = TASK_ON_RQ_MIGRATING;
+               deactivate_task(src, p, 0);
+               set_task_cpu(p, this);
+               activate_task(dst, p, 0);
+               p->on_rq = TASK_ON_RQ_QUEUED;
+
+               resched_curr(dst);
+
+               success = true;
+               break;
+
+next:
+               p = sched_core_next(p, cookie);
+       } while (p);
+
+unlock:
+       double_rq_unlock(dst, src);
+       local_irq_enable();
+
+       return success;
+}
+
+static bool steal_cookie_task(int cpu, struct sched_domain *sd)
+{
+       int i;
+
+       for_each_cpu_wrap(i, sched_domain_span(sd), cpu) {
+               if (i == cpu)
+                       continue;
+
+               if (need_resched())
+                       break;
+
+               if (try_steal_cookie(cpu, i))
+                       return true;
+       }
+
+       return false;
+}
+
+static void sched_core_balance(struct rq *rq)
+{
+       struct sched_domain *sd;
+       int cpu = cpu_of(rq);
+
+       preempt_disable();
+       rcu_read_lock();
+       raw_spin_rq_unlock_irq(rq);
+       for_each_domain(cpu, sd) {
+               if (need_resched())
+                       break;
+
+               if (steal_cookie_task(cpu, sd))
+                       break;
+       }
+       raw_spin_rq_lock_irq(rq);
+       rcu_read_unlock();
+       preempt_enable();
+}
+
+static DEFINE_PER_CPU(struct callback_head, core_balance_head);
+
+void queue_core_balance(struct rq *rq)
+{
+       if (!sched_core_enabled(rq))
+               return;
+
+       if (!rq->core->core_cookie)
+               return;
+
+       if (!rq->nr_running) /* not forced idle */
+               return;
+
+       queue_balance_callback(rq, &per_cpu(core_balance_head, rq->cpu), sched_core_balance);
+}
+
+static inline void sched_core_cpu_starting(unsigned int cpu)
+{
+       const struct cpumask *smt_mask = cpu_smt_mask(cpu);
+       struct rq *rq, *core_rq = NULL;
+       int i;
+
+       core_rq = cpu_rq(cpu)->core;
+
+       if (!core_rq) {
+               for_each_cpu(i, smt_mask) {
+                       rq = cpu_rq(i);
+                       if (rq->core && rq->core == rq)
+                               core_rq = rq;
+               }
+
+               if (!core_rq)
+                       core_rq = cpu_rq(cpu);
+
+               for_each_cpu(i, smt_mask) {
+                       rq = cpu_rq(i);
+
+                       WARN_ON_ONCE(rq->core && rq->core != core_rq);
+                       rq->core = core_rq;
+               }
+       }
+}
+#else /* !CONFIG_SCHED_CORE */
+
+static inline void sched_core_cpu_starting(unsigned int cpu) {}
+
+static struct task_struct *
+pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
+{
+       return __pick_next_task(rq, prev, rf);
+}
+
+#endif /* CONFIG_SCHED_CORE */
+
 /*
  * __schedule() is the main scheduler function.
  *
@@ -5074,10 +5867,10 @@ static void __sched notrace __schedule(bool preempt)
         *  - we form a control dependency vs deactivate_task() below.
         *  - ptrace_{,un}freeze_traced() can change ->state underneath us.
         */
-       prev_state = prev->state;
+       prev_state = READ_ONCE(prev->__state);
        if (!preempt && prev_state) {
                if (signal_pending_state(prev_state, prev)) {
-                       prev->state = TASK_RUNNING;
+                       WRITE_ONCE(prev->__state, TASK_RUNNING);
                } else {
                        prev->sched_contributes_to_load =
                                (prev_state & TASK_UNINTERRUPTIBLE) &&
@@ -5150,7 +5943,7 @@ static void __sched notrace __schedule(bool preempt)
 
                rq_unpin_lock(rq, &rf);
                __balance_callbacks(rq);
-               raw_spin_unlock_irq(&rq->lock);
+               raw_spin_rq_unlock_irq(rq);
        }
 }
 
@@ -5174,7 +5967,7 @@ static inline void sched_submit_work(struct task_struct *tsk)
 {
        unsigned int task_flags;
 
-       if (!tsk->state)
+       if (task_is_running(tsk))
                return;
 
        task_flags = tsk->flags;
@@ -5249,7 +6042,7 @@ void __sched schedule_idle(void)
         * current task can be in any other state. Note, idle is always in the
         * TASK_RUNNING state.
         */
-       WARN_ON_ONCE(current->state);
+       WARN_ON_ONCE(current->__state);
        do {
                __schedule(false);
        } while (need_resched());
@@ -5692,7 +6485,7 @@ out_unlock:
 
        rq_unpin_lock(rq, &rf);
        __balance_callbacks(rq);
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
 
        preempt_enable();
 }
@@ -6389,7 +7182,6 @@ int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
 {
        return __sched_setscheduler(p, attr, false, true);
 }
-EXPORT_SYMBOL_GPL(sched_setattr_nocheck);
 
 /**
  * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
@@ -7149,7 +7941,7 @@ again:
        if (curr->sched_class != p->sched_class)
                goto out_unlock;
 
-       if (task_running(p_rq, p) || p->state)
+       if (task_running(p_rq, p) || !task_is_running(p))
                goto out_unlock;
 
        yielded = curr->sched_class->yield_to_task(rq, p);
@@ -7352,7 +8144,7 @@ void sched_show_task(struct task_struct *p)
 
        pr_info("task:%-15.15s state:%c", p->comm, task_state_to_char(p));
 
-       if (p->state == TASK_RUNNING)
+       if (task_is_running(p))
                pr_cont("  running task    ");
 #ifdef CONFIG_DEBUG_STACK_USAGE
        free = stack_not_used(p);
@@ -7376,26 +8168,28 @@ EXPORT_SYMBOL_GPL(sched_show_task);
 static inline bool
 state_filter_match(unsigned long state_filter, struct task_struct *p)
 {
+       unsigned int state = READ_ONCE(p->__state);
+
        /* no filter, everything matches */
        if (!state_filter)
                return true;
 
        /* filter, but doesn't match */
-       if (!(p->state & state_filter))
+       if (!(state & state_filter))
                return false;
 
        /*
         * When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
         * TASK_KILLABLE).
         */
-       if (state_filter == TASK_UNINTERRUPTIBLE && p->state == TASK_IDLE)
+       if (state_filter == TASK_UNINTERRUPTIBLE && state == TASK_IDLE)
                return false;
 
        return true;
 }
 
 
-void show_state_filter(unsigned long state_filter)
+void show_state_filter(unsigned int state_filter)
 {
        struct task_struct *g, *p;
 
@@ -7434,19 +8228,32 @@ void show_state_filter(unsigned long state_filter)
  * NOTE: this function does not set the idle thread's NEED_RESCHED
  * flag, to make booting more robust.
  */
-void init_idle(struct task_struct *idle, int cpu)
+void __init init_idle(struct task_struct *idle, int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
        unsigned long flags;
 
        __sched_fork(0, idle);
 
+       /*
+        * The idle task doesn't need the kthread struct to function, but it
+        * is dressed up as a per-CPU kthread and thus needs to play the part
+        * if we want to avoid special-casing it in code that deals with per-CPU
+        * kthreads.
+        */
+       set_kthread_struct(idle);
+
        raw_spin_lock_irqsave(&idle->pi_lock, flags);
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
 
-       idle->state = TASK_RUNNING;
+       idle->__state = TASK_RUNNING;
        idle->se.exec_start = sched_clock();
-       idle->flags |= PF_IDLE;
+       /*
+        * PF_KTHREAD should already be set at this point; regardless, make it
+        * look like a proper per-CPU kthread.
+        */
+       idle->flags |= PF_IDLE | PF_KTHREAD | PF_NO_SETAFFINITY;
+       kthread_set_per_cpu(idle, cpu);
 
        scs_task_reset(idle);
        kasan_unpoison_task_stack(idle);
@@ -7480,7 +8287,7 @@ void init_idle(struct task_struct *idle, int cpu)
 #ifdef CONFIG_SMP
        idle->on_cpu = 1;
 #endif
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
        raw_spin_unlock_irqrestore(&idle->pi_lock, flags);
 
        /* Set the preempt count _outside_ the spinlocks! */
@@ -7646,7 +8453,7 @@ static void balance_push(struct rq *rq)
 {
        struct task_struct *push_task = rq->curr;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        SCHED_WARN_ON(rq->cpu != smp_processor_id());
 
        /*
@@ -7663,12 +8470,8 @@ static void balance_push(struct rq *rq)
        /*
         * Both the cpu-hotplug and stop task are in this case and are
         * required to complete the hotplug process.
-        *
-        * XXX: the idle task does not match kthread_is_per_cpu() due to
-        * histerical raisins.
         */
-       if (rq->idle == push_task ||
-           kthread_is_per_cpu(push_task) ||
+       if (kthread_is_per_cpu(push_task) ||
            is_migration_disabled(push_task)) {
 
                /*
@@ -7684,9 +8487,9 @@ static void balance_push(struct rq *rq)
                 */
                if (!rq->nr_running && !rq_has_pinned_tasks(rq) &&
                    rcuwait_active(&rq->hotplug_wait)) {
-                       raw_spin_unlock(&rq->lock);
+                       raw_spin_rq_unlock(rq);
                        rcuwait_wake_up(&rq->hotplug_wait);
-                       raw_spin_lock(&rq->lock);
+                       raw_spin_rq_lock(rq);
                }
                return;
        }
@@ -7696,7 +8499,7 @@ static void balance_push(struct rq *rq)
         * Temporarily drop rq->lock such that we can wake-up the stop task.
         * Both preemption and IRQs are still disabled.
         */
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
        stop_one_cpu_nowait(rq->cpu, __balance_push_cpu_stop, push_task,
                            this_cpu_ptr(&push_work));
        /*
@@ -7704,7 +8507,7 @@ static void balance_push(struct rq *rq)
         * schedule(). The next pick is obviously going to be the stop task
         * which kthread_is_per_cpu() and will push this task away.
         */
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
 }
 
 static void balance_push_set(int cpu, bool on)
@@ -7948,6 +8751,7 @@ static void sched_rq_cpu_starting(unsigned int cpu)
 
 int sched_cpu_starting(unsigned int cpu)
 {
+       sched_core_cpu_starting(cpu);
        sched_rq_cpu_starting(cpu);
        sched_tick_start(cpu);
        return 0;
@@ -7994,7 +8798,7 @@ static void dump_rq_tasks(struct rq *rq, const char *loglvl)
        struct task_struct *g, *p;
        int cpu = cpu_of(rq);
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        printk("%sCPU%d enqueued tasks (%u total):\n", loglvl, cpu, rq->nr_running);
        for_each_process_thread(g, p) {
@@ -8046,6 +8850,7 @@ void __init sched_init_smp(void)
        /* Move init over to a non-isolated CPU */
        if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0)
                BUG();
+       current->flags &= ~PF_NO_SETAFFINITY;
        sched_init_granularity();
 
        init_sched_rt_class();
@@ -8167,7 +8972,7 @@ void __init sched_init(void)
                struct rq *rq;
 
                rq = cpu_rq(i);
-               raw_spin_lock_init(&rq->lock);
+               raw_spin_lock_init(&rq->__lock);
                rq->nr_running = 0;
                rq->calc_load_active = 0;
                rq->calc_load_update = jiffies + LOAD_FREQ;
@@ -8215,6 +9020,8 @@ void __init sched_init(void)
                rq->online = 0;
                rq->idle_stamp = 0;
                rq->avg_idle = 2*sysctl_sched_migration_cost;
+               rq->wake_stamp = jiffies;
+               rq->wake_avg_idle = rq->avg_idle;
                rq->max_idle_balance_cost = sysctl_sched_migration_cost;
 
                INIT_LIST_HEAD(&rq->cfs_tasks);
@@ -8232,6 +9039,16 @@ void __init sched_init(void)
 #endif /* CONFIG_SMP */
                hrtick_rq_init(rq);
                atomic_set(&rq->nr_iowait, 0);
+
+#ifdef CONFIG_SCHED_CORE
+               rq->core = NULL;
+               rq->core_pick = NULL;
+               rq->core_enabled = 0;
+               rq->core_tree = RB_ROOT;
+               rq->core_forceidle = false;
+
+               rq->core_cookie = 0UL;
+#endif
        }
 
        set_load_weight(&init_task, false);
@@ -8258,8 +9075,6 @@ void __init sched_init(void)
 #endif
        init_sched_fair_class();
 
-       init_schedstats();
-
        psi_init();
 
        init_uclamp();
@@ -8277,15 +9092,15 @@ static inline int preempt_count_equals(int preempt_offset)
 
 void __might_sleep(const char *file, int line, int preempt_offset)
 {
+       unsigned int state = get_current_state();
        /*
         * Blocking primitives will set (and therefore destroy) current->state,
         * since we will exit with TASK_RUNNING make sure we enter with it,
         * otherwise we will destroy state.
         */
-       WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change,
+       WARN_ONCE(state != TASK_RUNNING && current->task_state_change,
                        "do not call blocking ops when !TASK_RUNNING; "
-                       "state=%lx set at [<%p>] %pS\n",
-                       current->state,
+                       "state=%x set at [<%p>] %pS\n", state,
                        (void *)current->task_state_change,
                        (void *)current->task_state_change);
 
@@ -8681,7 +9496,11 @@ static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
 
 #ifdef CONFIG_UCLAMP_TASK_GROUP
        /* Propagate the effective uclamp value for the new group */
+       mutex_lock(&uclamp_mutex);
+       rcu_read_lock();
        cpu_util_update_eff(css);
+       rcu_read_unlock();
+       mutex_unlock(&uclamp_mutex);
 #endif
 
        return 0;
@@ -8742,7 +9561,7 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
                 * has happened. This would lead to problems with PELT, due to
                 * move wanting to detach+attach while we're not attached yet.
                 */
-               if (task->state == TASK_NEW)
+               if (READ_ONCE(task->__state) == TASK_NEW)
                        ret = -EINVAL;
                raw_spin_unlock_irq(&task->pi_lock);
 
@@ -8771,6 +9590,9 @@ static void cpu_util_update_eff(struct cgroup_subsys_state *css)
        enum uclamp_id clamp_id;
        unsigned int clamps;
 
+       lockdep_assert_held(&uclamp_mutex);
+       SCHED_WARN_ON(!rcu_read_lock_held());
+
        css_for_each_descendant_pre(css, top_css) {
                uc_parent = css_tg(css)->parent
                        ? css_tg(css)->parent->uclamp : NULL;
@@ -8803,7 +9625,7 @@ static void cpu_util_update_eff(struct cgroup_subsys_state *css)
                }
 
                /* Immediately update descendants RUNNABLE tasks */
-               uclamp_update_active_tasks(css, clamps);
+               uclamp_update_active_tasks(css);
        }
 }
 
@@ -8962,7 +9784,8 @@ static const u64 max_cfs_runtime = MAX_BW * NSEC_PER_USEC;
 
 static int __cfs_schedulable(struct task_group *tg, u64 period, u64 runtime);
 
-static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
+static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota,
+                               u64 burst)
 {
        int i, ret = 0, runtime_enabled, runtime_was_enabled;
        struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
@@ -8992,6 +9815,10 @@ static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
        if (quota != RUNTIME_INF && quota > max_cfs_runtime)
                return -EINVAL;
 
+       if (quota != RUNTIME_INF && (burst > quota ||
+                                    burst + quota > max_cfs_runtime))
+               return -EINVAL;
+
        /*
         * Prevent race between setting of cfs_rq->runtime_enabled and
         * unthrottle_offline_cfs_rqs().
@@ -9013,6 +9840,7 @@ static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
        raw_spin_lock_irq(&cfs_b->lock);
        cfs_b->period = ns_to_ktime(period);
        cfs_b->quota = quota;
+       cfs_b->burst = burst;
 
        __refill_cfs_bandwidth_runtime(cfs_b);
 
@@ -9046,9 +9874,10 @@ out_unlock:
 
 static int tg_set_cfs_quota(struct task_group *tg, long cfs_quota_us)
 {
-       u64 quota, period;
+       u64 quota, period, burst;
 
        period = ktime_to_ns(tg->cfs_bandwidth.period);
+       burst = tg->cfs_bandwidth.burst;
        if (cfs_quota_us < 0)
                quota = RUNTIME_INF;
        else if ((u64)cfs_quota_us <= U64_MAX / NSEC_PER_USEC)
@@ -9056,7 +9885,7 @@ static int tg_set_cfs_quota(struct task_group *tg, long cfs_quota_us)
        else
                return -EINVAL;
 
-       return tg_set_cfs_bandwidth(tg, period, quota);
+       return tg_set_cfs_bandwidth(tg, period, quota, burst);
 }
 
 static long tg_get_cfs_quota(struct task_group *tg)
@@ -9074,15 +9903,16 @@ static long tg_get_cfs_quota(struct task_group *tg)
 
 static int tg_set_cfs_period(struct task_group *tg, long cfs_period_us)
 {
-       u64 quota, period;
+       u64 quota, period, burst;
 
        if ((u64)cfs_period_us > U64_MAX / NSEC_PER_USEC)
                return -EINVAL;
 
        period = (u64)cfs_period_us * NSEC_PER_USEC;
        quota = tg->cfs_bandwidth.quota;
+       burst = tg->cfs_bandwidth.burst;
 
-       return tg_set_cfs_bandwidth(tg, period, quota);
+       return tg_set_cfs_bandwidth(tg, period, quota, burst);
 }
 
 static long tg_get_cfs_period(struct task_group *tg)
@@ -9095,6 +9925,30 @@ static long tg_get_cfs_period(struct task_group *tg)
        return cfs_period_us;
 }
 
+static int tg_set_cfs_burst(struct task_group *tg, long cfs_burst_us)
+{
+       u64 quota, period, burst;
+
+       if ((u64)cfs_burst_us > U64_MAX / NSEC_PER_USEC)
+               return -EINVAL;
+
+       burst = (u64)cfs_burst_us * NSEC_PER_USEC;
+       period = ktime_to_ns(tg->cfs_bandwidth.period);
+       quota = tg->cfs_bandwidth.quota;
+
+       return tg_set_cfs_bandwidth(tg, period, quota, burst);
+}
+
+static long tg_get_cfs_burst(struct task_group *tg)
+{
+       u64 burst_us;
+
+       burst_us = tg->cfs_bandwidth.burst;
+       do_div(burst_us, NSEC_PER_USEC);
+
+       return burst_us;
+}
+
 static s64 cpu_cfs_quota_read_s64(struct cgroup_subsys_state *css,
                                  struct cftype *cft)
 {
@@ -9119,6 +9973,18 @@ static int cpu_cfs_period_write_u64(struct cgroup_subsys_state *css,
        return tg_set_cfs_period(css_tg(css), cfs_period_us);
 }
 
+static u64 cpu_cfs_burst_read_u64(struct cgroup_subsys_state *css,
+                                 struct cftype *cft)
+{
+       return tg_get_cfs_burst(css_tg(css));
+}
+
+static int cpu_cfs_burst_write_u64(struct cgroup_subsys_state *css,
+                                  struct cftype *cftype, u64 cfs_burst_us)
+{
+       return tg_set_cfs_burst(css_tg(css), cfs_burst_us);
+}
+
 struct cfs_schedulable_data {
        struct task_group *tg;
        u64 period, quota;
@@ -9272,6 +10138,11 @@ static struct cftype cpu_legacy_files[] = {
                .write_u64 = cpu_cfs_period_write_u64,
        },
        {
+               .name = "cfs_burst_us",
+               .read_u64 = cpu_cfs_burst_read_u64,
+               .write_u64 = cpu_cfs_burst_write_u64,
+       },
+       {
                .name = "stat",
                .seq_show = cpu_cfs_stat_show,
        },
@@ -9436,12 +10307,13 @@ static ssize_t cpu_max_write(struct kernfs_open_file *of,
 {
        struct task_group *tg = css_tg(of_css(of));
        u64 period = tg_get_cfs_period(tg);
+       u64 burst = tg_get_cfs_burst(tg);
        u64 quota;
        int ret;
 
        ret = cpu_period_quota_parse(buf, &period, &quota);
        if (!ret)
-               ret = tg_set_cfs_bandwidth(tg, period, quota);
+               ret = tg_set_cfs_bandwidth(tg, period, quota, burst);
        return ret ?: nbytes;
 }
 #endif
@@ -9468,6 +10340,12 @@ static struct cftype cpu_files[] = {
                .seq_show = cpu_max_show,
                .write = cpu_max_write,
        },
+       {
+               .name = "max.burst",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .read_u64 = cpu_cfs_burst_read_u64,
+               .write_u64 = cpu_cfs_burst_write_u64,
+       },
 #endif
 #ifdef CONFIG_UCLAMP_TASK_GROUP
        {
diff --git a/kernel/sched/core_sched.c b/kernel/sched/core_sched.c
new file mode 100644 (file)
index 0000000..9a80e9a
--- /dev/null
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/prctl.h>
+#include "sched.h"
+
+/*
+ * A simple wrapper around refcount. An allocated sched_core_cookie's
+ * address is used to compute the cookie of the task.
+ */
+struct sched_core_cookie {
+       refcount_t refcnt;
+};
+
+unsigned long sched_core_alloc_cookie(void)
+{
+       struct sched_core_cookie *ck = kmalloc(sizeof(*ck), GFP_KERNEL);
+       if (!ck)
+               return 0;
+
+       refcount_set(&ck->refcnt, 1);
+       sched_core_get();
+
+       return (unsigned long)ck;
+}
+
+void sched_core_put_cookie(unsigned long cookie)
+{
+       struct sched_core_cookie *ptr = (void *)cookie;
+
+       if (ptr && refcount_dec_and_test(&ptr->refcnt)) {
+               kfree(ptr);
+               sched_core_put();
+       }
+}
+
+unsigned long sched_core_get_cookie(unsigned long cookie)
+{
+       struct sched_core_cookie *ptr = (void *)cookie;
+
+       if (ptr)
+               refcount_inc(&ptr->refcnt);
+
+       return cookie;
+}
+
+/*
+ * sched_core_update_cookie - replace the cookie on a task
+ * @p: the task to update
+ * @cookie: the new cookie
+ *
+ * Effectively exchange the task cookie; caller is responsible for lifetimes on
+ * both ends.
+ *
+ * Returns: the old cookie
+ */
+unsigned long sched_core_update_cookie(struct task_struct *p, unsigned long cookie)
+{
+       unsigned long old_cookie;
+       struct rq_flags rf;
+       struct rq *rq;
+       bool enqueued;
+
+       rq = task_rq_lock(p, &rf);
+
+       /*
+        * Since creating a cookie implies sched_core_get(), and we cannot set
+        * a cookie until after we've created it, similarly, we cannot destroy
+        * a cookie until after we've removed it, we must have core scheduling
+        * enabled here.
+        */
+       SCHED_WARN_ON((p->core_cookie || cookie) && !sched_core_enabled(rq));
+
+       enqueued = sched_core_enqueued(p);
+       if (enqueued)
+               sched_core_dequeue(rq, p);
+
+       old_cookie = p->core_cookie;
+       p->core_cookie = cookie;
+
+       if (enqueued)
+               sched_core_enqueue(rq, p);
+
+       /*
+        * If task is currently running, it may not be compatible anymore after
+        * the cookie change, so enter the scheduler on its CPU to schedule it
+        * away.
+        */
+       if (task_running(rq, p))
+               resched_curr(rq);
+
+       task_rq_unlock(rq, p, &rf);
+
+       return old_cookie;
+}
+
+static unsigned long sched_core_clone_cookie(struct task_struct *p)
+{
+       unsigned long cookie, flags;
+
+       raw_spin_lock_irqsave(&p->pi_lock, flags);
+       cookie = sched_core_get_cookie(p->core_cookie);
+       raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
+       return cookie;
+}
+
+void sched_core_fork(struct task_struct *p)
+{
+       RB_CLEAR_NODE(&p->core_node);
+       p->core_cookie = sched_core_clone_cookie(current);
+}
+
+void sched_core_free(struct task_struct *p)
+{
+       sched_core_put_cookie(p->core_cookie);
+}
+
+static void __sched_core_set(struct task_struct *p, unsigned long cookie)
+{
+       cookie = sched_core_get_cookie(cookie);
+       cookie = sched_core_update_cookie(p, cookie);
+       sched_core_put_cookie(cookie);
+}
+
+/* Called from prctl interface: PR_SCHED_CORE */
+int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type,
+                        unsigned long uaddr)
+{
+       unsigned long cookie = 0, id = 0;
+       struct task_struct *task, *p;
+       struct pid *grp;
+       int err = 0;
+
+       if (!static_branch_likely(&sched_smt_present))
+               return -ENODEV;
+
+       if (type > PIDTYPE_PGID || cmd >= PR_SCHED_CORE_MAX || pid < 0 ||
+           (cmd != PR_SCHED_CORE_GET && uaddr))
+               return -EINVAL;
+
+       rcu_read_lock();
+       if (pid == 0) {
+               task = current;
+       } else {
+               task = find_task_by_vpid(pid);
+               if (!task) {
+                       rcu_read_unlock();
+                       return -ESRCH;
+               }
+       }
+       get_task_struct(task);
+       rcu_read_unlock();
+
+       /*
+        * Check if this process has the right to modify the specified
+        * process. Use the regular "ptrace_may_access()" checks.
+        */
+       if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
+               err = -EPERM;
+               goto out;
+       }
+
+       switch (cmd) {
+       case PR_SCHED_CORE_GET:
+               if (type != PIDTYPE_PID || uaddr & 7) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               cookie = sched_core_clone_cookie(task);
+               if (cookie) {
+                       /* XXX improve ? */
+                       ptr_to_hashval((void *)cookie, &id);
+               }
+               err = put_user(id, (u64 __user *)uaddr);
+               goto out;
+
+       case PR_SCHED_CORE_CREATE:
+               cookie = sched_core_alloc_cookie();
+               if (!cookie) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               break;
+
+       case PR_SCHED_CORE_SHARE_TO:
+               cookie = sched_core_clone_cookie(current);
+               break;
+
+       case PR_SCHED_CORE_SHARE_FROM:
+               if (type != PIDTYPE_PID) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               cookie = sched_core_clone_cookie(task);
+               __sched_core_set(current, cookie);
+               goto out;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       };
+
+       if (type == PIDTYPE_PID) {
+               __sched_core_set(task, cookie);
+               goto out;
+       }
+
+       read_lock(&tasklist_lock);
+       grp = task_pid_type(task, type);
+
+       do_each_pid_thread(grp, type, p) {
+               if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) {
+                       err = -EPERM;
+                       goto out_tasklist;
+               }
+       } while_each_pid_thread(grp, type, p);
+
+       do_each_pid_thread(grp, type, p) {
+               __sched_core_set(p, cookie);
+       } while_each_pid_thread(grp, type, p);
+out_tasklist:
+       read_unlock(&tasklist_lock);
+
+out:
+       sched_core_put_cookie(cookie);
+       put_task_struct(task);
+       return err;
+}
+
index 104a1ba..893eece 100644 (file)
@@ -112,7 +112,7 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
        /*
         * Take rq->lock to make 64-bit read safe on 32-bit platforms.
         */
-       raw_spin_lock_irq(&cpu_rq(cpu)->lock);
+       raw_spin_rq_lock_irq(cpu_rq(cpu));
 #endif
 
        if (index == CPUACCT_STAT_NSTATS) {
@@ -126,7 +126,7 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
        }
 
 #ifndef CONFIG_64BIT
-       raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
+       raw_spin_rq_unlock_irq(cpu_rq(cpu));
 #endif
 
        return data;
@@ -141,14 +141,14 @@ static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
        /*
         * Take rq->lock to make 64-bit write safe on 32-bit platforms.
         */
-       raw_spin_lock_irq(&cpu_rq(cpu)->lock);
+       raw_spin_rq_lock_irq(cpu_rq(cpu));
 #endif
 
        for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
                cpuusage->usages[i] = val;
 
 #ifndef CONFIG_64BIT
-       raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
+       raw_spin_rq_unlock_irq(cpu_rq(cpu));
 #endif
 }
 
@@ -253,13 +253,13 @@ static int cpuacct_all_seq_show(struct seq_file *m, void *V)
                         * Take rq->lock to make 64-bit read safe on 32-bit
                         * platforms.
                         */
-                       raw_spin_lock_irq(&cpu_rq(cpu)->lock);
+                       raw_spin_rq_lock_irq(cpu_rq(cpu));
 #endif
 
                        seq_printf(m, " %llu", cpuusage->usages[index]);
 
 #ifndef CONFIG_64BIT
-                       raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
+                       raw_spin_rq_unlock_irq(cpu_rq(cpu));
 #endif
                }
                seq_puts(m, "\n");
index 4f09afd..5712461 100644 (file)
@@ -151,6 +151,7 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
        unsigned int freq = arch_scale_freq_invariant() ?
                                policy->cpuinfo.max_freq : policy->cur;
 
+       util = map_util_perf(util);
        freq = map_util_freq(util, freq, max);
 
        if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update)
index 9a29897..aaacd6c 100644 (file)
@@ -157,7 +157,7 @@ void __add_running_bw(u64 dl_bw, struct dl_rq *dl_rq)
 {
        u64 old = dl_rq->running_bw;
 
-       lockdep_assert_held(&(rq_of_dl_rq(dl_rq))->lock);
+       lockdep_assert_rq_held(rq_of_dl_rq(dl_rq));
        dl_rq->running_bw += dl_bw;
        SCHED_WARN_ON(dl_rq->running_bw < old); /* overflow */
        SCHED_WARN_ON(dl_rq->running_bw > dl_rq->this_bw);
@@ -170,7 +170,7 @@ void __sub_running_bw(u64 dl_bw, struct dl_rq *dl_rq)
 {
        u64 old = dl_rq->running_bw;
 
-       lockdep_assert_held(&(rq_of_dl_rq(dl_rq))->lock);
+       lockdep_assert_rq_held(rq_of_dl_rq(dl_rq));
        dl_rq->running_bw -= dl_bw;
        SCHED_WARN_ON(dl_rq->running_bw > old); /* underflow */
        if (dl_rq->running_bw > old)
@@ -184,7 +184,7 @@ void __add_rq_bw(u64 dl_bw, struct dl_rq *dl_rq)
 {
        u64 old = dl_rq->this_bw;
 
-       lockdep_assert_held(&(rq_of_dl_rq(dl_rq))->lock);
+       lockdep_assert_rq_held(rq_of_dl_rq(dl_rq));
        dl_rq->this_bw += dl_bw;
        SCHED_WARN_ON(dl_rq->this_bw < old); /* overflow */
 }
@@ -194,7 +194,7 @@ void __sub_rq_bw(u64 dl_bw, struct dl_rq *dl_rq)
 {
        u64 old = dl_rq->this_bw;
 
-       lockdep_assert_held(&(rq_of_dl_rq(dl_rq))->lock);
+       lockdep_assert_rq_held(rq_of_dl_rq(dl_rq));
        dl_rq->this_bw -= dl_bw;
        SCHED_WARN_ON(dl_rq->this_bw > old); /* underflow */
        if (dl_rq->this_bw > old)
@@ -348,10 +348,10 @@ static void task_non_contending(struct task_struct *p)
        if ((zerolag_time < 0) || hrtimer_active(&dl_se->inactive_timer)) {
                if (dl_task(p))
                        sub_running_bw(dl_se, dl_rq);
-               if (!dl_task(p) || p->state == TASK_DEAD) {
+               if (!dl_task(p) || READ_ONCE(p->__state) == TASK_DEAD) {
                        struct dl_bw *dl_b = dl_bw_of(task_cpu(p));
 
-                       if (p->state == TASK_DEAD)
+                       if (READ_ONCE(p->__state) == TASK_DEAD)
                                sub_rq_bw(&p->dl, &rq->dl);
                        raw_spin_lock(&dl_b->lock);
                        __dl_sub(dl_b, p->dl.dl_bw, dl_bw_cpus(task_cpu(p)));
@@ -987,7 +987,7 @@ static int start_dl_timer(struct task_struct *p)
        ktime_t now, act;
        s64 delta;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        /*
         * We want the timer to fire at the deadline, but considering
@@ -1097,9 +1097,9 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer)
                 * If the runqueue is no longer available, migrate the
                 * task elsewhere. This necessarily changes rq.
                 */
-               lockdep_unpin_lock(&rq->lock, rf.cookie);
+               lockdep_unpin_lock(__rq_lockp(rq), rf.cookie);
                rq = dl_task_offline_migration(rq, p);
-               rf.cookie = lockdep_pin_lock(&rq->lock);
+               rf.cookie = lockdep_pin_lock(__rq_lockp(rq));
                update_rq_clock(rq);
 
                /*
@@ -1355,10 +1355,10 @@ static enum hrtimer_restart inactive_task_timer(struct hrtimer *timer)
        sched_clock_tick();
        update_rq_clock(rq);
 
-       if (!dl_task(p) || p->state == TASK_DEAD) {
+       if (!dl_task(p) || READ_ONCE(p->__state) == TASK_DEAD) {
                struct dl_bw *dl_b = dl_bw_of(task_cpu(p));
 
-               if (p->state == TASK_DEAD && dl_se->dl_non_contending) {
+               if (READ_ONCE(p->__state) == TASK_DEAD && dl_se->dl_non_contending) {
                        sub_running_bw(&p->dl, dl_rq_of_se(&p->dl));
                        sub_rq_bw(&p->dl, dl_rq_of_se(&p->dl));
                        dl_se->dl_non_contending = 0;
@@ -1722,7 +1722,7 @@ static void migrate_task_rq_dl(struct task_struct *p, int new_cpu __maybe_unused
 {
        struct rq *rq;
 
-       if (p->state != TASK_WAKING)
+       if (READ_ONCE(p->__state) != TASK_WAKING)
                return;
 
        rq = task_rq(p);
@@ -1731,7 +1731,7 @@ static void migrate_task_rq_dl(struct task_struct *p, int new_cpu __maybe_unused
         * from try_to_wake_up(). Hence, p->pi_lock is locked, but
         * rq->lock is not... So, lock it
         */
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
        if (p->dl.dl_non_contending) {
                sub_running_bw(&p->dl, &rq->dl);
                p->dl.dl_non_contending = 0;
@@ -1746,7 +1746,7 @@ static void migrate_task_rq_dl(struct task_struct *p, int new_cpu __maybe_unused
                        put_task_struct(p);
        }
        sub_rq_bw(&p->dl, &rq->dl);
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
 }
 
 static void check_preempt_equal_dl(struct rq *rq, struct task_struct *p)
@@ -1852,7 +1852,7 @@ static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,
        return rb_entry(left, struct sched_dl_entity, rb_node);
 }
 
-static struct task_struct *pick_next_task_dl(struct rq *rq)
+static struct task_struct *pick_task_dl(struct rq *rq)
 {
        struct sched_dl_entity *dl_se;
        struct dl_rq *dl_rq = &rq->dl;
@@ -1864,7 +1864,18 @@ static struct task_struct *pick_next_task_dl(struct rq *rq)
        dl_se = pick_next_dl_entity(rq, dl_rq);
        BUG_ON(!dl_se);
        p = dl_task_of(dl_se);
-       set_next_task_dl(rq, p, true);
+
+       return p;
+}
+
+static struct task_struct *pick_next_task_dl(struct rq *rq)
+{
+       struct task_struct *p;
+
+       p = pick_task_dl(rq);
+       if (p)
+               set_next_task_dl(rq, p, true);
+
        return p;
 }
 
@@ -2291,10 +2302,10 @@ skip:
                double_unlock_balance(this_rq, src_rq);
 
                if (push_task) {
-                       raw_spin_unlock(&this_rq->lock);
+                       raw_spin_rq_unlock(this_rq);
                        stop_one_cpu_nowait(src_rq->cpu, push_cpu_stop,
                                            push_task, &src_rq->push_work);
-                       raw_spin_lock(&this_rq->lock);
+                       raw_spin_rq_lock(this_rq);
                }
        }
 
@@ -2486,6 +2497,8 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
                        check_preempt_curr_dl(rq, p, 0);
                else
                        resched_curr(rq);
+       } else {
+               update_dl_rq_load_avg(rq_clock_pelt(rq), rq, 0);
        }
 }
 
@@ -2539,6 +2552,7 @@ DEFINE_SCHED_CLASS(dl) = {
 
 #ifdef CONFIG_SMP
        .balance                = balance_dl,
+       .pick_task              = pick_task_dl,
        .select_task_rq         = select_task_rq_dl,
        .migrate_task_rq        = migrate_task_rq_dl,
        .set_cpus_allowed       = set_cpus_allowed_dl,
index c5aacbd..0c5ec27 100644 (file)
@@ -576,7 +576,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
        SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
                        SPLIT_NS(cfs_rq->exec_clock));
 
-       raw_spin_lock_irqsave(&rq->lock, flags);
+       raw_spin_rq_lock_irqsave(rq, flags);
        if (rb_first_cached(&cfs_rq->tasks_timeline))
                MIN_vruntime = (__pick_first_entity(cfs_rq))->vruntime;
        last = __pick_last_entity(cfs_rq);
@@ -584,7 +584,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
                max_vruntime = last->vruntime;
        min_vruntime = cfs_rq->min_vruntime;
        rq0_min_vruntime = cpu_rq(0)->cfs.min_vruntime;
-       raw_spin_unlock_irqrestore(&rq->lock, flags);
+       raw_spin_rq_unlock_irqrestore(rq, flags);
        SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "MIN_vruntime",
                        SPLIT_NS(MIN_vruntime));
        SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "min_vruntime",
index 2c8a935..e6d1dd4 100644 (file)
@@ -268,33 +268,11 @@ const struct sched_class fair_sched_class;
  */
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-static inline struct task_struct *task_of(struct sched_entity *se)
-{
-       SCHED_WARN_ON(!entity_is_task(se));
-       return container_of(se, struct task_struct, se);
-}
 
 /* Walk up scheduling entities hierarchy */
 #define for_each_sched_entity(se) \
                for (; se; se = se->parent)
 
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
-{
-       return p->se.cfs_rq;
-}
-
-/* runqueue on which this entity is (to be) queued */
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-       return se->cfs_rq;
-}
-
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-       return grp->my_q;
-}
-
 static inline void cfs_rq_tg_path(struct cfs_rq *cfs_rq, char *path, int len)
 {
        if (!path)
@@ -455,33 +433,9 @@ find_matching_se(struct sched_entity **se, struct sched_entity **pse)
 
 #else  /* !CONFIG_FAIR_GROUP_SCHED */
 
-static inline struct task_struct *task_of(struct sched_entity *se)
-{
-       return container_of(se, struct task_struct, se);
-}
-
 #define for_each_sched_entity(se) \
                for (; se; se = NULL)
 
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
-{
-       return &task_rq(p)->cfs;
-}
-
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-       struct task_struct *p = task_of(se);
-       struct rq *rq = task_rq(p);
-
-       return &rq->cfs;
-}
-
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-       return NULL;
-}
-
 static inline void cfs_rq_tg_path(struct cfs_rq *cfs_rq, char *path, int len)
 {
        if (path)
@@ -1039,11 +993,14 @@ update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 
        if ((flags & DEQUEUE_SLEEP) && entity_is_task(se)) {
                struct task_struct *tsk = task_of(se);
+               unsigned int state;
 
-               if (tsk->state & TASK_INTERRUPTIBLE)
+               /* XXX racy against TTWU */
+               state = READ_ONCE(tsk->__state);
+               if (state & TASK_INTERRUPTIBLE)
                        __schedstat_set(se->statistics.sleep_start,
                                      rq_clock(rq_of(cfs_rq)));
-               if (tsk->state & TASK_UNINTERRUPTIBLE)
+               if (state & TASK_UNINTERRUPTIBLE)
                        __schedstat_set(se->statistics.block_start,
                                      rq_clock(rq_of(cfs_rq)));
        }
@@ -1107,7 +1064,7 @@ struct numa_group {
 static struct numa_group *deref_task_numa_group(struct task_struct *p)
 {
        return rcu_dereference_check(p->numa_group, p == current ||
-               (lockdep_is_held(&task_rq(p)->lock) && !READ_ONCE(p->on_cpu)));
+               (lockdep_is_held(__rq_lockp(task_rq(p))) && !READ_ONCE(p->on_cpu)));
 }
 
 static struct numa_group *deref_curr_numa_group(struct task_struct *p)
@@ -3139,7 +3096,7 @@ void reweight_task(struct task_struct *p, int prio)
  *
  *                     tg->weight * grq->load.weight
  *   ge->load.weight = -----------------------------               (1)
- *                       \Sum grq->load.weight
+ *                       \Sum grq->load.weight
  *
  * Now, because computing that sum is prohibitively expensive to compute (been
  * there, done that) we approximate it with this average stuff. The average
@@ -3153,7 +3110,7 @@ void reweight_task(struct task_struct *p, int prio)
  *
  *                     tg->weight * grq->avg.load_avg
  *   ge->load.weight = ------------------------------              (3)
- *                             tg->load_avg
+ *                             tg->load_avg
  *
  * Where: tg->load_avg ~= \Sum grq->avg.load_avg
  *
@@ -3169,7 +3126,7 @@ void reweight_task(struct task_struct *p, int prio)
  *
  *                     tg->weight * grq->load.weight
  *   ge->load.weight = ----------------------------- = tg->weight   (4)
- *                         grp->load.weight
+ *                         grp->load.weight
  *
  * That is, the sum collapses because all other CPUs are idle; the UP scenario.
  *
@@ -3188,7 +3145,7 @@ void reweight_task(struct task_struct *p, int prio)
  *
  *                     tg->weight * grq->load.weight
  *   ge->load.weight = -----------------------------              (6)
- *                             tg_load_avg'
+ *                             tg_load_avg'
  *
  * Where:
  *
@@ -3298,6 +3255,61 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_FAIR_GROUP_SCHED
+/*
+ * Because list_add_leaf_cfs_rq always places a child cfs_rq on the list
+ * immediately before a parent cfs_rq, and cfs_rqs are removed from the list
+ * bottom-up, we only have to test whether the cfs_rq before us on the list
+ * is our child.
+ * If cfs_rq is not on the list, test whether a child needs its to be added to
+ * connect a branch to the tree  * (see list_add_leaf_cfs_rq() for details).
+ */
+static inline bool child_cfs_rq_on_list(struct cfs_rq *cfs_rq)
+{
+       struct cfs_rq *prev_cfs_rq;
+       struct list_head *prev;
+
+       if (cfs_rq->on_list) {
+               prev = cfs_rq->leaf_cfs_rq_list.prev;
+       } else {
+               struct rq *rq = rq_of(cfs_rq);
+
+               prev = rq->tmp_alone_branch;
+       }
+
+       prev_cfs_rq = container_of(prev, struct cfs_rq, leaf_cfs_rq_list);
+
+       return (prev_cfs_rq->tg->parent == cfs_rq->tg);
+}
+
+static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
+{
+       if (cfs_rq->load.weight)
+               return false;
+
+       if (cfs_rq->avg.load_sum)
+               return false;
+
+       if (cfs_rq->avg.util_sum)
+               return false;
+
+       if (cfs_rq->avg.runnable_sum)
+               return false;
+
+       if (child_cfs_rq_on_list(cfs_rq))
+               return false;
+
+       /*
+        * _avg must be null when _sum are null because _avg = _sum / divider
+        * Make sure that rounding and/or propagation of PELT values never
+        * break this.
+        */
+       SCHED_WARN_ON(cfs_rq->avg.load_avg ||
+                     cfs_rq->avg.util_avg ||
+                     cfs_rq->avg.runnable_avg);
+
+       return true;
+}
+
 /**
  * update_tg_load_avg - update the tg's load avg
  * @cfs_rq: the cfs_rq whose avg changed
@@ -3548,9 +3560,12 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
        load_sum = (s64)se_weight(se) * runnable_sum;
        load_avg = div_s64(load_sum, divider);
 
+       se->avg.load_sum = runnable_sum;
+
        delta = load_avg - se->avg.load_avg;
+       if (!delta)
+               return;
 
-       se->avg.load_sum = runnable_sum;
        se->avg.load_avg = load_avg;
 
        add_positive(&cfs_rq->avg.load_avg, delta);
@@ -4091,6 +4106,11 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq)
 
 #else /* CONFIG_SMP */
 
+static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
+{
+       return true;
+}
+
 #define UPDATE_TG      0x0
 #define SKIP_AGE_LOAD  0x0
 #define DO_ATTACH      0x0
@@ -4425,6 +4445,8 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
 static void
 set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
+       clear_buddies(cfs_rq, se);
+
        /* 'current' is not kept within the tree. */
        if (se->on_rq) {
                /*
@@ -4484,7 +4506,7 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
         * Avoid running the skip buddy, if running something else can
         * be done without getting too unfair.
         */
-       if (cfs_rq->skip == se) {
+       if (cfs_rq->skip && cfs_rq->skip == se) {
                struct sched_entity *second;
 
                if (se == curr) {
@@ -4511,8 +4533,6 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
                se = cfs_rq->last;
        }
 
-       clear_buddies(cfs_rq, se);
-
        return se;
 }
 
@@ -4634,8 +4654,11 @@ static inline u64 sched_cfs_bandwidth_slice(void)
  */
 void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
 {
-       if (cfs_b->quota != RUNTIME_INF)
-               cfs_b->runtime = cfs_b->quota;
+       if (unlikely(cfs_b->quota == RUNTIME_INF))
+               return;
+
+       cfs_b->runtime += cfs_b->quota;
+       cfs_b->runtime = min(cfs_b->runtime, cfs_b->quota + cfs_b->burst);
 }
 
 static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
@@ -4749,8 +4772,8 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
                cfs_rq->throttled_clock_task_time += rq_clock_task(rq) -
                                             cfs_rq->throttled_clock_task;
 
-               /* Add cfs_rq with already running entity in the list */
-               if (cfs_rq->nr_running >= 1)
+               /* Add cfs_rq with load or one or more already running entities to the list */
+               if (!cfs_rq_is_decayed(cfs_rq) || cfs_rq->nr_running)
                        list_add_leaf_cfs_rq(cfs_rq);
        }
 
@@ -4996,6 +5019,9 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, u
        throttled = !list_empty(&cfs_b->throttled_cfs_rq);
        cfs_b->nr_periods += overrun;
 
+       /* Refill extra burst quota even if cfs_b->idle */
+       __refill_cfs_bandwidth_runtime(cfs_b);
+
        /*
         * idle depends on !throttled (for the case of a large deficit), and if
         * we're going inactive then everything else can be deferred
@@ -5003,8 +5029,6 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, u
        if (cfs_b->idle && !throttled)
                goto out_deactivate;
 
-       __refill_cfs_bandwidth_runtime(cfs_b);
-
        if (!throttled) {
                /* mark as potentially idle for the upcoming period */
                cfs_b->idle = 1;
@@ -5254,6 +5278,7 @@ static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer)
                        if (new < max_cfs_quota_period) {
                                cfs_b->period = ns_to_ktime(new);
                                cfs_b->quota *= 2;
+                               cfs_b->burst *= 2;
 
                                pr_warn_ratelimited(
        "cfs_period_timer[cpu%d]: period too short, scaling up (new cfs_period_us = %lld, cfs_quota_us = %lld)\n",
@@ -5285,6 +5310,7 @@ void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
        cfs_b->runtime = 0;
        cfs_b->quota = RUNTIME_INF;
        cfs_b->period = ns_to_ktime(default_cfs_period());
+       cfs_b->burst = 0;
 
        INIT_LIST_HEAD(&cfs_b->throttled_cfs_rq);
        hrtimer_init(&cfs_b->period_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
@@ -5334,7 +5360,7 @@ static void __maybe_unused update_runtime_enabled(struct rq *rq)
 {
        struct task_group *tg;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        rcu_read_lock();
        list_for_each_entry_rcu(tg, &task_groups, list) {
@@ -5353,7 +5379,7 @@ static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq)
 {
        struct task_group *tg;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        rcu_read_lock();
        list_for_each_entry_rcu(tg, &task_groups, list) {
@@ -5941,11 +5967,15 @@ find_idlest_group_cpu(struct sched_group *group, struct task_struct *p, int this
 
        /* Traverse only the allowed CPUs */
        for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) {
+               struct rq *rq = cpu_rq(i);
+
+               if (!sched_core_cookie_match(rq, p))
+                       continue;
+
                if (sched_idle_cpu(i))
                        return i;
 
                if (available_idle_cpu(i)) {
-                       struct rq *rq = cpu_rq(i);
                        struct cpuidle_state *idle = idle_get_state(rq);
                        if (idle && idle->exit_latency < min_exit_latency) {
                                /*
@@ -6031,9 +6061,10 @@ static inline int find_idlest_cpu(struct sched_domain *sd, struct task_struct *p
        return new_cpu;
 }
 
-static inline int __select_idle_cpu(int cpu)
+static inline int __select_idle_cpu(int cpu, struct task_struct *p)
 {
-       if (available_idle_cpu(cpu) || sched_idle_cpu(cpu))
+       if ((available_idle_cpu(cpu) || sched_idle_cpu(cpu)) &&
+           sched_cpu_cookie_match(cpu_rq(cpu), p))
                return cpu;
 
        return -1;
@@ -6103,7 +6134,7 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu
        int cpu;
 
        if (!static_branch_likely(&sched_smt_present))
-               return __select_idle_cpu(core);
+               return __select_idle_cpu(core, p);
 
        for_each_cpu(cpu, cpu_smt_mask(core)) {
                if (!available_idle_cpu(cpu)) {
@@ -6159,7 +6190,7 @@ static inline bool test_idle_cores(int cpu, bool def)
 
 static inline int select_idle_core(struct task_struct *p, int core, struct cpumask *cpus, int *idle_cpu)
 {
-       return __select_idle_cpu(core);
+       return __select_idle_cpu(core, p);
 }
 
 static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target)
@@ -6178,9 +6209,10 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
 {
        struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
        int i, cpu, idle_cpu = -1, nr = INT_MAX;
+       struct rq *this_rq = this_rq();
        int this = smp_processor_id();
        struct sched_domain *this_sd;
-       u64 time;
+       u64 time = 0;
 
        this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc));
        if (!this_sd)
@@ -6190,12 +6222,21 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
 
        if (sched_feat(SIS_PROP) && !has_idle_core) {
                u64 avg_cost, avg_idle, span_avg;
+               unsigned long now = jiffies;
 
                /*
-                * Due to large variance we need a large fuzz factor;
-                * hackbench in particularly is sensitive here.
+                * If we're busy, the assumption that the last idle period
+                * predicts the future is flawed; age away the remaining
+                * predicted idle time.
                 */
-               avg_idle = this_rq()->avg_idle / 512;
+               if (unlikely(this_rq->wake_stamp < now)) {
+                       while (this_rq->wake_stamp < now && this_rq->wake_avg_idle) {
+                               this_rq->wake_stamp++;
+                               this_rq->wake_avg_idle >>= 1;
+                       }
+               }
+
+               avg_idle = this_rq->wake_avg_idle;
                avg_cost = this_sd->avg_scan_cost + 1;
 
                span_avg = sd->span_weight * avg_idle;
@@ -6216,7 +6257,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
                } else {
                        if (!--nr)
                                return -1;
-                       idle_cpu = __select_idle_cpu(cpu);
+                       idle_cpu = __select_idle_cpu(cpu, p);
                        if ((unsigned int)idle_cpu < nr_cpumask_bits)
                                break;
                }
@@ -6227,6 +6268,13 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
 
        if (sched_feat(SIS_PROP) && !has_idle_core) {
                time = cpu_clock(this) - time;
+
+               /*
+                * Account for the scan cost of wakeups against the average
+                * idle time.
+                */
+               this_rq->wake_avg_idle -= min(this_rq->wake_avg_idle, time);
+
                update_avg(&this_sd->avg_scan_cost, time);
        }
 
@@ -6294,6 +6342,11 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
                task_util = uclamp_task_util(p);
        }
 
+       /*
+        * per-cpu select_idle_mask usage
+        */
+       lockdep_assert_irqs_disabled();
+
        if ((available_idle_cpu(target) || sched_idle_cpu(target)) &&
            asym_fits_capacity(task_util, target))
                return target;
@@ -6569,8 +6622,11 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
        struct cpumask *pd_mask = perf_domain_span(pd);
        unsigned long cpu_cap = arch_scale_cpu_capacity(cpumask_first(pd_mask));
        unsigned long max_util = 0, sum_util = 0;
+       unsigned long _cpu_cap = cpu_cap;
        int cpu;
 
+       _cpu_cap -= arch_scale_thermal_pressure(cpumask_first(pd_mask));
+
        /*
         * The capacity state of CPUs of the current rd can be driven by CPUs
         * of another rd if they belong to the same pd. So, account for the
@@ -6606,8 +6662,10 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
                 * is already enough to scale the EM reported power
                 * consumption at the (eventually clamped) cpu_capacity.
                 */
-               sum_util += effective_cpu_util(cpu, util_running, cpu_cap,
-                                              ENERGY_UTIL, NULL);
+               cpu_util = effective_cpu_util(cpu, util_running, cpu_cap,
+                                             ENERGY_UTIL, NULL);
+
+               sum_util += min(cpu_util, _cpu_cap);
 
                /*
                 * Performance domain frequency: utilization clamping
@@ -6618,10 +6676,10 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
                 */
                cpu_util = effective_cpu_util(cpu, util_freq, cpu_cap,
                                              FREQUENCY_UTIL, tsk);
-               max_util = max(max_util, cpu_util);
+               max_util = max(max_util, min(cpu_util, _cpu_cap));
        }
 
-       return em_cpu_energy(pd->em_pd, max_util, sum_util);
+       return em_cpu_energy(pd->em_pd, max_util, sum_util, _cpu_cap);
 }
 
 /*
@@ -6667,15 +6725,15 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
 {
        unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX;
        struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
+       int cpu, best_energy_cpu = prev_cpu, target = -1;
        unsigned long cpu_cap, util, base_energy = 0;
-       int cpu, best_energy_cpu = prev_cpu;
        struct sched_domain *sd;
        struct perf_domain *pd;
 
        rcu_read_lock();
        pd = rcu_dereference(rd->pd);
        if (!pd || READ_ONCE(rd->overutilized))
-               goto fail;
+               goto unlock;
 
        /*
         * Energy-aware wake-up happens on the lowest sched_domain starting
@@ -6685,7 +6743,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
        while (sd && !cpumask_test_cpu(prev_cpu, sched_domain_span(sd)))
                sd = sd->parent;
        if (!sd)
-               goto fail;
+               goto unlock;
+
+       target = prev_cpu;
 
        sync_entity_load_avg(&p->se);
        if (!task_util_est(p))
@@ -6693,13 +6753,10 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
 
        for (; pd; pd = pd->next) {
                unsigned long cur_delta, spare_cap, max_spare_cap = 0;
+               bool compute_prev_delta = false;
                unsigned long base_energy_pd;
                int max_spare_cap_cpu = -1;
 
-               /* Compute the 'base' energy of the pd, without @p */
-               base_energy_pd = compute_energy(p, -1, pd);
-               base_energy += base_energy_pd;
-
                for_each_cpu_and(cpu, perf_domain_span(pd), sched_domain_span(sd)) {
                        if (!cpumask_test_cpu(cpu, p->cpus_ptr))
                                continue;
@@ -6720,26 +6777,40 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                        if (!fits_capacity(util, cpu_cap))
                                continue;
 
-                       /* Always use prev_cpu as a candidate. */
                        if (cpu == prev_cpu) {
-                               prev_delta = compute_energy(p, prev_cpu, pd);
-                               prev_delta -= base_energy_pd;
-                               best_delta = min(best_delta, prev_delta);
-                       }
-
-                       /*
-                        * Find the CPU with the maximum spare capacity in
-                        * the performance domain
-                        */
-                       if (spare_cap > max_spare_cap) {
+                               /* Always use prev_cpu as a candidate. */
+                               compute_prev_delta = true;
+                       } else if (spare_cap > max_spare_cap) {
+                               /*
+                                * Find the CPU with the maximum spare capacity
+                                * in the performance domain.
+                                */
                                max_spare_cap = spare_cap;
                                max_spare_cap_cpu = cpu;
                        }
                }
 
-               /* Evaluate the energy impact of using this CPU. */
-               if (max_spare_cap_cpu >= 0 && max_spare_cap_cpu != prev_cpu) {
+               if (max_spare_cap_cpu < 0 && !compute_prev_delta)
+                       continue;
+
+               /* Compute the 'base' energy of the pd, without @p */
+               base_energy_pd = compute_energy(p, -1, pd);
+               base_energy += base_energy_pd;
+
+               /* Evaluate the energy impact of using prev_cpu. */
+               if (compute_prev_delta) {
+                       prev_delta = compute_energy(p, prev_cpu, pd);
+                       if (prev_delta < base_energy_pd)
+                               goto unlock;
+                       prev_delta -= base_energy_pd;
+                       best_delta = min(best_delta, prev_delta);
+               }
+
+               /* Evaluate the energy impact of using max_spare_cap_cpu. */
+               if (max_spare_cap_cpu >= 0) {
                        cur_delta = compute_energy(p, max_spare_cap_cpu, pd);
+                       if (cur_delta < base_energy_pd)
+                               goto unlock;
                        cur_delta -= base_energy_pd;
                        if (cur_delta < best_delta) {
                                best_delta = cur_delta;
@@ -6747,25 +6818,22 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                        }
                }
        }
-unlock:
        rcu_read_unlock();
 
        /*
         * Pick the best CPU if prev_cpu cannot be used, or if it saves at
         * least 6% of the energy used by prev_cpu.
         */
-       if (prev_delta == ULONG_MAX)
-               return best_energy_cpu;
-
-       if ((prev_delta - best_delta) > ((prev_delta + base_energy) >> 4))
-               return best_energy_cpu;
+       if ((prev_delta == ULONG_MAX) ||
+           (prev_delta - best_delta) > ((prev_delta + base_energy) >> 4))
+               target = best_energy_cpu;
 
-       return prev_cpu;
+       return target;
 
-fail:
+unlock:
        rcu_read_unlock();
 
-       return -1;
+       return target;
 }
 
 /*
@@ -6777,8 +6845,6 @@ fail:
  * certain conditions an idle sibling CPU if the domain has SD_WAKE_AFFINE set.
  *
  * Returns the target CPU number.
- *
- * preempt must be disabled.
  */
 static int
 select_task_rq_fair(struct task_struct *p, int prev_cpu, int wake_flags)
@@ -6791,6 +6857,10 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int wake_flags)
        /* SD_flags and WF_flags share the first nibble */
        int sd_flag = wake_flags & 0xF;
 
+       /*
+        * required for stable ->cpus_allowed
+        */
+       lockdep_assert_held(&p->pi_lock);
        if (wake_flags & WF_TTWU) {
                record_wakee(p);
 
@@ -6855,7 +6925,7 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
         * min_vruntime -- the latter is done by enqueue_entity() when placing
         * the task on the new runqueue.
         */
-       if (p->state == TASK_WAKING) {
+       if (READ_ONCE(p->__state) == TASK_WAKING) {
                struct sched_entity *se = &p->se;
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
                u64 min_vruntime;
@@ -6880,7 +6950,7 @@ static void migrate_task_rq_fair(struct task_struct *p, int new_cpu)
                 * In case of TASK_ON_RQ_MIGRATING we in fact hold the 'old'
                 * rq->lock and can modify state directly.
                 */
-               lockdep_assert_held(&task_rq(p)->lock);
+               lockdep_assert_rq_held(task_rq(p));
                detach_entity_cfs_rq(&p->se);
 
        } else {
@@ -7084,6 +7154,39 @@ preempt:
                set_last_buddy(se);
 }
 
+#ifdef CONFIG_SMP
+static struct task_struct *pick_task_fair(struct rq *rq)
+{
+       struct sched_entity *se;
+       struct cfs_rq *cfs_rq;
+
+again:
+       cfs_rq = &rq->cfs;
+       if (!cfs_rq->nr_running)
+               return NULL;
+
+       do {
+               struct sched_entity *curr = cfs_rq->curr;
+
+               /* When we pick for a remote RQ, we'll not have done put_prev_entity() */
+               if (curr) {
+                       if (curr->on_rq)
+                               update_curr(cfs_rq);
+                       else
+                               curr = NULL;
+
+                       if (unlikely(check_cfs_rq_runtime(cfs_rq)))
+                               goto again;
+               }
+
+               se = pick_next_entity(cfs_rq, curr);
+               cfs_rq = group_cfs_rq(se);
+       } while (cfs_rq);
+
+       return task_of(se);
+}
+#endif
+
 struct task_struct *
 pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 {
@@ -7507,7 +7610,7 @@ static int task_hot(struct task_struct *p, struct lb_env *env)
 {
        s64 delta;
 
-       lockdep_assert_held(&env->src_rq->lock);
+       lockdep_assert_rq_held(env->src_rq);
 
        if (p->sched_class != &fair_sched_class)
                return 0;
@@ -7529,6 +7632,14 @@ static int task_hot(struct task_struct *p, struct lb_env *env)
 
        if (sysctl_sched_migration_cost == -1)
                return 1;
+
+       /*
+        * Don't migrate task if the task's cookie does not match
+        * with the destination CPU's core cookie.
+        */
+       if (!sched_core_cookie_match(cpu_rq(env->dst_cpu), p))
+               return 1;
+
        if (sysctl_sched_migration_cost == 0)
                return 0;
 
@@ -7605,7 +7716,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
 {
        int tsk_cache_hot;
 
-       lockdep_assert_held(&env->src_rq->lock);
+       lockdep_assert_rq_held(env->src_rq);
 
        /*
         * We do not migrate tasks that are:
@@ -7694,7 +7805,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
  */
 static void detach_task(struct task_struct *p, struct lb_env *env)
 {
-       lockdep_assert_held(&env->src_rq->lock);
+       lockdep_assert_rq_held(env->src_rq);
 
        deactivate_task(env->src_rq, p, DEQUEUE_NOCLOCK);
        set_task_cpu(p, env->dst_cpu);
@@ -7710,7 +7821,7 @@ static struct task_struct *detach_one_task(struct lb_env *env)
 {
        struct task_struct *p;
 
-       lockdep_assert_held(&env->src_rq->lock);
+       lockdep_assert_rq_held(env->src_rq);
 
        list_for_each_entry_reverse(p,
                        &env->src_rq->cfs_tasks, se.group_node) {
@@ -7746,7 +7857,7 @@ static int detach_tasks(struct lb_env *env)
        struct task_struct *p;
        int detached = 0;
 
-       lockdep_assert_held(&env->src_rq->lock);
+       lockdep_assert_rq_held(env->src_rq);
 
        /*
         * Source run queue has been emptied by another CPU, clear
@@ -7876,7 +7987,7 @@ next:
  */
 static void attach_task(struct rq *rq, struct task_struct *p)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        BUG_ON(task_rq(p) != rq);
        activate_task(rq, p, ENQUEUE_NOCLOCK);
@@ -7996,23 +8107,6 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
-static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
-{
-       if (cfs_rq->load.weight)
-               return false;
-
-       if (cfs_rq->avg.load_sum)
-               return false;
-
-       if (cfs_rq->avg.util_sum)
-               return false;
-
-       if (cfs_rq->avg.runnable_sum)
-               return false;
-
-       return true;
-}
-
 static bool __update_blocked_fair(struct rq *rq, bool *done)
 {
        struct cfs_rq *cfs_rq, *pos;
@@ -8859,6 +8953,10 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
                                        p->cpus_ptr))
                        continue;
 
+               /* Skip over this group if no cookie matched */
+               if (!sched_group_cookie_match(cpu_rq(this_cpu), p, group))
+                       continue;
+
                local_group = cpumask_test_cpu(this_cpu,
                                               sched_group_span(group));
 
@@ -9787,7 +9885,7 @@ more_balance:
                if (need_active_balance(&env)) {
                        unsigned long flags;
 
-                       raw_spin_lock_irqsave(&busiest->lock, flags);
+                       raw_spin_rq_lock_irqsave(busiest, flags);
 
                        /*
                         * Don't kick the active_load_balance_cpu_stop,
@@ -9795,8 +9893,7 @@ more_balance:
                         * moved to this_cpu:
                         */
                        if (!cpumask_test_cpu(this_cpu, busiest->curr->cpus_ptr)) {
-                               raw_spin_unlock_irqrestore(&busiest->lock,
-                                                           flags);
+                               raw_spin_rq_unlock_irqrestore(busiest, flags);
                                goto out_one_pinned;
                        }
 
@@ -9813,7 +9910,7 @@ more_balance:
                                busiest->push_cpu = this_cpu;
                                active_balance = 1;
                        }
-                       raw_spin_unlock_irqrestore(&busiest->lock, flags);
+                       raw_spin_rq_unlock_irqrestore(busiest, flags);
 
                        if (active_balance) {
                                stop_one_cpu_nowait(cpu_of(busiest),
@@ -10598,6 +10695,14 @@ static int newidle_balance(struct rq *this_rq, struct rq_flags *rf)
        u64 curr_cost = 0;
 
        update_misfit_status(NULL, this_rq);
+
+       /*
+        * There is a task waiting to run. No need to search for one.
+        * Return 0; the task will be enqueued when switching to idle.
+        */
+       if (this_rq->ttwu_pending)
+               return 0;
+
        /*
         * We must set idle_stamp _before_ calling idle_balance(), such that we
         * measure the duration of idle_balance() as idle time.
@@ -10630,7 +10735,7 @@ static int newidle_balance(struct rq *this_rq, struct rq_flags *rf)
                goto out;
        }
 
-       raw_spin_unlock(&this_rq->lock);
+       raw_spin_rq_unlock(this_rq);
 
        update_blocked_averages(this_cpu);
        rcu_read_lock();
@@ -10663,12 +10768,13 @@ static int newidle_balance(struct rq *this_rq, struct rq_flags *rf)
                 * Stop searching for tasks to pull if there are
                 * now runnable tasks on this rq.
                 */
-               if (pulled_task || this_rq->nr_running > 0)
+               if (pulled_task || this_rq->nr_running > 0 ||
+                   this_rq->ttwu_pending)
                        break;
        }
        rcu_read_unlock();
 
-       raw_spin_lock(&this_rq->lock);
+       raw_spin_rq_lock(this_rq);
 
        if (curr_cost > this_rq->max_idle_balance_cost)
                this_rq->max_idle_balance_cost = curr_cost;
@@ -10761,6 +10867,119 @@ static void rq_offline_fair(struct rq *rq)
 
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_SCHED_CORE
+static inline bool
+__entity_slice_used(struct sched_entity *se, int min_nr_tasks)
+{
+       u64 slice = sched_slice(cfs_rq_of(se), se);
+       u64 rtime = se->sum_exec_runtime - se->prev_sum_exec_runtime;
+
+       return (rtime * min_nr_tasks > slice);
+}
+
+#define MIN_NR_TASKS_DURING_FORCEIDLE  2
+static inline void task_tick_core(struct rq *rq, struct task_struct *curr)
+{
+       if (!sched_core_enabled(rq))
+               return;
+
+       /*
+        * If runqueue has only one task which used up its slice and
+        * if the sibling is forced idle, then trigger schedule to
+        * give forced idle task a chance.
+        *
+        * sched_slice() considers only this active rq and it gets the
+        * whole slice. But during force idle, we have siblings acting
+        * like a single runqueue and hence we need to consider runnable
+        * tasks on this CPU and the forced idle CPU. Ideally, we should
+        * go through the forced idle rq, but that would be a perf hit.
+        * We can assume that the forced idle CPU has at least
+        * MIN_NR_TASKS_DURING_FORCEIDLE - 1 tasks and use that to check
+        * if we need to give up the CPU.
+        */
+       if (rq->core->core_forceidle && rq->cfs.nr_running == 1 &&
+           __entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE))
+               resched_curr(rq);
+}
+
+/*
+ * se_fi_update - Update the cfs_rq->min_vruntime_fi in a CFS hierarchy if needed.
+ */
+static void se_fi_update(struct sched_entity *se, unsigned int fi_seq, bool forceidle)
+{
+       for_each_sched_entity(se) {
+               struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+               if (forceidle) {
+                       if (cfs_rq->forceidle_seq == fi_seq)
+                               break;
+                       cfs_rq->forceidle_seq = fi_seq;
+               }
+
+               cfs_rq->min_vruntime_fi = cfs_rq->min_vruntime;
+       }
+}
+
+void task_vruntime_update(struct rq *rq, struct task_struct *p, bool in_fi)
+{
+       struct sched_entity *se = &p->se;
+
+       if (p->sched_class != &fair_sched_class)
+               return;
+
+       se_fi_update(se, rq->core->core_forceidle_seq, in_fi);
+}
+
+bool cfs_prio_less(struct task_struct *a, struct task_struct *b, bool in_fi)
+{
+       struct rq *rq = task_rq(a);
+       struct sched_entity *sea = &a->se;
+       struct sched_entity *seb = &b->se;
+       struct cfs_rq *cfs_rqa;
+       struct cfs_rq *cfs_rqb;
+       s64 delta;
+
+       SCHED_WARN_ON(task_rq(b)->core != rq->core);
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       /*
+        * Find an se in the hierarchy for tasks a and b, such that the se's
+        * are immediate siblings.
+        */
+       while (sea->cfs_rq->tg != seb->cfs_rq->tg) {
+               int sea_depth = sea->depth;
+               int seb_depth = seb->depth;
+
+               if (sea_depth >= seb_depth)
+                       sea = parent_entity(sea);
+               if (sea_depth <= seb_depth)
+                       seb = parent_entity(seb);
+       }
+
+       se_fi_update(sea, rq->core->core_forceidle_seq, in_fi);
+       se_fi_update(seb, rq->core->core_forceidle_seq, in_fi);
+
+       cfs_rqa = sea->cfs_rq;
+       cfs_rqb = seb->cfs_rq;
+#else
+       cfs_rqa = &task_rq(a)->cfs;
+       cfs_rqb = &task_rq(b)->cfs;
+#endif
+
+       /*
+        * Find delta after normalizing se's vruntime with its cfs_rq's
+        * min_vruntime_fi, which would have been updated in prior calls
+        * to se_fi_update().
+        */
+       delta = (s64)(sea->vruntime - seb->vruntime) +
+               (s64)(cfs_rqb->min_vruntime_fi - cfs_rqa->min_vruntime_fi);
+
+       return delta > 0;
+}
+#else
+static inline void task_tick_core(struct rq *rq, struct task_struct *curr) {}
+#endif
+
 /*
  * scheduler tick hitting a task of our scheduling class.
  *
@@ -10784,6 +11003,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
 
        update_misfit_status(curr, rq);
        update_overutilized_status(task_rq(curr));
+
+       task_tick_core(rq, curr);
 }
 
 /*
@@ -10869,7 +11090,7 @@ static inline bool vruntime_normalized(struct task_struct *p)
         *   waiting for actually being woken up by sched_ttwu_pending().
         */
        if (!se->sum_exec_runtime ||
-           (p->state == TASK_WAKING && p->sched_remote_wakeup))
+           (READ_ONCE(p->__state) == TASK_WAKING && p->sched_remote_wakeup))
                return true;
 
        return false;
@@ -11155,9 +11376,9 @@ void unregister_fair_sched_group(struct task_group *tg)
 
                rq = cpu_rq(cpu);
 
-               raw_spin_lock_irqsave(&rq->lock, flags);
+               raw_spin_rq_lock_irqsave(rq, flags);
                list_del_leaf_cfs_rq(tg->cfs_rq[cpu]);
-               raw_spin_unlock_irqrestore(&rq->lock, flags);
+               raw_spin_rq_unlock_irqrestore(rq, flags);
        }
 }
 
@@ -11279,6 +11500,7 @@ DEFINE_SCHED_CLASS(fair) = {
 
 #ifdef CONFIG_SMP
        .balance                = balance_fair,
+       .pick_task              = pick_task_fair,
        .select_task_rq         = select_task_rq_fair,
        .migrate_task_rq        = migrate_task_rq_fair,
 
index 7ca3d3d..912b47a 100644 (file)
@@ -437,8 +437,16 @@ static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool fir
 {
        update_idle_core(rq);
        schedstat_inc(rq->sched_goidle);
+       queue_core_balance(rq);
 }
 
+#ifdef CONFIG_SMP
+static struct task_struct *pick_task_idle(struct rq *rq)
+{
+       return rq->idle;
+}
+#endif
+
 struct task_struct *pick_next_task_idle(struct rq *rq)
 {
        struct task_struct *next = rq->idle;
@@ -455,10 +463,10 @@ struct task_struct *pick_next_task_idle(struct rq *rq)
 static void
 dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 {
-       raw_spin_unlock_irq(&rq->lock);
+       raw_spin_rq_unlock_irq(rq);
        printk(KERN_ERR "bad: scheduling from the idle thread!\n");
        dump_stack();
-       raw_spin_lock_irq(&rq->lock);
+       raw_spin_rq_lock_irq(rq);
 }
 
 /*
@@ -506,6 +514,7 @@ DEFINE_SCHED_CLASS(idle) = {
 
 #ifdef CONFIG_SMP
        .balance                = balance_idle,
+       .pick_task              = pick_task_idle,
        .select_task_rq         = select_task_rq_idle,
        .set_cpus_allowed       = set_cpus_allowed_common,
 #endif
index 5a6ea03..7f06eaf 100644 (file)
@@ -81,11 +81,9 @@ static int __init housekeeping_setup(char *str, enum hk_flags flags)
 {
        cpumask_var_t non_housekeeping_mask;
        cpumask_var_t tmp;
-       int err;
 
        alloc_bootmem_cpumask_var(&non_housekeeping_mask);
-       err = cpulist_parse(str, non_housekeeping_mask);
-       if (err < 0 || cpumask_last(non_housekeeping_mask) >= nr_cpu_ids) {
+       if (cpulist_parse(str, non_housekeeping_mask) < 0) {
                pr_warn("Housekeeping: nohz_full= or isolcpus= incorrect CPU range\n");
                free_bootmem_cpumask_var(non_housekeeping_mask);
                return 0;
index 1c79896..954b229 100644 (file)
@@ -81,7 +81,7 @@ long calc_load_fold_active(struct rq *this_rq, long adjust)
        long nr_active, delta = 0;
 
        nr_active = this_rq->nr_running - adjust;
-       nr_active += (long)this_rq->nr_uninterruptible;
+       nr_active += (int)this_rq->nr_uninterruptible;
 
        if (nr_active != this_rq->calc_load_active) {
                delta = nr_active - this_rq->calc_load_active;
index cfe94ff..e06071b 100644 (file)
@@ -132,7 +132,7 @@ static inline void update_idle_rq_clock_pelt(struct rq *rq)
 
 static inline u64 rq_clock_pelt(struct rq *rq)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        assert_clock_updated(rq);
 
        return rq->clock_pelt - rq->lost_idle_time;
index cc25a3c..58b36d1 100644 (file)
@@ -182,6 +182,8 @@ struct psi_group psi_system = {
 
 static void psi_avgs_work(struct work_struct *work);
 
+static void poll_timer_fn(struct timer_list *t);
+
 static void group_init(struct psi_group *group)
 {
        int cpu;
@@ -201,6 +203,8 @@ static void group_init(struct psi_group *group)
        memset(group->polling_total, 0, sizeof(group->polling_total));
        group->polling_next_update = ULLONG_MAX;
        group->polling_until = 0;
+       init_waitqueue_head(&group->poll_wait);
+       timer_setup(&group->poll_timer, poll_timer_fn, 0);
        rcu_assign_pointer(group->poll_task, NULL);
 }
 
@@ -1157,9 +1161,7 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
                        return ERR_CAST(task);
                }
                atomic_set(&group->poll_wakeup, 0);
-               init_waitqueue_head(&group->poll_wait);
                wake_up_process(task);
-               timer_setup(&group->poll_timer, poll_timer_fn, 0);
                rcu_assign_pointer(group->poll_task, task);
        }
 
@@ -1211,6 +1213,7 @@ static void psi_trigger_destroy(struct kref *ref)
                                        group->poll_task,
                                        lockdep_is_held(&group->trigger_lock));
                        rcu_assign_pointer(group->poll_task, NULL);
+                       del_timer(&group->poll_timer);
                }
        }
 
@@ -1223,17 +1226,14 @@ static void psi_trigger_destroy(struct kref *ref)
         */
        synchronize_rcu();
        /*
-        * Destroy the kworker after releasing trigger_lock to prevent a
+        * Stop kthread 'psimon' after releasing trigger_lock to prevent a
         * deadlock while waiting for psi_poll_work to acquire trigger_lock
         */
        if (task_to_destroy) {
                /*
                 * After the RCU grace period has expired, the worker
                 * can no longer be found through group->poll_task.
-                * But it might have been already scheduled before
-                * that - deschedule it cleanly before destroying it.
                 */
-               del_timer_sync(&group->poll_timer);
                kthread_stop(task_to_destroy);
        }
        kfree(t);
index c286e5b..3daf42a 100644 (file)
@@ -888,7 +888,7 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
                if (skip)
                        continue;
 
-               raw_spin_lock(&rq->lock);
+               raw_spin_rq_lock(rq);
                update_rq_clock(rq);
 
                if (rt_rq->rt_time) {
@@ -926,7 +926,7 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
 
                if (enqueue)
                        sched_rt_rq_enqueue(rt_rq);
-               raw_spin_unlock(&rq->lock);
+               raw_spin_rq_unlock(rq);
        }
 
        if (!throttled && (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF))
@@ -1626,7 +1626,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
        return rt_task_of(rt_se);
 }
 
-static struct task_struct *pick_next_task_rt(struct rq *rq)
+static struct task_struct *pick_task_rt(struct rq *rq)
 {
        struct task_struct *p;
 
@@ -1634,7 +1634,17 @@ static struct task_struct *pick_next_task_rt(struct rq *rq)
                return NULL;
 
        p = _pick_next_task_rt(rq);
-       set_next_task_rt(rq, p, true);
+
+       return p;
+}
+
+static struct task_struct *pick_next_task_rt(struct rq *rq)
+{
+       struct task_struct *p = pick_task_rt(rq);
+
+       if (p)
+               set_next_task_rt(rq, p, true);
+
        return p;
 }
 
@@ -1894,10 +1904,10 @@ retry:
                 */
                push_task = get_push_task(rq);
                if (push_task) {
-                       raw_spin_unlock(&rq->lock);
+                       raw_spin_rq_unlock(rq);
                        stop_one_cpu_nowait(rq->cpu, push_cpu_stop,
                                            push_task, &rq->push_work);
-                       raw_spin_lock(&rq->lock);
+                       raw_spin_rq_lock(rq);
                }
 
                return 0;
@@ -2122,10 +2132,10 @@ void rto_push_irq_work_func(struct irq_work *work)
         * When it gets updated, a check is made if a push is possible.
         */
        if (has_pushable_tasks(rq)) {
-               raw_spin_lock(&rq->lock);
+               raw_spin_rq_lock(rq);
                while (push_rt_task(rq, true))
                        ;
-               raw_spin_unlock(&rq->lock);
+               raw_spin_rq_unlock(rq);
        }
 
        raw_spin_lock(&rd->rto_lock);
@@ -2243,10 +2253,10 @@ skip:
                double_unlock_balance(this_rq, src_rq);
 
                if (push_task) {
-                       raw_spin_unlock(&this_rq->lock);
+                       raw_spin_rq_unlock(this_rq);
                        stop_one_cpu_nowait(src_rq->cpu, push_cpu_stop,
                                            push_task, &src_rq->push_work);
-                       raw_spin_lock(&this_rq->lock);
+                       raw_spin_rq_lock(this_rq);
                }
        }
 
@@ -2331,13 +2341,20 @@ void __init init_sched_rt_class(void)
 static void switched_to_rt(struct rq *rq, struct task_struct *p)
 {
        /*
-        * If we are already running, then there's nothing
-        * that needs to be done. But if we are not running
-        * we may need to preempt the current running task.
-        * If that current running task is also an RT task
+        * If we are running, update the avg_rt tracking, as the running time
+        * will now on be accounted into the latter.
+        */
+       if (task_current(rq, p)) {
+               update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 0);
+               return;
+       }
+
+       /*
+        * If we are not running we may need to preempt the current
+        * running task. If that current running task is also an RT task
         * then see if we can move to another run queue.
         */
-       if (task_on_rq_queued(p) && rq->curr != p) {
+       if (task_on_rq_queued(p)) {
 #ifdef CONFIG_SMP
                if (p->nr_cpus_allowed > 1 && rq->rt.overloaded)
                        rt_queue_push_tasks(rq);
@@ -2483,6 +2500,7 @@ DEFINE_SCHED_CLASS(rt) = {
 
 #ifdef CONFIG_SMP
        .balance                = balance_rt,
+       .pick_task              = pick_task_rt,
        .select_task_rq         = select_task_rq_rt,
        .set_cpus_allowed       = set_cpus_allowed_common,
        .rq_online              = rq_online_rt,
index a189bec..c80d42e 100644 (file)
@@ -366,6 +366,7 @@ struct cfs_bandwidth {
        ktime_t                 period;
        u64                     quota;
        u64                     runtime;
+       u64                     burst;
        s64                     hierarchical_quota;
 
        u8                      idle;
@@ -526,6 +527,11 @@ struct cfs_rq {
 
        u64                     exec_clock;
        u64                     min_vruntime;
+#ifdef CONFIG_SCHED_CORE
+       unsigned int            forceidle_seq;
+       u64                     min_vruntime_fi;
+#endif
+
 #ifndef CONFIG_64BIT
        u64                     min_vruntime_copy;
 #endif
@@ -631,8 +637,8 @@ struct rt_rq {
        } highest_prio;
 #endif
 #ifdef CONFIG_SMP
-       unsigned long           rt_nr_migratory;
-       unsigned long           rt_nr_total;
+       unsigned int            rt_nr_migratory;
+       unsigned int            rt_nr_total;
        int                     overloaded;
        struct plist_head       pushable_tasks;
 
@@ -646,7 +652,7 @@ struct rt_rq {
        raw_spinlock_t          rt_runtime_lock;
 
 #ifdef CONFIG_RT_GROUP_SCHED
-       unsigned long           rt_nr_boosted;
+       unsigned int            rt_nr_boosted;
 
        struct rq               *rq;
        struct task_group       *tg;
@@ -663,7 +669,7 @@ struct dl_rq {
        /* runqueue is an rbtree, ordered by deadline */
        struct rb_root_cached   root;
 
-       unsigned long           dl_nr_running;
+       unsigned int            dl_nr_running;
 
 #ifdef CONFIG_SMP
        /*
@@ -677,7 +683,7 @@ struct dl_rq {
                u64             next;
        } earliest_dl;
 
-       unsigned long           dl_nr_migratory;
+       unsigned int            dl_nr_migratory;
        int                     overloaded;
 
        /*
@@ -905,7 +911,7 @@ DECLARE_STATIC_KEY_FALSE(sched_uclamp_used);
  */
 struct rq {
        /* runqueue lock: */
-       raw_spinlock_t          lock;
+       raw_spinlock_t          __lock;
 
        /*
         * nr_running and cpu_load should be in the same cacheline because
@@ -955,7 +961,7 @@ struct rq {
         * one CPU and if it got migrated afterwards it may decrease
         * it on another CPU. Always updated under the runqueue lock:
         */
-       unsigned long           nr_uninterruptible;
+       unsigned int            nr_uninterruptible;
 
        struct task_struct __rcu        *curr;
        struct task_struct      *idle;
@@ -1017,6 +1023,9 @@ struct rq {
        u64                     idle_stamp;
        u64                     avg_idle;
 
+       unsigned long           wake_stamp;
+       u64                     wake_avg_idle;
+
        /* This is used to determine avg_idle's max value */
        u64                     max_idle_balance_cost;
 
@@ -1075,6 +1084,22 @@ struct rq {
 #endif
        unsigned int            push_busy;
        struct cpu_stop_work    push_work;
+
+#ifdef CONFIG_SCHED_CORE
+       /* per rq */
+       struct rq               *core;
+       struct task_struct      *core_pick;
+       unsigned int            core_enabled;
+       unsigned int            core_sched_seq;
+       struct rb_root          core_tree;
+
+       /* shared state */
+       unsigned int            core_task_seq;
+       unsigned int            core_pick_seq;
+       unsigned long           core_cookie;
+       unsigned char           core_forceidle;
+       unsigned int            core_forceidle_seq;
+#endif
 };
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -1113,6 +1138,206 @@ static inline bool is_migration_disabled(struct task_struct *p)
 #endif
 }
 
+struct sched_group;
+#ifdef CONFIG_SCHED_CORE
+static inline struct cpumask *sched_group_span(struct sched_group *sg);
+
+DECLARE_STATIC_KEY_FALSE(__sched_core_enabled);
+
+static inline bool sched_core_enabled(struct rq *rq)
+{
+       return static_branch_unlikely(&__sched_core_enabled) && rq->core_enabled;
+}
+
+static inline bool sched_core_disabled(void)
+{
+       return !static_branch_unlikely(&__sched_core_enabled);
+}
+
+/*
+ * Be careful with this function; not for general use. The return value isn't
+ * stable unless you actually hold a relevant rq->__lock.
+ */
+static inline raw_spinlock_t *rq_lockp(struct rq *rq)
+{
+       if (sched_core_enabled(rq))
+               return &rq->core->__lock;
+
+       return &rq->__lock;
+}
+
+static inline raw_spinlock_t *__rq_lockp(struct rq *rq)
+{
+       if (rq->core_enabled)
+               return &rq->core->__lock;
+
+       return &rq->__lock;
+}
+
+bool cfs_prio_less(struct task_struct *a, struct task_struct *b, bool fi);
+
+/*
+ * Helpers to check if the CPU's core cookie matches with the task's cookie
+ * when core scheduling is enabled.
+ * A special case is that the task's cookie always matches with CPU's core
+ * cookie if the CPU is in an idle core.
+ */
+static inline bool sched_cpu_cookie_match(struct rq *rq, struct task_struct *p)
+{
+       /* Ignore cookie match if core scheduler is not enabled on the CPU. */
+       if (!sched_core_enabled(rq))
+               return true;
+
+       return rq->core->core_cookie == p->core_cookie;
+}
+
+static inline bool sched_core_cookie_match(struct rq *rq, struct task_struct *p)
+{
+       bool idle_core = true;
+       int cpu;
+
+       /* Ignore cookie match if core scheduler is not enabled on the CPU. */
+       if (!sched_core_enabled(rq))
+               return true;
+
+       for_each_cpu(cpu, cpu_smt_mask(cpu_of(rq))) {
+               if (!available_idle_cpu(cpu)) {
+                       idle_core = false;
+                       break;
+               }
+       }
+
+       /*
+        * A CPU in an idle core is always the best choice for tasks with
+        * cookies.
+        */
+       return idle_core || rq->core->core_cookie == p->core_cookie;
+}
+
+static inline bool sched_group_cookie_match(struct rq *rq,
+                                           struct task_struct *p,
+                                           struct sched_group *group)
+{
+       int cpu;
+
+       /* Ignore cookie match if core scheduler is not enabled on the CPU. */
+       if (!sched_core_enabled(rq))
+               return true;
+
+       for_each_cpu_and(cpu, sched_group_span(group), p->cpus_ptr) {
+               if (sched_core_cookie_match(rq, p))
+                       return true;
+       }
+       return false;
+}
+
+extern void queue_core_balance(struct rq *rq);
+
+static inline bool sched_core_enqueued(struct task_struct *p)
+{
+       return !RB_EMPTY_NODE(&p->core_node);
+}
+
+extern void sched_core_enqueue(struct rq *rq, struct task_struct *p);
+extern void sched_core_dequeue(struct rq *rq, struct task_struct *p);
+
+extern void sched_core_get(void);
+extern void sched_core_put(void);
+
+extern unsigned long sched_core_alloc_cookie(void);
+extern void sched_core_put_cookie(unsigned long cookie);
+extern unsigned long sched_core_get_cookie(unsigned long cookie);
+extern unsigned long sched_core_update_cookie(struct task_struct *p, unsigned long cookie);
+
+#else /* !CONFIG_SCHED_CORE */
+
+static inline bool sched_core_enabled(struct rq *rq)
+{
+       return false;
+}
+
+static inline bool sched_core_disabled(void)
+{
+       return true;
+}
+
+static inline raw_spinlock_t *rq_lockp(struct rq *rq)
+{
+       return &rq->__lock;
+}
+
+static inline raw_spinlock_t *__rq_lockp(struct rq *rq)
+{
+       return &rq->__lock;
+}
+
+static inline void queue_core_balance(struct rq *rq)
+{
+}
+
+static inline bool sched_cpu_cookie_match(struct rq *rq, struct task_struct *p)
+{
+       return true;
+}
+
+static inline bool sched_core_cookie_match(struct rq *rq, struct task_struct *p)
+{
+       return true;
+}
+
+static inline bool sched_group_cookie_match(struct rq *rq,
+                                           struct task_struct *p,
+                                           struct sched_group *group)
+{
+       return true;
+}
+#endif /* CONFIG_SCHED_CORE */
+
+static inline void lockdep_assert_rq_held(struct rq *rq)
+{
+       lockdep_assert_held(__rq_lockp(rq));
+}
+
+extern void raw_spin_rq_lock_nested(struct rq *rq, int subclass);
+extern bool raw_spin_rq_trylock(struct rq *rq);
+extern void raw_spin_rq_unlock(struct rq *rq);
+
+static inline void raw_spin_rq_lock(struct rq *rq)
+{
+       raw_spin_rq_lock_nested(rq, 0);
+}
+
+static inline void raw_spin_rq_lock_irq(struct rq *rq)
+{
+       local_irq_disable();
+       raw_spin_rq_lock(rq);
+}
+
+static inline void raw_spin_rq_unlock_irq(struct rq *rq)
+{
+       raw_spin_rq_unlock(rq);
+       local_irq_enable();
+}
+
+static inline unsigned long _raw_spin_rq_lock_irqsave(struct rq *rq)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       raw_spin_rq_lock(rq);
+       return flags;
+}
+
+static inline void raw_spin_rq_unlock_irqrestore(struct rq *rq, unsigned long flags)
+{
+       raw_spin_rq_unlock(rq);
+       local_irq_restore(flags);
+}
+
+#define raw_spin_rq_lock_irqsave(rq, flags)    \
+do {                                           \
+       flags = _raw_spin_rq_lock_irqsave(rq);  \
+} while (0)
+
 #ifdef CONFIG_SCHED_SMT
 extern void __update_idle_core(struct rq *rq);
 
@@ -1134,6 +1359,57 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 #define raw_rq()               raw_cpu_ptr(&runqueues)
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+static inline struct task_struct *task_of(struct sched_entity *se)
+{
+       SCHED_WARN_ON(!entity_is_task(se));
+       return container_of(se, struct task_struct, se);
+}
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+       return p->se.cfs_rq;
+}
+
+/* runqueue on which this entity is (to be) queued */
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+       return se->cfs_rq;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+       return grp->my_q;
+}
+
+#else
+
+static inline struct task_struct *task_of(struct sched_entity *se)
+{
+       return container_of(se, struct task_struct, se);
+}
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+       return &task_rq(p)->cfs;
+}
+
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+       struct task_struct *p = task_of(se);
+       struct rq *rq = task_rq(p);
+
+       return &rq->cfs;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+       return NULL;
+}
+#endif
+
 extern void update_rq_clock(struct rq *rq);
 
 static inline u64 __rq_clock_broken(struct rq *rq)
@@ -1179,7 +1455,7 @@ static inline void assert_clock_updated(struct rq *rq)
 
 static inline u64 rq_clock(struct rq *rq)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        assert_clock_updated(rq);
 
        return rq->clock;
@@ -1187,7 +1463,7 @@ static inline u64 rq_clock(struct rq *rq)
 
 static inline u64 rq_clock_task(struct rq *rq)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        assert_clock_updated(rq);
 
        return rq->clock_task;
@@ -1213,7 +1489,7 @@ static inline u64 rq_clock_thermal(struct rq *rq)
 
 static inline void rq_clock_skip_update(struct rq *rq)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        rq->clock_update_flags |= RQCF_REQ_SKIP;
 }
 
@@ -1223,7 +1499,7 @@ static inline void rq_clock_skip_update(struct rq *rq)
  */
 static inline void rq_clock_cancel_skipupdate(struct rq *rq)
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
        rq->clock_update_flags &= ~RQCF_REQ_SKIP;
 }
 
@@ -1254,7 +1530,7 @@ extern struct callback_head balance_push_callback;
  */
 static inline void rq_pin_lock(struct rq *rq, struct rq_flags *rf)
 {
-       rf->cookie = lockdep_pin_lock(&rq->lock);
+       rf->cookie = lockdep_pin_lock(__rq_lockp(rq));
 
 #ifdef CONFIG_SCHED_DEBUG
        rq->clock_update_flags &= (RQCF_REQ_SKIP|RQCF_ACT_SKIP);
@@ -1272,12 +1548,12 @@ static inline void rq_unpin_lock(struct rq *rq, struct rq_flags *rf)
                rf->clock_update_flags = RQCF_UPDATED;
 #endif
 
-       lockdep_unpin_lock(&rq->lock, rf->cookie);
+       lockdep_unpin_lock(__rq_lockp(rq), rf->cookie);
 }
 
 static inline void rq_repin_lock(struct rq *rq, struct rq_flags *rf)
 {
-       lockdep_repin_lock(&rq->lock, rf->cookie);
+       lockdep_repin_lock(__rq_lockp(rq), rf->cookie);
 
 #ifdef CONFIG_SCHED_DEBUG
        /*
@@ -1298,7 +1574,7 @@ static inline void __task_rq_unlock(struct rq *rq, struct rq_flags *rf)
        __releases(rq->lock)
 {
        rq_unpin_lock(rq, rf);
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
 }
 
 static inline void
@@ -1307,7 +1583,7 @@ task_rq_unlock(struct rq *rq, struct task_struct *p, struct rq_flags *rf)
        __releases(p->pi_lock)
 {
        rq_unpin_lock(rq, rf);
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
        raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
 }
 
@@ -1315,7 +1591,7 @@ static inline void
 rq_lock_irqsave(struct rq *rq, struct rq_flags *rf)
        __acquires(rq->lock)
 {
-       raw_spin_lock_irqsave(&rq->lock, rf->flags);
+       raw_spin_rq_lock_irqsave(rq, rf->flags);
        rq_pin_lock(rq, rf);
 }
 
@@ -1323,7 +1599,7 @@ static inline void
 rq_lock_irq(struct rq *rq, struct rq_flags *rf)
        __acquires(rq->lock)
 {
-       raw_spin_lock_irq(&rq->lock);
+       raw_spin_rq_lock_irq(rq);
        rq_pin_lock(rq, rf);
 }
 
@@ -1331,7 +1607,7 @@ static inline void
 rq_lock(struct rq *rq, struct rq_flags *rf)
        __acquires(rq->lock)
 {
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
        rq_pin_lock(rq, rf);
 }
 
@@ -1339,7 +1615,7 @@ static inline void
 rq_relock(struct rq *rq, struct rq_flags *rf)
        __acquires(rq->lock)
 {
-       raw_spin_lock(&rq->lock);
+       raw_spin_rq_lock(rq);
        rq_repin_lock(rq, rf);
 }
 
@@ -1348,7 +1624,7 @@ rq_unlock_irqrestore(struct rq *rq, struct rq_flags *rf)
        __releases(rq->lock)
 {
        rq_unpin_lock(rq, rf);
-       raw_spin_unlock_irqrestore(&rq->lock, rf->flags);
+       raw_spin_rq_unlock_irqrestore(rq, rf->flags);
 }
 
 static inline void
@@ -1356,7 +1632,7 @@ rq_unlock_irq(struct rq *rq, struct rq_flags *rf)
        __releases(rq->lock)
 {
        rq_unpin_lock(rq, rf);
-       raw_spin_unlock_irq(&rq->lock);
+       raw_spin_rq_unlock_irq(rq);
 }
 
 static inline void
@@ -1364,7 +1640,7 @@ rq_unlock(struct rq *rq, struct rq_flags *rf)
        __releases(rq->lock)
 {
        rq_unpin_lock(rq, rf);
-       raw_spin_unlock(&rq->lock);
+       raw_spin_rq_unlock(rq);
 }
 
 static inline struct rq *
@@ -1429,7 +1705,7 @@ queue_balance_callback(struct rq *rq,
                       struct callback_head *head,
                       void (*func)(struct rq *rq))
 {
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        if (unlikely(head->next || rq->balance_callback == &balance_push_callback))
                return;
@@ -1844,6 +2120,9 @@ struct sched_class {
 #ifdef CONFIG_SMP
        int (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
        int  (*select_task_rq)(struct task_struct *p, int task_cpu, int flags);
+
+       struct task_struct * (*pick_task)(struct rq *rq);
+
        void (*migrate_task_rq)(struct task_struct *p, int new_cpu);
 
        void (*task_woken)(struct rq *this_rq, struct task_struct *task);
@@ -1893,7 +2172,6 @@ static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 
 static inline void set_next_task(struct rq *rq, struct task_struct *next)
 {
-       WARN_ON_ONCE(rq->curr != next);
        next->sched_class->set_next_task(rq, next, false);
 }
 
@@ -1969,7 +2247,7 @@ static inline struct task_struct *get_push_task(struct rq *rq)
 {
        struct task_struct *p = rq->curr;
 
-       lockdep_assert_held(&rq->lock);
+       lockdep_assert_rq_held(rq);
 
        if (rq->push_busy)
                return NULL;
@@ -2181,10 +2459,38 @@ unsigned long arch_scale_freq_capacity(int cpu)
 }
 #endif
 
+
 #ifdef CONFIG_SMP
-#ifdef CONFIG_PREEMPTION
 
-static inline void double_rq_lock(struct rq *rq1, struct rq *rq2);
+static inline bool rq_order_less(struct rq *rq1, struct rq *rq2)
+{
+#ifdef CONFIG_SCHED_CORE
+       /*
+        * In order to not have {0,2},{1,3} turn into into an AB-BA,
+        * order by core-id first and cpu-id second.
+        *
+        * Notably:
+        *
+        *      double_rq_lock(0,3); will take core-0, core-1 lock
+        *      double_rq_lock(1,2); will take core-1, core-0 lock
+        *
+        * when only cpu-id is considered.
+        */
+       if (rq1->core->cpu < rq2->core->cpu)
+               return true;
+       if (rq1->core->cpu > rq2->core->cpu)
+               return false;
+
+       /*
+        * __sched_core_flip() relies on SMT having cpu-id lock order.
+        */
+#endif
+       return rq1->cpu < rq2->cpu;
+}
+
+extern void double_rq_lock(struct rq *rq1, struct rq *rq2);
+
+#ifdef CONFIG_PREEMPTION
 
 /*
  * fair double_lock_balance: Safely acquires both rq->locks in a fair
@@ -2199,7 +2505,7 @@ static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
        __acquires(busiest->lock)
        __acquires(this_rq->lock)
 {
-       raw_spin_unlock(&this_rq->lock);
+       raw_spin_rq_unlock(this_rq);
        double_rq_lock(this_rq, busiest);
 
        return 1;
@@ -2218,20 +2524,21 @@ static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
        __acquires(busiest->lock)
        __acquires(this_rq->lock)
 {
-       int ret = 0;
-
-       if (unlikely(!raw_spin_trylock(&busiest->lock))) {
-               if (busiest < this_rq) {
-                       raw_spin_unlock(&this_rq->lock);
-                       raw_spin_lock(&busiest->lock);
-                       raw_spin_lock_nested(&this_rq->lock,
-                                             SINGLE_DEPTH_NESTING);
-                       ret = 1;
-               } else
-                       raw_spin_lock_nested(&busiest->lock,
-                                             SINGLE_DEPTH_NESTING);
+       if (__rq_lockp(this_rq) == __rq_lockp(busiest))
+               return 0;
+
+       if (likely(raw_spin_rq_trylock(busiest)))
+               return 0;
+
+       if (rq_order_less(this_rq, busiest)) {
+               raw_spin_rq_lock_nested(busiest, SINGLE_DEPTH_NESTING);
+               return 0;
        }
-       return ret;
+
+       raw_spin_rq_unlock(this_rq);
+       double_rq_lock(this_rq, busiest);
+
+       return 1;
 }
 
 #endif /* CONFIG_PREEMPTION */
@@ -2241,11 +2548,7 @@ static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
  */
 static inline int double_lock_balance(struct rq *this_rq, struct rq *busiest)
 {
-       if (unlikely(!irqs_disabled())) {
-               /* printk() doesn't work well under rq->lock */
-               raw_spin_unlock(&this_rq->lock);
-               BUG_ON(1);
-       }
+       lockdep_assert_irqs_disabled();
 
        return _double_lock_balance(this_rq, busiest);
 }
@@ -2253,8 +2556,9 @@ static inline int double_lock_balance(struct rq *this_rq, struct rq *busiest)
 static inline void double_unlock_balance(struct rq *this_rq, struct rq *busiest)
        __releases(busiest->lock)
 {
-       raw_spin_unlock(&busiest->lock);
-       lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_);
+       if (__rq_lockp(this_rq) != __rq_lockp(busiest))
+               raw_spin_rq_unlock(busiest);
+       lock_set_subclass(&__rq_lockp(this_rq)->dep_map, 0, _RET_IP_);
 }
 
 static inline void double_lock(spinlock_t *l1, spinlock_t *l2)
@@ -2285,31 +2589,6 @@ static inline void double_raw_lock(raw_spinlock_t *l1, raw_spinlock_t *l2)
 }
 
 /*
- * double_rq_lock - safely lock two runqueues
- *
- * Note this does not disable interrupts like task_rq_lock,
- * you need to do so manually before calling.
- */
-static inline void double_rq_lock(struct rq *rq1, struct rq *rq2)
-       __acquires(rq1->lock)
-       __acquires(rq2->lock)
-{
-       BUG_ON(!irqs_disabled());
-       if (rq1 == rq2) {
-               raw_spin_lock(&rq1->lock);
-               __acquire(rq2->lock);   /* Fake it out ;) */
-       } else {
-               if (rq1 < rq2) {
-                       raw_spin_lock(&rq1->lock);
-                       raw_spin_lock_nested(&rq2->lock, SINGLE_DEPTH_NESTING);
-               } else {
-                       raw_spin_lock(&rq2->lock);
-                       raw_spin_lock_nested(&rq1->lock, SINGLE_DEPTH_NESTING);
-               }
-       }
-}
-
-/*
  * double_rq_unlock - safely unlock two runqueues
  *
  * Note this does not restore interrupts like task_rq_unlock,
@@ -2319,11 +2598,11 @@ static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2)
        __releases(rq1->lock)
        __releases(rq2->lock)
 {
-       raw_spin_unlock(&rq1->lock);
-       if (rq1 != rq2)
-               raw_spin_unlock(&rq2->lock);
+       if (__rq_lockp(rq1) != __rq_lockp(rq2))
+               raw_spin_rq_unlock(rq2);
        else
                __release(rq2->lock);
+       raw_spin_rq_unlock(rq1);
 }
 
 extern void set_rq_online (struct rq *rq);
@@ -2344,7 +2623,7 @@ static inline void double_rq_lock(struct rq *rq1, struct rq *rq2)
 {
        BUG_ON(!irqs_disabled());
        BUG_ON(rq1 != rq2);
-       raw_spin_lock(&rq1->lock);
+       raw_spin_rq_lock(rq1);
        __acquire(rq2->lock);   /* Fake it out ;) */
 }
 
@@ -2359,7 +2638,7 @@ static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2)
        __releases(rq2->lock)
 {
        BUG_ON(rq1 != rq2);
-       raw_spin_unlock(&rq1->lock);
+       raw_spin_rq_unlock(rq1);
        __release(rq2->lock);
 }
 
index dc218e9..d8f8eb0 100644 (file)
@@ -25,7 +25,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long long delta)
 }
 
 static inline void
-rq_sched_info_dequeued(struct rq *rq, unsigned long long delta)
+rq_sched_info_dequeue(struct rq *rq, unsigned long long delta)
 {
        if (rq)
                rq->rq_sched_info.run_delay += delta;
@@ -42,7 +42,7 @@ rq_sched_info_dequeued(struct rq *rq, unsigned long long delta)
 
 #else /* !CONFIG_SCHEDSTATS: */
 static inline void rq_sched_info_arrive  (struct rq *rq, unsigned long long delta) { }
-static inline void rq_sched_info_dequeued(struct rq *rq, unsigned long long delta) { }
+static inline void rq_sched_info_dequeue(struct rq *rq, unsigned long long delta) { }
 static inline void rq_sched_info_depart  (struct rq *rq, unsigned long long delta) { }
 # define   schedstat_enabled()         0
 # define __schedstat_inc(var)          do { } while (0)
@@ -150,29 +150,24 @@ static inline void psi_sched_switch(struct task_struct *prev,
 #endif /* CONFIG_PSI */
 
 #ifdef CONFIG_SCHED_INFO
-static inline void sched_info_reset_dequeued(struct task_struct *t)
-{
-       t->sched_info.last_queued = 0;
-}
-
 /*
  * We are interested in knowing how long it was from the *first* time a
  * task was queued to the time that it finally hit a CPU, we call this routine
  * from dequeue_task() to account for possible rq->clock skew across CPUs. The
  * delta taken on each CPU would annul the skew.
  */
-static inline void sched_info_dequeued(struct rq *rq, struct task_struct *t)
+static inline void sched_info_dequeue(struct rq *rq, struct task_struct *t)
 {
-       unsigned long long now = rq_clock(rq), delta = 0;
+       unsigned long long delta = 0;
 
-       if (sched_info_on()) {
-               if (t->sched_info.last_queued)
-                       delta = now - t->sched_info.last_queued;
-       }
-       sched_info_reset_dequeued(t);
+       if (!t->sched_info.last_queued)
+               return;
+
+       delta = rq_clock(rq) - t->sched_info.last_queued;
+       t->sched_info.last_queued = 0;
        t->sched_info.run_delay += delta;
 
-       rq_sched_info_dequeued(rq, delta);
+       rq_sched_info_dequeue(rq, delta);
 }
 
 /*
@@ -182,11 +177,14 @@ static inline void sched_info_dequeued(struct rq *rq, struct task_struct *t)
  */
 static void sched_info_arrive(struct rq *rq, struct task_struct *t)
 {
-       unsigned long long now = rq_clock(rq), delta = 0;
+       unsigned long long now, delta = 0;
+
+       if (!t->sched_info.last_queued)
+               return;
 
-       if (t->sched_info.last_queued)
-               delta = now - t->sched_info.last_queued;
-       sched_info_reset_dequeued(t);
+       now = rq_clock(rq);
+       delta = now - t->sched_info.last_queued;
+       t->sched_info.last_queued = 0;
        t->sched_info.run_delay += delta;
        t->sched_info.last_arrival = now;
        t->sched_info.pcount++;
@@ -197,14 +195,12 @@ static void sched_info_arrive(struct rq *rq, struct task_struct *t)
 /*
  * This function is only called from enqueue_task(), but also only updates
  * the timestamp if it is already not set.  It's assumed that
- * sched_info_dequeued() will clear that stamp when appropriate.
+ * sched_info_dequeue() will clear that stamp when appropriate.
  */
-static inline void sched_info_queued(struct rq *rq, struct task_struct *t)
+static inline void sched_info_enqueue(struct rq *rq, struct task_struct *t)
 {
-       if (sched_info_on()) {
-               if (!t->sched_info.last_queued)
-                       t->sched_info.last_queued = rq_clock(rq);
-       }
+       if (!t->sched_info.last_queued)
+               t->sched_info.last_queued = rq_clock(rq);
 }
 
 /*
@@ -212,7 +208,7 @@ static inline void sched_info_queued(struct rq *rq, struct task_struct *t)
  * due, typically, to expiring its time slice (this may also be called when
  * switching to the idle task).  Now we can calculate how long we ran.
  * Also, if the process is still in the TASK_RUNNING state, call
- * sched_info_queued() to mark that it has now again started waiting on
+ * sched_info_enqueue() to mark that it has now again started waiting on
  * the runqueue.
  */
 static inline void sched_info_depart(struct rq *rq, struct task_struct *t)
@@ -221,8 +217,8 @@ static inline void sched_info_depart(struct rq *rq, struct task_struct *t)
 
        rq_sched_info_depart(rq, delta);
 
-       if (t->state == TASK_RUNNING)
-               sched_info_queued(rq, t);
+       if (task_is_running(t))
+               sched_info_enqueue(rq, t);
 }
 
 /*
@@ -231,7 +227,7 @@ static inline void sched_info_depart(struct rq *rq, struct task_struct *t)
  * the idle task.)  We are only called when prev != next.
  */
 static inline void
-__sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
+sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
 {
        /*
         * prev now departs the CPU.  It's not interesting to record
@@ -245,18 +241,8 @@ __sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct
                sched_info_arrive(rq, next);
 }
 
-static inline void
-sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
-{
-       if (sched_info_on())
-               __sched_info_switch(rq, prev, next);
-}
-
 #else /* !CONFIG_SCHED_INFO: */
-# define sched_info_queued(rq, t)      do { } while (0)
-# define sched_info_reset_dequeued(t)  do { } while (0)
-# define sched_info_dequeued(rq, t)    do { } while (0)
-# define sched_info_depart(rq, t)      do { } while (0)
-# define sched_info_arrive(rq, next)   do { } while (0)
+# define sched_info_enqueue(rq, t)     do { } while (0)
+# define sched_info_dequeue(rq, t)     do { } while (0)
 # define sched_info_switch(rq, t, next)        do { } while (0)
 #endif /* CONFIG_SCHED_INFO */
index 55f3912..f988ebe 100644 (file)
@@ -34,15 +34,24 @@ static void set_next_task_stop(struct rq *rq, struct task_struct *stop, bool fir
        stop->se.exec_start = rq_clock_task(rq);
 }
 
-static struct task_struct *pick_next_task_stop(struct rq *rq)
+static struct task_struct *pick_task_stop(struct rq *rq)
 {
        if (!sched_stop_runnable(rq))
                return NULL;
 
-       set_next_task_stop(rq, rq->stop, true);
        return rq->stop;
 }
 
+static struct task_struct *pick_next_task_stop(struct rq *rq)
+{
+       struct task_struct *p = pick_task_stop(rq);
+
+       if (p)
+               set_next_task_stop(rq, p, true);
+
+       return p;
+}
+
 static void
 enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 {
@@ -123,6 +132,7 @@ DEFINE_SCHED_CLASS(stop) = {
 
 #ifdef CONFIG_SMP
        .balance                = balance_stop,
+       .pick_task              = pick_task_stop,
        .select_task_rq         = select_task_rq_stop,
        .set_cpus_allowed       = set_cpus_allowed_common,
 #endif
index 55a0a24..b77ad49 100644 (file)
@@ -467,7 +467,7 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)
        struct root_domain *old_rd = NULL;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&rq->lock, flags);
+       raw_spin_rq_lock_irqsave(rq, flags);
 
        if (rq->rd) {
                old_rd = rq->rd;
@@ -493,7 +493,7 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)
        if (cpumask_test_cpu(rq->cpu, cpu_active_mask))
                set_rq_online(rq);
 
-       raw_spin_unlock_irqrestore(&rq->lock, flags);
+       raw_spin_rq_unlock_irqrestore(rq, flags);
 
        if (old_rd)
                call_rcu(&old_rd->rcu, free_rootdomain);
@@ -675,7 +675,7 @@ static void update_top_cache_domain(int cpu)
        sd = highest_flag_domain(cpu, SD_ASYM_PACKING);
        rcu_assign_pointer(per_cpu(sd_asym_packing, cpu), sd);
 
-       sd = lowest_flag_domain(cpu, SD_ASYM_CPUCAPACITY);
+       sd = lowest_flag_domain(cpu, SD_ASYM_CPUCAPACITY_FULL);
        rcu_assign_pointer(per_cpu(sd_asym_cpucapacity, cpu), sd);
 }
 
@@ -1267,6 +1267,116 @@ next:
 }
 
 /*
+ * Asymmetric CPU capacity bits
+ */
+struct asym_cap_data {
+       struct list_head link;
+       unsigned long capacity;
+       unsigned long cpus[];
+};
+
+/*
+ * Set of available CPUs grouped by their corresponding capacities
+ * Each list entry contains a CPU mask reflecting CPUs that share the same
+ * capacity.
+ * The lifespan of data is unlimited.
+ */
+static LIST_HEAD(asym_cap_list);
+
+#define cpu_capacity_span(asym_data) to_cpumask((asym_data)->cpus)
+
+/*
+ * Verify whether there is any CPU capacity asymmetry in a given sched domain.
+ * Provides sd_flags reflecting the asymmetry scope.
+ */
+static inline int
+asym_cpu_capacity_classify(const struct cpumask *sd_span,
+                          const struct cpumask *cpu_map)
+{
+       struct asym_cap_data *entry;
+       int count = 0, miss = 0;
+
+       /*
+        * Count how many unique CPU capacities this domain spans across
+        * (compare sched_domain CPUs mask with ones representing  available
+        * CPUs capacities). Take into account CPUs that might be offline:
+        * skip those.
+        */
+       list_for_each_entry(entry, &asym_cap_list, link) {
+               if (cpumask_intersects(sd_span, cpu_capacity_span(entry)))
+                       ++count;
+               else if (cpumask_intersects(cpu_map, cpu_capacity_span(entry)))
+                       ++miss;
+       }
+
+       WARN_ON_ONCE(!count && !list_empty(&asym_cap_list));
+
+       /* No asymmetry detected */
+       if (count < 2)
+               return 0;
+       /* Some of the available CPU capacity values have not been detected */
+       if (miss)
+               return SD_ASYM_CPUCAPACITY;
+
+       /* Full asymmetry */
+       return SD_ASYM_CPUCAPACITY | SD_ASYM_CPUCAPACITY_FULL;
+
+}
+
+static inline void asym_cpu_capacity_update_data(int cpu)
+{
+       unsigned long capacity = arch_scale_cpu_capacity(cpu);
+       struct asym_cap_data *entry = NULL;
+
+       list_for_each_entry(entry, &asym_cap_list, link) {
+               if (capacity == entry->capacity)
+                       goto done;
+       }
+
+       entry = kzalloc(sizeof(*entry) + cpumask_size(), GFP_KERNEL);
+       if (WARN_ONCE(!entry, "Failed to allocate memory for asymmetry data\n"))
+               return;
+       entry->capacity = capacity;
+       list_add(&entry->link, &asym_cap_list);
+done:
+       __cpumask_set_cpu(cpu, cpu_capacity_span(entry));
+}
+
+/*
+ * Build-up/update list of CPUs grouped by their capacities
+ * An update requires explicit request to rebuild sched domains
+ * with state indicating CPU topology changes.
+ */
+static void asym_cpu_capacity_scan(void)
+{
+       struct asym_cap_data *entry, *next;
+       int cpu;
+
+       list_for_each_entry(entry, &asym_cap_list, link)
+               cpumask_clear(cpu_capacity_span(entry));
+
+       for_each_cpu_and(cpu, cpu_possible_mask, housekeeping_cpumask(HK_FLAG_DOMAIN))
+               asym_cpu_capacity_update_data(cpu);
+
+       list_for_each_entry_safe(entry, next, &asym_cap_list, link) {
+               if (cpumask_empty(cpu_capacity_span(entry))) {
+                       list_del(&entry->link);
+                       kfree(entry);
+               }
+       }
+
+       /*
+        * Only one capacity value has been detected i.e. this system is symmetric.
+        * No need to keep this data around.
+        */
+       if (list_is_singular(&asym_cap_list)) {
+               entry = list_first_entry(&asym_cap_list, typeof(*entry), link);
+               list_del(&entry->link);
+               kfree(entry);
+       }
+}
+
+/*
  * Initializers for schedule domains
  * Non-inlined to reduce accumulated stack pressure in build_sched_domains()
  */
@@ -1399,11 +1509,12 @@ int __read_mostly               node_reclaim_distance = RECLAIM_DISTANCE;
 static struct sched_domain *
 sd_init(struct sched_domain_topology_level *tl,
        const struct cpumask *cpu_map,
-       struct sched_domain *child, int dflags, int cpu)
+       struct sched_domain *child, int cpu)
 {
        struct sd_data *sdd = &tl->data;
        struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu);
        int sd_id, sd_weight, sd_flags = 0;
+       struct cpumask *sd_span;
 
 #ifdef CONFIG_NUMA
        /*
@@ -1420,9 +1531,6 @@ sd_init(struct sched_domain_topology_level *tl,
                        "wrong sd_flags in topology description\n"))
                sd_flags &= TOPOLOGY_SD_FLAGS;
 
-       /* Apply detected topology flags */
-       sd_flags |= dflags;
-
        *sd = (struct sched_domain){
                .min_interval           = sd_weight,
                .max_interval           = 2*sd_weight,
@@ -1454,13 +1562,19 @@ sd_init(struct sched_domain_topology_level *tl,
 #endif
        };
 
-       cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu));
-       sd_id = cpumask_first(sched_domain_span(sd));
+       sd_span = sched_domain_span(sd);
+       cpumask_and(sd_span, cpu_map, tl->mask(cpu));
+       sd_id = cpumask_first(sd_span);
+
+       sd->flags |= asym_cpu_capacity_classify(sd_span, cpu_map);
+
+       WARN_ONCE((sd->flags & (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY)) ==
+                 (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY),
+                 "CPU capacity asymmetry not supported on SMT\n");
 
        /*
         * Convert topological properties into behaviour.
         */
-
        /* Don't attempt to spread across CPUs of different capacities. */
        if ((sd->flags & SD_ASYM_CPUCAPACITY) && sd->child)
                sd->child->flags &= ~SD_PREFER_SIBLING;
@@ -1926,9 +2040,9 @@ static void __sdt_free(const struct cpumask *cpu_map)
 
 static struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
                const struct cpumask *cpu_map, struct sched_domain_attr *attr,
-               struct sched_domain *child, int dflags, int cpu)
+               struct sched_domain *child, int cpu)
 {
-       struct sched_domain *sd = sd_init(tl, cpu_map, child, dflags, cpu);
+       struct sched_domain *sd = sd_init(tl, cpu_map, child, cpu);
 
        if (child) {
                sd->level = child->level + 1;
@@ -1991,65 +2105,6 @@ static bool topology_span_sane(struct sched_domain_topology_level *tl,
 }
 
 /*
- * Find the sched_domain_topology_level where all CPU capacities are visible
- * for all CPUs.
- */
-static struct sched_domain_topology_level
-*asym_cpu_capacity_level(const struct cpumask *cpu_map)
-{
-       int i, j, asym_level = 0;
-       bool asym = false;
-       struct sched_domain_topology_level *tl, *asym_tl = NULL;
-       unsigned long cap;
-
-       /* Is there any asymmetry? */
-       cap = arch_scale_cpu_capacity(cpumask_first(cpu_map));
-
-       for_each_cpu(i, cpu_map) {
-               if (arch_scale_cpu_capacity(i) != cap) {
-                       asym = true;
-                       break;
-               }
-       }
-
-       if (!asym)
-               return NULL;
-
-       /*
-        * Examine topology from all CPU's point of views to detect the lowest
-        * sched_domain_topology_level where a highest capacity CPU is visible
-        * to everyone.
-        */
-       for_each_cpu(i, cpu_map) {
-               unsigned long max_capacity = arch_scale_cpu_capacity(i);
-               int tl_id = 0;
-
-               for_each_sd_topology(tl) {
-                       if (tl_id < asym_level)
-                               goto next_level;
-
-                       for_each_cpu_and(j, tl->mask(i), cpu_map) {
-                               unsigned long capacity;
-
-                               capacity = arch_scale_cpu_capacity(j);
-
-                               if (capacity <= max_capacity)
-                                       continue;
-
-                               max_capacity = capacity;
-                               asym_level = tl_id;
-                               asym_tl = tl;
-                       }
-next_level:
-                       tl_id++;
-               }
-       }
-
-       return asym_tl;
-}
-
-
-/*
  * Build sched domains for a given set of CPUs and attach the sched domains
  * to the individual CPUs
  */
@@ -2061,7 +2116,6 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
        struct s_data d;
        struct rq *rq = NULL;
        int i, ret = -ENOMEM;
-       struct sched_domain_topology_level *tl_asym;
        bool has_asym = false;
 
        if (WARN_ON(cpumask_empty(cpu_map)))
@@ -2071,24 +2125,19 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
        if (alloc_state != sa_rootdomain)
                goto error;
 
-       tl_asym = asym_cpu_capacity_level(cpu_map);
-
        /* Set up domains for CPUs specified by the cpu_map: */
        for_each_cpu(i, cpu_map) {
                struct sched_domain_topology_level *tl;
-               int dflags = 0;
 
                sd = NULL;
                for_each_sd_topology(tl) {
-                       if (tl == tl_asym) {
-                               dflags |= SD_ASYM_CPUCAPACITY;
-                               has_asym = true;
-                       }
 
                        if (WARN_ON(!topology_span_sane(tl, cpu_map, i)))
                                goto error;
 
-                       sd = build_sched_domain(tl, cpu_map, attr, sd, dflags, i);
+                       sd = build_sched_domain(tl, cpu_map, attr, sd, i);
+
+                       has_asym |= sd->flags & SD_ASYM_CPUCAPACITY;
 
                        if (tl == sched_domain_topology)
                                *per_cpu_ptr(d.sd, i) = sd;
@@ -2217,6 +2266,7 @@ int sched_init_domains(const struct cpumask *cpu_map)
        zalloc_cpumask_var(&fallback_doms, GFP_KERNEL);
 
        arch_update_cpu_topology();
+       asym_cpu_capacity_scan();
        ndoms_cur = 1;
        doms_cur = alloc_sched_domains(ndoms_cur);
        if (!doms_cur)
@@ -2299,6 +2349,9 @@ void partition_sched_domains_locked(int ndoms_new, cpumask_var_t doms_new[],
 
        /* Let the architecture update CPU core mappings: */
        new_topology = arch_update_cpu_topology();
+       /* Trigger rebuilding CPU capacity asymmetry data */
+       if (new_topology)
+               asym_cpu_capacity_scan();
 
        if (!doms_new) {
                WARN_ON_ONCE(dattr_new);
index 9f58049..057e17f 100644 (file)
@@ -107,6 +107,7 @@ struct seccomp_knotif {
  *      installing process should allocate the fd as normal.
  * @flags: The flags for the new file descriptor. At the moment, only O_CLOEXEC
  *         is allowed.
+ * @ioctl_flags: The flags used for the seccomp_addfd ioctl.
  * @ret: The return value of the installing process. It is set to the fd num
  *       upon success (>= 0).
  * @completion: Indicates that the installing process has completed fd
@@ -118,6 +119,7 @@ struct seccomp_kaddfd {
        struct file *file;
        int fd;
        unsigned int flags;
+       __u32 ioctl_flags;
 
        union {
                bool setfd;
@@ -1065,18 +1067,37 @@ static u64 seccomp_next_notify_id(struct seccomp_filter *filter)
        return filter->notif->next_id++;
 }
 
-static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd)
+static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_knotif *n)
 {
+       int fd;
+
        /*
         * Remove the notification, and reset the list pointers, indicating
         * that it has been handled.
         */
        list_del_init(&addfd->list);
        if (!addfd->setfd)
-               addfd->ret = receive_fd(addfd->file, addfd->flags);
+               fd = receive_fd(addfd->file, addfd->flags);
        else
-               addfd->ret = receive_fd_replace(addfd->fd, addfd->file,
-                                               addfd->flags);
+               fd = receive_fd_replace(addfd->fd, addfd->file, addfd->flags);
+       addfd->ret = fd;
+
+       if (addfd->ioctl_flags & SECCOMP_ADDFD_FLAG_SEND) {
+               /* If we fail reset and return an error to the notifier */
+               if (fd < 0) {
+                       n->state = SECCOMP_NOTIFY_SENT;
+               } else {
+                       /* Return the FD we just added */
+                       n->flags = 0;
+                       n->error = 0;
+                       n->val = fd;
+               }
+       }
+
+       /*
+        * Mark the notification as completed. From this point, addfd mem
+        * might be invalidated and we can't safely read it anymore.
+        */
        complete(&addfd->completion);
 }
 
@@ -1120,7 +1141,7 @@ static int seccomp_do_user_notification(int this_syscall,
                                                 struct seccomp_kaddfd, list);
                /* Check if we were woken up by a addfd message */
                if (addfd)
-                       seccomp_handle_addfd(addfd);
+                       seccomp_handle_addfd(addfd, &n);
 
        }  while (n.state != SECCOMP_NOTIFY_REPLIED);
 
@@ -1581,7 +1602,7 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter,
        if (addfd.newfd_flags & ~O_CLOEXEC)
                return -EINVAL;
 
-       if (addfd.flags & ~SECCOMP_ADDFD_FLAG_SETFD)
+       if (addfd.flags & ~(SECCOMP_ADDFD_FLAG_SETFD | SECCOMP_ADDFD_FLAG_SEND))
                return -EINVAL;
 
        if (addfd.newfd && !(addfd.flags & SECCOMP_ADDFD_FLAG_SETFD))
@@ -1591,6 +1612,7 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter,
        if (!kaddfd.file)
                return -EBADF;
 
+       kaddfd.ioctl_flags = addfd.flags;
        kaddfd.flags = addfd.newfd_flags;
        kaddfd.setfd = addfd.flags & SECCOMP_ADDFD_FLAG_SETFD;
        kaddfd.fd = addfd.newfd;
@@ -1616,6 +1638,23 @@ static long seccomp_notify_addfd(struct seccomp_filter *filter,
                goto out_unlock;
        }
 
+       if (addfd.flags & SECCOMP_ADDFD_FLAG_SEND) {
+               /*
+                * Disallow queuing an atomic addfd + send reply while there are
+                * some addfd requests still to process.
+                *
+                * There is no clear reason to support it and allows us to keep
+                * the loop on the other side straight-forward.
+                */
+               if (!list_empty(&knotif->addfd)) {
+                       ret = -EBUSY;
+                       goto out_unlock;
+               }
+
+               /* Allow exactly only one reply */
+               knotif->state = SECCOMP_NOTIFY_REPLIED;
+       }
+
        list_add(&kaddfd.list, &knotif->addfd);
        complete(&knotif->ready);
        mutex_unlock(&filter->notify_lock);
index f7c6ffc..de09203 100644 (file)
@@ -412,8 +412,8 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
                 int override_rlimit, const unsigned int sigqueue_flags)
 {
        struct sigqueue *q = NULL;
-       struct user_struct *user;
-       int sigpending;
+       struct ucounts *ucounts = NULL;
+       long sigpending;
 
        /*
         * Protect access to @t credentials. This can go away when all
@@ -424,77 +424,38 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
         * changes from/to zero.
         */
        rcu_read_lock();
-       user = __task_cred(t)->user;
-       sigpending = atomic_inc_return(&user->sigpending);
+       ucounts = task_ucounts(t);
+       sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
        if (sigpending == 1)
-               get_uid(user);
+               ucounts = get_ucounts(ucounts);
        rcu_read_unlock();
 
-       if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
-               /*
-                * Preallocation does not hold sighand::siglock so it can't
-                * use the cache. The lockless caching requires that only
-                * one consumer and only one producer run at a time.
-                */
-               q = READ_ONCE(t->sigqueue_cache);
-               if (!q || sigqueue_flags)
-                       q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
-               else
-                       WRITE_ONCE(t->sigqueue_cache, NULL);
+       if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
+               q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
        } else {
                print_dropped_signal(sig);
        }
 
        if (unlikely(q == NULL)) {
-               if (atomic_dec_and_test(&user->sigpending))
-                       free_uid(user);
+               if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))
+                       put_ucounts(ucounts);
        } else {
                INIT_LIST_HEAD(&q->list);
                q->flags = sigqueue_flags;
-               q->user = user;
+               q->ucounts = ucounts;
        }
-
        return q;
 }
 
-void exit_task_sigqueue_cache(struct task_struct *tsk)
-{
-       /* Race free because @tsk is mopped up */
-       struct sigqueue *q = tsk->sigqueue_cache;
-
-       if (q) {
-               tsk->sigqueue_cache = NULL;
-               /*
-                * Hand it back to the cache as the task might
-                * be self reaping which would leak the object.
-                */
-                kmem_cache_free(sigqueue_cachep, q);
-       }
-}
-
-static void sigqueue_cache_or_free(struct sigqueue *q)
-{
-       /*
-        * Cache one sigqueue per task. This pairs with the consumer side
-        * in __sigqueue_alloc() and needs READ/WRITE_ONCE() to prevent the
-        * compiler from store tearing and to tell KCSAN that the data race
-        * is intentional when run without holding current->sighand->siglock,
-        * which is fine as current obviously cannot run __sigqueue_free()
-        * concurrently.
-        */
-       if (!READ_ONCE(current->sigqueue_cache))
-               WRITE_ONCE(current->sigqueue_cache, q);
-       else
-               kmem_cache_free(sigqueue_cachep, q);
-}
-
 static void __sigqueue_free(struct sigqueue *q)
 {
        if (q->flags & SIGQUEUE_PREALLOC)
                return;
-       if (atomic_dec_and_test(&q->user->sigpending))
-               free_uid(q->user);
-       sigqueue_cache_or_free(q);
+       if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {
+               put_ucounts(q->ucounts);
+               q->ucounts = NULL;
+       }
+       kmem_cache_free(sigqueue_cachep, q);
 }
 
 void flush_sigqueue(struct sigpending *queue)
@@ -4719,7 +4680,7 @@ void kdb_send_sig(struct task_struct *t, int sig)
        }
        new_t = kdb_prev_t != t;
        kdb_prev_t = t;
-       if (t->state != TASK_RUNNING && new_t) {
+       if (!task_is_running(t) && new_t) {
                spin_unlock(&t->sighand->siglock);
                kdb_printf("Process is not RUNNING, sending a signal from "
                           "kdb risks deadlock\n"
index f25208e..e416304 100644 (file)
@@ -33,7 +33,6 @@ struct task_struct *idle_thread_get(unsigned int cpu)
 
        if (!tsk)
                return ERR_PTR(-ENOMEM);
-       init_idle(tsk, cpu);
        return tsk;
 }
 
index 4992853..f3a0121 100644 (file)
@@ -76,7 +76,7 @@ static void wakeup_softirqd(void)
        /* Interrupts are disabled: no need to stop preemption */
        struct task_struct *tsk = __this_cpu_read(ksoftirqd);
 
-       if (tsk && tsk->state != TASK_RUNNING)
+       if (tsk)
                wake_up_process(tsk);
 }
 
@@ -92,8 +92,7 @@ static bool ksoftirqd_running(unsigned long pending)
 
        if (pending & SOFTIRQ_NOW_MASK)
                return false;
-       return tsk && (tsk->state == TASK_RUNNING) &&
-               !__kthread_should_park(tsk);
+       return tsk && task_is_running(tsk) && !__kthread_should_park(tsk);
 }
 
 #ifdef CONFIG_TRACE_IRQFLAGS
index 3a583a2..ef1a78f 100644 (file)
@@ -479,7 +479,7 @@ static int set_user(struct cred *new)
         * for programs doing set*uid()+execve() by harmlessly deferring the
         * failure to the execve() stage.
         */
-       if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
+       if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
                        new_user != INIT_USER)
                current->flags |= PF_NPROC_EXCEEDED;
        else
@@ -558,6 +558,10 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
        if (retval < 0)
                goto error;
 
+       retval = set_cred_ucounts(new);
+       if (retval < 0)
+               goto error;
+
        return commit_creds(new);
 
 error:
@@ -616,6 +620,10 @@ long __sys_setuid(uid_t uid)
        if (retval < 0)
                goto error;
 
+       retval = set_cred_ucounts(new);
+       if (retval < 0)
+               goto error;
+
        return commit_creds(new);
 
 error:
@@ -691,6 +699,10 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        if (retval < 0)
                goto error;
 
+       retval = set_cred_ucounts(new);
+       if (retval < 0)
+               goto error;
+
        return commit_creds(new);
 
 error:
@@ -2550,6 +2562,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                error = set_syscall_user_dispatch(arg2, arg3, arg4,
                                                  (char __user *) arg5);
                break;
+#ifdef CONFIG_SCHED_CORE
+       case PR_SCHED_CORE:
+               error = sched_core_share_pid(arg2, arg3, arg4, arg5);
+               break;
+#endif
        default:
                error = -EINVAL;
                break;
index d4a78e0..8c8c220 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/coredump.h>
 #include <linux/latencytop.h>
 #include <linux/pid.h>
+#include <linux/delayacct.h>
 
 #include "../lib/kstrtox.h"
 
@@ -1747,6 +1748,17 @@ static struct ctl_table kern_table[] = {
                .extra2         = SYSCTL_ONE,
        },
 #endif /* CONFIG_SCHEDSTATS */
+#ifdef CONFIG_TASK_DELAY_ACCT
+       {
+               .procname       = "task_delayacct",
+               .data           = NULL,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = sysctl_delayacct,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
+#endif /* CONFIG_TASK_DELAY_ACCT */
 #ifdef CONFIG_NUMA_BALANCING
        {
                .procname       = "numa_balancing",
index 83e158d..04bfd62 100644 (file)
@@ -64,6 +64,15 @@ config LEGACY_TIMER_TICK
          lack support for the generic clockevent framework.
          New platforms should use generic clockevents instead.
 
+config TIME_KUNIT_TEST
+       tristate "KUnit test for kernel/time functions" if !KUNIT_ALL_TESTS
+       depends on KUNIT
+       default KUNIT_ALL_TESTS
+       help
+         Enable this option to test RTC library functions.
+
+         If unsure, say N.
+
 if GENERIC_CLOCKEVENTS
 menu "Timers subsystem"
 
@@ -117,13 +126,14 @@ config NO_HZ_FULL
         the task mostly runs in userspace and has few kernel activity.
 
         You need to fill up the nohz_full boot parameter with the
-        desired range of dynticks CPUs.
+        desired range of dynticks CPUs to use it. This is implemented at
+        the expense of some overhead in user <-> kernel transitions:
+        syscalls, exceptions and interrupts.
 
-        This is implemented at the expense of some overhead in user <-> kernel
-        transitions: syscalls, exceptions and interrupts. Even when it's
-        dynamically off.
+        By default, without passing the nohz_full parameter, this behaves just
+        like NO_HZ_IDLE.
 
-        Say N.
+        If you're a distro say Y.
 
 endchoice
 
index 1fb1c1e..7e875e6 100644 (file)
@@ -21,3 +21,5 @@ obj-$(CONFIG_HAVE_GENERIC_VDSO)                       += vsyscall.o
 obj-$(CONFIG_DEBUG_FS)                         += timekeeping_debug.o
 obj-$(CONFIG_TEST_UDELAY)                      += test_udelay.o
 obj-$(CONFIG_TIME_NS)                          += namespace.o
+obj-$(CONFIG_TEST_CLOCKSOURCE_WATCHDOG)                += clocksource-wdtest.o
+obj-$(CONFIG_TIME_KUNIT_TEST)                  += time_test.o
index f549022..003ccf3 100644 (file)
@@ -347,8 +347,7 @@ static void clockevents_notify_released(void)
        while (!list_empty(&clockevents_released)) {
                dev = list_entry(clockevents_released.next,
                                 struct clock_event_device, list);
-               list_del(&dev->list);
-               list_add(&dev->list, &clockevent_devices);
+               list_move(&dev->list, &clockevent_devices);
                tick_check_new_device(dev);
        }
 }
@@ -576,8 +575,7 @@ void clockevents_exchange_device(struct clock_event_device *old,
        if (old) {
                module_put(old->owner);
                clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED);
-               list_del(&old->list);
-               list_add(&old->list, &clockevents_released);
+               list_move(&old->list, &clockevents_released);
        }
 
        if (new) {
@@ -629,6 +627,7 @@ void tick_offline_cpu(unsigned int cpu)
 
 /**
  * tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu
+ * @cpu:       The dead CPU
  */
 void tick_cleanup_dead_cpu(int cpu)
 {
@@ -668,9 +667,9 @@ static struct bus_type clockevents_subsys = {
 static DEFINE_PER_CPU(struct device, tick_percpu_dev);
 static struct tick_device *tick_get_tick_dev(struct device *dev);
 
-static ssize_t sysfs_show_current_tick_dev(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf)
+static ssize_t current_device_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
 {
        struct tick_device *td;
        ssize_t count = 0;
@@ -682,12 +681,12 @@ static ssize_t sysfs_show_current_tick_dev(struct device *dev,
        raw_spin_unlock_irq(&clockevents_lock);
        return count;
 }
-static DEVICE_ATTR(current_device, 0444, sysfs_show_current_tick_dev, NULL);
+static DEVICE_ATTR_RO(current_device);
 
 /* We don't support the abomination of removable broadcast devices */
-static ssize_t sysfs_unbind_tick_dev(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
+static ssize_t unbind_device_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
 {
        char name[CS_NAME_LEN];
        ssize_t ret = sysfs_get_uname(buf, name, count);
@@ -714,7 +713,7 @@ static ssize_t sysfs_unbind_tick_dev(struct device *dev,
        mutex_unlock(&clockevents_mutex);
        return ret ? ret : count;
 }
-static DEVICE_ATTR(unbind_device, 0200, NULL, sysfs_unbind_tick_dev);
+static DEVICE_ATTR_WO(unbind_device);
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 static struct device tick_bc_dev = {
diff --git a/kernel/time/clocksource-wdtest.c b/kernel/time/clocksource-wdtest.c
new file mode 100644 (file)
index 0000000..01df123
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unit test for the clocksource watchdog.
+ *
+ * Copyright (C) 2021 Facebook, Inc.
+ *
+ * Author: Paul E. McKenney <paulmck@kernel.org>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
+#include <linux/tick.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/prandom.h>
+#include <linux/cpu.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@kernel.org>");
+
+static int holdoff = IS_BUILTIN(CONFIG_TEST_CLOCKSOURCE_WATCHDOG) ? 10 : 0;
+module_param(holdoff, int, 0444);
+MODULE_PARM_DESC(holdoff, "Time to wait to start test (s).");
+
+/* Watchdog kthread's task_struct pointer for debug purposes. */
+static struct task_struct *wdtest_task;
+
+static u64 wdtest_jiffies_read(struct clocksource *cs)
+{
+       return (u64)jiffies;
+}
+
+/* Assume HZ > 100. */
+#define JIFFIES_SHIFT  8
+
+static struct clocksource clocksource_wdtest_jiffies = {
+       .name                   = "wdtest-jiffies",
+       .rating                 = 1, /* lowest valid rating*/
+       .uncertainty_margin     = TICK_NSEC,
+       .read                   = wdtest_jiffies_read,
+       .mask                   = CLOCKSOURCE_MASK(32),
+       .flags                  = CLOCK_SOURCE_MUST_VERIFY,
+       .mult                   = TICK_NSEC << JIFFIES_SHIFT, /* details above */
+       .shift                  = JIFFIES_SHIFT,
+       .max_cycles             = 10,
+};
+
+static int wdtest_ktime_read_ndelays;
+static bool wdtest_ktime_read_fuzz;
+
+static u64 wdtest_ktime_read(struct clocksource *cs)
+{
+       int wkrn = READ_ONCE(wdtest_ktime_read_ndelays);
+       static int sign = 1;
+       u64 ret;
+
+       if (wkrn) {
+               udelay(cs->uncertainty_margin / 250);
+               WRITE_ONCE(wdtest_ktime_read_ndelays, wkrn - 1);
+       }
+       ret = ktime_get_real_fast_ns();
+       if (READ_ONCE(wdtest_ktime_read_fuzz)) {
+               sign = -sign;
+               ret = ret + sign * 100 * NSEC_PER_MSEC;
+       }
+       return ret;
+}
+
+static void wdtest_ktime_cs_mark_unstable(struct clocksource *cs)
+{
+       pr_info("--- Marking %s unstable due to clocksource watchdog.\n", cs->name);
+}
+
+#define KTIME_FLAGS (CLOCK_SOURCE_IS_CONTINUOUS | \
+                    CLOCK_SOURCE_VALID_FOR_HRES | \
+                    CLOCK_SOURCE_MUST_VERIFY | \
+                    CLOCK_SOURCE_VERIFY_PERCPU)
+
+static struct clocksource clocksource_wdtest_ktime = {
+       .name                   = "wdtest-ktime",
+       .rating                 = 300,
+       .read                   = wdtest_ktime_read,
+       .mask                   = CLOCKSOURCE_MASK(64),
+       .flags                  = KTIME_FLAGS,
+       .mark_unstable          = wdtest_ktime_cs_mark_unstable,
+       .list                   = LIST_HEAD_INIT(clocksource_wdtest_ktime.list),
+};
+
+/* Reset the clocksource if needed. */
+static void wdtest_ktime_clocksource_reset(void)
+{
+       if (clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE) {
+               clocksource_unregister(&clocksource_wdtest_ktime);
+               clocksource_wdtest_ktime.flags = KTIME_FLAGS;
+               schedule_timeout_uninterruptible(HZ / 10);
+               clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
+       }
+}
+
+/* Run the specified series of watchdog tests. */
+static int wdtest_func(void *arg)
+{
+       unsigned long j1, j2;
+       char *s;
+       int i;
+
+       schedule_timeout_uninterruptible(holdoff * HZ);
+
+       /*
+        * Verify that jiffies-like clocksources get the manually
+        * specified uncertainty margin.
+        */
+       pr_info("--- Verify jiffies-like uncertainty margin.\n");
+       __clocksource_register(&clocksource_wdtest_jiffies);
+       WARN_ON_ONCE(clocksource_wdtest_jiffies.uncertainty_margin != TICK_NSEC);
+
+       j1 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
+       schedule_timeout_uninterruptible(HZ);
+       j2 = clocksource_wdtest_jiffies.read(&clocksource_wdtest_jiffies);
+       WARN_ON_ONCE(j1 == j2);
+
+       clocksource_unregister(&clocksource_wdtest_jiffies);
+
+       /*
+        * Verify that tsc-like clocksources are assigned a reasonable
+        * uncertainty margin.
+        */
+       pr_info("--- Verify tsc-like uncertainty margin.\n");
+       clocksource_register_khz(&clocksource_wdtest_ktime, 1000 * 1000);
+       WARN_ON_ONCE(clocksource_wdtest_ktime.uncertainty_margin < NSEC_PER_USEC);
+
+       j1 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
+       udelay(1);
+       j2 = clocksource_wdtest_ktime.read(&clocksource_wdtest_ktime);
+       pr_info("--- tsc-like times: %lu - %lu = %lu.\n", j2, j1, j2 - j1);
+       WARN_ON_ONCE(time_before(j2, j1 + NSEC_PER_USEC));
+
+       /* Verify tsc-like stability with various numbers of errors injected. */
+       for (i = 0; i <= max_cswd_read_retries + 1; i++) {
+               if (i <= 1 && i < max_cswd_read_retries)
+                       s = "";
+               else if (i <= max_cswd_read_retries)
+                       s = ", expect message";
+               else
+                       s = ", expect clock skew";
+               pr_info("--- Watchdog with %dx error injection, %lu retries%s.\n", i, max_cswd_read_retries, s);
+               WRITE_ONCE(wdtest_ktime_read_ndelays, i);
+               schedule_timeout_uninterruptible(2 * HZ);
+               WARN_ON_ONCE(READ_ONCE(wdtest_ktime_read_ndelays));
+               WARN_ON_ONCE((i <= max_cswd_read_retries) !=
+                            !(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
+               wdtest_ktime_clocksource_reset();
+       }
+
+       /* Verify tsc-like stability with clock-value-fuzz error injection. */
+       pr_info("--- Watchdog clock-value-fuzz error injection, expect clock skew and per-CPU mismatches.\n");
+       WRITE_ONCE(wdtest_ktime_read_fuzz, true);
+       schedule_timeout_uninterruptible(2 * HZ);
+       WARN_ON_ONCE(!(clocksource_wdtest_ktime.flags & CLOCK_SOURCE_UNSTABLE));
+       clocksource_verify_percpu(&clocksource_wdtest_ktime);
+       WRITE_ONCE(wdtest_ktime_read_fuzz, false);
+
+       clocksource_unregister(&clocksource_wdtest_ktime);
+
+       pr_info("--- Done with test.\n");
+       return 0;
+}
+
+static void wdtest_print_module_parms(void)
+{
+       pr_alert("--- holdoff=%d\n", holdoff);
+}
+
+/* Cleanup function. */
+static void clocksource_wdtest_cleanup(void)
+{
+}
+
+static int __init clocksource_wdtest_init(void)
+{
+       int ret = 0;
+
+       wdtest_print_module_parms();
+
+       /* Create watchdog-test task. */
+       wdtest_task = kthread_run(wdtest_func, NULL, "wdtest");
+       if (IS_ERR(wdtest_task)) {
+               ret = PTR_ERR(wdtest_task);
+               pr_warn("%s: Failed to create wdtest kthread.\n", __func__);
+               wdtest_task = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+
+module_init(clocksource_wdtest_init);
+module_exit(clocksource_wdtest_cleanup);
index 2cd9025..b89c76e 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
 #include <linux/tick.h>
 #include <linux/kthread.h>
+#include <linux/prandom.h>
+#include <linux/cpu.h>
 
 #include "tick-internal.h"
 #include "timekeeping_internal.h"
@@ -93,6 +95,20 @@ static char override_name[CS_NAME_LEN];
 static int finished_booting;
 static u64 suspend_start;
 
+/*
+ * Threshold: 0.0312s, when doubled: 0.0625s.
+ * Also a default for cs->uncertainty_margin when registering clocks.
+ */
+#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 5)
+
+/*
+ * Maximum permissible delay between two readouts of the watchdog
+ * clocksource surrounding a read of the clocksource being validated.
+ * This delay could be due to SMIs, NMIs, or to VCPU preemptions.  Used as
+ * a lower bound for cs->uncertainty_margin values when registering clocks.
+ */
+#define WATCHDOG_MAX_SKEW (50 * NSEC_PER_USEC)
+
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
 static void clocksource_watchdog_work(struct work_struct *work);
 static void clocksource_select(void);
@@ -119,10 +135,9 @@ static int clocksource_watchdog_kthread(void *data);
 static void __clocksource_change_rating(struct clocksource *cs, int rating);
 
 /*
- * Interval: 0.5sec Threshold: 0.0625s
+ * Interval: 0.5sec.
  */
 #define WATCHDOG_INTERVAL (HZ >> 1)
-#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)
 
 static void clocksource_watchdog_work(struct work_struct *work)
 {
@@ -184,12 +199,164 @@ void clocksource_mark_unstable(struct clocksource *cs)
        spin_unlock_irqrestore(&watchdog_lock, flags);
 }
 
+ulong max_cswd_read_retries = 3;
+module_param(max_cswd_read_retries, ulong, 0644);
+EXPORT_SYMBOL_GPL(max_cswd_read_retries);
+static int verify_n_cpus = 8;
+module_param(verify_n_cpus, int, 0644);
+
+static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow)
+{
+       unsigned int nretries;
+       u64 wd_end, wd_delta;
+       int64_t wd_delay;
+
+       for (nretries = 0; nretries <= max_cswd_read_retries; nretries++) {
+               local_irq_disable();
+               *wdnow = watchdog->read(watchdog);
+               *csnow = cs->read(cs);
+               wd_end = watchdog->read(watchdog);
+               local_irq_enable();
+
+               wd_delta = clocksource_delta(wd_end, *wdnow, watchdog->mask);
+               wd_delay = clocksource_cyc2ns(wd_delta, watchdog->mult,
+                                             watchdog->shift);
+               if (wd_delay <= WATCHDOG_MAX_SKEW) {
+                       if (nretries > 1 || nretries >= max_cswd_read_retries) {
+                               pr_warn("timekeeping watchdog on CPU%d: %s retried %d times before success\n",
+                                       smp_processor_id(), watchdog->name, nretries);
+                       }
+                       return true;
+               }
+       }
+
+       pr_warn("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n",
+               smp_processor_id(), watchdog->name, wd_delay, nretries);
+       return false;
+}
+
+static u64 csnow_mid;
+static cpumask_t cpus_ahead;
+static cpumask_t cpus_behind;
+static cpumask_t cpus_chosen;
+
+static void clocksource_verify_choose_cpus(void)
+{
+       int cpu, i, n = verify_n_cpus;
+
+       if (n < 0) {
+               /* Check all of the CPUs. */
+               cpumask_copy(&cpus_chosen, cpu_online_mask);
+               cpumask_clear_cpu(smp_processor_id(), &cpus_chosen);
+               return;
+       }
+
+       /* If no checking desired, or no other CPU to check, leave. */
+       cpumask_clear(&cpus_chosen);
+       if (n == 0 || num_online_cpus() <= 1)
+               return;
+
+       /* Make sure to select at least one CPU other than the current CPU. */
+       cpu = cpumask_next(-1, cpu_online_mask);
+       if (cpu == smp_processor_id())
+               cpu = cpumask_next(cpu, cpu_online_mask);
+       if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
+               return;
+       cpumask_set_cpu(cpu, &cpus_chosen);
+
+       /* Force a sane value for the boot parameter. */
+       if (n > nr_cpu_ids)
+               n = nr_cpu_ids;
+
+       /*
+        * Randomly select the specified number of CPUs.  If the same
+        * CPU is selected multiple times, that CPU is checked only once,
+        * and no replacement CPU is selected.  This gracefully handles
+        * situations where verify_n_cpus is greater than the number of
+        * CPUs that are currently online.
+        */
+       for (i = 1; i < n; i++) {
+               cpu = prandom_u32() % nr_cpu_ids;
+               cpu = cpumask_next(cpu - 1, cpu_online_mask);
+               if (cpu >= nr_cpu_ids)
+                       cpu = cpumask_next(-1, cpu_online_mask);
+               if (!WARN_ON_ONCE(cpu >= nr_cpu_ids))
+                       cpumask_set_cpu(cpu, &cpus_chosen);
+       }
+
+       /* Don't verify ourselves. */
+       cpumask_clear_cpu(smp_processor_id(), &cpus_chosen);
+}
+
+static void clocksource_verify_one_cpu(void *csin)
+{
+       struct clocksource *cs = (struct clocksource *)csin;
+
+       csnow_mid = cs->read(cs);
+}
+
+void clocksource_verify_percpu(struct clocksource *cs)
+{
+       int64_t cs_nsec, cs_nsec_max = 0, cs_nsec_min = LLONG_MAX;
+       u64 csnow_begin, csnow_end;
+       int cpu, testcpu;
+       s64 delta;
+
+       if (verify_n_cpus == 0)
+               return;
+       cpumask_clear(&cpus_ahead);
+       cpumask_clear(&cpus_behind);
+       get_online_cpus();
+       preempt_disable();
+       clocksource_verify_choose_cpus();
+       if (cpumask_weight(&cpus_chosen) == 0) {
+               preempt_enable();
+               put_online_cpus();
+               pr_warn("Not enough CPUs to check clocksource '%s'.\n", cs->name);
+               return;
+       }
+       testcpu = smp_processor_id();
+       pr_warn("Checking clocksource %s synchronization from CPU %d to CPUs %*pbl.\n", cs->name, testcpu, cpumask_pr_args(&cpus_chosen));
+       for_each_cpu(cpu, &cpus_chosen) {
+               if (cpu == testcpu)
+                       continue;
+               csnow_begin = cs->read(cs);
+               smp_call_function_single(cpu, clocksource_verify_one_cpu, cs, 1);
+               csnow_end = cs->read(cs);
+               delta = (s64)((csnow_mid - csnow_begin) & cs->mask);
+               if (delta < 0)
+                       cpumask_set_cpu(cpu, &cpus_behind);
+               delta = (csnow_end - csnow_mid) & cs->mask;
+               if (delta < 0)
+                       cpumask_set_cpu(cpu, &cpus_ahead);
+               delta = clocksource_delta(csnow_end, csnow_begin, cs->mask);
+               cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);
+               if (cs_nsec > cs_nsec_max)
+                       cs_nsec_max = cs_nsec;
+               if (cs_nsec < cs_nsec_min)
+                       cs_nsec_min = cs_nsec;
+       }
+       preempt_enable();
+       put_online_cpus();
+       if (!cpumask_empty(&cpus_ahead))
+               pr_warn("        CPUs %*pbl ahead of CPU %d for clocksource %s.\n",
+                       cpumask_pr_args(&cpus_ahead), testcpu, cs->name);
+       if (!cpumask_empty(&cpus_behind))
+               pr_warn("        CPUs %*pbl behind CPU %d for clocksource %s.\n",
+                       cpumask_pr_args(&cpus_behind), testcpu, cs->name);
+       if (!cpumask_empty(&cpus_ahead) || !cpumask_empty(&cpus_behind))
+               pr_warn("        CPU %d check durations %lldns - %lldns for clocksource %s.\n",
+                       testcpu, cs_nsec_min, cs_nsec_max, cs->name);
+}
+EXPORT_SYMBOL_GPL(clocksource_verify_percpu);
+
 static void clocksource_watchdog(struct timer_list *unused)
 {
-       struct clocksource *cs;
        u64 csnow, wdnow, cslast, wdlast, delta;
-       int64_t wd_nsec, cs_nsec;
        int next_cpu, reset_pending;
+       int64_t wd_nsec, cs_nsec;
+       struct clocksource *cs;
+       u32 md;
 
        spin_lock(&watchdog_lock);
        if (!watchdog_running)
@@ -206,10 +373,11 @@ static void clocksource_watchdog(struct timer_list *unused)
                        continue;
                }
 
-               local_irq_disable();
-               csnow = cs->read(cs);
-               wdnow = watchdog->read(watchdog);
-               local_irq_enable();
+               if (!cs_watchdog_read(cs, &csnow, &wdnow)) {
+                       /* Clock readout unreliable, so give it up. */
+                       __clocksource_unstable(cs);
+                       continue;
+               }
 
                /* Clocksource initialized ? */
                if (!(cs->flags & CLOCK_SOURCE_WATCHDOG) ||
@@ -235,13 +403,20 @@ static void clocksource_watchdog(struct timer_list *unused)
                        continue;
 
                /* Check the deviation from the watchdog clocksource. */
-               if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
+               md = cs->uncertainty_margin + watchdog->uncertainty_margin;
+               if (abs(cs_nsec - wd_nsec) > md) {
                        pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",
                                smp_processor_id(), cs->name);
-                       pr_warn("                      '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
-                               watchdog->name, wdnow, wdlast, watchdog->mask);
-                       pr_warn("                      '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
-                               cs->name, csnow, cslast, cs->mask);
+                       pr_warn("                      '%s' wd_nsec: %lld wd_now: %llx wd_last: %llx mask: %llx\n",
+                               watchdog->name, wd_nsec, wdnow, wdlast, watchdog->mask);
+                       pr_warn("                      '%s' cs_nsec: %lld cs_now: %llx cs_last: %llx mask: %llx\n",
+                               cs->name, cs_nsec, csnow, cslast, cs->mask);
+                       if (curr_clocksource == cs)
+                               pr_warn("                      '%s' is current clocksource.\n", cs->name);
+                       else if (curr_clocksource)
+                               pr_warn("                      '%s' (not '%s') is current clocksource.\n", curr_clocksource->name, cs->name);
+                       else
+                               pr_warn("                      No current clocksource.\n");
                        __clocksource_unstable(cs);
                        continue;
                }
@@ -407,6 +582,12 @@ static int __clocksource_watchdog_kthread(void)
        unsigned long flags;
        int select = 0;
 
+       /* Do any required per-CPU skew verification. */
+       if (curr_clocksource &&
+           curr_clocksource->flags & CLOCK_SOURCE_UNSTABLE &&
+           curr_clocksource->flags & CLOCK_SOURCE_VERIFY_PERCPU)
+               clocksource_verify_percpu(curr_clocksource);
+
        spin_lock_irqsave(&watchdog_lock, flags);
        list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
                if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
@@ -876,6 +1057,26 @@ void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq
                clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
                                       NSEC_PER_SEC / scale, sec * scale);
        }
+
+       /*
+        * If the uncertainty margin is not specified, calculate it.
+        * If both scale and freq are non-zero, calculate the clock
+        * period, but bound below at 2*WATCHDOG_MAX_SKEW.  However,
+        * if either of scale or freq is zero, be very conservative and
+        * take the tens-of-milliseconds WATCHDOG_THRESHOLD value for the
+        * uncertainty margin.  Allow stupidly small uncertainty margins
+        * to be specified by the caller for testing purposes, but warn
+        * to discourage production use of this capability.
+        */
+       if (scale && freq && !cs->uncertainty_margin) {
+               cs->uncertainty_margin = NSEC_PER_SEC / (scale * freq);
+               if (cs->uncertainty_margin < 2 * WATCHDOG_MAX_SKEW)
+                       cs->uncertainty_margin = 2 * WATCHDOG_MAX_SKEW;
+       } else if (!cs->uncertainty_margin) {
+               cs->uncertainty_margin = WATCHDOG_THRESHOLD;
+       }
+       WARN_ON_ONCE(cs->uncertainty_margin < 2 * WATCHDOG_MAX_SKEW);
+
        /*
         * Ensure clocksources that have large 'mult' values don't overflow
         * when adjusted.
index a492e4d..01935aa 100644 (file)
@@ -49,13 +49,14 @@ static u64 jiffies_read(struct clocksource *cs)
  * for "tick-less" systems.
  */
 static struct clocksource clocksource_jiffies = {
-       .name           = "jiffies",
-       .rating         = 1, /* lowest valid rating*/
-       .read           = jiffies_read,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .mult           = TICK_NSEC << JIFFIES_SHIFT, /* details above */
-       .shift          = JIFFIES_SHIFT,
-       .max_cycles     = 10,
+       .name                   = "jiffies",
+       .rating                 = 1, /* lowest valid rating*/
+       .uncertainty_margin     = 32 * NSEC_PER_MSEC,
+       .read                   = jiffies_read,
+       .mask                   = CLOCKSOURCE_MASK(32),
+       .mult                   = TICK_NSEC << JIFFIES_SHIFT, /* details above */
+       .shift                  = JIFFIES_SHIFT,
+       .max_cycles             = 10,
 };
 
 __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(jiffies_lock);
index 3bb96a8..29a5e54 100644 (file)
@@ -523,7 +523,7 @@ static void arm_timer(struct k_itimer *timer, struct task_struct *p)
        if (CPUCLOCK_PERTHREAD(timer->it_clock))
                tick_dep_set_task(p, TICK_DEP_BIT_POSIX_TIMER);
        else
-               tick_dep_set_signal(p->signal, TICK_DEP_BIT_POSIX_TIMER);
+               tick_dep_set_signal(p, TICK_DEP_BIT_POSIX_TIMER);
 }
 
 /*
@@ -1358,7 +1358,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clkid,
        if (*newval < *nextevt)
                *nextevt = *newval;
 
-       tick_dep_set_signal(tsk->signal, TICK_DEP_BIT_POSIX_TIMER);
+       tick_dep_set_signal(tsk, TICK_DEP_BIT_POSIX_TIMER);
 }
 
 static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
index a440552..f7fe6fe 100644 (file)
@@ -33,6 +33,8 @@ static int tick_broadcast_forced;
 static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
 
 #ifdef CONFIG_TICK_ONESHOT
+static DEFINE_PER_CPU(struct clock_event_device *, tick_oneshot_wakeup_device);
+
 static void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
 static void tick_broadcast_clear_oneshot(int cpu);
 static void tick_resume_broadcast_oneshot(struct clock_event_device *bc);
@@ -61,6 +63,13 @@ struct cpumask *tick_get_broadcast_mask(void)
        return tick_broadcast_mask;
 }
 
+static struct clock_event_device *tick_get_oneshot_wakeup_device(int cpu);
+
+const struct clock_event_device *tick_get_wakeup_device(int cpu)
+{
+       return tick_get_oneshot_wakeup_device(cpu);
+}
+
 /*
  * Start the device in periodic mode
  */
@@ -88,13 +97,75 @@ static bool tick_check_broadcast_device(struct clock_event_device *curdev,
        return !curdev || newdev->rating > curdev->rating;
 }
 
+#ifdef CONFIG_TICK_ONESHOT
+static struct clock_event_device *tick_get_oneshot_wakeup_device(int cpu)
+{
+       return per_cpu(tick_oneshot_wakeup_device, cpu);
+}
+
+static void tick_oneshot_wakeup_handler(struct clock_event_device *wd)
+{
+       /*
+        * If we woke up early and the tick was reprogrammed in the
+        * meantime then this may be spurious but harmless.
+        */
+       tick_receive_broadcast();
+}
+
+static bool tick_set_oneshot_wakeup_device(struct clock_event_device *newdev,
+                                          int cpu)
+{
+       struct clock_event_device *curdev = tick_get_oneshot_wakeup_device(cpu);
+
+       if (!newdev)
+               goto set_device;
+
+       if ((newdev->features & CLOCK_EVT_FEAT_DUMMY) ||
+           (newdev->features & CLOCK_EVT_FEAT_C3STOP))
+                return false;
+
+       if (!(newdev->features & CLOCK_EVT_FEAT_PERCPU) ||
+           !(newdev->features & CLOCK_EVT_FEAT_ONESHOT))
+               return false;
+
+       if (!cpumask_equal(newdev->cpumask, cpumask_of(cpu)))
+               return false;
+
+       if (curdev && newdev->rating <= curdev->rating)
+               return false;
+
+       if (!try_module_get(newdev->owner))
+               return false;
+
+       newdev->event_handler = tick_oneshot_wakeup_handler;
+set_device:
+       clockevents_exchange_device(curdev, newdev);
+       per_cpu(tick_oneshot_wakeup_device, cpu) = newdev;
+       return true;
+}
+#else
+static struct clock_event_device *tick_get_oneshot_wakeup_device(int cpu)
+{
+       return NULL;
+}
+
+static bool tick_set_oneshot_wakeup_device(struct clock_event_device *newdev,
+                                          int cpu)
+{
+       return false;
+}
+#endif
+
 /*
  * Conditionally install/replace broadcast device
  */
-void tick_install_broadcast_device(struct clock_event_device *dev)
+void tick_install_broadcast_device(struct clock_event_device *dev, int cpu)
 {
        struct clock_event_device *cur = tick_broadcast_device.evtdev;
 
+       if (tick_set_oneshot_wakeup_device(dev, cpu))
+               return;
+
        if (!tick_check_broadcast_device(cur, dev))
                return;
 
@@ -253,7 +324,6 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
        return ret;
 }
 
-#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 int tick_receive_broadcast(void)
 {
        struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
@@ -268,7 +338,6 @@ int tick_receive_broadcast(void)
        evt->event_handler(evt);
        return 0;
 }
-#endif
 
 /*
  * Broadcast the event to the cpus, which are set in the mask (mangled).
@@ -719,24 +788,16 @@ static void broadcast_shutdown_local(struct clock_event_device *bc,
        clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
 }
 
-int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+static int ___tick_broadcast_oneshot_control(enum tick_broadcast_state state,
+                                            struct tick_device *td,
+                                            int cpu)
 {
-       struct clock_event_device *bc, *dev;
-       int cpu, ret = 0;
+       struct clock_event_device *bc, *dev = td->evtdev;
+       int ret = 0;
        ktime_t now;
 
-       /*
-        * If there is no broadcast device, tell the caller not to go
-        * into deep idle.
-        */
-       if (!tick_broadcast_device.evtdev)
-               return -EBUSY;
-
-       dev = this_cpu_ptr(&tick_cpu_device)->evtdev;
-
        raw_spin_lock(&tick_broadcast_lock);
        bc = tick_broadcast_device.evtdev;
-       cpu = smp_processor_id();
 
        if (state == TICK_BROADCAST_ENTER) {
                /*
@@ -865,6 +926,53 @@ out:
        return ret;
 }
 
+static int tick_oneshot_wakeup_control(enum tick_broadcast_state state,
+                                      struct tick_device *td,
+                                      int cpu)
+{
+       struct clock_event_device *dev, *wd;
+
+       dev = td->evtdev;
+       if (td->mode != TICKDEV_MODE_ONESHOT)
+               return -EINVAL;
+
+       wd = tick_get_oneshot_wakeup_device(cpu);
+       if (!wd)
+               return -ENODEV;
+
+       switch (state) {
+       case TICK_BROADCAST_ENTER:
+               clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT_STOPPED);
+               clockevents_switch_state(wd, CLOCK_EVT_STATE_ONESHOT);
+               clockevents_program_event(wd, dev->next_event, 1);
+               break;
+       case TICK_BROADCAST_EXIT:
+               /* We may have transitioned to oneshot mode while idle */
+               if (clockevent_get_state(wd) != CLOCK_EVT_STATE_ONESHOT)
+                       return -ENODEV;
+       }
+
+       return 0;
+}
+
+int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+{
+       struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
+       int cpu = smp_processor_id();
+
+       if (!tick_oneshot_wakeup_control(state, td, cpu))
+               return 0;
+
+       if (tick_broadcast_device.evtdev)
+               return ___tick_broadcast_oneshot_control(state, td, cpu);
+
+       /*
+        * If there is no broadcast or wakeup device, tell the caller not
+        * to go into deep idle.
+        */
+       return -EBUSY;
+}
+
 /*
  * Reset the one shot broadcast for a cpu
  *
@@ -991,6 +1099,9 @@ void hotplug_cpu__broadcast_tick_pull(int deadcpu)
  */
 static void tick_broadcast_oneshot_offline(unsigned int cpu)
 {
+       if (tick_get_oneshot_wakeup_device(cpu))
+               tick_set_oneshot_wakeup_device(NULL, cpu);
+
        /*
         * Clear the broadcast masks for the dead cpu, but do not stop
         * the broadcast device!
index e15bc0e..d663249 100644 (file)
@@ -373,7 +373,7 @@ out_bc:
        /*
         * Can the new device be used as a broadcast device ?
         */
-       tick_install_broadcast_device(newdev);
+       tick_install_broadcast_device(newdev, cpu);
 }
 
 /**
index 7a981c9..6a742a2 100644 (file)
@@ -61,7 +61,7 @@ extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt);
 /* Broadcasting support */
 # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu);
-extern void tick_install_broadcast_device(struct clock_event_device *dev);
+extern void tick_install_broadcast_device(struct clock_event_device *dev, int cpu);
 extern int tick_is_broadcast_device(struct clock_event_device *dev);
 extern void tick_suspend_broadcast(void);
 extern void tick_resume_broadcast(void);
@@ -71,8 +71,9 @@ extern void tick_set_periodic_handler(struct clock_event_device *dev, int broadc
 extern int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
 extern struct tick_device *tick_get_broadcast_device(void);
 extern struct cpumask *tick_get_broadcast_mask(void);
+extern const struct clock_event_device *tick_get_wakeup_device(int cpu);
 # else /* !CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: */
-static inline void tick_install_broadcast_device(struct clock_event_device *dev) { }
+static inline void tick_install_broadcast_device(struct clock_event_device *dev, int cpu) { }
 static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; }
 static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; }
 static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
index 6784f27..6bffe5a 100644 (file)
@@ -323,6 +323,46 @@ void tick_nohz_full_kick_cpu(int cpu)
        irq_work_queue_on(&per_cpu(nohz_full_kick_work, cpu), cpu);
 }
 
+static void tick_nohz_kick_task(struct task_struct *tsk)
+{
+       int cpu;
+
+       /*
+        * If the task is not running, run_posix_cpu_timers()
+        * has nothing to elapse, IPI can then be spared.
+        *
+        * activate_task()                      STORE p->tick_dep_mask
+        *   STORE p->on_rq
+        * __schedule() (switch to task 'p')    smp_mb() (atomic_fetch_or())
+        *   LOCK rq->lock                      LOAD p->on_rq
+        *   smp_mb__after_spin_lock()
+        *   tick_nohz_task_switch()
+        *     LOAD p->tick_dep_mask
+        */
+       if (!sched_task_on_rq(tsk))
+               return;
+
+       /*
+        * If the task concurrently migrates to another CPU,
+        * we guarantee it sees the new tick dependency upon
+        * schedule.
+        *
+        * set_task_cpu(p, cpu);
+        *   STORE p->cpu = @cpu
+        * __schedule() (switch to task 'p')
+        *   LOCK rq->lock
+        *   smp_mb__after_spin_lock()          STORE p->tick_dep_mask
+        *   tick_nohz_task_switch()            smp_mb() (atomic_fetch_or())
+        *      LOAD p->tick_dep_mask           LOAD p->cpu
+        */
+       cpu = task_cpu(tsk);
+
+       preempt_disable();
+       if (cpu_online(cpu))
+               tick_nohz_full_kick_cpu(cpu);
+       preempt_enable();
+}
+
 /*
  * Kick all full dynticks CPUs in order to force these to re-evaluate
  * their dependency on the tick and restart it if necessary.
@@ -405,19 +445,8 @@ EXPORT_SYMBOL_GPL(tick_nohz_dep_clear_cpu);
  */
 void tick_nohz_dep_set_task(struct task_struct *tsk, enum tick_dep_bits bit)
 {
-       if (!atomic_fetch_or(BIT(bit), &tsk->tick_dep_mask)) {
-               if (tsk == current) {
-                       preempt_disable();
-                       tick_nohz_full_kick();
-                       preempt_enable();
-               } else {
-                       /*
-                        * Some future tick_nohz_full_kick_task()
-                        * should optimize this.
-                        */
-                       tick_nohz_full_kick_all();
-               }
-       }
+       if (!atomic_fetch_or(BIT(bit), &tsk->tick_dep_mask))
+               tick_nohz_kick_task(tsk);
 }
 EXPORT_SYMBOL_GPL(tick_nohz_dep_set_task);
 
@@ -431,9 +460,20 @@ EXPORT_SYMBOL_GPL(tick_nohz_dep_clear_task);
  * Set a per-taskgroup tick dependency. Posix CPU timers need this in order to elapse
  * per process timers.
  */
-void tick_nohz_dep_set_signal(struct signal_struct *sig, enum tick_dep_bits bit)
+void tick_nohz_dep_set_signal(struct task_struct *tsk,
+                             enum tick_dep_bits bit)
 {
-       tick_nohz_dep_set_all(&sig->tick_dep_mask, bit);
+       int prev;
+       struct signal_struct *sig = tsk->signal;
+
+       prev = atomic_fetch_or(BIT(bit), &sig->tick_dep_mask);
+       if (!prev) {
+               struct task_struct *t;
+
+               lockdep_assert_held(&tsk->sighand->siglock);
+               __for_each_thread(sig, t)
+                       tick_nohz_kick_task(t);
+       }
 }
 
 void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit)
@@ -448,13 +488,10 @@ void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bi
  */
 void __tick_nohz_task_switch(void)
 {
-       unsigned long flags;
        struct tick_sched *ts;
 
-       local_irq_save(flags);
-
        if (!tick_nohz_full_cpu(smp_processor_id()))
-               goto out;
+               return;
 
        ts = this_cpu_ptr(&tick_cpu_sched);
 
@@ -463,8 +500,6 @@ void __tick_nohz_task_switch(void)
                    atomic_read(&current->signal->tick_dep_mask))
                        tick_nohz_full_kick();
        }
-out:
-       local_irq_restore(flags);
 }
 
 /* Get the boot-time nohz CPU list from the kernel parameters. */
@@ -922,27 +957,31 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
         * Cancel the scheduled timer and restore the tick
         */
        ts->tick_stopped  = 0;
-       ts->idle_exittime = now;
-
        tick_nohz_restart(ts, now);
 }
 
-static void tick_nohz_full_update_tick(struct tick_sched *ts)
+static void __tick_nohz_full_update_tick(struct tick_sched *ts,
+                                        ktime_t now)
 {
 #ifdef CONFIG_NO_HZ_FULL
        int cpu = smp_processor_id();
 
-       if (!tick_nohz_full_cpu(cpu))
+       if (can_stop_full_tick(cpu, ts))
+               tick_nohz_stop_sched_tick(ts, cpu);
+       else if (ts->tick_stopped)
+               tick_nohz_restart_sched_tick(ts, now);
+#endif
+}
+
+static void tick_nohz_full_update_tick(struct tick_sched *ts)
+{
+       if (!tick_nohz_full_cpu(smp_processor_id()))
                return;
 
        if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE)
                return;
 
-       if (can_stop_full_tick(cpu, ts))
-               tick_nohz_stop_sched_tick(ts, cpu);
-       else if (ts->tick_stopped)
-               tick_nohz_restart_sched_tick(ts, ktime_get());
-#endif
+       __tick_nohz_full_update_tick(ts, ktime_get());
 }
 
 static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
@@ -1189,11 +1228,13 @@ unsigned long tick_nohz_get_idle_calls(void)
        return ts->idle_calls;
 }
 
-static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
+static void tick_nohz_account_idle_time(struct tick_sched *ts,
+                                       ktime_t now)
 {
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        unsigned long ticks;
 
+       ts->idle_exittime = now;
+
        if (vtime_accounting_enabled_this_cpu())
                return;
        /*
@@ -1207,21 +1248,27 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
         */
        if (ticks && ticks < LONG_MAX)
                account_idle_ticks(ticks);
-#endif
 }
 
-static void __tick_nohz_idle_restart_tick(struct tick_sched *ts, ktime_t now)
+void tick_nohz_idle_restart_tick(void)
 {
-       tick_nohz_restart_sched_tick(ts, now);
-       tick_nohz_account_idle_ticks(ts);
+       struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
+
+       if (ts->tick_stopped) {
+               ktime_t now = ktime_get();
+               tick_nohz_restart_sched_tick(ts, now);
+               tick_nohz_account_idle_time(ts, now);
+       }
 }
 
-void tick_nohz_idle_restart_tick(void)
+static void tick_nohz_idle_update_tick(struct tick_sched *ts, ktime_t now)
 {
-       struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
+       if (tick_nohz_full_cpu(smp_processor_id()))
+               __tick_nohz_full_update_tick(ts, now);
+       else
+               tick_nohz_restart_sched_tick(ts, now);
 
-       if (ts->tick_stopped)
-               __tick_nohz_idle_restart_tick(ts, ktime_get());
+       tick_nohz_account_idle_time(ts, now);
 }
 
 /**
@@ -1253,7 +1300,7 @@ void tick_nohz_idle_exit(void)
                tick_nohz_stop_idle(ts, now);
 
        if (tick_stopped)
-               __tick_nohz_idle_restart_tick(ts, now);
+               tick_nohz_idle_update_tick(ts, now);
 
        local_irq_enable();
 }
diff --git a/kernel/time/time_test.c b/kernel/time/time_test.c
new file mode 100644 (file)
index 0000000..831e8e7
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#include <kunit/test.h>
+#include <linux/time.h>
+
+/*
+ * Traditional implementation of leap year evaluation.
+ */
+static bool is_leap(long year)
+{
+       return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+}
+
+/*
+ * Gets the last day of a month.
+ */
+static int last_day_of_month(long year, int month)
+{
+       if (month == 2)
+               return 28 + is_leap(year);
+       if (month == 4 || month == 6 || month == 9 || month == 11)
+               return 30;
+       return 31;
+}
+
+/*
+ * Advances a date by one day.
+ */
+static void advance_date(long *year, int *month, int *mday, int *yday)
+{
+       if (*mday != last_day_of_month(*year, *month)) {
+               ++*mday;
+               ++*yday;
+               return;
+       }
+
+       *mday = 1;
+       if (*month != 12) {
+               ++*month;
+               ++*yday;
+               return;
+       }
+
+       *month = 1;
+       *yday  = 0;
+       ++*year;
+}
+
+/*
+ * Checks every day in a 160000 years interval centered at 1970-01-01
+ * against the expected result.
+ */
+static void time64_to_tm_test_date_range(struct kunit *test)
+{
+       /*
+        * 80000 years  = (80000 / 400) * 400 years
+        *              = (80000 / 400) * 146097 days
+        *              = (80000 / 400) * 146097 * 86400 seconds
+        */
+       time64_t total_secs = ((time64_t) 80000) / 400 * 146097 * 86400;
+       long year = 1970 - 80000;
+       int month = 1;
+       int mdday = 1;
+       int yday = 0;
+
+       struct tm result;
+       time64_t secs;
+       s64 days;
+
+       for (secs = -total_secs; secs <= total_secs; secs += 86400) {
+
+               time64_to_tm(secs, 0, &result);
+
+               days = div_s64(secs, 86400);
+
+               #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %ld", \
+                       year, month, mdday, yday, days
+
+               KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
+               KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG);
+               KUNIT_ASSERT_EQ_MSG(test, mdday, result.tm_mday, FAIL_MSG);
+               KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG);
+
+               advance_date(&year, &month, &mdday, &yday);
+       }
+}
+
+static struct kunit_case time_test_cases[] = {
+       KUNIT_CASE(time64_to_tm_test_date_range),
+       {}
+};
+
+static struct kunit_suite time_test_suite = {
+       .name = "time_test_cases",
+       .test_cases = time_test_cases,
+};
+
+kunit_test_suite(time_test_suite);
+MODULE_LICENSE("GPL");
index 62e3b46..59b922c 100644 (file)
 
 /*
  * Converts the calendar time to broken-down time representation
- * Based on code from glibc-2.6
  *
  * 2009-7-14:
  *   Moved from glibc-2.6 to kernel by Zhaolei<zhaolei@cn.fujitsu.com>
+ * 2021-06-02:
+ *   Reimplemented by Cassio Neri <cassio.neri@gmail.com>
  */
 
 #include <linux/time.h>
 #include <linux/module.h>
-
-/*
- * Nonzero if YEAR is a leap year (every 4 years,
- * except every 100th isn't, and every 400th is).
- */
-static int __isleap(long year)
-{
-       return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
-}
-
-/* do a mathdiv for long type */
-static long math_div(long a, long b)
-{
-       return a / b - (a % b < 0);
-}
-
-/* How many leap years between y1 and y2, y1 must less or equal to y2 */
-static long leaps_between(long y1, long y2)
-{
-       long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100)
-               + math_div(y1 - 1, 400);
-       long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100)
-               + math_div(y2 - 1, 400);
-       return leaps2 - leaps1;
-}
-
-/* How many days come before each month (0-12). */
-static const unsigned short __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}
-};
+#include <linux/kernel.h>
 
 #define SECS_PER_HOUR  (60 * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
@@ -77,9 +46,11 @@ static const unsigned short __mon_yday[2][13] = {
  */
 void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
 {
-       long days, rem, y;
+       u32 u32tmp, day_of_century, year_of_century, day_of_year, month, day;
+       u64 u64tmp, udays, century, year;
+       bool is_Jan_or_Feb, is_leap_year;
+       long days, rem;
        int remainder;
-       const unsigned short *ip;
 
        days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder);
        rem = remainder;
@@ -103,27 +74,68 @@ void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
        if (result->tm_wday < 0)
                result->tm_wday += 7;
 
-       y = 1970;
-
-       while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
-               /* Guess a corrected year, assuming 365 days per year. */
-               long yg = y + math_div(days, 365);
-
-               /* Adjust DAYS and Y to match the guessed year. */
-               days -= (yg - y) * 365 + leaps_between(y, yg);
-               y = yg;
-       }
-
-       result->tm_year = y - 1900;
-
-       result->tm_yday = days;
-
-       ip = __mon_yday[__isleap(y)];
-       for (y = 11; days < ip[y]; y--)
-               continue;
-       days -= ip[y];
-
-       result->tm_mon = y;
-       result->tm_mday = days + 1;
+       /*
+        * The following algorithm is, basically, Proposition 6.3 of Neri
+        * and Schneider [1]. In a few words: it works on the computational
+        * (fictitious) calendar where the year starts in March, month = 2
+        * (*), and finishes in February, month = 13. This calendar is
+        * mathematically convenient because the day of the year does not
+        * depend on whether the year is leap or not. For instance:
+        *
+        * March 1st            0-th day of the year;
+        * ...
+        * April 1st            31-st day of the year;
+        * ...
+        * January 1st          306-th day of the year; (Important!)
+        * ...
+        * February 28th        364-th day of the year;
+        * February 29th        365-th day of the year (if it exists).
+        *
+        * After having worked out the date in the computational calendar
+        * (using just arithmetics) it's easy to convert it to the
+        * corresponding date in the Gregorian calendar.
+        *
+        * [1] "Euclidean Affine Functions and Applications to Calendar
+        * Algorithms". https://arxiv.org/abs/2102.06959
+        *
+        * (*) The numbering of months follows tm more closely and thus,
+        * is slightly different from [1].
+        */
+
+       udays   = ((u64) days) + 2305843009213814918ULL;
+
+       u64tmp          = 4 * udays + 3;
+       century         = div64_u64_rem(u64tmp, 146097, &u64tmp);
+       day_of_century  = (u32) (u64tmp / 4);
+
+       u32tmp          = 4 * day_of_century + 3;
+       u64tmp          = 2939745ULL * u32tmp;
+       year_of_century = upper_32_bits(u64tmp);
+       day_of_year     = lower_32_bits(u64tmp) / 2939745 / 4;
+
+       year            = 100 * century + year_of_century;
+       is_leap_year    = year_of_century ? !(year_of_century % 4) : !(century % 4);
+
+       u32tmp          = 2141 * day_of_year + 132377;
+       month           = u32tmp >> 16;
+       day             = ((u16) u32tmp) / 2141;
+
+       /*
+        * Recall that January 1st is the 306-th day of the year in the
+        * computational (not Gregorian) calendar.
+        */
+       is_Jan_or_Feb   = day_of_year >= 306;
+
+       /* Convert to the Gregorian calendar and adjust to Unix time. */
+       year            = year + is_Jan_or_Feb - 6313183731940000ULL;
+       month           = is_Jan_or_Feb ? month - 12 : month;
+       day             = day + 1;
+       day_of_year     += is_Jan_or_Feb ? -306 : 31 + 28 + is_leap_year;
+
+       /* Convert to tm's format. */
+       result->tm_year = (long) (year - 1900);
+       result->tm_mon  = (int) month;
+       result->tm_mday = (int) day;
+       result->tm_yday = (int) day_of_year;
 }
 EXPORT_SYMBOL(time64_to_tm);
index d111adf..467087d 100644 (file)
@@ -1879,7 +1879,7 @@ signed long __sched schedule_timeout(signed long timeout)
                        printk(KERN_ERR "schedule_timeout: wrong timeout "
                                "value %lx\n", timeout);
                        dump_stack();
-                       current->state = TASK_RUNNING;
+                       __set_current_state(TASK_RUNNING);
                        goto out;
                }
        }
index 6939140..ed7d6ad 100644 (file)
@@ -228,6 +228,14 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
        SEQ_printf(m, " event_handler:  %ps\n", dev->event_handler);
        SEQ_printf(m, "\n");
        SEQ_printf(m, " retries:        %lu\n", dev->retries);
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+       if (cpu >= 0) {
+               const struct clock_event_device *wd = tick_get_wakeup_device(cpu);
+
+               SEQ_printf(m, "Wakeup Device: %s\n", wd ? wd->name : "<NULL>");
+       }
+#endif
        SEQ_printf(m, "\n");
 }
 
@@ -248,7 +256,7 @@ static void timer_list_show_tickdevices_header(struct seq_file *m)
 
 static inline void timer_list_header(struct seq_file *m, u64 now)
 {
-       SEQ_printf(m, "Timer List Version: v0.8\n");
+       SEQ_printf(m, "Timer List Version: v0.9\n");
        SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
        SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
        SEQ_printf(m, "\n");
index 9299057..d23a09d 100644 (file)
@@ -2198,9 +2198,6 @@ struct saved_cmdlines_buffer {
 };
 static struct saved_cmdlines_buffer *savedcmd;
 
-/* temporary disable recording */
-static atomic_t trace_record_taskinfo_disabled __read_mostly;
-
 static inline char *get_saved_cmdlines(int idx)
 {
        return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];
@@ -2486,8 +2483,6 @@ static bool tracing_record_taskinfo_skip(int flags)
 {
        if (unlikely(!(flags & (TRACE_RECORD_CMDLINE | TRACE_RECORD_TGID))))
                return true;
-       if (atomic_read(&trace_record_taskinfo_disabled) || !tracing_is_on())
-               return true;
        if (!__this_cpu_read(trace_taskinfo_save))
                return true;
        return false;
@@ -3998,9 +3993,6 @@ static void *s_start(struct seq_file *m, loff_t *pos)
                return ERR_PTR(-EBUSY);
 #endif
 
-       if (!iter->snapshot)
-               atomic_inc(&trace_record_taskinfo_disabled);
-
        if (*pos != iter->pos) {
                iter->ent = NULL;
                iter->cpu = 0;
@@ -4043,9 +4035,6 @@ static void s_stop(struct seq_file *m, void *p)
                return;
 #endif
 
-       if (!iter->snapshot)
-               atomic_dec(&trace_record_taskinfo_disabled);
-
        trace_access_unlock(iter->cpu_file);
        trace_event_read_unlock();
 }
index c1637f9..4702efb 100644 (file)
@@ -115,9 +115,9 @@ u64 notrace trace_clock_global(void)
        prev_time = READ_ONCE(trace_clock_struct.prev_time);
        now = sched_clock_cpu(this_cpu);
 
-       /* Make sure that now is always greater than prev_time */
+       /* Make sure that now is always greater than or equal to prev_time */
        if ((s64)(now - prev_time) < 0)
-               now = prev_time + 1;
+               now = prev_time;
 
        /*
         * If in an NMI context then dont risk lockups and simply return
@@ -131,7 +131,7 @@ u64 notrace trace_clock_global(void)
                /* Reread prev_time in case it was already updated */
                prev_time = READ_ONCE(trace_clock_struct.prev_time);
                if ((s64)(now - prev_time) < 0)
-                       now = prev_time + 1;
+                       now = prev_time;
 
                trace_clock_struct.prev_time = now;
 
index 8d8874f..87799e2 100644 (file)
@@ -8,6 +8,12 @@
 #include <linux/kmemleak.h>
 #include <linux/user_namespace.h>
 
+struct ucounts init_ucounts = {
+       .ns    = &init_user_ns,
+       .uid   = GLOBAL_ROOT_UID,
+       .count = ATOMIC_INIT(1),
+};
+
 #define UCOUNTS_HASHTABLE_BITS 10
 static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
 static DEFINE_SPINLOCK(ucounts_lock);
@@ -78,6 +84,10 @@ static struct ctl_table user_table[] = {
        UCOUNT_ENTRY("max_fanotify_groups"),
        UCOUNT_ENTRY("max_fanotify_marks"),
 #endif
+       { },
+       { },
+       { },
+       { },
        { }
 };
 #endif /* CONFIG_SYSCTL */
@@ -129,7 +139,24 @@ static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struc
        return NULL;
 }
 
-static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
+static void hlist_add_ucounts(struct ucounts *ucounts)
+{
+       struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
+       spin_lock_irq(&ucounts_lock);
+       hlist_add_head(&ucounts->node, hashent);
+       spin_unlock_irq(&ucounts_lock);
+}
+
+struct ucounts *get_ucounts(struct ucounts *ucounts)
+{
+       if (ucounts && atomic_add_negative(1, &ucounts->count)) {
+               put_ucounts(ucounts);
+               ucounts = NULL;
+       }
+       return ucounts;
+}
+
+struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
 {
        struct hlist_head *hashent = ucounts_hashentry(ns, uid);
        struct ucounts *ucounts, *new;
@@ -145,7 +172,7 @@ static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
 
                new->ns = ns;
                new->uid = uid;
-               new->count = 0;
+               atomic_set(&new->count, 1);
 
                spin_lock_irq(&ucounts_lock);
                ucounts = find_ucounts(ns, uid, hashent);
@@ -153,40 +180,35 @@ static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
                        kfree(new);
                } else {
                        hlist_add_head(&new->node, hashent);
-                       ucounts = new;
+                       spin_unlock_irq(&ucounts_lock);
+                       return new;
                }
        }
-       if (ucounts->count == INT_MAX)
-               ucounts = NULL;
-       else
-               ucounts->count += 1;
        spin_unlock_irq(&ucounts_lock);
+       ucounts = get_ucounts(ucounts);
        return ucounts;
 }
 
-static void put_ucounts(struct ucounts *ucounts)
+void put_ucounts(struct ucounts *ucounts)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&ucounts_lock, flags);
-       ucounts->count -= 1;
-       if (!ucounts->count)
+       if (atomic_dec_and_test(&ucounts->count)) {
+               spin_lock_irqsave(&ucounts_lock, flags);
                hlist_del_init(&ucounts->node);
-       else
-               ucounts = NULL;
-       spin_unlock_irqrestore(&ucounts_lock, flags);
-
-       kfree(ucounts);
+               spin_unlock_irqrestore(&ucounts_lock, flags);
+               kfree(ucounts);
+       }
 }
 
-static inline bool atomic_inc_below(atomic_t *v, int u)
+static inline bool atomic_long_inc_below(atomic_long_t *v, int u)
 {
-       int c, old;
-       c = atomic_read(v);
+       long c, old;
+       c = atomic_long_read(v);
        for (;;) {
                if (unlikely(c >= u))
                        return false;
-               old = atomic_cmpxchg(v, c, c+1);
+               old = atomic_long_cmpxchg(v, c, c+1);
                if (likely(old == c))
                        return true;
                c = old;
@@ -198,19 +220,19 @@ struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
 {
        struct ucounts *ucounts, *iter, *bad;
        struct user_namespace *tns;
-       ucounts = get_ucounts(ns, uid);
+       ucounts = alloc_ucounts(ns, uid);
        for (iter = ucounts; iter; iter = tns->ucounts) {
-               int max;
+               long max;
                tns = iter->ns;
                max = READ_ONCE(tns->ucount_max[type]);
-               if (!atomic_inc_below(&iter->ucount[type], max))
+               if (!atomic_long_inc_below(&iter->ucount[type], max))
                        goto fail;
        }
        return ucounts;
 fail:
        bad = iter;
        for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
-               atomic_dec(&iter->ucount[type]);
+               atomic_long_dec(&iter->ucount[type]);
 
        put_ucounts(ucounts);
        return NULL;
@@ -220,12 +242,54 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
 {
        struct ucounts *iter;
        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
-               int dec = atomic_dec_if_positive(&iter->ucount[type]);
+               long dec = atomic_long_dec_if_positive(&iter->ucount[type]);
                WARN_ON_ONCE(dec < 0);
        }
        put_ucounts(ucounts);
 }
 
+long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
+{
+       struct ucounts *iter;
+       long ret = 0;
+
+       for (iter = ucounts; iter; iter = iter->ns->ucounts) {
+               long max = READ_ONCE(iter->ns->ucount_max[type]);
+               long new = atomic_long_add_return(v, &iter->ucount[type]);
+               if (new < 0 || new > max)
+                       ret = LONG_MAX;
+               else if (iter == ucounts)
+                       ret = new;
+       }
+       return ret;
+}
+
+bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v)
+{
+       struct ucounts *iter;
+       long new = -1; /* Silence compiler warning */
+       for (iter = ucounts; iter; iter = iter->ns->ucounts) {
+               long dec = atomic_long_add_return(-v, &iter->ucount[type]);
+               WARN_ON_ONCE(dec < 0);
+               if (iter == ucounts)
+                       new = dec;
+       }
+       return (new == 0);
+}
+
+bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max)
+{
+       struct ucounts *iter;
+       if (get_ucounts_value(ucounts, type) > max)
+               return true;
+       for (iter = ucounts; iter; iter = iter->ns->ucounts) {
+               max = READ_ONCE(iter->ns->ucount_max[type]);
+               if (get_ucounts_value(iter, type) > max)
+                       return true;
+       }
+       return false;
+}
+
 static __init int user_namespace_sysctl_init(void)
 {
 #ifdef CONFIG_SYSCTL
@@ -241,6 +305,8 @@ static __init int user_namespace_sysctl_init(void)
        BUG_ON(!user_header);
        BUG_ON(!setup_userns_sysctls(&init_user_ns));
 #endif
+       hlist_add_ucounts(&init_ucounts);
+       inc_rlimit_ucounts(&init_ucounts, UCOUNT_RLIMIT_NPROC, 1);
        return 0;
 }
 subsys_initcall(user_namespace_sysctl_init);
index a2478cd..c82399c 100644 (file)
@@ -98,9 +98,6 @@ static DEFINE_SPINLOCK(uidhash_lock);
 /* root_user.__count is 1, for init task cred */
 struct user_struct root_user = {
        .__count        = REFCOUNT_INIT(1),
-       .processes      = ATOMIC_INIT(1),
-       .sigpending     = ATOMIC_INIT(0),
-       .locked_shm     = 0,
        .uid            = GLOBAL_ROOT_UID,
        .ratelimit      = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),
 };
index 8d62863..ef82d40 100644 (file)
@@ -119,9 +119,13 @@ int create_user_ns(struct cred *new)
        ns->owner = owner;
        ns->group = group;
        INIT_WORK(&ns->work, free_user_ns);
-       for (i = 0; i < UCOUNT_COUNTS; i++) {
+       for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++) {
                ns->ucount_max[i] = INT_MAX;
        }
+       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC));
+       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
+       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
+       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
        ns->ucounts = ucounts;
 
        /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
@@ -1340,6 +1344,9 @@ static int userns_install(struct nsset *nsset, struct ns_common *ns)
        put_user_ns(cred->user_ns);
        set_cred_user_ns(cred, get_user_ns(user_ns));
 
+       if (set_cred_ucounts(cred) < 0)
+               return -EINVAL;
+
        return 0;
 }
 
index 678c139..b9e223b 100644 (file)
@@ -1372,7 +1372,6 @@ config LOCKDEP
        bool
        depends on DEBUG_KERNEL && LOCK_DEBUGGING_SUPPORT
        select STACKTRACE
-       depends on FRAME_POINTER || MIPS || PPC || S390 || MICROBLAZE || ARM || ARC || X86
        select KALLSYMS
        select KALLSYMS_ALL
 
@@ -2181,6 +2180,9 @@ config TEST_KSTRTOX
 config TEST_PRINTF
        tristate "Test printf() family of functions at runtime"
 
+config TEST_SCANF
+       tristate "Test scanf() family of functions at runtime"
+
 config TEST_BITMAP
        tristate "Test bitmap_*() family of functions at runtime"
        help
@@ -2571,6 +2573,18 @@ config TEST_FPU
 
          If unsure, say N.
 
+config TEST_CLOCKSOURCE_WATCHDOG
+       tristate "Test clocksource watchdog in kernel space"
+       depends on CLOCKSOURCE_WATCHDOG
+       help
+         Enable this option to create a kernel module that will trigger
+         a test of the clocksource watchdog.  This module may be loaded
+         via modprobe or insmod in which case it will run upon being
+         loaded, or it may be built in, in which case it will run
+         shortly after boot.
+
+         If unsure, say N.
+
 endif # RUNTIME_TESTING_MENU
 
 config ARCH_USE_MEMTEST
index 2cc359e..a93f080 100644 (file)
@@ -83,6 +83,7 @@ obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
 obj-$(CONFIG_TEST_PRINTF) += test_printf.o
+obj-$(CONFIG_TEST_SCANF) += test_scanf.o
 obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
 obj-$(CONFIG_TEST_STRSCPY) += test_strscpy.o
 obj-$(CONFIG_TEST_UUID) += test_uuid.o
index e98c85a..3df6539 100644 (file)
@@ -42,7 +42,7 @@ static inline raw_spinlock_t *lock_addr(const atomic64_t *v)
        return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
 }
 
-s64 atomic64_read(const atomic64_t *v)
+s64 generic_atomic64_read(const atomic64_t *v)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -53,9 +53,9 @@ s64 atomic64_read(const atomic64_t *v)
        raw_spin_unlock_irqrestore(lock, flags);
        return val;
 }
-EXPORT_SYMBOL(atomic64_read);
+EXPORT_SYMBOL(generic_atomic64_read);
 
-void atomic64_set(atomic64_t *v, s64 i)
+void generic_atomic64_set(atomic64_t *v, s64 i)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -64,10 +64,10 @@ void atomic64_set(atomic64_t *v, s64 i)
        v->counter = i;
        raw_spin_unlock_irqrestore(lock, flags);
 }
-EXPORT_SYMBOL(atomic64_set);
+EXPORT_SYMBOL(generic_atomic64_set);
 
 #define ATOMIC64_OP(op, c_op)                                          \
-void atomic64_##op(s64 a, atomic64_t *v)                               \
+void generic_atomic64_##op(s64 a, atomic64_t *v)                       \
 {                                                                      \
        unsigned long flags;                                            \
        raw_spinlock_t *lock = lock_addr(v);                            \
@@ -76,10 +76,10 @@ void atomic64_##op(s64 a, atomic64_t *v)                            \
        v->counter c_op a;                                              \
        raw_spin_unlock_irqrestore(lock, flags);                        \
 }                                                                      \
-EXPORT_SYMBOL(atomic64_##op);
+EXPORT_SYMBOL(generic_atomic64_##op);
 
 #define ATOMIC64_OP_RETURN(op, c_op)                                   \
-s64 atomic64_##op##_return(s64 a, atomic64_t *v)                       \
+s64 generic_atomic64_##op##_return(s64 a, atomic64_t *v)               \
 {                                                                      \
        unsigned long flags;                                            \
        raw_spinlock_t *lock = lock_addr(v);                            \
@@ -90,10 +90,10 @@ s64 atomic64_##op##_return(s64 a, atomic64_t *v)                    \
        raw_spin_unlock_irqrestore(lock, flags);                        \
        return val;                                                     \
 }                                                                      \
-EXPORT_SYMBOL(atomic64_##op##_return);
+EXPORT_SYMBOL(generic_atomic64_##op##_return);
 
 #define ATOMIC64_FETCH_OP(op, c_op)                                    \
-s64 atomic64_fetch_##op(s64 a, atomic64_t *v)                          \
+s64 generic_atomic64_fetch_##op(s64 a, atomic64_t *v)                  \
 {                                                                      \
        unsigned long flags;                                            \
        raw_spinlock_t *lock = lock_addr(v);                            \
@@ -105,7 +105,7 @@ s64 atomic64_fetch_##op(s64 a, atomic64_t *v)                               \
        raw_spin_unlock_irqrestore(lock, flags);                        \
        return val;                                                     \
 }                                                                      \
-EXPORT_SYMBOL(atomic64_fetch_##op);
+EXPORT_SYMBOL(generic_atomic64_fetch_##op);
 
 #define ATOMIC64_OPS(op, c_op)                                         \
        ATOMIC64_OP(op, c_op)                                           \
@@ -130,7 +130,7 @@ ATOMIC64_OPS(xor, ^=)
 #undef ATOMIC64_OP_RETURN
 #undef ATOMIC64_OP
 
-s64 atomic64_dec_if_positive(atomic64_t *v)
+s64 generic_atomic64_dec_if_positive(atomic64_t *v)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -143,9 +143,9 @@ s64 atomic64_dec_if_positive(atomic64_t *v)
        raw_spin_unlock_irqrestore(lock, flags);
        return val;
 }
-EXPORT_SYMBOL(atomic64_dec_if_positive);
+EXPORT_SYMBOL(generic_atomic64_dec_if_positive);
 
-s64 atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n)
+s64 generic_atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -158,9 +158,9 @@ s64 atomic64_cmpxchg(atomic64_t *v, s64 o, s64 n)
        raw_spin_unlock_irqrestore(lock, flags);
        return val;
 }
-EXPORT_SYMBOL(atomic64_cmpxchg);
+EXPORT_SYMBOL(generic_atomic64_cmpxchg);
 
-s64 atomic64_xchg(atomic64_t *v, s64 new)
+s64 generic_atomic64_xchg(atomic64_t *v, s64 new)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -172,9 +172,9 @@ s64 atomic64_xchg(atomic64_t *v, s64 new)
        raw_spin_unlock_irqrestore(lock, flags);
        return val;
 }
-EXPORT_SYMBOL(atomic64_xchg);
+EXPORT_SYMBOL(generic_atomic64_xchg);
 
-s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
+s64 generic_atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 {
        unsigned long flags;
        raw_spinlock_t *lock = lock_addr(v);
@@ -188,4 +188,4 @@ s64 atomic64_fetch_add_unless(atomic64_t *v, s64 a, s64 u)
 
        return val;
 }
-EXPORT_SYMBOL(atomic64_fetch_add_unless);
+EXPORT_SYMBOL(generic_atomic64_fetch_add_unless);
index 06d3135..a75ee30 100644 (file)
@@ -36,7 +36,7 @@ EXPORT_SYMBOL_GPL(debug_locks_silent);
 /*
  * Generic 'turn off all lock debugging' function:
  */
-noinstr int debug_locks_off(void)
+int debug_locks_off(void)
 {
        if (debug_locks && __debug_locks_off()) {
                if (!debug_locks_silent) {
index f5a33b6..5ebf437 100644 (file)
@@ -84,50 +84,16 @@ static void __dump_stack(void)
  *
  * Architectures can override this implementation by implementing its own.
  */
-#ifdef CONFIG_SMP
-static atomic_t dump_lock = ATOMIC_INIT(-1);
-
 asmlinkage __visible void dump_stack(void)
 {
        unsigned long flags;
-       int was_locked;
-       int old;
-       int cpu;
 
        /*
         * Permit this cpu to perform nested stack dumps while serialising
         * against other CPUs
         */
-retry:
-       local_irq_save(flags);
-       cpu = smp_processor_id();
-       old = atomic_cmpxchg(&dump_lock, -1, cpu);
-       if (old == -1) {
-               was_locked = 0;
-       } else if (old == cpu) {
-               was_locked = 1;
-       } else {
-               local_irq_restore(flags);
-               /*
-                * Wait for the lock to release before jumping to
-                * atomic_cmpxchg() in order to mitigate the thundering herd
-                * problem.
-                */
-               do { cpu_relax(); } while (atomic_read(&dump_lock) != -1);
-               goto retry;
-       }
-
-       __dump_stack();
-
-       if (!was_locked)
-               atomic_set(&dump_lock, -1);
-
-       local_irq_restore(flags);
-}
-#else
-asmlinkage __visible void dump_stack(void)
-{
+       printk_cpu_lock_irqsave(flags);
        __dump_stack();
+       printk_cpu_unlock_irqrestore(flags);
 }
-#endif
 EXPORT_SYMBOL(dump_stack);
index a118b0b..0b5fe8b 100644 (file)
@@ -39,20 +39,22 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
 
 /*
  * Convert non-negative integer string representation in explicitly given radix
- * to an integer.
+ * to an integer. A maximum of max_chars characters will be converted.
+ *
  * Return number of characters consumed maybe or-ed with overflow bit.
  * If overflow occurs, result integer (incorrect) is still returned.
  *
  * Don't you dare use this function.
  */
-unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)
+unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *p,
+                                 size_t max_chars)
 {
        unsigned long long res;
        unsigned int rv;
 
        res = 0;
        rv = 0;
-       while (1) {
+       while (max_chars--) {
                unsigned int c = *s;
                unsigned int lc = c | 0x20; /* don't tolower() this line */
                unsigned int val;
@@ -82,6 +84,11 @@ unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long
        return rv;
 }
 
+unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)
+{
+       return _parse_integer_limit(s, base, p, INT_MAX);
+}
+
 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
 {
        unsigned long long _res;
index 3b4637b..158c400 100644 (file)
@@ -4,6 +4,8 @@
 
 #define KSTRTOX_OVERFLOW       (1U << 31)
 const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
+unsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *res,
+                                 size_t max_chars);
 unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res);
 
 #endif
index 2d85aba..161108e 100644 (file)
@@ -53,6 +53,7 @@ __setup("debug_locks_verbose=", setup_debug_locks_verbose);
 #define LOCKTYPE_WW    0x10
 #define LOCKTYPE_RTMUTEX 0x20
 #define LOCKTYPE_LL    0x40
+#define LOCKTYPE_SPECIAL 0x80
 
 static struct ww_acquire_ctx t, t2;
 static struct ww_mutex o, o2, o3;
@@ -194,6 +195,7 @@ static void init_shared_classes(void)
 #define HARDIRQ_ENTER()                                \
        local_irq_disable();                    \
        __irq_enter();                          \
+       lockdep_hardirq_threaded();             \
        WARN_ON(!in_irq());
 
 #define HARDIRQ_EXIT()                         \
@@ -2492,16 +2494,6 @@ static void rcu_sched_exit(int *_)
        int rcu_sched_guard_##name __guard(rcu_sched_exit);     \
        rcu_read_lock_sched();
 
-static void rcu_callback_exit(int *_)
-{
-       rcu_lock_release(&rcu_callback_map);
-}
-
-#define RCU_CALLBACK_CONTEXT(name, ...)                                        \
-       int rcu_callback_guard_##name __guard(rcu_callback_exit);       \
-       rcu_lock_acquire(&rcu_callback_map);
-
-
 static void raw_spinlock_exit(raw_spinlock_t **lock)
 {
        raw_spin_unlock(*lock);
@@ -2558,8 +2550,6 @@ static void __maybe_unused inner##_in_##outer(void)                               \
  * ---------------+-------+----------+------+-------
  * RCU_BH         |   o   |    o     |  o   |  x
  * ---------------+-------+----------+------+-------
- * RCU_CALLBACK   |   o   |    o     |  o   |  x
- * ---------------+-------+----------+------+-------
  * RCU_SCHED      |   o   |    o     |  x   |  x
  * ---------------+-------+----------+------+-------
  * RAW_SPIN       |   o   |    o     |  x   |  x
@@ -2576,7 +2566,6 @@ GENERATE_2_CONTEXT_TESTCASE(NOTTHREADED_HARDIRQ, , inner, inner_lock)             \
 GENERATE_2_CONTEXT_TESTCASE(SOFTIRQ, , inner, inner_lock)                      \
 GENERATE_2_CONTEXT_TESTCASE(RCU, , inner, inner_lock)                          \
 GENERATE_2_CONTEXT_TESTCASE(RCU_BH, , inner, inner_lock)                       \
-GENERATE_2_CONTEXT_TESTCASE(RCU_CALLBACK, , inner, inner_lock)                 \
 GENERATE_2_CONTEXT_TESTCASE(RCU_SCHED, , inner, inner_lock)                    \
 GENERATE_2_CONTEXT_TESTCASE(RAW_SPINLOCK, raw_lock_A, inner, inner_lock)       \
 GENERATE_2_CONTEXT_TESTCASE(SPINLOCK, lock_A, inner, inner_lock)               \
@@ -2638,10 +2627,6 @@ static void wait_context_tests(void)
        DO_CONTEXT_TESTCASE_OUTER_LIMITED_PREEMPTIBLE(RCU_BH);
        pr_cont("\n");
 
-       print_testname("in RCU callback context");
-       DO_CONTEXT_TESTCASE_OUTER_LIMITED_PREEMPTIBLE(RCU_CALLBACK);
-       pr_cont("\n");
-
        print_testname("in RCU-sched context");
        DO_CONTEXT_TESTCASE_OUTER_NOT_PREEMPTIBLE(RCU_SCHED);
        pr_cont("\n");
@@ -2744,6 +2729,66 @@ static void local_lock_tests(void)
        pr_cont("\n");
 }
 
+static void hardirq_deadlock_softirq_not_deadlock(void)
+{
+       /* mutex_A is hardirq-unsafe and softirq-unsafe */
+       /* mutex_A -> lock_C */
+       mutex_lock(&mutex_A);
+       HARDIRQ_DISABLE();
+       spin_lock(&lock_C);
+       spin_unlock(&lock_C);
+       HARDIRQ_ENABLE();
+       mutex_unlock(&mutex_A);
+
+       /* lock_A is hardirq-safe */
+       HARDIRQ_ENTER();
+       spin_lock(&lock_A);
+       spin_unlock(&lock_A);
+       HARDIRQ_EXIT();
+
+       /* lock_A -> lock_B */
+       HARDIRQ_DISABLE();
+       spin_lock(&lock_A);
+       spin_lock(&lock_B);
+       spin_unlock(&lock_B);
+       spin_unlock(&lock_A);
+       HARDIRQ_ENABLE();
+
+       /* lock_B -> lock_C */
+       HARDIRQ_DISABLE();
+       spin_lock(&lock_B);
+       spin_lock(&lock_C);
+       spin_unlock(&lock_C);
+       spin_unlock(&lock_B);
+       HARDIRQ_ENABLE();
+
+       /* lock_D is softirq-safe */
+       SOFTIRQ_ENTER();
+       spin_lock(&lock_D);
+       spin_unlock(&lock_D);
+       SOFTIRQ_EXIT();
+
+       /* And lock_D is hardirq-unsafe */
+       SOFTIRQ_DISABLE();
+       spin_lock(&lock_D);
+       spin_unlock(&lock_D);
+       SOFTIRQ_ENABLE();
+
+       /*
+        * mutex_A -> lock_C -> lock_D is softirq-unsafe -> softirq-safe, not
+        * deadlock.
+        *
+        * lock_A -> lock_B -> lock_C -> lock_D is hardirq-safe ->
+        * hardirq-unsafe, deadlock.
+        */
+       HARDIRQ_DISABLE();
+       spin_lock(&lock_C);
+       spin_lock(&lock_D);
+       spin_unlock(&lock_D);
+       spin_unlock(&lock_C);
+       HARDIRQ_ENABLE();
+}
+
 void locking_selftest(void)
 {
        /*
@@ -2872,6 +2917,10 @@ void locking_selftest(void)
 
        local_lock_tests();
 
+       print_testname("hardirq_unsafe_softirq_safe");
+       dotest(hardirq_deadlock_softirq_not_deadlock, FAILURE, LOCKTYPE_SPECIAL);
+       pr_cont("\n");
+
        if (unexpected_testcase_failures) {
                printk("-----------------------------------------------------------------\n");
                debug_locks = 0;
index 1c1dbd3..046ac62 100644 (file)
@@ -19,11 +19,7 @@ unsigned int check_preemption_disabled(const char *what1, const char *what2)
        if (irqs_disabled())
                goto out;
 
-       /*
-        * Kernel threads bound to a single CPU can safely use
-        * smp_processor_id():
-        */
-       if (current->nr_cpus_allowed == 1)
+       if (is_percpu_thread())
                goto out;
 
 #ifdef CONFIG_SMP
index ba13e92..006e256 100644 (file)
@@ -68,13 +68,13 @@ static int collect_syscall(struct task_struct *target, struct syscall_info *info
  */
 int task_current_syscall(struct task_struct *target, struct syscall_info *info)
 {
-       long state;
        unsigned long ncsw;
+       unsigned int state;
 
        if (target == current)
                return collect_syscall(target, info);
 
-       state = target->state;
+       state = READ_ONCE(target->__state);
        if (unlikely(!state))
                return -EAGAIN;
 
index ec0d597..8ac71ae 100644 (file)
@@ -528,6 +528,11 @@ time_and_date(void)
        test("0119-00-04T15:32:23", "%ptTr", &t);
        test("15:32:23|2019-01-04", "%ptTt|%ptTd", &t, &t);
        test("15:32:23|0119-00-04", "%ptTtr|%ptTdr", &t, &t);
+
+       test("2019-01-04 15:32:23", "%ptTs", &t);
+       test("0119-00-04 15:32:23", "%ptTsr", &t);
+       test("15:32:23|2019-01-04", "%ptTts|%ptTds", &t, &t);
+       test("15:32:23|0119-00-04", "%ptTtrs|%ptTdrs", &t, &t);
 }
 
 static void __init
diff --git a/lib/test_scanf.c b/lib/test_scanf.c
new file mode 100644 (file)
index 0000000..48ff574
--- /dev/null
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test cases for sscanf facility.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "../tools/testing/selftests/kselftest_module.h"
+
+#define BUF_SIZE 1024
+
+KSTM_MODULE_GLOBALS();
+static char *test_buffer __initdata;
+static char *fmt_buffer __initdata;
+static struct rnd_state rnd_state __initdata;
+
+typedef int (*check_fn)(const void *check_data, const char *string,
+                       const char *fmt, int n_args, va_list ap);
+
+static void __scanf(4, 6) __init
+_test(check_fn fn, const void *check_data, const char *string, const char *fmt,
+       int n_args, ...)
+{
+       va_list ap, ap_copy;
+       int ret;
+
+       total_tests++;
+
+       va_start(ap, n_args);
+       va_copy(ap_copy, ap);
+       ret = vsscanf(string, fmt, ap_copy);
+       va_end(ap_copy);
+
+       if (ret != n_args) {
+               pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n",
+                       string, fmt, ret, n_args);
+               goto fail;
+       }
+
+       ret = (*fn)(check_data, string, fmt, n_args, ap);
+       if (ret)
+               goto fail;
+
+       va_end(ap);
+
+       return;
+
+fail:
+       failed_tests++;
+       va_end(ap);
+}
+
+#define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap)         \
+do {                                                                           \
+       pr_debug("\"%s\", \"%s\" ->\n", str, fmt);                              \
+       for (; n_args > 0; n_args--, expect++) {                                \
+               typeof(*expect) got = *va_arg(ap, typeof(expect));              \
+               pr_debug("\t" arg_fmt "\n", got);                               \
+               if (got != *expect) {                                           \
+                       pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
+                               str, fmt, *expect, got);                        \
+                       return 1;                                               \
+               }                                                               \
+       }                                                                       \
+       return 0;                                                               \
+} while (0)
+
+static int __init check_ull(const void *check_data, const char *string,
+                           const char *fmt, int n_args, va_list ap)
+{
+       const unsigned long long *pval = check_data;
+
+       _check_numbers_template("%llu", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_ll(const void *check_data, const char *string,
+                          const char *fmt, int n_args, va_list ap)
+{
+       const long long *pval = check_data;
+
+       _check_numbers_template("%lld", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_ulong(const void *check_data, const char *string,
+                          const char *fmt, int n_args, va_list ap)
+{
+       const unsigned long *pval = check_data;
+
+       _check_numbers_template("%lu", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_long(const void *check_data, const char *string,
+                         const char *fmt, int n_args, va_list ap)
+{
+       const long *pval = check_data;
+
+       _check_numbers_template("%ld", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_uint(const void *check_data, const char *string,
+                            const char *fmt, int n_args, va_list ap)
+{
+       const unsigned int *pval = check_data;
+
+       _check_numbers_template("%u", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_int(const void *check_data, const char *string,
+                           const char *fmt, int n_args, va_list ap)
+{
+       const int *pval = check_data;
+
+       _check_numbers_template("%d", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_ushort(const void *check_data, const char *string,
+                              const char *fmt, int n_args, va_list ap)
+{
+       const unsigned short *pval = check_data;
+
+       _check_numbers_template("%hu", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_short(const void *check_data, const char *string,
+                              const char *fmt, int n_args, va_list ap)
+{
+       const short *pval = check_data;
+
+       _check_numbers_template("%hd", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_uchar(const void *check_data, const char *string,
+                              const char *fmt, int n_args, va_list ap)
+{
+       const unsigned char *pval = check_data;
+
+       _check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
+}
+
+static int __init check_char(const void *check_data, const char *string,
+                              const char *fmt, int n_args, va_list ap)
+{
+       const signed char *pval = check_data;
+
+       _check_numbers_template("%hhd", pval, string, fmt, n_args, ap);
+}
+
+/* Selection of interesting numbers to test, copied from test-kstrtox.c */
+static const unsigned long long numbers[] __initconst = {
+       0x0ULL,
+       0x1ULL,
+       0x7fULL,
+       0x80ULL,
+       0x81ULL,
+       0xffULL,
+       0x100ULL,
+       0x101ULL,
+       0x7fffULL,
+       0x8000ULL,
+       0x8001ULL,
+       0xffffULL,
+       0x10000ULL,
+       0x10001ULL,
+       0x7fffffffULL,
+       0x80000000ULL,
+       0x80000001ULL,
+       0xffffffffULL,
+       0x100000000ULL,
+       0x100000001ULL,
+       0x7fffffffffffffffULL,
+       0x8000000000000000ULL,
+       0x8000000000000001ULL,
+       0xfffffffffffffffeULL,
+       0xffffffffffffffffULL,
+};
+
+#define value_representable_in_type(T, val)                                     \
+(is_signed_type(T)                                                              \
+       ? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \
+       : ((unsigned long long)(val) <= type_max(T)))
+
+
+#define test_one_number(T, gen_fmt, scan_fmt, val, fn)                 \
+do {                                                                   \
+       const T expect_val = (T)(val);                                  \
+       T result = ~expect_val; /* should be overwritten */             \
+                                                                       \
+       snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val);           \
+       _test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);  \
+} while (0)
+
+#define simple_numbers_loop(T, gen_fmt, scan_fmt, fn)                  \
+do {                                                                   \
+       int i;                                                          \
+                                                                       \
+       for (i = 0; i < ARRAY_SIZE(numbers); i++) {                     \
+               if (value_representable_in_type(T, numbers[i]))         \
+                       test_one_number(T, gen_fmt, scan_fmt,           \
+                                       numbers[i], fn);                \
+                                                                       \
+               if (value_representable_in_type(T, -numbers[i]))        \
+                       test_one_number(T, gen_fmt, scan_fmt,           \
+                                       -numbers[i], fn);               \
+       }                                                               \
+} while (0)
+
+static void __init numbers_simple(void)
+{
+       simple_numbers_loop(unsigned long long, "%llu",   "llu", check_ull);
+       simple_numbers_loop(long long,          "%lld",   "lld", check_ll);
+       simple_numbers_loop(long long,          "%lld",   "lli", check_ll);
+       simple_numbers_loop(unsigned long long, "%llx",   "llx", check_ull);
+       simple_numbers_loop(long long,          "%llx",   "llx", check_ll);
+       simple_numbers_loop(long long,          "0x%llx", "lli", check_ll);
+       simple_numbers_loop(unsigned long long, "0x%llx", "llx", check_ull);
+       simple_numbers_loop(long long,          "0x%llx", "llx", check_ll);
+
+       simple_numbers_loop(unsigned long,      "%lu",    "lu", check_ulong);
+       simple_numbers_loop(long,               "%ld",    "ld", check_long);
+       simple_numbers_loop(long,               "%ld",    "li", check_long);
+       simple_numbers_loop(unsigned long,      "%lx",    "lx", check_ulong);
+       simple_numbers_loop(long,               "%lx",    "lx", check_long);
+       simple_numbers_loop(long,               "0x%lx",  "li", check_long);
+       simple_numbers_loop(unsigned long,      "0x%lx",  "lx", check_ulong);
+       simple_numbers_loop(long,               "0x%lx",  "lx", check_long);
+
+       simple_numbers_loop(unsigned int,       "%u",     "u", check_uint);
+       simple_numbers_loop(int,                "%d",     "d", check_int);
+       simple_numbers_loop(int,                "%d",     "i", check_int);
+       simple_numbers_loop(unsigned int,       "%x",     "x", check_uint);
+       simple_numbers_loop(int,                "%x",     "x", check_int);
+       simple_numbers_loop(int,                "0x%x",   "i", check_int);
+       simple_numbers_loop(unsigned int,       "0x%x",   "x", check_uint);
+       simple_numbers_loop(int,                "0x%x",   "x", check_int);
+
+       simple_numbers_loop(unsigned short,     "%hu",    "hu", check_ushort);
+       simple_numbers_loop(short,              "%hd",    "hd", check_short);
+       simple_numbers_loop(short,              "%hd",    "hi", check_short);
+       simple_numbers_loop(unsigned short,     "%hx",    "hx", check_ushort);
+       simple_numbers_loop(short,              "%hx",    "hx", check_short);
+       simple_numbers_loop(short,              "0x%hx",  "hi", check_short);
+       simple_numbers_loop(unsigned short,     "0x%hx",  "hx", check_ushort);
+       simple_numbers_loop(short,              "0x%hx",  "hx", check_short);
+
+       simple_numbers_loop(unsigned char,      "%hhu",   "hhu", check_uchar);
+       simple_numbers_loop(signed char,        "%hhd",   "hhd", check_char);
+       simple_numbers_loop(signed char,        "%hhd",   "hhi", check_char);
+       simple_numbers_loop(unsigned char,      "%hhx",   "hhx", check_uchar);
+       simple_numbers_loop(signed char,        "%hhx",   "hhx", check_char);
+       simple_numbers_loop(signed char,        "0x%hhx", "hhi", check_char);
+       simple_numbers_loop(unsigned char,      "0x%hhx", "hhx", check_uchar);
+       simple_numbers_loop(signed char,        "0x%hhx", "hhx", check_char);
+}
+
+/*
+ * This gives a better variety of number "lengths" in a small sample than
+ * the raw prandom*() functions (Not mathematically rigorous!!).
+ * Variabilty of length and value is more important than perfect randomness.
+ */
+static u32 __init next_test_random(u32 max_bits)
+{
+       u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
+
+       return prandom_u32_state(&rnd_state) & (UINT_MAX >> (32 - n_bits));
+}
+
+static unsigned long long __init next_test_random_ull(void)
+{
+       u32 rand1 = prandom_u32_state(&rnd_state);
+       u32 n_bits = (hweight32(rand1) * 3) % 64;
+       u64 val = (u64)prandom_u32_state(&rnd_state) * rand1;
+
+       return val & (ULLONG_MAX >> (64 - n_bits));
+}
+
+#define random_for_type(T)                             \
+       ((T)(sizeof(T) <= sizeof(u32)                   \
+               ? next_test_random(BITS_PER_TYPE(T))    \
+               : next_test_random_ull()))
+
+/*
+ * Define a pattern of negative and positive numbers to ensure we get
+ * some of both within the small number of samples in a test string.
+ */
+#define NEGATIVES_PATTERN 0x3246       /* 00110010 01000110 */
+
+#define fill_random_array(arr)                                                 \
+do {                                                                           \
+       unsigned int neg_pattern = NEGATIVES_PATTERN;                           \
+       int i;                                                                  \
+                                                                               \
+       for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) {              \
+               (arr)[i] = random_for_type(typeof((arr)[0]));                   \
+               if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1))      \
+                       (arr)[i] = -(arr)[i];                                   \
+       }                                                                       \
+} while (0)
+
+/*
+ * Convenience wrapper around snprintf() to append at buf_pos in buf,
+ * updating buf_pos and returning the number of characters appended.
+ * On error buf_pos is not changed and return value is 0.
+ */
+static int __init __printf(4, 5)
+append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
+{
+       va_list ap;
+       int field_len;
+
+       va_start(ap, val_fmt);
+       field_len = vsnprintf(buf + *buf_pos, buf_len - *buf_pos, val_fmt, ap);
+       va_end(ap);
+
+       if (field_len < 0)
+               field_len = 0;
+
+       *buf_pos += field_len;
+
+       return field_len;
+}
+
+/*
+ * Convenience function to append the field delimiter string
+ * to both the value string and format string buffers.
+ */
+static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
+                               char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
+                               const char *delim_str)
+{
+       append_fmt(str_buf, str_buf_pos, str_buf_len, delim_str);
+       append_fmt(fmt_buf, fmt_buf_pos, fmt_buf_len, delim_str);
+}
+
+#define test_array_8(fn, check_data, string, fmt, arr)                         \
+do {                                                                           \
+       BUILD_BUG_ON(ARRAY_SIZE(arr) != 8);                                     \
+       _test(fn, check_data, string, fmt, 8,                                   \
+               &(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3],                     \
+               &(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]);                    \
+} while (0)
+
+#define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn)                    \
+do {                                                                           \
+       int i, pos = 0, fmt_pos = 0;                                            \
+       T expect[8], result[8];                                                 \
+                                                                               \
+       fill_random_array(expect);                                              \
+                                                                               \
+       for (i = 0; i < ARRAY_SIZE(expect); i++) {                              \
+               if (i != 0)                                                     \
+                       append_delim(test_buffer, &pos, BUF_SIZE,               \
+                                    fmt_buffer, &fmt_pos, BUF_SIZE,            \
+                                    field_sep);                                \
+                                                                               \
+               append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]);    \
+               append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt);   \
+       }                                                                       \
+                                                                               \
+       test_array_8(fn, expect, test_buffer, fmt_buffer, result);              \
+} while (0)
+
+#define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn)     \
+do {                                                                           \
+       char full_fmt[16];                                                      \
+                                                                               \
+       snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt);          \
+       numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn);                    \
+} while (0)
+
+#define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn)            \
+do {                                                                           \
+       int i, val_len, pos = 0, fmt_pos = 0;                                   \
+       T expect[8], result[8];                                                 \
+                                                                               \
+       fill_random_array(expect);                                              \
+                                                                               \
+       for (i = 0; i < ARRAY_SIZE(expect); i++) {                              \
+               if (i != 0)                                                     \
+                       append_delim(test_buffer, &pos, BUF_SIZE,               \
+                                    fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\
+                                                                               \
+               val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt,      \
+                                    expect[i]);                                \
+               append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE,                      \
+                          "%%%u%s", val_len, scan_fmt);                        \
+       }                                                                       \
+                                                                               \
+       test_array_8(fn, expect, test_buffer, fmt_buffer, result);              \
+} while (0)
+
+static void __init numbers_list(const char *delim)
+{
+       numbers_list_8(unsigned long long, "%llu",   delim, "llu", check_ull);
+       numbers_list_8(long long,          "%lld",   delim, "lld", check_ll);
+       numbers_list_8(long long,          "%lld",   delim, "lli", check_ll);
+       numbers_list_8(unsigned long long, "%llx",   delim, "llx", check_ull);
+       numbers_list_8(unsigned long long, "0x%llx", delim, "llx", check_ull);
+       numbers_list_8(long long,          "0x%llx", delim, "lli", check_ll);
+
+       numbers_list_8(unsigned long,      "%lu",    delim, "lu", check_ulong);
+       numbers_list_8(long,               "%ld",    delim, "ld", check_long);
+       numbers_list_8(long,               "%ld",    delim, "li", check_long);
+       numbers_list_8(unsigned long,      "%lx",    delim, "lx", check_ulong);
+       numbers_list_8(unsigned long,      "0x%lx",  delim, "lx", check_ulong);
+       numbers_list_8(long,               "0x%lx",  delim, "li", check_long);
+
+       numbers_list_8(unsigned int,       "%u",     delim, "u", check_uint);
+       numbers_list_8(int,                "%d",     delim, "d", check_int);
+       numbers_list_8(int,                "%d",     delim, "i", check_int);
+       numbers_list_8(unsigned int,       "%x",     delim, "x", check_uint);
+       numbers_list_8(unsigned int,       "0x%x",   delim, "x", check_uint);
+       numbers_list_8(int,                "0x%x",   delim, "i", check_int);
+
+       numbers_list_8(unsigned short,     "%hu",    delim, "hu", check_ushort);
+       numbers_list_8(short,              "%hd",    delim, "hd", check_short);
+       numbers_list_8(short,              "%hd",    delim, "hi", check_short);
+       numbers_list_8(unsigned short,     "%hx",    delim, "hx", check_ushort);
+       numbers_list_8(unsigned short,     "0x%hx",  delim, "hx", check_ushort);
+       numbers_list_8(short,              "0x%hx",  delim, "hi", check_short);
+
+       numbers_list_8(unsigned char,      "%hhu",   delim, "hhu", check_uchar);
+       numbers_list_8(signed char,        "%hhd",   delim, "hhd", check_char);
+       numbers_list_8(signed char,        "%hhd",   delim, "hhi", check_char);
+       numbers_list_8(unsigned char,      "%hhx",   delim, "hhx", check_uchar);
+       numbers_list_8(unsigned char,      "0x%hhx", delim, "hhx", check_uchar);
+       numbers_list_8(signed char,        "0x%hhx", delim, "hhi", check_char);
+}
+
+/*
+ * List of numbers separated by delim. Each field width specifier is the
+ * maximum possible digits for the given type and base.
+ */
+static void __init numbers_list_field_width_typemax(const char *delim)
+{
+       numbers_list_fix_width(unsigned long long, "%llu",   delim, 20, "llu", check_ull);
+       numbers_list_fix_width(long long,          "%lld",   delim, 20, "lld", check_ll);
+       numbers_list_fix_width(long long,          "%lld",   delim, 20, "lli", check_ll);
+       numbers_list_fix_width(unsigned long long, "%llx",   delim, 16, "llx", check_ull);
+       numbers_list_fix_width(unsigned long long, "0x%llx", delim, 18, "llx", check_ull);
+       numbers_list_fix_width(long long,          "0x%llx", delim, 18, "lli", check_ll);
+
+#if BITS_PER_LONG == 64
+       numbers_list_fix_width(unsigned long,   "%lu",       delim, 20, "lu", check_ulong);
+       numbers_list_fix_width(long,            "%ld",       delim, 20, "ld", check_long);
+       numbers_list_fix_width(long,            "%ld",       delim, 20, "li", check_long);
+       numbers_list_fix_width(unsigned long,   "%lx",       delim, 16, "lx", check_ulong);
+       numbers_list_fix_width(unsigned long,   "0x%lx",     delim, 18, "lx", check_ulong);
+       numbers_list_fix_width(long,            "0x%lx",     delim, 18, "li", check_long);
+#else
+       numbers_list_fix_width(unsigned long,   "%lu",       delim, 10, "lu", check_ulong);
+       numbers_list_fix_width(long,            "%ld",       delim, 11, "ld", check_long);
+       numbers_list_fix_width(long,            "%ld",       delim, 11, "li", check_long);
+       numbers_list_fix_width(unsigned long,   "%lx",       delim, 8,  "lx", check_ulong);
+       numbers_list_fix_width(unsigned long,   "0x%lx",     delim, 10, "lx", check_ulong);
+       numbers_list_fix_width(long,            "0x%lx",     delim, 10, "li", check_long);
+#endif
+
+       numbers_list_fix_width(unsigned int,    "%u",        delim, 10, "u", check_uint);
+       numbers_list_fix_width(int,             "%d",        delim, 11, "d", check_int);
+       numbers_list_fix_width(int,             "%d",        delim, 11, "i", check_int);
+       numbers_list_fix_width(unsigned int,    "%x",        delim, 8,  "x", check_uint);
+       numbers_list_fix_width(unsigned int,    "0x%x",      delim, 10, "x", check_uint);
+       numbers_list_fix_width(int,             "0x%x",      delim, 10, "i", check_int);
+
+       numbers_list_fix_width(unsigned short,  "%hu",       delim, 5, "hu", check_ushort);
+       numbers_list_fix_width(short,           "%hd",       delim, 6, "hd", check_short);
+       numbers_list_fix_width(short,           "%hd",       delim, 6, "hi", check_short);
+       numbers_list_fix_width(unsigned short,  "%hx",       delim, 4, "hx", check_ushort);
+       numbers_list_fix_width(unsigned short,  "0x%hx",     delim, 6, "hx", check_ushort);
+       numbers_list_fix_width(short,           "0x%hx",     delim, 6, "hi", check_short);
+
+       numbers_list_fix_width(unsigned char,   "%hhu",      delim, 3, "hhu", check_uchar);
+       numbers_list_fix_width(signed char,     "%hhd",      delim, 4, "hhd", check_char);
+       numbers_list_fix_width(signed char,     "%hhd",      delim, 4, "hhi", check_char);
+       numbers_list_fix_width(unsigned char,   "%hhx",      delim, 2, "hhx", check_uchar);
+       numbers_list_fix_width(unsigned char,   "0x%hhx",    delim, 4, "hhx", check_uchar);
+       numbers_list_fix_width(signed char,     "0x%hhx",    delim, 4, "hhi", check_char);
+}
+
+/*
+ * List of numbers separated by delim. Each field width specifier is the
+ * exact length of the corresponding value digits in the string being scanned.
+ */
+static void __init numbers_list_field_width_val_width(const char *delim)
+{
+       numbers_list_val_width(unsigned long long, "%llu",   delim, "llu", check_ull);
+       numbers_list_val_width(long long,          "%lld",   delim, "lld", check_ll);
+       numbers_list_val_width(long long,          "%lld",   delim, "lli", check_ll);
+       numbers_list_val_width(unsigned long long, "%llx",   delim, "llx", check_ull);
+       numbers_list_val_width(unsigned long long, "0x%llx", delim, "llx", check_ull);
+       numbers_list_val_width(long long,          "0x%llx", delim, "lli", check_ll);
+
+       numbers_list_val_width(unsigned long,   "%lu",       delim, "lu", check_ulong);
+       numbers_list_val_width(long,            "%ld",       delim, "ld", check_long);
+       numbers_list_val_width(long,            "%ld",       delim, "li", check_long);
+       numbers_list_val_width(unsigned long,   "%lx",       delim, "lx", check_ulong);
+       numbers_list_val_width(unsigned long,   "0x%lx",     delim, "lx", check_ulong);
+       numbers_list_val_width(long,            "0x%lx",     delim, "li", check_long);
+
+       numbers_list_val_width(unsigned int,    "%u",        delim, "u", check_uint);
+       numbers_list_val_width(int,             "%d",        delim, "d", check_int);
+       numbers_list_val_width(int,             "%d",        delim, "i", check_int);
+       numbers_list_val_width(unsigned int,    "%x",        delim, "x", check_uint);
+       numbers_list_val_width(unsigned int,    "0x%x",      delim, "x", check_uint);
+       numbers_list_val_width(int,             "0x%x",      delim, "i", check_int);
+
+       numbers_list_val_width(unsigned short,  "%hu",       delim, "hu", check_ushort);
+       numbers_list_val_width(short,           "%hd",       delim, "hd", check_short);
+       numbers_list_val_width(short,           "%hd",       delim, "hi", check_short);
+       numbers_list_val_width(unsigned short,  "%hx",       delim, "hx", check_ushort);
+       numbers_list_val_width(unsigned short,  "0x%hx",     delim, "hx", check_ushort);
+       numbers_list_val_width(short,           "0x%hx",     delim, "hi", check_short);
+
+       numbers_list_val_width(unsigned char,   "%hhu",      delim, "hhu", check_uchar);
+       numbers_list_val_width(signed char,     "%hhd",      delim, "hhd", check_char);
+       numbers_list_val_width(signed char,     "%hhd",      delim, "hhi", check_char);
+       numbers_list_val_width(unsigned char,   "%hhx",      delim, "hhx", check_uchar);
+       numbers_list_val_width(unsigned char,   "0x%hhx",    delim, "hhx", check_uchar);
+       numbers_list_val_width(signed char,     "0x%hhx",    delim, "hhi", check_char);
+}
+
+/*
+ * Slice a continuous string of digits without field delimiters, containing
+ * numbers of varying length, using the field width to extract each group
+ * of digits. For example the hex values c0,3,bf01,303 would have a
+ * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
+ */
+static void __init numbers_slice(void)
+{
+       numbers_list_field_width_val_width("");
+}
+
+#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn)     \
+do {                                                                           \
+       const T expect[2] = { expect0, expect1 };                               \
+       T result[2] = {~expect[0], ~expect[1]};                                 \
+                                                                               \
+       _test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);      \
+} while (0)
+
+/*
+ * Number prefix is >= field width.
+ * Expected behaviour is derived from testing userland sscanf.
+ */
+static void __init numbers_prefix_overflow(void)
+{
+       /*
+        * Negative decimal with a field of width 1, should quit scanning
+        * and return 0.
+        */
+       test_number_prefix(long long,   "-1 1", "%1lld %lld",   0, 0, 0, check_ll);
+       test_number_prefix(long,        "-1 1", "%1ld %ld",     0, 0, 0, check_long);
+       test_number_prefix(int,         "-1 1", "%1d %d",       0, 0, 0, check_int);
+       test_number_prefix(short,       "-1 1", "%1hd %hd",     0, 0, 0, check_short);
+       test_number_prefix(signed char, "-1 1", "%1hhd %hhd",   0, 0, 0, check_char);
+
+       test_number_prefix(long long,   "-1 1", "%1lli %lli",   0, 0, 0, check_ll);
+       test_number_prefix(long,        "-1 1", "%1li %li",     0, 0, 0, check_long);
+       test_number_prefix(int,         "-1 1", "%1i %i",       0, 0, 0, check_int);
+       test_number_prefix(short,       "-1 1", "%1hi %hi",     0, 0, 0, check_short);
+       test_number_prefix(signed char, "-1 1", "%1hhi %hhi",   0, 0, 0, check_char);
+
+       /*
+        * 0x prefix in a field of width 1: 0 is a valid digit so should
+        * convert. Next field scan starts at the 'x' which isn't a digit so
+        * scan quits with one field converted.
+        */
+       test_number_prefix(unsigned long long,  "0xA7", "%1llx%llx", 0, 0, 1, check_ull);
+       test_number_prefix(unsigned long,       "0xA7", "%1lx%lx",   0, 0, 1, check_ulong);
+       test_number_prefix(unsigned int,        "0xA7", "%1x%x",     0, 0, 1, check_uint);
+       test_number_prefix(unsigned short,      "0xA7", "%1hx%hx",   0, 0, 1, check_ushort);
+       test_number_prefix(unsigned char,       "0xA7", "%1hhx%hhx", 0, 0, 1, check_uchar);
+       test_number_prefix(long long,           "0xA7", "%1lli%llx", 0, 0, 1, check_ll);
+       test_number_prefix(long,                "0xA7", "%1li%lx",   0, 0, 1, check_long);
+       test_number_prefix(int,                 "0xA7", "%1i%x",     0, 0, 1, check_int);
+       test_number_prefix(short,               "0xA7", "%1hi%hx",   0, 0, 1, check_short);
+       test_number_prefix(char,                "0xA7", "%1hhi%hhx", 0, 0, 1, check_char);
+
+       /*
+        * 0x prefix in a field of width 2 using %x conversion: first field
+        * converts to 0. Next field scan starts at the character after "0x".
+        * Both fields will convert.
+        */
+       test_number_prefix(unsigned long long,  "0xA7", "%2llx%llx", 0, 0xa7, 2, check_ull);
+       test_number_prefix(unsigned long,       "0xA7", "%2lx%lx",   0, 0xa7, 2, check_ulong);
+       test_number_prefix(unsigned int,        "0xA7", "%2x%x",     0, 0xa7, 2, check_uint);
+       test_number_prefix(unsigned short,      "0xA7", "%2hx%hx",   0, 0xa7, 2, check_ushort);
+       test_number_prefix(unsigned char,       "0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar);
+
+       /*
+        * 0x prefix in a field of width 2 using %i conversion: first field
+        * converts to 0. Next field scan starts at the character after "0x",
+        * which will convert if can be intepreted as decimal but will fail
+        * if it contains any hex digits (since no 0x prefix).
+        */
+       test_number_prefix(long long,   "0x67", "%2lli%lli", 0, 67, 2, check_ll);
+       test_number_prefix(long,        "0x67", "%2li%li",   0, 67, 2, check_long);
+       test_number_prefix(int,         "0x67", "%2i%i",     0, 67, 2, check_int);
+       test_number_prefix(short,       "0x67", "%2hi%hi",   0, 67, 2, check_short);
+       test_number_prefix(char,        "0x67", "%2hhi%hhi", 0, 67, 2, check_char);
+
+       test_number_prefix(long long,   "0xA7", "%2lli%lli", 0, 0,  1, check_ll);
+       test_number_prefix(long,        "0xA7", "%2li%li",   0, 0,  1, check_long);
+       test_number_prefix(int,         "0xA7", "%2i%i",     0, 0,  1, check_int);
+       test_number_prefix(short,       "0xA7", "%2hi%hi",   0, 0,  1, check_short);
+       test_number_prefix(char,        "0xA7", "%2hhi%hhi", 0, 0,  1, check_char);
+}
+
+#define _test_simple_strtoxx(T, fn, gen_fmt, expect, base)                     \
+do {                                                                           \
+       T got;                                                                  \
+       char *endp;                                                             \
+       int len;                                                                \
+       bool fail = false;                                                      \
+                                                                               \
+       total_tests++;                                                          \
+       len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect);                 \
+       got = (fn)(test_buffer, &endp, base);                                   \
+       pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got);  \
+       if (got != (expect)) {                                                  \
+               fail = true;                                                    \
+               pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
+                       test_buffer, base, got, expect);                        \
+       } else if (endp != test_buffer + len) {                                 \
+               fail = true;                                                    \
+               pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
+                       test_buffer, base, test_buffer,                         \
+                       test_buffer + len, endp);                               \
+       }                                                                       \
+                                                                               \
+       if (fail)                                                               \
+               failed_tests++;                                                 \
+} while (0)
+
+#define test_simple_strtoxx(T, fn, gen_fmt, base)                              \
+do {                                                                           \
+       int i;                                                                  \
+                                                                               \
+       for (i = 0; i < ARRAY_SIZE(numbers); i++) {                             \
+               _test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base);      \
+                                                                               \
+               if (is_signed_type(T))                                          \
+                       _test_simple_strtoxx(T, fn, gen_fmt,                    \
+                                             -(T)numbers[i], base);            \
+       }                                                                       \
+} while (0)
+
+static void __init test_simple_strtoull(void)
+{
+       test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   10);
+       test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   0);
+       test_simple_strtoxx(unsigned long long, simple_strtoull, "%llx",   16);
+       test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 16);
+       test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
+}
+
+static void __init test_simple_strtoll(void)
+{
+       test_simple_strtoxx(long long, simple_strtoll, "%lld",   10);
+       test_simple_strtoxx(long long, simple_strtoll, "%lld",   0);
+       test_simple_strtoxx(long long, simple_strtoll, "%llx",   16);
+       test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 16);
+       test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
+}
+
+static void __init test_simple_strtoul(void)
+{
+       test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   10);
+       test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   0);
+       test_simple_strtoxx(unsigned long, simple_strtoul, "%lx",   16);
+       test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 16);
+       test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
+}
+
+static void __init test_simple_strtol(void)
+{
+       test_simple_strtoxx(long, simple_strtol, "%ld",   10);
+       test_simple_strtoxx(long, simple_strtol, "%ld",   0);
+       test_simple_strtoxx(long, simple_strtol, "%lx",   16);
+       test_simple_strtoxx(long, simple_strtol, "0x%lx", 16);
+       test_simple_strtoxx(long, simple_strtol, "0x%lx", 0);
+}
+
+/* Selection of common delimiters/separators between numbers in a string. */
+static const char * const number_delimiters[] __initconst = {
+       " ", ":", ",", "-", "/",
+};
+
+static void __init test_numbers(void)
+{
+       int i;
+
+       /* String containing only one number. */
+       numbers_simple();
+
+       /* String with multiple numbers separated by delimiter. */
+       for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) {
+               numbers_list(number_delimiters[i]);
+
+               /* Field width may be longer than actual field digits. */
+               numbers_list_field_width_typemax(number_delimiters[i]);
+
+               /* Each field width exactly length of actual field digits. */
+               numbers_list_field_width_val_width(number_delimiters[i]);
+       }
+
+       /* Slice continuous sequence of digits using field widths. */
+       numbers_slice();
+
+       numbers_prefix_overflow();
+}
+
+static void __init selftest(void)
+{
+       test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
+       if (!test_buffer)
+               return;
+
+       fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
+       if (!fmt_buffer) {
+               kfree(test_buffer);
+               return;
+       }
+
+       prandom_seed_state(&rnd_state, 3141592653589793238ULL);
+
+       test_numbers();
+
+       test_simple_strtoull();
+       test_simple_strtoll();
+       test_simple_strtoul();
+       test_simple_strtol();
+
+       kfree(fmt_buffer);
+       kfree(test_buffer);
+}
+
+KSTM_MODULE_LOADERS(test_scanf);
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL v2");
index f0c35d9..ea65ec5 100644 (file)
 #include <linux/string_helpers.h>
 #include "kstrtox.h"
 
+static unsigned long long simple_strntoull(const char *startp, size_t max_chars,
+                                          char **endp, unsigned int base)
+{
+       const char *cp;
+       unsigned long long result = 0ULL;
+       size_t prefix_chars;
+       unsigned int rv;
+
+       cp = _parse_integer_fixup_radix(startp, &base);
+       prefix_chars = cp - startp;
+       if (prefix_chars < max_chars) {
+               rv = _parse_integer_limit(cp, base, &result, max_chars - prefix_chars);
+               /* FIXME */
+               cp += (rv & ~KSTRTOX_OVERFLOW);
+       } else {
+               /* Field too short for prefix + digit, skip over without converting */
+               cp = startp + max_chars;
+       }
+
+       if (endp)
+               *endp = (char *)cp;
+
+       return result;
+}
+
 /**
  * simple_strtoull - convert a string to an unsigned long long
  * @cp: The start of the string
  */
 unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
 {
-       unsigned long long result;
-       unsigned int rv;
-
-       cp = _parse_integer_fixup_radix(cp, &base);
-       rv = _parse_integer(cp, base, &result);
-       /* FIXME */
-       cp += (rv & ~KSTRTOX_OVERFLOW);
-
-       if (endp)
-               *endp = (char *)cp;
-
-       return result;
+       return simple_strntoull(cp, INT_MAX, endp, base);
 }
 EXPORT_SYMBOL(simple_strtoull);
 
@@ -109,6 +123,21 @@ long simple_strtol(const char *cp, char **endp, unsigned int base)
 }
 EXPORT_SYMBOL(simple_strtol);
 
+static long long simple_strntoll(const char *cp, size_t max_chars, char **endp,
+                                unsigned int base)
+{
+       /*
+        * simple_strntoull() safely handles receiving max_chars==0 in the
+        * case cp[0] == '-' && max_chars == 1.
+        * If max_chars == 0 we can drop through and pass it to simple_strntoull()
+        * and the content of *cp is irrelevant.
+        */
+       if (*cp == '-' && max_chars > 0)
+               return -simple_strntoull(cp + 1, max_chars - 1, endp, base);
+
+       return simple_strntoull(cp, max_chars, endp, base);
+}
+
 /**
  * simple_strtoll - convert a string to a signed long long
  * @cp: The start of the string
@@ -119,10 +148,7 @@ EXPORT_SYMBOL(simple_strtol);
  */
 long long simple_strtoll(const char *cp, char **endp, unsigned int base)
 {
-       if (*cp == '-')
-               return -simple_strtoull(cp + 1, endp, base);
-
-       return simple_strtoull(cp, endp, base);
+       return simple_strntoll(cp, INT_MAX, endp, base);
 }
 EXPORT_SYMBOL(simple_strtoll);
 
@@ -1834,7 +1860,8 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm,
              struct printf_spec spec, const char *fmt)
 {
        bool have_t = true, have_d = true;
-       bool raw = false;
+       bool raw = false, iso8601_separator = true;
+       bool found = true;
        int count = 2;
 
        if (check_pointer(&buf, end, tm, spec))
@@ -1851,14 +1878,25 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm,
                break;
        }
 
-       raw = fmt[count] == 'r';
+       do {
+               switch (fmt[count++]) {
+               case 'r':
+                       raw = true;
+                       break;
+               case 's':
+                       iso8601_separator = false;
+                       break;
+               default:
+                       found = false;
+                       break;
+               }
+       } while (found);
 
        if (have_d)
                buf = date_str(buf, end, tm, raw);
        if (have_d && have_t) {
-               /* Respect ISO 8601 */
                if (buf < end)
-                       *buf = 'T';
+                       *buf = iso8601_separator ? 'T' : ' ';
                buf++;
        }
        if (have_t)
@@ -2298,7 +2336,7 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
  * - 'd[234]' For a dentry name (optionally 2-4 last components)
  * - 'D[234]' Same as 'd' but for a struct file
  * - 'g' For block_device name (gendisk + partition number)
- * - 't[RT][dt][r]' For time and date as represented by:
+ * - 't[RT][dt][r][s]' For time and date as represented by:
  *      R    struct rtc_time
  *      T    time64_t
  * - 'C' For a clock, it prints the name (Common Clock Framework) or address
@@ -3565,8 +3603,12 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                str = skip_spaces(str);
 
                digit = *str;
-               if (is_sign && digit == '-')
+               if (is_sign && digit == '-') {
+                       if (field_width == 1)
+                               break;
+
                        digit = *(str + 1);
+               }
 
                if (!digit
                    || (base == 16 && !isxdigit(digit))
@@ -3576,25 +3618,13 @@ int vsscanf(const char *buf, const char *fmt, va_list args)
                        break;
 
                if (is_sign)
-                       val.s = qualifier != 'L' ?
-                               simple_strtol(str, &next, base) :
-                               simple_strtoll(str, &next, base);
+                       val.s = simple_strntoll(str,
+                                               field_width >= 0 ? field_width : INT_MAX,
+                                               &next, base);
                else
-                       val.u = qualifier != 'L' ?
-                               simple_strtoul(str, &next, base) :
-                               simple_strtoull(str, &next, base);
-
-               if (field_width > 0 && next - str > field_width) {
-                       if (base == 0)
-                               _parse_integer_fixup_radix(str, &base);
-                       while (next - str > field_width) {
-                               if (is_sign)
-                                       val.s = div_s64(val.s, base);
-                               else
-                                       val.u = div_u64(val.u, base);
-                               --next;
-                       }
-               }
+                       val.u = simple_strntoull(str,
+                                                field_width >= 0 ? field_width : INT_MAX,
+                                                &next, base);
 
                switch (qualifier) {
                case 'H':       /* that's 'hh' in format */
index 84fde27..725f564 100644 (file)
@@ -1955,7 +1955,7 @@ static inline bool is_via_compact_memory(int order)
 
 static bool kswapd_is_running(pg_data_t *pgdat)
 {
-       return pgdat->kswapd && (pgdat->kswapd->state == TASK_RUNNING);
+       return pgdat->kswapd && task_is_running(pgdat->kswapd);
 }
 
 /*
index 63ed6b2..6d2a011 100644 (file)
@@ -62,6 +62,7 @@ static struct shrinker deferred_split_shrinker;
 
 static atomic_t huge_zero_refcount;
 struct page *huge_zero_page __read_mostly;
+unsigned long huge_zero_pfn __read_mostly = ~0UL;
 
 bool transparent_hugepage_enabled(struct vm_area_struct *vma)
 {
@@ -98,6 +99,7 @@ retry:
                __free_pages(zero_page, compound_order(zero_page));
                goto retry;
        }
+       WRITE_ONCE(huge_zero_pfn, page_to_pfn(zero_page));
 
        /* We take additional reference here. It will be put back by shrinker */
        atomic_set(&huge_zero_refcount, 2);
@@ -147,6 +149,7 @@ static unsigned long shrink_huge_zero_page_scan(struct shrinker *shrink,
        if (atomic_cmpxchg(&huge_zero_refcount, 1, 0) == 1) {
                struct page *zero_page = xchg(&huge_zero_page, NULL);
                BUG_ON(zero_page == NULL);
+               WRITE_ONCE(huge_zero_pfn, ~0UL);
                __free_pages(zero_page, compound_order(zero_page));
                return HPAGE_PMD_NR;
        }
@@ -2044,7 +2047,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
        count_vm_event(THP_SPLIT_PMD);
 
        if (!vma_is_anonymous(vma)) {
-               _pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
+               old_pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd);
                /*
                 * We are going to unmap this huge page. So
                 * just go ahead and zap it
@@ -2053,16 +2056,25 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
                        zap_deposited_table(mm, pmd);
                if (vma_is_special_huge(vma))
                        return;
-               page = pmd_page(_pmd);
-               if (!PageDirty(page) && pmd_dirty(_pmd))
-                       set_page_dirty(page);
-               if (!PageReferenced(page) && pmd_young(_pmd))
-                       SetPageReferenced(page);
-               page_remove_rmap(page, true);
-               put_page(page);
+               if (unlikely(is_pmd_migration_entry(old_pmd))) {
+                       swp_entry_t entry;
+
+                       entry = pmd_to_swp_entry(old_pmd);
+                       page = migration_entry_to_page(entry);
+               } else {
+                       page = pmd_page(old_pmd);
+                       if (!PageDirty(page) && pmd_dirty(old_pmd))
+                               set_page_dirty(page);
+                       if (!PageReferenced(page) && pmd_young(old_pmd))
+                               SetPageReferenced(page);
+                       page_remove_rmap(page, true);
+                       put_page(page);
+               }
                add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
                return;
-       } else if (pmd_trans_huge(*pmd) && is_huge_zero_pmd(*pmd)) {
+       }
+
+       if (is_huge_zero_pmd(*pmd)) {
                /*
                 * FIXME: Do we want to invalidate secondary mmu by calling
                 * mmu_notifier_invalidate_range() see comments below inside
@@ -2338,17 +2350,17 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
 
 static void unmap_page(struct page *page)
 {
-       enum ttu_flags ttu_flags = TTU_IGNORE_MLOCK |
+       enum ttu_flags ttu_flags = TTU_IGNORE_MLOCK | TTU_SYNC |
                TTU_RMAP_LOCKED | TTU_SPLIT_HUGE_PMD;
-       bool unmap_success;
 
        VM_BUG_ON_PAGE(!PageHead(page), page);
 
        if (PageAnon(page))
                ttu_flags |= TTU_SPLIT_FREEZE;
 
-       unmap_success = try_to_unmap(page, ttu_flags);
-       VM_BUG_ON_PAGE(!unmap_success, page);
+       try_to_unmap(page, ttu_flags);
+
+       VM_WARN_ON_ONCE_PAGE(page_mapped(page), page);
 }
 
 static void remap_page(struct page *page, unsigned int nr)
@@ -2659,7 +2671,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
        struct deferred_split *ds_queue = get_deferred_split_queue(head);
        struct anon_vma *anon_vma = NULL;
        struct address_space *mapping = NULL;
-       int count, mapcount, extra_pins, ret;
+       int extra_pins, ret;
        pgoff_t end;
 
        VM_BUG_ON_PAGE(is_huge_zero_page(head), head);
@@ -2718,7 +2730,6 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
        }
 
        unmap_page(head);
-       VM_BUG_ON_PAGE(compound_mapcount(head), head);
 
        /* block interrupt reentry in xa_lock and spinlock */
        local_irq_disable();
@@ -2736,9 +2747,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
 
        /* Prevent deferred_split_scan() touching ->_refcount */
        spin_lock(&ds_queue->split_queue_lock);
-       count = page_count(head);
-       mapcount = total_mapcount(head);
-       if (!mapcount && page_ref_freeze(head, 1 + extra_pins)) {
+       if (page_ref_freeze(head, 1 + extra_pins)) {
                if (!list_empty(page_deferred_list(head))) {
                        ds_queue->split_queue_len--;
                        list_del(page_deferred_list(head));
@@ -2758,16 +2767,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                __split_huge_page(page, list, end);
                ret = 0;
        } else {
-               if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) {
-                       pr_alert("total_mapcount: %u, page_count(): %u\n",
-                                       mapcount, count);
-                       if (PageTail(page))
-                               dump_page(head, NULL);
-                       dump_page(page, "total_mapcount(head) > 0");
-                       BUG();
-               }
                spin_unlock(&ds_queue->split_queue_lock);
-fail:          if (mapping)
+fail:
+               if (mapping)
                        xa_unlock(&mapping->i_pages);
                local_irq_enable();
                remap_page(head, thp_nr_pages(head));
index 5560b50..5ba5a0d 100644 (file)
@@ -1588,15 +1588,12 @@ struct address_space *hugetlb_page_mapping_lock_write(struct page *hpage)
        return NULL;
 }
 
-pgoff_t __basepage_index(struct page *page)
+pgoff_t hugetlb_basepage_index(struct page *page)
 {
        struct page *page_head = compound_head(page);
        pgoff_t index = page_index(page_head);
        unsigned long compound_idx;
 
-       if (!PageHuge(page_head))
-               return page_index(page);
-
        if (compound_order(page_head) >= MAX_ORDER)
                compound_idx = page_to_pfn(page) - page_to_pfn(page_head);
        else
@@ -2121,12 +2118,18 @@ out:
  * be restored when a newly allocated huge page must be freed.  It is
  * to be called after calling vma_needs_reservation to determine if a
  * reservation exists.
+ *
+ * vma_del_reservation is used in error paths where an entry in the reserve
+ * map was created during huge page allocation and must be removed.  It is to
+ * be called after calling vma_needs_reservation to determine if a reservation
+ * exists.
  */
 enum vma_resv_mode {
        VMA_NEEDS_RESV,
        VMA_COMMIT_RESV,
        VMA_END_RESV,
        VMA_ADD_RESV,
+       VMA_DEL_RESV,
 };
 static long __vma_reservation_common(struct hstate *h,
                                struct vm_area_struct *vma, unsigned long addr,
@@ -2170,11 +2173,21 @@ static long __vma_reservation_common(struct hstate *h,
                        ret = region_del(resv, idx, idx + 1);
                }
                break;
+       case VMA_DEL_RESV:
+               if (vma->vm_flags & VM_MAYSHARE) {
+                       region_abort(resv, idx, idx + 1, 1);
+                       ret = region_del(resv, idx, idx + 1);
+               } else {
+                       ret = region_add(resv, idx, idx + 1, 1, NULL, NULL);
+                       /* region_add calls of range 1 should never fail. */
+                       VM_BUG_ON(ret < 0);
+               }
+               break;
        default:
                BUG();
        }
 
-       if (vma->vm_flags & VM_MAYSHARE)
+       if (vma->vm_flags & VM_MAYSHARE || mode == VMA_DEL_RESV)
                return ret;
        /*
         * We know private mapping must have HPAGE_RESV_OWNER set.
@@ -2222,25 +2235,39 @@ static long vma_add_reservation(struct hstate *h,
        return __vma_reservation_common(h, vma, addr, VMA_ADD_RESV);
 }
 
+static long vma_del_reservation(struct hstate *h,
+                       struct vm_area_struct *vma, unsigned long addr)
+{
+       return __vma_reservation_common(h, vma, addr, VMA_DEL_RESV);
+}
+
 /*
- * This routine is called to restore a reservation on error paths.  In the
- * specific error paths, a huge page was allocated (via alloc_huge_page)
- * and is about to be freed.  If a reservation for the page existed,
- * alloc_huge_page would have consumed the reservation and set
- * HPageRestoreReserve in the newly allocated page.  When the page is freed
- * via free_huge_page, the global reservation count will be incremented if
- * HPageRestoreReserve is set.  However, free_huge_page can not adjust the
- * reserve map.  Adjust the reserve map here to be consistent with global
- * reserve count adjustments to be made by free_huge_page.
+ * This routine is called to restore reservation information on error paths.
+ * It should ONLY be called for pages allocated via alloc_huge_page(), and
+ * the hugetlb mutex should remain held when calling this routine.
+ *
+ * It handles two specific cases:
+ * 1) A reservation was in place and the page consumed the reservation.
+ *    HPageRestoreReserve is set in the page.
+ * 2) No reservation was in place for the page, so HPageRestoreReserve is
+ *    not set.  However, alloc_huge_page always updates the reserve map.
+ *
+ * In case 1, free_huge_page later in the error path will increment the
+ * global reserve count.  But, free_huge_page does not have enough context
+ * to adjust the reservation map.  This case deals primarily with private
+ * mappings.  Adjust the reserve map here to be consistent with global
+ * reserve count adjustments to be made by free_huge_page.  Make sure the
+ * reserve map indicates there is a reservation present.
+ *
+ * In case 2, simply undo reserve map modifications done by alloc_huge_page.
  */
-static void restore_reserve_on_error(struct hstate *h,
-                       struct vm_area_struct *vma, unsigned long address,
-                       struct page *page)
+void restore_reserve_on_error(struct hstate *h, struct vm_area_struct *vma,
+                       unsigned long address, struct page *page)
 {
-       if (unlikely(HPageRestoreReserve(page))) {
-               long rc = vma_needs_reservation(h, vma, address);
+       long rc = vma_needs_reservation(h, vma, address);
 
-               if (unlikely(rc < 0)) {
+       if (HPageRestoreReserve(page)) {
+               if (unlikely(rc < 0))
                        /*
                         * Rare out of memory condition in reserve map
                         * manipulation.  Clear HPageRestoreReserve so that
@@ -2253,16 +2280,57 @@ static void restore_reserve_on_error(struct hstate *h,
                         * accounting of reserve counts.
                         */
                        ClearHPageRestoreReserve(page);
-               } else if (rc) {
-                       rc = vma_add_reservation(h, vma, address);
-                       if (unlikely(rc < 0))
+               else if (rc)
+                       (void)vma_add_reservation(h, vma, address);
+               else
+                       vma_end_reservation(h, vma, address);
+       } else {
+               if (!rc) {
+                       /*
+                        * This indicates there is an entry in the reserve map
+                        * added by alloc_huge_page.  We know it was added
+                        * before the alloc_huge_page call, otherwise
+                        * HPageRestoreReserve would be set on the page.
+                        * Remove the entry so that a subsequent allocation
+                        * does not consume a reservation.
+                        */
+                       rc = vma_del_reservation(h, vma, address);
+                       if (rc < 0)
+                               /*
+                                * VERY rare out of memory condition.  Since
+                                * we can not delete the entry, set
+                                * HPageRestoreReserve so that the reserve
+                                * count will be incremented when the page
+                                * is freed.  This reserve will be consumed
+                                * on a subsequent allocation.
+                                */
+                               SetHPageRestoreReserve(page);
+               } else if (rc < 0) {
+                       /*
+                        * Rare out of memory condition from
+                        * vma_needs_reservation call.  Memory allocation is
+                        * only attempted if a new entry is needed.  Therefore,
+                        * this implies there is not an entry in the
+                        * reserve map.
+                        *
+                        * For shared mappings, no entry in the map indicates
+                        * no reservation.  We are done.
+                        */
+                       if (!(vma->vm_flags & VM_MAYSHARE))
                                /*
-                                * See above comment about rare out of
-                                * memory condition.
+                                * For private mappings, no entry indicates
+                                * a reservation is present.  Since we can
+                                * not add an entry, set SetHPageRestoreReserve
+                                * on the page so reserve count will be
+                                * incremented when freed.  This reserve will
+                                * be consumed on a subsequent allocation.
                                 */
-                               ClearHPageRestoreReserve(page);
+                               SetHPageRestoreReserve(page);
                } else
-                       vma_end_reservation(h, vma, address);
+                       /*
+                        * No reservation present, do nothing
+                        */
+                        vma_end_reservation(h, vma, address);
        }
 }
 
@@ -4037,6 +4105,8 @@ again:
                                spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
                                entry = huge_ptep_get(src_pte);
                                if (!pte_same(src_pte_old, entry)) {
+                                       restore_reserve_on_error(h, vma, addr,
+                                                               new);
                                        put_page(new);
                                        /* dst_entry won't change as in child */
                                        goto again;
@@ -5006,6 +5076,7 @@ out_release_unlock:
        if (vm_shared || is_continue)
                unlock_page(page);
 out_release_nounlock:
+       restore_reserve_on_error(h, dst_vma, dst_addr, page);
        put_page(page);
        goto out;
 }
@@ -5857,6 +5928,21 @@ unlock:
        return ret;
 }
 
+int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+{
+       int ret = 0;
+
+       *hugetlb = false;
+       spin_lock_irq(&hugetlb_lock);
+       if (PageHeadHuge(page)) {
+               *hugetlb = true;
+               if (HPageFreed(page) || HPageMigratable(page))
+                       ret = get_page_unless_zero(page);
+       }
+       spin_unlock_irq(&hugetlb_lock);
+       return ret;
+}
+
 void putback_active_hugepage(struct page *page)
 {
        spin_lock_irq(&hugetlb_lock);
index 2f11829..e8fdb53 100644 (file)
@@ -384,27 +384,52 @@ static inline void mlock_migrate_page(struct page *newpage, struct page *page)
 extern pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma);
 
 /*
- * At what user virtual address is page expected in @vma?
+ * At what user virtual address is page expected in vma?
+ * Returns -EFAULT if all of the page is outside the range of vma.
+ * If page is a compound head, the entire compound page is considered.
  */
 static inline unsigned long
-__vma_address(struct page *page, struct vm_area_struct *vma)
+vma_address(struct page *page, struct vm_area_struct *vma)
 {
-       pgoff_t pgoff = page_to_pgoff(page);
-       return vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+       pgoff_t pgoff;
+       unsigned long address;
+
+       VM_BUG_ON_PAGE(PageKsm(page), page);    /* KSM page->index unusable */
+       pgoff = page_to_pgoff(page);
+       if (pgoff >= vma->vm_pgoff) {
+               address = vma->vm_start +
+                       ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+               /* Check for address beyond vma (or wrapped through 0?) */
+               if (address < vma->vm_start || address >= vma->vm_end)
+                       address = -EFAULT;
+       } else if (PageHead(page) &&
+                  pgoff + compound_nr(page) - 1 >= vma->vm_pgoff) {
+               /* Test above avoids possibility of wrap to 0 on 32-bit */
+               address = vma->vm_start;
+       } else {
+               address = -EFAULT;
+       }
+       return address;
 }
 
+/*
+ * Then at what user virtual address will none of the page be found in vma?
+ * Assumes that vma_address() already returned a good starting address.
+ * If page is a compound head, the entire compound page is considered.
+ */
 static inline unsigned long
-vma_address(struct page *page, struct vm_area_struct *vma)
+vma_address_end(struct page *page, struct vm_area_struct *vma)
 {
-       unsigned long start, end;
-
-       start = __vma_address(page, vma);
-       end = start + thp_size(page) - PAGE_SIZE;
-
-       /* page should be within @vma mapping range */
-       VM_BUG_ON_VMA(end < vma->vm_start || start >= vma->vm_end, vma);
-
-       return max(start, vma->vm_start);
+       pgoff_t pgoff;
+       unsigned long address;
+
+       VM_BUG_ON_PAGE(PageKsm(page), page);    /* KSM page->index unusable */
+       pgoff = page_to_pgoff(page) + compound_nr(page);
+       address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+       /* Check for address beyond vma (or wrapped through 0?) */
+       if (address < vma->vm_start || address > vma->vm_end)
+               address = vma->vm_end;
+       return address;
 }
 
 static inline struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf,
index 6bb87f2..0ecd293 100644 (file)
@@ -97,7 +97,7 @@ slab_flags_t __kasan_never_merge(void)
        return 0;
 }
 
-void __kasan_alloc_pages(struct page *page, unsigned int order, bool init)
+void __kasan_unpoison_pages(struct page *page, unsigned int order, bool init)
 {
        u8 tag;
        unsigned long i;
@@ -111,7 +111,7 @@ void __kasan_alloc_pages(struct page *page, unsigned int order, bool init)
        kasan_unpoison(page_address(page), PAGE_SIZE << order, init);
 }
 
-void __kasan_free_pages(struct page *page, unsigned int order, bool init)
+void __kasan_poison_pages(struct page *page, unsigned int order, bool init)
 {
        if (likely(!PageHighMem(page)))
                kasan_poison(page_address(page), PAGE_SIZE << order,
index 4004388..ed5e5b8 100644 (file)
@@ -238,6 +238,38 @@ struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
        return &alloc_meta->free_track[0];
 }
 
+void kasan_alloc_pages(struct page *page, unsigned int order, gfp_t flags)
+{
+       /*
+        * This condition should match the one in post_alloc_hook() in
+        * page_alloc.c.
+        */
+       bool init = !want_init_on_free() && want_init_on_alloc(flags);
+
+       if (flags & __GFP_SKIP_KASAN_POISON)
+               SetPageSkipKASanPoison(page);
+
+       if (flags & __GFP_ZEROTAGS) {
+               int i;
+
+               for (i = 0; i != 1 << order; ++i)
+                       tag_clear_highpage(page + i);
+       } else {
+               kasan_unpoison_pages(page, order, init);
+       }
+}
+
+void kasan_free_pages(struct page *page, unsigned int order)
+{
+       /*
+        * This condition should match the one in free_pages_prepare() in
+        * page_alloc.c.
+        */
+       bool init = want_init_on_free();
+
+       kasan_poison_pages(page, order, init);
+}
+
 #if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST)
 
 void kasan_set_tagging_report_once(bool state)
index 9df8e7f..9362938 100644 (file)
@@ -207,3 +207,10 @@ struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
 
        return &alloc_meta->free_track[i];
 }
+
+void kasan_tag_mismatch(unsigned long addr, unsigned long access_info,
+                       unsigned long ret_ip)
+{
+       kasan_report(addr, 1 << (access_info & 0xf), access_info & 0x10,
+                    ret_ip);
+}
index 2647c89..081dd33 100644 (file)
@@ -297,9 +297,9 @@ SYSCALL_DEFINE2(memfd_create,
        }
 
        if (flags & MFD_HUGETLB) {
-               struct user_struct *user = NULL;
+               struct ucounts *ucounts = NULL;
 
-               file = hugetlb_file_setup(name, 0, VM_NORESERVE, &user,
+               file = hugetlb_file_setup(name, 0, VM_NORESERVE, &ucounts,
                                        HUGETLB_ANONHUGE_INODE,
                                        (flags >> MFD_HUGE_SHIFT) &
                                        MFD_HUGE_MASK);
index 85ad98c..6f5f788 100644 (file)
@@ -658,6 +658,7 @@ static int truncate_error_page(struct page *p, unsigned long pfn,
  */
 static int me_kernel(struct page *p, unsigned long pfn)
 {
+       unlock_page(p);
        return MF_IGNORED;
 }
 
@@ -667,6 +668,7 @@ static int me_kernel(struct page *p, unsigned long pfn)
 static int me_unknown(struct page *p, unsigned long pfn)
 {
        pr_err("Memory failure: %#lx: Unknown page state\n", pfn);
+       unlock_page(p);
        return MF_FAILED;
 }
 
@@ -675,6 +677,7 @@ static int me_unknown(struct page *p, unsigned long pfn)
  */
 static int me_pagecache_clean(struct page *p, unsigned long pfn)
 {
+       int ret;
        struct address_space *mapping;
 
        delete_from_lru_cache(p);
@@ -683,8 +686,10 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
         * For anonymous pages we're done the only reference left
         * should be the one m_f() holds.
         */
-       if (PageAnon(p))
-               return MF_RECOVERED;
+       if (PageAnon(p)) {
+               ret = MF_RECOVERED;
+               goto out;
+       }
 
        /*
         * Now truncate the page in the page cache. This is really
@@ -698,7 +703,8 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
                /*
                 * Page has been teared down in the meanwhile
                 */
-               return MF_FAILED;
+               ret = MF_FAILED;
+               goto out;
        }
 
        /*
@@ -706,7 +712,10 @@ static int me_pagecache_clean(struct page *p, unsigned long pfn)
         *
         * Open: to take i_mutex or not for this? Right now we don't.
         */
-       return truncate_error_page(p, pfn, mapping);
+       ret = truncate_error_page(p, pfn, mapping);
+out:
+       unlock_page(p);
+       return ret;
 }
 
 /*
@@ -782,24 +791,26 @@ static int me_pagecache_dirty(struct page *p, unsigned long pfn)
  */
 static int me_swapcache_dirty(struct page *p, unsigned long pfn)
 {
+       int ret;
+
        ClearPageDirty(p);
        /* Trigger EIO in shmem: */
        ClearPageUptodate(p);
 
-       if (!delete_from_lru_cache(p))
-               return MF_DELAYED;
-       else
-               return MF_FAILED;
+       ret = delete_from_lru_cache(p) ? MF_FAILED : MF_DELAYED;
+       unlock_page(p);
+       return ret;
 }
 
 static int me_swapcache_clean(struct page *p, unsigned long pfn)
 {
+       int ret;
+
        delete_from_swap_cache(p);
 
-       if (!delete_from_lru_cache(p))
-               return MF_RECOVERED;
-       else
-               return MF_FAILED;
+       ret = delete_from_lru_cache(p) ? MF_FAILED : MF_RECOVERED;
+       unlock_page(p);
+       return ret;
 }
 
 /*
@@ -820,6 +831,7 @@ static int me_huge_page(struct page *p, unsigned long pfn)
        mapping = page_mapping(hpage);
        if (mapping) {
                res = truncate_error_page(hpage, pfn, mapping);
+               unlock_page(hpage);
        } else {
                res = MF_FAILED;
                unlock_page(hpage);
@@ -834,7 +846,6 @@ static int me_huge_page(struct page *p, unsigned long pfn)
                        page_ref_inc(p);
                        res = MF_RECOVERED;
                }
-               lock_page(hpage);
        }
 
        return res;
@@ -866,6 +877,8 @@ static struct page_state {
        unsigned long mask;
        unsigned long res;
        enum mf_action_page_type type;
+
+       /* Callback ->action() has to unlock the relevant page inside it. */
        int (*action)(struct page *p, unsigned long pfn);
 } error_states[] = {
        { reserved,     reserved,       MF_MSG_KERNEL,  me_kernel },
@@ -929,6 +942,7 @@ static int page_action(struct page_state *ps, struct page *p,
        int result;
        int count;
 
+       /* page p should be unlocked after returning from ps->action().  */
        result = ps->action(p, pfn);
 
        count = page_count(p) - 1;
@@ -949,6 +963,17 @@ static int page_action(struct page_state *ps, struct page *p,
        return (result == MF_RECOVERED || result == MF_DELAYED) ? 0 : -EBUSY;
 }
 
+/*
+ * Return true if a page type of a given page is supported by hwpoison
+ * mechanism (while handling could fail), otherwise false.  This function
+ * does not return true for hugetlb or device memory pages, so it's assumed
+ * to be called only in the context where we never have such pages.
+ */
+static inline bool HWPoisonHandlable(struct page *page)
+{
+       return PageLRU(page) || __PageMovable(page);
+}
+
 /**
  * __get_hwpoison_page() - Get refcount for memory error handling:
  * @page:      raw error page (hit by memory error)
@@ -959,8 +984,22 @@ static int page_action(struct page_state *ps, struct page *p,
 static int __get_hwpoison_page(struct page *page)
 {
        struct page *head = compound_head(page);
+       int ret = 0;
+       bool hugetlb = false;
+
+       ret = get_hwpoison_huge_page(head, &hugetlb);
+       if (hugetlb)
+               return ret;
+
+       /*
+        * This check prevents from calling get_hwpoison_unless_zero()
+        * for any unsupported type of page in order to reduce the risk of
+        * unexpected races caused by taking a page refcount.
+        */
+       if (!HWPoisonHandlable(head))
+               return 0;
 
-       if (!PageHuge(head) && PageTransHuge(head)) {
+       if (PageTransHuge(head)) {
                /*
                 * Non anonymous thp exists only in allocation/free time. We
                 * can't handle such a case correctly, so let's give it up.
@@ -1017,7 +1056,7 @@ try_again:
                        ret = -EIO;
                }
        } else {
-               if (PageHuge(p) || PageLRU(p) || __PageMovable(p)) {
+               if (PageHuge(p) || HWPoisonHandlable(p)) {
                        ret = 1;
                } else {
                        /*
@@ -1228,7 +1267,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
        if (TestSetPageHWPoison(head)) {
                pr_err("Memory failure: %#lx: already hardware poisoned\n",
                       pfn);
-               return 0;
+               return -EHWPOISON;
        }
 
        num_poisoned_pages_inc();
@@ -1288,7 +1327,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags)
                goto out;
        }
 
-       res = identify_page_state(pfn, p, page_flags);
+       return identify_page_state(pfn, p, page_flags);
 out:
        unlock_page(head);
        return res;
@@ -1404,9 +1443,10 @@ int memory_failure(unsigned long pfn, int flags)
        struct page *hpage;
        struct page *orig_head;
        struct dev_pagemap *pgmap;
-       int res;
+       int res = 0;
        unsigned long page_flags;
        bool retry = true;
+       static DEFINE_MUTEX(mf_mutex);
 
        if (!sysctl_memory_failure_recovery)
                panic("Memory failure on page %lx", pfn);
@@ -1424,13 +1464,19 @@ int memory_failure(unsigned long pfn, int flags)
                return -ENXIO;
        }
 
+       mutex_lock(&mf_mutex);
+
 try_again:
-       if (PageHuge(p))
-               return memory_failure_hugetlb(pfn, flags);
+       if (PageHuge(p)) {
+               res = memory_failure_hugetlb(pfn, flags);
+               goto unlock_mutex;
+       }
+
        if (TestSetPageHWPoison(p)) {
                pr_err("Memory failure: %#lx: already hardware poisoned\n",
                        pfn);
-               return 0;
+               res = -EHWPOISON;
+               goto unlock_mutex;
        }
 
        orig_head = hpage = compound_head(p);
@@ -1463,17 +1509,19 @@ try_again:
                                res = MF_FAILED;
                        }
                        action_result(pfn, MF_MSG_BUDDY, res);
-                       return res == MF_RECOVERED ? 0 : -EBUSY;
+                       res = res == MF_RECOVERED ? 0 : -EBUSY;
                } else {
                        action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED);
-                       return -EBUSY;
+                       res = -EBUSY;
                }
+               goto unlock_mutex;
        }
 
        if (PageTransHuge(hpage)) {
                if (try_to_split_thp_page(p, "Memory Failure") < 0) {
                        action_result(pfn, MF_MSG_UNSPLIT_THP, MF_IGNORED);
-                       return -EBUSY;
+                       res = -EBUSY;
+                       goto unlock_mutex;
                }
                VM_BUG_ON_PAGE(!page_count(p), p);
        }
@@ -1497,7 +1545,7 @@ try_again:
        if (PageCompound(p) && compound_head(p) != orig_head) {
                action_result(pfn, MF_MSG_DIFFERENT_COMPOUND, MF_IGNORED);
                res = -EBUSY;
-               goto out;
+               goto unlock_page;
        }
 
        /*
@@ -1517,17 +1565,22 @@ try_again:
                num_poisoned_pages_dec();
                unlock_page(p);
                put_page(p);
-               return 0;
+               goto unlock_mutex;
        }
        if (hwpoison_filter(p)) {
                if (TestClearPageHWPoison(p))
                        num_poisoned_pages_dec();
                unlock_page(p);
                put_page(p);
-               return 0;
+               goto unlock_mutex;
        }
 
-       if (!PageTransTail(p) && !PageLRU(p))
+       /*
+        * __munlock_pagevec may clear a writeback page's LRU flag without
+        * page_lock. We need wait writeback completion for this page or it
+        * may trigger vfs BUG while evict inode.
+        */
+       if (!PageTransTail(p) && !PageLRU(p) && !PageWriteback(p))
                goto identify_page_state;
 
        /*
@@ -1543,7 +1596,7 @@ try_again:
        if (!hwpoison_user_mappings(p, pfn, flags, &p)) {
                action_result(pfn, MF_MSG_UNMAP_FAILED, MF_IGNORED);
                res = -EBUSY;
-               goto out;
+               goto unlock_page;
        }
 
        /*
@@ -1552,13 +1605,17 @@ try_again:
        if (PageLRU(p) && !PageSwapCache(p) && p->mapping == NULL) {
                action_result(pfn, MF_MSG_TRUNCATED_LRU, MF_IGNORED);
                res = -EBUSY;
-               goto out;
+               goto unlock_page;
        }
 
 identify_page_state:
        res = identify_page_state(pfn, p, page_flags);
-out:
+       mutex_unlock(&mf_mutex);
+       return res;
+unlock_page:
        unlock_page(p);
+unlock_mutex:
+       mutex_unlock(&mf_mutex);
        return res;
 }
 EXPORT_SYMBOL_GPL(memory_failure);
index f3ffab9..486f4a2 100644 (file)
@@ -1361,7 +1361,18 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                        else if (zap_huge_pmd(tlb, vma, pmd, addr))
                                goto next;
                        /* fall through */
+               } else if (details && details->single_page &&
+                          PageTransCompound(details->single_page) &&
+                          next - addr == HPAGE_PMD_SIZE && pmd_none(*pmd)) {
+                       spinlock_t *ptl = pmd_lock(tlb->mm, pmd);
+                       /*
+                        * Take and drop THP pmd lock so that we cannot return
+                        * prematurely, while zap_huge_pmd() has cleared *pmd,
+                        * but not yet decremented compound_mapcount().
+                        */
+                       spin_unlock(ptl);
                }
+
                /*
                 * Here there can be other concurrent MADV_DONTNEED or
                 * trans huge page faults running, and if the pmd is
@@ -3237,6 +3248,36 @@ static inline void unmap_mapping_range_tree(struct rb_root_cached *root,
 }
 
 /**
+ * unmap_mapping_page() - Unmap single page from processes.
+ * @page: The locked page to be unmapped.
+ *
+ * Unmap this page from any userspace process which still has it mmaped.
+ * Typically, for efficiency, the range of nearby pages has already been
+ * unmapped by unmap_mapping_pages() or unmap_mapping_range().  But once
+ * truncation or invalidation holds the lock on a page, it may find that
+ * the page has been remapped again: and then uses unmap_mapping_page()
+ * to unmap it finally.
+ */
+void unmap_mapping_page(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct zap_details details = { };
+
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(PageTail(page));
+
+       details.check_mapping = mapping;
+       details.first_index = page->index;
+       details.last_index = page->index + thp_nr_pages(page) - 1;
+       details.single_page = page;
+
+       i_mmap_lock_write(mapping);
+       if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)))
+               unmap_mapping_range_tree(&mapping->i_mmap, &details);
+       i_mmap_unlock_write(mapping);
+}
+
+/**
  * unmap_mapping_pages() - Unmap pages from processes.
  * @mapping: The address space containing pages to be unmapped.
  * @start: Index of first page to be unmapped.
index a258cf4..0b8afbe 100644 (file)
@@ -106,7 +106,8 @@ static __always_inline void kasan_poison_element(mempool_t *pool, void *element)
        if (pool->alloc == mempool_alloc_slab || pool->alloc == mempool_kmalloc)
                kasan_slab_free_mempool(element);
        else if (pool->alloc == mempool_alloc_pages)
-               kasan_free_pages(element, (unsigned long)pool->pool_data, false);
+               kasan_poison_pages(element, (unsigned long)pool->pool_data,
+                                  false);
 }
 
 static void kasan_unpoison_element(mempool_t *pool, void *element)
@@ -114,7 +115,8 @@ static void kasan_unpoison_element(mempool_t *pool, void *element)
        if (pool->alloc == mempool_alloc_slab || pool->alloc == mempool_kmalloc)
                kasan_unpoison_range(element, __ksize(element));
        else if (pool->alloc == mempool_alloc_pages)
-               kasan_alloc_pages(element, (unsigned long)pool->pool_data, false);
+               kasan_unpoison_pages(element, (unsigned long)pool->pool_data,
+                                    false);
 }
 
 static __always_inline void add_element(mempool_t *pool, void *element)
index b234c3f..41ff2c9 100644 (file)
@@ -295,6 +295,7 @@ void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep,
                goto out;
 
        page = migration_entry_to_page(entry);
+       page = compound_head(page);
 
        /*
         * Once page cache replacement of page migration started, page_count
index df590fd..e338ebc 100644 (file)
@@ -817,9 +817,10 @@ SYSCALL_DEFINE0(munlockall)
  */
 static DEFINE_SPINLOCK(shmlock_user_lock);
 
-int user_shm_lock(size_t size, struct user_struct *user)
+int user_shm_lock(size_t size, struct ucounts *ucounts)
 {
        unsigned long lock_limit, locked;
+       long memlock;
        int allowed = 0;
 
        locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -828,21 +829,26 @@ int user_shm_lock(size_t size, struct user_struct *user)
                allowed = 1;
        lock_limit >>= PAGE_SHIFT;
        spin_lock(&shmlock_user_lock);
-       if (!allowed &&
-           locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
+       memlock = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
+
+       if (!allowed && (memlock == LONG_MAX || memlock > lock_limit) && !capable(CAP_IPC_LOCK)) {
+               dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
+               goto out;
+       }
+       if (!get_ucounts(ucounts)) {
+               dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, locked);
                goto out;
-       get_uid(user);
-       user->locked_shm += locked;
+       }
        allowed = 1;
 out:
        spin_unlock(&shmlock_user_lock);
        return allowed;
 }
 
-void user_shm_unlock(size_t size, struct user_struct *user)
+void user_shm_unlock(size_t size, struct ucounts *ucounts)
 {
        spin_lock(&shmlock_user_lock);
-       user->locked_shm -= (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_MEMLOCK, (size + PAGE_SIZE - 1) >> PAGE_SHIFT);
        spin_unlock(&shmlock_user_lock);
-       free_uid(user);
+       put_ucounts(ucounts);
 }
index 0584e54..bc88d16 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1611,7 +1611,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
                        goto out_fput;
                }
        } else if (flags & MAP_HUGETLB) {
-               struct user_struct *user = NULL;
+               struct ucounts *ucounts = NULL;
                struct hstate *hs;
 
                hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
@@ -1627,7 +1627,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
                 */
                file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
                                VM_NORESERVE,
-                               &user, HUGETLB_ANONHUGE_INODE,
+                               &ucounts, HUGETLB_ANONHUGE_INODE,
                                (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
                if (IS_ERR(file))
                        return PTR_ERR(file);
index d1f5de1..e7af86e 100644 (file)
@@ -382,7 +382,7 @@ int page_group_by_mobility_disabled __read_mostly;
 static DEFINE_STATIC_KEY_TRUE(deferred_pages);
 
 /*
- * Calling kasan_free_pages() only after deferred memory initialization
+ * Calling kasan_poison_pages() only after deferred memory initialization
  * has completed. Poisoning pages during deferred memory init will greatly
  * lengthen the process and cause problem in large memory systems as the
  * deferred pages initialization is done with interrupt disabled.
@@ -394,15 +394,12 @@ static DEFINE_STATIC_KEY_TRUE(deferred_pages);
  * on-demand allocation and then freed again before the deferred pages
  * initialization is done, but this is not likely to happen.
  */
-static inline void kasan_free_nondeferred_pages(struct page *page, int order,
-                                               bool init, fpi_t fpi_flags)
+static inline bool should_skip_kasan_poison(struct page *page, fpi_t fpi_flags)
 {
-       if (static_branch_unlikely(&deferred_pages))
-               return;
-       if (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
-                       (fpi_flags & FPI_SKIP_KASAN_POISON))
-               return;
-       kasan_free_pages(page, order, init);
+       return static_branch_unlikely(&deferred_pages) ||
+              (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
+               (fpi_flags & FPI_SKIP_KASAN_POISON)) ||
+              PageSkipKASanPoison(page);
 }
 
 /* Returns true if the struct page for the pfn is uninitialised */
@@ -453,13 +450,11 @@ defer_init(int nid, unsigned long pfn, unsigned long end_pfn)
        return false;
 }
 #else
-static inline void kasan_free_nondeferred_pages(struct page *page, int order,
-                                               bool init, fpi_t fpi_flags)
+static inline bool should_skip_kasan_poison(struct page *page, fpi_t fpi_flags)
 {
-       if (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
-                       (fpi_flags & FPI_SKIP_KASAN_POISON))
-               return;
-       kasan_free_pages(page, order, init);
+       return (!IS_ENABLED(CONFIG_KASAN_GENERIC) &&
+               (fpi_flags & FPI_SKIP_KASAN_POISON)) ||
+              PageSkipKASanPoison(page);
 }
 
 static inline bool early_page_uninitialised(unsigned long pfn)
@@ -1226,10 +1221,16 @@ out:
        return ret;
 }
 
-static void kernel_init_free_pages(struct page *page, int numpages)
+static void kernel_init_free_pages(struct page *page, int numpages, bool zero_tags)
 {
        int i;
 
+       if (zero_tags) {
+               for (i = 0; i < numpages; i++)
+                       tag_clear_highpage(page + i);
+               return;
+       }
+
        /* s390's use of memset() could override KASAN redzones. */
        kasan_disable_current();
        for (i = 0; i < numpages; i++) {
@@ -1245,7 +1246,7 @@ static __always_inline bool free_pages_prepare(struct page *page,
                        unsigned int order, bool check_free, fpi_t fpi_flags)
 {
        int bad = 0;
-       bool init;
+       bool skip_kasan_poison = should_skip_kasan_poison(page, fpi_flags);
 
        VM_BUG_ON_PAGE(PageTail(page), page);
 
@@ -1314,10 +1315,17 @@ static __always_inline bool free_pages_prepare(struct page *page,
         * With hardware tag-based KASAN, memory tags must be set before the
         * page becomes unavailable via debug_pagealloc or arch_free_page.
         */
-       init = want_init_on_free();
-       if (init && !kasan_has_integrated_init())
-               kernel_init_free_pages(page, 1 << order);
-       kasan_free_nondeferred_pages(page, order, init, fpi_flags);
+       if (kasan_has_integrated_init()) {
+               if (!skip_kasan_poison)
+                       kasan_free_pages(page, order);
+       } else {
+               bool init = want_init_on_free();
+
+               if (init)
+                       kernel_init_free_pages(page, 1 << order, false);
+               if (!skip_kasan_poison)
+                       kasan_poison_pages(page, order, init);
+       }
 
        /*
         * arch_free_page() can make the page's contents inaccessible.  s390
@@ -2324,8 +2332,6 @@ static bool check_new_pages(struct page *page, unsigned int order)
 inline void post_alloc_hook(struct page *page, unsigned int order,
                                gfp_t gfp_flags)
 {
-       bool init;
-
        set_page_private(page, 0);
        set_page_refcounted(page);
 
@@ -2344,10 +2350,16 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
         * kasan_alloc_pages and kernel_init_free_pages must be
         * kept together to avoid discrepancies in behavior.
         */
-       init = !want_init_on_free() && want_init_on_alloc(gfp_flags);
-       kasan_alloc_pages(page, order, init);
-       if (init && !kasan_has_integrated_init())
-               kernel_init_free_pages(page, 1 << order);
+       if (kasan_has_integrated_init()) {
+               kasan_alloc_pages(page, order, gfp_flags);
+       } else {
+               bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags);
+
+               kasan_unpoison_pages(page, order, init);
+               if (init)
+                       kernel_init_free_pages(page, 1 << order,
+                                              gfp_flags & __GFP_ZEROTAGS);
+       }
 
        set_page_owner(page, order, gfp_flags);
 }
@@ -5053,9 +5065,13 @@ unsigned long __alloc_pages_bulk(gfp_t gfp, int preferred_nid,
         * Skip populated array elements to determine if any pages need
         * to be allocated before disabling IRQs.
         */
-       while (page_array && page_array[nr_populated] && nr_populated < nr_pages)
+       while (page_array && nr_populated < nr_pages && page_array[nr_populated])
                nr_populated++;
 
+       /* Already populated array? */
+       if (unlikely(page_array && nr_pages - nr_populated == 0))
+               return nr_populated;
+
        /* Use the single page allocator for one page. */
        if (nr_pages - nr_populated == 1)
                goto failed;
index 2cf01d9..a443531 100644 (file)
@@ -116,6 +116,13 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw)
        return pfn_is_match(pvmw->page, pfn);
 }
 
+static void step_forward(struct page_vma_mapped_walk *pvmw, unsigned long size)
+{
+       pvmw->address = (pvmw->address + size) & ~(size - 1);
+       if (!pvmw->address)
+               pvmw->address = ULONG_MAX;
+}
+
 /**
  * page_vma_mapped_walk - check if @pvmw->page is mapped in @pvmw->vma at
  * @pvmw->address
@@ -144,6 +151,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
 {
        struct mm_struct *mm = pvmw->vma->vm_mm;
        struct page *page = pvmw->page;
+       unsigned long end;
        pgd_t *pgd;
        p4d_t *p4d;
        pud_t *pud;
@@ -153,10 +161,11 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
        if (pvmw->pmd && !pvmw->pte)
                return not_found(pvmw);
 
-       if (pvmw->pte)
-               goto next_pte;
+       if (unlikely(PageHuge(page))) {
+               /* The only possible mapping was handled on last iteration */
+               if (pvmw->pte)
+                       return not_found(pvmw);
 
-       if (unlikely(PageHuge(pvmw->page))) {
                /* when pud is not present, pte will be NULL */
                pvmw->pte = huge_pte_offset(mm, pvmw->address, page_size(page));
                if (!pvmw->pte)
@@ -168,78 +177,108 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
                        return not_found(pvmw);
                return true;
        }
-restart:
-       pgd = pgd_offset(mm, pvmw->address);
-       if (!pgd_present(*pgd))
-               return false;
-       p4d = p4d_offset(pgd, pvmw->address);
-       if (!p4d_present(*p4d))
-               return false;
-       pud = pud_offset(p4d, pvmw->address);
-       if (!pud_present(*pud))
-               return false;
-       pvmw->pmd = pmd_offset(pud, pvmw->address);
+
        /*
-        * Make sure the pmd value isn't cached in a register by the
-        * compiler and used as a stale value after we've observed a
-        * subsequent update.
+        * Seek to next pte only makes sense for THP.
+        * But more important than that optimization, is to filter out
+        * any PageKsm page: whose page->index misleads vma_address()
+        * and vma_address_end() to disaster.
         */
-       pmde = READ_ONCE(*pvmw->pmd);
-       if (pmd_trans_huge(pmde) || is_pmd_migration_entry(pmde)) {
-               pvmw->ptl = pmd_lock(mm, pvmw->pmd);
-               if (likely(pmd_trans_huge(*pvmw->pmd))) {
-                       if (pvmw->flags & PVMW_MIGRATION)
-                               return not_found(pvmw);
-                       if (pmd_page(*pvmw->pmd) != page)
-                               return not_found(pvmw);
-                       return true;
-               } else if (!pmd_present(*pvmw->pmd)) {
-                       if (thp_migration_supported()) {
-                               if (!(pvmw->flags & PVMW_MIGRATION))
+       end = PageTransCompound(page) ?
+               vma_address_end(page, pvmw->vma) :
+               pvmw->address + PAGE_SIZE;
+       if (pvmw->pte)
+               goto next_pte;
+restart:
+       do {
+               pgd = pgd_offset(mm, pvmw->address);
+               if (!pgd_present(*pgd)) {
+                       step_forward(pvmw, PGDIR_SIZE);
+                       continue;
+               }
+               p4d = p4d_offset(pgd, pvmw->address);
+               if (!p4d_present(*p4d)) {
+                       step_forward(pvmw, P4D_SIZE);
+                       continue;
+               }
+               pud = pud_offset(p4d, pvmw->address);
+               if (!pud_present(*pud)) {
+                       step_forward(pvmw, PUD_SIZE);
+                       continue;
+               }
+
+               pvmw->pmd = pmd_offset(pud, pvmw->address);
+               /*
+                * Make sure the pmd value isn't cached in a register by the
+                * compiler and used as a stale value after we've observed a
+                * subsequent update.
+                */
+               pmde = READ_ONCE(*pvmw->pmd);
+
+               if (pmd_trans_huge(pmde) || is_pmd_migration_entry(pmde)) {
+                       pvmw->ptl = pmd_lock(mm, pvmw->pmd);
+                       pmde = *pvmw->pmd;
+                       if (likely(pmd_trans_huge(pmde))) {
+                               if (pvmw->flags & PVMW_MIGRATION)
                                        return not_found(pvmw);
-                               if (is_migration_entry(pmd_to_swp_entry(*pvmw->pmd))) {
-                                       swp_entry_t entry = pmd_to_swp_entry(*pvmw->pmd);
+                               if (pmd_page(pmde) != page)
+                                       return not_found(pvmw);
+                               return true;
+                       }
+                       if (!pmd_present(pmde)) {
+                               swp_entry_t entry;
 
-                                       if (migration_entry_to_page(entry) != page)
-                                               return not_found(pvmw);
-                                       return true;
-                               }
+                               if (!thp_migration_supported() ||
+                                   !(pvmw->flags & PVMW_MIGRATION))
+                                       return not_found(pvmw);
+                               entry = pmd_to_swp_entry(pmde);
+                               if (!is_migration_entry(entry) ||
+                                   migration_entry_to_page(entry) != page)
+                                       return not_found(pvmw);
+                               return true;
                        }
-                       return not_found(pvmw);
-               } else {
                        /* THP pmd was split under us: handle on pte level */
                        spin_unlock(pvmw->ptl);
                        pvmw->ptl = NULL;
+               } else if (!pmd_present(pmde)) {
+                       /*
+                        * If PVMW_SYNC, take and drop THP pmd lock so that we
+                        * cannot return prematurely, while zap_huge_pmd() has
+                        * cleared *pmd but not decremented compound_mapcount().
+                        */
+                       if ((pvmw->flags & PVMW_SYNC) &&
+                           PageTransCompound(page)) {
+                               spinlock_t *ptl = pmd_lock(mm, pvmw->pmd);
+
+                               spin_unlock(ptl);
+                       }
+                       step_forward(pvmw, PMD_SIZE);
+                       continue;
                }
-       } else if (!pmd_present(pmde)) {
-               return false;
-       }
-       if (!map_pte(pvmw))
-               goto next_pte;
-       while (1) {
+               if (!map_pte(pvmw))
+                       goto next_pte;
+this_pte:
                if (check_pte(pvmw))
                        return true;
 next_pte:
-               /* Seek to next pte only makes sense for THP */
-               if (!PageTransHuge(pvmw->page) || PageHuge(pvmw->page))
-                       return not_found(pvmw);
                do {
                        pvmw->address += PAGE_SIZE;
-                       if (pvmw->address >= pvmw->vma->vm_end ||
-                           pvmw->address >=
-                                       __vma_address(pvmw->page, pvmw->vma) +
-                                       thp_size(pvmw->page))
+                       if (pvmw->address >= end)
                                return not_found(pvmw);
                        /* Did we cross page table boundary? */
-                       if (pvmw->address % PMD_SIZE == 0) {
-                               pte_unmap(pvmw->pte);
+                       if ((pvmw->address & (PMD_SIZE - PAGE_SIZE)) == 0) {
                                if (pvmw->ptl) {
                                        spin_unlock(pvmw->ptl);
                                        pvmw->ptl = NULL;
                                }
+                               pte_unmap(pvmw->pte);
+                               pvmw->pte = NULL;
                                goto restart;
-                       } else {
-                               pvmw->pte++;
+                       }
+                       pvmw->pte++;
+                       if ((pvmw->flags & PVMW_SYNC) && !pvmw->ptl) {
+                               pvmw->ptl = pte_lockptr(mm, pvmw->pmd);
+                               spin_lock(pvmw->ptl);
                        }
                } while (pte_none(*pvmw->pte));
 
@@ -247,7 +286,10 @@ next_pte:
                        pvmw->ptl = pte_lockptr(mm, pvmw->pmd);
                        spin_lock(pvmw->ptl);
                }
-       }
+               goto this_pte;
+       } while (pvmw->address < end);
+
+       return false;
 }
 
 /**
@@ -266,14 +308,10 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma)
                .vma = vma,
                .flags = PVMW_SYNC,
        };
-       unsigned long start, end;
-
-       start = __vma_address(page, vma);
-       end = start + thp_size(page) - PAGE_SIZE;
 
-       if (unlikely(end < vma->vm_start || start >= vma->vm_end))
+       pvmw.address = vma_address(page, vma);
+       if (pvmw.address == -EFAULT)
                return 0;
-       pvmw.address = max(start, vma->vm_start);
        if (!page_vma_mapped_walk(&pvmw))
                return 0;
        page_vma_mapped_walk_done(&pvmw);
index c2210e1..4e640ba 100644 (file)
@@ -135,9 +135,8 @@ pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address,
 {
        pmd_t pmd;
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
-       VM_BUG_ON(!pmd_present(*pmdp));
-       /* Below assumes pmd_present() is true */
-       VM_BUG_ON(!pmd_trans_huge(*pmdp) && !pmd_devmap(*pmdp));
+       VM_BUG_ON(pmd_present(*pmdp) && !pmd_trans_huge(*pmdp) &&
+                          !pmd_devmap(*pmdp));
        pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
        flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        return pmd;
index 693a610..e05c300 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -707,7 +707,6 @@ static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags)
  */
 unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
 {
-       unsigned long address;
        if (PageAnon(page)) {
                struct anon_vma *page__anon_vma = page_anon_vma(page);
                /*
@@ -717,15 +716,13 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
                if (!vma->anon_vma || !page__anon_vma ||
                    vma->anon_vma->root != page__anon_vma->root)
                        return -EFAULT;
-       } else if (page->mapping) {
-               if (!vma->vm_file || vma->vm_file->f_mapping != page->mapping)
-                       return -EFAULT;
-       } else
+       } else if (!vma->vm_file) {
                return -EFAULT;
-       address = __vma_address(page, vma);
-       if (unlikely(address < vma->vm_start || address >= vma->vm_end))
+       } else if (vma->vm_file->f_mapping != compound_head(page)->mapping) {
                return -EFAULT;
-       return address;
+       }
+
+       return vma_address(page, vma);
 }
 
 pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address)
@@ -919,7 +916,7 @@ static bool page_mkclean_one(struct page *page, struct vm_area_struct *vma,
         */
        mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_PAGE,
                                0, vma, vma->vm_mm, address,
-                               min(vma->vm_end, address + page_size(page)));
+                               vma_address_end(page, vma));
        mmu_notifier_invalidate_range_start(&range);
 
        while (page_vma_mapped_walk(&pvmw)) {
@@ -1405,6 +1402,15 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
        struct mmu_notifier_range range;
        enum ttu_flags flags = (enum ttu_flags)(long)arg;
 
+       /*
+        * When racing against e.g. zap_pte_range() on another cpu,
+        * in between its ptep_get_and_clear_full() and page_remove_rmap(),
+        * try_to_unmap() may return false when it is about to become true,
+        * if page table locking is skipped: use TTU_SYNC to wait for that.
+        */
+       if (flags & TTU_SYNC)
+               pvmw.flags = PVMW_SYNC;
+
        /* munlock has nothing to gain from examining un-locked vmas */
        if ((flags & TTU_MUNLOCK) && !(vma->vm_flags & VM_LOCKED))
                return true;
@@ -1426,9 +1432,10 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
         * Note that the page can not be free in this function as call of
         * try_to_unmap() must hold a reference on the page.
         */
+       range.end = PageKsm(page) ?
+                       address + PAGE_SIZE : vma_address_end(page, vma);
        mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm,
-                               address,
-                               min(vma->vm_end, address + page_size(page)));
+                               address, range.end);
        if (PageHuge(page)) {
                /*
                 * If sharing is possible, start and end will be adjusted
@@ -1777,7 +1784,13 @@ bool try_to_unmap(struct page *page, enum ttu_flags flags)
        else
                rmap_walk(page, &rwc);
 
-       return !page_mapcount(page) ? true : false;
+       /*
+        * When racing against e.g. zap_pte_range() on another cpu,
+        * in between its ptep_get_and_clear_full() and page_remove_rmap(),
+        * try_to_unmap() may return false when it is about to become true,
+        * if page table locking is skipped: use TTU_SYNC to wait for that.
+        */
+       return !page_mapcount(page);
 }
 
 /**
@@ -1874,6 +1887,7 @@ static void rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
                struct vm_area_struct *vma = avc->vma;
                unsigned long address = vma_address(page, vma);
 
+               VM_BUG_ON_VMA(address == -EFAULT, vma);
                cond_resched();
 
                if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
@@ -1928,6 +1942,7 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
                        pgoff_start, pgoff_end) {
                unsigned long address = vma_address(page, vma);
 
+               VM_BUG_ON_VMA(address == -EFAULT, vma);
                cond_resched();
 
                if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
index 5d46611..14997a9 100644 (file)
@@ -2227,7 +2227,7 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
 }
 #endif
 
-int shmem_lock(struct file *file, int lock, struct user_struct *user)
+int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
 {
        struct inode *inode = file_inode(file);
        struct shmem_inode_info *info = SHMEM_I(inode);
@@ -2239,13 +2239,13 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
         * no serialization needed when called from shm_destroy().
         */
        if (lock && !(info->flags & VM_LOCKED)) {
-               if (!user_shm_lock(inode->i_size, user))
+               if (!user_shm_lock(inode->i_size, ucounts))
                        goto out_nomem;
                info->flags |= VM_LOCKED;
                mapping_set_unevictable(file->f_mapping);
        }
-       if (!lock && (info->flags & VM_LOCKED) && user) {
-               user_shm_unlock(inode->i_size, user);
+       if (!lock && (info->flags & VM_LOCKED) && ucounts) {
+               user_shm_unlock(inode->i_size, ucounts);
                info->flags &= ~VM_LOCKED;
                mapping_clear_unevictable(file->f_mapping);
        }
@@ -4092,7 +4092,7 @@ int shmem_unuse(unsigned int type, bool frontswap,
        return 0;
 }
 
-int shmem_lock(struct file *file, int lock, struct user_struct *user)
+int shmem_lock(struct file *file, int lock, struct ucounts *ucounts)
 {
        return 0;
 }
index a4a5714..7cab776 100644 (file)
@@ -97,8 +97,7 @@ EXPORT_SYMBOL(kmem_cache_size);
 #ifdef CONFIG_DEBUG_VM
 static int kmem_cache_sanity_check(const char *name, unsigned int size)
 {
-       if (!name || in_interrupt() || size < sizeof(void *) ||
-               size > KMALLOC_MAX_SIZE) {
+       if (!name || in_interrupt() || size > KMALLOC_MAX_SIZE) {
                pr_err("kmem_cache_create(%s) integrity check failed\n", name);
                return -EINVAL;
        }
index 3f96e09..61bd40e 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/bit_spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/swab.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include "slab.h"
@@ -712,15 +713,15 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
               p, p - addr, get_freepointer(s, p));
 
        if (s->flags & SLAB_RED_ZONE)
-               print_section(KERN_ERR, "Redzone ", p - s->red_left_pad,
+               print_section(KERN_ERR, "Redzone  ", p - s->red_left_pad,
                              s->red_left_pad);
        else if (p > addr + 16)
                print_section(KERN_ERR, "Bytes b4 ", p - 16, 16);
 
-       print_section(KERN_ERR, "Object ", p,
+       print_section(KERN_ERR,         "Object   ", p,
                      min_t(unsigned int, s->object_size, PAGE_SIZE));
        if (s->flags & SLAB_RED_ZONE)
-               print_section(KERN_ERR, "Redzone ", p + s->object_size,
+               print_section(KERN_ERR, "Redzone  ", p + s->object_size,
                        s->inuse - s->object_size);
 
        off = get_info_end(s);
@@ -732,7 +733,7 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
 
        if (off != size_from_object(s))
                /* Beginning of the filler is the free pointer */
-               print_section(KERN_ERR, "Padding ", p + off,
+               print_section(KERN_ERR, "Padding  ", p + off,
                              size_from_object(s) - off);
 
        dump_stack();
@@ -909,11 +910,11 @@ static int check_object(struct kmem_cache *s, struct page *page,
        u8 *endobject = object + s->object_size;
 
        if (s->flags & SLAB_RED_ZONE) {
-               if (!check_bytes_and_report(s, page, object, "Redzone",
+               if (!check_bytes_and_report(s, page, object, "Left Redzone",
                        object - s->red_left_pad, val, s->red_left_pad))
                        return 0;
 
-               if (!check_bytes_and_report(s, page, object, "Redzone",
+               if (!check_bytes_and_report(s, page, object, "Right Redzone",
                        endobject, val, s->inuse - s->object_size))
                        return 0;
        } else {
@@ -928,7 +929,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
                if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
                        (!check_bytes_and_report(s, page, p, "Poison", p,
                                        POISON_FREE, s->object_size - 1) ||
-                        !check_bytes_and_report(s, page, p, "Poison",
+                        !check_bytes_and_report(s, page, p, "End Poison",
                                p + s->object_size - 1, POISON_END, 1)))
                        return 0;
                /*
@@ -3689,7 +3690,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
        slab_flags_t flags = s->flags;
        unsigned int size = s->object_size;
-       unsigned int freepointer_area;
        unsigned int order;
 
        /*
@@ -3698,13 +3698,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
         * the possible location of the free pointer.
         */
        size = ALIGN(size, sizeof(void *));
-       /*
-        * This is the area of the object where a freepointer can be
-        * safely written. If redzoning adds more to the inuse size, we
-        * can't use that portion for writing the freepointer, so
-        * s->offset must be limited within this for the general case.
-        */
-       freepointer_area = size;
 
 #ifdef CONFIG_SLUB_DEBUG
        /*
@@ -3730,19 +3723,21 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 
        /*
         * With that we have determined the number of bytes in actual use
-        * by the object. This is the potential offset to the free pointer.
+        * by the object and redzoning.
         */
        s->inuse = size;
 
-       if (((flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) ||
-               s->ctor)) {
+       if ((flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) ||
+           ((flags & SLAB_RED_ZONE) && s->object_size < sizeof(void *)) ||
+           s->ctor) {
                /*
                 * Relocate free pointer after the object if it is not
                 * permitted to overwrite the first word of the object on
                 * kmem_cache_free.
                 *
                 * This is the case if we do RCU, have a constructor or
-                * destructor or are poisoning the objects.
+                * destructor, are poisoning the objects, or are
+                * redzoning an object smaller than sizeof(void *).
                 *
                 * The assumption that s->offset >= s->inuse means free
                 * pointer is outside of the object is used in the
@@ -3751,13 +3746,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                 */
                s->offset = size;
                size += sizeof(void *);
-       } else if (freepointer_area > sizeof(void *)) {
+       } else {
                /*
                 * Store freelist pointer near middle of object to keep
                 * it away from the edges of the object to avoid small
                 * sized over/underflows from neighboring allocations.
                 */
-               s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
+               s->offset = ALIGN_DOWN(s->object_size / 2, sizeof(void *));
        }
 
 #ifdef CONFIG_SLUB_DEBUG
index b2ada9d..55c18af 100644 (file)
@@ -344,6 +344,15 @@ size_t mem_section_usage_size(void)
        return sizeof(struct mem_section_usage) + usemap_size();
 }
 
+static inline phys_addr_t pgdat_to_phys(struct pglist_data *pgdat)
+{
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+       return __pa_symbol(pgdat);
+#else
+       return __pa(pgdat);
+#endif
+}
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 static struct mem_section_usage * __init
 sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
@@ -362,7 +371,7 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
         * from the same section as the pgdat where possible to avoid
         * this problem.
         */
-       goal = __pa(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
+       goal = pgdat_to_phys(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
        limit = goal + (1UL << PA_SECTION_SHIFT);
        nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
 again:
@@ -390,7 +399,7 @@ static void __init check_usemap_section_nr(int nid,
        }
 
        usemap_snr = pfn_to_section_nr(__pa(usage) >> PAGE_SHIFT);
-       pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
+       pgdat_snr = pfn_to_section_nr(pgdat_to_phys(pgdat) >> PAGE_SHIFT);
        if (usemap_snr == pgdat_snr)
                return;
 
index 149e774..996afa8 100644 (file)
@@ -1900,7 +1900,7 @@ unsigned int count_swap_pages(int type, int free)
 
 static inline int pte_same_as_swp(pte_t pte, pte_t swp_pte)
 {
-       return pte_same(pte_swp_clear_soft_dirty(pte), swp_pte);
+       return pte_same(pte_swp_clear_flags(pte), swp_pte);
 }
 
 /*
index 95af244..234ddd8 100644 (file)
@@ -167,13 +167,10 @@ void do_invalidatepage(struct page *page, unsigned int offset,
  * its lock, b) when a concurrent invalidate_mapping_pages got there first and
  * c) when tmpfs swizzles a page between a tmpfs inode and swapper_space.
  */
-static void
-truncate_cleanup_page(struct address_space *mapping, struct page *page)
+static void truncate_cleanup_page(struct page *page)
 {
-       if (page_mapped(page)) {
-               unsigned int nr = thp_nr_pages(page);
-               unmap_mapping_pages(mapping, page->index, nr, false);
-       }
+       if (page_mapped(page))
+               unmap_mapping_page(page);
 
        if (page_has_private(page))
                do_invalidatepage(page, 0, thp_size(page));
@@ -218,7 +215,7 @@ int truncate_inode_page(struct address_space *mapping, struct page *page)
        if (page->mapping != mapping)
                return -EIO;
 
-       truncate_cleanup_page(mapping, page);
+       truncate_cleanup_page(page);
        delete_from_page_cache(page);
        return 0;
 }
@@ -325,7 +322,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                index = indices[pagevec_count(&pvec) - 1] + 1;
                truncate_exceptional_pvec_entries(mapping, &pvec, indices);
                for (i = 0; i < pagevec_count(&pvec); i++)
-                       truncate_cleanup_page(mapping, pvec.pages[i]);
+                       truncate_cleanup_page(pvec.pages[i]);
                delete_from_page_cache_batch(mapping, &pvec);
                for (i = 0; i < pagevec_count(&pvec); i++)
                        unlock_page(pvec.pages[i]);
@@ -639,6 +636,16 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                continue;
                        }
 
+                       if (!did_range_unmap && page_mapped(page)) {
+                               /*
+                                * If page is mapped, before taking its lock,
+                                * zap the rest of the file in one hit.
+                                */
+                               unmap_mapping_pages(mapping, index,
+                                               (1 + end - index), false);
+                               did_range_unmap = 1;
+                       }
+
                        lock_page(page);
                        WARN_ON(page_to_index(page) != index);
                        if (page->mapping != mapping) {
@@ -646,23 +653,11 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                                continue;
                        }
                        wait_on_page_writeback(page);
-                       if (page_mapped(page)) {
-                               if (!did_range_unmap) {
-                                       /*
-                                        * Zap the rest of the file in one hit.
-                                        */
-                                       unmap_mapping_pages(mapping, index,
-                                               (1 + end - index), false);
-                                       did_range_unmap = 1;
-                               } else {
-                                       /*
-                                        * Just zap this page
-                                        */
-                                       unmap_mapping_pages(mapping, index,
-                                                               1, false);
-                               }
-                       }
+
+                       if (page_mapped(page))
+                               unmap_mapping_page(page);
                        BUG_ON(page_mapped(page));
+
                        ret2 = do_launder_page(mapping, page);
                        if (ret2 == 0) {
                                if (!invalidate_complete_page2(mapping, page))
index a13ac52..d0a7d89 100644 (file)
@@ -2344,15 +2344,16 @@ static void clear_vm_uninitialized_flag(struct vm_struct *vm)
 }
 
 static struct vm_struct *__get_vm_area_node(unsigned long size,
-               unsigned long align, unsigned long flags, unsigned long start,
-               unsigned long end, int node, gfp_t gfp_mask, const void *caller)
+               unsigned long align, unsigned long shift, unsigned long flags,
+               unsigned long start, unsigned long end, int node,
+               gfp_t gfp_mask, const void *caller)
 {
        struct vmap_area *va;
        struct vm_struct *area;
        unsigned long requested_size = size;
 
        BUG_ON(in_interrupt());
-       size = PAGE_ALIGN(size);
+       size = ALIGN(size, 1ul << shift);
        if (unlikely(!size))
                return NULL;
 
@@ -2384,8 +2385,8 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
                                       unsigned long start, unsigned long end,
                                       const void *caller)
 {
-       return __get_vm_area_node(size, 1, flags, start, end, NUMA_NO_NODE,
-                                 GFP_KERNEL, caller);
+       return __get_vm_area_node(size, 1, PAGE_SHIFT, flags, start, end,
+                                 NUMA_NO_NODE, GFP_KERNEL, caller);
 }
 
 /**
@@ -2401,7 +2402,8 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
  */
 struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
-       return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+       return __get_vm_area_node(size, 1, PAGE_SHIFT, flags,
+                                 VMALLOC_START, VMALLOC_END,
                                  NUMA_NO_NODE, GFP_KERNEL,
                                  __builtin_return_address(0));
 }
@@ -2409,7 +2411,8 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
                                const void *caller)
 {
-       return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+       return __get_vm_area_node(size, 1, PAGE_SHIFT, flags,
+                                 VMALLOC_START, VMALLOC_END,
                                  NUMA_NO_NODE, GFP_KERNEL, caller);
 }
 
@@ -2902,9 +2905,9 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
        }
 
 again:
-       size = PAGE_ALIGN(size);
-       area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED |
-                               vm_flags, start, end, node, gfp_mask, caller);
+       area = __get_vm_area_node(real_size, align, shift, VM_ALLOC |
+                                 VM_UNINITIALIZED | vm_flags, start, end, node,
+                                 gfp_mask, caller);
        if (!area) {
                warn_alloc(gfp_mask, NULL,
                           "vmalloc size %lu allocation failure: "
@@ -2923,6 +2926,7 @@ again:
         */
        clear_vm_uninitialized_flag(area);
 
+       size = PAGE_ALIGN(size);
        kmemleak_vmalloc(area, size, gfp_mask);
 
        return addr;
@@ -2999,6 +3003,23 @@ void *vmalloc(unsigned long size)
 EXPORT_SYMBOL(vmalloc);
 
 /**
+ * vmalloc_no_huge - allocate virtually contiguous memory using small pages
+ * @size:    allocation size
+ *
+ * Allocate enough non-huge pages to cover @size from the page level
+ * allocator and map them into contiguous kernel virtual space.
+ *
+ * Return: pointer to the allocated memory or %NULL on error
+ */
+void *vmalloc_no_huge(unsigned long size)
+{
+       return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
+                                   GFP_KERNEL, PAGE_KERNEL, VM_NO_HUGE_VMAP,
+                                   NUMA_NO_NODE, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(vmalloc_no_huge);
+
+/**
  * vzalloc - allocate virtually contiguous memory with zero fill
  * @size:    allocation size
  *
index be18af4..c7236da 100644 (file)
@@ -768,7 +768,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
        if (a && a->status & ATIF_PROBE) {
                a->status |= ATIF_PROBE_FAIL;
                /*
-                * we do not respond to probe or request packets for
+                * we do not respond to probe or request packets of
                 * this address while we are probing this address
                 */
                goto unlock;
index 789f257..fc8be49 100644 (file)
@@ -409,8 +409,10 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
        if (WARN_ON(!forw_packet->if_outgoing))
                return;
 
-       if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface))
+       if (forw_packet->if_outgoing->soft_iface != soft_iface) {
+               pr_warn("%s: soft interface switch for queued OGM\n", __func__);
                return;
+       }
 
        if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
                return;
index 372e3b2..7dd51da 100644 (file)
@@ -3229,7 +3229,7 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
 {
        struct l2cap_chan *chan;
 
-       bt_dev_dbg(pchan->conn->hcon->hdev, "pchan %p", pchan);
+       BT_DBG("pchan %p", pchan);
 
        chan = l2cap_chan_create();
        if (!chan)
@@ -3250,7 +3250,7 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
         */
        atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
 
-       bt_dev_dbg(pchan->conn->hcon->hdev, "created chan %p", chan);
+       BT_DBG("created chan %p", chan);
 
        return chan;
 }
@@ -3354,7 +3354,7 @@ static void smp_del_chan(struct l2cap_chan *chan)
 {
        struct smp_dev *smp;
 
-       bt_dev_dbg(chan->conn->hcon->hdev, "chan %p", chan);
+       BT_DBG("chan %p", chan);
 
        smp = chan->data;
        if (smp) {
index 7ce8a77..e013d33 100644 (file)
@@ -90,8 +90,8 @@ struct bridge_mcast_stats {
 #endif
 
 struct br_tunnel_info {
-       __be64                  tunnel_id;
-       struct metadata_dst     *tunnel_dst;
+       __be64                          tunnel_id;
+       struct metadata_dst __rcu       *tunnel_dst;
 };
 
 /* private vlan flags */
index 0d3a8c0..0101744 100644 (file)
@@ -41,26 +41,33 @@ static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl,
                                      br_vlan_tunnel_rht_params);
 }
 
+static void vlan_tunnel_info_release(struct net_bridge_vlan *vlan)
+{
+       struct metadata_dst *tdst = rtnl_dereference(vlan->tinfo.tunnel_dst);
+
+       WRITE_ONCE(vlan->tinfo.tunnel_id, 0);
+       RCU_INIT_POINTER(vlan->tinfo.tunnel_dst, NULL);
+       dst_release(&tdst->dst);
+}
+
 void vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
                          struct net_bridge_vlan *vlan)
 {
-       if (!vlan->tinfo.tunnel_dst)
+       if (!rcu_access_pointer(vlan->tinfo.tunnel_dst))
                return;
        rhashtable_remove_fast(&vg->tunnel_hash, &vlan->tnode,
                               br_vlan_tunnel_rht_params);
-       vlan->tinfo.tunnel_id = 0;
-       dst_release(&vlan->tinfo.tunnel_dst->dst);
-       vlan->tinfo.tunnel_dst = NULL;
+       vlan_tunnel_info_release(vlan);
 }
 
 static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
                                  struct net_bridge_vlan *vlan, u32 tun_id)
 {
-       struct metadata_dst *metadata = NULL;
+       struct metadata_dst *metadata = rtnl_dereference(vlan->tinfo.tunnel_dst);
        __be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id));
        int err;
 
-       if (vlan->tinfo.tunnel_dst)
+       if (metadata)
                return -EEXIST;
 
        metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY,
@@ -69,8 +76,8 @@ static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
                return -EINVAL;
 
        metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE;
-       vlan->tinfo.tunnel_dst = metadata;
-       vlan->tinfo.tunnel_id = key;
+       rcu_assign_pointer(vlan->tinfo.tunnel_dst, metadata);
+       WRITE_ONCE(vlan->tinfo.tunnel_id, key);
 
        err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode,
                                            br_vlan_tunnel_rht_params);
@@ -79,9 +86,7 @@ static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
 
        return 0;
 out:
-       dst_release(&vlan->tinfo.tunnel_dst->dst);
-       vlan->tinfo.tunnel_dst = NULL;
-       vlan->tinfo.tunnel_id = 0;
+       vlan_tunnel_info_release(vlan);
 
        return err;
 }
@@ -182,12 +187,15 @@ int br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
 int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
                                 struct net_bridge_vlan *vlan)
 {
+       struct metadata_dst *tunnel_dst;
+       __be64 tunnel_id;
        int err;
 
-       if (!vlan || !vlan->tinfo.tunnel_id)
+       if (!vlan)
                return 0;
 
-       if (unlikely(!skb_vlan_tag_present(skb)))
+       tunnel_id = READ_ONCE(vlan->tinfo.tunnel_id);
+       if (!tunnel_id || unlikely(!skb_vlan_tag_present(skb)))
                return 0;
 
        skb_dst_drop(skb);
@@ -195,7 +203,9 @@ int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
        if (err)
                return err;
 
-       skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst));
+       tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
+       if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
+               skb_dst_set(skb, &tunnel_dst->dst);
 
        return 0;
 }
index 909b9e6..f3e4d95 100644 (file)
@@ -125,7 +125,7 @@ struct bcm_sock {
        struct sock sk;
        int bound;
        int ifindex;
-       struct notifier_block notifier;
+       struct list_head notifier;
        struct list_head rx_ops;
        struct list_head tx_ops;
        unsigned long dropped_usr_msgs;
@@ -133,6 +133,10 @@ struct bcm_sock {
        char procname [32]; /* inode number in decimal with \0 */
 };
 
+static LIST_HEAD(bcm_notifier_list);
+static DEFINE_SPINLOCK(bcm_notifier_lock);
+static struct bcm_sock *bcm_busy_notifier;
+
 static inline struct bcm_sock *bcm_sk(const struct sock *sk)
 {
        return (struct bcm_sock *)sk;
@@ -402,6 +406,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
                if (!op->count && (op->flags & TX_COUNTEVT)) {
 
                        /* create notification to user */
+                       memset(&msg_head, 0, sizeof(msg_head));
                        msg_head.opcode  = TX_EXPIRED;
                        msg_head.flags   = op->flags;
                        msg_head.count   = op->count;
@@ -439,6 +444,7 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data)
        /* this element is not throttled anymore */
        data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV);
 
+       memset(&head, 0, sizeof(head));
        head.opcode  = RX_CHANGED;
        head.flags   = op->flags;
        head.count   = op->count;
@@ -560,6 +566,7 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
        }
 
        /* create notification to user */
+       memset(&msg_head, 0, sizeof(msg_head));
        msg_head.opcode  = RX_TIMEOUT;
        msg_head.flags   = op->flags;
        msg_head.count   = op->count;
@@ -1378,20 +1385,15 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 /*
  * notification handler for netdevice status changes
  */
-static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
-                       void *ptr)
+static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
+                      struct net_device *dev)
 {
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct bcm_sock *bo = container_of(nb, struct bcm_sock, notifier);
        struct sock *sk = &bo->sk;
        struct bcm_op *op;
        int notify_enodev = 0;
 
        if (!net_eq(dev_net(dev), sock_net(sk)))
-               return NOTIFY_DONE;
-
-       if (dev->type != ARPHRD_CAN)
-               return NOTIFY_DONE;
+               return;
 
        switch (msg) {
 
@@ -1426,7 +1428,28 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
                                sk->sk_error_report(sk);
                }
        }
+}
 
+static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
+                       void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+       if (dev->type != ARPHRD_CAN)
+               return NOTIFY_DONE;
+       if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
+               return NOTIFY_DONE;
+       if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */
+               return NOTIFY_DONE;
+
+       spin_lock(&bcm_notifier_lock);
+       list_for_each_entry(bcm_busy_notifier, &bcm_notifier_list, notifier) {
+               spin_unlock(&bcm_notifier_lock);
+               bcm_notify(bcm_busy_notifier, msg, dev);
+               spin_lock(&bcm_notifier_lock);
+       }
+       bcm_busy_notifier = NULL;
+       spin_unlock(&bcm_notifier_lock);
        return NOTIFY_DONE;
 }
 
@@ -1446,9 +1469,9 @@ static int bcm_init(struct sock *sk)
        INIT_LIST_HEAD(&bo->rx_ops);
 
        /* set notifier */
-       bo->notifier.notifier_call = bcm_notifier;
-
-       register_netdevice_notifier(&bo->notifier);
+       spin_lock(&bcm_notifier_lock);
+       list_add_tail(&bo->notifier, &bcm_notifier_list);
+       spin_unlock(&bcm_notifier_lock);
 
        return 0;
 }
@@ -1471,7 +1494,14 @@ static int bcm_release(struct socket *sock)
 
        /* remove bcm_ops, timer, rx_unregister(), etc. */
 
-       unregister_netdevice_notifier(&bo->notifier);
+       spin_lock(&bcm_notifier_lock);
+       while (bcm_busy_notifier == bo) {
+               spin_unlock(&bcm_notifier_lock);
+               schedule_timeout_uninterruptible(1);
+               spin_lock(&bcm_notifier_lock);
+       }
+       list_del(&bo->notifier);
+       spin_unlock(&bcm_notifier_lock);
 
        lock_sock(sk);
 
@@ -1692,6 +1722,10 @@ static struct pernet_operations canbcm_pernet_ops __read_mostly = {
        .exit = canbcm_pernet_exit,
 };
 
+static struct notifier_block canbcm_notifier = {
+       .notifier_call = bcm_notifier
+};
+
 static int __init bcm_module_init(void)
 {
        int err;
@@ -1705,12 +1739,14 @@ static int __init bcm_module_init(void)
        }
 
        register_pernet_subsys(&canbcm_pernet_ops);
+       register_netdevice_notifier(&canbcm_notifier);
        return 0;
 }
 
 static void __exit bcm_module_exit(void)
 {
        can_proto_unregister(&bcm_can_proto);
+       unregister_netdevice_notifier(&canbcm_notifier);
        unregister_pernet_subsys(&canbcm_pernet_ops);
 }
 
index 253b244..be6183f 100644 (file)
@@ -143,10 +143,14 @@ struct isotp_sock {
        u32 force_tx_stmin;
        u32 force_rx_stmin;
        struct tpcon rx, tx;
-       struct notifier_block notifier;
+       struct list_head notifier;
        wait_queue_head_t wait;
 };
 
+static LIST_HEAD(isotp_notifier_list);
+static DEFINE_SPINLOCK(isotp_notifier_lock);
+static struct isotp_sock *isotp_busy_notifier;
+
 static inline struct isotp_sock *isotp_sk(const struct sock *sk)
 {
        return (struct isotp_sock *)sk;
@@ -1013,7 +1017,14 @@ static int isotp_release(struct socket *sock)
        /* wait for complete transmission of current pdu */
        wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
 
-       unregister_netdevice_notifier(&so->notifier);
+       spin_lock(&isotp_notifier_lock);
+       while (isotp_busy_notifier == so) {
+               spin_unlock(&isotp_notifier_lock);
+               schedule_timeout_uninterruptible(1);
+               spin_lock(&isotp_notifier_lock);
+       }
+       list_del(&so->notifier);
+       spin_unlock(&isotp_notifier_lock);
 
        lock_sock(sk);
 
@@ -1317,21 +1328,16 @@ static int isotp_getsockopt(struct socket *sock, int level, int optname,
        return 0;
 }
 
-static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
-                         void *ptr)
+static void isotp_notify(struct isotp_sock *so, unsigned long msg,
+                        struct net_device *dev)
 {
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct isotp_sock *so = container_of(nb, struct isotp_sock, notifier);
        struct sock *sk = &so->sk;
 
        if (!net_eq(dev_net(dev), sock_net(sk)))
-               return NOTIFY_DONE;
-
-       if (dev->type != ARPHRD_CAN)
-               return NOTIFY_DONE;
+               return;
 
        if (so->ifindex != dev->ifindex)
-               return NOTIFY_DONE;
+               return;
 
        switch (msg) {
        case NETDEV_UNREGISTER:
@@ -1357,7 +1363,28 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
                        sk->sk_error_report(sk);
                break;
        }
+}
 
+static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
+                         void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+       if (dev->type != ARPHRD_CAN)
+               return NOTIFY_DONE;
+       if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
+               return NOTIFY_DONE;
+       if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
+               return NOTIFY_DONE;
+
+       spin_lock(&isotp_notifier_lock);
+       list_for_each_entry(isotp_busy_notifier, &isotp_notifier_list, notifier) {
+               spin_unlock(&isotp_notifier_lock);
+               isotp_notify(isotp_busy_notifier, msg, dev);
+               spin_lock(&isotp_notifier_lock);
+       }
+       isotp_busy_notifier = NULL;
+       spin_unlock(&isotp_notifier_lock);
        return NOTIFY_DONE;
 }
 
@@ -1394,8 +1421,9 @@ static int isotp_init(struct sock *sk)
 
        init_waitqueue_head(&so->wait);
 
-       so->notifier.notifier_call = isotp_notifier;
-       register_netdevice_notifier(&so->notifier);
+       spin_lock(&isotp_notifier_lock);
+       list_add_tail(&so->notifier, &isotp_notifier_list);
+       spin_unlock(&isotp_notifier_lock);
 
        return 0;
 }
@@ -1442,6 +1470,10 @@ static const struct can_proto isotp_can_proto = {
        .prot = &isotp_proto,
 };
 
+static struct notifier_block canisotp_notifier = {
+       .notifier_call = isotp_notifier
+};
+
 static __init int isotp_module_init(void)
 {
        int err;
@@ -1451,6 +1483,8 @@ static __init int isotp_module_init(void)
        err = can_proto_register(&isotp_can_proto);
        if (err < 0)
                pr_err("can: registration of isotp protocol failed\n");
+       else
+               register_netdevice_notifier(&canisotp_notifier);
 
        return err;
 }
@@ -1458,6 +1492,7 @@ static __init int isotp_module_init(void)
 static __exit void isotp_module_exit(void)
 {
        can_proto_unregister(&isotp_can_proto);
+       unregister_netdevice_notifier(&canisotp_notifier);
 }
 
 module_init(isotp_module_init);
index e09d087..c3946c3 100644 (file)
@@ -330,6 +330,9 @@ static void j1939_session_skb_drop_old(struct j1939_session *session)
 
        if ((do_skcb->offset + do_skb->len) < offset_start) {
                __skb_unlink(do_skb, &session->skb_queue);
+               /* drop ref taken in j1939_session_skb_queue() */
+               skb_unref(do_skb);
+
                kfree_skb(do_skb);
        }
        spin_unlock_irqrestore(&session->skb_queue.lock, flags);
@@ -349,12 +352,13 @@ void j1939_session_skb_queue(struct j1939_session *session,
 
        skcb->flags |= J1939_ECU_LOCAL_SRC;
 
+       skb_get(skb);
        skb_queue_tail(&session->skb_queue, skb);
 }
 
 static struct
-sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
-                                         unsigned int offset_start)
+sk_buff *j1939_session_skb_get_by_offset(struct j1939_session *session,
+                                        unsigned int offset_start)
 {
        struct j1939_priv *priv = session->priv;
        struct j1939_sk_buff_cb *do_skcb;
@@ -371,6 +375,10 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
                        skb = do_skb;
                }
        }
+
+       if (skb)
+               skb_get(skb);
+
        spin_unlock_irqrestore(&session->skb_queue.lock, flags);
 
        if (!skb)
@@ -381,12 +389,12 @@ sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
        return skb;
 }
 
-static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
+static struct sk_buff *j1939_session_skb_get(struct j1939_session *session)
 {
        unsigned int offset_start;
 
        offset_start = session->pkt.dpo * 7;
-       return j1939_session_skb_find_by_offset(session, offset_start);
+       return j1939_session_skb_get_by_offset(session, offset_start);
 }
 
 /* see if we are receiver
@@ -776,7 +784,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
        int ret = 0;
        u8 dat[8];
 
-       se_skb = j1939_session_skb_find_by_offset(session, session->pkt.tx * 7);
+       se_skb = j1939_session_skb_get_by_offset(session, session->pkt.tx * 7);
        if (!se_skb)
                return -ENOBUFS;
 
@@ -801,7 +809,8 @@ static int j1939_session_tx_dat(struct j1939_session *session)
                        netdev_err_once(priv->ndev,
                                        "%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n",
                                        __func__, session, skcb->offset, se_skb->len , session->pkt.tx);
-                       return -EOVERFLOW;
+                       ret = -EOVERFLOW;
+                       goto out_free;
                }
 
                if (!len) {
@@ -835,6 +844,12 @@ static int j1939_session_tx_dat(struct j1939_session *session)
        if (pkt_done)
                j1939_tp_set_rxtimeout(session, 250);
 
+ out_free:
+       if (ret)
+               kfree_skb(se_skb);
+       else
+               consume_skb(se_skb);
+
        return ret;
 }
 
@@ -1007,7 +1022,7 @@ static int j1939_xtp_txnext_receiver(struct j1939_session *session)
 static int j1939_simple_txnext(struct j1939_session *session)
 {
        struct j1939_priv *priv = session->priv;
-       struct sk_buff *se_skb = j1939_session_skb_find(session);
+       struct sk_buff *se_skb = j1939_session_skb_get(session);
        struct sk_buff *skb;
        int ret;
 
@@ -1015,8 +1030,10 @@ static int j1939_simple_txnext(struct j1939_session *session)
                return 0;
 
        skb = skb_clone(se_skb, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
 
        can_skb_set_owner(skb, se_skb->sk);
 
@@ -1024,12 +1041,18 @@ static int j1939_simple_txnext(struct j1939_session *session)
 
        ret = j1939_send_one(priv, skb);
        if (ret)
-               return ret;
+               goto out_free;
 
        j1939_sk_errqueue(session, J1939_ERRQUEUE_SCHED);
        j1939_sk_queue_activate_next(session);
 
-       return 0;
+ out_free:
+       if (ret)
+               kfree_skb(se_skb);
+       else
+               consume_skb(se_skb);
+
+       return ret;
 }
 
 static bool j1939_session_deactivate_locked(struct j1939_session *session)
@@ -1170,9 +1193,10 @@ static void j1939_session_completed(struct j1939_session *session)
        struct sk_buff *skb;
 
        if (!session->transmission) {
-               skb = j1939_session_skb_find(session);
+               skb = j1939_session_skb_get(session);
                /* distribute among j1939 receivers */
                j1939_sk_recv(session->priv, skb);
+               consume_skb(skb);
        }
 
        j1939_session_deactivate_activate_next(session);
@@ -1744,7 +1768,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
 {
        struct j1939_priv *priv = session->priv;
        struct j1939_sk_buff_cb *skcb;
-       struct sk_buff *se_skb;
+       struct sk_buff *se_skb = NULL;
        const u8 *dat;
        u8 *tpdat;
        int offset;
@@ -1786,7 +1810,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
                goto out_session_cancel;
        }
 
-       se_skb = j1939_session_skb_find_by_offset(session, packet * 7);
+       se_skb = j1939_session_skb_get_by_offset(session, packet * 7);
        if (!se_skb) {
                netdev_warn(priv->ndev, "%s: 0x%p: no skb found\n", __func__,
                            session);
@@ -1848,11 +1872,13 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
                j1939_tp_set_rxtimeout(session, 250);
        }
        session->last_cmd = 0xff;
+       consume_skb(se_skb);
        j1939_session_put(session);
 
        return;
 
  out_session_cancel:
+       kfree_skb(se_skb);
        j1939_session_timers_cancel(session);
        j1939_session_cancel(session, J1939_XTP_ABORT_FAULT);
        j1939_session_put(session);
index 139d947..ac96fc2 100644 (file)
@@ -83,7 +83,7 @@ struct raw_sock {
        struct sock sk;
        int bound;
        int ifindex;
-       struct notifier_block notifier;
+       struct list_head notifier;
        int loopback;
        int recv_own_msgs;
        int fd_frames;
@@ -95,6 +95,10 @@ struct raw_sock {
        struct uniqframe __percpu *uniq;
 };
 
+static LIST_HEAD(raw_notifier_list);
+static DEFINE_SPINLOCK(raw_notifier_lock);
+static struct raw_sock *raw_busy_notifier;
+
 /* Return pointer to store the extra msg flags for raw_recvmsg().
  * We use the space of one unsigned int beyond the 'struct sockaddr_can'
  * in skb->cb.
@@ -263,21 +267,16 @@ static int raw_enable_allfilters(struct net *net, struct net_device *dev,
        return err;
 }
 
-static int raw_notifier(struct notifier_block *nb,
-                       unsigned long msg, void *ptr)
+static void raw_notify(struct raw_sock *ro, unsigned long msg,
+                      struct net_device *dev)
 {
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
        struct sock *sk = &ro->sk;
 
        if (!net_eq(dev_net(dev), sock_net(sk)))
-               return NOTIFY_DONE;
-
-       if (dev->type != ARPHRD_CAN)
-               return NOTIFY_DONE;
+               return;
 
        if (ro->ifindex != dev->ifindex)
-               return NOTIFY_DONE;
+               return;
 
        switch (msg) {
        case NETDEV_UNREGISTER:
@@ -305,7 +304,28 @@ static int raw_notifier(struct notifier_block *nb,
                        sk->sk_error_report(sk);
                break;
        }
+}
+
+static int raw_notifier(struct notifier_block *nb, unsigned long msg,
+                       void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+       if (dev->type != ARPHRD_CAN)
+               return NOTIFY_DONE;
+       if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
+               return NOTIFY_DONE;
+       if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */
+               return NOTIFY_DONE;
 
+       spin_lock(&raw_notifier_lock);
+       list_for_each_entry(raw_busy_notifier, &raw_notifier_list, notifier) {
+               spin_unlock(&raw_notifier_lock);
+               raw_notify(raw_busy_notifier, msg, dev);
+               spin_lock(&raw_notifier_lock);
+       }
+       raw_busy_notifier = NULL;
+       spin_unlock(&raw_notifier_lock);
        return NOTIFY_DONE;
 }
 
@@ -334,9 +354,9 @@ static int raw_init(struct sock *sk)
                return -ENOMEM;
 
        /* set notifier */
-       ro->notifier.notifier_call = raw_notifier;
-
-       register_netdevice_notifier(&ro->notifier);
+       spin_lock(&raw_notifier_lock);
+       list_add_tail(&ro->notifier, &raw_notifier_list);
+       spin_unlock(&raw_notifier_lock);
 
        return 0;
 }
@@ -351,7 +371,14 @@ static int raw_release(struct socket *sock)
 
        ro = raw_sk(sk);
 
-       unregister_netdevice_notifier(&ro->notifier);
+       spin_lock(&raw_notifier_lock);
+       while (raw_busy_notifier == ro) {
+               spin_unlock(&raw_notifier_lock);
+               schedule_timeout_uninterruptible(1);
+               spin_lock(&raw_notifier_lock);
+       }
+       list_del(&ro->notifier);
+       spin_unlock(&raw_notifier_lock);
 
        lock_sock(sk);
 
@@ -889,6 +916,10 @@ static const struct can_proto raw_can_proto = {
        .prot       = &raw_proto,
 };
 
+static struct notifier_block canraw_notifier = {
+       .notifier_call = raw_notifier
+};
+
 static __init int raw_module_init(void)
 {
        int err;
@@ -898,6 +929,8 @@ static __init int raw_module_init(void)
        err = can_proto_register(&raw_can_proto);
        if (err < 0)
                pr_err("can: registration of raw protocol failed\n");
+       else
+               register_netdevice_notifier(&canraw_notifier);
 
        return err;
 }
@@ -905,6 +938,7 @@ static __init int raw_module_init(void)
 static __exit void raw_module_exit(void)
 {
        can_proto_unregister(&raw_can_proto);
+       unregister_netdevice_notifier(&canraw_notifier);
 }
 
 module_init(raw_module_init);
index de407e8..d2b268a 100644 (file)
@@ -36,7 +36,7 @@ static int init_protocol(struct ceph_auth_client *ac, int proto)
        }
 }
 
-static void set_global_id(struct ceph_auth_client *ac, u64 global_id)
+void ceph_auth_set_global_id(struct ceph_auth_client *ac, u64 global_id)
 {
        dout("%s global_id %llu\n", __func__, global_id);
 
@@ -260,19 +260,22 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
                ac->negotiating = false;
        }
 
-       ret = ac->ops->handle_reply(ac, result, payload, payload_end,
+       if (result) {
+               pr_err("auth protocol '%s' mauth authentication failed: %d\n",
+                      ceph_auth_proto_name(ac->protocol), result);
+               ret = result;
+               goto out;
+       }
+
+       ret = ac->ops->handle_reply(ac, global_id, payload, payload_end,
                                    NULL, NULL, NULL, NULL);
        if (ret == -EAGAIN) {
                ret = build_request(ac, true, reply_buf, reply_len);
                goto out;
        } else if (ret) {
-               pr_err("auth protocol '%s' mauth authentication failed: %d\n",
-                      ceph_auth_proto_name(ac->protocol), result);
                goto out;
        }
 
-       set_global_id(ac, global_id);
-
 out:
        mutex_unlock(&ac->mutex);
        return ret;
@@ -498,11 +501,10 @@ int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
        int ret;
 
        mutex_lock(&ac->mutex);
-       ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
+       ret = ac->ops->handle_reply(ac, global_id, reply, reply + reply_len,
                                    session_key, session_key_len,
                                    con_secret, con_secret_len);
-       if (!ret)
-               set_global_id(ac, global_id);
+       WARN_ON(ret == -EAGAIN || ret > 0);
        mutex_unlock(&ac->mutex);
        return ret;
 }
index 70e86e4..097e9f8 100644 (file)
@@ -69,7 +69,7 @@ static int build_request(struct ceph_auth_client *ac, void *buf, void *end)
  * the generic auth code decode the global_id, and we carry no actual
  * authenticate state, so nothing happens here.
  */
-static int handle_reply(struct ceph_auth_client *ac, int result,
+static int handle_reply(struct ceph_auth_client *ac, u64 global_id,
                        void *buf, void *end, u8 *session_key,
                        int *session_key_len, u8 *con_secret,
                        int *con_secret_len)
@@ -77,7 +77,8 @@ static int handle_reply(struct ceph_auth_client *ac, int result,
        struct ceph_auth_none_info *xi = ac->private;
 
        xi->starting = false;
-       return result;
+       ceph_auth_set_global_id(ac, global_id);
+       return 0;
 }
 
 static void ceph_auth_none_destroy_authorizer(struct ceph_authorizer *a)
index 79641c4..b71b163 100644 (file)
@@ -597,7 +597,7 @@ bad:
        return -EINVAL;
 }
 
-static int handle_auth_session_key(struct ceph_auth_client *ac,
+static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id,
                                   void **p, void *end,
                                   u8 *session_key, int *session_key_len,
                                   u8 *con_secret, int *con_secret_len)
@@ -613,6 +613,7 @@ static int handle_auth_session_key(struct ceph_auth_client *ac,
        if (ret)
                return ret;
 
+       ceph_auth_set_global_id(ac, global_id);
        if (*p == end) {
                /* pre-nautilus (or didn't request service tickets!) */
                WARN_ON(session_key || con_secret);
@@ -661,7 +662,7 @@ e_inval:
        return -EINVAL;
 }
 
-static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
+static int ceph_x_handle_reply(struct ceph_auth_client *ac, u64 global_id,
                               void *buf, void *end,
                               u8 *session_key, int *session_key_len,
                               u8 *con_secret, int *con_secret_len)
@@ -669,13 +670,11 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
        struct ceph_x_info *xi = ac->private;
        struct ceph_x_ticket_handler *th;
        int len = end - buf;
+       int result;
        void *p;
        int op;
        int ret;
 
-       if (result)
-               return result;  /* XXX hmm? */
-
        if (xi->starting) {
                /* it's a hello */
                struct ceph_x_server_challenge *sc = buf;
@@ -697,9 +696,9 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
        switch (op) {
        case CEPHX_GET_AUTH_SESSION_KEY:
                /* AUTH ticket + [connection secret] + service tickets */
-               ret = handle_auth_session_key(ac, &p, end, session_key,
-                                             session_key_len, con_secret,
-                                             con_secret_len);
+               ret = handle_auth_session_key(ac, global_id, &p, end,
+                                             session_key, session_key_len,
+                                             con_secret, con_secret_len);
                break;
 
        case CEPHX_GET_PRINCIPAL_SESSION_KEY:
index ef8cf76..2512f67 100644 (file)
@@ -4363,7 +4363,7 @@ static inline void ____napi_schedule(struct softnet_data *sd,
                         * makes sure to proceed with napi polling
                         * if the thread is explicitly woken from here.
                         */
-                       if (READ_ONCE(thread->state) != TASK_INTERRUPTIBLE)
+                       if (READ_ONCE(thread->__state) != TASK_INTERRUPTIBLE)
                                set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
                        wake_up_process(thread);
                        return;
index 65ab4e2..d81352c 100644 (file)
@@ -17,6 +17,7 @@
  * Kris Katterjohn - Added many additional checks in bpf_check_classic()
  */
 
+#include <linux/atomic.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -41,7 +42,6 @@
 #include <linux/timer.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
-#include <asm/cmpxchg.h>
 #include <linux/filter.h>
 #include <linux/ratelimit.h>
 #include <linux/seccomp.h>
index 98f20ef..bf77457 100644 (file)
@@ -238,6 +238,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
 
                        write_lock(&n->lock);
                        if ((n->nud_state == NUD_FAILED) ||
+                           (n->nud_state == NUD_NOARP) ||
                            (tbl->is_multicast &&
                             tbl->is_multicast(n->primary_key)) ||
                            time_after(tref, n->updated))
index 43b6ac4..9b5a767 100644 (file)
@@ -641,6 +641,18 @@ void __put_net(struct net *net)
 }
 EXPORT_SYMBOL_GPL(__put_net);
 
+/**
+ * get_net_ns - increment the refcount of the network namespace
+ * @ns: common namespace (net)
+ *
+ * Returns the net's common namespace.
+ */
+struct ns_common *get_net_ns(struct ns_common *ns)
+{
+       return &get_net(container_of(ns, struct net, ns))->ns;
+}
+EXPORT_SYMBOL_GPL(get_net_ns);
+
 struct net *get_net_ns_by_fd(int fd)
 {
        struct file *file;
@@ -660,14 +672,8 @@ struct net *get_net_ns_by_fd(int fd)
        fput(file);
        return net;
 }
-
-#else
-struct net *get_net_ns_by_fd(int fd)
-{
-       return ERR_PTR(-EINVAL);
-}
-#endif
 EXPORT_SYMBOL_GPL(get_net_ns_by_fd);
+#endif
 
 struct net *get_net_ns_by_pid(pid_t pid)
 {
index 3e84279..ec931b0 100644 (file)
@@ -4842,10 +4842,12 @@ static int rtnl_bridge_notify(struct net_device *dev)
        if (err < 0)
                goto errout;
 
-       if (!skb->len) {
-               err = -EINVAL;
+       /* Notification info is only filled for bridge ports, not the bridge
+        * device itself. Therefore, a zero notification length is valid and
+        * should not result in an error.
+        */
+       if (!skb->len)
                goto errout;
-       }
 
        rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
        return 0;
index 3ad2287..bbc3b4b 100644 (file)
@@ -1253,6 +1253,7 @@ static void __msg_zerocopy_callback(struct ubuf_info *uarg)
        struct sock *sk = skb->sk;
        struct sk_buff_head *q;
        unsigned long flags;
+       bool is_zerocopy;
        u32 lo, hi;
        u16 len;
 
@@ -1267,6 +1268,7 @@ static void __msg_zerocopy_callback(struct ubuf_info *uarg)
        len = uarg->len;
        lo = uarg->id;
        hi = uarg->id + len - 1;
+       is_zerocopy = uarg->zerocopy;
 
        serr = SKB_EXT_ERR(skb);
        memset(serr, 0, sizeof(*serr));
@@ -1274,7 +1276,7 @@ static void __msg_zerocopy_callback(struct ubuf_info *uarg)
        serr->ee.ee_origin = SO_EE_ORIGIN_ZEROCOPY;
        serr->ee.ee_data = hi;
        serr->ee.ee_info = lo;
-       if (!uarg->zerocopy)
+       if (!is_zerocopy)
                serr->ee.ee_code |= SO_EE_CODE_ZEROCOPY_COPIED;
 
        q = &sk->sk_error_queue;
index 2a6733a..5d38e90 100644 (file)
@@ -95,7 +95,7 @@ static int get_module_eeprom_by_page(struct net_device *dev,
        if (dev->sfp_bus)
                return sfp_get_module_eeprom_by_page(dev->sfp_bus, page_data, extack);
 
-       if (ops->get_module_info)
+       if (ops->get_module_eeprom_by_page)
                return ops->get_module_eeprom_by_page(dev, page_data, extack);
 
        return -EOPNOTSUPP;
index 3fa7a39..baa5d10 100644 (file)
@@ -1421,7 +1421,7 @@ static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
        if (eeprom.offset + eeprom.len > total_len)
                return -EINVAL;
 
-       data = kmalloc(PAGE_SIZE, GFP_USER);
+       data = kzalloc(PAGE_SIZE, GFP_USER);
        if (!data)
                return -ENOMEM;
 
@@ -1486,7 +1486,7 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
        if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
                return -EINVAL;
 
-       data = kmalloc(PAGE_SIZE, GFP_USER);
+       data = kzalloc(PAGE_SIZE, GFP_USER);
        if (!data)
                return -ENOMEM;
 
@@ -1765,7 +1765,7 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
                return -EFAULT;
 
        test.len = test_len;
-       data = kmalloc_array(test_len, sizeof(u64), GFP_USER);
+       data = kcalloc(test_len, sizeof(u64), GFP_USER);
        if (!data)
                return -ENOMEM;
 
@@ -2293,7 +2293,7 @@ static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
        ret = ethtool_tunable_valid(&tuna);
        if (ret)
                return ret;
-       data = kmalloc(tuna.len, GFP_USER);
+       data = kzalloc(tuna.len, GFP_USER);
        if (!data)
                return -ENOMEM;
        ret = ops->get_tunable(dev, &tuna, data);
@@ -2485,7 +2485,7 @@ static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
        ret = ethtool_phy_tunable_valid(&tuna);
        if (ret)
                return ret;
-       data = kmalloc(tuna.len, GFP_USER);
+       data = kzalloc(tuna.len, GFP_USER);
        if (!data)
                return -ENOMEM;
        if (phy_drv_tunable) {
index b3029ff..2d51b7a 100644 (file)
@@ -353,6 +353,8 @@ static int strset_reply_size(const struct ethnl_req_info *req_base,
        int len = 0;
        int ret;
 
+       len += nla_total_size(0); /* ETHTOOL_A_STRSET_STRINGSETS */
+
        for (i = 0; i < ETH_SS_COUNT; i++) {
                const struct strset_info *set_info = &data->sets[i];
 
index f17870e..2f94d22 100644 (file)
@@ -575,7 +575,7 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr,
                        return err;
        }
 
-       if (!inet_sk(sk)->inet_num && inet_autobind(sk))
+       if (data_race(!inet_sk(sk)->inet_num) && inet_autobind(sk))
                return -EAGAIN;
        return sk->sk_prot->connect(sk, uaddr, addr_len);
 }
@@ -803,7 +803,7 @@ int inet_send_prepare(struct sock *sk)
        sock_rps_record_flow(sk);
 
        /* We may need to bind the socket. */
-       if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
+       if (data_race(!inet_sk(sk)->inet_num) && !sk->sk_prot->no_autobind &&
            inet_autobind(sk))
                return -EAGAIN;
 
index 36ed85b..fab0958 100644 (file)
@@ -450,6 +450,7 @@ static int ah4_err(struct sk_buff *skb, u32 info)
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
                        return 0;
+               break;
        case ICMP_REDIRECT:
                break;
        default:
index bfaf327..e0480c6 100644 (file)
@@ -472,6 +472,7 @@ void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
                kfree(doi_def->map.std->lvl.local);
                kfree(doi_def->map.std->cat.cipso);
                kfree(doi_def->map.std->cat.local);
+               kfree(doi_def->map.std);
                break;
        }
        kfree(doi_def);
index 2e35f68..1c6429c 100644 (file)
@@ -1989,7 +1989,7 @@ static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
                return -EAFNOSUPPORT;
 
        if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0)
-               BUG();
+               return -EINVAL;
 
        if (tb[IFLA_INET_CONF]) {
                nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
index 35803ab..8e3b445 100644 (file)
@@ -982,6 +982,7 @@ static int esp4_err(struct sk_buff *skb, u32 info)
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
                        return 0;
+               break;
        case ICMP_REDIRECT:
                break;
        default:
index a632b66..4c0c33e 100644 (file)
@@ -1874,6 +1874,7 @@ static int call_fib_nh_notifiers(struct fib_nh *nh,
                    (nh->fib_nh_flags & RTNH_F_DEAD))
                        return call_fib4_notifiers(dev_net(nh->fib_nh_dev),
                                                   event_type, &info.info);
+               break;
        default:
                break;
        }
index 7b6931a..752e392 100644 (file)
@@ -759,6 +759,13 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
                icmp_param.data_len = room;
        icmp_param.head_len = sizeof(struct icmphdr);
 
+       /* if we don't have a source address at this point, fall back to the
+        * dummy address instead of sending out a packet with a source address
+        * of 0.0.0.0
+        */
+       if (!fl4.saddr)
+               fl4.saddr = htonl(INADDR_DUMMY);
+
        icmp_push_reply(&icmp_param, &fl4, &ipc, &rt);
 ende:
        ip_rt_put(rt);
index 7b272bb..6b3c558 100644 (file)
@@ -1801,6 +1801,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
        while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
                in_dev->mc_list = i->next_rcu;
                in_dev->mc_count--;
+               ip_mc_clear_src(i);
                ip_ma_put(i);
        }
 }
index 31c6c6d..eb560ee 100644 (file)
@@ -351,6 +351,7 @@ static int vti4_err(struct sk_buff *skb, u32 info)
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
                        return 0;
+               break;
        case ICMP_REDIRECT:
                break;
        default:
index b426832..bbb56f5 100644 (file)
@@ -31,6 +31,7 @@ static int ipcomp4_err(struct sk_buff *skb, u32 info)
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
                        return 0;
+               break;
        case ICMP_REDIRECT:
                break;
        default:
index 1c9f71a..95a7183 100644 (file)
@@ -954,6 +954,7 @@ bool ping_rcv(struct sk_buff *skb)
        struct sock *sk;
        struct net *net = dev_net(skb->dev);
        struct icmphdr *icmph = icmp_hdr(skb);
+       bool rc = false;
 
        /* We assume the packet has already been checked by icmp_rcv */
 
@@ -968,14 +969,15 @@ bool ping_rcv(struct sk_buff *skb)
                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
                pr_debug("rcv on socket %p\n", sk);
-               if (skb2)
-                       ping_queue_rcv_skb(sk, skb2);
+               if (skb2 && !ping_queue_rcv_skb(sk, skb2))
+                       rc = true;
                sock_put(sk);
-               return true;
        }
-       pr_debug("no socket, dropping\n");
 
-       return false;
+       if (!rc)
+               pr_debug("no socket, dropping\n");
+
+       return rc;
 }
 EXPORT_SYMBOL_GPL(ping_rcv);
 
index f6787c5..6a36ac9 100644 (file)
@@ -2056,6 +2056,19 @@ martian_source:
        return err;
 }
 
+/* get device for dst_alloc with local routes */
+static struct net_device *ip_rt_get_dev(struct net *net,
+                                       const struct fib_result *res)
+{
+       struct fib_nh_common *nhc = res->fi ? res->nhc : NULL;
+       struct net_device *dev = NULL;
+
+       if (nhc)
+               dev = l3mdev_master_dev_rcu(nhc->nhc_dev);
+
+       return dev ? : net->loopback_dev;
+}
+
 /*
  *     NOTE. We drop all the packets that has local source
  *     addresses, because every properly looped back packet
@@ -2212,7 +2225,7 @@ local_input:
                }
        }
 
-       rth = rt_dst_alloc(l3mdev_master_dev_rcu(dev) ? : net->loopback_dev,
+       rth = rt_dst_alloc(ip_rt_get_dev(net, res),
                           flags | RTCF_LOCAL, res->type,
                           IN_DEV_ORCONF(in_dev, NOPOLICY), false);
        if (!rth)
index 15f5504..1307ad0 100644 (file)
@@ -2607,6 +2607,9 @@ void udp_destroy_sock(struct sock *sk)
 {
        struct udp_sock *up = udp_sk(sk);
        bool slow = lock_sock_fast(sk);
+
+       /* protects from races with udp_abort() */
+       sock_set_flag(sk, SOCK_DEAD);
        udp_flush_pending_frames(sk);
        unlock_sock_fast(sk, slow);
        if (static_branch_unlikely(&udp_encap_needed_key)) {
@@ -2857,10 +2860,17 @@ int udp_abort(struct sock *sk, int err)
 {
        lock_sock(sk);
 
+       /* udp{v6}_destroy_sock() sets it under the sk lock, avoid racing
+        * with close()
+        */
+       if (sock_flag(sk, SOCK_DEAD))
+               goto out;
+
        sk->sk_err = err;
        sk->sk_error_report(sk);
        __udp_disconnect(sk, 0);
 
+out:
        release_sock(sk);
 
        return 0;
index b0ef65e..701eb82 100644 (file)
@@ -5827,7 +5827,7 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla,
                return -EAFNOSUPPORT;
 
        if (nla_parse_nested_deprecated(tb, IFLA_INET6_MAX, nla, NULL, NULL) < 0)
-               BUG();
+               return -EINVAL;
 
        if (tb[IFLA_INET6_TOKEN]) {
                err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN]),
index e204163..92f3235 100644 (file)
@@ -135,6 +135,17 @@ void nft_fib6_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
 }
 EXPORT_SYMBOL_GPL(nft_fib6_eval_type);
 
+static bool nft_fib_v6_skip_icmpv6(const struct sk_buff *skb, u8 next, const struct ipv6hdr *iph)
+{
+       if (likely(next != IPPROTO_ICMPV6))
+               return false;
+
+       if (ipv6_addr_type(&iph->saddr) != IPV6_ADDR_ANY)
+               return false;
+
+       return ipv6_addr_type(&iph->daddr) & IPV6_ADDR_LINKLOCAL;
+}
+
 void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
                   const struct nft_pktinfo *pkt)
 {
@@ -163,10 +174,13 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
 
        lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif, iph);
 
-       if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
-           nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
-               nft_fib_store_result(dest, priv, nft_in(pkt));
-               return;
+       if (nft_hook(pkt) == NF_INET_PRE_ROUTING ||
+           nft_hook(pkt) == NF_INET_INGRESS) {
+               if (nft_fib_is_loopback(pkt->skb, nft_in(pkt)) ||
+                   nft_fib_v6_skip_icmpv6(pkt->skb, pkt->tprot, iph)) {
+                       nft_fib_store_result(dest, priv, nft_in(pkt));
+                       return;
+               }
        }
 
        *dest = 0;
index 199b080..3fcd86f 100644 (file)
@@ -1598,6 +1598,9 @@ void udpv6_destroy_sock(struct sock *sk)
 {
        struct udp_sock *up = udp_sk(sk);
        lock_sock(sk);
+
+       /* protects from races with udp_abort() */
+       sock_set_flag(sk, SOCK_DEAD);
        udp_v6_flush_pending_frames(sk);
        release_sock(sk);
 
index 1c572c8..6201965 100644 (file)
@@ -1066,11 +1066,6 @@ out_error:
                goto partial_message;
        }
 
-       if (skb_has_frag_list(head)) {
-               kfree_skb_list(skb_shinfo(head)->frag_list);
-               skb_shinfo(head)->frag_list = NULL;
-       }
-
        if (head != kcm->seq_skb)
                kfree_skb(head);
 
index 9245c04..fc34ae2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2019, 2021 Intel Corporation
  */
 
 #include <linux/debugfs.h>
@@ -387,10 +387,17 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
                           size_t count, loff_t *ppos)
 {
        struct ieee80211_local *local = file->private_data;
+       int ret;
 
        rtnl_lock();
+       wiphy_lock(local->hw.wiphy);
        __ieee80211_suspend(&local->hw, NULL);
-       __ieee80211_resume(&local->hw);
+       ret = __ieee80211_resume(&local->hw);
+       wiphy_unlock(local->hw.wiphy);
+
+       if (ret)
+               cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
        rtnl_unlock();
 
        return count;
index 214404a..648696b 100644 (file)
@@ -1442,7 +1442,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
-       if (WARN_ON_ONCE(!chanctx_conf)) {
+       if (!chanctx_conf) {
                rcu_read_unlock();
                return NULL;
        }
index 2e2f73a..137fa4c 100644 (file)
@@ -476,14 +476,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
                                   GFP_KERNEL);
        }
 
-       /* APs need special treatment */
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
-               struct ieee80211_sub_if_data *vlan, *tmpsdata;
-
-               /* down all dependent devices, that is VLANs */
-               list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
-                                        u.vlan.list)
-                       dev_close(vlan->dev);
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
        } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
                /* remove all packets in parent bc_buf pointing to this dev */
@@ -641,6 +634,15 @@ static int ieee80211_stop(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       /* close all dependent VLAN interfaces before locking wiphy */
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct ieee80211_sub_if_data *vlan, *tmpsdata;
+
+               list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
+                                        u.vlan.list)
+                       dev_close(vlan->dev);
+       }
+
        wiphy_lock(sdata->local->hw.wiphy);
        ieee80211_do_stop(sdata, true);
        wiphy_unlock(sdata->local->hw.wiphy);
@@ -1591,6 +1593,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
+               if (!list_empty(&sdata->u.ap.vlans))
+                       return -EBUSY;
+               break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_OCB:
index 62145e5..f33a3ac 100644 (file)
@@ -252,6 +252,7 @@ static void ieee80211_restart_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, restart_work);
        struct ieee80211_sub_if_data *sdata;
+       int ret;
 
        /* wait for scan work complete */
        flush_workqueue(local->workqueue);
@@ -301,8 +302,12 @@ static void ieee80211_restart_work(struct work_struct *work)
        /* wait for all packet processing to be done */
        synchronize_net();
 
-       ieee80211_reconfig(local);
+       ret = ieee80211_reconfig(local);
        wiphy_unlock(local->hw.wiphy);
+
+       if (ret)
+               cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
        rtnl_unlock();
 }
 
index 2480bd0..3f2aad2 100644 (file)
@@ -4062,10 +4062,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                if (elems.mbssid_config_ie)
                        bss_conf->profile_periodicity =
                                elems.mbssid_config_ie->profile_periodicity;
+               else
+                       bss_conf->profile_periodicity = 0;
 
                if (elems.ext_capab_len >= 11 &&
                    (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
                        bss_conf->ema_ap = true;
+               else
+                       bss_conf->ema_ap = false;
 
                /* continue assoc process */
                ifmgd->assoc_data->timeout = jiffies;
@@ -5802,12 +5806,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                                              beacon_ies->data, beacon_ies->len);
                if (elem && elem->datalen >= 3)
                        sdata->vif.bss_conf.profile_periodicity = elem->data[2];
+               else
+                       sdata->vif.bss_conf.profile_periodicity = 0;
 
                elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
                                          beacon_ies->data, beacon_ies->len);
                if (elem && elem->datalen >= 11 &&
                    (elem->data[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
                        sdata->vif.bss_conf.ema_ap = true;
+               else
+                       sdata->vif.bss_conf.ema_ap = false;
        } else {
                assoc_data->timeout = jiffies;
                assoc_data->timeout_started = true;
index 6487b05..a6f3fb4 100644 (file)
@@ -1514,7 +1514,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
            (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
                return;
 
-       if (time_is_before_jiffies(mi->sample_time))
+       if (time_is_after_jiffies(mi->sample_time))
                return;
 
        mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL;
index 1bb43ed..af0ef45 100644 (file)
@@ -2240,17 +2240,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        sc = le16_to_cpu(hdr->seq_ctrl);
        frag = sc & IEEE80211_SCTL_FRAG;
 
-       if (is_multicast_ether_addr(hdr->addr1)) {
-               I802_DEBUG_INC(rx->local->dot11MulticastReceivedFrameCount);
-               goto out_no_led;
-       }
-
        if (rx->sta)
                cache = &rx->sta->frags;
 
        if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
                goto out;
 
+       if (is_multicast_ether_addr(hdr->addr1))
+               return RX_DROP_MONITOR;
+
        I802_DEBUG_INC(rx->local->rx_handlers_fragments);
 
        if (skb_linearize(rx->skb))
@@ -2376,7 +2374,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
  out:
        ieee80211_led_rx(rx->local);
- out_no_led:
        if (rx->sta)
                rx->sta->rx_stats.packets++;
        return RX_CONTINUE;
index d4cc9ac..6b50cb5 100644 (file)
@@ -251,13 +251,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
        struct ieee80211_mgmt *mgmt = (void *)skb->data;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
+       size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
+                                     u.probe_resp.variable);
+
+       if (!ieee80211_is_probe_resp(mgmt->frame_control) &&
+           !ieee80211_is_beacon(mgmt->frame_control) &&
+           !ieee80211_is_s1g_beacon(mgmt->frame_control))
+               return;
 
        if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
-               if (skb->len < 15)
-                       return;
-       } else if (skb->len < 24 ||
-                (!ieee80211_is_probe_resp(mgmt->frame_control) &&
-                 !ieee80211_is_beacon(mgmt->frame_control)))
+               if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
+                       min_hdr_len = offsetof(struct ieee80211_ext,
+                                              u.s1g_short_beacon.variable);
+               else
+                       min_hdr_len = offsetof(struct ieee80211_ext,
+                                              u.s1g_beacon);
+       }
+
+       if (skb->len < min_hdr_len)
                return;
 
        sdata1 = rcu_dereference(local->scan_sdata);
index 0b719f3..2651498 100644 (file)
@@ -2014,6 +2014,26 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
        ieee80211_tx(sdata, sta, skb, false);
 }
 
+static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
+{
+       struct ieee80211_radiotap_header *rthdr =
+               (struct ieee80211_radiotap_header *)skb->data;
+
+       /* check for not even having the fixed radiotap header part */
+       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+               return false; /* too short to be possibly valid */
+
+       /* is it a header version we can trust to find length from? */
+       if (unlikely(rthdr->it_version))
+               return false; /* only version 0 is supported */
+
+       /* does the skb contain enough to deliver on the alleged length? */
+       if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
+               return false; /* skb too short for claimed rt header extent */
+
+       return true;
+}
+
 bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
                                 struct net_device *dev)
 {
@@ -2022,8 +2042,6 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
        struct ieee80211_radiotap_header *rthdr =
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_supported_band *sband =
-               local->hw.wiphy->bands[info->band];
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
                                                   NULL);
        u16 txflags;
@@ -2036,17 +2054,8 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
        u8 vht_mcs = 0, vht_nss = 0;
        int i;
 
-       /* check for not even having the fixed radiotap header part */
-       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
-               return false; /* too short to be possibly valid */
-
-       /* is it a header version we can trust to find length from? */
-       if (unlikely(rthdr->it_version))
-               return false; /* only version 0 is supported */
-
-       /* does the skb contain enough to deliver on the alleged length? */
-       if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
-               return false; /* skb too short for claimed rt header extent */
+       if (!ieee80211_validate_radiotap_len(skb))
+               return false;
 
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
                       IEEE80211_TX_CTL_DONTFRAG;
@@ -2186,6 +2195,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
                return false;
 
        if (rate_found) {
+               struct ieee80211_supported_band *sband =
+                       local->hw.wiphy->bands[info->band];
+
                info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
 
                for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
@@ -2199,7 +2211,7 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
                } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
                        ieee80211_rate_set_vht(info->control.rates, vht_mcs,
                                               vht_nss);
-               } else {
+               } else if (sband) {
                        for (i = 0; i < sband->n_bitrates; i++) {
                                if (rate * 5 != sband->bitrates[i].bitrate)
                                        continue;
@@ -2236,8 +2248,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
                      IEEE80211_TX_CTL_INJECTED;
 
-       /* Sanity-check and process the injection radiotap header */
-       if (!ieee80211_parse_tx_radiotap(skb, dev))
+       /* Sanity-check the length of the radiotap header */
+       if (!ieee80211_validate_radiotap_len(skb))
                goto fail;
 
        /* we now know there is a radiotap header with a length we can use */
@@ -2351,6 +2363,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        ieee80211_select_queue_80211(sdata, skb, hdr);
        skb_set_queue_mapping(skb, ieee80211_ac_from_tid(skb->priority));
 
+       /*
+        * Process the radiotap header. This will now take into account the
+        * selected chandef above to accurately set injection rates and
+        * retransmissions.
+        */
+       if (!ieee80211_parse_tx_radiotap(skb, dev))
+               goto fail_rcu;
+
        /* remove the injection radiotap header */
        skb_pull(skb, len_rthdr);
 
index 0a0481f..060059e 100644 (file)
@@ -947,7 +947,7 @@ static void ieee80211_parse_extension_element(u32 *crc,
 
        switch (elem->data[0]) {
        case WLAN_EID_EXT_HE_MU_EDCA:
-               if (len == sizeof(*elems->mu_edca_param_set)) {
+               if (len >= sizeof(*elems->mu_edca_param_set)) {
                        elems->mu_edca_param_set = data;
                        if (crc)
                                *crc = crc32_be(*crc, (void *)elem,
@@ -968,7 +968,7 @@ static void ieee80211_parse_extension_element(u32 *crc,
                }
                break;
        case WLAN_EID_EXT_UORA:
-               if (len == 1)
+               if (len >= 1)
                        elems->uora_element = data;
                break;
        case WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME:
@@ -976,7 +976,7 @@ static void ieee80211_parse_extension_element(u32 *crc,
                        elems->max_channel_switch_time = data;
                break;
        case WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION:
-               if (len == sizeof(*elems->mbssid_config_ie))
+               if (len >= sizeof(*elems->mbssid_config_ie))
                        elems->mbssid_config_ie = data;
                break;
        case WLAN_EID_EXT_HE_SPR:
@@ -985,7 +985,7 @@ static void ieee80211_parse_extension_element(u32 *crc,
                        elems->he_spr = data;
                break;
        case WLAN_EID_EXT_HE_6GHZ_CAPA:
-               if (len == sizeof(*elems->he_6ghz_capa))
+               if (len >= sizeof(*elems->he_6ghz_capa))
                        elems->he_6ghz_capa = data;
                break;
        }
@@ -1074,14 +1074,14 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 
                switch (id) {
                case WLAN_EID_LINK_ID:
-                       if (elen + 2 != sizeof(struct ieee80211_tdls_lnkie)) {
+                       if (elen + 2 < sizeof(struct ieee80211_tdls_lnkie)) {
                                elem_parse_failed = true;
                                break;
                        }
                        elems->lnk_id = (void *)(pos - 2);
                        break;
                case WLAN_EID_CHAN_SWITCH_TIMING:
-                       if (elen != sizeof(struct ieee80211_ch_switch_timing)) {
+                       if (elen < sizeof(struct ieee80211_ch_switch_timing)) {
                                elem_parse_failed = true;
                                break;
                        }
@@ -1244,7 +1244,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        elems->sec_chan_offs = (void *)pos;
                        break;
                case WLAN_EID_CHAN_SWITCH_PARAM:
-                       if (elen !=
+                       if (elen <
                            sizeof(*elems->mesh_chansw_params_ie)) {
                                elem_parse_failed = true;
                                break;
@@ -1253,7 +1253,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        break;
                case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
                        if (!action ||
-                           elen != sizeof(*elems->wide_bw_chansw_ie)) {
+                           elen < sizeof(*elems->wide_bw_chansw_ie)) {
                                elem_parse_failed = true;
                                break;
                        }
@@ -1272,7 +1272,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
                                              pos, elen);
                        if (ie) {
-                               if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
+                               if (ie[1] >= sizeof(*elems->wide_bw_chansw_ie))
                                        elems->wide_bw_chansw_ie =
                                                (void *)(ie + 2);
                                else
@@ -1316,7 +1316,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        elems->cisco_dtpc_elem = pos;
                        break;
                case WLAN_EID_ADDBA_EXT:
-                       if (elen != sizeof(struct ieee80211_addba_ext_ie)) {
+                       if (elen < sizeof(struct ieee80211_addba_ext_ie)) {
                                elem_parse_failed = true;
                                break;
                        }
@@ -1342,7 +1342,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                                                          elem, elems);
                        break;
                case WLAN_EID_S1G_CAPABILITIES:
-                       if (elen == sizeof(*elems->s1g_capab))
+                       if (elen >= sizeof(*elems->s1g_capab))
                                elems->s1g_capab = (void *)pos;
                        else
                                elem_parse_failed = true;
@@ -2178,8 +2178,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
        list_for_each_entry(ctx, &local->chanctx_list, list)
                ctx->driver_present = false;
        mutex_unlock(&local->chanctx_mtx);
-
-       cfg80211_shutdown_all_interfaces(local->hw.wiphy);
 }
 
 static void ieee80211_assign_chanctx(struct ieee80211_local *local,
index 6b825fb..9b263f2 100644 (file)
@@ -356,6 +356,8 @@ void mptcp_get_options(const struct sk_buff *skb,
                        length--;
                        continue;
                default:
+                       if (length < 2)
+                               return;
                        opsize = *ptr++;
                        if (opsize < 2) /* "silly options" */
                                return;
index 5edc686..6323500 100644 (file)
@@ -280,11 +280,13 @@ static bool __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk,
 
        /* try to fetch required memory from subflow */
        if (!sk_rmem_schedule(sk, skb, skb->truesize)) {
-               if (ssk->sk_forward_alloc < skb->truesize)
-                       goto drop;
-               __sk_mem_reclaim(ssk, skb->truesize);
-               if (!sk_rmem_schedule(sk, skb, skb->truesize))
+               int amount = sk_mem_pages(skb->truesize) << SK_MEM_QUANTUM_SHIFT;
+
+               if (ssk->sk_forward_alloc < amount)
                        goto drop;
+
+               ssk->sk_forward_alloc -= amount;
+               sk->sk_forward_alloc += amount;
        }
 
        /* the skb map_seq accounts for the skb offset:
@@ -668,18 +670,22 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk)
 /* In most cases we will be able to lock the mptcp socket.  If its already
  * owned, we need to defer to the work queue to avoid ABBA deadlock.
  */
-static void move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)
+static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)
 {
        struct sock *sk = (struct sock *)msk;
        unsigned int moved = 0;
 
        if (inet_sk_state_load(sk) == TCP_CLOSE)
-               return;
-
-       mptcp_data_lock(sk);
+               return false;
 
        __mptcp_move_skbs_from_subflow(msk, ssk, &moved);
        __mptcp_ofo_queue(msk);
+       if (unlikely(ssk->sk_err)) {
+               if (!sock_owned_by_user(sk))
+                       __mptcp_error_report(sk);
+               else
+                       set_bit(MPTCP_ERROR_REPORT,  &msk->flags);
+       }
 
        /* If the moves have caught up with the DATA_FIN sequence number
         * it's time to ack the DATA_FIN and change socket state, but
@@ -688,7 +694,7 @@ static void move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)
         */
        if (mptcp_pending_data_fin(sk, NULL))
                mptcp_schedule_work(sk);
-       mptcp_data_unlock(sk);
+       return moved > 0;
 }
 
 void mptcp_data_ready(struct sock *sk, struct sock *ssk)
@@ -696,7 +702,6 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
        struct mptcp_sock *msk = mptcp_sk(sk);
        int sk_rbuf, ssk_rbuf;
-       bool wake;
 
        /* The peer can send data while we are shutting down this
         * subflow at msk destruction time, but we must avoid enqueuing
@@ -705,28 +710,22 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
        if (unlikely(subflow->disposable))
                return;
 
-       /* move_skbs_to_msk below can legitly clear the data_avail flag,
-        * but we will need later to properly woke the reader, cache its
-        * value
-        */
-       wake = subflow->data_avail == MPTCP_SUBFLOW_DATA_AVAIL;
-       if (wake)
-               set_bit(MPTCP_DATA_READY, &msk->flags);
-
        ssk_rbuf = READ_ONCE(ssk->sk_rcvbuf);
        sk_rbuf = READ_ONCE(sk->sk_rcvbuf);
        if (unlikely(ssk_rbuf > sk_rbuf))
                sk_rbuf = ssk_rbuf;
 
-       /* over limit? can't append more skbs to msk */
+       /* over limit? can't append more skbs to msk, Also, no need to wake-up*/
        if (atomic_read(&sk->sk_rmem_alloc) > sk_rbuf)
-               goto wake;
-
-       move_skbs_to_msk(msk, ssk);
+               return;
 
-wake:
-       if (wake)
+       /* Wake-up the reader only for in-sequence data */
+       mptcp_data_lock(sk);
+       if (move_skbs_to_msk(msk, ssk)) {
+               set_bit(MPTCP_DATA_READY, &msk->flags);
                sk->sk_data_ready(sk);
+       }
+       mptcp_data_unlock(sk);
 }
 
 static bool mptcp_do_flush_join_list(struct mptcp_sock *msk)
@@ -858,7 +857,7 @@ static struct sock *mptcp_subflow_recv_lookup(const struct mptcp_sock *msk)
        sock_owned_by_me(sk);
 
        mptcp_for_each_subflow(msk, subflow) {
-               if (subflow->data_avail)
+               if (READ_ONCE(subflow->data_avail))
                        return mptcp_subflow_tcp_sock(subflow);
        }
 
@@ -1955,6 +1954,9 @@ static bool __mptcp_move_skbs(struct mptcp_sock *msk)
                done = __mptcp_move_skbs_from_subflow(msk, ssk, &moved);
                mptcp_data_unlock(sk);
                tcp_cleanup_rbuf(ssk, moved);
+
+               if (unlikely(ssk->sk_err))
+                       __mptcp_error_report(sk);
                unlock_sock_fast(ssk, slowpath);
        } while (!done);
 
index 0c6f99c..385796f 100644 (file)
@@ -362,7 +362,6 @@ mptcp_subflow_rsk(const struct request_sock *rsk)
 enum mptcp_data_avail {
        MPTCP_SUBFLOW_NODATA,
        MPTCP_SUBFLOW_DATA_AVAIL,
-       MPTCP_SUBFLOW_OOO_DATA
 };
 
 struct mptcp_delegated_action {
index ef3d037..be1de40 100644 (file)
@@ -784,10 +784,10 @@ static u64 expand_seq(u64 old_seq, u16 old_data_len, u64 seq)
        return seq | ((old_seq + old_data_len + 1) & GENMASK_ULL(63, 32));
 }
 
-static void warn_bad_map(struct mptcp_subflow_context *subflow, u32 ssn)
+static void dbg_bad_map(struct mptcp_subflow_context *subflow, u32 ssn)
 {
-       WARN_ONCE(1, "Bad mapping: ssn=%d map_seq=%d map_data_len=%d",
-                 ssn, subflow->map_subflow_seq, subflow->map_data_len);
+       pr_debug("Bad mapping: ssn=%d map_seq=%d map_data_len=%d",
+                ssn, subflow->map_subflow_seq, subflow->map_data_len);
 }
 
 static bool skb_is_fully_mapped(struct sock *ssk, struct sk_buff *skb)
@@ -812,13 +812,13 @@ static bool validate_mapping(struct sock *ssk, struct sk_buff *skb)
                /* Mapping covers data later in the subflow stream,
                 * currently unsupported.
                 */
-               warn_bad_map(subflow, ssn);
+               dbg_bad_map(subflow, ssn);
                return false;
        }
        if (unlikely(!before(ssn, subflow->map_subflow_seq +
                                  subflow->map_data_len))) {
                /* Mapping does covers past subflow data, invalid */
-               warn_bad_map(subflow, ssn + skb->len);
+               dbg_bad_map(subflow, ssn);
                return false;
        }
        return true;
@@ -1000,7 +1000,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
        struct sk_buff *skb;
 
        if (!skb_peek(&ssk->sk_receive_queue))
-               subflow->data_avail = 0;
+               WRITE_ONCE(subflow->data_avail, 0);
        if (subflow->data_avail)
                return true;
 
@@ -1039,18 +1039,13 @@ static bool subflow_check_data_avail(struct sock *ssk)
                ack_seq = mptcp_subflow_get_mapped_dsn(subflow);
                pr_debug("msk ack_seq=%llx subflow ack_seq=%llx", old_ack,
                         ack_seq);
-               if (ack_seq == old_ack) {
-                       subflow->data_avail = MPTCP_SUBFLOW_DATA_AVAIL;
-                       break;
-               } else if (after64(ack_seq, old_ack)) {
-                       subflow->data_avail = MPTCP_SUBFLOW_OOO_DATA;
-                       break;
+               if (unlikely(before64(ack_seq, old_ack))) {
+                       mptcp_subflow_discard_data(ssk, skb, old_ack - ack_seq);
+                       continue;
                }
 
-               /* only accept in-sequence mapping. Old values are spurious
-                * retransmission
-                */
-               mptcp_subflow_discard_data(ssk, skb, old_ack - ack_seq);
+               WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_DATA_AVAIL);
+               break;
        }
        return true;
 
@@ -1065,12 +1060,11 @@ fallback:
                 * subflow_error_report() will introduce the appropriate barriers
                 */
                ssk->sk_err = EBADMSG;
-               ssk->sk_error_report(ssk);
                tcp_set_state(ssk, TCP_CLOSE);
                subflow->reset_transient = 0;
                subflow->reset_reason = MPTCP_RST_EMPTCP;
                tcp_send_active_reset(ssk, GFP_ATOMIC);
-               subflow->data_avail = 0;
+               WRITE_ONCE(subflow->data_avail, 0);
                return false;
        }
 
@@ -1080,7 +1074,7 @@ fallback:
        subflow->map_seq = READ_ONCE(msk->ack_seq);
        subflow->map_data_len = skb->len;
        subflow->map_subflow_seq = tcp_sk(ssk)->copied_seq - subflow->ssn_offset;
-       subflow->data_avail = MPTCP_SUBFLOW_DATA_AVAIL;
+       WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_DATA_AVAIL);
        return true;
 }
 
@@ -1092,7 +1086,7 @@ bool mptcp_subflow_data_available(struct sock *sk)
        if (subflow->map_valid &&
            mptcp_subflow_get_map_offset(subflow) >= subflow->map_data_len) {
                subflow->map_valid = 0;
-               subflow->data_avail = 0;
+               WRITE_ONCE(subflow->data_avail, 0);
 
                pr_debug("Done with mapping: seq=%u data_len=%u",
                         subflow->map_subflow_seq,
@@ -1120,41 +1114,6 @@ void mptcp_space(const struct sock *ssk, int *space, int *full_space)
        *full_space = tcp_full_space(sk);
 }
 
-static void subflow_data_ready(struct sock *sk)
-{
-       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
-       u16 state = 1 << inet_sk_state_load(sk);
-       struct sock *parent = subflow->conn;
-       struct mptcp_sock *msk;
-
-       msk = mptcp_sk(parent);
-       if (state & TCPF_LISTEN) {
-               /* MPJ subflow are removed from accept queue before reaching here,
-                * avoid stray wakeups
-                */
-               if (reqsk_queue_empty(&inet_csk(sk)->icsk_accept_queue))
-                       return;
-
-               set_bit(MPTCP_DATA_READY, &msk->flags);
-               parent->sk_data_ready(parent);
-               return;
-       }
-
-       WARN_ON_ONCE(!__mptcp_check_fallback(msk) && !subflow->mp_capable &&
-                    !subflow->mp_join && !(state & TCPF_CLOSE));
-
-       if (mptcp_subflow_data_available(sk))
-               mptcp_data_ready(parent, sk);
-}
-
-static void subflow_write_space(struct sock *ssk)
-{
-       struct sock *sk = mptcp_subflow_ctx(ssk)->conn;
-
-       mptcp_propagate_sndbuf(sk, ssk);
-       mptcp_write_space(sk);
-}
-
 void __mptcp_error_report(struct sock *sk)
 {
        struct mptcp_subflow_context *subflow;
@@ -1195,6 +1154,43 @@ static void subflow_error_report(struct sock *ssk)
        mptcp_data_unlock(sk);
 }
 
+static void subflow_data_ready(struct sock *sk)
+{
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+       u16 state = 1 << inet_sk_state_load(sk);
+       struct sock *parent = subflow->conn;
+       struct mptcp_sock *msk;
+
+       msk = mptcp_sk(parent);
+       if (state & TCPF_LISTEN) {
+               /* MPJ subflow are removed from accept queue before reaching here,
+                * avoid stray wakeups
+                */
+               if (reqsk_queue_empty(&inet_csk(sk)->icsk_accept_queue))
+                       return;
+
+               set_bit(MPTCP_DATA_READY, &msk->flags);
+               parent->sk_data_ready(parent);
+               return;
+       }
+
+       WARN_ON_ONCE(!__mptcp_check_fallback(msk) && !subflow->mp_capable &&
+                    !subflow->mp_join && !(state & TCPF_CLOSE));
+
+       if (mptcp_subflow_data_available(sk))
+               mptcp_data_ready(parent, sk);
+       else if (unlikely(sk->sk_err))
+               subflow_error_report(sk);
+}
+
+static void subflow_write_space(struct sock *ssk)
+{
+       struct sock *sk = mptcp_subflow_ctx(ssk)->conn;
+
+       mptcp_propagate_sndbuf(sk, ssk);
+       mptcp_write_space(sk);
+}
+
 static struct inet_connection_sock_af_ops *
 subflow_default_af_ops(struct sock *sk)
 {
@@ -1505,6 +1501,8 @@ static void subflow_state_change(struct sock *sk)
         */
        if (mptcp_subflow_data_available(sk))
                mptcp_data_ready(parent, sk);
+       else if (unlikely(sk->sk_err))
+               subflow_error_report(sk);
 
        subflow_sched_work_if_closed(mptcp_sk(parent), sk);
 
index b100c04..3d6d494 100644 (file)
@@ -31,6 +31,9 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
        int length = (th->doff * 4) - sizeof(*th);
        u8 buf[40], *ptr;
 
+       if (unlikely(length < 0))
+               return false;
+
        ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf);
        if (ptr == NULL)
                return false;
@@ -47,6 +50,8 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
                        length--;
                        continue;
                default:
+                       if (length < 2)
+                               return true;
                        opsize = *ptr++;
                        if (opsize < 2)
                                return true;
index 72bc759..bf4d6ec 100644 (file)
@@ -4364,13 +4364,45 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
        err = nf_tables_set_alloc_name(&ctx, set, name);
        kfree(name);
        if (err < 0)
-               goto err_set_alloc_name;
+               goto err_set_name;
+
+       udata = NULL;
+       if (udlen) {
+               udata = set->data + size;
+               nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
+       }
+
+       INIT_LIST_HEAD(&set->bindings);
+       INIT_LIST_HEAD(&set->catchall_list);
+       set->table = table;
+       write_pnet(&set->net, net);
+       set->ops = ops;
+       set->ktype = ktype;
+       set->klen = desc.klen;
+       set->dtype = dtype;
+       set->objtype = objtype;
+       set->dlen = desc.dlen;
+       set->flags = flags;
+       set->size = desc.size;
+       set->policy = policy;
+       set->udlen = udlen;
+       set->udata = udata;
+       set->timeout = timeout;
+       set->gc_int = gc_int;
+
+       set->field_count = desc.field_count;
+       for (i = 0; i < desc.field_count; i++)
+               set->field_len[i] = desc.field_len[i];
+
+       err = ops->init(set, &desc, nla);
+       if (err < 0)
+               goto err_set_init;
 
        if (nla[NFTA_SET_EXPR]) {
                expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
                if (IS_ERR(expr)) {
                        err = PTR_ERR(expr);
-                       goto err_set_alloc_name;
+                       goto err_set_expr_alloc;
                }
                set->exprs[0] = expr;
                set->num_exprs++;
@@ -4381,75 +4413,44 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
 
                if (!(flags & NFT_SET_EXPR)) {
                        err = -EINVAL;
-                       goto err_set_alloc_name;
+                       goto err_set_expr_alloc;
                }
                i = 0;
                nla_for_each_nested(tmp, nla[NFTA_SET_EXPRESSIONS], left) {
                        if (i == NFT_SET_EXPR_MAX) {
                                err = -E2BIG;
-                               goto err_set_init;
+                               goto err_set_expr_alloc;
                        }
                        if (nla_type(tmp) != NFTA_LIST_ELEM) {
                                err = -EINVAL;
-                               goto err_set_init;
+                               goto err_set_expr_alloc;
                        }
                        expr = nft_set_elem_expr_alloc(&ctx, set, tmp);
                        if (IS_ERR(expr)) {
                                err = PTR_ERR(expr);
-                               goto err_set_init;
+                               goto err_set_expr_alloc;
                        }
                        set->exprs[i++] = expr;
                        set->num_exprs++;
                }
        }
 
-       udata = NULL;
-       if (udlen) {
-               udata = set->data + size;
-               nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
-       }
-
-       INIT_LIST_HEAD(&set->bindings);
-       INIT_LIST_HEAD(&set->catchall_list);
-       set->table = table;
-       write_pnet(&set->net, net);
-       set->ops   = ops;
-       set->ktype = ktype;
-       set->klen  = desc.klen;
-       set->dtype = dtype;
-       set->objtype = objtype;
-       set->dlen  = desc.dlen;
-       set->flags = flags;
-       set->size  = desc.size;
-       set->policy = policy;
-       set->udlen  = udlen;
-       set->udata  = udata;
-       set->timeout = timeout;
-       set->gc_int = gc_int;
        set->handle = nf_tables_alloc_handle(table);
 
-       set->field_count = desc.field_count;
-       for (i = 0; i < desc.field_count; i++)
-               set->field_len[i] = desc.field_len[i];
-
-       err = ops->init(set, &desc, nla);
-       if (err < 0)
-               goto err_set_init;
-
        err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
        if (err < 0)
-               goto err_set_trans;
+               goto err_set_expr_alloc;
 
        list_add_tail_rcu(&set->list, &table->sets);
        table->use++;
        return 0;
 
-err_set_trans:
-       ops->destroy(set);
-err_set_init:
+err_set_expr_alloc:
        for (i = 0; i < set->num_exprs; i++)
                nft_expr_destroy(&ctx, set->exprs[i]);
-err_set_alloc_name:
+
+       ops->destroy(set);
+err_set_init:
        kfree(set->name);
 err_set_name:
        kvfree(set);
index 78da5ea..de04560 100644 (file)
@@ -266,6 +266,7 @@ static int __must_check nr_add_node(ax25_address *nr, const char *mnemonic,
                fallthrough;
        case 2:
                re_sort_routes(nr_node, 0, 1);
+               break;
        case 1:
                break;
        }
@@ -359,6 +360,7 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
                                        fallthrough;
                                case 1:
                                        nr_node->routes[1] = nr_node->routes[2];
+                                       fallthrough;
                                case 2:
                                        break;
                                }
@@ -482,6 +484,7 @@ static int nr_dec_obs(void)
                                        fallthrough;
                                case 1:
                                        s->routes[1] = s->routes[2];
+                                       break;
                                case 2:
                                        break;
                                }
@@ -529,6 +532,7 @@ void nr_rt_device_down(struct net_device *dev)
                                                        fallthrough;
                                                case 1:
                                                        t->routes[1] = t->routes[2];
+                                                       break;
                                                case 2:
                                                        break;
                                                }
index ae906eb..d56941d 100644 (file)
@@ -1656,6 +1656,7 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
        case PACKET_FANOUT_ROLLOVER:
                if (type_flags & PACKET_FANOUT_FLAG_ROLLOVER)
                        return -EINVAL;
+               break;
        case PACKET_FANOUT_HASH:
        case PACKET_FANOUT_LB:
        case PACKET_FANOUT_CPU:
@@ -2683,7 +2684,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        }
        if (likely(saddr == NULL)) {
                dev     = packet_cached_dev_get(po);
-               proto   = po->num;
+               proto   = READ_ONCE(po->num);
        } else {
                err = -EINVAL;
                if (msg->msg_namelen < sizeof(struct sockaddr_ll))
@@ -2896,7 +2897,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
        if (likely(saddr == NULL)) {
                dev     = packet_cached_dev_get(po);
-               proto   = po->num;
+               proto   = READ_ONCE(po->num);
        } else {
                err = -EINVAL;
                if (msg->msg_namelen < sizeof(struct sockaddr_ll))
@@ -3034,10 +3035,13 @@ static int packet_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
        struct sock *sk = sock->sk;
        struct packet_sock *po = pkt_sk(sk);
 
-       if (po->tx_ring.pg_vec)
+       /* Reading tx_ring.pg_vec without holding pg_vec_lock is racy.
+        * tpacket_snd() will redo the check safely.
+        */
+       if (data_race(po->tx_ring.pg_vec))
                return tpacket_snd(po, msg);
-       else
-               return packet_snd(sock, msg, len);
+
+       return packet_snd(sock, msg, len);
 }
 
 /*
@@ -3168,7 +3172,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
                        /* prevents packet_notifier() from calling
                         * register_prot_hook()
                         */
-                       po->num = 0;
+                       WRITE_ONCE(po->num, 0);
                        __unregister_prot_hook(sk, true);
                        rcu_read_lock();
                        dev_curr = po->prot_hook.dev;
@@ -3178,17 +3182,17 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
                }
 
                BUG_ON(po->running);
-               po->num = proto;
+               WRITE_ONCE(po->num, proto);
                po->prot_hook.type = proto;
 
                if (unlikely(unlisted)) {
                        dev_put(dev);
                        po->prot_hook.dev = NULL;
-                       po->ifindex = -1;
+                       WRITE_ONCE(po->ifindex, -1);
                        packet_cached_dev_reset(po);
                } else {
                        po->prot_hook.dev = dev;
-                       po->ifindex = dev ? dev->ifindex : 0;
+                       WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0);
                        packet_cached_dev_assign(po, dev);
                }
        }
@@ -3502,7 +3506,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
        uaddr->sa_family = AF_PACKET;
        memset(uaddr->sa_data, 0, sizeof(uaddr->sa_data));
        rcu_read_lock();
-       dev = dev_get_by_index_rcu(sock_net(sk), pkt_sk(sk)->ifindex);
+       dev = dev_get_by_index_rcu(sock_net(sk), READ_ONCE(pkt_sk(sk)->ifindex));
        if (dev)
                strlcpy(uaddr->sa_data, dev->name, sizeof(uaddr->sa_data));
        rcu_read_unlock();
@@ -3517,16 +3521,18 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
        struct sock *sk = sock->sk;
        struct packet_sock *po = pkt_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_ll *, sll, uaddr);
+       int ifindex;
 
        if (peer)
                return -EOPNOTSUPP;
 
+       ifindex = READ_ONCE(po->ifindex);
        sll->sll_family = AF_PACKET;
-       sll->sll_ifindex = po->ifindex;
-       sll->sll_protocol = po->num;
+       sll->sll_ifindex = ifindex;
+       sll->sll_protocol = READ_ONCE(po->num);
        sll->sll_pkttype = 0;
        rcu_read_lock();
-       dev = dev_get_by_index_rcu(sock_net(sk), po->ifindex);
+       dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
        if (dev) {
                sll->sll_hatype = dev->type;
                sll->sll_halen = dev->addr_len;
@@ -4105,7 +4111,7 @@ static int packet_notifier(struct notifier_block *this,
                                }
                                if (msg == NETDEV_UNREGISTER) {
                                        packet_cached_dev_reset(po);
-                                       po->ifindex = -1;
+                                       WRITE_ONCE(po->ifindex, -1);
                                        if (po->prot_hook.dev)
                                                dev_put(po->prot_hook.dev);
                                        po->prot_hook.dev = NULL;
@@ -4411,7 +4417,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        was_running = po->running;
        num = po->num;
        if (was_running) {
-               po->num = 0;
+               WRITE_ONCE(po->num, 0);
                __unregister_prot_hook(sk, false);
        }
        spin_unlock(&po->bind_lock);
@@ -4446,7 +4452,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 
        spin_lock(&po->bind_lock);
        if (was_running) {
-               po->num = num;
+               WRITE_ONCE(po->num, num);
                register_prot_hook(sk);
        }
        spin_unlock(&po->bind_lock);
@@ -4616,8 +4622,8 @@ static int packet_seq_show(struct seq_file *seq, void *v)
                           s,
                           refcount_read(&s->sk_refcnt),
                           s->sk_type,
-                          ntohs(po->num),
-                          po->ifindex,
+                          ntohs(READ_ONCE(po->num)),
+                          READ_ONCE(po->ifindex),
                           po->running,
                           atomic_read(&s->sk_rmem_alloc),
                           from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)),
index c0477be..f2efaa4 100644 (file)
@@ -436,7 +436,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
        struct qrtr_sock *ipc;
        struct sk_buff *skb;
        struct qrtr_cb *cb;
-       unsigned int size;
+       size_t size;
        unsigned int ver;
        size_t hdrlen;
 
index 4db109f..5b426dc 100644 (file)
@@ -714,7 +714,7 @@ int rds_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
 
                if (rds_cmsg_recv(inc, msg, rs)) {
                        ret = -EFAULT;
-                       goto out;
+                       break;
                }
                rds_recvmsg_zcookie(rs, msg);
 
index 4e64598..5461d77 100644 (file)
@@ -78,6 +78,7 @@ void rds_tcp_state_change(struct sock *sk)
        case TCP_CLOSE_WAIT:
        case TCP_CLOSE:
                rds_conn_path_drop(cp, false);
+               break;
        default:
                break;
        }
index 32dc50f..1f424cb 100644 (file)
@@ -208,6 +208,7 @@ void rds_send_worker(struct work_struct *work)
                case -ENOMEM:
                        rds_stats_inc(s_send_delayed_retry);
                        queue_delayed_work(rds_wq, &cp->cp_send_w, 2);
+                       break;
                default:
                        break;
                }
@@ -232,6 +233,7 @@ void rds_recv_worker(struct work_struct *work)
                case -ENOMEM:
                        rds_stats_inc(s_recv_delayed_retry);
                        queue_delayed_work(rds_wq, &cp->cp_recv_w, 2);
+                       break;
                default:
                        break;
                }
index 41671af..2b5f897 100644 (file)
@@ -471,6 +471,7 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr,
        switch (rx->sk.sk_state) {
        case RXRPC_UNBOUND:
                rx->sk.sk_state = RXRPC_CLIENT_UNBOUND;
+               break;
        case RXRPC_CLIENT_UNBOUND:
        case RXRPC_CLIENT_BOUND:
                break;
index 18edd9a..a656baa 100644 (file)
@@ -904,14 +904,19 @@ static int tcf_ct_act_nat(struct sk_buff *skb,
        }
 
        err = ct_nat_execute(skb, ct, ctinfo, range, maniptype);
-       if (err == NF_ACCEPT &&
-           ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
-               if (maniptype == NF_NAT_MANIP_SRC)
-                       maniptype = NF_NAT_MANIP_DST;
-               else
-                       maniptype = NF_NAT_MANIP_SRC;
-
-               err = ct_nat_execute(skb, ct, ctinfo, range, maniptype);
+       if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
+               if (ct->status & IPS_SRC_NAT) {
+                       if (maniptype == NF_NAT_MANIP_SRC)
+                               maniptype = NF_NAT_MANIP_DST;
+                       else
+                               maniptype = NF_NAT_MANIP_SRC;
+
+                       err = ct_nat_execute(skb, ct, ctinfo, range,
+                                            maniptype);
+               } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
+                       err = ct_nat_execute(skb, ct, ctinfo, NULL,
+                                            NF_NAT_MANIP_SRC);
+               }
        }
        return err;
 #else
index 7d37638..9515428 100644 (file)
@@ -943,7 +943,7 @@ static struct tcphdr *cake_get_tcphdr(const struct sk_buff *skb,
        }
 
        tcph = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
-       if (!tcph)
+       if (!tcph || tcph->doff < 5)
                return NULL;
 
        return skb_header_pointer(skb, offset,
@@ -967,6 +967,8 @@ static const void *cake_get_tcpopt(const struct tcphdr *tcph,
                        length--;
                        continue;
                }
+               if (length < 2)
+                       break;
                opsize = *ptr++;
                if (opsize < 2 || opsize > length)
                        break;
@@ -1104,6 +1106,8 @@ static bool cake_tcph_may_drop(const struct tcphdr *tcph,
                        length--;
                        continue;
                }
+               if (length < 2)
+                       break;
                opsize = *ptr++;
                if (opsize < 2 || opsize > length)
                        break;
@@ -2338,7 +2342,7 @@ static int cake_config_precedence(struct Qdisc *sch)
 
 /*     List of known Diffserv codepoints:
  *
- *     Least Effort (CS1)
+ *     Least Effort (CS1, LE)
  *     Best Effort (CS0)
  *     Max Reliability & LLT "Lo" (TOS1)
  *     Max Throughput (TOS2)
@@ -2360,7 +2364,7 @@ static int cake_config_precedence(struct Qdisc *sch)
  *     Total 25 codepoints.
  */
 
-/*     List of traffic classes in RFC 4594:
+/*     List of traffic classes in RFC 4594, updated by RFC 8622:
  *             (roughly descending order of contended priority)
  *             (roughly ascending order of uncontended throughput)
  *
@@ -2375,7 +2379,7 @@ static int cake_config_precedence(struct Qdisc *sch)
  *     Ops, Admin, Management (CS2,TOS1) - eg. ssh
  *     Standard Service (CS0 & unrecognised codepoints)
  *     High Throughput Data (AF1x,TOS2)  - eg. web traffic
- *     Low Priority Data (CS1)           - eg. BitTorrent
+ *     Low Priority Data (CS1,LE)        - eg. BitTorrent
 
  *     Total 12 traffic classes.
  */
@@ -2391,7 +2395,7 @@ static int cake_config_diffserv8(struct Qdisc *sch)
  *             Video Streaming          (AF4x, AF3x, CS3)
  *             Bog Standard             (CS0 etc.)
  *             High Throughput          (AF1x, TOS2)
- *             Background Traffic       (CS1)
+ *             Background Traffic       (CS1, LE)
  *
  *             Total 8 traffic classes.
  */
@@ -2435,7 +2439,7 @@ static int cake_config_diffserv4(struct Qdisc *sch)
  *         Latency Sensitive  (CS7, CS6, EF, VA, CS5, CS4)
  *         Streaming Media    (AF4x, AF3x, CS3, AF2x, TOS4, CS2, TOS1)
  *         Best Effort        (CS0, AF1x, TOS2, and those not specified)
- *         Background Traffic (CS1)
+ *         Background Traffic (CS1, LE)
  *
  *             Total 4 traffic classes.
  */
@@ -2473,7 +2477,7 @@ static int cake_config_diffserv4(struct Qdisc *sch)
 static int cake_config_diffserv3(struct Qdisc *sch)
 {
 /*  Simplified Diffserv structure with 3 tins.
- *             Low Priority            (CS1)
+ *             Low Priority            (CS1, LE)
  *             Best Effort
  *             Latency Sensitive       (TOS4, VA, EF, CS6, CS7)
  */
index d508f6f..5ceaf75 100644 (file)
@@ -633,7 +633,7 @@ int sctp_v4_err(struct sk_buff *skb, __u32 info)
                break;
        case ICMP_REDIRECT:
                sctp_icmp_redirect(sk, transport, skb);
-               /* Fall through to out_unlock. */
+               goto out_unlock;
        default:
                goto out_unlock;
        }
@@ -1236,6 +1236,7 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net,
                                                net, ch, laddr,
                                                sctp_hdr(skb)->source,
                                                transportp);
+                       break;
                default:
                        break;
                }
index 27e3e7d..4f2c6d2 100644 (file)
@@ -1072,19 +1072,6 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
  *     what to do with it - that's up to the protocol still.
  */
 
-/**
- *     get_net_ns - increment the refcount of the network namespace
- *     @ns: common namespace (net)
- *
- *     Returns the net's common namespace.
- */
-
-struct ns_common *get_net_ns(struct ns_common *ns)
-{
-       return &get_net(container_of(ns, struct net, ns))->ns;
-}
-EXPORT_SYMBOL_GPL(get_net_ns);
-
 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
        struct socket *sock;
index 78c075a..1b40731 100644 (file)
@@ -7,13 +7,13 @@
  * Trond Myklebust <trond.myklebust@primarydata.com>
  *
  */
+#include <linux/atomic.h>
 #include <linux/types.h>
 #include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/rculist.h>
 #include <linux/slab.h>
-#include <asm/cmpxchg.h>
 #include <linux/spinlock.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/addr.h>
index c44b4bf..1b7a487 100644 (file)
@@ -654,6 +654,7 @@ int tipc_link_fsm_evt(struct tipc_link *l, int evt)
                        break;
                case LINK_FAILOVER_BEGIN_EVT:
                        l->state = LINK_FAILINGOVER;
+                       break;
                case LINK_FAILURE_EVT:
                case LINK_RESET_EVT:
                case LINK_ESTABLISH_EVT:
index 5a31307..5d1192c 100644 (file)
@@ -535,12 +535,14 @@ static void unix_release_sock(struct sock *sk, int embrion)
        u->path.mnt = NULL;
        state = sk->sk_state;
        sk->sk_state = TCP_CLOSE;
+
+       skpair = unix_peer(sk);
+       unix_peer(sk) = NULL;
+
        unix_state_unlock(sk);
 
        wake_up_interruptible_all(&u->peer_wait);
 
-       skpair = unix_peer(sk);
-
        if (skpair != NULL) {
                if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
                        unix_state_lock(skpair);
@@ -555,7 +557,6 @@ static void unix_release_sock(struct sock *sk, int embrion)
 
                unix_dgram_peer_wake_disconnect(sk, skpair);
                sock_put(skpair); /* It may now die */
-               unix_peer(sk) = NULL;
        }
 
        /* Try to flush out this socket. Throw out buffers at least */
index cc3bae2..19189cf 100644 (file)
@@ -596,7 +596,7 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
                return -EOPNOTSUPP;
 
        if (need_refill) {
-               hvs->recv_desc = hv_pkt_iter_first(hvs->chan);
+               hvs->recv_desc = hv_pkt_iter_first_raw(hvs->chan);
                ret = hvs_update_recv_data(hvs);
                if (ret)
                        return ret;
@@ -610,7 +610,7 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
 
        hvs->recv_data_len -= to_read;
        if (hvs->recv_data_len == 0) {
-               hvs->recv_desc = hv_pkt_iter_next(hvs->chan, hvs->recv_desc);
+               hvs->recv_desc = hv_pkt_iter_next_raw(hvs->chan, hvs->recv_desc);
                if (hvs->recv_desc) {
                        ret = hvs_update_recv_data(hvs);
                        if (ret)
index 2eee939..af590ae 100644 (file)
@@ -28,7 +28,7 @@ $(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
        @$(kecho) "  GEN     $@"
        @(echo '#include "reg.h"'; \
          echo 'const u8 shipped_regdb_certs[] = {'; \
-         cat $^ ; \
+         echo | cat - $^ ; \
          echo '};'; \
          echo 'unsigned int shipped_regdb_certs_len = sizeof(shipped_regdb_certs);'; \
         ) > $@
index 6fbf753..8d0883e 100644 (file)
@@ -1340,6 +1340,11 @@ void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
        rdev->devlist_generation++;
        wdev->registered = true;
 
+       if (wdev->netdev &&
+           sysfs_create_link(&wdev->netdev->dev.kobj, &rdev->wiphy.dev.kobj,
+                             "phy80211"))
+               pr_err("failed to add phy80211 symlink to netdev!\n");
+
        nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
 }
 
@@ -1365,14 +1370,6 @@ int cfg80211_register_netdevice(struct net_device *dev)
        if (ret)
                goto out;
 
-       if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
-                             "phy80211")) {
-               pr_err("failed to add phy80211 symlink to netdev!\n");
-               unregister_netdevice(dev);
-               ret = -EINVAL;
-               goto out;
-       }
-
        cfg80211_register_wdev(rdev, wdev);
        ret = 0;
 out:
index 6bdd964..d245968 100644 (file)
@@ -334,6 +334,7 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev,
                            gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct cfg80211_pmsr_request *tmp, *prev, *to_free = NULL;
        struct sk_buff *msg;
        void *hdr;
 
@@ -364,9 +365,20 @@ free_msg:
        nlmsg_free(msg);
 free_request:
        spin_lock_bh(&wdev->pmsr_lock);
-       list_del(&req->list);
+       /*
+        * cfg80211_pmsr_process_abort() may have already moved this request
+        * to the free list, and will free it later. In this case, don't free
+        * it here.
+        */
+       list_for_each_entry_safe(tmp, prev, &wdev->pmsr_list, list) {
+               if (tmp == req) {
+                       list_del(&req->list);
+                       to_free = req;
+                       break;
+               }
+       }
        spin_unlock_bh(&wdev->pmsr_lock);
-       kfree(req);
+       kfree(to_free);
 }
 EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete);
 
index 9b959e3..0c3f05c 100644 (file)
@@ -133,6 +133,10 @@ static int wiphy_resume(struct device *dev)
        if (rdev->wiphy.registered && rdev->ops->resume)
                ret = rdev_resume(rdev);
        wiphy_unlock(&rdev->wiphy);
+
+       if (ret)
+               cfg80211_shutdown_all_interfaces(&rdev->wiphy);
+
        rtnl_unlock();
 
        return ret;
index 7ec021a..18dba3d 100644 (file)
@@ -1059,6 +1059,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                case NL80211_IFTYPE_MESH_POINT:
                        /* mesh should be handled? */
                        break;
+               case NL80211_IFTYPE_OCB:
+                       cfg80211_leave_ocb(rdev, dev);
+                       break;
                default:
                        break;
                }
index 8831f5a..41de46b 100644 (file)
@@ -432,6 +432,7 @@ static int xfrmi4_err(struct sk_buff *skb, u32 info)
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
                        return 0;
+               break;
        case ICMP_REDIRECT:
                break;
        default:
index c495664..f991a66 100644 (file)
@@ -10,6 +10,8 @@
  * whenever kernel_clone() is invoked to create a new process.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
@@ -27,32 +29,31 @@ static struct kprobe kp = {
 static int __kprobes handler_pre(struct kprobe *p, struct pt_regs *regs)
 {
 #ifdef CONFIG_X86
-       pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->ip, regs->flags);
 #endif
 #ifdef CONFIG_PPC
-       pr_info("<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",
                p->symbol_name, p->addr, regs->nip, regs->msr);
 #endif
 #ifdef CONFIG_MIPS
-       pr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
 #endif
 #ifdef CONFIG_ARM64
-       pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"
-                       " pstate = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, pstate = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
 #endif
 #ifdef CONFIG_ARM
-       pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx, cpsr = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, cpsr = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->ARM_pc, (long)regs->ARM_cpsr);
 #endif
 #ifdef CONFIG_RISCV
-       pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx, status = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, pc = 0x%lx, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->epc, regs->status);
 #endif
 #ifdef CONFIG_S390
-       pr_info("<%s> pre_handler: p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",
+       pr_info("<%s> p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->psw.addr, regs->flags);
 #endif
 
@@ -65,55 +66,40 @@ static void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs,
                                unsigned long flags)
 {
 #ifdef CONFIG_X86
-       pr_info("<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->flags);
 #endif
 #ifdef CONFIG_PPC
-       pr_info("<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, msr = 0x%lx\n",
                p->symbol_name, p->addr, regs->msr);
 #endif
 #ifdef CONFIG_MIPS
-       pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->cp0_status);
 #endif
 #ifdef CONFIG_ARM64
-       pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, pstate = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->pstate);
 #endif
 #ifdef CONFIG_ARM
-       pr_info("<%s> post_handler: p->addr = 0x%p, cpsr = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, cpsr = 0x%lx\n",
                p->symbol_name, p->addr, (long)regs->ARM_cpsr);
 #endif
 #ifdef CONFIG_RISCV
-       pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
+       pr_info("<%s> p->addr = 0x%p, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->status);
 #endif
 #ifdef CONFIG_S390
-       pr_info("<%s> pre_handler: p->addr, 0x%p, flags = 0x%lx\n",
+       pr_info("<%s> p->addr, 0x%p, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->flags);
 #endif
 }
 
-/*
- * fault_handler: this is called if an exception is generated for any
- * instruction within the pre- or post-handler, or when Kprobes
- * single-steps the probed instruction.
- */
-static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
-{
-       pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
-       /* Return 0 because we don't handle the fault. */
-       return 0;
-}
-/* NOKPROBE_SYMBOL() is also available */
-NOKPROBE_SYMBOL(handler_fault);
-
 static int __init kprobe_init(void)
 {
        int ret;
        kp.pre_handler = handler_pre;
        kp.post_handler = handler_post;
-       kp.fault_handler = handler_fault;
 
        ret = register_kprobe(&kp);
        if (ret < 0) {
index 949f723..34d2576 100644 (file)
@@ -268,7 +268,8 @@ define rule_as_o_S
 endef
 
 # Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
+.SECONDEXPANSION:
+$(obj)/%.o: $(src)/%.c $(recordmcount_source) $$(objtool_dep) FORCE
        $(call if_changed_rule,cc_o_c)
        $(call cmd,force_checksrc)
 
@@ -349,7 +350,7 @@ cmd_modversions_S =                                                         \
        fi
 endif
 
-$(obj)/%.o: $(src)/%.S $(objtool_dep) FORCE
+$(obj)/%.o: $(src)/%.S $$(objtool_dep) FORCE
        $(call if_changed_rule,as_o_S)
 
 targets += $(filter-out $(subdir-builtin), $(real-obj-y))
index 3d79190..801c415 100644 (file)
@@ -50,6 +50,7 @@ endif
 CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
                $(call cc-param,hwasan-instrument-stack=$(stack_enable)) \
                $(call cc-param,hwasan-use-short-granules=0) \
+               $(call cc-param,hwasan-inline-all-checks=0) \
                $(instrumentation_flags)
 
 endif # CONFIG_KASAN_SW_TAGS
index 82748d4..9c7fbd4 100755 (executable)
@@ -17,7 +17,6 @@ cat <<EOF |
 asm-generic/atomic-instrumented.h
 asm-generic/atomic-long.h
 linux/atomic-arch-fallback.h
-linux/atomic-fallback.h
 EOF
 while read header; do
        OLDSUM="$(tail -n 1 ${LINUXDIR}/include/${header})"
index 5766ffc..b0c45ae 100755 (executable)
@@ -41,34 +41,6 @@ gen_params_checks()
        done
 }
 
-# gen_guard(meta, atomic, pfx, name, sfx, order)
-gen_guard()
-{
-       local meta="$1"; shift
-       local atomic="$1"; shift
-       local pfx="$1"; shift
-       local name="$1"; shift
-       local sfx="$1"; shift
-       local order="$1"; shift
-
-       local atomicname="arch_${atomic}_${pfx}${name}${sfx}${order}"
-
-       local template="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
-
-       # We definitely need a preprocessor symbol for this atomic if it is an
-       # ordering variant, or if there's a generic fallback.
-       if [ ! -z "${order}" ] || [ ! -z "${template}" ]; then
-               printf "defined(${atomicname})"
-               return
-       fi
-
-       # If this is a base variant, but a relaxed variant *may* exist, then we
-       # only have a preprocessor symbol if the relaxed variant isn't defined
-       if meta_has_relaxed "${meta}"; then
-               printf "!defined(${atomicname}_relaxed) || defined(${atomicname})"
-       fi
-}
-
 #gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, arg...)
 gen_proto_order_variant()
 {
@@ -82,16 +54,12 @@ gen_proto_order_variant()
 
        local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
 
-       local guard="$(gen_guard "${meta}" "${atomic}" "${pfx}" "${name}" "${sfx}" "${order}")"
-
        local ret="$(gen_ret_type "${meta}" "${int}")"
        local params="$(gen_params "${int}" "${atomic}" "$@")"
        local checks="$(gen_params_checks "${meta}" "$@")"
        local args="$(gen_args "$@")"
        local retstmt="$(gen_ret_stmt "${meta}")"
 
-       [ ! -z "${guard}" ] && printf "#if ${guard}\n"
-
 cat <<EOF
 static __always_inline ${ret}
 ${atomicname}(${params})
@@ -99,11 +67,8 @@ ${atomicname}(${params})
 ${checks}
        ${retstmt}arch_${atomicname}(${args});
 }
-#define ${atomicname} ${atomicname}
 EOF
 
-       [ ! -z "${guard}" ] && printf "#endif\n"
-
        printf "\n"
 }
 
@@ -139,19 +104,6 @@ EOF
        fi
 }
 
-gen_optional_xchg()
-{
-       local name="$1"; shift
-       local sfx="$1"; shift
-       local guard="defined(arch_${name}${sfx})"
-
-       [ -z "${sfx}" ] && guard="!defined(arch_${name}_relaxed) || defined(arch_${name})"
-
-       printf "#if ${guard}\n"
-       gen_xchg "${name}${sfx}" ""
-       printf "#endif\n\n"
-}
-
 cat << EOF
 // SPDX-License-Identifier: GPL-2.0
 
@@ -188,7 +140,8 @@ done
 
 for xchg in "xchg" "cmpxchg" "cmpxchg64" "try_cmpxchg"; do
        for order in "" "_acquire" "_release" "_relaxed"; do
-               gen_optional_xchg "${xchg}" "${order}"
+               gen_xchg "${xchg}${order}" ""
+               printf "\n"
        done
 done
 
index d29e159..f776a57 100755 (executable)
@@ -11,7 +11,6 @@ cat <<EOF |
 gen-atomic-instrumented.sh      asm-generic/atomic-instrumented.h
 gen-atomic-long.sh              asm-generic/atomic-long.h
 gen-atomic-fallback.sh          linux/atomic-arch-fallback.h           arch_
-gen-atomic-fallback.sh          linux/atomic-fallback.h
 EOF
 while read script header args; do
        /bin/sh ${ATOMICDIR}/${script} ${ATOMICTBL} ${args} > ${LINUXDIR}/include/${header}
index c71832b..7187ea5 100755 (executable)
@@ -24,7 +24,7 @@ my $help = 0;
 my $fix = 0;
 my $warn = 0;
 
-if (! -d ".git") {
+if (! -e ".git") {
        printf "Warning: can't check if file exists, as this is not a git tree\n";
        exit 0;
 }
index 4840e74..7c4a6a5 100755 (executable)
@@ -406,6 +406,8 @@ my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)';
 my $doc_inline_end = '^\s*\*/\s*$';
 my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$';
 my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
+my $function_pointer = qr{([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)};
+my $attribute = qr{__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)}i;
 
 my %parameterdescs;
 my %parameterdesc_start_lines;
@@ -694,7 +696,7 @@ sub output_function_man(%) {
            $post = ");";
        }
        $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+       if ($type =~ m/$function_pointer/) {
            # pointer-to-function
            print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n";
        } else {
@@ -974,7 +976,7 @@ sub output_function_rst(%) {
        $count++;
        $type = $args{'parametertypes'}{$parameter};
 
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+       if ($type =~ m/$function_pointer/) {
            # pointer-to-function
            print $1 . $parameter . ") (" . $2 . ")";
        } else {
@@ -1211,7 +1213,9 @@ sub dump_struct($$) {
     my $members;
     my $type = qr{struct|union};
     # For capturing struct/union definition body, i.e. "{members*}qualifiers*"
-    my $definition_body = qr{\{(.*)\}(?:\s*(?:__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*};
+    my $qualifiers = qr{$attribute|__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned};
+    my $definition_body = qr{\{(.*)\}\s*$qualifiers*};
+    my $struct_members = qr{($type)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;};
 
     if ($x =~ /($type)\s+(\w+)\s*$definition_body/) {
        $decl_type = $1;
@@ -1235,27 +1239,27 @@ sub dump_struct($$) {
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
        # strip attributes
-       $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi;
+       $members =~ s/\s*$attribute/ /gi;
        $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos;
        $members =~ s/\s*__packed\s*/ /gos;
        $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
        $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
        $members =~ s/\s*____cacheline_aligned/ /gos;
 
+       my $args = qr{([^,)]+)};
        # replace DECLARE_BITMAP
        $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos;
-       $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
+       $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
        # replace DECLARE_HASHTABLE
-       $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
+       $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
        # replace DECLARE_KFIFO
-       $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
+       $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos;
        # replace DECLARE_KFIFO_PTR
-       $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
-
+       $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos;
        my $declaration = $members;
 
        # Split nested struct/union elements as newer ones
-       while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) {
+       while ($members =~ m/$struct_members/) {
                my $newmember;
                my $maintype = $1;
                my $ids = $4;
@@ -1315,7 +1319,7 @@ sub dump_struct($$) {
                                }
                        }
                }
-               $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/;
+               $members =~ s/$struct_members/$newmember/;
        }
 
        # Ignore other nested elements, like enums
@@ -1555,8 +1559,9 @@ sub create_parameterlist($$$$) {
     my $param;
 
     # temporarily replace commas inside function pointer definition
-    while ($args =~ /(\([^\),]+),/) {
-       $args =~ s/(\([^\),]+),/$1#/g;
+    my $arg_expr = qr{\([^\),]+};
+    while ($args =~ /$arg_expr,/) {
+       $args =~ s/($arg_expr),/$1#/g;
     }
 
     foreach my $arg (split($splitter, $args)) {
@@ -1707,7 +1712,7 @@ sub check_sections($$$$$) {
                foreach $px (0 .. $#prms) {
                        $prm_clean = $prms[$px];
                        $prm_clean =~ s/\[.*\]//;
-                       $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+                       $prm_clean =~ s/$attribute//i;
                        # ignore array size in a parameter string;
                        # however, the original param string may contain
                        # spaces, e.g.:  addr[6 + 2]
@@ -1809,8 +1814,14 @@ sub dump_function($$) {
     # - parport_register_device (function pointer parameters)
     # - atomic_set (macro)
     # - pci_match_device, __copy_to_user (long return type)
-
-    if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) {
+    my $name = qr{[a-zA-Z0-9_~:]+};
+    my $prototype_end1 = qr{[^\(]*};
+    my $prototype_end2 = qr{[^\{]*};
+    my $prototype_end = qr{\(($prototype_end1|$prototype_end2)\)};
+    my $type1 = qr{[\w\s]+};
+    my $type2 = qr{$type1\*+};
+
+    if ($define && $prototype =~ m/^()($name)\s+/) {
         # This is an object-like macro, it has no return type and no parameter
         # list.
         # Function-like macros are not allowed to have spaces between
@@ -1818,23 +1829,9 @@ sub dump_function($$) {
         $return_type = $1;
         $declaration_name = $2;
         $noret = 1;
-    } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
-       $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
-       $prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
+    } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ ||
+       $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ ||
+       $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/)  {
        $return_type = $1;
        $declaration_name = $2;
        my $args = $3;
@@ -2111,12 +2108,12 @@ sub process_name($$) {
     } elsif (/$doc_decl/o) {
        $identifier = $1;
        my $is_kernel_comment = 0;
-       my $decl_start = qr{\s*\*};
+       my $decl_start = qr{$doc_com};
        # test for pointer declaration type, foo * bar() - desc
        my $fn_type = qr{\w+\s*\*\s*}; 
        my $parenthesis = qr{\(\w*\)};
        my $decl_end = qr{[-:].*};
-       if (/^$decl_start\s*([\w\s]+?)$parenthesis?\s*$decl_end?$/) {
+       if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) {
            $identifier = $1;
        }
        if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) {
@@ -2126,8 +2123,8 @@ sub process_name($$) {
        }
        # Look for foo() or static void foo() - description; or misspelt
        # identifier
-       elsif (/^$decl_start\s*$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ ||
-           /^$decl_start\s*$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) {
+       elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ ||
+           /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) {
            $identifier = $1;
            $decl_type = 'function';
            $identifier =~ s/^define\s+//;
index f9b1952..1e9baa5 100644 (file)
@@ -192,15 +192,20 @@ static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
                                 Elf32_Word const *symtab_shndx)
 {
        unsigned long offset;
+       unsigned short shndx = w2(sym->st_shndx);
        int index;
 
-       if (sym->st_shndx != SHN_XINDEX)
-               return w2(sym->st_shndx);
+       if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
+               return shndx;
 
-       offset = (unsigned long)sym - (unsigned long)symtab;
-       index = offset / sizeof(*sym);
+       if (shndx == SHN_XINDEX) {
+               offset = (unsigned long)sym - (unsigned long)symtab;
+               index = offset / sizeof(*sym);
 
-       return w(symtab_shndx[index]);
+               return w(symtab_shndx[index]);
+       }
+
+       return 0;
 }
 
 static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
index fe92020..288e86a 100755 (executable)
@@ -22,16 +22,18 @@ my $need = 0;
 my $optional = 0;
 my $need_symlink = 0;
 my $need_sphinx = 0;
-my $need_venv = 0;
+my $need_pip = 0;
 my $need_virtualenv = 0;
 my $rec_sphinx_upgrade = 0;
 my $install = "";
 my $virtenv_dir = "";
 my $python_cmd = "";
+my $activate_cmd;
 my $min_version;
 my $cur_version;
 my $rec_version = "1.7.9";     # PDF won't build here
 my $min_pdf_version = "2.4.4"; # Min version where pdf builds
+my $latest_avail_ver;
 
 #
 # Command line arguments
@@ -319,10 +321,7 @@ sub check_sphinx()
                return;
        }
 
-       if ($cur_version lt $rec_version) {
-               $rec_sphinx_upgrade = 1;
-               return;
-       }
+       return if ($cur_version lt $rec_version);
 
        # On version check mode, just assume Sphinx has all mandatory deps
        exit (0) if ($version_check);
@@ -701,6 +700,162 @@ sub deactivate_help()
        printf "\tdeactivate\n";
 }
 
+sub get_virtenv()
+{
+       my $ver;
+       my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate";
+       my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate";
+
+       @activates = sort {$b cmp $a} @activates;
+
+       foreach my $f (@activates) {
+               next if ($f lt $min_activate);
+
+               my $sphinx_cmd = $f;
+               $sphinx_cmd =~ s/activate/sphinx-build/;
+               next if (! -f $sphinx_cmd);
+
+               my $ver = get_sphinx_version($sphinx_cmd);
+               if ($need_sphinx && ($ver ge $min_version)) {
+                       return ($f, $ver);
+               } elsif ($ver gt $cur_version) {
+                       return ($f, $ver);
+               }
+       }
+       return ("", "");
+}
+
+sub recommend_sphinx_upgrade()
+{
+       my $venv_ver;
+
+       # Avoid running sphinx-builds from venv if $cur_version is good
+       if ($cur_version && ($cur_version ge $rec_version)) {
+               $latest_avail_ver = $cur_version;
+               return;
+       }
+
+       # Get the highest version from sphinx_*/bin/sphinx-build and the
+       # corresponding command to activate the venv/virtenv
+       $activate_cmd = get_virtenv();
+
+       # Store the highest version from Sphinx existing virtualenvs
+       if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) {
+               $latest_avail_ver = $venv_ver;
+       } else {
+               $latest_avail_ver = $cur_version if ($cur_version);
+       }
+
+       # As we don't know package version of Sphinx, and there's no
+       # virtual environments, don't check if upgrades are needed
+       if (!$virtualenv) {
+               return if (!$latest_avail_ver);
+       }
+
+       # Either there are already a virtual env or a new one should be created
+       $need_pip = 1;
+
+       # Return if the reason is due to an upgrade or not
+       if ($latest_avail_ver lt $rec_version) {
+               $rec_sphinx_upgrade = 1;
+       }
+}
+
+#
+# The logic here is complex, as it have to deal with different versions:
+#      - minimal supported version;
+#      - minimal PDF version;
+#      - recommended version.
+# It also needs to work fine with both distro's package and venv/virtualenv
+sub recommend_sphinx_version($)
+{
+       my $virtualenv_cmd = shift;
+
+       if ($latest_avail_ver lt $min_pdf_version) {
+               print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
+       }
+
+       # Version is OK. Nothing to do.
+       return if ($cur_version && ($cur_version ge $rec_version));
+
+       if (!$need_sphinx) {
+               # sphinx-build is present and its version is >= $min_version
+
+               #only recommend enabling a newer virtenv version if makes sense.
+               if ($latest_avail_ver gt $cur_version) {
+                       printf "\nYou may also use the newer Sphinx version $latest_avail_ver with:\n";
+                       printf "\tdeactivate\n"  if ($ENV{'PWD'} =~ /${virtenv_prefix}/);
+                       printf "\t. $activate_cmd\n";
+                       deactivate_help();
+
+                       return;
+               }
+               return if ($latest_avail_ver ge $rec_version);
+       }
+
+       if (!$virtualenv) {
+               # No sphinx either via package or via virtenv. As we can't
+               # Compare the versions here, just return, recommending the
+               # user to install it from the package distro.
+               return if (!$latest_avail_ver);
+
+               # User doesn't want a virtenv recommendation, but he already
+               # installed one via virtenv with a newer version.
+               # So, print commands to enable it
+               if ($latest_avail_ver gt $cur_version) {
+                       printf "\nYou may also use the Sphinx virtualenv version $latest_avail_ver with:\n";
+                       printf "\tdeactivate\n"  if ($ENV{'PWD'} =~ /${virtenv_prefix}/);
+                       printf "\t. $activate_cmd\n";
+                       deactivate_help();
+
+                       return;
+               }
+               print "\n";
+       } else {
+               $need++ if ($need_sphinx);
+       }
+
+       # Suggest newer versions if current ones are too old
+       if ($latest_avail_ver && $cur_version ge $min_version) {
+               # If there's a good enough version, ask the user to enable it
+               if ($latest_avail_ver ge $rec_version) {
+                       printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n";
+                       printf "\t. $activate_cmd\n";
+                       deactivate_help();
+
+                       return;
+               }
+
+               # Version is above the minimal required one, but may be
+               # below the recommended one. So, print warnings/notes
+
+               if ($latest_avail_ver lt $rec_version) {
+                       print "Warning: It is recommended at least Sphinx version $rec_version.\n";
+               }
+       }
+
+       # At this point, either it needs Sphinx or upgrade is recommended,
+       # both via pip
+
+       if ($rec_sphinx_upgrade) {
+               if (!$virtualenv) {
+                       print "Instead of install/upgrade Python Sphinx pkg, you could use pip/pypi with:\n\n";
+               } else {
+                       print "To upgrade Sphinx, use:\n\n";
+               }
+       } else {
+               print "Sphinx needs to be installed either as a package or via pip/pypi with:\n";
+       }
+
+       $python_cmd = find_python_no_venv();
+
+       printf "\t$virtualenv_cmd $virtenv_dir\n";
+
+       printf "\t. $virtenv_dir/bin/activate\n";
+       printf "\tpip install -r $requirement_file\n";
+       deactivate_help();
+}
+
 sub check_needs()
 {
        # Check if Sphinx is already accessible from current environment
@@ -722,15 +877,14 @@ sub check_needs()
                if ($virtualenv) {
                        my $tmp = qx($python_cmd --version 2>&1);
                        if ($tmp =~ m/(\d+\.)(\d+\.)/) {
-                               if ($1 >= 3 && $2 >= 3) {
-                                       $need_venv = 1;         # python 3.3 or upper
-                               } else {
-                                       $need_virtualenv = 1;
-                               }
                                if ($1 < 3) {
                                        # Fail if it finds python2 (or worse)
                                        die "Python 3 is required to build the kernel docs\n";
                                }
+                               if ($1 == 3 && $2 < 3) {
+                                       # Need Python 3.3 or upper for venv
+                                       $need_virtualenv = 1;
+                               }
                        } else {
                                die "Warning: couldn't identify $python_cmd version!";
                        }
@@ -739,14 +893,22 @@ sub check_needs()
                }
        }
 
-       # Set virtualenv command line, if python < 3.3
+       recommend_sphinx_upgrade();
+
        my $virtualenv_cmd;
-       if ($need_virtualenv) {
-               $virtualenv_cmd = findprog("virtualenv-3");
-               $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd);
-               if (!$virtualenv_cmd) {
-                       check_program("virtualenv", 0);
-                       $virtualenv_cmd = "virtualenv";
+
+       if ($need_pip) {
+               # Set virtualenv command line, if python < 3.3
+               if ($need_virtualenv) {
+                       $virtualenv_cmd = findprog("virtualenv-3");
+                       $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd);
+                       if (!$virtualenv_cmd) {
+                               check_program("virtualenv", 0);
+                               $virtualenv_cmd = "virtualenv";
+                       }
+               } else {
+                       $virtualenv_cmd = "$python_cmd -m venv";
+                       check_python_module("ensurepip", 0);
                }
        }
 
@@ -763,10 +925,6 @@ sub check_needs()
        check_program("rsvg-convert", 2) if ($pdf);
        check_program("latexmk", 2) if ($pdf);
 
-       if ($need_sphinx || $rec_sphinx_upgrade) {
-               check_python_module("ensurepip", 0) if ($need_venv);
-       }
-
        # Do distro-specific checks and output distro-install commands
        check_distros();
 
@@ -784,67 +942,7 @@ sub check_needs()
                       which("sphinx-build-3");
        }
 
-       # NOTE: if the system has a too old Sphinx version installed,
-       # it will recommend installing a newer version using virtualenv
-
-       if ($need_sphinx || $rec_sphinx_upgrade) {
-               my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate";
-               my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate";
-
-               if ($cur_version lt $rec_version) {
-                       print "Warning: It is recommended at least Sphinx version $rec_version.\n";
-                       print "         If you want pdf, you need at least $min_pdf_version.\n";
-               }
-               if ($cur_version lt $min_pdf_version) {
-                       print "Note: It is recommended at least Sphinx version $min_pdf_version if you need PDF support.\n";
-               }
-               @activates = sort {$b cmp $a} @activates;
-               my ($activate, $ver);
-               foreach my $f (@activates) {
-                       next if ($f lt $min_activate);
-
-                       my $sphinx_cmd = $f;
-                       $sphinx_cmd =~ s/activate/sphinx-build/;
-                       next if (! -f $sphinx_cmd);
-
-                       $ver = get_sphinx_version($sphinx_cmd);
-                       if ($need_sphinx && ($ver ge $min_version)) {
-                               $activate = $f;
-                               last;
-                       } elsif ($ver gt $cur_version) {
-                               $activate = $f;
-                               last;
-                       }
-               }
-               if ($activate ne "") {
-                       if ($need_sphinx) {
-                               printf "\nNeed to activate Sphinx (version $ver) on virtualenv with:\n";
-                               printf "\t. $activate\n";
-                               deactivate_help();
-                               exit (1);
-                       } else {
-                               printf "\nYou may also use a newer Sphinx (version $ver) with:\n";
-                               printf "\tdeactivate && . $activate\n";
-                       }
-               } else {
-                       my $rec_activate = "$virtenv_dir/bin/activate";
-
-                       print "To upgrade Sphinx, use:\n\n" if ($rec_sphinx_upgrade);
-
-                       $python_cmd = find_python_no_venv();
-
-                       if ($need_venv) {
-                               printf "\t$python_cmd -m venv $virtenv_dir\n";
-                       } else {
-                               printf "\t$virtualenv_cmd $virtenv_dir\n";
-                       }
-                       printf "\t. $rec_activate\n";
-                       printf "\tpip install -r $requirement_file\n";
-                       deactivate_help();
-
-                       $need++ if (!$rec_sphinx_upgrade);
-               }
-       }
+       recommend_sphinx_version($virtualenv_cmd);
        printf "\n";
 
        print "All optional dependencies are met.\n" if (!$optional);
index 45e8aa3..cb55878 100755 (executable)
@@ -7,7 +7,8 @@ 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
+$LD $tmp_file.o -shared -Bsymbolic --pack-dyn-relocs=relr \
+  --use-android-relr-tags -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.
index f2fef2b..0d44f41 100644 (file)
@@ -29,6 +29,7 @@
 struct xattr_list {
        struct list_head list;
        char *name;
+       bool enabled;
 };
 
 extern int evm_initialized;
index d76b006..0450d79 100644 (file)
@@ -10,6 +10,8 @@
  *      Using root's kernel master key (kmk), calculate the HMAC
  */
 
+#define pr_fmt(fmt) "EVM: "fmt
+
 #include <linux/export.h>
 #include <linux/crypto.h>
 #include <linux/xattr.h>
@@ -175,6 +177,30 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
            type != EVM_XATTR_PORTABLE_DIGSIG)
                crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
        crypto_shash_final(desc, digest);
+
+       pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
+                (int)sizeof(struct h_misc), &hmac_misc);
+}
+
+/*
+ * Dump large security xattr values as a continuous ascii hexademical string.
+ * (pr_debug is limited to 64 bytes.)
+ */
+static void dump_security_xattr(const char *prefix, const void *src,
+                               size_t count)
+{
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
+       char *asciihex, *p;
+
+       p = asciihex = kmalloc(count * 2 + 1, GFP_KERNEL);
+       if (!asciihex)
+               return;
+
+       p = bin2hex(p, src, count);
+       *p = 0;
+       pr_debug("%s: (%zu) %.*s\n", prefix, count, (int)count * 2, asciihex);
+       kfree(asciihex);
+#endif
 }
 
 /*
@@ -196,7 +222,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
        size_t xattr_size = 0;
        char *xattr_value = NULL;
        int error;
-       int size;
+       int size, user_space_size;
        bool ima_present = false;
 
        if (!(inode->i_opflags & IOP_XATTR) ||
@@ -216,6 +242,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                if (strcmp(xattr->name, XATTR_NAME_IMA) == 0)
                        is_ima = true;
 
+               /*
+                * Skip non-enabled xattrs for locally calculated
+                * signatures/HMACs.
+                */
+               if (type != EVM_XATTR_PORTABLE_DIGSIG && !xattr->enabled)
+                       continue;
+
                if ((req_xattr_name && req_xattr_value)
                    && !strcmp(xattr->name, req_xattr_name)) {
                        error = 0;
@@ -223,6 +256,16 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                                             req_xattr_value_len);
                        if (is_ima)
                                ima_present = true;
+
+                       if (req_xattr_value_len < 64)
+                               pr_debug("%s: (%zu) [%*phN]\n", req_xattr_name,
+                                        req_xattr_value_len,
+                                        (int)req_xattr_value_len,
+                                        req_xattr_value);
+                       else
+                               dump_security_xattr(req_xattr_name,
+                                                   req_xattr_value,
+                                                   req_xattr_value_len);
                        continue;
                }
                size = vfs_getxattr_alloc(&init_user_ns, dentry, xattr->name,
@@ -234,11 +277,24 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
                if (size < 0)
                        continue;
 
+               user_space_size = vfs_getxattr(&init_user_ns, dentry,
+                                              xattr->name, NULL, 0);
+               if (user_space_size != size)
+                       pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
+                                dentry->d_name.name, xattr->name, size,
+                                user_space_size);
                error = 0;
                xattr_size = size;
                crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
                if (is_ima)
                        ima_present = true;
+
+               if (xattr_size < 64)
+                       pr_debug("%s: (%zu) [%*phN]", xattr->name, xattr_size,
+                                (int)xattr_size, xattr_value);
+               else
+                       dump_security_xattr(xattr->name, xattr_value,
+                                           xattr_size);
        }
        hmac_add_misc(desc, inode, type, data->digest);
 
index 0de367a..1c8435d 100644 (file)
@@ -11,6 +11,8 @@
  *     evm_inode_removexattr, and evm_verifyxattr
  */
 
+#define pr_fmt(fmt) "EVM: "fmt
+
 #include <linux/init.h>
 #include <linux/crypto.h>
 #include <linux/audit.h>
@@ -18,6 +20,7 @@
 #include <linux/integrity.h>
 #include <linux/evm.h>
 #include <linux/magic.h>
+#include <linux/posix_acl_xattr.h>
 
 #include <crypto/hash.h>
 #include <crypto/hash_info.h>
 int evm_initialized;
 
 static const char * const integrity_status_msg[] = {
-       "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
+       "pass", "pass_immutable", "fail", "fail_immutable", "no_label",
+       "no_xattrs", "unknown"
 };
 int evm_hmac_attrs;
 
 static struct xattr_list evm_config_default_xattrnames[] = {
+       {.name = XATTR_NAME_SELINUX,
 #ifdef CONFIG_SECURITY_SELINUX
-       {.name = XATTR_NAME_SELINUX},
+        .enabled = true
 #endif
+       },
+       {.name = XATTR_NAME_SMACK,
 #ifdef CONFIG_SECURITY_SMACK
-       {.name = XATTR_NAME_SMACK},
+        .enabled = true
+#endif
+       },
+       {.name = XATTR_NAME_SMACKEXEC,
 #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
-       {.name = XATTR_NAME_SMACKEXEC},
-       {.name = XATTR_NAME_SMACKTRANSMUTE},
-       {.name = XATTR_NAME_SMACKMMAP},
+        .enabled = true
 #endif
+       },
+       {.name = XATTR_NAME_SMACKTRANSMUTE,
+#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
+        .enabled = true
+#endif
+       },
+       {.name = XATTR_NAME_SMACKMMAP,
+#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
+        .enabled = true
 #endif
+       },
+       {.name = XATTR_NAME_APPARMOR,
 #ifdef CONFIG_SECURITY_APPARMOR
-       {.name = XATTR_NAME_APPARMOR},
+        .enabled = true
 #endif
+       },
+       {.name = XATTR_NAME_IMA,
 #ifdef CONFIG_IMA_APPRAISE
-       {.name = XATTR_NAME_IMA},
+        .enabled = true
 #endif
-       {.name = XATTR_NAME_CAPS},
+       },
+       {.name = XATTR_NAME_CAPS,
+        .enabled = true
+       },
 };
 
 LIST_HEAD(evm_config_xattrnames);
@@ -74,7 +98,9 @@ static void __init evm_init_config(void)
 
        pr_info("Initialising EVM extended attributes:\n");
        for (i = 0; i < xattrs; i++) {
-               pr_info("%s\n", evm_config_default_xattrnames[i].name);
+               pr_info("%s%s\n", evm_config_default_xattrnames[i].name,
+                       !evm_config_default_xattrnames[i].enabled ?
+                       " (disabled)" : "");
                list_add_tail(&evm_config_default_xattrnames[i].list,
                              &evm_config_xattrnames);
        }
@@ -90,6 +116,24 @@ static bool evm_key_loaded(void)
        return (bool)(evm_initialized & EVM_KEY_MASK);
 }
 
+/*
+ * This function determines whether or not it is safe to ignore verification
+ * errors, based on the ability of EVM to calculate HMACs. If the HMAC key
+ * is not loaded, and it cannot be loaded in the future due to the
+ * EVM_SETUP_COMPLETE initialization flag, allowing an operation despite the
+ * attrs/xattrs being found invalid will not make them valid.
+ */
+static bool evm_hmac_disabled(void)
+{
+       if (evm_initialized & EVM_INIT_HMAC)
+               return false;
+
+       if (!(evm_initialized & EVM_SETUP_COMPLETE))
+               return false;
+
+       return true;
+}
+
 static int evm_find_protected_xattrs(struct dentry *dentry)
 {
        struct inode *inode = d_backing_inode(dentry);
@@ -137,7 +181,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
        enum integrity_status evm_status = INTEGRITY_PASS;
        struct evm_digest digest;
        struct inode *inode;
-       int rc, xattr_len;
+       int rc, xattr_len, evm_immutable = 0;
 
        if (iint && (iint->evm_status == INTEGRITY_PASS ||
                     iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
@@ -182,8 +226,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                if (rc)
                        rc = -EINVAL;
                break;
-       case EVM_IMA_XATTR_DIGSIG:
        case EVM_XATTR_PORTABLE_DIGSIG:
+               evm_immutable = 1;
+               fallthrough;
+       case EVM_IMA_XATTR_DIGSIG:
                /* accept xattr with non-empty signature field */
                if (xattr_len <= sizeof(struct signature_v2_hdr)) {
                        evm_status = INTEGRITY_FAIL;
@@ -220,9 +266,16 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                break;
        }
 
-       if (rc)
-               evm_status = (rc == -ENODATA) ?
-                               INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+       if (rc) {
+               if (rc == -ENODATA)
+                       evm_status = INTEGRITY_NOXATTRS;
+               else if (evm_immutable)
+                       evm_status = INTEGRITY_FAIL_IMMUTABLE;
+               else
+                       evm_status = INTEGRITY_FAIL;
+       }
+       pr_debug("digest: (%d) [%*phN]\n", digest.hdr.length, digest.hdr.length,
+                 digest.digest);
 out:
        if (iint)
                iint->evm_status = evm_status;
@@ -230,7 +283,8 @@ out:
        return evm_status;
 }
 
-static int evm_protected_xattr(const char *req_xattr_name)
+static int evm_protected_xattr_common(const char *req_xattr_name,
+                                     bool all_xattrs)
 {
        int namelen;
        int found = 0;
@@ -238,6 +292,9 @@ static int evm_protected_xattr(const char *req_xattr_name)
 
        namelen = strlen(req_xattr_name);
        list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
+               if (!all_xattrs && !xattr->enabled)
+                       continue;
+
                if ((strlen(xattr->name) == namelen)
                    && (strncmp(req_xattr_name, xattr->name, namelen) == 0)) {
                        found = 1;
@@ -254,6 +311,85 @@ static int evm_protected_xattr(const char *req_xattr_name)
        return found;
 }
 
+static int evm_protected_xattr(const char *req_xattr_name)
+{
+       return evm_protected_xattr_common(req_xattr_name, false);
+}
+
+int evm_protected_xattr_if_enabled(const char *req_xattr_name)
+{
+       return evm_protected_xattr_common(req_xattr_name, true);
+}
+
+/**
+ * evm_read_protected_xattrs - read EVM protected xattr names, lengths, values
+ * @dentry: dentry of the read xattrs
+ * @inode: inode of the read xattrs
+ * @buffer: buffer xattr names, lengths or values are copied to
+ * @buffer_size: size of buffer
+ * @type: n: names, l: lengths, v: values
+ * @canonical_fmt: data format (true: little endian, false: native format)
+ *
+ * Read protected xattr names (separated by |), lengths (u32) or values for a
+ * given dentry and return the total size of copied data. If buffer is NULL,
+ * just return the total size.
+ *
+ * Returns the total size on success, a negative value on error.
+ */
+int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
+                             int buffer_size, char type, bool canonical_fmt)
+{
+       struct xattr_list *xattr;
+       int rc, size, total_size = 0;
+
+       list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
+               rc = __vfs_getxattr(dentry, d_backing_inode(dentry),
+                                   xattr->name, NULL, 0);
+               if (rc < 0 && rc == -ENODATA)
+                       continue;
+               else if (rc < 0)
+                       return rc;
+
+               switch (type) {
+               case 'n':
+                       size = strlen(xattr->name) + 1;
+                       if (buffer) {
+                               if (total_size)
+                                       *(buffer + total_size - 1) = '|';
+
+                               memcpy(buffer + total_size, xattr->name, size);
+                       }
+                       break;
+               case 'l':
+                       size = sizeof(u32);
+                       if (buffer) {
+                               if (canonical_fmt)
+                                       rc = (__force int)cpu_to_le32(rc);
+
+                               *(u32 *)(buffer + total_size) = rc;
+                       }
+                       break;
+               case 'v':
+                       size = rc;
+                       if (buffer) {
+                               rc = __vfs_getxattr(dentry,
+                                       d_backing_inode(dentry), xattr->name,
+                                       buffer + total_size,
+                                       buffer_size - total_size);
+                               if (rc < 0)
+                                       return rc;
+                       }
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               total_size += size;
+       }
+
+       return total_size;
+}
+
 /**
  * evm_verifyxattr - verify the integrity of the requested xattr
  * @dentry: object of the verify xattr
@@ -305,6 +441,92 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
 }
 
 /*
+ * evm_xattr_acl_change - check if passed ACL changes the inode mode
+ * @mnt_userns: user namespace of the idmapped mount
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Check if passed ACL changes the inode mode, which is protected by EVM.
+ *
+ * Returns 1 if passed ACL causes inode mode change, 0 otherwise.
+ */
+static int evm_xattr_acl_change(struct user_namespace *mnt_userns,
+                               struct dentry *dentry, const char *xattr_name,
+                               const void *xattr_value, size_t xattr_value_len)
+{
+#ifdef CONFIG_FS_POSIX_ACL
+       umode_t mode;
+       struct posix_acl *acl = NULL, *acl_res;
+       struct inode *inode = d_backing_inode(dentry);
+       int rc;
+
+       /*
+        * user_ns is not relevant here, ACL_USER/ACL_GROUP don't have impact
+        * on the inode mode (see posix_acl_equiv_mode()).
+        */
+       acl = posix_acl_from_xattr(&init_user_ns, xattr_value, xattr_value_len);
+       if (IS_ERR_OR_NULL(acl))
+               return 1;
+
+       acl_res = acl;
+       /*
+        * Passing mnt_userns is necessary to correctly determine the GID in
+        * an idmapped mount, as the GID is used to clear the setgid bit in
+        * the inode mode.
+        */
+       rc = posix_acl_update_mode(mnt_userns, inode, &mode, &acl_res);
+
+       posix_acl_release(acl);
+
+       if (rc)
+               return 1;
+
+       if (inode->i_mode != mode)
+               return 1;
+#endif
+       return 0;
+}
+
+/*
+ * evm_xattr_change - check if passed xattr value differs from current value
+ * @mnt_userns: user namespace of the idmapped mount
+ * @dentry: pointer to the affected dentry
+ * @xattr_name: requested xattr
+ * @xattr_value: requested xattr value
+ * @xattr_value_len: requested xattr value length
+ *
+ * Check if passed xattr value differs from current value.
+ *
+ * Returns 1 if passed xattr value differs from current value, 0 otherwise.
+ */
+static int evm_xattr_change(struct user_namespace *mnt_userns,
+                           struct dentry *dentry, const char *xattr_name,
+                           const void *xattr_value, size_t xattr_value_len)
+{
+       char *xattr_data = NULL;
+       int rc = 0;
+
+       if (posix_xattr_acl(xattr_name))
+               return evm_xattr_acl_change(mnt_userns, dentry, xattr_name,
+                                           xattr_value, xattr_value_len);
+
+       rc = vfs_getxattr_alloc(&init_user_ns, dentry, xattr_name, &xattr_data,
+                               0, GFP_NOFS);
+       if (rc < 0)
+               return 1;
+
+       if (rc == xattr_value_len)
+               rc = !!memcmp(xattr_value, xattr_data, rc);
+       else
+               rc = 1;
+
+       kfree(xattr_data);
+       return rc;
+}
+
+/*
  * evm_protect_xattr - protect the EVM extended attribute
  *
  * Prevent security.evm from being modified or removed without the
@@ -316,7 +538,8 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
  * For posix xattr acls only, permit security.evm, even if it currently
  * doesn't exist, to be updated unless the EVM signature is immutable.
  */
-static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
+static int evm_protect_xattr(struct user_namespace *mnt_userns,
+                            struct dentry *dentry, const char *xattr_name,
                             const void *xattr_value, size_t xattr_value_len)
 {
        enum integrity_status evm_status;
@@ -338,6 +561,10 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
        if (evm_status == INTEGRITY_NOXATTRS) {
                struct integrity_iint_cache *iint;
 
+               /* Exception if the HMAC is not going to be calculated. */
+               if (evm_hmac_disabled())
+                       return 0;
+
                iint = integrity_iint_find(d_backing_inode(dentry));
                if (iint && (iint->flags & IMA_NEW_FILE))
                        return 0;
@@ -354,7 +581,25 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
                                    -EPERM, 0);
        }
 out:
-       if (evm_status != INTEGRITY_PASS)
+       /* Exception if the HMAC is not going to be calculated. */
+       if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
+           evm_status == INTEGRITY_UNKNOWN))
+               return 0;
+
+       /*
+        * Writing other xattrs is safe for portable signatures, as portable
+        * signatures are immutable and can never be updated.
+        */
+       if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
+               return 0;
+
+       if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+           !evm_xattr_change(mnt_userns, dentry, xattr_name, xattr_value,
+                             xattr_value_len))
+               return 0;
+
+       if (evm_status != INTEGRITY_PASS &&
+           evm_status != INTEGRITY_PASS_IMMUTABLE)
                integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
                                    dentry->d_name.name, "appraise_metadata",
                                    integrity_status_msg[evm_status],
@@ -364,6 +609,7 @@ out:
 
 /**
  * evm_inode_setxattr - protect the EVM extended attribute
+ * @mnt_userns: user namespace of the idmapped mount
  * @dentry: pointer to the affected dentry
  * @xattr_name: pointer to the affected extended attribute name
  * @xattr_value: pointer to the new extended attribute value
@@ -375,8 +621,9 @@ out:
  * userspace from writing HMAC value.  Writing 'security.evm' requires
  * requires CAP_SYS_ADMIN privileges.
  */
-int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
-                      const void *xattr_value, size_t xattr_value_len)
+int evm_inode_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+                      const char *xattr_name, const void *xattr_value,
+                      size_t xattr_value_len)
 {
        const struct evm_ima_xattr_data *xattr_data = xattr_value;
 
@@ -393,19 +640,21 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
                    xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG)
                        return -EPERM;
        }
-       return evm_protect_xattr(dentry, xattr_name, xattr_value,
+       return evm_protect_xattr(mnt_userns, dentry, xattr_name, xattr_value,
                                 xattr_value_len);
 }
 
 /**
  * evm_inode_removexattr - protect the EVM extended attribute
+ * @mnt_userns: user namespace of the idmapped mount
  * @dentry: pointer to the affected dentry
  * @xattr_name: pointer to the affected extended attribute name
  *
  * Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
  * the current value is valid.
  */
-int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+int evm_inode_removexattr(struct user_namespace *mnt_userns,
+                         struct dentry *dentry, const char *xattr_name)
 {
        /* Policy permits modification of the protected xattrs even though
         * there's no HMAC key loaded
@@ -413,7 +662,7 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
        if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
                return 0;
 
-       return evm_protect_xattr(dentry, xattr_name, NULL, 0);
+       return evm_protect_xattr(mnt_userns, dentry, xattr_name, NULL, 0);
 }
 
 static void evm_reset_status(struct inode *inode)
@@ -426,6 +675,31 @@ static void evm_reset_status(struct inode *inode)
 }
 
 /**
+ * evm_revalidate_status - report whether EVM status re-validation is necessary
+ * @xattr_name: pointer to the affected extended attribute name
+ *
+ * Report whether callers of evm_verifyxattr() should re-validate the
+ * EVM status.
+ *
+ * Return true if re-validation is necessary, false otherwise.
+ */
+bool evm_revalidate_status(const char *xattr_name)
+{
+       if (!evm_key_loaded())
+               return false;
+
+       /* evm_inode_post_setattr() passes NULL */
+       if (!xattr_name)
+               return true;
+
+       if (!evm_protected_xattr(xattr_name) && !posix_xattr_acl(xattr_name) &&
+           strcmp(xattr_name, XATTR_NAME_EVM))
+               return false;
+
+       return true;
+}
+
+/**
  * evm_inode_post_setxattr - update 'security.evm' to reflect the changes
  * @dentry: pointer to the affected dentry
  * @xattr_name: pointer to the affected extended attribute name
@@ -441,12 +715,17 @@ static void evm_reset_status(struct inode *inode)
 void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
                             const void *xattr_value, size_t xattr_value_len)
 {
-       if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name)
-                                 && !posix_xattr_acl(xattr_name)))
+       if (!evm_revalidate_status(xattr_name))
                return;
 
        evm_reset_status(dentry->d_inode);
 
+       if (!strcmp(xattr_name, XATTR_NAME_EVM))
+               return;
+
+       if (!(evm_initialized & EVM_INIT_HMAC))
+               return;
+
        evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
 }
 
@@ -462,14 +741,33 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
  */
 void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
 {
-       if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
+       if (!evm_revalidate_status(xattr_name))
                return;
 
        evm_reset_status(dentry->d_inode);
 
+       if (!strcmp(xattr_name, XATTR_NAME_EVM))
+               return;
+
+       if (!(evm_initialized & EVM_INIT_HMAC))
+               return;
+
        evm_update_evmxattr(dentry, xattr_name, NULL, 0);
 }
 
+static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = d_backing_inode(dentry);
+       unsigned int ia_valid = attr->ia_valid;
+
+       if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) &&
+           (!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) &&
+           (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
+               return 0;
+
+       return 1;
+}
+
 /**
  * evm_inode_setattr - prevent updating an invalid EVM extended attribute
  * @dentry: pointer to the affected dentry
@@ -491,9 +789,21 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
        if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
                return 0;
        evm_status = evm_verify_current_integrity(dentry);
+       /*
+        * Writing attrs is safe for portable signatures, as portable signatures
+        * are immutable and can never be updated.
+        */
        if ((evm_status == INTEGRITY_PASS) ||
-           (evm_status == INTEGRITY_NOXATTRS))
+           (evm_status == INTEGRITY_NOXATTRS) ||
+           (evm_status == INTEGRITY_FAIL_IMMUTABLE) ||
+           (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
+            evm_status == INTEGRITY_UNKNOWN)))
                return 0;
+
+       if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+           !evm_attr_change(dentry, attr))
+               return 0;
+
        integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
                            dentry->d_name.name, "appraise_metadata",
                            integrity_status_msg[evm_status], -EPERM, 0);
@@ -513,7 +823,12 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
  */
 void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
 {
-       if (!evm_key_loaded())
+       if (!evm_revalidate_status(NULL))
+               return;
+
+       evm_reset_status(dentry->d_inode);
+
+       if (!(evm_initialized & EVM_INIT_HMAC))
                return;
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
@@ -521,7 +836,7 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
 }
 
 /*
- * evm_inode_init_security - initializes security.evm
+ * evm_inode_init_security - initializes security.evm HMAC value
  */
 int evm_inode_init_security(struct inode *inode,
                                 const struct xattr *lsm_xattr,
@@ -530,7 +845,8 @@ int evm_inode_init_security(struct inode *inode,
        struct evm_xattr *xattr_data;
        int rc;
 
-       if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
+       if (!(evm_initialized & EVM_INIT_HMAC) ||
+           !evm_protected_xattr(lsm_xattr->name))
                return 0;
 
        xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
index bbc8563..8a9db7d 100644 (file)
@@ -66,12 +66,13 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
 static ssize_t evm_write_key(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       int i, ret;
+       unsigned int i;
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP_COMPLETE))
                return -EPERM;
 
-       ret = kstrtoint_from_user(buf, count, 0, &i);
+       ret = kstrtouint_from_user(buf, count, 0, &i);
 
        if (ret)
                return ret;
@@ -80,12 +81,12 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
        if (!i || (i & ~EVM_INIT_MASK) != 0)
                return -EINVAL;
 
-       /* Don't allow a request to freshly enable metadata writes if
-        * keys are loaded.
+       /*
+        * Don't allow a request to enable metadata writes if
+        * an HMAC key is loaded.
         */
        if ((i & EVM_ALLOW_METADATA_WRITES) &&
-           ((evm_initialized & EVM_KEY_MASK) != 0) &&
-           !(evm_initialized & EVM_ALLOW_METADATA_WRITES))
+           (evm_initialized & EVM_INIT_HMAC) != 0)
                return -EPERM;
 
        if (i & EVM_INIT_HMAC) {
@@ -138,8 +139,12 @@ static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
        if (rc)
                return -ERESTARTSYS;
 
-       list_for_each_entry(xattr, &evm_config_xattrnames, list)
+       list_for_each_entry(xattr, &evm_config_xattrnames, list) {
+               if (!xattr->enabled)
+                       continue;
+
                size += strlen(xattr->name) + 1;
+       }
 
        temp = kmalloc(size + 1, GFP_KERNEL);
        if (!temp) {
@@ -148,6 +153,9 @@ static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
        }
 
        list_for_each_entry(xattr, &evm_config_xattrnames, list) {
+               if (!xattr->enabled)
+                       continue;
+
                sprintf(temp + offset, "%s\n", xattr->name);
                offset += strlen(xattr->name) + 1;
        }
@@ -189,7 +197,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
 
        ab = audit_log_start(audit_context(), GFP_KERNEL,
                             AUDIT_INTEGRITY_EVM_XATTR);
-       if (!ab)
+       if (!ab && IS_ENABLED(CONFIG_AUDIT))
                return -ENOMEM;
 
        xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
@@ -198,6 +206,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
                goto out;
        }
 
+       xattr->enabled = true;
        xattr->name = memdup_user_nul(buf, count);
        if (IS_ERR(xattr->name)) {
                err = PTR_ERR(xattr->name);
@@ -244,6 +253,10 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
        list_for_each_entry(tmp, &evm_config_xattrnames, list) {
                if (strcmp(xattr->name, tmp->name) == 0) {
                        err = -EEXIST;
+                       if (!tmp->enabled) {
+                               tmp->enabled = true;
+                               err = count;
+                       }
                        mutex_unlock(&xattr_list_mutex);
                        goto out;
                }
@@ -255,7 +268,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
        audit_log_end(ab);
        return count;
 out:
-       audit_log_format(ab, " res=%d", err);
+       audit_log_format(ab, " res=%d", (err < 0) ? err : 0);
        audit_log_end(ab);
        if (xattr) {
                kfree(xattr->name);
index fca8a94..8638976 100644 (file)
@@ -208,7 +208,9 @@ int integrity_kernel_read(struct file *file, loff_t offset,
 void __init integrity_load_keys(void)
 {
        ima_load_x509();
-       evm_load_x509();
+
+       if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
+               evm_load_x509();
 }
 
 static int __init integrity_fs_init(void)
index 12e9250..d0ceada 100644 (file)
@@ -334,3 +334,10 @@ config IMA_SECURE_AND_OR_TRUSTED_BOOT
        help
           This option is selected by architectures to enable secure and/or
           trusted boot based on IMA runtime policies.
+
+config IMA_DISABLE_HTABLE
+       bool "Disable htable to allow measurement of duplicate records"
+       depends on IMA
+       default n
+       help
+          This option disables htable to allow measurement of duplicate records.
index 4e5eb02..ef9dcfc 100644 (file)
@@ -242,12 +242,16 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
                hash_start = 1;
                fallthrough;
        case IMA_XATTR_DIGEST:
-               if (iint->flags & IMA_DIGSIG_REQUIRED) {
-                       *cause = "IMA-signature-required";
-                       *status = INTEGRITY_FAIL;
-                       break;
+               if (*status != INTEGRITY_PASS_IMMUTABLE) {
+                       if (iint->flags & IMA_DIGSIG_REQUIRED) {
+                               *cause = "IMA-signature-required";
+                               *status = INTEGRITY_FAIL;
+                               break;
+                       }
+                       clear_bit(IMA_DIGSIG, &iint->atomic_flags);
+               } else {
+                       set_bit(IMA_DIGSIG, &iint->atomic_flags);
                }
-               clear_bit(IMA_DIGSIG, &iint->atomic_flags);
                if (xattr_len - sizeof(xattr_value->type) - hash_start >=
                                iint->ima_hash->length)
                        /*
@@ -416,6 +420,10 @@ int ima_appraise_measurement(enum ima_hooks func,
        case INTEGRITY_NOLABEL:         /* No security.evm xattr. */
                cause = "missing-HMAC";
                goto out;
+       case INTEGRITY_FAIL_IMMUTABLE:
+               set_bit(IMA_DIGSIG, &iint->atomic_flags);
+               cause = "invalid-fail-immutable";
+               goto out;
        case INTEGRITY_FAIL:            /* Invalid HMAC/signature. */
                cause = "invalid-HMAC";
                goto out;
@@ -459,9 +467,12 @@ out:
                                status = INTEGRITY_PASS;
                }
 
-               /* Permit new files with file signatures, but without data. */
+               /*
+                * Permit new files with file/EVM portable signatures, but
+                * without data.
+                */
                if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
-                   xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
+                   test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
                        status = INTEGRITY_PASS;
                }
 
@@ -522,8 +533,6 @@ void ima_inode_post_setattr(struct user_namespace *mnt_userns,
                return;
 
        action = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR);
-       if (!action)
-               __vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_IMA);
        iint = integrity_iint_find(inode);
        if (iint) {
                set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
@@ -570,6 +579,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
                       const void *xattr_value, size_t xattr_value_len)
 {
        const struct evm_ima_xattr_data *xvalue = xattr_value;
+       int digsig = 0;
        int result;
 
        result = ima_protect_xattr(dentry, xattr_name, xattr_value,
@@ -577,9 +587,14 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
        if (result == 1) {
                if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
                        return -EINVAL;
-               ima_reset_appraise_flags(d_backing_inode(dentry),
-                       xvalue->type == EVM_IMA_XATTR_DIGSIG);
-               result = 0;
+               digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
+       } else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
+               digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
+       }
+       if (result == 1 || evm_revalidate_status(xattr_name)) {
+               ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
+               if (result == 1)
+                       result = 0;
        }
        return result;
 }
@@ -589,9 +604,10 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
        int result;
 
        result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
-       if (result == 1) {
+       if (result == 1 || evm_revalidate_status(xattr_name)) {
                ima_reset_appraise_flags(d_backing_inode(dentry), 0);
-               result = 0;
+               if (result == 1)
+                       result = 0;
        }
        return result;
 }
index 1fb0b0e..c985418 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <keys/asymmetric-type.h>
 #include <linux/user_namespace.h>
+#include <linux/ima.h>
 #include "ima.h"
 
 /**
index f6a7e96..a7206cc 100644 (file)
@@ -598,8 +598,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
                u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
                u8 *data_to_hash = field_data[i].data;
                u32 datalen = field_data[i].len;
-               u32 datalen_to_hash =
-                   !ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
+               u32 datalen_to_hash = !ima_canonical_fmt ?
+                               datalen : (__force u32)cpu_to_le32(datalen);
 
                if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
                        rc = crypto_shash_update(shash,
index ea8ff8a..3d8e9d5 100644 (file)
@@ -147,7 +147,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
         * PCR used defaults to the same (config option) in
         * little-endian format, unless set in policy
         */
-       pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
+       pcr = !ima_canonical_fmt ? e->pcr : (__force u32)cpu_to_le32(e->pcr);
        ima_putc(m, &pcr, sizeof(e->pcr));
 
        /* 2nd: template digest */
@@ -155,7 +155,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
 
        /* 3rd: template name size */
        namelen = !ima_canonical_fmt ? strlen(template_name) :
-               cpu_to_le32(strlen(template_name));
+               (__force u32)cpu_to_le32(strlen(template_name));
        ima_putc(m, &namelen, sizeof(namelen));
 
        /* 4th:  template name */
@@ -167,7 +167,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
 
        if (!is_ima_template) {
                template_data_len = !ima_canonical_fmt ? e->template_data_len :
-                       cpu_to_le32(e->template_data_len);
+                       (__force u32)cpu_to_le32(e->template_data_len);
                ima_putc(m, &template_data_len, sizeof(e->template_data_len));
        }
 
index 6e87429..5076a7d 100644 (file)
@@ -108,6 +108,10 @@ void __init ima_load_x509(void)
 
        ima_policy_flag &= ~unset_flags;
        integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
+
+       /* load also EVM key to avoid appraisal */
+       evm_load_x509();
+
        ima_policy_flag |= unset_flags;
 }
 #endif
index 6678876..f799cc2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/vmalloc.h>
 #include <linux/kexec.h>
 #include <linux/of.h>
+#include <linux/ima.h>
 #include "ima.h"
 
 #ifdef CONFIG_IMA_KEXEC
index 906c1d8..287b905 100644 (file)
@@ -433,7 +433,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
        inode = file_inode(vma->vm_file);
        action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
                                current_cred(), secid, MAY_EXEC, MMAP_CHECK,
-                               &pcr, &template, 0);
+                               &pcr, &template, NULL);
 
        /* Is the mmap'ed file in policy? */
        if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
index c096ef8..532da87 100644 (file)
@@ -168,7 +168,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
        int result = 0, tpmresult = 0;
 
        mutex_lock(&ima_extend_list_mutex);
-       if (!violation) {
+       if (!violation && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
                if (ima_lookup_digest_entry(digest, entry->pcr)) {
                        audit_cause = "hash_exists";
                        result = -EEXIST;
@@ -176,7 +176,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                }
        }
 
-       result = ima_add_digest_entry(entry, 1);
+       result = ima_add_digest_entry(entry,
+                                     !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE));
        if (result < 0) {
                audit_cause = "ENOMEM";
                audit_info = 0;
index 4e081e6..6945603 100644 (file)
@@ -22,6 +22,8 @@ static struct ima_template_desc builtin_templates[] = {
        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
        {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
        {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
+       {.name = "evm-sig",
+        .fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"},
        {.name = "", .fmt = ""},        /* placeholder for a custom format */
 };
 
@@ -45,6 +47,23 @@ static const struct ima_template_field supported_fields[] = {
         .field_show = ima_show_template_digest_ng},
        {.field_id = "modsig", .field_init = ima_eventmodsig_init,
         .field_show = ima_show_template_sig},
+       {.field_id = "evmsig", .field_init = ima_eventevmsig_init,
+        .field_show = ima_show_template_sig},
+       {.field_id = "iuid", .field_init = ima_eventinodeuid_init,
+        .field_show = ima_show_template_uint},
+       {.field_id = "igid", .field_init = ima_eventinodegid_init,
+        .field_show = ima_show_template_uint},
+       {.field_id = "imode", .field_init = ima_eventinodemode_init,
+        .field_show = ima_show_template_uint},
+       {.field_id = "xattrnames",
+        .field_init = ima_eventinodexattrnames_init,
+        .field_show = ima_show_template_string},
+       {.field_id = "xattrlengths",
+        .field_init = ima_eventinodexattrlengths_init,
+        .field_show = ima_show_template_sig},
+       {.field_id = "xattrvalues",
+        .field_init = ima_eventinodexattrvalues_init,
+        .field_show = ima_show_template_sig},
 };
 
 /*
@@ -52,7 +71,8 @@ static const struct ima_template_field supported_fields[] = {
  * need to be accounted for since they shouldn't be defined in the same template
  * description as 'd-ng' and 'n-ng' respectively.
  */
-#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
+#define MAX_TEMPLATE_NAME_LEN \
+       sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode")
 
 static struct ima_template_desc *ima_template;
 static struct ima_template_desc *ima_buf_template;
@@ -403,9 +423,9 @@ int ima_restore_measurement_list(loff_t size, void *buf)
                return 0;
 
        if (ima_canonical_fmt) {
-               khdr->version = le16_to_cpu(khdr->version);
-               khdr->count = le64_to_cpu(khdr->count);
-               khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
+               khdr->version = le16_to_cpu((__force __le16)khdr->version);
+               khdr->count = le64_to_cpu((__force __le64)khdr->count);
+               khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size);
        }
 
        if (khdr->version != 1) {
@@ -495,7 +515,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
                }
 
                entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :
-                            le32_to_cpu(*(u32 *)(hdr[HDR_PCR].data));
+                            le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data));
                ret = ima_restore_measurement_entry(entry);
                if (ret < 0)
                        break;
index c022ee9..ca017ca 100644 (file)
@@ -10,6 +10,8 @@
  */
 
 #include "ima_template_lib.h"
+#include <linux/xattr.h>
+#include <linux/evm.h>
 
 static bool ima_template_hash_algo_allowed(u8 algo)
 {
@@ -23,7 +25,8 @@ enum data_formats {
        DATA_FMT_DIGEST = 0,
        DATA_FMT_DIGEST_WITH_ALGO,
        DATA_FMT_STRING,
-       DATA_FMT_HEX
+       DATA_FMT_HEX,
+       DATA_FMT_UINT
 };
 
 static int ima_write_template_field_data(const void *data, const u32 datalen,
@@ -87,6 +90,36 @@ static void ima_show_template_data_ascii(struct seq_file *m,
        case DATA_FMT_STRING:
                seq_printf(m, "%s", buf_ptr);
                break;
+       case DATA_FMT_UINT:
+               switch (field_data->len) {
+               case sizeof(u8):
+                       seq_printf(m, "%u", *(u8 *)buf_ptr);
+                       break;
+               case sizeof(u16):
+                       if (ima_canonical_fmt)
+                               seq_printf(m, "%u",
+                                          le16_to_cpu(*(__le16 *)buf_ptr));
+                       else
+                               seq_printf(m, "%u", *(u16 *)buf_ptr);
+                       break;
+               case sizeof(u32):
+                       if (ima_canonical_fmt)
+                               seq_printf(m, "%u",
+                                          le32_to_cpu(*(__le32 *)buf_ptr));
+                       else
+                               seq_printf(m, "%u", *(u32 *)buf_ptr);
+                       break;
+               case sizeof(u64):
+                       if (ima_canonical_fmt)
+                               seq_printf(m, "%llu",
+                                          le64_to_cpu(*(__le64 *)buf_ptr));
+                       else
+                               seq_printf(m, "%llu", *(u64 *)buf_ptr);
+                       break;
+               default:
+                       break;
+               }
+               break;
        default:
                break;
        }
@@ -101,7 +134,8 @@ static void ima_show_template_data_binary(struct seq_file *m,
            strlen(field_data->data) : field_data->len;
 
        if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
-               u32 field_len = !ima_canonical_fmt ? len : cpu_to_le32(len);
+               u32 field_len = !ima_canonical_fmt ?
+                               len : (__force u32)cpu_to_le32(len);
 
                ima_putc(m, &field_len, sizeof(field_len));
        }
@@ -162,6 +196,12 @@ void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
        ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
 }
 
+void ima_show_template_uint(struct seq_file *m, enum ima_show_type show,
+                           struct ima_field_data *field_data)
+{
+       ima_show_template_field_data(m, show, DATA_FMT_UINT, field_data);
+}
+
 /**
  * ima_parse_buf() - Parses lengths and data from an input buffer
  * @bufstartp:       Buffer start address.
@@ -188,9 +228,10 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
                        if (bufp > (bufendp - sizeof(u32)))
                                break;
 
-                       fields[i].len = *(u32 *)bufp;
                        if (ima_canonical_fmt)
-                               fields[i].len = le32_to_cpu(fields[i].len);
+                               fields[i].len = le32_to_cpu(*(__le32 *)bufp);
+                       else
+                               fields[i].len = *(u32 *)bufp;
 
                        bufp += sizeof(u32);
                }
@@ -438,7 +479,7 @@ int ima_eventsig_init(struct ima_event_data *event_data,
        struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
 
        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
-               return 0;
+               return ima_eventevmsig_init(event_data, field_data);
 
        return ima_write_template_field_data(xattr_value, event_data->xattr_len,
                                             DATA_FMT_HEX, field_data);
@@ -484,3 +525,163 @@ int ima_eventmodsig_init(struct ima_event_data *event_data,
        return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
                                             field_data);
 }
+
+/*
+ *  ima_eventevmsig_init - include the EVM portable signature as part of the
+ *  template data
+ */
+int ima_eventevmsig_init(struct ima_event_data *event_data,
+                        struct ima_field_data *field_data)
+{
+       struct evm_ima_xattr_data *xattr_data = NULL;
+       int rc = 0;
+
+       if (!event_data->file)
+               return 0;
+
+       rc = vfs_getxattr_alloc(&init_user_ns, file_dentry(event_data->file),
+                               XATTR_NAME_EVM, (char **)&xattr_data, 0,
+                               GFP_NOFS);
+       if (rc <= 0)
+               return 0;
+
+       if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
+               kfree(xattr_data);
+               return 0;
+       }
+
+       rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
+                                          field_data);
+       kfree(xattr_data);
+       return rc;
+}
+
+static int ima_eventinodedac_init_common(struct ima_event_data *event_data,
+                                        struct ima_field_data *field_data,
+                                        bool get_uid)
+{
+       unsigned int id;
+
+       if (!event_data->file)
+               return 0;
+
+       if (get_uid)
+               id = i_uid_read(file_inode(event_data->file));
+       else
+               id = i_gid_read(file_inode(event_data->file));
+
+       if (ima_canonical_fmt) {
+               if (sizeof(id) == sizeof(u16))
+                       id = (__force u16)cpu_to_le16(id);
+               else
+                       id = (__force u32)cpu_to_le32(id);
+       }
+
+       return ima_write_template_field_data((void *)&id, sizeof(id),
+                                            DATA_FMT_UINT, field_data);
+}
+
+/*
+ *  ima_eventinodeuid_init - include the inode UID as part of the template
+ *  data
+ */
+int ima_eventinodeuid_init(struct ima_event_data *event_data,
+                          struct ima_field_data *field_data)
+{
+       return ima_eventinodedac_init_common(event_data, field_data, true);
+}
+
+/*
+ *  ima_eventinodegid_init - include the inode GID as part of the template
+ *  data
+ */
+int ima_eventinodegid_init(struct ima_event_data *event_data,
+                          struct ima_field_data *field_data)
+{
+       return ima_eventinodedac_init_common(event_data, field_data, false);
+}
+
+/*
+ *  ima_eventinodemode_init - include the inode mode as part of the template
+ *  data
+ */
+int ima_eventinodemode_init(struct ima_event_data *event_data,
+                           struct ima_field_data *field_data)
+{
+       struct inode *inode;
+       u16 mode;
+
+       if (!event_data->file)
+               return 0;
+
+       inode = file_inode(event_data->file);
+       mode = inode->i_mode;
+       if (ima_canonical_fmt)
+               mode = (__force u16)cpu_to_le16(mode);
+
+       return ima_write_template_field_data((char *)&mode, sizeof(mode),
+                                            DATA_FMT_UINT, field_data);
+}
+
+static int ima_eventinodexattrs_init_common(struct ima_event_data *event_data,
+                                           struct ima_field_data *field_data,
+                                           char type)
+{
+       u8 *buffer = NULL;
+       int rc;
+
+       if (!event_data->file)
+               return 0;
+
+       rc = evm_read_protected_xattrs(file_dentry(event_data->file), NULL, 0,
+                                      type, ima_canonical_fmt);
+       if (rc < 0)
+               return 0;
+
+       buffer = kmalloc(rc, GFP_KERNEL);
+       if (!buffer)
+               return 0;
+
+       rc = evm_read_protected_xattrs(file_dentry(event_data->file), buffer,
+                                      rc, type, ima_canonical_fmt);
+       if (rc < 0) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = ima_write_template_field_data((char *)buffer, rc, DATA_FMT_HEX,
+                                          field_data);
+out:
+       kfree(buffer);
+       return rc;
+}
+
+/*
+ *  ima_eventinodexattrnames_init - include a list of xattr names as part of the
+ *  template data
+ */
+int ima_eventinodexattrnames_init(struct ima_event_data *event_data,
+                                 struct ima_field_data *field_data)
+{
+       return ima_eventinodexattrs_init_common(event_data, field_data, 'n');
+}
+
+/*
+ *  ima_eventinodexattrlengths_init - include a list of xattr lengths as part of
+ *  the template data
+ */
+int ima_eventinodexattrlengths_init(struct ima_event_data *event_data,
+                                   struct ima_field_data *field_data)
+{
+       return ima_eventinodexattrs_init_common(event_data, field_data, 'l');
+}
+
+/*
+ *  ima_eventinodexattrvalues_init - include a list of xattr values as part of
+ *  the template data
+ */
+int ima_eventinodexattrvalues_init(struct ima_event_data *event_data,
+                                  struct ima_field_data *field_data)
+{
+       return ima_eventinodexattrs_init_common(event_data, field_data, 'v');
+}
index 6b3b880..c71f1de 100644 (file)
@@ -27,6 +27,8 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
                           struct ima_field_data *field_data);
 void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
                           struct ima_field_data *field_data);
+void ima_show_template_uint(struct seq_file *m, enum ima_show_type show,
+                           struct ima_field_data *field_data);
 int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
                  int maxfields, struct ima_field_data *fields, int *curfields,
                  unsigned long *len_mask, int enforce_mask, char *bufname);
@@ -46,4 +48,18 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
                      struct ima_field_data *field_data);
 int ima_eventmodsig_init(struct ima_event_data *event_data,
                         struct ima_field_data *field_data);
+int ima_eventevmsig_init(struct ima_event_data *event_data,
+                        struct ima_field_data *field_data);
+int ima_eventinodeuid_init(struct ima_event_data *event_data,
+                          struct ima_field_data *field_data);
+int ima_eventinodegid_init(struct ima_event_data *event_data,
+                          struct ima_field_data *field_data);
+int ima_eventinodemode_init(struct ima_event_data *event_data,
+                           struct ima_field_data *field_data);
+int ima_eventinodexattrnames_init(struct ima_event_data *event_data,
+                                 struct ima_field_data *field_data);
+int ima_eventinodexattrlengths_init(struct ima_event_data *event_data,
+                                   struct ima_field_data *field_data);
+int ima_eventinodexattrvalues_init(struct ima_event_data *event_data,
+                                  struct ima_field_data *field_data);
 #endif /* __LINUX_IMA_TEMPLATE_LIB_H */
index b38155b..e9f8010 100644 (file)
@@ -1354,7 +1354,7 @@ int security_inode_setxattr(struct user_namespace *mnt_userns,
        ret = ima_inode_setxattr(dentry, name, value, size);
        if (ret)
                return ret;
-       return evm_inode_setxattr(dentry, name, value, size);
+       return evm_inode_setxattr(mnt_userns, dentry, name, value, size);
 }
 
 void security_inode_post_setxattr(struct dentry *dentry, const char *name,
@@ -1399,7 +1399,7 @@ int security_inode_removexattr(struct user_namespace *mnt_userns,
        ret = ima_inode_removexattr(dentry, name);
        if (ret)
                return ret;
-       return evm_inode_removexattr(dentry, name);
+       return evm_inode_removexattr(mnt_userns, dentry, name);
 }
 
 int security_inode_need_killpriv(struct dentry *dentry)
index b51bad1..d79bf07 100644 (file)
@@ -320,6 +320,7 @@ static unsigned int tomoyo_log_count;
  * @ns:          Pointer to "struct tomoyo_policy_namespace".
  * @profile:     Profile number.
  * @index:       Index number of functionality.
+ * @matched_acl: Pointer to "struct tomoyo_acl_info".
  * @is_granted:  True if granted log, false otherwise.
  *
  * Returns true if this request should be audited, false otherwise.
index 065f494..a270579 100644 (file)
@@ -139,6 +139,7 @@ static int tomoyo_open(struct inode *inode, struct file *file)
 /**
  * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
  *
+ * @inode: Pointer to "struct inode".
  * @file:  Pointer to "struct file".
  *
  */
index 1f3cd43..b6a3190 100644 (file)
@@ -63,7 +63,7 @@ static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm)
 
 #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
 /**
- * tomoyo_bprm_for_exec - Target for security_bprm_creds_for_exec().
+ * tomoyo_bprm_creds_for_exec - Target for security_bprm_creds_for_exec().
  *
  * @bprm: Pointer to "struct linux_binprm".
  *
@@ -113,8 +113,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
 /**
  * tomoyo_inode_getattr - Target for security_inode_getattr().
  *
- * @mnt:    Pointer to "struct vfsmount".
- * @dentry: Pointer to "struct dentry".
+ * @path: Pointer to "struct path".
  *
  * Returns 0 on success, negative value otherwise.
  */
@@ -300,8 +299,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
 /**
  * tomoyo_file_open - Target for security_file_open().
  *
- * @f:    Pointer to "struct file".
- * @cred: Pointer to "struct cred".
+ * @f: Pointer to "struct file".
  *
  * Returns 0 on success, negative value otherwise.
  */
@@ -487,8 +485,8 @@ struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = {
 /**
  * tomoyo_task_alloc - Target for security_task_alloc().
  *
- * @task:  Pointer to "struct task_struct".
- * @flags: clone() flags.
+ * @task:        Pointer to "struct task_struct".
+ * @clone_flags: clone() flags.
  *
  * Returns 0.
  */
index e89cac9..1da2e37 100644 (file)
@@ -83,8 +83,8 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
 /**
  * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
  *
- * @time Seconds since 1970/01/01 00:00:00.
- * @stamp: Pointer to "struct tomoyo_time".
+ * @time64: Seconds since 1970/01/01 00:00:00.
+ * @stamp:  Pointer to "struct tomoyo_time".
  *
  * Returns nothing.
  */
index 438fa18..9408ee6 100644 (file)
@@ -3388,44 +3388,30 @@ static int rt5645_probe(struct snd_soc_component *component)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
        struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
-       int ret = 0;
 
        rt5645->component = component;
 
        switch (rt5645->codec_type) {
        case CODEC_TYPE_RT5645:
-               ret = snd_soc_dapm_new_controls(dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5645_specific_dapm_widgets,
                        ARRAY_SIZE(rt5645_specific_dapm_widgets));
-               if (ret < 0)
-                       goto exit;
-
-               ret = snd_soc_dapm_add_routes(dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5645_specific_dapm_routes,
                        ARRAY_SIZE(rt5645_specific_dapm_routes));
-               if (ret < 0)
-                       goto exit;
-
                if (rt5645->v_id < 3) {
-                       ret = snd_soc_dapm_add_routes(dapm,
+                       snd_soc_dapm_add_routes(dapm,
                                rt5645_old_dapm_routes,
                                ARRAY_SIZE(rt5645_old_dapm_routes));
-                       if (ret < 0)
-                               goto exit;
                }
                break;
        case CODEC_TYPE_RT5650:
-               ret = snd_soc_dapm_new_controls(dapm,
+               snd_soc_dapm_new_controls(dapm,
                        rt5650_specific_dapm_widgets,
                        ARRAY_SIZE(rt5650_specific_dapm_widgets));
-               if (ret < 0)
-                       goto exit;
-
-               ret = snd_soc_dapm_add_routes(dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5650_specific_dapm_routes,
                        ARRAY_SIZE(rt5650_specific_dapm_routes));
-               if (ret < 0)
-                       goto exit;
                break;
        }
 
@@ -3433,17 +3419,9 @@ static int rt5645_probe(struct snd_soc_component *component)
 
        /* for JD function */
        if (rt5645->pdata.jd_mode) {
-               ret = snd_soc_dapm_force_enable_pin(dapm, "JD Power");
-               if (ret < 0)
-                       goto exit;
-
-               ret = snd_soc_dapm_force_enable_pin(dapm, "LDO2");
-               if (ret < 0)
-                       goto exit;
-
-               ret = snd_soc_dapm_sync(dapm);
-               if (ret < 0)
-                       goto exit;
+               snd_soc_dapm_force_enable_pin(dapm, "JD Power");
+               snd_soc_dapm_force_enable_pin(dapm, "LDO2");
+               snd_soc_dapm_sync(dapm);
        }
 
        if (rt5645->pdata.long_name)
@@ -3454,14 +3432,9 @@ static int rt5645_probe(struct snd_soc_component *component)
                GFP_KERNEL);
 
        if (!rt5645->eq_param)
-               ret = -ENOMEM;
-exit:
-       /*
-        * If there was an error above, everything will be cleaned up by the
-        * caller if we return an error here.  This will be done with a later
-        * call to rt5645_remove().
-        */
-       return ret;
+               return -ENOMEM;
+
+       return 0;
 }
 
 static void rt5645_remove(struct snd_soc_component *component)
index b941adc..939e7e2 100644 (file)
@@ -61,22 +61,6 @@ static void dump_registers(struct ssp_device *ssp)
                 pxa_ssp_read_reg(ssp, SSACD));
 }
 
-static void pxa_ssp_enable(struct ssp_device *ssp)
-{
-       uint32_t sscr0;
-
-       sscr0 = __raw_readl(ssp->mmio_base + SSCR0) | SSCR0_SSE;
-       __raw_writel(sscr0, ssp->mmio_base + SSCR0);
-}
-
-static void pxa_ssp_disable(struct ssp_device *ssp)
-{
-       uint32_t sscr0;
-
-       sscr0 = __raw_readl(ssp->mmio_base + SSCR0) & ~SSCR0_SSE;
-       __raw_writel(sscr0, ssp->mmio_base + SSCR0);
-}
-
 static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
                        int out, struct snd_dmaengine_dai_dma_data *dma)
 {
diff --git a/tools/arch/x86/include/asm/asm.h b/tools/arch/x86/include/asm/asm.h
new file mode 100644 (file)
index 0000000..3ad3da9
--- /dev/null
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_ASM_H
+#define _ASM_X86_ASM_H
+
+#ifdef __ASSEMBLY__
+# define __ASM_FORM(x, ...)            x,## __VA_ARGS__
+# define __ASM_FORM_RAW(x, ...)                x,## __VA_ARGS__
+# define __ASM_FORM_COMMA(x, ...)      x,## __VA_ARGS__,
+#else
+#include <linux/stringify.h>
+# define __ASM_FORM(x, ...)            " " __stringify(x,##__VA_ARGS__) " "
+# define __ASM_FORM_RAW(x, ...)                    __stringify(x,##__VA_ARGS__)
+# define __ASM_FORM_COMMA(x, ...)      " " __stringify(x,##__VA_ARGS__) ","
+#endif
+
+#define _ASM_BYTES(x, ...)     __ASM_FORM(.byte x,##__VA_ARGS__ ;)
+
+#ifndef __x86_64__
+/* 32 bit */
+# define __ASM_SEL(a,b)                __ASM_FORM(a)
+# define __ASM_SEL_RAW(a,b)    __ASM_FORM_RAW(a)
+#else
+/* 64 bit */
+# define __ASM_SEL(a,b)                __ASM_FORM(b)
+# define __ASM_SEL_RAW(a,b)    __ASM_FORM_RAW(b)
+#endif
+
+#define __ASM_SIZE(inst, ...)  __ASM_SEL(inst##l##__VA_ARGS__, \
+                                         inst##q##__VA_ARGS__)
+#define __ASM_REG(reg)         __ASM_SEL_RAW(e##reg, r##reg)
+
+#define _ASM_PTR       __ASM_SEL(.long, .quad)
+#define _ASM_ALIGN     __ASM_SEL(.balign 4, .balign 8)
+
+#define _ASM_MOV       __ASM_SIZE(mov)
+#define _ASM_INC       __ASM_SIZE(inc)
+#define _ASM_DEC       __ASM_SIZE(dec)
+#define _ASM_ADD       __ASM_SIZE(add)
+#define _ASM_SUB       __ASM_SIZE(sub)
+#define _ASM_XADD      __ASM_SIZE(xadd)
+#define _ASM_MUL       __ASM_SIZE(mul)
+
+#define _ASM_AX                __ASM_REG(ax)
+#define _ASM_BX                __ASM_REG(bx)
+#define _ASM_CX                __ASM_REG(cx)
+#define _ASM_DX                __ASM_REG(dx)
+#define _ASM_SP                __ASM_REG(sp)
+#define _ASM_BP                __ASM_REG(bp)
+#define _ASM_SI                __ASM_REG(si)
+#define _ASM_DI                __ASM_REG(di)
+
+#ifndef __x86_64__
+/* 32 bit */
+
+#define _ASM_ARG1      _ASM_AX
+#define _ASM_ARG2      _ASM_DX
+#define _ASM_ARG3      _ASM_CX
+
+#define _ASM_ARG1L     eax
+#define _ASM_ARG2L     edx
+#define _ASM_ARG3L     ecx
+
+#define _ASM_ARG1W     ax
+#define _ASM_ARG2W     dx
+#define _ASM_ARG3W     cx
+
+#define _ASM_ARG1B     al
+#define _ASM_ARG2B     dl
+#define _ASM_ARG3B     cl
+
+#else
+/* 64 bit */
+
+#define _ASM_ARG1      _ASM_DI
+#define _ASM_ARG2      _ASM_SI
+#define _ASM_ARG3      _ASM_DX
+#define _ASM_ARG4      _ASM_CX
+#define _ASM_ARG5      r8
+#define _ASM_ARG6      r9
+
+#define _ASM_ARG1Q     rdi
+#define _ASM_ARG2Q     rsi
+#define _ASM_ARG3Q     rdx
+#define _ASM_ARG4Q     rcx
+#define _ASM_ARG5Q     r8
+#define _ASM_ARG6Q     r9
+
+#define _ASM_ARG1L     edi
+#define _ASM_ARG2L     esi
+#define _ASM_ARG3L     edx
+#define _ASM_ARG4L     ecx
+#define _ASM_ARG5L     r8d
+#define _ASM_ARG6L     r9d
+
+#define _ASM_ARG1W     di
+#define _ASM_ARG2W     si
+#define _ASM_ARG3W     dx
+#define _ASM_ARG4W     cx
+#define _ASM_ARG5W     r8w
+#define _ASM_ARG6W     r9w
+
+#define _ASM_ARG1B     dil
+#define _ASM_ARG2B     sil
+#define _ASM_ARG3B     dl
+#define _ASM_ARG4B     cl
+#define _ASM_ARG5B     r8b
+#define _ASM_ARG6B     r9b
+
+#endif
+
+/*
+ * Macros to generate condition code outputs from inline assembly,
+ * The output operand must be type "bool".
+ */
+#ifdef __GCC_ASM_FLAG_OUTPUTS__
+# define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
+# define CC_OUT(c) "=@cc" #c
+#else
+# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
+# define CC_OUT(c) [_cc_ ## c] "=qm"
+#endif
+
+#ifdef __KERNEL__
+
+/* Exception table entry */
+#ifdef __ASSEMBLY__
+# define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
+       .pushsection "__ex_table","a" ;                         \
+       .balign 4 ;                                             \
+       .long (from) - . ;                                      \
+       .long (to) - . ;                                        \
+       .long (handler) - . ;                                   \
+       .popsection
+
+# define _ASM_EXTABLE(from, to)                                        \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
+
+# define _ASM_EXTABLE_UA(from, to)                             \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
+
+# define _ASM_EXTABLE_CPY(from, to)                            \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_copy)
+
+# define _ASM_EXTABLE_FAULT(from, to)                          \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
+
+# ifdef CONFIG_KPROBES
+#  define _ASM_NOKPROBE(entry)                                 \
+       .pushsection "_kprobe_blacklist","aw" ;                 \
+       _ASM_ALIGN ;                                            \
+       _ASM_PTR (entry);                                       \
+       .popsection
+# else
+#  define _ASM_NOKPROBE(entry)
+# endif
+
+#else /* ! __ASSEMBLY__ */
+# define _EXPAND_EXTABLE_HANDLE(x) #x
+# define _ASM_EXTABLE_HANDLE(from, to, handler)                        \
+       " .pushsection \"__ex_table\",\"a\"\n"                  \
+       " .balign 4\n"                                          \
+       " .long (" #from ") - .\n"                              \
+       " .long (" #to ") - .\n"                                \
+       " .long (" _EXPAND_EXTABLE_HANDLE(handler) ") - .\n"    \
+       " .popsection\n"
+
+# define _ASM_EXTABLE(from, to)                                        \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
+
+# define _ASM_EXTABLE_UA(from, to)                             \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
+
+# define _ASM_EXTABLE_CPY(from, to)                            \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_copy)
+
+# define _ASM_EXTABLE_FAULT(from, to)                          \
+       _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
+
+/* For C file, we already have NOKPROBE_SYMBOL macro */
+
+/*
+ * This output constraint should be used for any inline asm which has a "call"
+ * instruction.  Otherwise the asm may be inserted before the frame pointer
+ * gets set up by the containing function.  If you forget to do this, objtool
+ * may print a "call without frame pointer save/setup" warning.
+ */
+register unsigned long current_stack_pointer asm(_ASM_SP);
+#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_X86_ASM_H */
index 889f8b1..43dcb92 100644 (file)
@@ -26,8 +26,8 @@
  * This file enumerates the exact layout of them:
  */
 
+/* This is used as an interrupt vector when programming the APIC. */
 #define NMI_VECTOR                     0x02
-#define MCE_VECTOR                     0x12
 
 /*
  * IDT vectors usable for external interrupt sources start at 0x20.
@@ -84,7 +84,7 @@
  */
 #define IRQ_WORK_VECTOR                        0xf6
 
-#define UV_BAU_MESSAGE                 0xf5
+/* 0xf5 - unused, was UV_BAU_MESSAGE */
 #define DEFERRED_ERROR_VECTOR          0xf4
 
 /* Vector on which hypervisor callbacks will be delivered */
 #define FIRST_SYSTEM_VECTOR            NR_VECTORS
 #endif
 
+#define NR_EXTERNAL_VECTORS            (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
+#define NR_SYSTEM_VECTORS              (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+
 /*
  * Size the maximum number of interrupts.
  *
index c1e5e81..c5573ea 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_NOPS_H
 #define _ASM_X86_NOPS_H
 
+#include <asm/asm.h>
+
 /*
  * Define nops for use with alternative() and for tracing.
  */
 
 #endif /* CONFIG_64BIT */
 
-#ifdef __ASSEMBLY__
-#define _ASM_MK_NOP(x) .byte x
-#else
-#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
-#endif
-
-#define ASM_NOP1 _ASM_MK_NOP(BYTES_NOP1)
-#define ASM_NOP2 _ASM_MK_NOP(BYTES_NOP2)
-#define ASM_NOP3 _ASM_MK_NOP(BYTES_NOP3)
-#define ASM_NOP4 _ASM_MK_NOP(BYTES_NOP4)
-#define ASM_NOP5 _ASM_MK_NOP(BYTES_NOP5)
-#define ASM_NOP6 _ASM_MK_NOP(BYTES_NOP6)
-#define ASM_NOP7 _ASM_MK_NOP(BYTES_NOP7)
-#define ASM_NOP8 _ASM_MK_NOP(BYTES_NOP8)
+#define ASM_NOP1 _ASM_BYTES(BYTES_NOP1)
+#define ASM_NOP2 _ASM_BYTES(BYTES_NOP2)
+#define ASM_NOP3 _ASM_BYTES(BYTES_NOP3)
+#define ASM_NOP4 _ASM_BYTES(BYTES_NOP4)
+#define ASM_NOP5 _ASM_BYTES(BYTES_NOP5)
+#define ASM_NOP6 _ASM_BYTES(BYTES_NOP6)
+#define ASM_NOP7 _ASM_BYTES(BYTES_NOP7)
+#define ASM_NOP8 _ASM_BYTES(BYTES_NOP8)
 
 #define ASM_NOP_MAX 8
 
index 719f18b..f1af27c 100755 (executable)
@@ -196,7 +196,7 @@ else
 fi
 
 echo "For a more detailed explanation of the various taint flags see"
-echo " Documentation/admin-guide/tainted-kernels.rst in the the Linux kernel sources"
+echo " Documentation/admin-guide/tainted-kernels.rst in the Linux kernel sources"
 echo " or https://kernel.org/doc/html/latest/admin-guide/tainted-kernels.html"
 echo "Raw taint value as int/string: $taint/'$out'"
 #EOF#
index 6de5a7f..d2a9420 100644 (file)
@@ -863,8 +863,7 @@ __SYSCALL(__NR_process_madvise, sys_process_madvise)
 __SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2)
 #define __NR_mount_setattr 442
 __SYSCALL(__NR_mount_setattr, sys_mount_setattr)
-#define __NR_quotactl_path 443
-__SYSCALL(__NR_quotactl_path, sys_quotactl_path)
+/* 443 is reserved for quotactl_path */
 
 #define __NR_landlock_create_ruleset 444
 __SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset)
index 7d66876..d1b3270 100644 (file)
@@ -289,6 +289,9 @@ struct sockaddr_in {
 /* Address indicating an error return. */
 #define        INADDR_NONE             ((unsigned long int) 0xffffffff)
 
+/* Dummy address for src of ICMP replies if no real address is set (RFC7600). */
+#define        INADDR_DUMMY            ((unsigned long int) 0xc0000008)
+
 /* Network number for local host loopback. */
 #define        IN_LOOPBACKNET          127
 
index 18a9f59..967d9c5 100644 (file)
@@ -259,4 +259,12 @@ struct prctl_mm_map {
 #define PR_PAC_SET_ENABLED_KEYS                60
 #define PR_PAC_GET_ENABLED_KEYS                61
 
+/* Request the scheduler to share a core */
+#define PR_SCHED_CORE                  62
+# define PR_SCHED_CORE_GET             0
+# define PR_SCHED_CORE_CREATE          1 /* create unique core_sched cookie */
+# define PR_SCHED_CORE_SHARE_TO                2 /* push core_sched cookie to pid */
+# define PR_SCHED_CORE_SHARE_FROM      3 /* pull core_sched cookie to pid */
+# define PR_SCHED_CORE_MAX             4
+
 #endif /* _LINUX_PRCTL_H */
index 6061431..e9b619a 100644 (file)
@@ -1094,7 +1094,7 @@ int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
                        goto out_put_ctx;
                }
                if (xsk->fd == umem->fd)
-                       umem->rx_ring_setup_done = true;
+                       umem->tx_ring_setup_done = true;
        }
 
        err = xsk_get_mmap_offsets(xsk->fd, &off);
index 51ceeb9..9ce7b4b 100644 (file)
@@ -366,7 +366,7 @@ union kvm_mmu_page_role {
                unsigned direct:1;
                unsigned access:3;
                unsigned invalid:1;
-               unsigned nxe:1;
+               unsigned efer_nx:1;
                unsigned cr0_wp:1;
                unsigned smep_and_not_wp:1;
                unsigned smap_and_not_wp:1;
@@ -403,7 +403,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
                                 access_str[role.access],
                                 role.invalid ? " invalid" : "",
                                 role.cr4_pae ? "" : "!",
-                                role.nxe ? "" : "!",
+                                role.efer_nx ? "" : "!",
                                 role.cr0_wp ? "" : "!",
                                 role.smep_and_not_wp ? " smep" : "",
                                 role.smap_and_not_wp ? " smap" : "",
index 523aa41..bc82105 100644 (file)
@@ -684,7 +684,7 @@ static int elf_add_alternative(struct elf *elf,
        sec = find_section_by_name(elf, ".altinstructions");
        if (!sec) {
                sec = elf_create_section(elf, ".altinstructions",
-                                        SHF_WRITE, size, 0);
+                                        SHF_ALLOC, size, 0);
 
                if (!sec) {
                        WARN_ELF("elf_create_section");
index 14271cc..f2918f7 100644 (file)
@@ -9,6 +9,7 @@
 #define JUMP_ENTRY_SIZE                16
 #define JUMP_ORIG_OFFSET       0
 #define JUMP_NEW_OFFSET                4
+#define JUMP_KEY_OFFSET                8
 
 #define ALT_ENTRY_SIZE         12
 #define ALT_ORIG_OFFSET                0
index 9ed1a4c..e5947fb 100644 (file)
@@ -1225,15 +1225,41 @@ static int handle_jump_alt(struct objtool_file *file,
                           struct instruction *orig_insn,
                           struct instruction **new_insn)
 {
-       if (orig_insn->type == INSN_NOP)
-               return 0;
+       if (orig_insn->type != INSN_JUMP_UNCONDITIONAL &&
+           orig_insn->type != INSN_NOP) {
 
-       if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) {
                WARN_FUNC("unsupported instruction at jump label",
                          orig_insn->sec, orig_insn->offset);
                return -1;
        }
 
+       if (special_alt->key_addend & 2) {
+               struct reloc *reloc = insn_reloc(file, orig_insn);
+
+               if (reloc) {
+                       reloc->type = R_NONE;
+                       elf_write_reloc(file->elf, reloc);
+               }
+               elf_write_insn(file->elf, orig_insn->sec,
+                              orig_insn->offset, orig_insn->len,
+                              arch_nop_insn(orig_insn->len));
+               orig_insn->type = INSN_NOP;
+       }
+
+       if (orig_insn->type == INSN_NOP) {
+               if (orig_insn->len == 2)
+                       file->jl_nop_short++;
+               else
+                       file->jl_nop_long++;
+
+               return 0;
+       }
+
+       if (orig_insn->len == 2)
+               file->jl_short++;
+       else
+               file->jl_long++;
+
        *new_insn = list_next_entry(orig_insn, list);
        return 0;
 }
@@ -1314,6 +1340,12 @@ static int add_special_section_alts(struct objtool_file *file)
                free(special_alt);
        }
 
+       if (stats) {
+               printf("jl\\\tNOP\tJMP\n");
+               printf("short:\t%ld\t%ld\n", file->jl_nop_short, file->jl_short);
+               printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long);
+       }
+
 out:
        return ret;
 }
index 41bca1d..8676c75 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -27,21 +28,27 @@ static inline u32 str_hash(const char *str)
        return jhash(str, strlen(str), 0);
 }
 
-static inline int elf_hash_bits(void)
-{
-       return vmlinux ? ELF_HASH_BITS : 16;
-}
+#define __elf_table(name)      (elf->name##_hash)
+#define __elf_bits(name)       (elf->name##_bits)
 
-#define elf_hash_add(hashtable, node, key) \
-       hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
+#define elf_hash_add(name, node, key) \
+       hlist_add_head(node, &__elf_table(name)[hash_min(key, __elf_bits(name))])
 
-static void elf_hash_init(struct hlist_head *table)
-{
-       __hash_init(table, 1U << elf_hash_bits());
-}
+#define elf_hash_for_each_possible(name, obj, member, key) \
+       hlist_for_each_entry(obj, &__elf_table(name)[hash_min(key, __elf_bits(name))], member)
 
-#define elf_hash_for_each_possible(name, obj, member, key)                     \
-       hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
+#define elf_alloc_hash(name, size) \
+({ \
+       __elf_bits(name) = max(10, ilog2(size)); \
+       __elf_table(name) = mmap(NULL, sizeof(struct hlist_head) << __elf_bits(name), \
+                                PROT_READ|PROT_WRITE, \
+                                MAP_PRIVATE|MAP_ANON, -1, 0); \
+       if (__elf_table(name) == (void *)-1L) { \
+               WARN("mmap fail " #name); \
+               __elf_table(name) = NULL; \
+       } \
+       __elf_table(name); \
+})
 
 static bool symbol_to_offset(struct rb_node *a, const struct rb_node *b)
 {
@@ -80,9 +87,10 @@ struct section *find_section_by_name(const struct elf *elf, const char *name)
 {
        struct section *sec;
 
-       elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
+       elf_hash_for_each_possible(section_name, sec, name_hash, str_hash(name)) {
                if (!strcmp(sec->name, name))
                        return sec;
+       }
 
        return NULL;
 }
@@ -92,9 +100,10 @@ static struct section *find_section_by_index(struct elf *elf,
 {
        struct section *sec;
 
-       elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
+       elf_hash_for_each_possible(section, sec, hash, idx) {
                if (sec->idx == idx)
                        return sec;
+       }
 
        return NULL;
 }
@@ -103,9 +112,10 @@ static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
 {
        struct symbol *sym;
 
-       elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
+       elf_hash_for_each_possible(symbol, sym, hash, idx) {
                if (sym->idx == idx)
                        return sym;
+       }
 
        return NULL;
 }
@@ -170,9 +180,10 @@ struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
 {
        struct symbol *sym;
 
-       elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
+       elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) {
                if (!strcmp(sym->name, name))
                        return sym;
+       }
 
        return NULL;
 }
@@ -189,8 +200,8 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se
        sec = sec->reloc;
 
        for_offset_range(o, offset, offset + len) {
-               elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
-                                      sec_offset_hash(sec, o)) {
+               elf_hash_for_each_possible(reloc, reloc, hash,
+                                          sec_offset_hash(sec, o)) {
                        if (reloc->sec != sec)
                                continue;
 
@@ -228,6 +239,10 @@ static int read_sections(struct elf *elf)
                return -1;
        }
 
+       if (!elf_alloc_hash(section, sections_nr) ||
+           !elf_alloc_hash(section_name, sections_nr))
+               return -1;
+
        for (i = 0; i < sections_nr; i++) {
                sec = malloc(sizeof(*sec));
                if (!sec) {
@@ -273,13 +288,18 @@ static int read_sections(struct elf *elf)
                }
                sec->len = sec->sh.sh_size;
 
+               if (sec->sh.sh_flags & SHF_EXECINSTR)
+                       elf->text_size += sec->len;
+
                list_add_tail(&sec->list, &elf->sections);
-               elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
-               elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
+               elf_hash_add(section, &sec->hash, sec->idx);
+               elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));
        }
 
-       if (stats)
+       if (stats) {
                printf("nr_sections: %lu\n", (unsigned long)sections_nr);
+               printf("section_bits: %d\n", elf->section_bits);
+       }
 
        /* sanity check, one more call to elf_nextscn() should return NULL */
        if (elf_nextscn(elf->elf, s)) {
@@ -308,8 +328,8 @@ static void elf_add_symbol(struct elf *elf, struct symbol *sym)
        else
                entry = &sym->sec->symbol_list;
        list_add(&sym->list, entry);
-       elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
-       elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
+       elf_hash_add(symbol, &sym->hash, sym->idx);
+       elf_hash_add(symbol_name, &sym->name_hash, str_hash(sym->name));
 
        /*
         * Don't store empty STT_NOTYPE symbols in the rbtree.  They
@@ -329,19 +349,25 @@ static int read_symbols(struct elf *elf)
        Elf32_Word shndx;
 
        symtab = find_section_by_name(elf, ".symtab");
-       if (!symtab) {
+       if (symtab) {
+               symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+               if (symtab_shndx)
+                       shndx_data = symtab_shndx->data;
+
+               symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
+       } else {
                /*
                 * A missing symbol table is actually possible if it's an empty
-                * .o file.  This can happen for thunk_64.o.
+                * .o file. This can happen for thunk_64.o. Make sure to at
+                * least allocate the symbol hash tables so we can do symbol
+                * lookups without crashing.
                 */
-               return 0;
+               symbols_nr = 0;
        }
 
-       symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
-       if (symtab_shndx)
-               shndx_data = symtab_shndx->data;
-
-       symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
+       if (!elf_alloc_hash(symbol, symbols_nr) ||
+           !elf_alloc_hash(symbol_name, symbols_nr))
+               return -1;
 
        for (i = 0; i < symbols_nr; i++) {
                sym = malloc(sizeof(*sym));
@@ -389,8 +415,10 @@ static int read_symbols(struct elf *elf)
                elf_add_symbol(elf, sym);
        }
 
-       if (stats)
+       if (stats) {
                printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);
+               printf("symbol_bits: %d\n", elf->symbol_bits);
+       }
 
        /* Create parent/child links for any cold subfunctions */
        list_for_each_entry(sec, &elf->sections, list) {
@@ -479,7 +507,7 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
        reloc->addend = addend;
 
        list_add_tail(&reloc->list, &sec->reloc->reloc_list);
-       elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
+       elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 
        sec->reloc->changed = true;
 
@@ -556,6 +584,9 @@ static int read_relocs(struct elf *elf)
        unsigned int symndx;
        unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
 
+       if (!elf_alloc_hash(reloc, elf->text_size / 16))
+               return -1;
+
        list_for_each_entry(sec, &elf->sections, list) {
                if ((sec->sh.sh_type != SHT_RELA) &&
                    (sec->sh.sh_type != SHT_REL))
@@ -600,7 +631,7 @@ static int read_relocs(struct elf *elf)
                        }
 
                        list_add_tail(&reloc->list, &sec->reloc_list);
-                       elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
+                       elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 
                        nr_reloc++;
                }
@@ -611,6 +642,7 @@ static int read_relocs(struct elf *elf)
        if (stats) {
                printf("max_reloc: %lu\n", max_reloc);
                printf("tot_reloc: %lu\n", tot_reloc);
+               printf("reloc_bits: %d\n", elf->reloc_bits);
        }
 
        return 0;
@@ -632,12 +664,6 @@ struct elf *elf_open_read(const char *name, int flags)
 
        INIT_LIST_HEAD(&elf->sections);
 
-       elf_hash_init(elf->symbol_hash);
-       elf_hash_init(elf->symbol_name_hash);
-       elf_hash_init(elf->section_hash);
-       elf_hash_init(elf->section_name_hash);
-       elf_hash_init(elf->reloc_hash);
-
        elf->fd = open(name, flags);
        if (elf->fd == -1) {
                fprintf(stderr, "objtool: Can't open '%s': %s\n",
@@ -874,8 +900,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
                return NULL;
 
        list_add_tail(&sec->list, &elf->sections);
-       elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
-       elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
+       elf_hash_add(section, &sec->hash, sec->idx);
+       elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));
 
        elf->changed = true;
 
index 45e5ede..e343950 100644 (file)
@@ -83,12 +83,20 @@ struct elf {
        int fd;
        bool changed;
        char *name;
+       unsigned int text_size;
        struct list_head sections;
-       DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS);
-       DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS);
-       DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS);
-       DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS);
-       DECLARE_HASHTABLE(reloc_hash, ELF_HASH_BITS);
+
+       int symbol_bits;
+       int symbol_name_bits;
+       int section_bits;
+       int section_name_bits;
+       int reloc_bits;
+
+       struct hlist_head *symbol_hash;
+       struct hlist_head *symbol_name_hash;
+       struct hlist_head *section_hash;
+       struct hlist_head *section_name_hash;
+       struct hlist_head *reloc_hash;
 };
 
 #define OFFSET_STRIDE_BITS     4
index e4084af..24fa836 100644 (file)
@@ -22,6 +22,9 @@ struct objtool_file {
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        bool ignore_unreachables, c_file, hints, rodata;
+
+       unsigned long jl_short, jl_long;
+       unsigned long jl_nop_short, jl_nop_long;
 };
 
 struct objtool_file *objtool_open_read(const char *_objname);
index 8a09f4e..dc4721e 100644 (file)
@@ -27,6 +27,7 @@ struct special_alt {
        unsigned long new_off;
 
        unsigned int orig_len, new_len; /* group only */
+       u8 key_addend;
 };
 
 int special_get_alts(struct elf *elf, struct list_head *alts);
index 07b21cf..bc925cf 100644 (file)
@@ -23,6 +23,7 @@ struct special_entry {
        unsigned char size, orig, new;
        unsigned char orig_len, new_len; /* group only */
        unsigned char feature; /* ALTERNATIVE macro CPU feature */
+       unsigned char key; /* jump_label key */
 };
 
 struct special_entry entries[] = {
@@ -42,6 +43,7 @@ struct special_entry entries[] = {
                .size = JUMP_ENTRY_SIZE,
                .orig = JUMP_ORIG_OFFSET,
                .new = JUMP_NEW_OFFSET,
+               .key = JUMP_KEY_OFFSET,
        },
        {
                .sec = "__ex_table",
@@ -122,6 +124,18 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
                        alt->new_off -= 0x7ffffff0;
        }
 
+       if (entry->key) {
+               struct reloc *key_reloc;
+
+               key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key);
+               if (!key_reloc) {
+                       WARN_FUNC("can't find key reloc",
+                                 sec, offset + entry->key);
+                       return -1;
+               }
+               alt->key_addend = key_reloc->addend;
+       }
+
        return 0;
 }
 
index 22eb31e..2f9948b 100755 (executable)
@@ -11,9 +11,9 @@ compare_number()
        second_num=$2
 
        # upper bound is first_num * 110%
-       upper=$(( $first_num + $first_num / 10 ))
+       upper=$(expr $first_num + $first_num / 10 )
        # lower bound is first_num * 90%
-       lower=$(( $first_num - $first_num / 10 ))
+       lower=$(expr $first_num - $first_num / 10 )
 
        if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then
                echo "The difference between $first_num and $second_num are greater than 10%."
index b8fc5c5..0d8e3dc 100644 (file)
@@ -438,6 +438,4 @@ extern int __sys_socketpair(int family, int type, int protocol,
                            int __user *usockvec);
 extern int __sys_shutdown_sock(struct socket *sock, int how);
 extern int __sys_shutdown(int fd, int how);
-
-extern struct ns_common *get_net_ns(struct ns_common *ns);
 #endif /* _LINUX_SOCKET_H */
index 3ff4936..da19be7 100644 (file)
@@ -776,10 +776,10 @@ static int machine__process_ksymbol_register(struct machine *machine,
                if (dso) {
                        dso->kernel = DSO_SPACE__KERNEL;
                        map = map__new2(0, dso);
+                       dso__put(dso);
                }
 
                if (!dso || !map) {
-                       dso__put(dso);
                        return -ENOMEM;
                }
 
@@ -792,6 +792,7 @@ static int machine__process_ksymbol_register(struct machine *machine,
                map->start = event->ksymbol.addr;
                map->end = map->start + event->ksymbol.len;
                maps__insert(&machine->kmaps, map);
+               map__put(map);
                dso__set_loaded(dso);
 
                if (is_bpf_image(event->ksymbol.name)) {
index 8336dd8..d3cf2de 100644 (file)
@@ -162,10 +162,10 @@ static bool contains_event(struct evsel **metric_events, int num_events,
        return false;
 }
 
-static bool evsel_same_pmu(struct evsel *ev1, struct evsel *ev2)
+static bool evsel_same_pmu_or_none(struct evsel *ev1, struct evsel *ev2)
 {
        if (!ev1->pmu_name || !ev2->pmu_name)
-               return false;
+               return true;
 
        return !strcmp(ev1->pmu_name, ev2->pmu_name);
 }
@@ -288,7 +288,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist,
                         */
                        if (!has_constraint &&
                            ev->leader != metric_events[i]->leader &&
-                           evsel_same_pmu(ev->leader, metric_events[i]->leader))
+                           evsel_same_pmu_or_none(ev->leader, metric_events[i]->leader))
                                break;
                        if (!strcmp(metric_events[i]->name, ev->name)) {
                                set_bit(ev->idx, evlist_used);
@@ -1073,16 +1073,18 @@ static int metricgroup__add_metric_sys_event_iter(struct pmu_event *pe,
 
        ret = add_metric(d->metric_list, pe, d->metric_no_group, &m, NULL, d->ids);
        if (ret)
-               return ret;
+               goto out;
 
        ret = resolve_metric(d->metric_no_group,
                                     d->metric_list, NULL, d->ids);
        if (ret)
-               return ret;
+               goto out;
 
        *(d->has_match) = true;
 
-       return *d->ret;
+out:
+       *(d->ret) = ret;
+       return ret;
 }
 
 static int metricgroup__add_metric(const char *metric, bool metric_no_group,
index bc3299a..fb010a3 100644 (file)
@@ -49,6 +49,7 @@ TARGETS += proc
 TARGETS += pstore
 TARGETS += ptrace
 TARGETS += openat2
+TARGETS += rlimits
 TARGETS += rseq
 TARGETS += rtc
 TARGETS += seccomp
index b29cbc6..76e1385 100644 (file)
@@ -25,7 +25,7 @@ int main(int argc, char **argv)
        ksft_set_plan(2);
 
        if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
-               ksft_exit_skip("SVE not available");
+               ksft_exit_skip("SVE not available\n");
 
        /*
         * Enumerate up to SVE_VQ_MAX vector lengths
index 1512092..3a9e332 100644 (file)
@@ -1147,7 +1147,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
                }
        }
 
-       if (test->insn_processed) {
+       if (!unpriv && test->insn_processed) {
                uint32_t insn_processed;
                char *proc;
 
index ca8fdb1..7d7ebee 100644 (file)
@@ -61,6 +61,8 @@
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R1 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 0
 },
index 8a1caf4..e061e87 100644 (file)
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, -1),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT
 },
 {
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, -1),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT
 },
 {
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 min value is outside of the allowed memory range",
+       .result_unpriv = REJECT,
        .fixup_map_hash_8b = { 3 },
        .result = ACCEPT,
 },
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 min value is outside of the allowed memory range",
+       .result_unpriv = REJECT,
        .fixup_map_hash_8b = { 3 },
        .result = ACCEPT,
 },
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 min value is outside of the allowed memory range",
+       .result_unpriv = REJECT,
        .fixup_map_hash_8b = { 3 },
        .result = ACCEPT,
 },
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 min value is outside of the allowed memory range",
+       .result_unpriv = REJECT,
        .fixup_map_hash_8b = { 3 },
        .result = ACCEPT,
 },
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 min value is outside of the allowed memory range",
+       .result_unpriv = REJECT,
        .fixup_map_hash_8b = { 3 },
        .result = ACCEPT,
 },
index 17fe33a..2c8935b 100644 (file)
@@ -8,6 +8,8 @@
        BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 10, -4),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 7,
 },
index bd5cae4..1c857b2 100644 (file)
@@ -87,6 +87,8 @@
        BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
 },
 {
        BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
 },
 {
        BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
 },
 {
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 2,
 },
index 8dcd4e0..11fc68d 100644 (file)
@@ -82,8 +82,8 @@
        BPF_EXIT_INSN(),
        },
        .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
-       .retval_unpriv = 1,
-       .result_unpriv = ACCEPT,
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .retval = 1,
        .result = ACCEPT,
 },
        BPF_EXIT_INSN(),
        },
        .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
-       .result_unpriv = ACCEPT,
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
 },
 {
        BPF_EXIT_INSN(),
        },
        .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
-       .result_unpriv = ACCEPT,
+       .errstr_unpriv = "R9 !read_ok",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
 },
index bd436df..111801a 100644 (file)
        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_7, 0),
        BPF_EXIT_INSN(),
        },
+       .errstr_unpriv = "R7 invalid mem access 'inv'",
+       .result_unpriv = REJECT,
        .result = ACCEPT,
        .retval = 0,
 },
index 7ae2859..a3e593d 100644 (file)
        .fixup_map_array_48b = { 1 },
        .result = ACCEPT,
        .result_unpriv = REJECT,
-       .errstr_unpriv = "R2 tried to add from different maps, paths or scalars",
+       .errstr_unpriv = "R2 pointer comparison prohibited",
        .retval = 0,
 },
 {
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        // fake-dead code; targeted from branch A to
-       // prevent dead code sanitization
+       // prevent dead code sanitization, rejected
+       // via branch B however
        BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        .fixup_map_array_48b = { 1 },
        .result = ACCEPT,
        .result_unpriv = REJECT,
-       .errstr_unpriv = "R2 tried to add from different maps, paths or scalars",
+       .errstr_unpriv = "R0 invalid mem access 'inv'",
        .retval = 0,
 },
 {
index 0efcd49..0e78b49 100644 (file)
@@ -6,3 +6,5 @@ futex_wait_private_mapped_file
 futex_wait_timeout
 futex_wait_uninitialized_heap
 futex_wait_wouldblock
+futex_wait
+futex_requeue
index 2320782..bd1fec5 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-INCLUDES := -I../include -I../../
+INCLUDES := -I../include -I../../ -I../../../../../usr/include/ \
+       -I$(KBUILD_OUTPUT)/kselftest/usr/include
 CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES)
 LDLIBS := -lpthread -lrt
 
@@ -14,7 +15,9 @@ TEST_GEN_FILES := \
        futex_requeue_pi_signal_restart \
        futex_requeue_pi_mismatched_ops \
        futex_wait_uninitialized_heap \
-       futex_wait_private_mapped_file
+       futex_wait_private_mapped_file \
+       futex_wait \
+       futex_requeue
 
 TEST_PROGS := run.sh
 
diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c
new file mode 100644 (file)
index 0000000..51485be
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright Collabora Ltd., 2021
+ *
+ * futex cmp requeue test by André Almeida <andrealmeid@collabora.com>
+ */
+
+#include <pthread.h>
+#include <limits.h>
+#include "logging.h"
+#include "futextest.h"
+
+#define TEST_NAME "futex-requeue"
+#define timeout_ns  30000000
+#define WAKE_WAIT_US 10000
+
+volatile futex_t *f1;
+
+void usage(char *prog)
+{
+       printf("Usage: %s\n", prog);
+       printf("  -c    Use color\n");
+       printf("  -h    Display this help message\n");
+       printf("  -v L  Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
+              VQUIET, VCRITICAL, VINFO);
+}
+
+void *waiterfn(void *arg)
+{
+       struct timespec to;
+
+       to.tv_sec = 0;
+       to.tv_nsec = timeout_ns;
+
+       if (futex_wait(f1, *f1, &to, 0))
+               printf("waiter failed errno %d\n", errno);
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       pthread_t waiter[10];
+       int res, ret = RET_PASS;
+       int c, i;
+       volatile futex_t _f1 = 0;
+       volatile futex_t f2 = 0;
+
+       f1 = &_f1;
+
+       while ((c = getopt(argc, argv, "cht:v:")) != -1) {
+               switch (c) {
+               case 'c':
+                       log_color(1);
+                       break;
+               case 'h':
+                       usage(basename(argv[0]));
+                       exit(0);
+               case 'v':
+                       log_verbosity(atoi(optarg));
+                       break;
+               default:
+                       usage(basename(argv[0]));
+                       exit(1);
+               }
+       }
+
+       ksft_print_header();
+       ksft_set_plan(2);
+       ksft_print_msg("%s: Test futex_requeue\n",
+                      basename(argv[0]));
+
+       /*
+        * Requeue a waiter from f1 to f2, and wake f2.
+        */
+       if (pthread_create(&waiter[0], NULL, waiterfn, NULL))
+               error("pthread_create failed\n", errno);
+
+       usleep(WAKE_WAIT_US);
+
+       info("Requeuing 1 futex from f1 to f2\n");
+       res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0);
+       if (res != 1) {
+               ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
+                                     res ? errno : res,
+                                     res ? strerror(errno) : "");
+               ret = RET_FAIL;
+       }
+
+
+       info("Waking 1 futex at f2\n");
+       res = futex_wake(&f2, 1, 0);
+       if (res != 1) {
+               ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
+                                     res ? errno : res,
+                                     res ? strerror(errno) : "");
+               ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("futex_requeue simple succeeds\n");
+       }
+
+
+       /*
+        * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
+        * At futex_wake, wake INT_MAX (should be exactly 7).
+        */
+       for (i = 0; i < 10; i++) {
+               if (pthread_create(&waiter[i], NULL, waiterfn, NULL))
+                       error("pthread_create failed\n", errno);
+       }
+
+       usleep(WAKE_WAIT_US);
+
+       info("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n");
+       res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0);
+       if (res != 10) {
+               ksft_test_result_fail("futex_requeue many returned: %d %s\n",
+                                     res ? errno : res,
+                                     res ? strerror(errno) : "");
+               ret = RET_FAIL;
+       }
+
+       info("Waking INT_MAX futexes at f2\n");
+       res = futex_wake(&f2, INT_MAX, 0);
+       if (res != 7) {
+               ksft_test_result_fail("futex_requeue many returned: %d %s\n",
+                                     res ? errno : res,
+                                     res ? strerror(errno) : "");
+               ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("futex_requeue many succeeds\n");
+       }
+
+       ksft_print_cnts();
+       return ret;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_wait.c b/tools/testing/selftests/futex/functional/futex_wait.c
new file mode 100644 (file)
index 0000000..685140d
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright Collabora Ltd., 2021
+ *
+ * futex cmp requeue test by André Almeida <andrealmeid@collabora.com>
+ */
+
+#include <pthread.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include "logging.h"
+#include "futextest.h"
+
+#define TEST_NAME "futex-wait"
+#define timeout_ns  30000000
+#define WAKE_WAIT_US 10000
+#define SHM_PATH "futex_shm_file"
+
+void *futex;
+
+void usage(char *prog)
+{
+       printf("Usage: %s\n", prog);
+       printf("  -c    Use color\n");
+       printf("  -h    Display this help message\n");
+       printf("  -v L  Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
+              VQUIET, VCRITICAL, VINFO);
+}
+
+static void *waiterfn(void *arg)
+{
+       struct timespec to;
+       unsigned int flags = 0;
+
+       if (arg)
+               flags = *((unsigned int *) arg);
+
+       to.tv_sec = 0;
+       to.tv_nsec = timeout_ns;
+
+       if (futex_wait(futex, 0, &to, flags))
+               printf("waiter failed errno %d\n", errno);
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       int res, ret = RET_PASS, fd, c, shm_id;
+       u_int32_t f_private = 0, *shared_data;
+       unsigned int flags = FUTEX_PRIVATE_FLAG;
+       pthread_t waiter;
+       void *shm;
+
+       futex = &f_private;
+
+       while ((c = getopt(argc, argv, "cht:v:")) != -1) {
+               switch (c) {
+               case 'c':
+                       log_color(1);
+                       break;
+               case 'h':
+                       usage(basename(argv[0]));
+                       exit(0);
+               case 'v':
+                       log_verbosity(atoi(optarg));
+                       break;
+               default:
+                       usage(basename(argv[0]));
+                       exit(1);
+               }
+       }
+
+       ksft_print_header();
+       ksft_set_plan(3);
+       ksft_print_msg("%s: Test futex_wait\n", basename(argv[0]));
+
+       /* Testing a private futex */
+       info("Calling private futex_wait on futex: %p\n", futex);
+       if (pthread_create(&waiter, NULL, waiterfn, (void *) &flags))
+               error("pthread_create failed\n", errno);
+
+       usleep(WAKE_WAIT_US);
+
+       info("Calling private futex_wake on futex: %p\n", futex);
+       res = futex_wake(futex, 1, FUTEX_PRIVATE_FLAG);
+       if (res != 1) {
+               ksft_test_result_fail("futex_wake private returned: %d %s\n",
+                                     errno, strerror(errno));
+               ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("futex_wake private succeeds\n");
+       }
+
+       /* Testing an anon page shared memory */
+       shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
+       if (shm_id < 0) {
+               perror("shmget");
+               exit(1);
+       }
+
+       shared_data = shmat(shm_id, NULL, 0);
+
+       *shared_data = 0;
+       futex = shared_data;
+
+       info("Calling shared (page anon) futex_wait on futex: %p\n", futex);
+       if (pthread_create(&waiter, NULL, waiterfn, NULL))
+               error("pthread_create failed\n", errno);
+
+       usleep(WAKE_WAIT_US);
+
+       info("Calling shared (page anon) futex_wake on futex: %p\n", futex);
+       res = futex_wake(futex, 1, 0);
+       if (res != 1) {
+               ksft_test_result_fail("futex_wake shared (page anon) returned: %d %s\n",
+                                     errno, strerror(errno));
+               ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("futex_wake shared (page anon) succeeds\n");
+       }
+
+
+       /* Testing a file backed shared memory */
+       fd = open(SHM_PATH, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+
+       if (ftruncate(fd, sizeof(f_private))) {
+               perror("ftruncate");
+               exit(1);
+       }
+
+       shm = mmap(NULL, sizeof(f_private), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (shm == MAP_FAILED) {
+               perror("mmap");
+               exit(1);
+       }
+
+       memcpy(shm, &f_private, sizeof(f_private));
+
+       futex = shm;
+
+       info("Calling shared (file backed) futex_wait on futex: %p\n", futex);
+       if (pthread_create(&waiter, NULL, waiterfn, NULL))
+               error("pthread_create failed\n", errno);
+
+       usleep(WAKE_WAIT_US);
+
+       info("Calling shared (file backed) futex_wake on futex: %p\n", futex);
+       res = futex_wake(shm, 1, 0);
+       if (res != 1) {
+               ksft_test_result_fail("futex_wake shared (file backed) returned: %d %s\n",
+                                     errno, strerror(errno));
+               ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("futex_wake shared (file backed) succeeds\n");
+       }
+
+       /* Freeing resources */
+       shmdt(shared_data);
+       munmap(shm, sizeof(f_private));
+       remove(SHM_PATH);
+       close(fd);
+
+       ksft_print_cnts();
+       return ret;
+}
index ee55e6d..1f8f6da 100644 (file)
  *
  * HISTORY
  *      2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
+ *      2021-Apr-26: More test cases by André Almeida <andrealmeid@collabora.com>
  *
  *****************************************************************************/
 
-#include <errno.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
+#include <pthread.h>
 #include "futextest.h"
 #include "logging.h"
 
 #define TEST_NAME "futex-wait-timeout"
 
 static long timeout_ns = 100000;       /* 100us default timeout */
+static futex_t futex_pi;
 
 void usage(char *prog)
 {
@@ -37,11 +34,67 @@ void usage(char *prog)
               VQUIET, VCRITICAL, VINFO);
 }
 
+/*
+ * Get a PI lock and hold it forever, so the main thread lock_pi will block
+ * and we can test the timeout
+ */
+void *get_pi_lock(void *arg)
+{
+       int ret;
+       volatile futex_t lock = 0;
+
+       ret = futex_lock_pi(&futex_pi, NULL, 0, 0);
+       if (ret != 0)
+               error("futex_lock_pi failed\n", ret);
+
+       /* Blocks forever */
+       ret = futex_wait(&lock, 0, NULL, 0);
+       error("futex_wait failed\n", ret);
+
+       return NULL;
+}
+
+/*
+ * Check if the function returned the expected error
+ */
+static void test_timeout(int res, int *ret, char *test_name, int err)
+{
+       if (!res || errno != err) {
+               ksft_test_result_fail("%s returned %d\n", test_name,
+                                     res < 0 ? errno : res);
+               *ret = RET_FAIL;
+       } else {
+               ksft_test_result_pass("%s succeeds\n", test_name);
+       }
+}
+
+/*
+ * Calculate absolute timeout and correct overflow
+ */
+static int futex_get_abs_timeout(clockid_t clockid, struct timespec *to,
+                                long timeout_ns)
+{
+       if (clock_gettime(clockid, to)) {
+               error("clock_gettime failed\n", errno);
+               return errno;
+       }
+
+       to->tv_nsec += timeout_ns;
+
+       if (to->tv_nsec >= 1000000000) {
+               to->tv_sec++;
+               to->tv_nsec -= 1000000000;
+       }
+
+       return 0;
+}
+
 int main(int argc, char *argv[])
 {
        futex_t f1 = FUTEX_INITIALIZER;
-       struct timespec to;
        int res, ret = RET_PASS;
+       struct timespec to;
+       pthread_t thread;
        int c;
 
        while ((c = getopt(argc, argv, "cht:v:")) != -1) {
@@ -65,22 +118,63 @@ int main(int argc, char *argv[])
        }
 
        ksft_print_header();
-       ksft_set_plan(1);
+       ksft_set_plan(7);
        ksft_print_msg("%s: Block on a futex and wait for timeout\n",
               basename(argv[0]));
        ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns);
 
-       /* initialize timeout */
+       pthread_create(&thread, NULL, get_pi_lock, NULL);
+
+       /* initialize relative timeout */
        to.tv_sec = 0;
        to.tv_nsec = timeout_ns;
 
-       info("Calling futex_wait on f1: %u @ %p\n", f1, &f1);
-       res = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG);
-       if (!res || errno != ETIMEDOUT) {
-               fail("futex_wait returned %d\n", ret < 0 ? errno : ret);
-               ret = RET_FAIL;
-       }
+       res = futex_wait(&f1, f1, &to, 0);
+       test_timeout(res, &ret, "futex_wait relative", ETIMEDOUT);
+
+       /* FUTEX_WAIT_BITSET with CLOCK_REALTIME */
+       if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
+               return RET_FAIL;
+       res = futex_wait_bitset(&f1, f1, &to, 1, FUTEX_CLOCK_REALTIME);
+       test_timeout(res, &ret, "futex_wait_bitset realtime", ETIMEDOUT);
+
+       /* FUTEX_WAIT_BITSET with CLOCK_MONOTONIC */
+       if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
+               return RET_FAIL;
+       res = futex_wait_bitset(&f1, f1, &to, 1, 0);
+       test_timeout(res, &ret, "futex_wait_bitset monotonic", ETIMEDOUT);
+
+       /* FUTEX_WAIT_REQUEUE_PI with CLOCK_REALTIME */
+       if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
+               return RET_FAIL;
+       res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, FUTEX_CLOCK_REALTIME);
+       test_timeout(res, &ret, "futex_wait_requeue_pi realtime", ETIMEDOUT);
+
+       /* FUTEX_WAIT_REQUEUE_PI with CLOCK_MONOTONIC */
+       if (futex_get_abs_timeout(CLOCK_MONOTONIC, &to, timeout_ns))
+               return RET_FAIL;
+       res = futex_wait_requeue_pi(&f1, f1, &futex_pi, &to, 0);
+       test_timeout(res, &ret, "futex_wait_requeue_pi monotonic", ETIMEDOUT);
+
+       /*
+        * FUTEX_LOCK_PI with CLOCK_REALTIME
+        * Due to historical reasons, FUTEX_LOCK_PI supports only realtime
+        * clock, but requires the caller to not set CLOCK_REALTIME flag.
+        *
+        * If you call FUTEX_LOCK_PI with a monotonic clock, it'll be
+        * interpreted as a realtime clock, and (unless you mess your machine's
+        * time or your time machine) the monotonic clock value is always
+        * smaller than realtime and the syscall will timeout immediately.
+        */
+       if (futex_get_abs_timeout(CLOCK_REALTIME, &to, timeout_ns))
+               return RET_FAIL;
+       res = futex_lock_pi(&futex_pi, &to, 0, 0);
+       test_timeout(res, &ret, "futex_lock_pi realtime", ETIMEDOUT);
+
+       /* Test operations that don't support FUTEX_CLOCK_REALTIME */
+       res = futex_lock_pi(&futex_pi, NULL, 0, FUTEX_CLOCK_REALTIME);
+       test_timeout(res, &ret, "futex_lock_pi invalid timeout flag", ENOSYS);
 
-       print_result(TEST_NAME, ret);
+       ksft_print_cnts();
        return ret;
 }
index 1acb6ac..11a9d62 100755 (executable)
@@ -73,3 +73,9 @@ echo
 echo
 ./futex_wait_uninitialized_heap $COLOR
 ./futex_wait_private_mapped_file $COLOR
+
+echo
+./futex_wait $COLOR
+
+echo
+./futex_requeue $COLOR
index 524c857..06a351b 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
+/aarch64/debug-exceptions
 /aarch64/get-reg-list
-/aarch64/get-reg-list-sve
 /aarch64/vgic_init
 /s390x/memop
 /s390x/resets
@@ -8,12 +8,15 @@
 /x86_64/cr4_cpuid_sync_test
 /x86_64/debug_regs
 /x86_64/evmcs_test
+/x86_64/emulator_error_test
 /x86_64/get_cpuid_test
 /x86_64/get_msr_index_features
 /x86_64/kvm_pv_test
 /x86_64/hyperv_clock
 /x86_64/hyperv_cpuid
+/x86_64/hyperv_features
 /x86_64/mmio_warning_test
+/x86_64/mmu_role_test
 /x86_64/platform_info_test
 /x86_64/set_boot_cpu_id
 /x86_64/set_sregs_test
@@ -29,6 +32,7 @@
 /x86_64/vmx_preemption_timer_test
 /x86_64/vmx_set_nested_state_test
 /x86_64/vmx_tsc_adjust_test
+/x86_64/vmx_nested_tsc_scaling_test
 /x86_64/xapic_ipi_test
 /x86_64/xen_shinfo_test
 /x86_64/xen_vmcall_test
@@ -44,3 +48,4 @@
 /memslot_perf_test
 /set_memory_region_test
 /steal_time
+/kvm_binary_stats_test
index daaee18..b853be2 100644 (file)
@@ -34,18 +34,21 @@ ifeq ($(ARCH),s390)
 endif
 
 LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/rbtree.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c
-LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S
-LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c
+LIBKVM_x86_64 = lib/x86_64/apic.c lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S
+LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c lib/aarch64/handlers.S
 LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c
 
 TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
 TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features
 TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
+TEST_GEN_PROGS_x86_64 += x86_64/emulator_error_test
 TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
+TEST_GEN_PROGS_x86_64 += x86_64/hyperv_features
 TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
 TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
+TEST_GEN_PROGS_x86_64 += x86_64/mmu_role_test
 TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
 TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
 TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
@@ -60,6 +63,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
+TEST_GEN_PROGS_x86_64 += x86_64/vmx_nested_tsc_scaling_test
 TEST_GEN_PROGS_x86_64 += x86_64/xapic_ipi_test
 TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test
 TEST_GEN_PROGS_x86_64 += x86_64/debug_regs
@@ -77,9 +81,10 @@ TEST_GEN_PROGS_x86_64 += memslot_modification_stress_test
 TEST_GEN_PROGS_x86_64 += memslot_perf_test
 TEST_GEN_PROGS_x86_64 += set_memory_region_test
 TEST_GEN_PROGS_x86_64 += steal_time
+TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test
 
+TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
 TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
-TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list-sve
 TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
 TEST_GEN_PROGS_aarch64 += demand_paging_test
 TEST_GEN_PROGS_aarch64 += dirty_log_test
@@ -88,6 +93,7 @@ TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus
 TEST_GEN_PROGS_aarch64 += kvm_page_table_test
 TEST_GEN_PROGS_aarch64 += set_memory_region_test
 TEST_GEN_PROGS_aarch64 += steal_time
+TEST_GEN_PROGS_aarch64 += kvm_binary_stats_test
 
 TEST_GEN_PROGS_s390x = s390x/memop
 TEST_GEN_PROGS_s390x += s390x/resets
@@ -97,6 +103,7 @@ TEST_GEN_PROGS_s390x += dirty_log_test
 TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
 TEST_GEN_PROGS_s390x += kvm_page_table_test
 TEST_GEN_PROGS_s390x += set_memory_region_test
+TEST_GEN_PROGS_s390x += kvm_binary_stats_test
 
 TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
 LIBKVM += $(LIBKVM_$(UNAME_M))
diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c
new file mode 100644 (file)
index 0000000..e5e6c92
--- /dev/null
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_util.h>
+#include <kvm_util.h>
+#include <processor.h>
+
+#define VCPU_ID 0
+
+#define MDSCR_KDE      (1 << 13)
+#define MDSCR_MDE      (1 << 15)
+#define MDSCR_SS       (1 << 0)
+
+#define DBGBCR_LEN8    (0xff << 5)
+#define DBGBCR_EXEC    (0x0 << 3)
+#define DBGBCR_EL1     (0x1 << 1)
+#define DBGBCR_E       (0x1 << 0)
+
+#define DBGWCR_LEN8    (0xff << 5)
+#define DBGWCR_RD      (0x1 << 3)
+#define DBGWCR_WR      (0x2 << 3)
+#define DBGWCR_EL1     (0x1 << 1)
+#define DBGWCR_E       (0x1 << 0)
+
+#define SPSR_D         (1 << 9)
+#define SPSR_SS                (1 << 21)
+
+extern unsigned char sw_bp, hw_bp, bp_svc, bp_brk, hw_wp, ss_start;
+static volatile uint64_t sw_bp_addr, hw_bp_addr;
+static volatile uint64_t wp_addr, wp_data_addr;
+static volatile uint64_t svc_addr;
+static volatile uint64_t ss_addr[4], ss_idx;
+#define  PC(v)  ((uint64_t)&(v))
+
+static void reset_debug_state(void)
+{
+       asm volatile("msr daifset, #8");
+
+       write_sysreg(osdlr_el1, 0);
+       write_sysreg(oslar_el1, 0);
+       isb();
+
+       write_sysreg(mdscr_el1, 0);
+       /* This test only uses the first bp and wp slot. */
+       write_sysreg(dbgbvr0_el1, 0);
+       write_sysreg(dbgbcr0_el1, 0);
+       write_sysreg(dbgwcr0_el1, 0);
+       write_sysreg(dbgwvr0_el1, 0);
+       isb();
+}
+
+static void install_wp(uint64_t addr)
+{
+       uint32_t wcr;
+       uint32_t mdscr;
+
+       wcr = DBGWCR_LEN8 | DBGWCR_RD | DBGWCR_WR | DBGWCR_EL1 | DBGWCR_E;
+       write_sysreg(dbgwcr0_el1, wcr);
+       write_sysreg(dbgwvr0_el1, addr);
+       isb();
+
+       asm volatile("msr daifclr, #8");
+
+       mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
+       write_sysreg(mdscr_el1, mdscr);
+       isb();
+}
+
+static void install_hw_bp(uint64_t addr)
+{
+       uint32_t bcr;
+       uint32_t mdscr;
+
+       bcr = DBGBCR_LEN8 | DBGBCR_EXEC | DBGBCR_EL1 | DBGBCR_E;
+       write_sysreg(dbgbcr0_el1, bcr);
+       write_sysreg(dbgbvr0_el1, addr);
+       isb();
+
+       asm volatile("msr daifclr, #8");
+
+       mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_MDE;
+       write_sysreg(mdscr_el1, mdscr);
+       isb();
+}
+
+static void install_ss(void)
+{
+       uint32_t mdscr;
+
+       asm volatile("msr daifclr, #8");
+
+       mdscr = read_sysreg(mdscr_el1) | MDSCR_KDE | MDSCR_SS;
+       write_sysreg(mdscr_el1, mdscr);
+       isb();
+}
+
+static volatile char write_data;
+
+static void guest_code(void)
+{
+       GUEST_SYNC(0);
+
+       /* Software-breakpoint */
+       asm volatile("sw_bp: brk #0");
+       GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp));
+
+       GUEST_SYNC(1);
+
+       /* Hardware-breakpoint */
+       reset_debug_state();
+       install_hw_bp(PC(hw_bp));
+       asm volatile("hw_bp: nop");
+       GUEST_ASSERT_EQ(hw_bp_addr, PC(hw_bp));
+
+       GUEST_SYNC(2);
+
+       /* Hardware-breakpoint + svc */
+       reset_debug_state();
+       install_hw_bp(PC(bp_svc));
+       asm volatile("bp_svc: svc #0");
+       GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_svc));
+       GUEST_ASSERT_EQ(svc_addr, PC(bp_svc) + 4);
+
+       GUEST_SYNC(3);
+
+       /* Hardware-breakpoint + software-breakpoint */
+       reset_debug_state();
+       install_hw_bp(PC(bp_brk));
+       asm volatile("bp_brk: brk #0");
+       GUEST_ASSERT_EQ(sw_bp_addr, PC(bp_brk));
+       GUEST_ASSERT_EQ(hw_bp_addr, PC(bp_brk));
+
+       GUEST_SYNC(4);
+
+       /* Watchpoint */
+       reset_debug_state();
+       install_wp(PC(write_data));
+       write_data = 'x';
+       GUEST_ASSERT_EQ(write_data, 'x');
+       GUEST_ASSERT_EQ(wp_data_addr, PC(write_data));
+
+       GUEST_SYNC(5);
+
+       /* Single-step */
+       reset_debug_state();
+       install_ss();
+       ss_idx = 0;
+       asm volatile("ss_start:\n"
+                    "mrs x0, esr_el1\n"
+                    "add x0, x0, #1\n"
+                    "msr daifset, #8\n"
+                    : : : "x0");
+       GUEST_ASSERT_EQ(ss_addr[0], PC(ss_start));
+       GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4);
+       GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8);
+
+       GUEST_DONE();
+}
+
+static void guest_sw_bp_handler(struct ex_regs *regs)
+{
+       sw_bp_addr = regs->pc;
+       regs->pc += 4;
+}
+
+static void guest_hw_bp_handler(struct ex_regs *regs)
+{
+       hw_bp_addr = regs->pc;
+       regs->pstate |= SPSR_D;
+}
+
+static void guest_wp_handler(struct ex_regs *regs)
+{
+       wp_data_addr = read_sysreg(far_el1);
+       wp_addr = regs->pc;
+       regs->pstate |= SPSR_D;
+}
+
+static void guest_ss_handler(struct ex_regs *regs)
+{
+       GUEST_ASSERT_1(ss_idx < 4, ss_idx);
+       ss_addr[ss_idx++] = regs->pc;
+       regs->pstate |= SPSR_SS;
+}
+
+static void guest_svc_handler(struct ex_regs *regs)
+{
+       svc_addr = regs->pc;
+}
+
+static int debug_version(struct kvm_vm *vm)
+{
+       uint64_t id_aa64dfr0;
+
+       get_reg(vm, VCPU_ID, ARM64_SYS_REG(ID_AA64DFR0_EL1), &id_aa64dfr0);
+       return id_aa64dfr0 & 0xf;
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_vm *vm;
+       struct ucall uc;
+       int stage;
+
+       vm = vm_create_default(VCPU_ID, 0, guest_code);
+       ucall_init(vm, NULL);
+
+       vm_init_descriptor_tables(vm);
+       vcpu_init_descriptor_tables(vm, VCPU_ID);
+
+       if (debug_version(vm) < 6) {
+               print_skip("Armv8 debug architecture not supported.");
+               kvm_vm_free(vm);
+               exit(KSFT_SKIP);
+       }
+
+       vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+                               ESR_EC_BRK_INS, guest_sw_bp_handler);
+       vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+                               ESR_EC_HW_BP_CURRENT, guest_hw_bp_handler);
+       vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+                               ESR_EC_WP_CURRENT, guest_wp_handler);
+       vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+                               ESR_EC_SSTEP_CURRENT, guest_ss_handler);
+       vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
+                               ESR_EC_SVC64, guest_svc_handler);
+
+       for (stage = 0; stage < 7; stage++) {
+               vcpu_run(vm, VCPU_ID);
+
+               switch (get_ucall(vm, VCPU_ID, &uc)) {
+               case UCALL_SYNC:
+                       TEST_ASSERT(uc.args[1] == stage,
+                               "Stage %d: Unexpected sync ucall, got %lx",
+                               stage, (ulong)uc.args[1]);
+                       break;
+               case UCALL_ABORT:
+                       TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx",
+                               (const char *)uc.args[0],
+                               __FILE__, uc.args[1], uc.args[2], uc.args[3]);
+                       break;
+               case UCALL_DONE:
+                       goto done;
+               default:
+                       TEST_FAIL("Unknown ucall %lu", uc.cmd);
+               }
+       }
+
+done:
+       kvm_vm_free(vm);
+       return 0;
+}
diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list-sve.c b/tools/testing/selftests/kvm/aarch64/get-reg-list-sve.c
deleted file mode 100644 (file)
index efba766..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define REG_LIST_SVE
-#include "get-reg-list.c"
index 4869321..a16c8f0 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include "kvm_util.h"
 #include "test_util.h"
 #include "processor.h"
 
-#ifdef REG_LIST_SVE
-#define reg_list_sve() (true)
-#else
-#define reg_list_sve() (false)
-#endif
+static struct kvm_reg_list *reg_list;
+static __u64 *blessed_reg, blessed_n;
 
-#define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK)
+struct reg_sublist {
+       const char *name;
+       long capability;
+       int feature;
+       bool finalize;
+       __u64 *regs;
+       __u64 regs_n;
+       __u64 *rejects_set;
+       __u64 rejects_set_n;
+};
+
+struct vcpu_config {
+       char *name;
+       struct reg_sublist sublists[];
+};
+
+static struct vcpu_config *vcpu_configs[];
+static int vcpu_configs_n;
+
+#define for_each_sublist(c, s)                                                 \
+       for ((s) = &(c)->sublists[0]; (s)->regs; ++(s))
 
 #define for_each_reg(i)                                                                \
        for ((i) = 0; (i) < reg_list->n; ++(i))
        for_each_reg_filtered(i)                                                \
                if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
 
+static const char *config_name(struct vcpu_config *c)
+{
+       struct reg_sublist *s;
+       int len = 0;
 
-static struct kvm_reg_list *reg_list;
+       if (c->name)
+               return c->name;
 
-static __u64 base_regs[], vregs[], sve_regs[], rejects_set[];
-static __u64 base_regs_n, vregs_n, sve_regs_n, rejects_set_n;
-static __u64 *blessed_reg, blessed_n;
+       for_each_sublist(c, s)
+               len += strlen(s->name) + 1;
+
+       c->name = malloc(len);
+
+       len = 0;
+       for_each_sublist(c, s) {
+               if (!strcmp(s->name, "base"))
+                       continue;
+               strcat(c->name + len, s->name);
+               len += strlen(s->name) + 1;
+               c->name[len - 1] = '+';
+       }
+       c->name[len - 1] = '\0';
+
+       return c->name;
+}
+
+static bool has_cap(struct vcpu_config *c, long capability)
+{
+       struct reg_sublist *s;
+
+       for_each_sublist(c, s)
+               if (s->capability == capability)
+                       return true;
+       return false;
+}
 
 static bool filter_reg(__u64 reg)
 {
@@ -96,11 +145,13 @@ static const char *str_with_index(const char *template, __u64 index)
        return (const char *)str;
 }
 
+#define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK)
+
 #define CORE_REGS_XX_NR_WORDS  2
 #define CORE_SPSR_XX_NR_WORDS  2
 #define CORE_FPREGS_XX_NR_WORDS        4
 
-static const char *core_id_to_str(__u64 id)
+static const char *core_id_to_str(struct vcpu_config *c, __u64 id)
 {
        __u64 core_off = id & ~REG_MASK, idx;
 
@@ -111,7 +162,7 @@ static const char *core_id_to_str(__u64 id)
        case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
             KVM_REG_ARM_CORE_REG(regs.regs[30]):
                idx = (core_off - KVM_REG_ARM_CORE_REG(regs.regs[0])) / CORE_REGS_XX_NR_WORDS;
-               TEST_ASSERT(idx < 31, "Unexpected regs.regs index: %lld", idx);
+               TEST_ASSERT(idx < 31, "%s: Unexpected regs.regs index: %lld", config_name(c), idx);
                return str_with_index("KVM_REG_ARM_CORE_REG(regs.regs[##])", idx);
        case KVM_REG_ARM_CORE_REG(regs.sp):
                return "KVM_REG_ARM_CORE_REG(regs.sp)";
@@ -126,12 +177,12 @@ static const char *core_id_to_str(__u64 id)
        case KVM_REG_ARM_CORE_REG(spsr[0]) ...
             KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]):
                idx = (core_off - KVM_REG_ARM_CORE_REG(spsr[0])) / CORE_SPSR_XX_NR_WORDS;
-               TEST_ASSERT(idx < KVM_NR_SPSR, "Unexpected spsr index: %lld", idx);
+               TEST_ASSERT(idx < KVM_NR_SPSR, "%s: Unexpected spsr index: %lld", config_name(c), idx);
                return str_with_index("KVM_REG_ARM_CORE_REG(spsr[##])", idx);
        case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
             KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
                idx = (core_off - KVM_REG_ARM_CORE_REG(fp_regs.vregs[0])) / CORE_FPREGS_XX_NR_WORDS;
-               TEST_ASSERT(idx < 32, "Unexpected fp_regs.vregs index: %lld", idx);
+               TEST_ASSERT(idx < 32, "%s: Unexpected fp_regs.vregs index: %lld", config_name(c), idx);
                return str_with_index("KVM_REG_ARM_CORE_REG(fp_regs.vregs[##])", idx);
        case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
                return "KVM_REG_ARM_CORE_REG(fp_regs.fpsr)";
@@ -139,11 +190,11 @@ static const char *core_id_to_str(__u64 id)
                return "KVM_REG_ARM_CORE_REG(fp_regs.fpcr)";
        }
 
-       TEST_FAIL("Unknown core reg id: 0x%llx", id);
+       TEST_FAIL("%s: Unknown core reg id: 0x%llx", config_name(c), id);
        return NULL;
 }
 
-static const char *sve_id_to_str(__u64 id)
+static const char *sve_id_to_str(struct vcpu_config *c, __u64 id)
 {
        __u64 sve_off, n, i;
 
@@ -153,37 +204,37 @@ static const char *sve_id_to_str(__u64 id)
        sve_off = id & ~(REG_MASK | ((1ULL << 5) - 1));
        i = id & (KVM_ARM64_SVE_MAX_SLICES - 1);
 
-       TEST_ASSERT(i == 0, "Currently we don't expect slice > 0, reg id 0x%llx", id);
+       TEST_ASSERT(i == 0, "%s: Currently we don't expect slice > 0, reg id 0x%llx", config_name(c), id);
 
        switch (sve_off) {
        case KVM_REG_ARM64_SVE_ZREG_BASE ...
             KVM_REG_ARM64_SVE_ZREG_BASE + (1ULL << 5) * KVM_ARM64_SVE_NUM_ZREGS - 1:
                n = (id >> 5) & (KVM_ARM64_SVE_NUM_ZREGS - 1);
                TEST_ASSERT(id == KVM_REG_ARM64_SVE_ZREG(n, 0),
-                           "Unexpected bits set in SVE ZREG id: 0x%llx", id);
+                           "%s: Unexpected bits set in SVE ZREG id: 0x%llx", config_name(c), id);
                return str_with_index("KVM_REG_ARM64_SVE_ZREG(##, 0)", n);
        case KVM_REG_ARM64_SVE_PREG_BASE ...
             KVM_REG_ARM64_SVE_PREG_BASE + (1ULL << 5) * KVM_ARM64_SVE_NUM_PREGS - 1:
                n = (id >> 5) & (KVM_ARM64_SVE_NUM_PREGS - 1);
                TEST_ASSERT(id == KVM_REG_ARM64_SVE_PREG(n, 0),
-                           "Unexpected bits set in SVE PREG id: 0x%llx", id);
+                           "%s: Unexpected bits set in SVE PREG id: 0x%llx", config_name(c), id);
                return str_with_index("KVM_REG_ARM64_SVE_PREG(##, 0)", n);
        case KVM_REG_ARM64_SVE_FFR_BASE:
                TEST_ASSERT(id == KVM_REG_ARM64_SVE_FFR(0),
-                           "Unexpected bits set in SVE FFR id: 0x%llx", id);
+                           "%s: Unexpected bits set in SVE FFR id: 0x%llx", config_name(c), id);
                return "KVM_REG_ARM64_SVE_FFR(0)";
        }
 
        return NULL;
 }
 
-static void print_reg(__u64 id)
+static void print_reg(struct vcpu_config *c, __u64 id)
 {
        unsigned op0, op1, crn, crm, op2;
        const char *reg_size = NULL;
 
        TEST_ASSERT((id & KVM_REG_ARCH_MASK) == KVM_REG_ARM64,
-                   "KVM_REG_ARM64 missing in reg id: 0x%llx", id);
+                   "%s: KVM_REG_ARM64 missing in reg id: 0x%llx", config_name(c), id);
 
        switch (id & KVM_REG_SIZE_MASK) {
        case KVM_REG_SIZE_U8:
@@ -214,17 +265,17 @@ static void print_reg(__u64 id)
                reg_size = "KVM_REG_SIZE_U2048";
                break;
        default:
-               TEST_FAIL("Unexpected reg size: 0x%llx in reg id: 0x%llx",
-                         (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id);
+               TEST_FAIL("%s: Unexpected reg size: 0x%llx in reg id: 0x%llx",
+                         config_name(c), (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id);
        }
 
        switch (id & KVM_REG_ARM_COPROC_MASK) {
        case KVM_REG_ARM_CORE:
-               printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_CORE | %s,\n", reg_size, core_id_to_str(id));
+               printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_CORE | %s,\n", reg_size, core_id_to_str(c, id));
                break;
        case KVM_REG_ARM_DEMUX:
                TEST_ASSERT(!(id & ~(REG_MASK | KVM_REG_ARM_DEMUX_ID_MASK | KVM_REG_ARM_DEMUX_VAL_MASK)),
-                           "Unexpected bits set in DEMUX reg id: 0x%llx", id);
+                           "%s: Unexpected bits set in DEMUX reg id: 0x%llx", config_name(c), id);
                printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_DEMUX | KVM_REG_ARM_DEMUX_ID_CCSIDR | %lld,\n",
                       reg_size, id & KVM_REG_ARM_DEMUX_VAL_MASK);
                break;
@@ -235,23 +286,23 @@ static void print_reg(__u64 id)
                crm = (id & KVM_REG_ARM64_SYSREG_CRM_MASK) >> KVM_REG_ARM64_SYSREG_CRM_SHIFT;
                op2 = (id & KVM_REG_ARM64_SYSREG_OP2_MASK) >> KVM_REG_ARM64_SYSREG_OP2_SHIFT;
                TEST_ASSERT(id == ARM64_SYS_REG(op0, op1, crn, crm, op2),
-                           "Unexpected bits set in SYSREG reg id: 0x%llx", id);
+                           "%s: Unexpected bits set in SYSREG reg id: 0x%llx", config_name(c), id);
                printf("\tARM64_SYS_REG(%d, %d, %d, %d, %d),\n", op0, op1, crn, crm, op2);
                break;
        case KVM_REG_ARM_FW:
                TEST_ASSERT(id == KVM_REG_ARM_FW_REG(id & 0xffff),
-                           "Unexpected bits set in FW reg id: 0x%llx", id);
+                           "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id);
                printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff);
                break;
        case KVM_REG_ARM64_SVE:
-               if (reg_list_sve())
-                       printf("\t%s,\n", sve_id_to_str(id));
+               if (has_cap(c, KVM_CAP_ARM_SVE))
+                       printf("\t%s,\n", sve_id_to_str(c, id));
                else
-                       TEST_FAIL("KVM_REG_ARM64_SVE is an unexpected coproc type in reg id: 0x%llx", id);
+                       TEST_FAIL("%s: KVM_REG_ARM64_SVE is an unexpected coproc type in reg id: 0x%llx", config_name(c), id);
                break;
        default:
-               TEST_FAIL("Unexpected coproc type: 0x%llx in reg id: 0x%llx",
-                         (id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT, id);
+               TEST_FAIL("%s: Unexpected coproc type: 0x%llx in reg id: 0x%llx",
+                         config_name(c), (id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT, id);
        }
 }
 
@@ -312,56 +363,58 @@ static void core_reg_fixup(void)
        reg_list = tmp;
 }
 
-static void prepare_vcpu_init(struct kvm_vcpu_init *init)
+static void prepare_vcpu_init(struct vcpu_config *c, struct kvm_vcpu_init *init)
 {
-       if (reg_list_sve())
-               init->features[0] |= 1 << KVM_ARM_VCPU_SVE;
+       struct reg_sublist *s;
+
+       for_each_sublist(c, s)
+               if (s->capability)
+                       init->features[s->feature / 32] |= 1 << (s->feature % 32);
 }
 
-static void finalize_vcpu(struct kvm_vm *vm, uint32_t vcpuid)
+static void finalize_vcpu(struct kvm_vm *vm, uint32_t vcpuid, struct vcpu_config *c)
 {
+       struct reg_sublist *s;
        int feature;
 
-       if (reg_list_sve()) {
-               feature = KVM_ARM_VCPU_SVE;
-               vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_FINALIZE, &feature);
+       for_each_sublist(c, s) {
+               if (s->finalize) {
+                       feature = s->feature;
+                       vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_FINALIZE, &feature);
+               }
        }
 }
 
-static void check_supported(void)
+static void check_supported(struct vcpu_config *c)
 {
-       if (reg_list_sve() && !kvm_check_cap(KVM_CAP_ARM_SVE)) {
-               fprintf(stderr, "SVE not available, skipping tests\n");
-               exit(KSFT_SKIP);
+       struct reg_sublist *s;
+
+       for_each_sublist(c, s) {
+               if (s->capability && !kvm_check_cap(s->capability)) {
+                       fprintf(stderr, "%s: %s not available, skipping tests\n", config_name(c), s->name);
+                       exit(KSFT_SKIP);
+               }
        }
 }
 
-int main(int ac, char **av)
+static bool print_list;
+static bool print_filtered;
+static bool fixup_core_regs;
+
+static void run_test(struct vcpu_config *c)
 {
        struct kvm_vcpu_init init = { .target = -1, };
-       int new_regs = 0, missing_regs = 0, i;
+       int new_regs = 0, missing_regs = 0, i, n;
        int failed_get = 0, failed_set = 0, failed_reject = 0;
-       bool print_list = false, print_filtered = false, fixup_core_regs = false;
        struct kvm_vm *vm;
-       __u64 *vec_regs;
+       struct reg_sublist *s;
 
-       check_supported();
-
-       for (i = 1; i < ac; ++i) {
-               if (strcmp(av[i], "--core-reg-fixup") == 0)
-                       fixup_core_regs = true;
-               else if (strcmp(av[i], "--list") == 0)
-                       print_list = true;
-               else if (strcmp(av[i], "--list-filtered") == 0)
-                       print_filtered = true;
-               else
-                       TEST_FAIL("Unknown option: %s\n", av[i]);
-       }
+       check_supported(c);
 
        vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
-       prepare_vcpu_init(&init);
+       prepare_vcpu_init(c, &init);
        aarch64_vcpu_add_default(vm, 0, &init, NULL);
-       finalize_vcpu(vm, 0);
+       finalize_vcpu(vm, 0, c);
 
        reg_list = vcpu_get_reg_list(vm, 0);
 
@@ -374,10 +427,10 @@ int main(int ac, char **av)
                        __u64 id = reg_list->reg[i];
                        if ((print_list && !filter_reg(id)) ||
                            (print_filtered && filter_reg(id)))
-                               print_reg(id);
+                               print_reg(c, id);
                }
                putchar('\n');
-               return 0;
+               return;
        }
 
        /*
@@ -396,50 +449,52 @@ int main(int ac, char **av)
                        .id = reg_list->reg[i],
                        .addr = (__u64)&addr,
                };
+               bool reject_reg = false;
                int ret;
 
                ret = _vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &reg);
                if (ret) {
-                       puts("Failed to get ");
-                       print_reg(reg.id);
+                       printf("%s: Failed to get ", config_name(c));
+                       print_reg(c, reg.id);
                        putchar('\n');
                        ++failed_get;
                }
 
                /* rejects_set registers are rejected after KVM_ARM_VCPU_FINALIZE */
-               if (find_reg(rejects_set, rejects_set_n, reg.id)) {
-                       ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
-                       if (ret != -1 || errno != EPERM) {
-                               printf("Failed to reject (ret=%d, errno=%d) ", ret, errno);
-                               print_reg(reg.id);
-                               putchar('\n');
-                               ++failed_reject;
+               for_each_sublist(c, s) {
+                       if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) {
+                               reject_reg = true;
+                               ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
+                               if (ret != -1 || errno != EPERM) {
+                                       printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno);
+                                       print_reg(c, reg.id);
+                                       putchar('\n');
+                                       ++failed_reject;
+                               }
+                               break;
                        }
-                       continue;
                }
 
-               ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
-               if (ret) {
-                       puts("Failed to set ");
-                       print_reg(reg.id);
-                       putchar('\n');
-                       ++failed_set;
+               if (!reject_reg) {
+                       ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, &reg);
+                       if (ret) {
+                               printf("%s: Failed to set ", config_name(c));
+                               print_reg(c, reg.id);
+                               putchar('\n');
+                               ++failed_set;
+                       }
                }
        }
 
-       if (reg_list_sve()) {
-               blessed_n = base_regs_n + sve_regs_n;
-               vec_regs = sve_regs;
-       } else {
-               blessed_n = base_regs_n + vregs_n;
-               vec_regs = vregs;
-       }
-
+       for_each_sublist(c, s)
+               blessed_n += s->regs_n;
        blessed_reg = calloc(blessed_n, sizeof(__u64));
-       for (i = 0; i < base_regs_n; ++i)
-               blessed_reg[i] = base_regs[i];
-       for (i = 0; i < blessed_n - base_regs_n; ++i)
-               blessed_reg[base_regs_n + i] = vec_regs[i];
+
+       n = 0;
+       for_each_sublist(c, s) {
+               for (i = 0; i < s->regs_n; ++i)
+                       blessed_reg[n++] = s->regs[i];
+       }
 
        for_each_new_reg(i)
                ++new_regs;
@@ -448,40 +503,141 @@ int main(int ac, char **av)
                ++missing_regs;
 
        if (new_regs || missing_regs) {
-               printf("Number blessed registers: %5lld\n", blessed_n);
-               printf("Number registers:         %5lld\n", reg_list->n);
+               printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n);
+               printf("%s: Number registers:         %5lld\n", config_name(c), reg_list->n);
        }
 
        if (new_regs) {
-               printf("\nThere are %d new registers.\n"
+               printf("\n%s: There are %d new registers.\n"
                       "Consider adding them to the blessed reg "
-                      "list with the following lines:\n\n", new_regs);
+                      "list with the following lines:\n\n", config_name(c), new_regs);
                for_each_new_reg(i)
-                       print_reg(reg_list->reg[i]);
+                       print_reg(c, reg_list->reg[i]);
                putchar('\n');
        }
 
        if (missing_regs) {
-               printf("\nThere are %d missing registers.\n"
-                      "The following lines are missing registers:\n\n", missing_regs);
+               printf("\n%s: There are %d missing registers.\n"
+                      "The following lines are missing registers:\n\n", config_name(c), missing_regs);
                for_each_missing_reg(i)
-                       print_reg(blessed_reg[i]);
+                       print_reg(c, blessed_reg[i]);
                putchar('\n');
        }
 
        TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject,
-                   "There are %d missing registers; "
+                   "%s: There are %d missing registers; "
                    "%d registers failed get; %d registers failed set; %d registers failed reject",
-                   missing_regs, failed_get, failed_set, failed_reject);
+                   config_name(c), missing_regs, failed_get, failed_set, failed_reject);
 
-       return 0;
+       pr_info("%s: PASS\n", config_name(c));
+       blessed_n = 0;
+       free(blessed_reg);
+       free(reg_list);
+       kvm_vm_free(vm);
+}
+
+static void help(void)
+{
+       struct vcpu_config *c;
+       int i;
+
+       printf(
+       "\n"
+       "usage: get-reg-list [--config=<selection>] [--list] [--list-filtered] [--core-reg-fixup]\n\n"
+       " --config=<selection>        Used to select a specific vcpu configuration for the test/listing\n"
+       "                             '<selection>' may be\n");
+
+       for (i = 0; i < vcpu_configs_n; ++i) {
+               c = vcpu_configs[i];
+               printf(
+       "                               '%s'\n", config_name(c));
+       }
+
+       printf(
+       "\n"
+       " --list                      Print the register list rather than test it (requires --config)\n"
+       " --list-filtered             Print registers that would normally be filtered out (requires --config)\n"
+       " --core-reg-fixup            Needed when running on old kernels with broken core reg listings\n"
+       "\n"
+       );
+}
+
+static struct vcpu_config *parse_config(const char *config)
+{
+       struct vcpu_config *c;
+       int i;
+
+       if (config[8] != '=')
+               help(), exit(1);
+
+       for (i = 0; i < vcpu_configs_n; ++i) {
+               c = vcpu_configs[i];
+               if (strcmp(config_name(c), &config[9]) == 0)
+                       break;
+       }
+
+       if (i == vcpu_configs_n)
+               help(), exit(1);
+
+       return c;
+}
+
+int main(int ac, char **av)
+{
+       struct vcpu_config *c, *sel = NULL;
+       int i, ret = 0;
+       pid_t pid;
+
+       for (i = 1; i < ac; ++i) {
+               if (strcmp(av[i], "--core-reg-fixup") == 0)
+                       fixup_core_regs = true;
+               else if (strncmp(av[i], "--config", 8) == 0)
+                       sel = parse_config(av[i]);
+               else if (strcmp(av[i], "--list") == 0)
+                       print_list = true;
+               else if (strcmp(av[i], "--list-filtered") == 0)
+                       print_filtered = true;
+               else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0)
+                       help(), exit(0);
+               else
+                       help(), exit(1);
+       }
+
+       if (print_list || print_filtered) {
+               /*
+                * We only want to print the register list of a single config.
+                */
+               if (!sel)
+                       help(), exit(1);
+       }
+
+       for (i = 0; i < vcpu_configs_n; ++i) {
+               c = vcpu_configs[i];
+               if (sel && c != sel)
+                       continue;
+
+               pid = fork();
+
+               if (!pid) {
+                       run_test(c);
+                       exit(0);
+               } else {
+                       int wstatus;
+                       pid_t wpid = wait(&wstatus);
+                       TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return");
+                       if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP)
+                               ret = KSFT_FAIL;
+               }
+       }
+
+       return ret;
 }
 
 /*
  * The current blessed list was primed with the output of kernel version
  * v4.15 with --core-reg-fixup and then later updated with new registers.
  *
- * The blessed list is up to date with kernel version v5.10-rc5
+ * The blessed list is up to date with kernel version v5.13-rc3
  */
 static __u64 base_regs[] = {
        KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(regs.regs[0]),
@@ -673,8 +829,6 @@ static __u64 base_regs[] = {
        ARM64_SYS_REG(3, 0, 5, 2, 0),   /* ESR_EL1 */
        ARM64_SYS_REG(3, 0, 6, 0, 0),   /* FAR_EL1 */
        ARM64_SYS_REG(3, 0, 7, 4, 0),   /* PAR_EL1 */
-       ARM64_SYS_REG(3, 0, 9, 14, 1),  /* PMINTENSET_EL1 */
-       ARM64_SYS_REG(3, 0, 9, 14, 2),  /* PMINTENCLR_EL1 */
        ARM64_SYS_REG(3, 0, 10, 2, 0),  /* MAIR_EL1 */
        ARM64_SYS_REG(3, 0, 10, 3, 0),  /* AMAIR_EL1 */
        ARM64_SYS_REG(3, 0, 12, 0, 0),  /* VBAR_EL1 */
@@ -683,6 +837,16 @@ static __u64 base_regs[] = {
        ARM64_SYS_REG(3, 0, 13, 0, 4),  /* TPIDR_EL1 */
        ARM64_SYS_REG(3, 0, 14, 1, 0),  /* CNTKCTL_EL1 */
        ARM64_SYS_REG(3, 2, 0, 0, 0),   /* CSSELR_EL1 */
+       ARM64_SYS_REG(3, 3, 13, 0, 2),  /* TPIDR_EL0 */
+       ARM64_SYS_REG(3, 3, 13, 0, 3),  /* TPIDRRO_EL0 */
+       ARM64_SYS_REG(3, 4, 3, 0, 0),   /* DACR32_EL2 */
+       ARM64_SYS_REG(3, 4, 5, 0, 1),   /* IFSR32_EL2 */
+       ARM64_SYS_REG(3, 4, 5, 3, 0),   /* FPEXC32_EL2 */
+};
+
+static __u64 pmu_regs[] = {
+       ARM64_SYS_REG(3, 0, 9, 14, 1),  /* PMINTENSET_EL1 */
+       ARM64_SYS_REG(3, 0, 9, 14, 2),  /* PMINTENCLR_EL1 */
        ARM64_SYS_REG(3, 3, 9, 12, 0),  /* PMCR_EL0 */
        ARM64_SYS_REG(3, 3, 9, 12, 1),  /* PMCNTENSET_EL0 */
        ARM64_SYS_REG(3, 3, 9, 12, 2),  /* PMCNTENCLR_EL0 */
@@ -692,8 +856,6 @@ static __u64 base_regs[] = {
        ARM64_SYS_REG(3, 3, 9, 13, 0),  /* PMCCNTR_EL0 */
        ARM64_SYS_REG(3, 3, 9, 14, 0),  /* PMUSERENR_EL0 */
        ARM64_SYS_REG(3, 3, 9, 14, 3),  /* PMOVSSET_EL0 */
-       ARM64_SYS_REG(3, 3, 13, 0, 2),  /* TPIDR_EL0 */
-       ARM64_SYS_REG(3, 3, 13, 0, 3),  /* TPIDRRO_EL0 */
        ARM64_SYS_REG(3, 3, 14, 8, 0),
        ARM64_SYS_REG(3, 3, 14, 8, 1),
        ARM64_SYS_REG(3, 3, 14, 8, 2),
@@ -757,11 +919,7 @@ static __u64 base_regs[] = {
        ARM64_SYS_REG(3, 3, 14, 15, 5),
        ARM64_SYS_REG(3, 3, 14, 15, 6),
        ARM64_SYS_REG(3, 3, 14, 15, 7), /* PMCCFILTR_EL0 */
-       ARM64_SYS_REG(3, 4, 3, 0, 0),   /* DACR32_EL2 */
-       ARM64_SYS_REG(3, 4, 5, 0, 1),   /* IFSR32_EL2 */
-       ARM64_SYS_REG(3, 4, 5, 3, 0),   /* FPEXC32_EL2 */
 };
-static __u64 base_regs_n = ARRAY_SIZE(base_regs);
 
 static __u64 vregs[] = {
        KVM_REG_ARM64 | KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]),
@@ -797,7 +955,6 @@ static __u64 vregs[] = {
        KVM_REG_ARM64 | KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(fp_regs.vregs[30]),
        KVM_REG_ARM64 | KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]),
 };
-static __u64 vregs_n = ARRAY_SIZE(vregs);
 
 static __u64 sve_regs[] = {
        KVM_REG_ARM64_SVE_VLS,
@@ -852,11 +1009,57 @@ static __u64 sve_regs[] = {
        KVM_REG_ARM64_SVE_FFR(0),
        ARM64_SYS_REG(3, 0, 1, 2, 0),   /* ZCR_EL1 */
 };
-static __u64 sve_regs_n = ARRAY_SIZE(sve_regs);
 
-static __u64 rejects_set[] = {
-#ifdef REG_LIST_SVE
+static __u64 sve_rejects_set[] = {
        KVM_REG_ARM64_SVE_VLS,
-#endif
 };
-static __u64 rejects_set_n = ARRAY_SIZE(rejects_set);
+
+#define BASE_SUBLIST \
+       { "base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), }
+#define VREGS_SUBLIST \
+       { "vregs", .regs = vregs, .regs_n = ARRAY_SIZE(vregs), }
+#define PMU_SUBLIST \
+       { "pmu", .regs = pmu_regs, .regs_n = ARRAY_SIZE(pmu_regs), }
+#define SVE_SUBLIST \
+       { "sve", .capability = KVM_CAP_ARM_SVE, .feature = KVM_ARM_VCPU_SVE, .finalize = true, \
+         .regs = sve_regs, .regs_n = ARRAY_SIZE(sve_regs), \
+         .rejects_set = sve_rejects_set, .rejects_set_n = ARRAY_SIZE(sve_rejects_set), }
+
+static struct vcpu_config vregs_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       VREGS_SUBLIST,
+       {0},
+       },
+};
+static struct vcpu_config vregs_pmu_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       VREGS_SUBLIST,
+       PMU_SUBLIST,
+       {0},
+       },
+};
+static struct vcpu_config sve_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       SVE_SUBLIST,
+       {0},
+       },
+};
+static struct vcpu_config sve_pmu_config = {
+       .sublists = {
+       BASE_SUBLIST,
+       SVE_SUBLIST,
+       PMU_SUBLIST,
+       {0},
+       },
+};
+
+static struct vcpu_config *vcpu_configs[] = {
+       &vregs_config,
+       &vregs_pmu_config,
+       &sve_config,
+       &sve_pmu_config,
+};
+static int vcpu_configs_n = ARRAY_SIZE(vcpu_configs);
index 81edbd2..5fe0140 100644 (file)
@@ -16,7 +16,6 @@
 #include <errno.h>
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
-#include <asm/barrier.h>
 #include <linux/atomic.h>
 
 #include "kvm_util.h"
@@ -681,7 +680,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid,
        pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode));
 
        vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
-       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       kvm_vm_elf_load(vm, program_invocation_name);
 #ifdef __x86_64__
        vm_create_irqchip(vm);
 #endif
@@ -761,7 +760,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
                                    KVM_MEM_LOG_DIRTY_PAGES);
 
        /* Do mapping for the dirty track memory slot */
-       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages, 0);
+       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
 
        /* Cache the HVA pointer of the region */
        host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_phys_mem);
index 4b8db3b..b21c69a 100644 (file)
@@ -105,7 +105,7 @@ static void run_test(uint32_t run)
                CPU_SET(i, &cpu_set);
 
        vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
-       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       kvm_vm_elf_load(vm, program_invocation_name);
        vm_create_irqchip(vm);
 
        pr_debug("%s: [%d] start vcpus\n", __func__, run);
index b7fa0c8..27dc5c2 100644 (file)
@@ -8,16 +8,20 @@
 #define SELFTEST_KVM_PROCESSOR_H
 
 #include "kvm_util.h"
+#include <linux/stringify.h>
 
 
 #define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
                           KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x))
 
-#define CPACR_EL1      3, 0,  1, 0, 2
-#define TCR_EL1                3, 0,  2, 0, 2
-#define MAIR_EL1       3, 0, 10, 2, 0
-#define TTBR0_EL1      3, 0,  2, 0, 0
-#define SCTLR_EL1      3, 0,  1, 0, 0
+#define CPACR_EL1               3, 0,  1, 0, 2
+#define TCR_EL1                 3, 0,  2, 0, 2
+#define MAIR_EL1                3, 0, 10, 2, 0
+#define TTBR0_EL1               3, 0,  2, 0, 0
+#define SCTLR_EL1               3, 0,  1, 0, 0
+#define VBAR_EL1                3, 0, 12, 0, 0
+
+#define ID_AA64DFR0_EL1         3, 0,  0, 5, 0
 
 /*
  * Default MAIR
@@ -56,4 +60,73 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, int vcpuid, struct kvm_vcpu_init *ini
 void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid,
                              struct kvm_vcpu_init *init, void *guest_code);
 
+struct ex_regs {
+       u64 regs[31];
+       u64 sp;
+       u64 pc;
+       u64 pstate;
+};
+
+#define VECTOR_NUM     16
+
+enum {
+       VECTOR_SYNC_CURRENT_SP0,
+       VECTOR_IRQ_CURRENT_SP0,
+       VECTOR_FIQ_CURRENT_SP0,
+       VECTOR_ERROR_CURRENT_SP0,
+
+       VECTOR_SYNC_CURRENT,
+       VECTOR_IRQ_CURRENT,
+       VECTOR_FIQ_CURRENT,
+       VECTOR_ERROR_CURRENT,
+
+       VECTOR_SYNC_LOWER_64,
+       VECTOR_IRQ_LOWER_64,
+       VECTOR_FIQ_LOWER_64,
+       VECTOR_ERROR_LOWER_64,
+
+       VECTOR_SYNC_LOWER_32,
+       VECTOR_IRQ_LOWER_32,
+       VECTOR_FIQ_LOWER_32,
+       VECTOR_ERROR_LOWER_32,
+};
+
+#define VECTOR_IS_SYNC(v) ((v) == VECTOR_SYNC_CURRENT_SP0 || \
+                          (v) == VECTOR_SYNC_CURRENT     || \
+                          (v) == VECTOR_SYNC_LOWER_64    || \
+                          (v) == VECTOR_SYNC_LOWER_32)
+
+#define ESR_EC_NUM             64
+#define ESR_EC_SHIFT           26
+#define ESR_EC_MASK            (ESR_EC_NUM - 1)
+
+#define ESR_EC_SVC64           0x15
+#define ESR_EC_HW_BP_CURRENT   0x31
+#define ESR_EC_SSTEP_CURRENT   0x33
+#define ESR_EC_WP_CURRENT      0x35
+#define ESR_EC_BRK_INS         0x3c
+
+void vm_init_descriptor_tables(struct kvm_vm *vm);
+void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
+
+typedef void(*handler_fn)(struct ex_regs *);
+void vm_install_exception_handler(struct kvm_vm *vm,
+               int vector, handler_fn handler);
+void vm_install_sync_handler(struct kvm_vm *vm,
+               int vector, int ec, handler_fn handler);
+
+#define write_sysreg(reg, val)                                           \
+({                                                                       \
+       u64 __val = (u64)(val);                                           \
+       asm volatile("msr " __stringify(reg) ", %x0" : : "rZ" (__val));   \
+})
+
+#define read_sysreg(reg)                                                 \
+({     u64 val;                                                          \
+       asm volatile("mrs %0, "__stringify(reg) : "=r"(val) : : "memory");\
+       val;                                                              \
+})
+
+#define isb()  asm volatile("isb" : : : "memory")
+
 #endif /* SELFTEST_KVM_PROCESSOR_H */
index 3573956..615ab25 100644 (file)
@@ -30,6 +30,7 @@ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */
 
 /* Minimum allocated guest virtual and physical addresses */
 #define KVM_UTIL_MIN_VADDR             0x2000
+#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000
 
 #define DEFAULT_GUEST_PHY_PAGES                512
 #define DEFAULT_GUEST_STACK_VADDR_MIN  0xab6000
@@ -98,8 +99,7 @@ uint32_t kvm_vm_reset_dirty_ring(struct kvm_vm *vm);
 int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva,
                       size_t len);
 
-void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
-                    uint32_t data_memslot, uint32_t pgd_memslot);
+void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename);
 
 void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent);
 
@@ -141,10 +141,12 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
 void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
 void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot);
 void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid);
-vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
-                         uint32_t data_memslot, uint32_t pgd_memslot);
+vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min);
+vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages);
+vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm);
+
 void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-             unsigned int npages, uint32_t pgd_memslot);
+             unsigned int npages);
 void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa);
 void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva);
 vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva);
@@ -237,7 +239,7 @@ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
 
 const char *exit_reason_str(unsigned int exit_reason);
 
-void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot);
+void virt_pgd_alloc(struct kvm_vm *vm);
 
 /*
  * VM Virtual Page Map
@@ -255,13 +257,13 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot);
  * Within @vm, creates a virtual translation for the page starting
  * at @vaddr to the page starting at @paddr.
  */
-void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-                uint32_t memslot);
+void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr);
 
 vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
                             uint32_t memslot);
 vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
                              vm_paddr_t paddr_min, uint32_t memslot);
+vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm);
 
 /*
  * Create a VM with reasonable defaults
@@ -351,6 +353,7 @@ enum {
        UCALL_SYNC,
        UCALL_ABORT,
        UCALL_DONE,
+       UCALL_UNHANDLED,
 };
 
 #define UCALL_MAX_ARGS 6
@@ -369,26 +372,31 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc);
                                ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4)
 #define GUEST_SYNC(stage)      ucall(UCALL_SYNC, 2, "hello", stage)
 #define GUEST_DONE()           ucall(UCALL_DONE, 0)
-#define __GUEST_ASSERT(_condition, _nargs, _args...) do {      \
-       if (!(_condition))                                      \
-               ucall(UCALL_ABORT, 2 + _nargs,                  \
-                       "Failed guest assert: "                 \
-                       #_condition, __LINE__, _args);          \
+#define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) do {    \
+       if (!(_condition))                                              \
+               ucall(UCALL_ABORT, 2 + _nargs,                          \
+                       "Failed guest assert: "                         \
+                       _condstr, __LINE__, _args);                     \
 } while (0)
 
 #define GUEST_ASSERT(_condition) \
-       __GUEST_ASSERT((_condition), 0, 0)
+       __GUEST_ASSERT(_condition, #_condition, 0, 0)
 
 #define GUEST_ASSERT_1(_condition, arg1) \
-       __GUEST_ASSERT((_condition), 1, (arg1))
+       __GUEST_ASSERT(_condition, #_condition, 1, (arg1))
 
 #define GUEST_ASSERT_2(_condition, arg1, arg2) \
-       __GUEST_ASSERT((_condition), 2, (arg1), (arg2))
+       __GUEST_ASSERT(_condition, #_condition, 2, (arg1), (arg2))
 
 #define GUEST_ASSERT_3(_condition, arg1, arg2, arg3) \
-       __GUEST_ASSERT((_condition), 3, (arg1), (arg2), (arg3))
+       __GUEST_ASSERT(_condition, #_condition, 3, (arg1), (arg2), (arg3))
 
 #define GUEST_ASSERT_4(_condition, arg1, arg2, arg3, arg4) \
-       __GUEST_ASSERT((_condition), 4, (arg1), (arg2), (arg3), (arg4))
+       __GUEST_ASSERT(_condition, #_condition, 4, (arg1), (arg2), (arg3), (arg4))
+
+#define GUEST_ASSERT_EQ(a, b) __GUEST_ASSERT((a) == (b), #a " == " #b, 2, a, b)
+
+int vm_get_stats_fd(struct kvm_vm *vm);
+int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid);
 
 #endif /* SELFTEST_KVM_UTIL_H */
diff --git a/tools/testing/selftests/kvm/include/x86_64/apic.h b/tools/testing/selftests/kvm/include/x86_64/apic.h
new file mode 100644 (file)
index 0000000..0be4757
--- /dev/null
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tools/testing/selftests/kvm/include/x86_64/apic.h
+ *
+ * Copyright (C) 2021, Google LLC.
+ */
+
+#ifndef SELFTEST_KVM_APIC_H
+#define SELFTEST_KVM_APIC_H
+
+#include <stdint.h>
+
+#include "processor.h"
+
+#define APIC_DEFAULT_GPA               0xfee00000ULL
+
+/* APIC base address MSR and fields */
+#define MSR_IA32_APICBASE              0x0000001b
+#define MSR_IA32_APICBASE_BSP          (1<<8)
+#define MSR_IA32_APICBASE_EXTD         (1<<10)
+#define MSR_IA32_APICBASE_ENABLE       (1<<11)
+#define MSR_IA32_APICBASE_BASE         (0xfffff<<12)
+#define                GET_APIC_BASE(x)        (((x) >> 12) << 12)
+
+#define APIC_BASE_MSR  0x800
+#define X2APIC_ENABLE  (1UL << 10)
+#define        APIC_ID         0x20
+#define        APIC_LVR        0x30
+#define                GET_APIC_ID_FIELD(x)    (((x) >> 24) & 0xFF)
+#define        APIC_TASKPRI    0x80
+#define        APIC_PROCPRI    0xA0
+#define        APIC_EOI        0xB0
+#define        APIC_SPIV       0xF0
+#define                APIC_SPIV_FOCUS_DISABLED        (1 << 9)
+#define                APIC_SPIV_APIC_ENABLED          (1 << 8)
+#define        APIC_ICR        0x300
+#define                APIC_DEST_SELF          0x40000
+#define                APIC_DEST_ALLINC        0x80000
+#define                APIC_DEST_ALLBUT        0xC0000
+#define                APIC_ICR_RR_MASK        0x30000
+#define                APIC_ICR_RR_INVALID     0x00000
+#define                APIC_ICR_RR_INPROG      0x10000
+#define                APIC_ICR_RR_VALID       0x20000
+#define                APIC_INT_LEVELTRIG      0x08000
+#define                APIC_INT_ASSERT         0x04000
+#define                APIC_ICR_BUSY           0x01000
+#define                APIC_DEST_LOGICAL       0x00800
+#define                APIC_DEST_PHYSICAL      0x00000
+#define                APIC_DM_FIXED           0x00000
+#define                APIC_DM_FIXED_MASK      0x00700
+#define                APIC_DM_LOWEST          0x00100
+#define                APIC_DM_SMI             0x00200
+#define                APIC_DM_REMRD           0x00300
+#define                APIC_DM_NMI             0x00400
+#define                APIC_DM_INIT            0x00500
+#define                APIC_DM_STARTUP         0x00600
+#define                APIC_DM_EXTINT          0x00700
+#define                APIC_VECTOR_MASK        0x000FF
+#define        APIC_ICR2       0x310
+#define                SET_APIC_DEST_FIELD(x)  ((x) << 24)
+
+void apic_disable(void);
+void xapic_enable(void);
+void x2apic_enable(void);
+
+static inline uint32_t get_bsp_flag(void)
+{
+       return rdmsr(MSR_IA32_APICBASE) & MSR_IA32_APICBASE_BSP;
+}
+
+static inline uint32_t xapic_read_reg(unsigned int reg)
+{
+       return ((volatile uint32_t *)APIC_DEFAULT_GPA)[reg >> 2];
+}
+
+static inline void xapic_write_reg(unsigned int reg, uint32_t val)
+{
+       ((volatile uint32_t *)APIC_DEFAULT_GPA)[reg >> 2] = val;
+}
+
+static inline uint64_t x2apic_read_reg(unsigned int reg)
+{
+       return rdmsr(APIC_BASE_MSR + (reg >> 4));
+}
+
+static inline void x2apic_write_reg(unsigned int reg, uint64_t value)
+{
+       wrmsr(APIC_BASE_MSR + (reg >> 4), value);
+}
+
+#endif /* SELFTEST_KVM_APIC_H */
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * tools/testing/selftests/kvm/include/vmx.h
+ * tools/testing/selftests/kvm/include/x86_64/evmcs.h
  *
  * Copyright (C) 2018, Red Hat, Inc.
  *
diff --git a/tools/testing/selftests/kvm/include/x86_64/hyperv.h b/tools/testing/selftests/kvm/include/x86_64/hyperv.h
new file mode 100644 (file)
index 0000000..412eaee
--- /dev/null
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * tools/testing/selftests/kvm/include/x86_64/hyperv.h
+ *
+ * Copyright (C) 2021, Red Hat, Inc.
+ *
+ */
+
+#ifndef SELFTEST_KVM_HYPERV_H
+#define SELFTEST_KVM_HYPERV_H
+
+#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS  0x40000000
+#define HYPERV_CPUID_INTERFACE                 0x40000001
+#define HYPERV_CPUID_VERSION                   0x40000002
+#define HYPERV_CPUID_FEATURES                  0x40000003
+#define HYPERV_CPUID_ENLIGHTMENT_INFO          0x40000004
+#define HYPERV_CPUID_IMPLEMENT_LIMITS          0x40000005
+#define HYPERV_CPUID_CPU_MANAGEMENT_FEATURES   0x40000007
+#define HYPERV_CPUID_NESTED_FEATURES           0x4000000A
+#define HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS   0x40000080
+#define HYPERV_CPUID_SYNDBG_INTERFACE                  0x40000081
+#define HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES      0x40000082
+
+#define HV_X64_MSR_GUEST_OS_ID                 0x40000000
+#define HV_X64_MSR_HYPERCALL                   0x40000001
+#define HV_X64_MSR_VP_INDEX                    0x40000002
+#define HV_X64_MSR_RESET                       0x40000003
+#define HV_X64_MSR_VP_RUNTIME                  0x40000010
+#define HV_X64_MSR_TIME_REF_COUNT              0x40000020
+#define HV_X64_MSR_REFERENCE_TSC               0x40000021
+#define HV_X64_MSR_TSC_FREQUENCY               0x40000022
+#define HV_X64_MSR_APIC_FREQUENCY              0x40000023
+#define HV_X64_MSR_EOI                         0x40000070
+#define HV_X64_MSR_ICR                         0x40000071
+#define HV_X64_MSR_TPR                         0x40000072
+#define HV_X64_MSR_VP_ASSIST_PAGE              0x40000073
+#define HV_X64_MSR_SCONTROL                    0x40000080
+#define HV_X64_MSR_SVERSION                    0x40000081
+#define HV_X64_MSR_SIEFP                       0x40000082
+#define HV_X64_MSR_SIMP                                0x40000083
+#define HV_X64_MSR_EOM                         0x40000084
+#define HV_X64_MSR_SINT0                       0x40000090
+#define HV_X64_MSR_SINT1                       0x40000091
+#define HV_X64_MSR_SINT2                       0x40000092
+#define HV_X64_MSR_SINT3                       0x40000093
+#define HV_X64_MSR_SINT4                       0x40000094
+#define HV_X64_MSR_SINT5                       0x40000095
+#define HV_X64_MSR_SINT6                       0x40000096
+#define HV_X64_MSR_SINT7                       0x40000097
+#define HV_X64_MSR_SINT8                       0x40000098
+#define HV_X64_MSR_SINT9                       0x40000099
+#define HV_X64_MSR_SINT10                      0x4000009A
+#define HV_X64_MSR_SINT11                      0x4000009B
+#define HV_X64_MSR_SINT12                      0x4000009C
+#define HV_X64_MSR_SINT13                      0x4000009D
+#define HV_X64_MSR_SINT14                      0x4000009E
+#define HV_X64_MSR_SINT15                      0x4000009F
+#define HV_X64_MSR_STIMER0_CONFIG              0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT               0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG              0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT               0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG              0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT               0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG              0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT               0x400000B7
+#define HV_X64_MSR_GUEST_IDLE                  0x400000F0
+#define HV_X64_MSR_CRASH_P0                    0x40000100
+#define HV_X64_MSR_CRASH_P1                    0x40000101
+#define HV_X64_MSR_CRASH_P2                    0x40000102
+#define HV_X64_MSR_CRASH_P3                    0x40000103
+#define HV_X64_MSR_CRASH_P4                    0x40000104
+#define HV_X64_MSR_CRASH_CTL                   0x40000105
+#define HV_X64_MSR_REENLIGHTENMENT_CONTROL     0x40000106
+#define HV_X64_MSR_TSC_EMULATION_CONTROL       0x40000107
+#define HV_X64_MSR_TSC_EMULATION_STATUS                0x40000108
+#define HV_X64_MSR_TSC_INVARIANT_CONTROL       0x40000118
+
+#define HV_X64_MSR_SYNDBG_CONTROL              0x400000F1
+#define HV_X64_MSR_SYNDBG_STATUS               0x400000F2
+#define HV_X64_MSR_SYNDBG_SEND_BUFFER          0x400000F3
+#define HV_X64_MSR_SYNDBG_RECV_BUFFER          0x400000F4
+#define HV_X64_MSR_SYNDBG_PENDING_BUFFER       0x400000F5
+#define HV_X64_MSR_SYNDBG_OPTIONS              0x400000FF
+
+/* HYPERV_CPUID_FEATURES.EAX */
+#define HV_MSR_VP_RUNTIME_AVAILABLE            BIT(0)
+#define HV_MSR_TIME_REF_COUNT_AVAILABLE                BIT(1)
+#define HV_MSR_SYNIC_AVAILABLE                 BIT(2)
+#define HV_MSR_SYNTIMER_AVAILABLE              BIT(3)
+#define HV_MSR_APIC_ACCESS_AVAILABLE           BIT(4)
+#define HV_MSR_HYPERCALL_AVAILABLE             BIT(5)
+#define HV_MSR_VP_INDEX_AVAILABLE              BIT(6)
+#define HV_MSR_RESET_AVAILABLE                 BIT(7)
+#define HV_MSR_STAT_PAGES_AVAILABLE            BIT(8)
+#define HV_MSR_REFERENCE_TSC_AVAILABLE         BIT(9)
+#define HV_MSR_GUEST_IDLE_AVAILABLE            BIT(10)
+#define HV_ACCESS_FREQUENCY_MSRS               BIT(11)
+#define HV_ACCESS_REENLIGHTENMENT              BIT(13)
+#define HV_ACCESS_TSC_INVARIANT                        BIT(15)
+
+/* HYPERV_CPUID_FEATURES.EBX */
+#define HV_CREATE_PARTITIONS                   BIT(0)
+#define HV_ACCESS_PARTITION_ID                 BIT(1)
+#define HV_ACCESS_MEMORY_POOL                  BIT(2)
+#define HV_ADJUST_MESSAGE_BUFFERS              BIT(3)
+#define HV_POST_MESSAGES                       BIT(4)
+#define HV_SIGNAL_EVENTS                       BIT(5)
+#define HV_CREATE_PORT                         BIT(6)
+#define HV_CONNECT_PORT                                BIT(7)
+#define HV_ACCESS_STATS                                BIT(8)
+#define HV_DEBUGGING                           BIT(11)
+#define HV_CPU_MANAGEMENT                      BIT(12)
+#define HV_ISOLATION                           BIT(22)
+
+/* HYPERV_CPUID_FEATURES.EDX */
+#define HV_X64_MWAIT_AVAILABLE                         BIT(0)
+#define HV_X64_GUEST_DEBUGGING_AVAILABLE               BIT(1)
+#define HV_X64_PERF_MONITOR_AVAILABLE                  BIT(2)
+#define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE      BIT(3)
+#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          BIT(4)
+#define HV_X64_GUEST_IDLE_STATE_AVAILABLE              BIT(5)
+#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE            BIT(8)
+#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE           BIT(10)
+#define HV_FEATURE_DEBUG_MSRS_AVAILABLE                        BIT(11)
+#define HV_STIMER_DIRECT_MODE_AVAILABLE                        BIT(19)
+
+/* HYPERV_CPUID_ENLIGHTMENT_INFO.EAX */
+#define HV_X64_AS_SWITCH_RECOMMENDED                   BIT(0)
+#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED             BIT(1)
+#define HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED            BIT(2)
+#define HV_X64_APIC_ACCESS_RECOMMENDED                 BIT(3)
+#define HV_X64_SYSTEM_RESET_RECOMMENDED                        BIT(4)
+#define HV_X64_RELAXED_TIMING_RECOMMENDED              BIT(5)
+#define HV_DEPRECATING_AEOI_RECOMMENDED                        BIT(9)
+#define HV_X64_CLUSTER_IPI_RECOMMENDED                 BIT(10)
+#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED          BIT(11)
+#define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED            BIT(14)
+
+/* HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX */
+#define HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING       BIT(1)
+
+/* Hypercalls */
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE     0x0002
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST      0x0003
+#define HVCALL_NOTIFY_LONG_SPIN_WAIT           0x0008
+#define HVCALL_SEND_IPI                                0x000b
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX  0x0013
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX   0x0014
+#define HVCALL_SEND_IPI_EX                     0x0015
+#define HVCALL_GET_PARTITION_ID                        0x0046
+#define HVCALL_DEPOSIT_MEMORY                  0x0048
+#define HVCALL_CREATE_VP                       0x004e
+#define HVCALL_GET_VP_REGISTERS                        0x0050
+#define HVCALL_SET_VP_REGISTERS                        0x0051
+#define HVCALL_POST_MESSAGE                    0x005c
+#define HVCALL_SIGNAL_EVENT                    0x005d
+#define HVCALL_POST_DEBUG_DATA                 0x0069
+#define HVCALL_RETRIEVE_DEBUG_DATA             0x006a
+#define HVCALL_RESET_DEBUG_SESSION             0x006b
+#define HVCALL_ADD_LOGICAL_PROCESSOR           0x0076
+#define HVCALL_MAP_DEVICE_INTERRUPT            0x007c
+#define HVCALL_UNMAP_DEVICE_INTERRUPT          0x007d
+#define HVCALL_RETARGET_INTERRUPT              0x007e
+#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
+#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
+
+#define HV_FLUSH_ALL_PROCESSORS                        BIT(0)
+#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES    BIT(1)
+#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY      BIT(2)
+#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT     BIT(3)
+
+/* hypercall status code */
+#define HV_STATUS_SUCCESS                      0
+#define HV_STATUS_INVALID_HYPERCALL_CODE       2
+#define HV_STATUS_INVALID_HYPERCALL_INPUT      3
+#define HV_STATUS_INVALID_ALIGNMENT            4
+#define HV_STATUS_INVALID_PARAMETER            5
+#define HV_STATUS_ACCESS_DENIED                        6
+#define HV_STATUS_OPERATION_DENIED             8
+#define HV_STATUS_INSUFFICIENT_MEMORY          11
+#define HV_STATUS_INVALID_PORT_ID              17
+#define HV_STATUS_INVALID_CONNECTION_ID                18
+#define HV_STATUS_INSUFFICIENT_BUFFERS         19
+
+#endif /* !SELFTEST_KVM_HYPERV_H */
index 0b30b4e..242ae8e 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <asm/msr-index.h>
 
+#include "../kvm_util.h"
+
 #define X86_EFLAGS_FIXED        (1u << 1)
 
 #define X86_CR4_VME            (1ul << 0)
@@ -53,7 +55,8 @@
 #define CPUID_PKU              (1ul << 3)
 #define CPUID_LA57             (1ul << 16)
 
-#define UNEXPECTED_VECTOR_PORT 0xfff0u
+/* CPUID.0x8000_0001.EDX */
+#define CPUID_GBPAGES          (1ul << 26)
 
 /* General Registers in 64-Bit Mode */
 struct gpr64_regs {
@@ -391,9 +394,13 @@ struct ex_regs {
 
 void vm_init_descriptor_tables(struct kvm_vm *vm);
 void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
-void vm_handle_exception(struct kvm_vm *vm, int vector,
+void vm_install_exception_handler(struct kvm_vm *vm, int vector,
                        void (*handler)(struct ex_regs *));
 
+uint64_t vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr);
+void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr,
+                            uint64_t pte);
+
 /*
  * set_cpuid() - overwrites a matching cpuid entry with the provided value.
  *              matches based on ent->function && ent->index. returns true
@@ -410,6 +417,14 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void);
 void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
 struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
 
+enum x86_page_size {
+       X86_PAGE_SIZE_4K = 0,
+       X86_PAGE_SIZE_2M,
+       X86_PAGE_SIZE_1G,
+};
+void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
+                  enum x86_page_size page_size);
+
 /*
  * Basic CPU control in CR0
  */
@@ -425,53 +440,6 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpui
 #define X86_CR0_CD          (1UL<<30) /* Cache Disable */
 #define X86_CR0_PG          (1UL<<31) /* Paging */
 
-#define APIC_DEFAULT_GPA               0xfee00000ULL
-
-/* APIC base address MSR and fields */
-#define MSR_IA32_APICBASE              0x0000001b
-#define MSR_IA32_APICBASE_BSP          (1<<8)
-#define MSR_IA32_APICBASE_EXTD         (1<<10)
-#define MSR_IA32_APICBASE_ENABLE       (1<<11)
-#define MSR_IA32_APICBASE_BASE         (0xfffff<<12)
-#define                GET_APIC_BASE(x)        (((x) >> 12) << 12)
-
-#define APIC_BASE_MSR  0x800
-#define X2APIC_ENABLE  (1UL << 10)
-#define        APIC_ID         0x20
-#define        APIC_LVR        0x30
-#define                GET_APIC_ID_FIELD(x)    (((x) >> 24) & 0xFF)
-#define        APIC_TASKPRI    0x80
-#define        APIC_PROCPRI    0xA0
-#define        APIC_EOI        0xB0
-#define        APIC_SPIV       0xF0
-#define                APIC_SPIV_FOCUS_DISABLED        (1 << 9)
-#define                APIC_SPIV_APIC_ENABLED          (1 << 8)
-#define        APIC_ICR        0x300
-#define                APIC_DEST_SELF          0x40000
-#define                APIC_DEST_ALLINC        0x80000
-#define                APIC_DEST_ALLBUT        0xC0000
-#define                APIC_ICR_RR_MASK        0x30000
-#define                APIC_ICR_RR_INVALID     0x00000
-#define                APIC_ICR_RR_INPROG      0x10000
-#define                APIC_ICR_RR_VALID       0x20000
-#define                APIC_INT_LEVELTRIG      0x08000
-#define                APIC_INT_ASSERT         0x04000
-#define                APIC_ICR_BUSY           0x01000
-#define                APIC_DEST_LOGICAL       0x00800
-#define                APIC_DEST_PHYSICAL      0x00000
-#define                APIC_DM_FIXED           0x00000
-#define                APIC_DM_FIXED_MASK      0x00700
-#define                APIC_DM_LOWEST          0x00100
-#define                APIC_DM_SMI             0x00200
-#define                APIC_DM_REMRD           0x00300
-#define                APIC_DM_NMI             0x00400
-#define                APIC_DM_INIT            0x00500
-#define                APIC_DM_STARTUP         0x00600
-#define                APIC_DM_EXTINT          0x00700
-#define                APIC_VECTOR_MASK        0x000FF
-#define        APIC_ICR2       0x310
-#define                SET_APIC_DEST_FIELD(x)  ((x) << 24)
-
 /* VMX_EPT_VPID_CAP bits */
 #define VMX_EPT_VPID_CAP_AD_BITS       (1ULL << 21)
 
index 65eb107..583ceb0 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <stdint.h>
 #include "processor.h"
+#include "apic.h"
 
 /*
  * Definitions of Primary Processor-Based VM-Execution Controls.
@@ -607,15 +608,13 @@ bool nested_vmx_supported(void);
 void nested_vmx_check_supported(void);
 
 void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-                  uint64_t nested_paddr, uint64_t paddr, uint32_t eptp_memslot);
+                  uint64_t nested_paddr, uint64_t paddr);
 void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-                uint64_t nested_paddr, uint64_t paddr, uint64_t size,
-                uint32_t eptp_memslot);
+                uint64_t nested_paddr, uint64_t paddr, uint64_t size);
 void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm,
-                       uint32_t memslot, uint32_t eptp_memslot);
+                       uint32_t memslot);
 void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm,
                  uint32_t eptp_memslot);
-void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm,
-                                     uint32_t eptp_memslot);
+void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm);
 
 #endif /* SELFTEST_KVM_VMX_H */
diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c
new file mode 100644 (file)
index 0000000..5906bbc
--- /dev/null
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * kvm_binary_stats_test
+ *
+ * Copyright (C) 2021, Google LLC.
+ *
+ * Test the fd-based interface for KVM statistics.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "test_util.h"
+
+#include "kvm_util.h"
+#include "asm/kvm.h"
+#include "linux/kvm.h"
+
+static void stats_test(int stats_fd)
+{
+       ssize_t ret;
+       int i;
+       size_t size_desc;
+       size_t size_data = 0;
+       struct kvm_stats_header *header;
+       char *id;
+       struct kvm_stats_desc *stats_desc;
+       u64 *stats_data;
+       struct kvm_stats_desc *pdesc;
+
+       /* Read kvm stats header */
+       header = malloc(sizeof(*header));
+       TEST_ASSERT(header, "Allocate memory for stats header");
+
+       ret = read(stats_fd, header, sizeof(*header));
+       TEST_ASSERT(ret == sizeof(*header), "Read stats header");
+       size_desc = sizeof(*stats_desc) + header->name_size;
+
+       /* Read kvm stats id string */
+       id = malloc(header->name_size);
+       TEST_ASSERT(id, "Allocate memory for id string");
+       ret = read(stats_fd, id, header->name_size);
+       TEST_ASSERT(ret == header->name_size, "Read id string");
+
+       /* Check id string, that should start with "kvm" */
+       TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header->name_size,
+                               "Invalid KVM stats type, id: %s", id);
+
+       /* Sanity check for other fields in header */
+       if (header->num_desc == 0) {
+               printf("No KVM stats defined!");
+               return;
+       }
+       /* Check overlap */
+       TEST_ASSERT(header->desc_offset > 0 && header->data_offset > 0
+                       && header->desc_offset >= sizeof(*header)
+                       && header->data_offset >= sizeof(*header),
+                       "Invalid offset fields in header");
+       TEST_ASSERT(header->desc_offset > header->data_offset ||
+                       (header->desc_offset + size_desc * header->num_desc <=
+                                                       header->data_offset),
+                       "Descriptor block is overlapped with data block");
+
+       /* Allocate memory for stats descriptors */
+       stats_desc = calloc(header->num_desc, size_desc);
+       TEST_ASSERT(stats_desc, "Allocate memory for stats descriptors");
+       /* Read kvm stats descriptors */
+       ret = pread(stats_fd, stats_desc,
+                       size_desc * header->num_desc, header->desc_offset);
+       TEST_ASSERT(ret == size_desc * header->num_desc,
+                       "Read KVM stats descriptors");
+
+       /* Sanity check for fields in descriptors */
+       for (i = 0; i < header->num_desc; ++i) {
+               pdesc = (void *)stats_desc + i * size_desc;
+               /* Check type,unit,base boundaries */
+               TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK)
+                               <= KVM_STATS_TYPE_MAX, "Unknown KVM stats type");
+               TEST_ASSERT((pdesc->flags & KVM_STATS_UNIT_MASK)
+                               <= KVM_STATS_UNIT_MAX, "Unknown KVM stats unit");
+               TEST_ASSERT((pdesc->flags & KVM_STATS_BASE_MASK)
+                               <= KVM_STATS_BASE_MAX, "Unknown KVM stats base");
+               /* Check exponent for stats unit
+                * Exponent for counter should be greater than or equal to 0
+                * Exponent for unit bytes should be greater than or equal to 0
+                * Exponent for unit seconds should be less than or equal to 0
+                * Exponent for unit clock cycles should be greater than or
+                * equal to 0
+                */
+               switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
+               case KVM_STATS_UNIT_NONE:
+               case KVM_STATS_UNIT_BYTES:
+               case KVM_STATS_UNIT_CYCLES:
+                       TEST_ASSERT(pdesc->exponent >= 0,
+                                       "Unsupported KVM stats unit");
+                       break;
+               case KVM_STATS_UNIT_SECONDS:
+                       TEST_ASSERT(pdesc->exponent <= 0,
+                                       "Unsupported KVM stats unit");
+                       break;
+               }
+               /* Check name string */
+               TEST_ASSERT(strlen(pdesc->name) < header->name_size,
+                               "KVM stats name(%s) too long", pdesc->name);
+               /* Check size field, which should not be zero */
+               TEST_ASSERT(pdesc->size, "KVM descriptor(%s) with size of 0",
+                               pdesc->name);
+               size_data += pdesc->size * sizeof(*stats_data);
+       }
+       /* Check overlap */
+       TEST_ASSERT(header->data_offset >= header->desc_offset
+               || header->data_offset + size_data <= header->desc_offset,
+               "Data block is overlapped with Descriptor block");
+       /* Check validity of all stats data size */
+       TEST_ASSERT(size_data >= header->num_desc * sizeof(*stats_data),
+                       "Data size is not correct");
+       /* Check stats offset */
+       for (i = 0; i < header->num_desc; ++i) {
+               pdesc = (void *)stats_desc + i * size_desc;
+               TEST_ASSERT(pdesc->offset < size_data,
+                       "Invalid offset (%u) for stats: %s",
+                       pdesc->offset, pdesc->name);
+       }
+
+       /* Allocate memory for stats data */
+       stats_data = malloc(size_data);
+       TEST_ASSERT(stats_data, "Allocate memory for stats data");
+       /* Read kvm stats data as a bulk */
+       ret = pread(stats_fd, stats_data, size_data, header->data_offset);
+       TEST_ASSERT(ret == size_data, "Read KVM stats data");
+       /* Read kvm stats data one by one */
+       size_data = 0;
+       for (i = 0; i < header->num_desc; ++i) {
+               pdesc = (void *)stats_desc + i * size_desc;
+               ret = pread(stats_fd, stats_data,
+                               pdesc->size * sizeof(*stats_data),
+                               header->data_offset + size_data);
+               TEST_ASSERT(ret == pdesc->size * sizeof(*stats_data),
+                               "Read data of KVM stats: %s", pdesc->name);
+               size_data += pdesc->size * sizeof(*stats_data);
+       }
+
+       free(stats_data);
+       free(stats_desc);
+       free(id);
+       free(header);
+}
+
+
+static void vm_stats_test(struct kvm_vm *vm)
+{
+       int stats_fd;
+
+       /* Get fd for VM stats */
+       stats_fd = vm_get_stats_fd(vm);
+       TEST_ASSERT(stats_fd >= 0, "Get VM stats fd");
+
+       stats_test(stats_fd);
+       close(stats_fd);
+       TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
+}
+
+static void vcpu_stats_test(struct kvm_vm *vm, int vcpu_id)
+{
+       int stats_fd;
+
+       /* Get fd for VCPU stats */
+       stats_fd = vcpu_get_stats_fd(vm, vcpu_id);
+       TEST_ASSERT(stats_fd >= 0, "Get VCPU stats fd");
+
+       stats_test(stats_fd);
+       close(stats_fd);
+       TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
+}
+
+#define DEFAULT_NUM_VM         4
+#define DEFAULT_NUM_VCPU       4
+
+/*
+ * Usage: kvm_bin_form_stats [#vm] [#vcpu]
+ * The first parameter #vm set the number of VMs being created.
+ * The second parameter #vcpu set the number of VCPUs being created.
+ * By default, DEFAULT_NUM_VM VM and DEFAULT_NUM_VCPU VCPU for the VM would be
+ * created for testing.
+ */
+
+int main(int argc, char *argv[])
+{
+       int i, j;
+       struct kvm_vm **vms;
+       int max_vm = DEFAULT_NUM_VM;
+       int max_vcpu = DEFAULT_NUM_VCPU;
+
+       /* Get the number of VMs and VCPUs that would be created for testing. */
+       if (argc > 1) {
+               max_vm = strtol(argv[1], NULL, 0);
+               if (max_vm <= 0)
+                       max_vm = DEFAULT_NUM_VM;
+       }
+       if (argc > 2) {
+               max_vcpu = strtol(argv[2], NULL, 0);
+               if (max_vcpu <= 0)
+                       max_vcpu = DEFAULT_NUM_VCPU;
+       }
+
+       /* Check the extension for binary stats */
+       if (kvm_check_cap(KVM_CAP_BINARY_STATS_FD) <= 0) {
+               print_skip("Binary form statistics interface is not supported");
+               exit(KSFT_SKIP);
+       }
+
+       /* Create VMs and VCPUs */
+       vms = malloc(sizeof(vms[0]) * max_vm);
+       TEST_ASSERT(vms, "Allocate memory for storing VM pointers");
+       for (i = 0; i < max_vm; ++i) {
+               vms[i] = vm_create(VM_MODE_DEFAULT,
+                               DEFAULT_GUEST_PHY_PAGES, O_RDWR);
+               for (j = 0; j < max_vcpu; ++j)
+                       vm_vcpu_add(vms[i], j);
+       }
+
+       /* Check stats read for every VM and VCPU */
+       for (i = 0; i < max_vm; ++i) {
+               vm_stats_test(vms[i]);
+               for (j = 0; j < max_vcpu; ++j)
+                       vcpu_stats_test(vms[i], j);
+       }
+
+       for (i = 0; i < max_vm; ++i)
+               kvm_vm_free(vms[i]);
+       free(vms);
+       return 0;
+}
index 82171f1..0d04a7d 100644 (file)
@@ -303,7 +303,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
                                    TEST_MEM_SLOT_INDEX, guest_num_pages, 0);
 
        /* Do mapping(GVA->GPA) for the testing memory slot */
-       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages, 0);
+       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
 
        /* Cache the HVA pointer of the region */
        host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_phys_mem);
diff --git a/tools/testing/selftests/kvm/lib/aarch64/handlers.S b/tools/testing/selftests/kvm/lib/aarch64/handlers.S
new file mode 100644 (file)
index 0000000..0e443ea
--- /dev/null
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+.macro save_registers
+       add     sp, sp, #-16 * 17
+
+       stp     x0, x1, [sp, #16 * 0]
+       stp     x2, x3, [sp, #16 * 1]
+       stp     x4, x5, [sp, #16 * 2]
+       stp     x6, x7, [sp, #16 * 3]
+       stp     x8, x9, [sp, #16 * 4]
+       stp     x10, x11, [sp, #16 * 5]
+       stp     x12, x13, [sp, #16 * 6]
+       stp     x14, x15, [sp, #16 * 7]
+       stp     x16, x17, [sp, #16 * 8]
+       stp     x18, x19, [sp, #16 * 9]
+       stp     x20, x21, [sp, #16 * 10]
+       stp     x22, x23, [sp, #16 * 11]
+       stp     x24, x25, [sp, #16 * 12]
+       stp     x26, x27, [sp, #16 * 13]
+       stp     x28, x29, [sp, #16 * 14]
+
+       /*
+        * This stores sp_el1 into ex_regs.sp so exception handlers can "look"
+        * at it. It will _not_ be used to restore the sp on return from the
+        * exception so handlers can not update it.
+        */
+       add     x1, sp, #16 * 17
+       stp     x30, x1, [sp, #16 * 15] /* x30, SP */
+
+       mrs     x1, elr_el1
+       mrs     x2, spsr_el1
+       stp     x1, x2, [sp, #16 * 16] /* PC, PSTATE */
+.endm
+
+.macro restore_registers
+       ldp     x1, x2, [sp, #16 * 16] /* PC, PSTATE */
+       msr     elr_el1, x1
+       msr     spsr_el1, x2
+
+       /* sp is not restored */
+       ldp     x30, xzr, [sp, #16 * 15] /* x30, SP */
+
+       ldp     x28, x29, [sp, #16 * 14]
+       ldp     x26, x27, [sp, #16 * 13]
+       ldp     x24, x25, [sp, #16 * 12]
+       ldp     x22, x23, [sp, #16 * 11]
+       ldp     x20, x21, [sp, #16 * 10]
+       ldp     x18, x19, [sp, #16 * 9]
+       ldp     x16, x17, [sp, #16 * 8]
+       ldp     x14, x15, [sp, #16 * 7]
+       ldp     x12, x13, [sp, #16 * 6]
+       ldp     x10, x11, [sp, #16 * 5]
+       ldp     x8, x9, [sp, #16 * 4]
+       ldp     x6, x7, [sp, #16 * 3]
+       ldp     x4, x5, [sp, #16 * 2]
+       ldp     x2, x3, [sp, #16 * 1]
+       ldp     x0, x1, [sp, #16 * 0]
+
+       add     sp, sp, #16 * 17
+
+       eret
+.endm
+
+.pushsection ".entry.text", "ax"
+.balign 0x800
+.global vectors
+vectors:
+.popsection
+
+.set   vector, 0
+
+/*
+ * Build an exception handler for vector and append a jump to it into
+ * vectors (while making sure that it's 0x80 aligned).
+ */
+.macro HANDLER, label
+handler_\label:
+       save_registers
+       mov     x0, sp
+       mov     x1, #vector
+       bl      route_exception
+       restore_registers
+
+.pushsection ".entry.text", "ax"
+.balign 0x80
+       b       handler_\label
+.popsection
+
+.set   vector, vector + 1
+.endm
+
+.macro HANDLER_INVALID
+.pushsection ".entry.text", "ax"
+.balign 0x80
+/* This will abort so no need to save and restore registers. */
+       mov     x0, #vector
+       mov     x1, #0 /* ec */
+       mov     x2, #0 /* valid_ec */
+       b       kvm_exit_unexpected_exception
+.popsection
+
+.set   vector, vector + 1
+.endm
+
+/*
+ * Caution: be sure to not add anything between the declaration of vectors
+ * above and these macro calls that will build the vectors table below it.
+ */
+       HANDLER_INVALID                         // Synchronous EL1t
+       HANDLER_INVALID                         // IRQ EL1t
+       HANDLER_INVALID                         // FIQ EL1t
+       HANDLER_INVALID                         // Error EL1t
+
+       HANDLER el1h_sync                       // Synchronous EL1h
+       HANDLER el1h_irq                        // IRQ EL1h
+       HANDLER el1h_fiq                        // FIQ EL1h
+       HANDLER el1h_error                      // Error EL1h
+
+       HANDLER el0_sync_64                     // Synchronous 64-bit EL0
+       HANDLER el0_irq_64                      // IRQ 64-bit EL0
+       HANDLER el0_fiq_64                      // FIQ 64-bit EL0
+       HANDLER el0_error_64                    // Error 64-bit EL0
+
+       HANDLER el0_sync_32                     // Synchronous 32-bit EL0
+       HANDLER el0_irq_32                      // IRQ 32-bit EL0
+       HANDLER el0_fiq_32                      // FIQ 32-bit EL0
+       HANDLER el0_error_32                    // Error 32-bit EL0
index cee92d4..9f49f6c 100644 (file)
@@ -6,14 +6,16 @@
  */
 
 #include <linux/compiler.h>
+#include <assert.h>
 
 #include "kvm_util.h"
 #include "../kvm_util_internal.h"
 #include "processor.h"
 
-#define KVM_GUEST_PAGE_TABLE_MIN_PADDR         0x180000
 #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN    0xac0000
 
+static vm_vaddr_t exception_handlers;
+
 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
 {
        return (v + vm->page_size) & ~(vm->page_size - 1);
@@ -72,19 +74,19 @@ static uint64_t __maybe_unused ptrs_per_pte(struct kvm_vm *vm)
        return 1 << (vm->page_shift - 3);
 }
 
-void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot)
+void virt_pgd_alloc(struct kvm_vm *vm)
 {
        if (!vm->pgd_created) {
                vm_paddr_t paddr = vm_phy_pages_alloc(vm,
                        page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size,
-                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
+                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);
                vm->pgd = paddr;
                vm->pgd_created = true;
        }
 }
 
-void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-                 uint32_t pgd_memslot, uint64_t flags)
+static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
+                        uint64_t flags)
 {
        uint8_t attr_idx = flags & 7;
        uint64_t *ptep;
@@ -104,25 +106,19 @@ void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
                paddr, vm->max_gfn, vm->page_size);
 
        ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8;
-       if (!*ptep) {
-               *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
-               *ptep |= 3;
-       }
+       if (!*ptep)
+               *ptep = vm_alloc_page_table(vm) | 3;
 
        switch (vm->pgtable_levels) {
        case 4:
                ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8;
-               if (!*ptep) {
-                       *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
-                       *ptep |= 3;
-               }
+               if (!*ptep)
+                       *ptep = vm_alloc_page_table(vm) | 3;
                /* fall through */
        case 3:
                ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8;
-               if (!*ptep) {
-                       *ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
-                       *ptep |= 3;
-               }
+               if (!*ptep)
+                       *ptep = vm_alloc_page_table(vm) | 3;
                /* fall through */
        case 2:
                ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8;
@@ -135,12 +131,11 @@ void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
        *ptep |= (attr_idx << 2) | (1 << 10) /* Access Flag */;
 }
 
-void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-                uint32_t pgd_memslot)
+void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
 {
        uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */
 
-       _virt_pg_map(vm, vaddr, paddr, pgd_memslot, attr_idx);
+       _virt_pg_map(vm, vaddr, paddr, attr_idx);
 }
 
 vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
@@ -302,7 +297,7 @@ void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid,
                                        DEFAULT_STACK_PGS * vm->page_size :
                                        vm->page_size;
        uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size,
-                                       DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0);
+                                             DEFAULT_ARM64_GUEST_STACK_VADDR_MIN);
 
        vm_vcpu_add(vm, vcpuid);
        aarch64_vcpu_setup(vm, vcpuid, init);
@@ -334,6 +329,100 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...)
        va_end(ap);
 }
 
+void kvm_exit_unexpected_exception(int vector, uint64_t ec, bool valid_ec)
+{
+       ucall(UCALL_UNHANDLED, 3, vector, ec, valid_ec);
+       while (1)
+               ;
+}
+
 void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid)
 {
+       struct ucall uc;
+
+       if (get_ucall(vm, vcpuid, &uc) != UCALL_UNHANDLED)
+               return;
+
+       if (uc.args[2]) /* valid_ec */ {
+               assert(VECTOR_IS_SYNC(uc.args[0]));
+               TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)",
+                         uc.args[0], uc.args[1]);
+       } else {
+               assert(!VECTOR_IS_SYNC(uc.args[0]));
+               TEST_FAIL("Unexpected exception (vector:0x%lx)",
+                         uc.args[0]);
+       }
+}
+
+struct handlers {
+       handler_fn exception_handlers[VECTOR_NUM][ESR_EC_NUM];
+};
+
+void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid)
+{
+       extern char vectors;
+
+       set_reg(vm, vcpuid, ARM64_SYS_REG(VBAR_EL1), (uint64_t)&vectors);
+}
+
+void route_exception(struct ex_regs *regs, int vector)
+{
+       struct handlers *handlers = (struct handlers *)exception_handlers;
+       bool valid_ec;
+       int ec = 0;
+
+       switch (vector) {
+       case VECTOR_SYNC_CURRENT:
+       case VECTOR_SYNC_LOWER_64:
+               ec = (read_sysreg(esr_el1) >> ESR_EC_SHIFT) & ESR_EC_MASK;
+               valid_ec = true;
+               break;
+       case VECTOR_IRQ_CURRENT:
+       case VECTOR_IRQ_LOWER_64:
+       case VECTOR_FIQ_CURRENT:
+       case VECTOR_FIQ_LOWER_64:
+       case VECTOR_ERROR_CURRENT:
+       case VECTOR_ERROR_LOWER_64:
+               ec = 0;
+               valid_ec = false;
+               break;
+       default:
+               valid_ec = false;
+               goto unexpected_exception;
+       }
+
+       if (handlers && handlers->exception_handlers[vector][ec])
+               return handlers->exception_handlers[vector][ec](regs);
+
+unexpected_exception:
+       kvm_exit_unexpected_exception(vector, ec, valid_ec);
+}
+
+void vm_init_descriptor_tables(struct kvm_vm *vm)
+{
+       vm->handlers = vm_vaddr_alloc(vm, sizeof(struct handlers),
+                       vm->page_size, 0, 0);
+
+       *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
+}
+
+void vm_install_sync_handler(struct kvm_vm *vm, int vector, int ec,
+                        void (*handler)(struct ex_regs *))
+{
+       struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
+
+       assert(VECTOR_IS_SYNC(vector));
+       assert(vector < VECTOR_NUM);
+       assert(ec < ESR_EC_NUM);
+       handlers->exception_handlers[vector][ec] = handler;
+}
+
+void vm_install_exception_handler(struct kvm_vm *vm, int vector,
+                        void (*handler)(struct ex_regs *))
+{
+       struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
+
+       assert(!VECTOR_IS_SYNC(vector));
+       assert(vector < VECTOR_NUM);
+       handlers->exception_handlers[vector][0] = handler;
 }
index 2f37b90..e0b0164 100644 (file)
@@ -14,7 +14,7 @@ static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa)
        if (kvm_userspace_memory_region_find(vm, gpa, gpa + 1))
                return false;
 
-       virt_pg_map(vm, gpa, gpa, 0);
+       virt_pg_map(vm, gpa, gpa);
 
        ucall_exit_mmio_addr = (vm_vaddr_t *)gpa;
        sync_global_to_guest(vm, ucall_exit_mmio_addr);
index bc75a91..eac44f5 100644 (file)
@@ -111,8 +111,7 @@ static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
  * by the image and it needs to have sufficient available physical pages, to
  * back the virtual pages used to load the image.
  */
-void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
-       uint32_t data_memslot, uint32_t pgd_memslot)
+void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename)
 {
        off_t offset, offset_rv;
        Elf64_Ehdr hdr;
@@ -164,8 +163,7 @@ void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
                seg_vend |= vm->page_size - 1;
                size_t seg_size = seg_vend - seg_vstart + 1;
 
-               vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
-                       data_memslot, pgd_memslot);
+               vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart);
                TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
                        "virtual memory for segment at requested min addr,\n"
                        "  segment idx: %u\n"
index 5c70596..5b56b57 100644 (file)
@@ -82,7 +82,7 @@ int kvm_check_cap(long cap)
 
        kvm_fd = open_kvm_dev_path_or_exit();
        ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap);
-       TEST_ASSERT(ret != -1, "KVM_CHECK_EXTENSION IOCTL failed,\n"
+       TEST_ASSERT(ret >= 0, "KVM_CHECK_EXTENSION IOCTL failed,\n"
                "  rc: %i errno: %i", ret, errno);
 
        close(kvm_fd);
@@ -365,7 +365,7 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
        pages = vm_adjust_num_guest_pages(mode, pages);
        vm = vm_create(mode, pages, O_RDWR);
 
-       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       kvm_vm_elf_load(vm, program_invocation_name);
 
 #ifdef __x86_64__
        vm_create_irqchip(vm);
@@ -375,10 +375,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
                uint32_t vcpuid = vcpuids ? vcpuids[i] : i;
 
                vm_vcpu_add_default(vm, vcpuid, guest_code);
-
-#ifdef __x86_64__
-               vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid());
-#endif
        }
 
        return vm;
@@ -1251,15 +1247,13 @@ va_found:
  * a unique set of pages, with the minimum real allocation being at least
  * a page.
  */
-vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
-                         uint32_t data_memslot, uint32_t pgd_memslot)
+vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min)
 {
        uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0);
 
-       virt_pgd_alloc(vm, pgd_memslot);
+       virt_pgd_alloc(vm);
        vm_paddr_t paddr = vm_phy_pages_alloc(vm, pages,
-                                             KVM_UTIL_MIN_PFN * vm->page_size,
-                                             data_memslot);
+                                             KVM_UTIL_MIN_PFN * vm->page_size, 0);
 
        /*
         * Find an unused range of virtual page addresses of at least
@@ -1271,7 +1265,7 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
        for (vm_vaddr_t vaddr = vaddr_start; pages > 0;
                pages--, vaddr += vm->page_size, paddr += vm->page_size) {
 
-               virt_pg_map(vm, vaddr, paddr, pgd_memslot);
+               virt_pg_map(vm, vaddr, paddr);
 
                sparsebit_set(vm->vpages_mapped,
                        vaddr >> vm->page_shift);
@@ -1281,6 +1275,44 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
 }
 
 /*
+ * VM Virtual Address Allocate Pages
+ *
+ * Input Args:
+ *   vm - Virtual Machine
+ *
+ * Output Args: None
+ *
+ * Return:
+ *   Starting guest virtual address
+ *
+ * Allocates at least N system pages worth of bytes within the virtual address
+ * space of the vm.
+ */
+vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages)
+{
+       return vm_vaddr_alloc(vm, nr_pages * getpagesize(), KVM_UTIL_MIN_VADDR);
+}
+
+/*
+ * VM Virtual Address Allocate Page
+ *
+ * Input Args:
+ *   vm - Virtual Machine
+ *
+ * Output Args: None
+ *
+ * Return:
+ *   Starting guest virtual address
+ *
+ * Allocates at least one system page worth of bytes within the virtual address
+ * space of the vm.
+ */
+vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm)
+{
+       return vm_vaddr_alloc_pages(vm, 1);
+}
+
+/*
  * Map a range of VM virtual address to the VM's physical address
  *
  * Input Args:
@@ -1298,7 +1330,7 @@ vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
  * @npages starting at @vaddr to the page range starting at @paddr.
  */
 void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-             unsigned int npages, uint32_t pgd_memslot)
+             unsigned int npages)
 {
        size_t page_size = vm->page_size;
        size_t size = npages * page_size;
@@ -1307,7 +1339,7 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
        TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
        while (npages--) {
-               virt_pg_map(vm, vaddr, paddr, pgd_memslot);
+               virt_pg_map(vm, vaddr, paddr);
                vaddr += page_size;
                paddr += page_size;
        }
@@ -2177,6 +2209,14 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
        return vm_phy_pages_alloc(vm, 1, paddr_min, memslot);
 }
 
+/* Arbitrary minimum physical address used for virtual translation tables. */
+#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000
+
+vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm)
+{
+       return vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);
+}
+
 /*
  * Address Guest Virtual to Host Virtual
  *
@@ -2286,3 +2326,15 @@ unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size)
        n = DIV_ROUND_UP(size, vm_guest_mode_params[mode].page_size);
        return vm_adjust_num_guest_pages(mode, n);
 }
+
+int vm_get_stats_fd(struct kvm_vm *vm)
+{
+       return ioctl(vm->fd, KVM_GET_STATS_FD, NULL);
+}
+
+int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid)
+{
+       struct vcpu *vcpu = vcpu_find(vm, vcpuid);
+
+       return ioctl(vcpu->fd, KVM_GET_STATS_FD, NULL);
+}
index 7397ca2..b488f4a 100644 (file)
@@ -101,7 +101,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
                                    guest_num_pages, 0);
 
        /* Do mapping for the demand paging memory slot */
-       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages, 0);
+       virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
 
        ucall_init(vm, NULL);
 
index 0152f35..f87c713 100644 (file)
@@ -9,11 +9,9 @@
 #include "kvm_util.h"
 #include "../kvm_util_internal.h"
 
-#define KVM_GUEST_PAGE_TABLE_MIN_PADDR         0x180000
-
 #define PAGES_PER_REGION 4
 
-void virt_pgd_alloc(struct kvm_vm *vm, uint32_t memslot)
+void virt_pgd_alloc(struct kvm_vm *vm)
 {
        vm_paddr_t paddr;
 
@@ -24,7 +22,7 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t memslot)
                return;
 
        paddr = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
-                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
+                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);
        memset(addr_gpa2hva(vm, paddr), 0xff, PAGES_PER_REGION * vm->page_size);
 
        vm->pgd = paddr;
@@ -36,12 +34,12 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t memslot)
  * a page table (ri == 4). Returns a suitable region/segment table entry
  * which points to the freshly allocated pages.
  */
-static uint64_t virt_alloc_region(struct kvm_vm *vm, int ri, uint32_t memslot)
+static uint64_t virt_alloc_region(struct kvm_vm *vm, int ri)
 {
        uint64_t taddr;
 
        taddr = vm_phy_pages_alloc(vm,  ri < 4 ? PAGES_PER_REGION : 1,
-                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
+                                  KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0);
        memset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm->page_size);
 
        return (taddr & REGION_ENTRY_ORIGIN)
@@ -49,8 +47,7 @@ static uint64_t virt_alloc_region(struct kvm_vm *vm, int ri, uint32_t memslot)
                | ((ri < 4 ? (PAGES_PER_REGION - 1) : 0) & REGION_ENTRY_LENGTH);
 }
 
-void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa,
-                uint32_t memslot)
+void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa)
 {
        int ri, idx;
        uint64_t *entry;
@@ -77,7 +74,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa,
        for (ri = 1; ri <= 4; ri++) {
                idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
                if (entry[idx] & REGION_ENTRY_INVALID)
-                       entry[idx] = virt_alloc_region(vm, ri, memslot);
+                       entry[idx] = virt_alloc_region(vm, ri);
                entry = addr_gpa2hva(vm, entry[idx] & REGION_ENTRY_ORIGIN);
        }
 
@@ -170,7 +167,7 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
                    vm->page_size);
 
        stack_vaddr = vm_vaddr_alloc(vm, stack_size,
-                                    DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0);
+                                    DEFAULT_GUEST_STACK_VADDR_MIN);
 
        vm_vcpu_add(vm, vcpuid);
 
index 6ad6c82..af1031f 100644 (file)
@@ -166,75 +166,75 @@ size_t get_def_hugetlb_pagesz(void)
        return 0;
 }
 
+#define ANON_FLAGS     (MAP_PRIVATE | MAP_ANONYMOUS)
+#define ANON_HUGE_FLAGS        (ANON_FLAGS | MAP_HUGETLB)
+
 const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i)
 {
-       static const int anon_flags = MAP_PRIVATE | MAP_ANONYMOUS;
-       static const int anon_huge_flags = anon_flags | MAP_HUGETLB;
-
        static const struct vm_mem_backing_src_alias aliases[] = {
                [VM_MEM_SRC_ANONYMOUS] = {
                        .name = "anonymous",
-                       .flag = anon_flags,
+                       .flag = ANON_FLAGS,
                },
                [VM_MEM_SRC_ANONYMOUS_THP] = {
                        .name = "anonymous_thp",
-                       .flag = anon_flags,
+                       .flag = ANON_FLAGS,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB] = {
                        .name = "anonymous_hugetlb",
-                       .flag = anon_huge_flags,
+                       .flag = ANON_HUGE_FLAGS,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_16KB] = {
                        .name = "anonymous_hugetlb_16kb",
-                       .flag = anon_huge_flags | MAP_HUGE_16KB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_16KB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_64KB] = {
                        .name = "anonymous_hugetlb_64kb",
-                       .flag = anon_huge_flags | MAP_HUGE_64KB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_64KB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_512KB] = {
                        .name = "anonymous_hugetlb_512kb",
-                       .flag = anon_huge_flags | MAP_HUGE_512KB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_512KB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_1MB] = {
                        .name = "anonymous_hugetlb_1mb",
-                       .flag = anon_huge_flags | MAP_HUGE_1MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_1MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_2MB] = {
                        .name = "anonymous_hugetlb_2mb",
-                       .flag = anon_huge_flags | MAP_HUGE_2MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_2MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_8MB] = {
                        .name = "anonymous_hugetlb_8mb",
-                       .flag = anon_huge_flags | MAP_HUGE_8MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_8MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_16MB] = {
                        .name = "anonymous_hugetlb_16mb",
-                       .flag = anon_huge_flags | MAP_HUGE_16MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_16MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_32MB] = {
                        .name = "anonymous_hugetlb_32mb",
-                       .flag = anon_huge_flags | MAP_HUGE_32MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_32MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_256MB] = {
                        .name = "anonymous_hugetlb_256mb",
-                       .flag = anon_huge_flags | MAP_HUGE_256MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_256MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_512MB] = {
                        .name = "anonymous_hugetlb_512mb",
-                       .flag = anon_huge_flags | MAP_HUGE_512MB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_512MB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB] = {
                        .name = "anonymous_hugetlb_1gb",
-                       .flag = anon_huge_flags | MAP_HUGE_1GB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_1GB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_2GB] = {
                        .name = "anonymous_hugetlb_2gb",
-                       .flag = anon_huge_flags | MAP_HUGE_2GB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_2GB,
                },
                [VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB] = {
                        .name = "anonymous_hugetlb_16gb",
-                       .flag = anon_huge_flags | MAP_HUGE_16GB,
+                       .flag = ANON_HUGE_FLAGS | MAP_HUGE_16GB,
                },
                [VM_MEM_SRC_SHMEM] = {
                        .name = "shmem",
diff --git a/tools/testing/selftests/kvm/lib/x86_64/apic.c b/tools/testing/selftests/kvm/lib/x86_64/apic.c
new file mode 100644 (file)
index 0000000..7168e25
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * tools/testing/selftests/kvm/lib/x86_64/processor.c
+ *
+ * Copyright (C) 2021, Google LLC.
+ */
+
+#include "apic.h"
+
+void apic_disable(void)
+{
+       wrmsr(MSR_IA32_APICBASE,
+             rdmsr(MSR_IA32_APICBASE) &
+               ~(MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD));
+}
+
+void xapic_enable(void)
+{
+       uint64_t val = rdmsr(MSR_IA32_APICBASE);
+
+       /* Per SDM: to enable xAPIC when in x2APIC must first disable APIC */
+       if (val & MSR_IA32_APICBASE_EXTD) {
+               apic_disable();
+               wrmsr(MSR_IA32_APICBASE,
+                     rdmsr(MSR_IA32_APICBASE) | MSR_IA32_APICBASE_ENABLE);
+       } else if (!(val & MSR_IA32_APICBASE_ENABLE)) {
+               wrmsr(MSR_IA32_APICBASE, val | MSR_IA32_APICBASE_ENABLE);
+       }
+
+       /*
+        * Per SDM: reset value of spurious interrupt vector register has the
+        * APIC software enabled bit=0. It must be enabled in addition to the
+        * enable bit in the MSR.
+        */
+       val = xapic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED;
+       xapic_write_reg(APIC_SPIV, val);
+}
+
+void x2apic_enable(void)
+{
+       wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) |
+             MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD);
+       x2apic_write_reg(APIC_SPIV,
+                        x2apic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED);
+}
index efe2350..28cb881 100644 (file)
 #define DEFAULT_CODE_SELECTOR 0x8
 #define DEFAULT_DATA_SELECTOR 0x10
 
-/* Minimum physical address used for virtual translation tables. */
-#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000
-
 vm_vaddr_t exception_handlers;
 
 /* Virtual translation table structure declarations */
-struct pageMapL4Entry {
+struct pageUpperEntry {
        uint64_t present:1;
        uint64_t writable:1;
        uint64_t user:1;
@@ -33,37 +30,7 @@ struct pageMapL4Entry {
        uint64_t ignored_06:1;
        uint64_t page_size:1;
        uint64_t ignored_11_08:4;
-       uint64_t address:40;
-       uint64_t ignored_62_52:11;
-       uint64_t execute_disable:1;
-};
-
-struct pageDirectoryPointerEntry {
-       uint64_t present:1;
-       uint64_t writable:1;
-       uint64_t user:1;
-       uint64_t write_through:1;
-       uint64_t cache_disable:1;
-       uint64_t accessed:1;
-       uint64_t ignored_06:1;
-       uint64_t page_size:1;
-       uint64_t ignored_11_08:4;
-       uint64_t address:40;
-       uint64_t ignored_62_52:11;
-       uint64_t execute_disable:1;
-};
-
-struct pageDirectoryEntry {
-       uint64_t present:1;
-       uint64_t writable:1;
-       uint64_t user:1;
-       uint64_t write_through:1;
-       uint64_t cache_disable:1;
-       uint64_t accessed:1;
-       uint64_t ignored_06:1;
-       uint64_t page_size:1;
-       uint64_t ignored_11_08:4;
-       uint64_t address:40;
+       uint64_t pfn:40;
        uint64_t ignored_62_52:11;
        uint64_t execute_disable:1;
 };
@@ -79,7 +46,7 @@ struct pageTableEntry {
        uint64_t reserved_07:1;
        uint64_t global:1;
        uint64_t ignored_11_09:3;
-       uint64_t address:40;
+       uint64_t pfn:40;
        uint64_t ignored_62_52:11;
        uint64_t execute_disable:1;
 };
@@ -207,96 +174,211 @@ void sregs_dump(FILE *stream, struct kvm_sregs *sregs,
        }
 }
 
-void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot)
+void virt_pgd_alloc(struct kvm_vm *vm)
 {
        TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use "
                "unknown or unsupported guest mode, mode: 0x%x", vm->mode);
 
        /* If needed, create page map l4 table. */
        if (!vm->pgd_created) {
-               vm_paddr_t paddr = vm_phy_page_alloc(vm,
-                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
-               vm->pgd = paddr;
+               vm->pgd = vm_alloc_page_table(vm);
                vm->pgd_created = true;
        }
 }
 
-void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
-       uint32_t pgd_memslot)
+static void *virt_get_pte(struct kvm_vm *vm, uint64_t pt_pfn, uint64_t vaddr,
+                         int level)
+{
+       uint64_t *page_table = addr_gpa2hva(vm, pt_pfn << vm->page_shift);
+       int index = vaddr >> (vm->page_shift + level * 9) & 0x1ffu;
+
+       return &page_table[index];
+}
+
+static struct pageUpperEntry *virt_create_upper_pte(struct kvm_vm *vm,
+                                                   uint64_t pt_pfn,
+                                                   uint64_t vaddr,
+                                                   uint64_t paddr,
+                                                   int level,
+                                                   enum x86_page_size page_size)
+{
+       struct pageUpperEntry *pte = virt_get_pte(vm, pt_pfn, vaddr, level);
+
+       if (!pte->present) {
+               pte->writable = true;
+               pte->present = true;
+               pte->page_size = (level == page_size);
+               if (pte->page_size)
+                       pte->pfn = paddr >> vm->page_shift;
+               else
+                       pte->pfn = vm_alloc_page_table(vm) >> vm->page_shift;
+       } else {
+               /*
+                * Entry already present.  Assert that the caller doesn't want
+                * a hugepage at this level, and that there isn't a hugepage at
+                * this level.
+                */
+               TEST_ASSERT(level != page_size,
+                           "Cannot create hugepage at level: %u, vaddr: 0x%lx\n",
+                           page_size, vaddr);
+               TEST_ASSERT(!pte->page_size,
+                           "Cannot create page table at level: %u, vaddr: 0x%lx\n",
+                           level, vaddr);
+       }
+       return pte;
+}
+
+void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
+                  enum x86_page_size page_size)
+{
+       const uint64_t pg_size = 1ull << ((page_size * 9) + 12);
+       struct pageUpperEntry *pml4e, *pdpe, *pde;
+       struct pageTableEntry *pte;
+
+       TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K,
+                   "Unknown or unsupported guest mode, mode: 0x%x", vm->mode);
+
+       TEST_ASSERT((vaddr % pg_size) == 0,
+                   "Virtual address not aligned,\n"
+                   "vaddr: 0x%lx page size: 0x%lx", vaddr, pg_size);
+       TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, (vaddr >> vm->page_shift)),
+                   "Invalid virtual address, vaddr: 0x%lx", vaddr);
+       TEST_ASSERT((paddr % pg_size) == 0,
+                   "Physical address not aligned,\n"
+                   "  paddr: 0x%lx page size: 0x%lx", paddr, pg_size);
+       TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn,
+                   "Physical address beyond maximum supported,\n"
+                   "  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
+                   paddr, vm->max_gfn, vm->page_size);
+
+       /*
+        * Allocate upper level page tables, if not already present.  Return
+        * early if a hugepage was created.
+        */
+       pml4e = virt_create_upper_pte(vm, vm->pgd >> vm->page_shift,
+                                     vaddr, paddr, 3, page_size);
+       if (pml4e->page_size)
+               return;
+
+       pdpe = virt_create_upper_pte(vm, pml4e->pfn, vaddr, paddr, 2, page_size);
+       if (pdpe->page_size)
+               return;
+
+       pde = virt_create_upper_pte(vm, pdpe->pfn, vaddr, paddr, 1, page_size);
+       if (pde->page_size)
+               return;
+
+       /* Fill in page table entry. */
+       pte = virt_get_pte(vm, pde->pfn, vaddr, 0);
+       TEST_ASSERT(!pte->present,
+                   "PTE already present for 4k page at vaddr: 0x%lx\n", vaddr);
+       pte->pfn = paddr >> vm->page_shift;
+       pte->writable = true;
+       pte->present = 1;
+}
+
+void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
+{
+       __virt_pg_map(vm, vaddr, paddr, X86_PAGE_SIZE_4K);
+}
+
+static struct pageTableEntry *_vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid,
+                                                      uint64_t vaddr)
 {
        uint16_t index[4];
-       struct pageMapL4Entry *pml4e;
+       struct pageUpperEntry *pml4e, *pdpe, *pde;
+       struct pageTableEntry *pte;
+       struct kvm_cpuid_entry2 *entry;
+       struct kvm_sregs sregs;
+       int max_phy_addr;
+       /* Set the bottom 52 bits. */
+       uint64_t rsvd_mask = 0x000fffffffffffff;
+
+       entry = kvm_get_supported_cpuid_index(0x80000008, 0);
+       max_phy_addr = entry->eax & 0x000000ff;
+       /* Clear the bottom bits of the reserved mask. */
+       rsvd_mask = (rsvd_mask >> max_phy_addr) << max_phy_addr;
+
+       /*
+        * SDM vol 3, fig 4-11 "Formats of CR3 and Paging-Structure Entries
+        * with 4-Level Paging and 5-Level Paging".
+        * If IA32_EFER.NXE = 0 and the P flag of a paging-structure entry is 1,
+        * the XD flag (bit 63) is reserved.
+        */
+       vcpu_sregs_get(vm, vcpuid, &sregs);
+       if ((sregs.efer & EFER_NX) == 0) {
+               rsvd_mask |= (1ull << 63);
+       }
 
        TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use "
                "unknown or unsupported guest mode, mode: 0x%x", vm->mode);
-
-       TEST_ASSERT((vaddr % vm->page_size) == 0,
-               "Virtual address not on page boundary,\n"
-               "  vaddr: 0x%lx vm->page_size: 0x%x",
-               vaddr, vm->page_size);
        TEST_ASSERT(sparsebit_is_set(vm->vpages_valid,
                (vaddr >> vm->page_shift)),
                "Invalid virtual address, vaddr: 0x%lx",
                vaddr);
-       TEST_ASSERT((paddr % vm->page_size) == 0,
-               "Physical address not on page boundary,\n"
-               "  paddr: 0x%lx vm->page_size: 0x%x",
-               paddr, vm->page_size);
-       TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn,
-               "Physical address beyond beyond maximum supported,\n"
-               "  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
-               paddr, vm->max_gfn, vm->page_size);
+       /*
+        * Based on the mode check above there are 48 bits in the vaddr, so
+        * shift 16 to sign extend the last bit (bit-47),
+        */
+       TEST_ASSERT(vaddr == (((int64_t)vaddr << 16) >> 16),
+               "Canonical check failed.  The virtual address is invalid.");
 
        index[0] = (vaddr >> 12) & 0x1ffu;
        index[1] = (vaddr >> 21) & 0x1ffu;
        index[2] = (vaddr >> 30) & 0x1ffu;
        index[3] = (vaddr >> 39) & 0x1ffu;
 
-       /* Allocate page directory pointer table if not present. */
        pml4e = addr_gpa2hva(vm, vm->pgd);
-       if (!pml4e[index[3]].present) {
-               pml4e[index[3]].address = vm_phy_page_alloc(vm,
-                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot)
-                       >> vm->page_shift;
-               pml4e[index[3]].writable = true;
-               pml4e[index[3]].present = true;
-       }
+       TEST_ASSERT(pml4e[index[3]].present,
+               "Expected pml4e to be present for gva: 0x%08lx", vaddr);
+       TEST_ASSERT((*(uint64_t*)(&pml4e[index[3]]) &
+               (rsvd_mask | (1ull << 7))) == 0,
+               "Unexpected reserved bits set.");
+
+       pdpe = addr_gpa2hva(vm, pml4e[index[3]].pfn * vm->page_size);
+       TEST_ASSERT(pdpe[index[2]].present,
+               "Expected pdpe to be present for gva: 0x%08lx", vaddr);
+       TEST_ASSERT(pdpe[index[2]].page_size == 0,
+               "Expected pdpe to map a pde not a 1-GByte page.");
+       TEST_ASSERT((*(uint64_t*)(&pdpe[index[2]]) & rsvd_mask) == 0,
+               "Unexpected reserved bits set.");
+
+       pde = addr_gpa2hva(vm, pdpe[index[2]].pfn * vm->page_size);
+       TEST_ASSERT(pde[index[1]].present,
+               "Expected pde to be present for gva: 0x%08lx", vaddr);
+       TEST_ASSERT(pde[index[1]].page_size == 0,
+               "Expected pde to map a pte not a 2-MByte page.");
+       TEST_ASSERT((*(uint64_t*)(&pde[index[1]]) & rsvd_mask) == 0,
+               "Unexpected reserved bits set.");
+
+       pte = addr_gpa2hva(vm, pde[index[1]].pfn * vm->page_size);
+       TEST_ASSERT(pte[index[0]].present,
+               "Expected pte to be present for gva: 0x%08lx", vaddr);
+
+       return &pte[index[0]];
+}
 
-       /* Allocate page directory table if not present. */
-       struct pageDirectoryPointerEntry *pdpe;
-       pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size);
-       if (!pdpe[index[2]].present) {
-               pdpe[index[2]].address = vm_phy_page_alloc(vm,
-                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot)
-                       >> vm->page_shift;
-               pdpe[index[2]].writable = true;
-               pdpe[index[2]].present = true;
-       }
+uint64_t vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr)
+{
+       struct pageTableEntry *pte = _vm_get_page_table_entry(vm, vcpuid, vaddr);
 
-       /* Allocate page table if not present. */
-       struct pageDirectoryEntry *pde;
-       pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size);
-       if (!pde[index[1]].present) {
-               pde[index[1]].address = vm_phy_page_alloc(vm,
-                       KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot)
-                       >> vm->page_shift;
-               pde[index[1]].writable = true;
-               pde[index[1]].present = true;
-       }
+       return *(uint64_t *)pte;
+}
 
-       /* Fill in page table entry. */
-       struct pageTableEntry *pte;
-       pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size);
-       pte[index[0]].address = paddr >> vm->page_shift;
-       pte[index[0]].writable = true;
-       pte[index[0]].present = 1;
+void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr,
+                            uint64_t pte)
+{
+       struct pageTableEntry *new_pte = _vm_get_page_table_entry(vm, vcpuid,
+                                                                 vaddr);
+
+       *(uint64_t *)new_pte = pte;
 }
 
 void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
 {
-       struct pageMapL4Entry *pml4e, *pml4e_start;
-       struct pageDirectoryPointerEntry *pdpe, *pdpe_start;
-       struct pageDirectoryEntry *pde, *pde_start;
+       struct pageUpperEntry *pml4e, *pml4e_start;
+       struct pageUpperEntry *pdpe, *pdpe_start;
+       struct pageUpperEntry *pde, *pde_start;
        struct pageTableEntry *pte, *pte_start;
 
        if (!vm->pgd_created)
@@ -307,8 +389,7 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
        fprintf(stream, "%*s      index hvaddr         gpaddr         "
                "addr         w exec dirty\n",
                indent, "");
-       pml4e_start = (struct pageMapL4Entry *) addr_gpa2hva(vm,
-               vm->pgd);
+       pml4e_start = (struct pageUpperEntry *) addr_gpa2hva(vm, vm->pgd);
        for (uint16_t n1 = 0; n1 <= 0x1ffu; n1++) {
                pml4e = &pml4e_start[n1];
                if (!pml4e->present)
@@ -317,11 +398,10 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
                        " %u\n",
                        indent, "",
                        pml4e - pml4e_start, pml4e,
-                       addr_hva2gpa(vm, pml4e), (uint64_t) pml4e->address,
+                       addr_hva2gpa(vm, pml4e), (uint64_t) pml4e->pfn,
                        pml4e->writable, pml4e->execute_disable);
 
-               pdpe_start = addr_gpa2hva(vm, pml4e->address
-                       * vm->page_size);
+               pdpe_start = addr_gpa2hva(vm, pml4e->pfn * vm->page_size);
                for (uint16_t n2 = 0; n2 <= 0x1ffu; n2++) {
                        pdpe = &pdpe_start[n2];
                        if (!pdpe->present)
@@ -331,11 +411,10 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
                                indent, "",
                                pdpe - pdpe_start, pdpe,
                                addr_hva2gpa(vm, pdpe),
-                               (uint64_t) pdpe->address, pdpe->writable,
+                               (uint64_t) pdpe->pfn, pdpe->writable,
                                pdpe->execute_disable);
 
-                       pde_start = addr_gpa2hva(vm,
-                               pdpe->address * vm->page_size);
+                       pde_start = addr_gpa2hva(vm, pdpe->pfn * vm->page_size);
                        for (uint16_t n3 = 0; n3 <= 0x1ffu; n3++) {
                                pde = &pde_start[n3];
                                if (!pde->present)
@@ -344,11 +423,10 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
                                        "0x%-12lx 0x%-10lx %u  %u\n",
                                        indent, "", pde - pde_start, pde,
                                        addr_hva2gpa(vm, pde),
-                                       (uint64_t) pde->address, pde->writable,
+                                       (uint64_t) pde->pfn, pde->writable,
                                        pde->execute_disable);
 
-                               pte_start = addr_gpa2hva(vm,
-                                       pde->address * vm->page_size);
+                               pte_start = addr_gpa2hva(vm, pde->pfn * vm->page_size);
                                for (uint16_t n4 = 0; n4 <= 0x1ffu; n4++) {
                                        pte = &pte_start[n4];
                                        if (!pte->present)
@@ -359,7 +437,7 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
                                                indent, "",
                                                pte - pte_start, pte,
                                                addr_hva2gpa(vm, pte),
-                                               (uint64_t) pte->address,
+                                               (uint64_t) pte->pfn,
                                                pte->writable,
                                                pte->execute_disable,
                                                pte->dirty,
@@ -480,9 +558,7 @@ static void kvm_seg_set_kernel_data_64bit(struct kvm_vm *vm, uint16_t selector,
 vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
 {
        uint16_t index[4];
-       struct pageMapL4Entry *pml4e;
-       struct pageDirectoryPointerEntry *pdpe;
-       struct pageDirectoryEntry *pde;
+       struct pageUpperEntry *pml4e, *pdpe, *pde;
        struct pageTableEntry *pte;
 
        TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use "
@@ -499,43 +575,39 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
        if (!pml4e[index[3]].present)
                goto unmapped_gva;
 
-       pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size);
+       pdpe = addr_gpa2hva(vm, pml4e[index[3]].pfn * vm->page_size);
        if (!pdpe[index[2]].present)
                goto unmapped_gva;
 
-       pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size);
+       pde = addr_gpa2hva(vm, pdpe[index[2]].pfn * vm->page_size);
        if (!pde[index[1]].present)
                goto unmapped_gva;
 
-       pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size);
+       pte = addr_gpa2hva(vm, pde[index[1]].pfn * vm->page_size);
        if (!pte[index[0]].present)
                goto unmapped_gva;
 
-       return (pte[index[0]].address * vm->page_size) + (gva & 0xfffu);
+       return (pte[index[0]].pfn * vm->page_size) + (gva & 0xfffu);
 
 unmapped_gva:
        TEST_FAIL("No mapping for vm virtual address, gva: 0x%lx", gva);
        exit(EXIT_FAILURE);
 }
 
-static void kvm_setup_gdt(struct kvm_vm *vm, struct kvm_dtable *dt, int gdt_memslot,
-                         int pgd_memslot)
+static void kvm_setup_gdt(struct kvm_vm *vm, struct kvm_dtable *dt)
 {
        if (!vm->gdt)
-               vm->gdt = vm_vaddr_alloc(vm, getpagesize(),
-                       KVM_UTIL_MIN_VADDR, gdt_memslot, pgd_memslot);
+               vm->gdt = vm_vaddr_alloc_page(vm);
 
        dt->base = vm->gdt;
        dt->limit = getpagesize();
 }
 
 static void kvm_setup_tss_64bit(struct kvm_vm *vm, struct kvm_segment *segp,
-                               int selector, int gdt_memslot,
-                               int pgd_memslot)
+                               int selector)
 {
        if (!vm->tss)
-               vm->tss = vm_vaddr_alloc(vm, getpagesize(),
-                       KVM_UTIL_MIN_VADDR, gdt_memslot, pgd_memslot);
+               vm->tss = vm_vaddr_alloc_page(vm);
 
        memset(segp, 0, sizeof(*segp));
        segp->base = vm->tss;
@@ -546,7 +618,7 @@ static void kvm_setup_tss_64bit(struct kvm_vm *vm, struct kvm_segment *segp,
        kvm_seg_fill_gdt_64bit(vm, segp);
 }
 
-static void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot)
+static void vcpu_setup(struct kvm_vm *vm, int vcpuid)
 {
        struct kvm_sregs sregs;
 
@@ -555,7 +627,7 @@ static void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_m
 
        sregs.idt.limit = 0;
 
-       kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot);
+       kvm_setup_gdt(vm, &sregs.gdt);
 
        switch (vm->mode) {
        case VM_MODE_PXXV48_4K:
@@ -567,7 +639,7 @@ static void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_m
                kvm_seg_set_kernel_code_64bit(vm, DEFAULT_CODE_SELECTOR, &sregs.cs);
                kvm_seg_set_kernel_data_64bit(vm, DEFAULT_DATA_SELECTOR, &sregs.ds);
                kvm_seg_set_kernel_data_64bit(vm, DEFAULT_DATA_SELECTOR, &sregs.es);
-               kvm_setup_tss_64bit(vm, &sregs.tr, 0x18, gdt_memslot, pgd_memslot);
+               kvm_setup_tss_64bit(vm, &sregs.tr, 0x18);
                break;
 
        default:
@@ -584,11 +656,11 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
        struct kvm_regs regs;
        vm_vaddr_t stack_vaddr;
        stack_vaddr = vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(),
-                                    DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0);
+                                    DEFAULT_GUEST_STACK_VADDR_MIN);
 
        /* Create VCPU */
        vm_vcpu_add(vm, vcpuid);
-       vcpu_setup(vm, vcpuid, 0, 0);
+       vcpu_setup(vm, vcpuid);
 
        /* Setup guest general purpose registers */
        vcpu_regs_get(vm, vcpuid, &regs);
@@ -600,6 +672,9 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
        /* Setup the MP state */
        mp_state.mp_state = 0;
        vcpu_set_mp_state(vm, vcpuid, &mp_state);
+
+       /* Setup supported CPUIDs */
+       vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid());
 }
 
 /*
@@ -1201,7 +1276,7 @@ static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr,
 
 void kvm_exit_unexpected_vector(uint32_t value)
 {
-       outl(UNEXPECTED_VECTOR_PORT, value);
+       ucall(UCALL_UNHANDLED, 1, value);
 }
 
 void route_exception(struct ex_regs *regs)
@@ -1222,8 +1297,8 @@ void vm_init_descriptor_tables(struct kvm_vm *vm)
        extern void *idt_handlers;
        int i;
 
-       vm->idt = vm_vaddr_alloc(vm, getpagesize(), 0x2000, 0, 0);
-       vm->handlers = vm_vaddr_alloc(vm, 256 * sizeof(void *), 0x2000, 0, 0);
+       vm->idt = vm_vaddr_alloc_page(vm);
+       vm->handlers = vm_vaddr_alloc_page(vm);
        /* Handlers have the same address in both address spaces.*/
        for (i = 0; i < NUM_INTERRUPTS; i++)
                set_idt_entry(vm, i, (unsigned long)(&idt_handlers)[i], 0,
@@ -1244,8 +1319,8 @@ void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid)
        *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
 }
 
-void vm_handle_exception(struct kvm_vm *vm, int vector,
-                        void (*handler)(struct ex_regs *))
+void vm_install_exception_handler(struct kvm_vm *vm, int vector,
+                              void (*handler)(struct ex_regs *))
 {
        vm_vaddr_t *handlers = (vm_vaddr_t *)addr_gva2hva(vm, vm->handlers);
 
@@ -1254,16 +1329,13 @@ void vm_handle_exception(struct kvm_vm *vm, int vector,
 
 void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid)
 {
-       if (vcpu_state(vm, vcpuid)->exit_reason == KVM_EXIT_IO
-               && vcpu_state(vm, vcpuid)->io.port == UNEXPECTED_VECTOR_PORT
-               && vcpu_state(vm, vcpuid)->io.size == 4) {
-               /* Grab pointer to io data */
-               uint32_t *data = (void *)vcpu_state(vm, vcpuid)
-                       + vcpu_state(vm, vcpuid)->io.data_offset;
-
-               TEST_ASSERT(false,
-                           "Unexpected vectored event in guest (vector:0x%x)",
-                           *data);
+       struct ucall uc;
+
+       if (get_ucall(vm, vcpuid, &uc) == UCALL_UNHANDLED) {
+               uint64_t vector = uc.args[0];
+
+               TEST_FAIL("Unexpected vectored event in guest (vector:0x%lx)",
+                         vector);
        }
 }
 
index 827fe60..2ac98d7 100644 (file)
@@ -30,17 +30,14 @@ u64 rflags;
 struct svm_test_data *
 vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva)
 {
-       vm_vaddr_t svm_gva = vm_vaddr_alloc(vm, getpagesize(),
-                                           0x10000, 0, 0);
+       vm_vaddr_t svm_gva = vm_vaddr_alloc_page(vm);
        struct svm_test_data *svm = addr_gva2hva(vm, svm_gva);
 
-       svm->vmcb = (void *)vm_vaddr_alloc(vm, getpagesize(),
-                                          0x10000, 0, 0);
+       svm->vmcb = (void *)vm_vaddr_alloc_page(vm);
        svm->vmcb_hva = addr_gva2hva(vm, (uintptr_t)svm->vmcb);
        svm->vmcb_gpa = addr_gva2gpa(vm, (uintptr_t)svm->vmcb);
 
-       svm->save_area = (void *)vm_vaddr_alloc(vm, getpagesize(),
-                                               0x10000, 0, 0);
+       svm->save_area = (void *)vm_vaddr_alloc_page(vm);
        svm->save_area_hva = addr_gva2hva(vm, (uintptr_t)svm->save_area);
        svm->save_area_gpa = addr_gva2gpa(vm, (uintptr_t)svm->save_area);
 
index 2448b30..d089d8b 100644 (file)
@@ -77,50 +77,48 @@ int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id)
 struct vmx_pages *
 vcpu_alloc_vmx(struct kvm_vm *vm, vm_vaddr_t *p_vmx_gva)
 {
-       vm_vaddr_t vmx_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vm_vaddr_t vmx_gva = vm_vaddr_alloc_page(vm);
        struct vmx_pages *vmx = addr_gva2hva(vm, vmx_gva);
 
        /* Setup of a region of guest memory for the vmxon region. */
-       vmx->vmxon = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->vmxon = (void *)vm_vaddr_alloc_page(vm);
        vmx->vmxon_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmxon);
        vmx->vmxon_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmxon);
 
        /* Setup of a region of guest memory for a vmcs. */
-       vmx->vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->vmcs = (void *)vm_vaddr_alloc_page(vm);
        vmx->vmcs_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmcs);
        vmx->vmcs_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmcs);
 
        /* Setup of a region of guest memory for the MSR bitmap. */
-       vmx->msr = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->msr = (void *)vm_vaddr_alloc_page(vm);
        vmx->msr_hva = addr_gva2hva(vm, (uintptr_t)vmx->msr);
        vmx->msr_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->msr);
        memset(vmx->msr_hva, 0, getpagesize());
 
        /* Setup of a region of guest memory for the shadow VMCS. */
-       vmx->shadow_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->shadow_vmcs = (void *)vm_vaddr_alloc_page(vm);
        vmx->shadow_vmcs_hva = addr_gva2hva(vm, (uintptr_t)vmx->shadow_vmcs);
        vmx->shadow_vmcs_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->shadow_vmcs);
 
        /* Setup of a region of guest memory for the VMREAD and VMWRITE bitmaps. */
-       vmx->vmread = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->vmread = (void *)vm_vaddr_alloc_page(vm);
        vmx->vmread_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmread);
        vmx->vmread_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmread);
        memset(vmx->vmread_hva, 0, getpagesize());
 
-       vmx->vmwrite = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->vmwrite = (void *)vm_vaddr_alloc_page(vm);
        vmx->vmwrite_hva = addr_gva2hva(vm, (uintptr_t)vmx->vmwrite);
        vmx->vmwrite_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vmwrite);
        memset(vmx->vmwrite_hva, 0, getpagesize());
 
        /* Setup of a region of guest memory for the VP Assist page. */
-       vmx->vp_assist = (void *)vm_vaddr_alloc(vm, getpagesize(),
-                                               0x10000, 0, 0);
+       vmx->vp_assist = (void *)vm_vaddr_alloc_page(vm);
        vmx->vp_assist_hva = addr_gva2hva(vm, (uintptr_t)vmx->vp_assist);
        vmx->vp_assist_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->vp_assist);
 
        /* Setup of a region of guest memory for the enlightened VMCS. */
-       vmx->enlightened_vmcs = (void *)vm_vaddr_alloc(vm, getpagesize(),
-                                                      0x10000, 0, 0);
+       vmx->enlightened_vmcs = (void *)vm_vaddr_alloc_page(vm);
        vmx->enlightened_vmcs_hva =
                addr_gva2hva(vm, (uintptr_t)vmx->enlightened_vmcs);
        vmx->enlightened_vmcs_gpa =
@@ -395,7 +393,7 @@ void nested_vmx_check_supported(void)
 }
 
 void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-                  uint64_t nested_paddr, uint64_t paddr, uint32_t eptp_memslot)
+                  uint64_t nested_paddr, uint64_t paddr)
 {
        uint16_t index[4];
        struct eptPageTableEntry *pml4e;
@@ -428,9 +426,7 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
        /* Allocate page directory pointer table if not present. */
        pml4e = vmx->eptp_hva;
        if (!pml4e[index[3]].readable) {
-               pml4e[index[3]].address = vm_phy_page_alloc(vm,
-                         KVM_EPT_PAGE_TABLE_MIN_PADDR, eptp_memslot)
-                       >> vm->page_shift;
+               pml4e[index[3]].address = vm_alloc_page_table(vm) >> vm->page_shift;
                pml4e[index[3]].writable = true;
                pml4e[index[3]].readable = true;
                pml4e[index[3]].executable = true;
@@ -440,9 +436,7 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
        struct eptPageTableEntry *pdpe;
        pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size);
        if (!pdpe[index[2]].readable) {
-               pdpe[index[2]].address = vm_phy_page_alloc(vm,
-                         KVM_EPT_PAGE_TABLE_MIN_PADDR, eptp_memslot)
-                       >> vm->page_shift;
+               pdpe[index[2]].address = vm_alloc_page_table(vm) >> vm->page_shift;
                pdpe[index[2]].writable = true;
                pdpe[index[2]].readable = true;
                pdpe[index[2]].executable = true;
@@ -452,9 +446,7 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
        struct eptPageTableEntry *pde;
        pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size);
        if (!pde[index[1]].readable) {
-               pde[index[1]].address = vm_phy_page_alloc(vm,
-                         KVM_EPT_PAGE_TABLE_MIN_PADDR, eptp_memslot)
-                       >> vm->page_shift;
+               pde[index[1]].address = vm_alloc_page_table(vm) >> vm->page_shift;
                pde[index[1]].writable = true;
                pde[index[1]].readable = true;
                pde[index[1]].executable = true;
@@ -494,8 +486,7 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm,
  * page range starting at nested_paddr to the page range starting at paddr.
  */
 void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
-               uint64_t nested_paddr, uint64_t paddr, uint64_t size,
-               uint32_t eptp_memslot)
+               uint64_t nested_paddr, uint64_t paddr, uint64_t size)
 {
        size_t page_size = vm->page_size;
        size_t npages = size / page_size;
@@ -504,7 +495,7 @@ void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
        TEST_ASSERT(paddr + size > paddr, "Paddr overflow");
 
        while (npages--) {
-               nested_pg_map(vmx, vm, nested_paddr, paddr, eptp_memslot);
+               nested_pg_map(vmx, vm, nested_paddr, paddr);
                nested_paddr += page_size;
                paddr += page_size;
        }
@@ -514,7 +505,7 @@ void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm,
  * physical pages in VM.
  */
 void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm,
-                       uint32_t memslot, uint32_t eptp_memslot)
+                       uint32_t memslot)
 {
        sparsebit_idx_t i, last;
        struct userspace_mem_region *region =
@@ -530,24 +521,21 @@ void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm,
                nested_map(vmx, vm,
                           (uint64_t)i << vm->page_shift,
                           (uint64_t)i << vm->page_shift,
-                          1 << vm->page_shift,
-                          eptp_memslot);
+                          1 << vm->page_shift);
        }
 }
 
 void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm,
                  uint32_t eptp_memslot)
 {
-       vmx->eptp = (void *)vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       vmx->eptp = (void *)vm_vaddr_alloc_page(vm);
        vmx->eptp_hva = addr_gva2hva(vm, (uintptr_t)vmx->eptp);
        vmx->eptp_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->eptp);
 }
 
-void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm,
-                                     uint32_t eptp_memslot)
+void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm)
 {
-       vmx->apic_access = (void *)vm_vaddr_alloc(vm, getpagesize(),
-                                                 0x10000, 0, 0);
+       vmx->apic_access = (void *)vm_vaddr_alloc_page(vm);
        vmx->apic_access_hva = addr_gva2hva(vm, (uintptr_t)vmx->apic_access);
        vmx->apic_access_gpa = addr_gva2gpa(vm, (uintptr_t)vmx->apic_access);
 }
index 1123965..d6e381e 100644 (file)
@@ -306,7 +306,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
                guest_addr += npages * 4096;
        }
 
-       virt_map(data->vm, MEM_GPA, MEM_GPA, mempages, 0);
+       virt_map(data->vm, MEM_GPA, MEM_GPA, mempages);
 
        sync = (typeof(sync))vm_gpa2hva(data, MEM_SYNC_GPA, NULL);
        atomic_init(&sync->start_flag, false);
index 978f5b5..85b18bb 100644 (file)
@@ -132,7 +132,7 @@ static struct kvm_vm *spawn_vm(pthread_t *vcpu_thread, void *guest_code)
        gpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_GPA, MEM_REGION_SLOT);
        TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n");
 
-       virt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2, 0);
+       virt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2);
 
        /* Ditto for the host mapping so that both pages can be zeroed. */
        hva = addr_gpa2hva(vm, MEM_REGION_GPA);
@@ -376,7 +376,7 @@ static void test_add_max_memory_regions(void)
        pr_info("Adding slots 0..%i, each memory region with %dK size\n",
                (max_mem_slots - 1), MEM_REGION_SIZE >> 10);
 
-       mem = mmap(NULL, MEM_REGION_SIZE * max_mem_slots + alignment,
+       mem = mmap(NULL, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment,
                   PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        TEST_ASSERT(mem != MAP_FAILED, "Failed to mmap() host");
        mem_aligned = (void *)(((size_t) mem + alignment - 1) & ~(alignment - 1));
@@ -401,7 +401,7 @@ static void test_add_max_memory_regions(void)
        TEST_ASSERT(ret == -1 && errno == EINVAL,
                    "Adding one more memory slot should fail with EINVAL");
 
-       munmap(mem, MEM_REGION_SIZE * max_mem_slots + alignment);
+       munmap(mem, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment);
        munmap(mem_extra, MEM_REGION_SIZE);
        kvm_vm_free(vm);
 }
index fcc8400..b0031f2 100644 (file)
@@ -73,8 +73,6 @@ static void steal_time_init(struct kvm_vm *vm)
        for (i = 0; i < NR_VCPUS; ++i) {
                int ret;
 
-               vcpu_set_cpuid(vm, i, kvm_get_supported_cpuid());
-
                /* ST_GPA_BASE is identity mapped */
                st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
                sync_global_to_guest(vm, st_gva[i]);
@@ -295,7 +293,7 @@ int main(int ac, char **av)
        vm = vm_create_default(0, 0, guest_code);
        gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * NR_VCPUS);
        vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
-       virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages, 0);
+       virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages);
        ucall_init(vm, NULL);
 
        /* Add the rest of the VCPUs */
diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c
new file mode 100644 (file)
index 0000000..f070ff0
--- /dev/null
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020, Google LLC.
+ *
+ * Tests for KVM_CAP_EXIT_ON_EMULATION_FAILURE capability.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_short_name */
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "vmx.h"
+
+#define VCPU_ID           1
+#define PAGE_SIZE  4096
+#define MAXPHYADDR 36
+
+#define MEM_REGION_GVA 0x0000123456789000
+#define MEM_REGION_GPA 0x0000000700000000
+#define MEM_REGION_SLOT        10
+#define MEM_REGION_SIZE PAGE_SIZE
+
+static void guest_code(void)
+{
+       __asm__ __volatile__("flds (%[addr])"
+                            :: [addr]"r"(MEM_REGION_GVA));
+
+       GUEST_DONE();
+}
+
+static void run_guest(struct kvm_vm *vm)
+{
+       int rc;
+
+       rc = _vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc);
+}
+
+/*
+ * Accessors to get R/M, REG, and Mod bits described in the SDM vol 2,
+ * figure 2-2 "Table Interpretation of ModR/M Byte (C8H)".
+ */
+#define GET_RM(insn_byte) (insn_byte & 0x7)
+#define GET_REG(insn_byte) ((insn_byte & 0x38) >> 3)
+#define GET_MOD(insn_byte) ((insn_byte & 0xc) >> 6)
+
+/* Ensure we are dealing with a simple 2-byte flds instruction. */
+static bool is_flds(uint8_t *insn_bytes, uint8_t insn_size)
+{
+       return insn_size >= 2 &&
+              insn_bytes[0] == 0xd9 &&
+              GET_REG(insn_bytes[1]) == 0x0 &&
+              GET_MOD(insn_bytes[1]) == 0x0 &&
+              /* Ensure there is no SIB byte. */
+              GET_RM(insn_bytes[1]) != 0x4 &&
+              /* Ensure there is no displacement byte. */
+              GET_RM(insn_bytes[1]) != 0x5;
+}
+
+static void process_exit_on_emulation_error(struct kvm_vm *vm)
+{
+       struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+       struct kvm_regs regs;
+       uint8_t *insn_bytes;
+       uint8_t insn_size;
+       uint64_t flags;
+
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR,
+                   "Unexpected exit reason: %u (%s)",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+
+       TEST_ASSERT(run->emulation_failure.suberror == KVM_INTERNAL_ERROR_EMULATION,
+                   "Unexpected suberror: %u",
+                   run->emulation_failure.suberror);
+
+       if (run->emulation_failure.ndata >= 1) {
+               flags = run->emulation_failure.flags;
+               if ((flags & KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES) &&
+                   run->emulation_failure.ndata >= 3) {
+                       insn_size = run->emulation_failure.insn_size;
+                       insn_bytes = run->emulation_failure.insn_bytes;
+
+                       TEST_ASSERT(insn_size <= 15 && insn_size > 0,
+                                   "Unexpected instruction size: %u",
+                                   insn_size);
+
+                       TEST_ASSERT(is_flds(insn_bytes, insn_size),
+                                   "Unexpected instruction.  Expected 'flds' (0xd9 /0)");
+
+                       /*
+                        * If is_flds() succeeded then the instruction bytes
+                        * contained an flds instruction that is 2-bytes in
+                        * length (ie: no prefix, no SIB, no displacement).
+                        */
+                       vcpu_regs_get(vm, VCPU_ID, &regs);
+                       regs.rip += 2;
+                       vcpu_regs_set(vm, VCPU_ID, &regs);
+               }
+       }
+}
+
+static void do_guest_assert(struct kvm_vm *vm, struct ucall *uc)
+{
+       TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], __FILE__,
+                 uc->args[1]);
+}
+
+static void check_for_guest_assert(struct kvm_vm *vm)
+{
+       struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+       struct ucall uc;
+
+       if (run->exit_reason == KVM_EXIT_IO &&
+           get_ucall(vm, VCPU_ID, &uc) == UCALL_ABORT) {
+               do_guest_assert(vm, &uc);
+       }
+}
+
+static void process_ucall_done(struct kvm_vm *vm)
+{
+       struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+       struct ucall uc;
+
+       check_for_guest_assert(vm);
+
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                   "Unexpected exit reason: %u (%s)",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+
+       TEST_ASSERT(get_ucall(vm, VCPU_ID, &uc) == UCALL_DONE,
+                   "Unexpected ucall command: %lu, expected UCALL_DONE (%d)",
+                   uc.cmd, UCALL_DONE);
+}
+
+static uint64_t process_ucall(struct kvm_vm *vm)
+{
+       struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+       struct ucall uc;
+
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                   "Unexpected exit reason: %u (%s)",
+                   run->exit_reason,
+                   exit_reason_str(run->exit_reason));
+
+       switch (get_ucall(vm, VCPU_ID, &uc)) {
+       case UCALL_SYNC:
+               break;
+       case UCALL_ABORT:
+               do_guest_assert(vm, &uc);
+               break;
+       case UCALL_DONE:
+               process_ucall_done(vm);
+               break;
+       default:
+               TEST_ASSERT(false, "Unexpected ucall");
+       }
+
+       return uc.cmd;
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_enable_cap emul_failure_cap = {
+               .cap = KVM_CAP_EXIT_ON_EMULATION_FAILURE,
+               .args[0] = 1,
+       };
+       struct kvm_cpuid_entry2 *entry;
+       struct kvm_cpuid2 *cpuid;
+       struct kvm_vm *vm;
+       uint64_t gpa, pte;
+       uint64_t *hva;
+       int rc;
+
+       /* Tell stdout not to buffer its content */
+       setbuf(stdout, NULL);
+
+       vm = vm_create_default(VCPU_ID, 0, guest_code);
+
+       if (!kvm_check_cap(KVM_CAP_SMALLER_MAXPHYADDR)) {
+               printf("module parameter 'allow_smaller_maxphyaddr' is not set.  Skipping test.\n");
+               return 0;
+       }
+
+       cpuid = kvm_get_supported_cpuid();
+
+       entry = kvm_get_supported_cpuid_index(0x80000008, 0);
+       entry->eax = (entry->eax & 0xffffff00) | MAXPHYADDR;
+       set_cpuid(cpuid, entry);
+
+       vcpu_set_cpuid(vm, VCPU_ID, cpuid);
+
+       rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE);
+       TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable");
+       vm_enable_cap(vm, &emul_failure_cap);
+
+       vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+                                   MEM_REGION_GPA, MEM_REGION_SLOT,
+                                   MEM_REGION_SIZE / PAGE_SIZE, 0);
+       gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE,
+                                MEM_REGION_GPA, MEM_REGION_SLOT);
+       TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n");
+       virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1);
+       hva = addr_gpa2hva(vm, MEM_REGION_GPA);
+       memset(hva, 0, PAGE_SIZE);
+       pte = vm_get_page_table_entry(vm, VCPU_ID, MEM_REGION_GVA);
+       vm_set_page_table_entry(vm, VCPU_ID, MEM_REGION_GVA, pte | (1ull << 36));
+
+       run_guest(vm);
+       process_exit_on_emulation_error(vm);
+       run_guest(vm);
+
+       TEST_ASSERT(process_ucall(vm) == UCALL_DONE, "Expected UCALL_DONE");
+
+       kvm_vm_free(vm);
+
+       return 0;
+}
index 63096ce..2b46dcc 100644 (file)
 
 static int ud_count;
 
-void enable_x2apic(void)
-{
-       uint32_t spiv_reg = APIC_BASE_MSR + (APIC_SPIV >> 4);
-
-       wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) |
-             MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD);
-       wrmsr(spiv_reg, rdmsr(spiv_reg) | APIC_SPIV_APIC_ENABLED);
-}
-
 static void guest_ud_handler(struct ex_regs *regs)
 {
        ud_count++;
@@ -59,7 +50,7 @@ void guest_code(struct vmx_pages *vmx_pages)
 #define L2_GUEST_STACK_SIZE 64
        unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 
-       enable_x2apic();
+       x2apic_enable();
 
        GUEST_SYNC(1);
        GUEST_SYNC(2);
@@ -121,14 +112,38 @@ void inject_nmi(struct kvm_vm *vm)
        vcpu_events_set(vm, VCPU_ID, &events);
 }
 
+static void save_restore_vm(struct kvm_vm *vm)
+{
+       struct kvm_regs regs1, regs2;
+       struct kvm_x86_state *state;
+
+       state = vcpu_save_state(vm, VCPU_ID);
+       memset(&regs1, 0, sizeof(regs1));
+       vcpu_regs_get(vm, VCPU_ID, &regs1);
+
+       kvm_vm_release(vm);
+
+       /* Restore state in a new VM.  */
+       kvm_vm_restart(vm, O_RDWR);
+       vm_vcpu_add(vm, VCPU_ID);
+       vcpu_set_hv_cpuid(vm, VCPU_ID);
+       vcpu_enable_evmcs(vm, VCPU_ID);
+       vcpu_load_state(vm, VCPU_ID, state);
+       free(state);
+
+       memset(&regs2, 0, sizeof(regs2));
+       vcpu_regs_get(vm, VCPU_ID, &regs2);
+       TEST_ASSERT(!memcmp(&regs1, &regs2, sizeof(regs2)),
+                   "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
+                   (ulong) regs2.rdi, (ulong) regs2.rsi);
+}
+
 int main(int argc, char *argv[])
 {
        vm_vaddr_t vmx_pages_gva = 0;
 
-       struct kvm_regs regs1, regs2;
        struct kvm_vm *vm;
        struct kvm_run *run;
-       struct kvm_x86_state *state;
        struct ucall uc;
        int stage;
 
@@ -145,21 +160,18 @@ int main(int argc, char *argv[])
        vcpu_set_hv_cpuid(vm, VCPU_ID);
        vcpu_enable_evmcs(vm, VCPU_ID);
 
-       run = vcpu_state(vm, VCPU_ID);
-
-       vcpu_regs_get(vm, VCPU_ID, &regs1);
-
        vcpu_alloc_vmx(vm, &vmx_pages_gva);
        vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva);
 
        vm_init_descriptor_tables(vm);
        vcpu_init_descriptor_tables(vm, VCPU_ID);
-       vm_handle_exception(vm, UD_VECTOR, guest_ud_handler);
-       vm_handle_exception(vm, NMI_VECTOR, guest_nmi_handler);
+       vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
+       vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
 
        pr_info("Running L1 which uses EVMCS to run L2\n");
 
        for (stage = 1;; stage++) {
+               run = vcpu_state(vm, VCPU_ID);
                _vcpu_run(vm, VCPU_ID);
                TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
                            "Stage %d: unexpected exit reason: %u (%s),\n",
@@ -184,32 +196,23 @@ int main(int argc, char *argv[])
                            uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx",
                            stage, (ulong)uc.args[1]);
 
-               state = vcpu_save_state(vm, VCPU_ID);
-               memset(&regs1, 0, sizeof(regs1));
-               vcpu_regs_get(vm, VCPU_ID, &regs1);
-
-               kvm_vm_release(vm);
-
-               /* Restore state in a new VM.  */
-               kvm_vm_restart(vm, O_RDWR);
-               vm_vcpu_add(vm, VCPU_ID);
-               vcpu_set_hv_cpuid(vm, VCPU_ID);
-               vcpu_enable_evmcs(vm, VCPU_ID);
-               vcpu_load_state(vm, VCPU_ID, state);
-               run = vcpu_state(vm, VCPU_ID);
-               free(state);
-
-               memset(&regs2, 0, sizeof(regs2));
-               vcpu_regs_get(vm, VCPU_ID, &regs2);
-               TEST_ASSERT(!memcmp(&regs1, &regs2, sizeof(regs2)),
-                           "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
-                           (ulong) regs2.rdi, (ulong) regs2.rsi);
+               save_restore_vm(vm);
 
                /* Force immediate L2->L1 exit before resuming */
                if (stage == 8) {
                        pr_info("Injecting NMI into L1 before L2 had a chance to run after restore\n");
                        inject_nmi(vm);
                }
+
+               /*
+                * Do KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE for a freshly
+                * restored VM (before the first KVM_RUN) to check that
+                * KVM_STATE_NESTED_EVMCS is not lost.
+                */
+               if (stage == 9) {
+                       pr_info("Trying extra KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE cycle\n");
+                       save_restore_vm(vm);
+               }
        }
 
 done:
index 8c77537..a711f83 100644 (file)
@@ -145,8 +145,7 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage)
 struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid)
 {
        int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]);
-       vm_vaddr_t gva = vm_vaddr_alloc(vm, size,
-                                       getpagesize(), 0, 0);
+       vm_vaddr_t gva = vm_vaddr_alloc(vm, size, KVM_UTIL_MIN_VADDR);
        struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva);
 
        memcpy(guest_cpuids, cpuid, size);
index 7f1d276..bab10ae 100644 (file)
@@ -7,6 +7,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "hyperv.h"
 
 struct ms_hyperv_tsc_page {
        volatile u32 tsc_sequence;
@@ -15,13 +16,6 @@ struct ms_hyperv_tsc_page {
        volatile s64 tsc_offset;
 } __packed;
 
-#define HV_X64_MSR_GUEST_OS_ID                 0x40000000
-#define HV_X64_MSR_TIME_REF_COUNT              0x40000020
-#define HV_X64_MSR_REFERENCE_TSC               0x40000021
-#define HV_X64_MSR_TSC_FREQUENCY               0x40000022
-#define HV_X64_MSR_REENLIGHTENMENT_CONTROL     0x40000106
-#define HV_X64_MSR_TSC_EMULATION_CONTROL       0x40000107
-
 /* Simplified mul_u64_u64_shr() */
 static inline u64 mul_u64_u64_shr64(u64 a, u64 b)
 {
@@ -220,7 +214,7 @@ int main(void)
 
        vcpu_set_hv_cpuid(vm, VCPU_ID);
 
-       tsc_page_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       tsc_page_gva = vm_vaddr_alloc_page(vm);
        memset(addr_gpa2hva(vm, tsc_page_gva), 0x0, getpagesize());
        TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0,
                "TSC page has to be page aligned\n");
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
new file mode 100644 (file)
index 0000000..42bd658
--- /dev/null
@@ -0,0 +1,649 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021, Red Hat, Inc.
+ *
+ * Tests for Hyper-V features enablement
+ */
+#include <asm/kvm_para.h>
+#include <linux/kvm_para.h>
+#include <stdint.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "hyperv.h"
+
+#define VCPU_ID 0
+#define LINUX_OS_ID ((u64)0x8100 << 48)
+
+extern unsigned char rdmsr_start;
+extern unsigned char rdmsr_end;
+
+static u64 do_rdmsr(u32 idx)
+{
+       u32 lo, hi;
+
+       asm volatile("rdmsr_start: rdmsr;"
+                    "rdmsr_end:"
+                    : "=a"(lo), "=c"(hi)
+                    : "c"(idx));
+
+       return (((u64) hi) << 32) | lo;
+}
+
+extern unsigned char wrmsr_start;
+extern unsigned char wrmsr_end;
+
+static void do_wrmsr(u32 idx, u64 val)
+{
+       u32 lo, hi;
+
+       lo = val;
+       hi = val >> 32;
+
+       asm volatile("wrmsr_start: wrmsr;"
+                    "wrmsr_end:"
+                    : : "a"(lo), "c"(idx), "d"(hi));
+}
+
+static int nr_gp;
+
+static inline u64 hypercall(u64 control, vm_vaddr_t input_address,
+                           vm_vaddr_t output_address)
+{
+       u64 hv_status;
+
+       asm volatile("mov %3, %%r8\n"
+                    "vmcall"
+                    : "=a" (hv_status),
+                      "+c" (control), "+d" (input_address)
+                    :  "r" (output_address)
+                    : "cc", "memory", "r8", "r9", "r10", "r11");
+
+       return hv_status;
+}
+
+static void guest_gp_handler(struct ex_regs *regs)
+{
+       unsigned char *rip = (unsigned char *)regs->rip;
+       bool r, w;
+
+       r = rip == &rdmsr_start;
+       w = rip == &wrmsr_start;
+       GUEST_ASSERT(r || w);
+
+       nr_gp++;
+
+       if (r)
+               regs->rip = (uint64_t)&rdmsr_end;
+       else
+               regs->rip = (uint64_t)&wrmsr_end;
+}
+
+struct msr_data {
+       uint32_t idx;
+       bool available;
+       bool write;
+       u64 write_val;
+};
+
+struct hcall_data {
+       uint64_t control;
+       uint64_t expect;
+};
+
+static void guest_msr(struct msr_data *msr)
+{
+       int i = 0;
+
+       while (msr->idx) {
+               WRITE_ONCE(nr_gp, 0);
+               if (!msr->write)
+                       do_rdmsr(msr->idx);
+               else
+                       do_wrmsr(msr->idx, msr->write_val);
+
+               if (msr->available)
+                       GUEST_ASSERT(READ_ONCE(nr_gp) == 0);
+               else
+                       GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
+
+               GUEST_SYNC(i++);
+       }
+
+       GUEST_DONE();
+}
+
+static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
+{
+       int i = 0;
+
+       wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID);
+       wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
+
+       while (hcall->control) {
+               GUEST_ASSERT(hypercall(hcall->control, pgs_gpa,
+                                      pgs_gpa + 4096) == hcall->expect);
+               GUEST_SYNC(i++);
+       }
+
+       GUEST_DONE();
+}
+
+static void hv_set_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid,
+                        struct kvm_cpuid_entry2 *feat,
+                        struct kvm_cpuid_entry2 *recomm,
+                        struct kvm_cpuid_entry2 *dbg)
+{
+       TEST_ASSERT(set_cpuid(cpuid, feat),
+                   "failed to set KVM_CPUID_FEATURES leaf");
+       TEST_ASSERT(set_cpuid(cpuid, recomm),
+                   "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf");
+       TEST_ASSERT(set_cpuid(cpuid, dbg),
+                   "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf");
+       vcpu_set_cpuid(vm, VCPU_ID, cpuid);
+}
+
+static void guest_test_msrs_access(struct kvm_vm *vm, struct msr_data *msr,
+                                  struct kvm_cpuid2 *best)
+{
+       struct kvm_run *run;
+       struct ucall uc;
+       int stage = 0, r;
+       struct kvm_cpuid_entry2 feat = {
+               .function = HYPERV_CPUID_FEATURES
+       };
+       struct kvm_cpuid_entry2 recomm = {
+               .function = HYPERV_CPUID_ENLIGHTMENT_INFO
+       };
+       struct kvm_cpuid_entry2 dbg = {
+               .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES
+       };
+       struct kvm_enable_cap cap = {0};
+
+       run = vcpu_state(vm, VCPU_ID);
+
+       while (true) {
+               switch (stage) {
+               case 0:
+                       /*
+                        * Only available when Hyper-V identification is set
+                        */
+                       msr->idx = HV_X64_MSR_GUEST_OS_ID;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 1:
+                       msr->idx = HV_X64_MSR_HYPERCALL;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 2:
+                       feat.eax |= HV_MSR_HYPERCALL_AVAILABLE;
+                       /*
+                        * HV_X64_MSR_GUEST_OS_ID has to be written first to make
+                        * HV_X64_MSR_HYPERCALL available.
+                        */
+                       msr->idx = HV_X64_MSR_GUEST_OS_ID;
+                       msr->write = 1;
+                       msr->write_val = LINUX_OS_ID;
+                       msr->available = 1;
+                       break;
+               case 3:
+                       msr->idx = HV_X64_MSR_GUEST_OS_ID;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 4:
+                       msr->idx = HV_X64_MSR_HYPERCALL;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+
+               case 5:
+                       msr->idx = HV_X64_MSR_VP_RUNTIME;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 6:
+                       feat.eax |= HV_MSR_VP_RUNTIME_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 7:
+                       /* Read only */
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 0;
+                       break;
+
+               case 8:
+                       msr->idx = HV_X64_MSR_TIME_REF_COUNT;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 9:
+                       feat.eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 10:
+                       /* Read only */
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 0;
+                       break;
+
+               case 11:
+                       msr->idx = HV_X64_MSR_VP_INDEX;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 12:
+                       feat.eax |= HV_MSR_VP_INDEX_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 13:
+                       /* Read only */
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 0;
+                       break;
+
+               case 14:
+                       msr->idx = HV_X64_MSR_RESET;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 15:
+                       feat.eax |= HV_MSR_RESET_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 16:
+                       msr->write = 1;
+                       msr->write_val = 0;
+                       msr->available = 1;
+                       break;
+
+               case 17:
+                       msr->idx = HV_X64_MSR_REFERENCE_TSC;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 18:
+                       feat.eax |= HV_MSR_REFERENCE_TSC_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 19:
+                       msr->write = 1;
+                       msr->write_val = 0;
+                       msr->available = 1;
+                       break;
+
+               case 20:
+                       msr->idx = HV_X64_MSR_EOM;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 21:
+                       /*
+                        * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2
+                        * capability enabled and guest visible CPUID bit unset.
+                        */
+                       cap.cap = KVM_CAP_HYPERV_SYNIC2;
+                       vcpu_enable_cap(vm, VCPU_ID, &cap);
+                       break;
+               case 22:
+                       feat.eax |= HV_MSR_SYNIC_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 23:
+                       msr->write = 1;
+                       msr->write_val = 0;
+                       msr->available = 1;
+                       break;
+
+               case 24:
+                       msr->idx = HV_X64_MSR_STIMER0_CONFIG;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 25:
+                       feat.eax |= HV_MSR_SYNTIMER_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 26:
+                       msr->write = 1;
+                       msr->write_val = 0;
+                       msr->available = 1;
+                       break;
+               case 27:
+                       /* Direct mode test */
+                       msr->write = 1;
+                       msr->write_val = 1 << 12;
+                       msr->available = 0;
+                       break;
+               case 28:
+                       feat.edx |= HV_STIMER_DIRECT_MODE_AVAILABLE;
+                       msr->available = 1;
+                       break;
+
+               case 29:
+                       msr->idx = HV_X64_MSR_EOI;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 30:
+                       feat.eax |= HV_MSR_APIC_ACCESS_AVAILABLE;
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 1;
+                       break;
+
+               case 31:
+                       msr->idx = HV_X64_MSR_TSC_FREQUENCY;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 32:
+                       feat.eax |= HV_ACCESS_FREQUENCY_MSRS;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 33:
+                       /* Read only */
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 0;
+                       break;
+
+               case 34:
+                       msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 35:
+                       feat.eax |= HV_ACCESS_REENLIGHTENMENT;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 36:
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 1;
+                       break;
+               case 37:
+                       /* Can only write '0' */
+                       msr->idx = HV_X64_MSR_TSC_EMULATION_STATUS;
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 0;
+                       break;
+
+               case 38:
+                       msr->idx = HV_X64_MSR_CRASH_P0;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 39:
+                       feat.edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 40:
+                       msr->write = 1;
+                       msr->write_val = 1;
+                       msr->available = 1;
+                       break;
+
+               case 41:
+                       msr->idx = HV_X64_MSR_SYNDBG_STATUS;
+                       msr->write = 0;
+                       msr->available = 0;
+                       break;
+               case 42:
+                       feat.edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE;
+                       dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+                       msr->write = 0;
+                       msr->available = 1;
+                       break;
+               case 43:
+                       msr->write = 1;
+                       msr->write_val = 0;
+                       msr->available = 1;
+                       break;
+
+               case 44:
+                       /* END */
+                       msr->idx = 0;
+                       break;
+               }
+
+               hv_set_cpuid(vm, best, &feat, &recomm, &dbg);
+
+               if (msr->idx)
+                       pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage,
+                                msr->idx, msr->write ? "write" : "read");
+               else
+                       pr_debug("Stage %d: finish\n", stage);
+
+               r = _vcpu_run(vm, VCPU_ID);
+               TEST_ASSERT(!r, "vcpu_run failed: %d\n", r);
+               TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                           "unexpected exit reason: %u (%s)",
+                           run->exit_reason, exit_reason_str(run->exit_reason));
+
+               switch (get_ucall(vm, VCPU_ID, &uc)) {
+               case UCALL_SYNC:
+                       TEST_ASSERT(uc.args[1] == stage,
+                                   "Unexpected stage: %ld (%d expected)\n",
+                                   uc.args[1], stage);
+                       break;
+               case UCALL_ABORT:
+                       TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
+                                 __FILE__, uc.args[1]);
+                       return;
+               case UCALL_DONE:
+                       return;
+               }
+
+               stage++;
+       }
+}
+
+static void guest_test_hcalls_access(struct kvm_vm *vm, struct hcall_data *hcall,
+                                    void *input, void *output, struct kvm_cpuid2 *best)
+{
+       struct kvm_run *run;
+       struct ucall uc;
+       int stage = 0, r;
+       struct kvm_cpuid_entry2 feat = {
+               .function = HYPERV_CPUID_FEATURES,
+               .eax = HV_MSR_HYPERCALL_AVAILABLE
+       };
+       struct kvm_cpuid_entry2 recomm = {
+               .function = HYPERV_CPUID_ENLIGHTMENT_INFO
+       };
+       struct kvm_cpuid_entry2 dbg = {
+               .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES
+       };
+
+       run = vcpu_state(vm, VCPU_ID);
+
+       while (true) {
+               switch (stage) {
+               case 0:
+                       hcall->control = 0xdeadbeef;
+                       hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE;
+                       break;
+
+               case 1:
+                       hcall->control = HVCALL_POST_MESSAGE;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 2:
+                       feat.ebx |= HV_POST_MESSAGES;
+                       hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       break;
+
+               case 3:
+                       hcall->control = HVCALL_SIGNAL_EVENT;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 4:
+                       feat.ebx |= HV_SIGNAL_EVENTS;
+                       hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       break;
+
+               case 5:
+                       hcall->control = HVCALL_RESET_DEBUG_SESSION;
+                       hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE;
+                       break;
+               case 6:
+                       dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 7:
+                       feat.ebx |= HV_DEBUGGING;
+                       hcall->expect = HV_STATUS_OPERATION_DENIED;
+                       break;
+
+               case 8:
+                       hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 9:
+                       recomm.eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED;
+                       hcall->expect = HV_STATUS_SUCCESS;
+                       break;
+               case 10:
+                       hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 11:
+                       recomm.eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED;
+                       hcall->expect = HV_STATUS_SUCCESS;
+                       break;
+
+               case 12:
+                       hcall->control = HVCALL_SEND_IPI;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 13:
+                       recomm.eax |= HV_X64_CLUSTER_IPI_RECOMMENDED;
+                       hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
+                       break;
+               case 14:
+                       /* Nothing in 'sparse banks' -> success */
+                       hcall->control = HVCALL_SEND_IPI_EX;
+                       hcall->expect = HV_STATUS_SUCCESS;
+                       break;
+
+               case 15:
+                       hcall->control = HVCALL_NOTIFY_LONG_SPIN_WAIT;
+                       hcall->expect = HV_STATUS_ACCESS_DENIED;
+                       break;
+               case 16:
+                       recomm.ebx = 0xfff;
+                       hcall->expect = HV_STATUS_SUCCESS;
+                       break;
+
+               case 17:
+                       /* END */
+                       hcall->control = 0;
+                       break;
+               }
+
+               hv_set_cpuid(vm, best, &feat, &recomm, &dbg);
+
+               if (hcall->control)
+                       pr_debug("Stage %d: testing hcall: 0x%lx\n", stage,
+                                hcall->control);
+               else
+                       pr_debug("Stage %d: finish\n", stage);
+
+               r = _vcpu_run(vm, VCPU_ID);
+               TEST_ASSERT(!r, "vcpu_run failed: %d\n", r);
+               TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                           "unexpected exit reason: %u (%s)",
+                           run->exit_reason, exit_reason_str(run->exit_reason));
+
+               switch (get_ucall(vm, VCPU_ID, &uc)) {
+               case UCALL_SYNC:
+                       TEST_ASSERT(uc.args[1] == stage,
+                                   "Unexpected stage: %ld (%d expected)\n",
+                                   uc.args[1], stage);
+                       break;
+               case UCALL_ABORT:
+                       TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
+                                 __FILE__, uc.args[1]);
+                       return;
+               case UCALL_DONE:
+                       return;
+               }
+
+               stage++;
+       }
+}
+
+int main(void)
+{
+       struct kvm_cpuid2 *best;
+       struct kvm_vm *vm;
+       vm_vaddr_t msr_gva, hcall_page, hcall_params;
+       struct kvm_enable_cap cap = {
+               .cap = KVM_CAP_HYPERV_ENFORCE_CPUID,
+               .args = {1}
+       };
+
+       /* Test MSRs */
+       vm = vm_create_default(VCPU_ID, 0, guest_msr);
+
+       msr_gva = vm_vaddr_alloc_page(vm);
+       memset(addr_gva2hva(vm, msr_gva), 0x0, getpagesize());
+       vcpu_args_set(vm, VCPU_ID, 1, msr_gva);
+       vcpu_enable_cap(vm, VCPU_ID, &cap);
+
+       vcpu_set_hv_cpuid(vm, VCPU_ID);
+
+       best = kvm_get_supported_hv_cpuid();
+
+       vm_init_descriptor_tables(vm);
+       vcpu_init_descriptor_tables(vm, VCPU_ID);
+       vm_handle_exception(vm, GP_VECTOR, guest_gp_handler);
+
+       pr_info("Testing access to Hyper-V specific MSRs\n");
+       guest_test_msrs_access(vm, addr_gva2hva(vm, msr_gva),
+                              best);
+       kvm_vm_free(vm);
+
+       /* Test hypercalls */
+       vm = vm_create_default(VCPU_ID, 0, guest_hcall);
+
+       /* Hypercall input/output */
+       hcall_page = vm_vaddr_alloc_pages(vm, 2);
+       memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize());
+
+       hcall_params = vm_vaddr_alloc_page(vm);
+       memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize());
+
+       vcpu_args_set(vm, VCPU_ID, 2, addr_gva2gpa(vm, hcall_page), hcall_params);
+       vcpu_enable_cap(vm, VCPU_ID, &cap);
+
+       vcpu_set_hv_cpuid(vm, VCPU_ID);
+
+       best = kvm_get_supported_hv_cpuid();
+
+       pr_info("Testing access to Hyper-V hypercalls\n");
+       guest_test_hcalls_access(vm, addr_gva2hva(vm, hcall_params),
+                                addr_gva2hva(vm, hcall_page),
+                                addr_gva2hva(vm, hcall_page) + getpagesize(),
+                                best);
+
+       kvm_vm_free(vm);
+}
index 732b244..04ed975 100644 (file)
@@ -227,7 +227,7 @@ int main(void)
 
        vm_init_descriptor_tables(vm);
        vcpu_init_descriptor_tables(vm, VCPU_ID);
-       vm_handle_exception(vm, GP_VECTOR, guest_gp_handler);
+       vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler);
 
        enter_guest(vm);
        kvm_vm_free(vm);
diff --git a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c
new file mode 100644 (file)
index 0000000..523371c
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "kvm_util.h"
+#include "processor.h"
+
+#define VCPU_ID                        1
+
+#define MMIO_GPA       0x100000000ull
+
+static void guest_code(void)
+{
+       (void)READ_ONCE(*((uint64_t *)MMIO_GPA));
+       (void)READ_ONCE(*((uint64_t *)MMIO_GPA));
+
+       GUEST_ASSERT(0);
+}
+
+static void guest_pf_handler(struct ex_regs *regs)
+{
+       /* PFEC == RSVD | PRESENT (read, kernel). */
+       GUEST_ASSERT(regs->error_code == 0x9);
+       GUEST_DONE();
+}
+
+static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val)
+{
+       u32 good_cpuid_val = *cpuid_reg;
+       struct kvm_run *run;
+       struct kvm_vm *vm;
+       uint64_t cmd;
+       int r;
+
+       /* Create VM */
+       vm = vm_create_default(VCPU_ID, 0, guest_code);
+       run = vcpu_state(vm, VCPU_ID);
+
+       /* Map 1gb page without a backing memlot. */
+       __virt_pg_map(vm, MMIO_GPA, MMIO_GPA, X86_PAGE_SIZE_1G);
+
+       r = _vcpu_run(vm, VCPU_ID);
+
+       /* Guest access to the 1gb page should trigger MMIO. */
+       TEST_ASSERT(r == 0, "vcpu_run failed: %d\n", r);
+       TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO,
+                   "Unexpected exit reason: %u (%s), expected MMIO exit (1gb page w/o memslot)\n",
+                   run->exit_reason, exit_reason_str(run->exit_reason));
+
+       TEST_ASSERT(run->mmio.len == 8, "Unexpected exit mmio size = %u", run->mmio.len);
+
+       TEST_ASSERT(run->mmio.phys_addr == MMIO_GPA,
+                   "Unexpected exit mmio address = 0x%llx", run->mmio.phys_addr);
+
+       /*
+        * Effect the CPUID change for the guest and re-enter the guest.  Its
+        * access should now #PF due to the PAGE_SIZE bit being reserved or
+        * the resulting GPA being invalid.  Note, kvm_get_supported_cpuid()
+        * returns the struct that contains the entry being modified.  Eww.
+        */
+       *cpuid_reg = evil_cpuid_val;
+       vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
+
+       /*
+        * Add a dummy memslot to coerce KVM into bumping the MMIO generation.
+        * KVM does not "officially" support mucking with CPUID after KVM_RUN,
+        * and will incorrectly reuse MMIO SPTEs.  Don't delete the memslot!
+        * KVM x86 zaps all shadow pages on memslot deletion.
+        */
+       vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+                                   MMIO_GPA << 1, 10, 1, 0);
+
+       /* Set up a #PF handler to eat the RSVD #PF and signal all done! */
+       vm_init_descriptor_tables(vm);
+       vcpu_init_descriptor_tables(vm, VCPU_ID);
+       vm_handle_exception(vm, PF_VECTOR, guest_pf_handler);
+
+       r = _vcpu_run(vm, VCPU_ID);
+       TEST_ASSERT(r == 0, "vcpu_run failed: %d\n", r);
+
+       cmd = get_ucall(vm, VCPU_ID, NULL);
+       TEST_ASSERT(cmd == UCALL_DONE,
+                   "Unexpected guest exit, exit_reason=%s, ucall.cmd = %lu\n",
+                   exit_reason_str(run->exit_reason), cmd);
+
+       /*
+        * Restore the happy CPUID value for the next test.  Yes, changes are
+        * indeed persistent across VM destruction.
+        */
+       *cpuid_reg = good_cpuid_val;
+
+       kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_cpuid_entry2 *entry;
+       int opt;
+
+       /*
+        * All tests are opt-in because TDP doesn't play nice with reserved #PF
+        * in the GVA->GPA translation.  The hardware page walker doesn't let
+        * software change GBPAGES or MAXPHYADDR, and KVM doesn't manually walk
+        * the GVA on fault for performance reasons.
+        */
+       bool do_gbpages = false;
+       bool do_maxphyaddr = false;
+
+       setbuf(stdout, NULL);
+
+       while ((opt = getopt(argc, argv, "gm")) != -1) {
+               switch (opt) {
+               case 'g':
+                       do_gbpages = true;
+                       break;
+               case 'm':
+                       do_maxphyaddr = true;
+                       break;
+               case 'h':
+               default:
+                       printf("usage: %s [-g (GBPAGES)] [-m (MAXPHYADDR)]\n", argv[0]);
+                       break;
+               }
+       }
+
+       if (!do_gbpages && !do_maxphyaddr) {
+               print_skip("No sub-tests selected");
+               return 0;
+       }
+
+       entry = kvm_get_supported_cpuid_entry(0x80000001);
+       if (!(entry->edx & CPUID_GBPAGES)) {
+               print_skip("1gb hugepages not supported");
+               return 0;
+       }
+
+       if (do_gbpages) {
+               pr_info("Test MMIO after toggling CPUID.GBPAGES\n\n");
+               mmu_role_test(&entry->edx, entry->edx & ~CPUID_GBPAGES);
+       }
+
+       if (do_maxphyaddr) {
+               pr_info("Test MMIO after changing CPUID.MAXPHYADDR\n\n");
+               entry = kvm_get_supported_cpuid_entry(0x80000008);
+               mmu_role_test(&entry->eax, (entry->eax & ~0xff) | 0x20);
+       }
+
+       return 0;
+}
index 12c558f..ae76436 100644 (file)
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "apic.h"
 
 #define N_VCPU 2
 #define VCPU_ID0 0
 #define VCPU_ID1 1
 
-static uint32_t get_bsp_flag(void)
-{
-       return rdmsr(MSR_IA32_APICBASE) & MSR_IA32_APICBASE_BSP;
-}
-
 static void guest_bsp_vcpu(void *arg)
 {
        GUEST_SYNC(1);
@@ -94,7 +90,7 @@ static struct kvm_vm *create_vm(void)
        pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages);
        vm = vm_create(VM_MODE_DEFAULT, pages, O_RDWR);
 
-       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       kvm_vm_elf_load(vm, program_invocation_name);
        vm_create_irqchip(vm);
 
        return vm;
@@ -106,8 +102,6 @@ static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code)
                vm_vcpu_add_default(vm, vcpuid, guest_bsp_vcpu);
        else
                vm_vcpu_add_default(vm, vcpuid, guest_not_bsp_vcpu);
-
-       vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid());
 }
 
 static void run_vm_bsp(uint32_t bsp_vcpu)
index 613c42c..c1f8318 100644 (file)
@@ -55,8 +55,8 @@ static inline void sync_with_host(uint64_t phase)
 
 void self_smi(void)
 {
-       wrmsr(APIC_BASE_MSR + (APIC_ICR >> 4),
-             APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_SMI);
+       x2apic_write_reg(APIC_ICR,
+                        APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_SMI);
 }
 
 void guest_code(void *arg)
index d672f0a..fc03a15 100644 (file)
 
 #define UCALL_PIO_PORT ((uint16_t)0x1000)
 
+struct ucall uc_none = {
+       .cmd = UCALL_NONE,
+};
+
 /*
  * ucall is embedded here to protect against compiler reshuffling registers
  * before calling a function. In this test we only need to get KVM_EXIT_IO
@@ -34,7 +38,8 @@ void guest_code(void)
        asm volatile("1: in %[port], %%al\n"
                     "add $0x1, %%rbx\n"
                     "jmp 1b"
-                    : : [port] "d" (UCALL_PIO_PORT) : "rax", "rbx");
+                    : : [port] "d" (UCALL_PIO_PORT), "D" (&uc_none)
+                    : "rax", "rbx");
 }
 
 static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
index e357d8e..5a6a662 100644 (file)
 #define rounded_rdmsr(x)       ROUND(rdmsr(x))
 #define rounded_host_rdmsr(x)  ROUND(vcpu_get_msr(vm, 0, x))
 
-#define GUEST_ASSERT_EQ(a, b) do {                             \
-       __typeof(a) _a = (a);                                   \
-       __typeof(b) _b = (b);                                   \
-       if (_a != _b)                                           \
-                ucall(UCALL_ABORT, 4,                          \
-                        "Failed guest assert: "                        \
-                        #a " == " #b, __LINE__, _a, _b);       \
-  } while(0)
-
 static void guest_code(void)
 {
        u64 val = 0;
index 72c0d07..e3e20e8 100644 (file)
@@ -574,7 +574,7 @@ static void test_msr_filter_allow(void) {
        vm_init_descriptor_tables(vm);
        vcpu_init_descriptor_tables(vm, VCPU_ID);
 
-       vm_handle_exception(vm, GP_VECTOR, guest_gp_handler);
+       vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler);
 
        /* Process guest code userspace exits. */
        run_guest_then_process_rdmsr(vm, MSR_IA32_XSS);
@@ -588,12 +588,12 @@ static void test_msr_filter_allow(void) {
        run_guest_then_process_wrmsr(vm, MSR_NON_EXISTENT);
        run_guest_then_process_rdmsr(vm, MSR_NON_EXISTENT);
 
-       vm_handle_exception(vm, UD_VECTOR, guest_ud_handler);
+       vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
        run_guest(vm);
-       vm_handle_exception(vm, UD_VECTOR, NULL);
+       vm_install_exception_handler(vm, UD_VECTOR, NULL);
 
        if (process_ucall(vm) != UCALL_DONE) {
-               vm_handle_exception(vm, GP_VECTOR, guest_fep_gp_handler);
+               vm_install_exception_handler(vm, GP_VECTOR, guest_fep_gp_handler);
 
                /* Process emulated rdmsr and wrmsr instructions. */
                run_guest_then_process_rdmsr(vm, MSR_IA32_XSS);
index d14888b..d438c4d 100644 (file)
@@ -96,7 +96,7 @@ int main(int argc, char *argv[])
        }
 
        vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva);
-       prepare_virtualize_apic_accesses(vmx, vm, 0);
+       prepare_virtualize_apic_accesses(vmx, vm);
        vcpu_args_set(vm, VCPU_ID, 2, vmx_pages_gva, high_gpa);
 
        while (!done) {
index 537de10..06a6498 100644 (file)
@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
         * Add an identity map for GVA range [0xc0000000, 0xc0002000).  This
         * affects both L1 and L2.  However...
         */
-       virt_map(vm, GUEST_TEST_MEM, GUEST_TEST_MEM, TEST_MEM_PAGES, 0);
+       virt_map(vm, GUEST_TEST_MEM, GUEST_TEST_MEM, TEST_MEM_PAGES);
 
        /*
         * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to
@@ -107,9 +107,9 @@ int main(int argc, char *argv[])
         * meaning after the last call to virt_map.
         */
        prepare_eptp(vmx, vm, 0);
-       nested_map_memslot(vmx, vm, 0, 0);
-       nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096, 0);
-       nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096, 0);
+       nested_map_memslot(vmx, vm, 0);
+       nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096);
+       nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096);
 
        bmap = bitmap_alloc(TEST_MEM_PAGES);
        host_test_mem = addr_gpa2hva(vm, GUEST_TEST_MEM);
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c
new file mode 100644 (file)
index 0000000..280c01f
--- /dev/null
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vmx_nested_tsc_scaling_test
+ *
+ * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * This test case verifies that nested TSC scaling behaves as expected when
+ * both L1 and L2 are scaled using different ratios. For this test we scale
+ * L1 down and scale L2 up.
+ */
+
+#include <time.h>
+
+#include "kvm_util.h"
+#include "vmx.h"
+#include "kselftest.h"
+
+
+#define VCPU_ID 0
+
+/* L2 is scaled up (from L1's perspective) by this factor */
+#define L2_SCALE_FACTOR 4ULL
+
+#define TSC_OFFSET_L2 ((uint64_t) -33125236320908)
+#define TSC_MULTIPLIER_L2 (L2_SCALE_FACTOR << 48)
+
+#define L2_GUEST_STACK_SIZE 64
+
+enum { USLEEP, UCHECK_L1, UCHECK_L2 };
+#define GUEST_SLEEP(sec)         ucall(UCALL_SYNC, 2, USLEEP, sec)
+#define GUEST_CHECK(level, freq) ucall(UCALL_SYNC, 2, level, freq)
+
+
+/*
+ * This function checks whether the "actual" TSC frequency of a guest matches
+ * its expected frequency. In order to account for delays in taking the TSC
+ * measurements, a difference of 1% between the actual and the expected value
+ * is tolerated.
+ */
+static void compare_tsc_freq(uint64_t actual, uint64_t expected)
+{
+       uint64_t tolerance, thresh_low, thresh_high;
+
+       tolerance = expected / 100;
+       thresh_low = expected - tolerance;
+       thresh_high = expected + tolerance;
+
+       TEST_ASSERT(thresh_low < actual,
+               "TSC freq is expected to be between %"PRIu64" and %"PRIu64
+               " but it actually is %"PRIu64,
+               thresh_low, thresh_high, actual);
+       TEST_ASSERT(thresh_high > actual,
+               "TSC freq is expected to be between %"PRIu64" and %"PRIu64
+               " but it actually is %"PRIu64,
+               thresh_low, thresh_high, actual);
+}
+
+static void check_tsc_freq(int level)
+{
+       uint64_t tsc_start, tsc_end, tsc_freq;
+
+       /*
+        * Reading the TSC twice with about a second's difference should give
+        * us an approximation of the TSC frequency from the guest's
+        * perspective. Now, this won't be completely accurate, but it should
+        * be good enough for the purposes of this test.
+        */
+       tsc_start = rdmsr(MSR_IA32_TSC);
+       GUEST_SLEEP(1);
+       tsc_end = rdmsr(MSR_IA32_TSC);
+
+       tsc_freq = tsc_end - tsc_start;
+
+       GUEST_CHECK(level, tsc_freq);
+}
+
+static void l2_guest_code(void)
+{
+       check_tsc_freq(UCHECK_L2);
+
+       /* exit to L1 */
+       __asm__ __volatile__("vmcall");
+}
+
+static void l1_guest_code(struct vmx_pages *vmx_pages)
+{
+       unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+       uint32_t control;
+
+       /* check that L1's frequency looks alright before launching L2 */
+       check_tsc_freq(UCHECK_L1);
+
+       GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
+       GUEST_ASSERT(load_vmcs(vmx_pages));
+
+       /* prepare the VMCS for L2 execution */
+       prepare_vmcs(vmx_pages, l2_guest_code, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+       /* enable TSC offsetting and TSC scaling for L2 */
+       control = vmreadz(CPU_BASED_VM_EXEC_CONTROL);
+       control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING;
+       vmwrite(CPU_BASED_VM_EXEC_CONTROL, control);
+
+       control = vmreadz(SECONDARY_VM_EXEC_CONTROL);
+       control |= SECONDARY_EXEC_TSC_SCALING;
+       vmwrite(SECONDARY_VM_EXEC_CONTROL, control);
+
+       vmwrite(TSC_OFFSET, TSC_OFFSET_L2);
+       vmwrite(TSC_MULTIPLIER, TSC_MULTIPLIER_L2);
+       vmwrite(TSC_MULTIPLIER_HIGH, TSC_MULTIPLIER_L2 >> 32);
+
+       /* launch L2 */
+       GUEST_ASSERT(!vmlaunch());
+       GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
+
+       /* check that L1's frequency still looks good */
+       check_tsc_freq(UCHECK_L1);
+
+       GUEST_DONE();
+}
+
+static void tsc_scaling_check_supported(void)
+{
+       if (!kvm_check_cap(KVM_CAP_TSC_CONTROL)) {
+               print_skip("TSC scaling not supported by the HW");
+               exit(KSFT_SKIP);
+       }
+}
+
+static void stable_tsc_check_supported(void)
+{
+       FILE *fp;
+       char buf[4];
+
+       fp = fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "r");
+       if (fp == NULL)
+               goto skip_test;
+
+       if (fgets(buf, sizeof(buf), fp) == NULL)
+               goto skip_test;
+
+       if (strncmp(buf, "tsc", sizeof(buf)))
+               goto skip_test;
+
+       return;
+skip_test:
+       print_skip("Kernel does not use TSC clocksource - assuming that host TSC is not stable");
+       exit(KSFT_SKIP);
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_vm *vm;
+       vm_vaddr_t vmx_pages_gva;
+
+       uint64_t tsc_start, tsc_end;
+       uint64_t tsc_khz;
+       uint64_t l1_scale_factor;
+       uint64_t l0_tsc_freq = 0;
+       uint64_t l1_tsc_freq = 0;
+       uint64_t l2_tsc_freq = 0;
+
+       nested_vmx_check_supported();
+       tsc_scaling_check_supported();
+       stable_tsc_check_supported();
+
+       /*
+        * We set L1's scale factor to be a random number from 2 to 10.
+        * Ideally we would do the same for L2's factor but that one is
+        * referenced by both main() and l1_guest_code() and using a global
+        * variable does not work.
+        */
+       srand(time(NULL));
+       l1_scale_factor = (rand() % 9) + 2;
+       printf("L1's scale down factor is: %"PRIu64"\n", l1_scale_factor);
+       printf("L2's scale up factor is: %llu\n", L2_SCALE_FACTOR);
+
+       tsc_start = rdtsc();
+       sleep(1);
+       tsc_end = rdtsc();
+
+       l0_tsc_freq = tsc_end - tsc_start;
+       printf("real TSC frequency is around: %"PRIu64"\n", l0_tsc_freq);
+
+       vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code);
+       vcpu_alloc_vmx(vm, &vmx_pages_gva);
+       vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva);
+
+       tsc_khz = _vcpu_ioctl(vm, VCPU_ID, KVM_GET_TSC_KHZ, NULL);
+       TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed");
+
+       /* scale down L1's TSC frequency */
+       vcpu_ioctl(vm, VCPU_ID, KVM_SET_TSC_KHZ,
+                 (void *) (tsc_khz / l1_scale_factor));
+
+       for (;;) {
+               volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
+               struct ucall uc;
+
+               vcpu_run(vm, VCPU_ID);
+               TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                           "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
+                           run->exit_reason,
+                           exit_reason_str(run->exit_reason));
+
+               switch (get_ucall(vm, VCPU_ID, &uc)) {
+               case UCALL_ABORT:
+                       TEST_FAIL("%s", (const char *) uc.args[0]);
+               case UCALL_SYNC:
+                       switch (uc.args[0]) {
+                       case USLEEP:
+                               sleep(uc.args[1]);
+                               break;
+                       case UCHECK_L1:
+                               l1_tsc_freq = uc.args[1];
+                               printf("L1's TSC frequency is around: %"PRIu64
+                                      "\n", l1_tsc_freq);
+
+                               compare_tsc_freq(l1_tsc_freq,
+                                                l0_tsc_freq / l1_scale_factor);
+                               break;
+                       case UCHECK_L2:
+                               l2_tsc_freq = uc.args[1];
+                               printf("L2's TSC frequency is around: %"PRIu64
+                                      "\n", l2_tsc_freq);
+
+                               compare_tsc_freq(l2_tsc_freq,
+                                                l1_tsc_freq * L2_SCALE_FACTOR);
+                               break;
+                       }
+                       break;
+               case UCALL_DONE:
+                       goto done;
+               default:
+                       TEST_FAIL("Unknown ucall %lu", uc.cmd);
+               }
+       }
+
+done:
+       kvm_vm_free(vm);
+       return 0;
+}
index 2f964cd..afbbc40 100644 (file)
@@ -42,8 +42,6 @@
 #define HALTER_VCPU_ID 0
 #define SENDER_VCPU_ID 1
 
-volatile uint32_t *apic_base = (volatile uint32_t *)APIC_DEFAULT_GPA;
-
 /*
  * Vector for IPI from sender vCPU to halting vCPU.
  * Value is arbitrary and was chosen for the alternating bit pattern. Any
@@ -86,45 +84,6 @@ struct thread_params {
        uint64_t *pipis_rcvd; /* host address of ipis_rcvd global */
 };
 
-uint32_t read_apic_reg(uint reg)
-{
-       return apic_base[reg >> 2];
-}
-
-void write_apic_reg(uint reg, uint32_t val)
-{
-       apic_base[reg >> 2] = val;
-}
-
-void disable_apic(void)
-{
-       wrmsr(MSR_IA32_APICBASE,
-             rdmsr(MSR_IA32_APICBASE) &
-               ~(MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD));
-}
-
-void enable_xapic(void)
-{
-       uint64_t val = rdmsr(MSR_IA32_APICBASE);
-
-       /* Per SDM: to enable xAPIC when in x2APIC must first disable APIC */
-       if (val & MSR_IA32_APICBASE_EXTD) {
-               disable_apic();
-               wrmsr(MSR_IA32_APICBASE,
-                     rdmsr(MSR_IA32_APICBASE) | MSR_IA32_APICBASE_ENABLE);
-       } else if (!(val & MSR_IA32_APICBASE_ENABLE)) {
-               wrmsr(MSR_IA32_APICBASE, val | MSR_IA32_APICBASE_ENABLE);
-       }
-
-       /*
-        * Per SDM: reset value of spurious interrupt vector register has the
-        * APIC software enabled bit=0. It must be enabled in addition to the
-        * enable bit in the MSR.
-        */
-       val = read_apic_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED;
-       write_apic_reg(APIC_SPIV, val);
-}
-
 void verify_apic_base_addr(void)
 {
        uint64_t msr = rdmsr(MSR_IA32_APICBASE);
@@ -136,10 +95,10 @@ void verify_apic_base_addr(void)
 static void halter_guest_code(struct test_data_page *data)
 {
        verify_apic_base_addr();
-       enable_xapic();
+       xapic_enable();
 
-       data->halter_apic_id = GET_APIC_ID_FIELD(read_apic_reg(APIC_ID));
-       data->halter_lvr = read_apic_reg(APIC_LVR);
+       data->halter_apic_id = GET_APIC_ID_FIELD(xapic_read_reg(APIC_ID));
+       data->halter_lvr = xapic_read_reg(APIC_LVR);
 
        /*
         * Loop forever HLTing and recording halts & wakes. Disable interrupts
@@ -150,8 +109,8 @@ static void halter_guest_code(struct test_data_page *data)
         * TPR and PPR for diagnostic purposes in case the test fails.
         */
        for (;;) {
-               data->halter_tpr = read_apic_reg(APIC_TASKPRI);
-               data->halter_ppr = read_apic_reg(APIC_PROCPRI);
+               data->halter_tpr = xapic_read_reg(APIC_TASKPRI);
+               data->halter_ppr = xapic_read_reg(APIC_PROCPRI);
                data->hlt_count++;
                asm volatile("sti; hlt; cli");
                data->wake_count++;
@@ -166,7 +125,7 @@ static void halter_guest_code(struct test_data_page *data)
 static void guest_ipi_handler(struct ex_regs *regs)
 {
        ipis_rcvd++;
-       write_apic_reg(APIC_EOI, 77);
+       xapic_write_reg(APIC_EOI, 77);
 }
 
 static void sender_guest_code(struct test_data_page *data)
@@ -179,7 +138,7 @@ static void sender_guest_code(struct test_data_page *data)
        uint64_t tsc_start;
 
        verify_apic_base_addr();
-       enable_xapic();
+       xapic_enable();
 
        /*
         * Init interrupt command register for sending IPIs
@@ -206,8 +165,8 @@ static void sender_guest_code(struct test_data_page *data)
                 * First IPI can be sent unconditionally because halter vCPU
                 * starts earlier.
                 */
-               write_apic_reg(APIC_ICR2, icr2_val);
-               write_apic_reg(APIC_ICR, icr_val);
+               xapic_write_reg(APIC_ICR2, icr2_val);
+               xapic_write_reg(APIC_ICR, icr_val);
                data->ipis_sent++;
 
                /*
@@ -462,13 +421,13 @@ int main(int argc, char *argv[])
 
        vm_init_descriptor_tables(vm);
        vcpu_init_descriptor_tables(vm, HALTER_VCPU_ID);
-       vm_handle_exception(vm, IPI_VECTOR, guest_ipi_handler);
+       vm_install_exception_handler(vm, IPI_VECTOR, guest_ipi_handler);
 
-       virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA, 0);
+       virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
 
        vm_vcpu_add_default(vm, SENDER_VCPU_ID, sender_guest_code);
 
-       test_data_page_vaddr = vm_vaddr_alloc(vm, 0x1000, 0x1000, 0, 0);
+       test_data_page_vaddr = vm_vaddr_alloc_page(vm);
        data =
           (struct test_data_page *)addr_gva2hva(vm, test_data_page_vaddr);
        memset(data, 0, sizeof(*data));
index 1f4a059..117bf49 100644 (file)
@@ -146,7 +146,7 @@ int main(int argc, char *argv[])
        /* Map a region for the shared_info page */
        vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
                                    SHINFO_REGION_GPA, SHINFO_REGION_SLOT, 2, 0);
-       virt_map(vm, SHINFO_REGION_GVA, SHINFO_REGION_GPA, 2, 0);
+       virt_map(vm, SHINFO_REGION_GVA, SHINFO_REGION_GPA, 2);
 
        struct kvm_xen_hvm_config hvmc = {
                .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
index 8389e0b..adc9445 100644 (file)
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
        /* Map a region for the hypercall pages */
        vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
                                    HCALL_REGION_GPA, HCALL_REGION_SLOT, 2, 0);
-       virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 2, 0);
+       virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 2);
 
        for (;;) {
                volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID);
index a105f09..ee71fc9 100644 (file)
@@ -4,6 +4,6 @@
 # No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
 all:
 
-TEST_PROGS := printf.sh bitmap.sh prime_numbers.sh strscpy.sh
+TEST_PROGS := printf.sh bitmap.sh prime_numbers.sh scanf.sh strscpy.sh
 
 include ../lib.mk
index b80ee3f..645839b 100644 (file)
@@ -1,4 +1,5 @@
 CONFIG_TEST_PRINTF=m
+CONFIG_TEST_SCANF=m
 CONFIG_TEST_BITMAP=m
 CONFIG_PRIME_NUMBERS=m
 CONFIG_TEST_STRSCPY=m
diff --git a/tools/testing/selftests/lib/scanf.sh b/tools/testing/selftests/lib/scanf.sh
new file mode 100755 (executable)
index 0000000..b59b8ba
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Tests the scanf infrastructure using test_scanf kernel module.
+$(dirname $0)/../kselftest/module.sh "scanf" test_scanf
index 76d9487..5abe92d 100755 (executable)
@@ -1384,12 +1384,37 @@ ipv4_rt_replace()
        ipv4_rt_replace_mpath
 }
 
+# checks that cached input route on VRF port is deleted
+# when VRF is deleted
+ipv4_local_rt_cache()
+{
+       run_cmd "ip addr add 10.0.0.1/32 dev lo"
+       run_cmd "ip netns add test-ns"
+       run_cmd "ip link add veth-outside type veth peer name veth-inside"
+       run_cmd "ip link add vrf-100 type vrf table 1100"
+       run_cmd "ip link set veth-outside master vrf-100"
+       run_cmd "ip link set veth-inside netns test-ns"
+       run_cmd "ip link set veth-outside up"
+       run_cmd "ip link set vrf-100 up"
+       run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
+       run_cmd "ip netns exec test-ns ip link set veth-inside up"
+       run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
+       run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
+       run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
+       run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
+       run_cmd "ip link delete vrf-100"
+
+       # if we do not hang test is a success
+       log_test $? 0 "Cached route removed from VRF port device"
+}
+
 ipv4_route_test()
 {
        route_setup
 
        ipv4_rt_add
        ipv4_rt_replace
+       ipv4_local_rt_cache
 
        route_cleanup
 }
diff --git a/tools/testing/selftests/net/icmp.sh b/tools/testing/selftests/net/icmp.sh
new file mode 100755 (executable)
index 0000000..e4b04cd
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Test for checking ICMP response with dummy address instead of 0.0.0.0.
+# Sets up two namespaces like:
+# +----------------------+                          +--------------------+
+# | ns1                  |    v4-via-v6 routes:     | ns2                |
+# |                      |                  '       |                    |
+# |             +--------+   -> 172.16.1.0/24 ->    +--------+           |
+# |             | veth0  +--------------------------+  veth0 |           |
+# |             +--------+   <- 172.16.0.0/24 <-    +--------+           |
+# |           172.16.0.1 |                          | 2001:db8:1::2/64   |
+# |     2001:db8:1::2/64 |                          |                    |
+# +----------------------+                          +--------------------+
+#
+# And then tries to ping 172.16.1.1 from ns1. This results in a "net
+# unreachable" message being sent from ns2, but there is no IPv4 address set in
+# that address space, so the kernel should substitute the dummy address
+# 192.0.0.8 defined in RFC7600.
+
+NS1=ns1
+NS2=ns2
+H1_IP=172.16.0.1/32
+H1_IP6=2001:db8:1::1
+RT1=172.16.1.0/24
+PINGADDR=172.16.1.1
+RT2=172.16.0.0/24
+H2_IP6=2001:db8:1::2
+
+TMPFILE=$(mktemp)
+
+cleanup()
+{
+    rm -f "$TMPFILE"
+    ip netns del $NS1
+    ip netns del $NS2
+}
+
+trap cleanup EXIT
+
+# Namespaces
+ip netns add $NS1
+ip netns add $NS2
+
+# Connectivity
+ip -netns $NS1 link add veth0 type veth peer name veth0 netns $NS2
+ip -netns $NS1 link set dev veth0 up
+ip -netns $NS2 link set dev veth0 up
+ip -netns $NS1 addr add $H1_IP dev veth0
+ip -netns $NS1 addr add $H1_IP6/64 dev veth0 nodad
+ip -netns $NS2 addr add $H2_IP6/64 dev veth0 nodad
+ip -netns $NS1 route add $RT1 via inet6 $H2_IP6
+ip -netns $NS2 route add $RT2 via inet6 $H1_IP6
+
+# Make sure ns2 will respond with ICMP unreachable
+ip netns exec $NS2 sysctl -qw net.ipv4.icmp_ratelimit=0 net.ipv4.ip_forward=1
+
+# Run the test - a ping runs in the background, and we capture ICMP responses
+# with tcpdump; -c 1 means it should exit on the first ping, but add a timeout
+# in case something goes wrong
+ip netns exec $NS1 ping -w 3 -i 0.5 $PINGADDR >/dev/null &
+ip netns exec $NS1 timeout 10 tcpdump -tpni veth0 -c 1 'icmp and icmp[icmptype] != icmp-echo' > $TMPFILE 2>/dev/null
+
+# Parse response and check for dummy address
+# tcpdump output looks like:
+# IP 192.0.0.8 > 172.16.0.1: ICMP net 172.16.1.1 unreachable, length 92
+RESP_IP=$(awk '{print $2}' < $TMPFILE)
+if [[ "$RESP_IP" != "192.0.0.8" ]]; then
+    echo "FAIL - got ICMP response from $RESP_IP, should be 192.0.0.8"
+    exit 1
+else
+    echo "OK"
+    exit 0
+fi
index 9ca5f1b..2b495dc 100755 (executable)
@@ -197,9 +197,6 @@ ip -net "$ns4" link set ns4eth3 up
 ip -net "$ns4" route add default via 10.0.3.2
 ip -net "$ns4" route add default via dead:beef:3::2
 
-# use TCP syn cookies, even if no flooding was detected.
-ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2
-
 set_ethtool_flags() {
        local ns="$1"
        local dev="$2"
@@ -737,6 +734,14 @@ for sender in $ns1 $ns2 $ns3 $ns4;do
                exit $ret
        fi
 
+       # ns1<->ns2 is not subject to reordering/tc delays. Use it to test
+       # mptcp syncookie support.
+       if [ $sender = $ns1 ]; then
+               ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2
+       else
+               ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=1
+       fi
+
        run_tests "$ns2" $sender 10.0.1.2
        run_tests "$ns2" $sender dead:beef:1::2
        run_tests "$ns2" $sender 10.0.2.1
index a8fa641..7f26591 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
 readonly BASE="ns-$(mktemp -u XXXXXX)"
index 2fedc07..11d7cdb 100755 (executable)
@@ -18,7 +18,8 @@ ret=0
 
 cleanup() {
        local ns
-       local -r jobs="$(jobs -p)"
+       local jobs
+       readonly jobs="$(jobs -p)"
        [ -n "${jobs}" ] && kill -1 ${jobs} 2>/dev/null
        rm -f $STATS
 
@@ -108,7 +109,7 @@ chk_gro() {
 
 if [ ! -f ../bpf/xdp_dummy.o ]; then
        echo "Missing xdp_dummy helper. Build bpf selftest first"
-       exit -1
+       exit 1
 fi
 
 create_ns
index 3171069..cd6430b 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for netfilter selftests
 
-TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
+TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
        conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
        nft_concat_range.sh nft_conntrack_helper.sh \
        nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
diff --git a/tools/testing/selftests/netfilter/nft_fib.sh b/tools/testing/selftests/netfilter/nft_fib.sh
new file mode 100755 (executable)
index 0000000..6caf6ac
--- /dev/null
@@ -0,0 +1,221 @@
+#!/bin/bash
+#
+# This tests the fib expression.
+#
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+ret=0
+
+sfx=$(mktemp -u "XXXXXXXX")
+ns1="ns1-$sfx"
+ns2="ns2-$sfx"
+nsrouter="nsrouter-$sfx"
+timeout=4
+
+log_netns=$(sysctl -n net.netfilter.nf_log_all_netns)
+
+cleanup()
+{
+       ip netns del ${ns1}
+       ip netns del ${ns2}
+       ip netns del ${nsrouter}
+
+       [ $log_netns -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns=$log_netns
+}
+
+nft --version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without nft tool"
+       exit $ksft_skip
+fi
+
+ip -Version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ip tool"
+       exit $ksft_skip
+fi
+
+ip netns add ${nsrouter}
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not create net namespace"
+       exit $ksft_skip
+fi
+
+trap cleanup EXIT
+
+dmesg | grep -q ' nft_rpfilter: '
+if [ $? -eq 0 ]; then
+       dmesg -c | grep ' nft_rpfilter: '
+       echo "WARN: a previous test run has failed" 1>&2
+fi
+
+sysctl -q net.netfilter.nf_log_all_netns=1
+ip netns add ${ns1}
+ip netns add ${ns2}
+
+load_ruleset() {
+       local netns=$1
+
+ip netns exec ${netns} nft -f /dev/stdin <<EOF
+table inet filter {
+       chain prerouting {
+               type filter hook prerouting priority 0; policy accept;
+               fib saddr . iif oif missing counter log prefix "$netns nft_rpfilter: " drop
+       }
+}
+EOF
+}
+
+load_ruleset_count() {
+       local netns=$1
+
+ip netns exec ${netns} nft -f /dev/stdin <<EOF
+table inet filter {
+       chain prerouting {
+               type filter hook prerouting priority 0; policy accept;
+               ip daddr 1.1.1.1 fib saddr . iif oif missing counter drop
+               ip6 daddr 1c3::c01d fib saddr . iif oif missing counter drop
+       }
+}
+EOF
+}
+
+check_drops() {
+       dmesg | grep -q ' nft_rpfilter: '
+       if [ $? -eq 0 ]; then
+               dmesg | grep ' nft_rpfilter: '
+               echo "FAIL: rpfilter did drop packets"
+               return 1
+       fi
+
+       return 0
+}
+
+check_fib_counter() {
+       local want=$1
+       local ns=$2
+       local address=$3
+
+       line=$(ip netns exec ${ns} nft list table inet filter | grep 'fib saddr . iif' | grep $address | grep "packets $want" )
+       ret=$?
+
+       if [ $ret -ne 0 ];then
+               echo "Netns $ns fib counter doesn't match expected packet count of $want for $address" 1>&2
+               ip netns exec ${ns} nft list table inet filter
+               return 1
+       fi
+
+       if [ $want -gt 0 ]; then
+               echo "PASS: fib expression did drop packets for $address"
+       fi
+
+       return 0
+}
+
+load_ruleset ${nsrouter}
+load_ruleset ${ns1}
+load_ruleset ${ns2}
+
+ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1
+if [ $? -ne 0 ];then
+    echo "SKIP: No virtual ethernet pair device support in kernel"
+    exit $ksft_skip
+fi
+ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2}
+
+ip -net ${nsrouter} link set lo up
+ip -net ${nsrouter} link set veth0 up
+ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0
+ip -net ${nsrouter} addr add dead:1::1/64 dev veth0
+
+ip -net ${nsrouter} link set veth1 up
+ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1
+ip -net ${nsrouter} addr add dead:2::1/64 dev veth1
+
+ip -net ${ns1} link set lo up
+ip -net ${ns1} link set eth0 up
+
+ip -net ${ns2} link set lo up
+ip -net ${ns2} link set eth0 up
+
+ip -net ${ns1} addr add 10.0.1.99/24 dev eth0
+ip -net ${ns1} addr add dead:1::99/64 dev eth0
+ip -net ${ns1} route add default via 10.0.1.1
+ip -net ${ns1} route add default via dead:1::1
+
+ip -net ${ns2} addr add 10.0.2.99/24 dev eth0
+ip -net ${ns2} addr add dead:2::99/64 dev eth0
+ip -net ${ns2} route add default via 10.0.2.1
+ip -net ${ns2} route add default via dead:2::1
+
+test_ping() {
+  local daddr4=$1
+  local daddr6=$2
+
+  ip netns exec ${ns1} ping -c 1 -q $daddr4 > /dev/null
+  ret=$?
+  if [ $ret -ne 0 ];then
+       check_drops
+       echo "FAIL: ${ns1} cannot reach $daddr4, ret $ret" 1>&2
+       return 1
+  fi
+
+  ip netns exec ${ns1} ping -c 3 -q $daddr6 > /dev/null
+  ret=$?
+  if [ $ret -ne 0 ];then
+       check_drops
+       echo "FAIL: ${ns1} cannot reach $daddr6, ret $ret" 1>&2
+       return 1
+  fi
+
+  return 0
+}
+
+ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
+ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+
+sleep 3
+
+test_ping 10.0.2.1 dead:2::1 || exit 1
+check_drops || exit 1
+
+test_ping 10.0.2.99 dead:2::99 || exit 1
+check_drops || exit 1
+
+echo "PASS: fib expression did not cause unwanted packet drops"
+
+ip netns exec ${nsrouter} nft flush table inet filter
+
+ip -net ${ns1} route del default
+ip -net ${ns1} -6 route del default
+
+ip -net ${ns1} addr del 10.0.1.99/24 dev eth0
+ip -net ${ns1} addr del dead:1::99/64 dev eth0
+
+ip -net ${ns1} addr add 10.0.2.99/24 dev eth0
+ip -net ${ns1} addr add dead:2::99/64 dev eth0
+
+ip -net ${ns1} route add default via 10.0.2.1
+ip -net ${ns1} -6 route add default via dead:2::1
+
+ip -net ${nsrouter} addr add dead:2::1/64 dev veth0
+
+# switch to ruleset that doesn't log, this time
+# its expected that this does drop the packets.
+load_ruleset_count ${nsrouter}
+
+# ns1 has a default route, but nsrouter does not.
+# must not check return value, ping to 1.1.1.1 will
+# fail.
+check_fib_counter 0 ${nsrouter} 1.1.1.1 || exit 1
+check_fib_counter 0 ${nsrouter} 1c3::c01d || exit 1
+
+ip netns exec ${ns1} ping -c 1 -W 1 -q 1.1.1.1 > /dev/null
+check_fib_counter 1 ${nsrouter} 1.1.1.1 || exit 1
+
+sleep 2
+ip netns exec ${ns1} ping -c 3 -q 1c3::c01d > /dev/null
+check_fib_counter 3 ${nsrouter} 1c3::c01d || exit 1
+
+exit 0
diff --git a/tools/testing/selftests/rlimits/.gitignore b/tools/testing/selftests/rlimits/.gitignore
new file mode 100644 (file)
index 0000000..091021f
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+rlimits-per-userns
diff --git a/tools/testing/selftests/rlimits/Makefile b/tools/testing/selftests/rlimits/Makefile
new file mode 100644 (file)
index 0000000..03aadb4
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+CFLAGS += -Wall -O2 -g
+TEST_GEN_PROGS := rlimits-per-userns
+
+include ../lib.mk
diff --git a/tools/testing/selftests/rlimits/config b/tools/testing/selftests/rlimits/config
new file mode 100644 (file)
index 0000000..416bd53
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_USER_NS=y
diff --git a/tools/testing/selftests/rlimits/rlimits-per-userns.c b/tools/testing/selftests/rlimits/rlimits-per-userns.c
new file mode 100644 (file)
index 0000000..26dc949
--- /dev/null
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Author: Alexey Gladkov <gladkov.alexey@gmail.com>
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sched.h>
+#include <signal.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+
+#define NR_CHILDS 2
+
+static char *service_prog;
+static uid_t user   = 60000;
+static uid_t group  = 60000;
+
+static void setrlimit_nproc(rlim_t n)
+{
+       pid_t pid = getpid();
+       struct rlimit limit = {
+               .rlim_cur = n,
+               .rlim_max = n
+       };
+
+       warnx("(pid=%d): Setting RLIMIT_NPROC=%ld", pid, n);
+
+       if (setrlimit(RLIMIT_NPROC, &limit) < 0)
+               err(EXIT_FAILURE, "(pid=%d): setrlimit(RLIMIT_NPROC)", pid);
+}
+
+static pid_t fork_child(void)
+{
+       pid_t pid = fork();
+
+       if (pid < 0)
+               err(EXIT_FAILURE, "fork");
+
+       if (pid > 0)
+               return pid;
+
+       pid = getpid();
+
+       warnx("(pid=%d): New process starting ...", pid);
+
+       if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
+               err(EXIT_FAILURE, "(pid=%d): prctl(PR_SET_PDEATHSIG)", pid);
+
+       signal(SIGUSR1, SIG_DFL);
+
+       warnx("(pid=%d): Changing to uid=%d, gid=%d", pid, user, group);
+
+       if (setgid(group) < 0)
+               err(EXIT_FAILURE, "(pid=%d): setgid(%d)", pid, group);
+       if (setuid(user) < 0)
+               err(EXIT_FAILURE, "(pid=%d): setuid(%d)", pid, user);
+
+       warnx("(pid=%d): Service running ...", pid);
+
+       warnx("(pid=%d): Unshare user namespace", pid);
+       if (unshare(CLONE_NEWUSER) < 0)
+               err(EXIT_FAILURE, "unshare(CLONE_NEWUSER)");
+
+       char *const argv[] = { "service", NULL };
+       char *const envp[] = { "I_AM_SERVICE=1", NULL };
+
+       warnx("(pid=%d): Executing real service ...", pid);
+
+       execve(service_prog, argv, envp);
+       err(EXIT_FAILURE, "(pid=%d): execve", pid);
+}
+
+int main(int argc, char **argv)
+{
+       size_t i;
+       pid_t child[NR_CHILDS];
+       int wstatus[NR_CHILDS];
+       int childs = NR_CHILDS;
+       pid_t pid;
+
+       if (getenv("I_AM_SERVICE")) {
+               pause();
+               exit(EXIT_SUCCESS);
+       }
+
+       service_prog = argv[0];
+       pid = getpid();
+
+       warnx("(pid=%d) Starting testcase", pid);
+
+       /*
+        * This rlimit is not a problem for root because it can be exceeded.
+        */
+       setrlimit_nproc(1);
+
+       for (i = 0; i < NR_CHILDS; i++) {
+               child[i] = fork_child();
+               wstatus[i] = 0;
+               usleep(250000);
+       }
+
+       while (1) {
+               for (i = 0; i < NR_CHILDS; i++) {
+                       if (child[i] <= 0)
+                               continue;
+
+                       errno = 0;
+                       pid_t ret = waitpid(child[i], &wstatus[i], WNOHANG);
+
+                       if (!ret || (!WIFEXITED(wstatus[i]) && !WIFSIGNALED(wstatus[i])))
+                               continue;
+
+                       if (ret < 0 && errno != ECHILD)
+                               warn("(pid=%d): waitpid(%d)", pid, child[i]);
+
+                       child[i] *= -1;
+                       childs -= 1;
+               }
+
+               if (!childs)
+                       break;
+
+               usleep(250000);
+
+               for (i = 0; i < NR_CHILDS; i++) {
+                       if (child[i] <= 0)
+                               continue;
+                       kill(child[i], SIGUSR1);
+               }
+       }
+
+       for (i = 0; i < NR_CHILDS; i++) {
+               if (WIFEXITED(wstatus[i]))
+                       warnx("(pid=%d): pid %d exited, status=%d",
+                               pid, -child[i], WEXITSTATUS(wstatus[i]));
+               else if (WIFSIGNALED(wstatus[i]))
+                       warnx("(pid=%d): pid %d killed by signal %d",
+                               pid, -child[i], WTERMSIG(wstatus[i]));
+
+               if (WIFSIGNALED(wstatus[i]) && WTERMSIG(wstatus[i]) == SIGUSR1)
+                       continue;
+
+               warnx("(pid=%d): Test failed", pid);
+               exit(EXIT_FAILURE);
+       }
+
+       warnx("(pid=%d): Test passed", pid);
+       exit(EXIT_SUCCESS);
+}
diff --git a/tools/testing/selftests/sched/.gitignore b/tools/testing/selftests/sched/.gitignore
new file mode 100644 (file)
index 0000000..6996d46
--- /dev/null
@@ -0,0 +1 @@
+cs_prctl_test
diff --git a/tools/testing/selftests/sched/Makefile b/tools/testing/selftests/sched/Makefile
new file mode 100644 (file)
index 0000000..10c72f1
--- /dev/null
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
+CLANG_FLAGS += -no-integrated-as
+endif
+
+CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/  -Wl,-rpath=./ \
+         $(CLANG_FLAGS)
+LDLIBS += -lpthread
+
+TEST_GEN_FILES := cs_prctl_test
+TEST_PROGS := cs_prctl_test
+
+include ../lib.mk
diff --git a/tools/testing/selftests/sched/config b/tools/testing/selftests/sched/config
new file mode 100644 (file)
index 0000000..e8b09aa
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_SCHED_DEBUG=y
diff --git a/tools/testing/selftests/sched/cs_prctl_test.c b/tools/testing/selftests/sched/cs_prctl_test.c
new file mode 100644 (file)
index 0000000..63fe652
--- /dev/null
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Use the core scheduling prctl() to test core scheduling cookies control.
+ *
+ * Copyright (c) 2021 Oracle and/or its affiliates.
+ * Author: Chris Hyser <chris.hyser@oracle.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This 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 this library; if not, see <http://www.gnu.org/licenses>.
+ */
+
+#define _GNU_SOURCE
+#include <sys/eventfd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if __GLIBC_PREREQ(2, 30) == 0
+#include <sys/syscall.h>
+static pid_t gettid(void)
+{
+       return syscall(SYS_gettid);
+}
+#endif
+
+#ifndef PR_SCHED_CORE
+#define PR_SCHED_CORE                  62
+# define PR_SCHED_CORE_GET             0
+# define PR_SCHED_CORE_CREATE          1 /* create unique core_sched cookie */
+# define PR_SCHED_CORE_SHARE_TO                2 /* push core_sched cookie to pid */
+# define PR_SCHED_CORE_SHARE_FROM      3 /* pull core_sched cookie to pid */
+# define PR_SCHED_CORE_MAX             4
+#endif
+
+#define MAX_PROCESSES 128
+#define MAX_THREADS   128
+
+static const char USAGE[] = "cs_prctl_test [options]\n"
+"    options:\n"
+"      -P  : number of processes to create.\n"
+"      -T  : number of threads per process to create.\n"
+"      -d  : delay time to keep tasks alive.\n"
+"      -k  : keep tasks alive until keypress.\n";
+
+enum pid_type {PIDTYPE_PID = 0, PIDTYPE_TGID, PIDTYPE_PGID};
+
+const int THREAD_CLONE_FLAGS = CLONE_THREAD | CLONE_SIGHAND | CLONE_FS | CLONE_VM | CLONE_FILES;
+
+static int _prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4,
+                 unsigned long arg5)
+{
+       int res;
+
+       res = prctl(option, arg2, arg3, arg4, arg5);
+       printf("%d = prctl(%d, %ld, %ld, %ld, %lx)\n", res, option, (long)arg2, (long)arg3,
+              (long)arg4, arg5);
+       return res;
+}
+
+#define STACK_SIZE (1024 * 1024)
+
+#define handle_error(msg) __handle_error(__FILE__, __LINE__, msg)
+static void __handle_error(char *fn, int ln, char *msg)
+{
+       printf("(%s:%d) - ", fn, ln);
+       perror(msg);
+       exit(EXIT_FAILURE);
+}
+
+static void handle_usage(int rc, char *msg)
+{
+       puts(USAGE);
+       puts(msg);
+       putchar('\n');
+       exit(rc);
+}
+
+static unsigned long get_cs_cookie(int pid)
+{
+       unsigned long long cookie;
+       int ret;
+
+       ret = prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, pid, PIDTYPE_PID,
+                   (unsigned long)&cookie);
+       if (ret) {
+               printf("Not a core sched system\n");
+               return -1UL;
+       }
+
+       return cookie;
+}
+
+struct child_args {
+       int num_threads;
+       int pfd[2];
+       int cpid;
+       int thr_tids[MAX_THREADS];
+};
+
+static int child_func_thread(void __attribute__((unused))*arg)
+{
+       while (1)
+               usleep(20000);
+       return 0;
+}
+
+static void create_threads(int num_threads, int thr_tids[])
+{
+       void *child_stack;
+       pid_t tid;
+       int i;
+
+       for (i = 0; i < num_threads; ++i) {
+               child_stack = malloc(STACK_SIZE);
+               if (!child_stack)
+                       handle_error("child stack allocate");
+
+               tid = clone(child_func_thread, child_stack + STACK_SIZE, THREAD_CLONE_FLAGS, NULL);
+               if (tid == -1)
+                       handle_error("clone thread");
+               thr_tids[i] = tid;
+       }
+}
+
+static int child_func_process(void *arg)
+{
+       struct child_args *ca = (struct child_args *)arg;
+
+       close(ca->pfd[0]);
+
+       create_threads(ca->num_threads, ca->thr_tids);
+
+       write(ca->pfd[1], &ca->thr_tids, sizeof(int) * ca->num_threads);
+       close(ca->pfd[1]);
+
+       while (1)
+               usleep(20000);
+       return 0;
+}
+
+static unsigned char child_func_process_stack[STACK_SIZE];
+
+void create_processes(int num_processes, int num_threads, struct child_args proc[])
+{
+       pid_t cpid;
+       int i;
+
+       for (i = 0; i < num_processes; ++i) {
+               proc[i].num_threads = num_threads;
+
+               if (pipe(proc[i].pfd) == -1)
+                       handle_error("pipe() failed");
+
+               cpid = clone(child_func_process, child_func_process_stack + STACK_SIZE,
+                            SIGCHLD, &proc[i]);
+               proc[i].cpid = cpid;
+               close(proc[i].pfd[1]);
+       }
+
+       for (i = 0; i < num_processes; ++i) {
+               read(proc[i].pfd[0], &proc[i].thr_tids, sizeof(int) * proc[i].num_threads);
+               close(proc[i].pfd[0]);
+       }
+}
+
+void disp_processes(int num_processes, struct child_args proc[])
+{
+       int i, j;
+
+       printf("tid=%d, / tgid=%d / pgid=%d: %lx\n", gettid(), getpid(), getpgid(0),
+              get_cs_cookie(getpid()));
+
+       for (i = 0; i < num_processes; ++i) {
+               printf("    tid=%d, / tgid=%d / pgid=%d: %lx\n", proc[i].cpid, proc[i].cpid,
+                      getpgid(proc[i].cpid), get_cs_cookie(proc[i].cpid));
+               for (j = 0; j < proc[i].num_threads; ++j) {
+                       printf("        tid=%d, / tgid=%d / pgid=%d: %lx\n", proc[i].thr_tids[j],
+                              proc[i].cpid, getpgid(0), get_cs_cookie(proc[i].thr_tids[j]));
+               }
+       }
+       puts("\n");
+}
+
+static int errors;
+
+#define validate(v) _validate(__LINE__, v, #v)
+void _validate(int line, int val, char *msg)
+{
+       if (!val) {
+               ++errors;
+               printf("(%d) FAILED: %s\n", line, msg);
+       } else {
+               printf("(%d) PASSED: %s\n", line, msg);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct child_args procs[MAX_PROCESSES];
+
+       int keypress = 0;
+       int num_processes = 2;
+       int num_threads = 3;
+       int delay = 0;
+       int res = 0;
+       int pidx;
+       int pid;
+       int opt;
+
+       while ((opt = getopt(argc, argv, ":hkT:P:d:")) != -1) {
+               switch (opt) {
+               case 'P':
+                       num_processes = (int)strtol(optarg, NULL, 10);
+                       break;
+               case 'T':
+                       num_threads = (int)strtoul(optarg, NULL, 10);
+                       break;
+               case 'd':
+                       delay = (int)strtol(optarg, NULL, 10);
+                       break;
+               case 'k':
+                       keypress = 1;
+                       break;
+               case 'h':
+                       printf(USAGE);
+                       exit(EXIT_SUCCESS);
+               default:
+                       handle_usage(20, "unknown option");
+               }
+       }
+
+       if (num_processes < 1 || num_processes > MAX_PROCESSES)
+               handle_usage(1, "Bad processes value");
+
+       if (num_threads < 1 || num_threads > MAX_THREADS)
+               handle_usage(2, "Bad thread value");
+
+       if (keypress)
+               delay = -1;
+
+       srand(time(NULL));
+
+       /* put into separate process group */
+       if (setpgid(0, 0) != 0)
+               handle_error("process group");
+
+       printf("\n## Create a thread/process/process group hiearchy\n");
+       create_processes(num_processes, num_threads, procs);
+       disp_processes(num_processes, procs);
+       validate(get_cs_cookie(0) == 0);
+
+       printf("\n## Set a cookie on entire process group\n");
+       if (_prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, 0, PIDTYPE_PGID, 0) < 0)
+               handle_error("core_sched create failed -- PGID");
+       disp_processes(num_processes, procs);
+
+       validate(get_cs_cookie(0) != 0);
+
+       /* get a random process pid */
+       pidx = rand() % num_processes;
+       pid = procs[pidx].cpid;
+
+       validate(get_cs_cookie(0) == get_cs_cookie(pid));
+       validate(get_cs_cookie(0) == get_cs_cookie(procs[pidx].thr_tids[0]));
+
+       printf("\n## Set a new cookie on entire process/TGID [%d]\n", pid);
+       if (_prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, pid, PIDTYPE_TGID, 0) < 0)
+               handle_error("core_sched create failed -- TGID");
+       disp_processes(num_processes, procs);
+
+       validate(get_cs_cookie(0) != get_cs_cookie(pid));
+       validate(get_cs_cookie(pid) != 0);
+       validate(get_cs_cookie(pid) == get_cs_cookie(procs[pidx].thr_tids[0]));
+
+       printf("\n## Copy the cookie of current/PGID[%d], to pid [%d] as PIDTYPE_PID\n",
+              getpid(), pid);
+       if (_prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, pid, PIDTYPE_PID, 0) < 0)
+               handle_error("core_sched share to itself failed -- PID");
+       disp_processes(num_processes, procs);
+
+       validate(get_cs_cookie(0) == get_cs_cookie(pid));
+       validate(get_cs_cookie(pid) != 0);
+       validate(get_cs_cookie(pid) != get_cs_cookie(procs[pidx].thr_tids[0]));
+
+       printf("\n## Copy cookie from a thread [%d] to current/PGID [%d] as PIDTYPE_PID\n",
+              procs[pidx].thr_tids[0], getpid());
+       if (_prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, procs[pidx].thr_tids[0],
+                  PIDTYPE_PID, 0) < 0)
+               handle_error("core_sched share from thread failed -- PID");
+       disp_processes(num_processes, procs);
+
+       validate(get_cs_cookie(0) == get_cs_cookie(procs[pidx].thr_tids[0]));
+       validate(get_cs_cookie(pid) != get_cs_cookie(procs[pidx].thr_tids[0]));
+
+       printf("\n## Copy cookie from current [%d] to current as pidtype PGID\n", getpid());
+       if (_prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, 0, PIDTYPE_PGID, 0) < 0)
+               handle_error("core_sched share to self failed -- PGID");
+       disp_processes(num_processes, procs);
+
+       validate(get_cs_cookie(0) == get_cs_cookie(pid));
+       validate(get_cs_cookie(pid) != 0);
+       validate(get_cs_cookie(pid) == get_cs_cookie(procs[pidx].thr_tids[0]));
+
+       if (errors) {
+               printf("TESTS FAILED. errors: %d\n", errors);
+               res = 10;
+       } else {
+               printf("SUCCESS !!!\n");
+       }
+
+       if (keypress)
+               getchar();
+       else
+               sleep(delay);
+
+       for (pidx = 0; pidx < num_processes; ++pidx)
+               kill(procs[pidx].cpid, 15);
+
+       return res;
+}
index fcc8065..6e5102a 100644 (file)
@@ -143,9 +143,15 @@ int main(int argc, char *argv[])
        unsigned long long native, filter1, filter2, bitmap1, bitmap2;
        unsigned long long entry, per_filter1, per_filter2;
 
+       setbuf(stdout, NULL);
+
+       printf("Running on:\n");
+       system("uname -a");
+
        printf("Current BPF sysctl settings:\n");
-       system("sysctl net.core.bpf_jit_enable");
-       system("sysctl net.core.bpf_jit_harden");
+       /* Avoid using "sysctl" which may not be installed. */
+       system("grep -H . /proc/sys/net/core/bpf_jit_enable");
+       system("grep -H . /proc/sys/net/core/bpf_jit_harden");
 
        if (argc > 1)
                samples = strtoull(argv[1], NULL, 0);
index e3d5c77..1d64891 100644 (file)
@@ -235,6 +235,10 @@ struct seccomp_notif_addfd {
 };
 #endif
 
+#ifndef SECCOMP_ADDFD_FLAG_SEND
+#define SECCOMP_ADDFD_FLAG_SEND        (1UL << 1) /* Addfd and return it, atomically */
+#endif
+
 struct seccomp_notif_addfd_small {
        __u64 id;
        char weird[4];
@@ -3959,7 +3963,7 @@ TEST(user_notification_addfd)
 {
        pid_t pid;
        long ret;
-       int status, listener, memfd, fd;
+       int status, listener, memfd, fd, nextfd;
        struct seccomp_notif_addfd addfd = {};
        struct seccomp_notif_addfd_small small = {};
        struct seccomp_notif_addfd_big big = {};
@@ -3968,25 +3972,34 @@ TEST(user_notification_addfd)
        /* 100 ms */
        struct timespec delay = { .tv_nsec = 100000000 };
 
+       /* There may be arbitrary already-open fds at test start. */
        memfd = memfd_create("test", 0);
        ASSERT_GE(memfd, 0);
+       nextfd = memfd + 1;
 
        ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
        ASSERT_EQ(0, ret) {
                TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
        }
 
+       /* fd: 4 */
        /* Check that the basic notification machinery works */
        listener = user_notif_syscall(__NR_getppid,
                                      SECCOMP_FILTER_FLAG_NEW_LISTENER);
-       ASSERT_GE(listener, 0);
+       ASSERT_EQ(listener, nextfd++);
 
        pid = fork();
        ASSERT_GE(pid, 0);
 
        if (pid == 0) {
+               /* fds will be added and this value is expected */
                if (syscall(__NR_getppid) != USER_NOTIF_MAGIC)
                        exit(1);
+
+               /* Atomic addfd+send is received here. Check it is a valid fd */
+               if (fcntl(syscall(__NR_getppid), F_GETFD) == -1)
+                       exit(1);
+
                exit(syscall(__NR_getppid) != USER_NOTIF_MAGIC);
        }
 
@@ -4028,14 +4041,14 @@ TEST(user_notification_addfd)
 
        /* Verify we can set an arbitrary remote fd */
        fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
-       EXPECT_GE(fd, 0);
+       EXPECT_EQ(fd, nextfd++);
        EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
 
        /* Verify we can set an arbitrary remote fd with large size */
        memset(&big, 0x0, sizeof(big));
        big.addfd = addfd;
        fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD_BIG, &big);
-       EXPECT_GE(fd, 0);
+       EXPECT_EQ(fd, nextfd++);
 
        /* Verify we can set a specific remote fd */
        addfd.newfd = 42;
@@ -4065,6 +4078,32 @@ TEST(user_notification_addfd)
        ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
        ASSERT_EQ(addfd.id, req.id);
 
+       /* Verify we can do an atomic addfd and send */
+       addfd.newfd = 0;
+       addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
+       fd = ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
+       /*
+        * Child has earlier "low" fds and now 42, so we expect the next
+        * lowest available fd to be assigned here.
+        */
+       EXPECT_EQ(fd, nextfd++);
+       EXPECT_EQ(filecmp(getpid(), pid, memfd, fd), 0);
+
+       /*
+        * This sets the ID of the ADD FD to the last request plus 1. The
+        * notification ID increments 1 per notification.
+        */
+       addfd.id = req.id + 1;
+
+       /* This spins until the underlying notification is generated */
+       while (ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd) != -1 &&
+              errno != -EINPROGRESS)
+               nanosleep(&delay, NULL);
+
+       memset(&req, 0, sizeof(req));
+       ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       ASSERT_EQ(addfd.id, req.id);
+
        resp.id = req.id;
        resp.error = 0;
        resp.val = USER_NOTIF_MAGIC;
@@ -4125,6 +4164,10 @@ TEST(user_notification_addfd_rlimit)
        EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
        EXPECT_EQ(errno, EMFILE);
 
+       addfd.flags = SECCOMP_ADDFD_FLAG_SEND;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
+       EXPECT_EQ(errno, EMFILE);
+
        addfd.newfd = 100;
        addfd.flags = SECCOMP_ADDFD_FLAG_SETFD;
        EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd), -1);
index d6b09cb..9915917 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * syscall_arg_fault.c - tests faults 32-bit fast syscall stack args
+ * syscall_numbering.c - test calling the x86-64 kernel with various
+ * valid and invalid system call numbers.
+ *
  * Copyright (c) 2018 Andrew Lutomirski
  */
 
 #include <stdbool.h>
 #include <errno.h>
 #include <unistd.h>
-#include <syscall.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <sysexits.h>
 
-static int nerrs;
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
 
-#define X32_BIT 0x40000000UL
+#include <linux/ptrace.h>
 
-static void check_enosys(unsigned long nr, bool *ok)
+/* Common system call numbers */
+#define SYS_READ         0
+#define SYS_WRITE        1
+#define SYS_GETPID      39
+/* x64-only system call numbers */
+#define X64_IOCTL       16
+#define X64_READV       19
+#define X64_WRITEV      20
+/* x32-only system call numbers (without X32_BIT) */
+#define X32_IOCTL      514
+#define X32_READV      515
+#define X32_WRITEV     516
+
+#define X32_BIT 0x40000000
+
+static int nullfd = -1;                /* File descriptor for /dev/null */
+static bool with_x32;          /* x32 supported on this kernel? */
+
+enum ptrace_pass {
+       PTP_NOTHING,
+       PTP_GETREGS,
+       PTP_WRITEBACK,
+       PTP_FUZZRET,
+       PTP_FUZZHIGH,
+       PTP_INTNUM,
+       PTP_DONE
+};
+
+static const char * const ptrace_pass_name[] =
 {
-       /* If this fails, a segfault is reasonably likely. */
-       fflush(stdout);
+       [PTP_NOTHING]   = "just stop, no data read",
+       [PTP_GETREGS]   = "only getregs",
+       [PTP_WRITEBACK] = "getregs, unmodified setregs",
+       [PTP_FUZZRET]   = "modifying the default return",
+       [PTP_FUZZHIGH]  = "clobbering the top 32 bits",
+       [PTP_INTNUM]    = "sign-extending the syscall number",
+};
 
-       long ret = syscall(nr, 0, 0, 0, 0, 0, 0);
-       if (ret == 0) {
-               printf("[FAIL]\tsyscall %lu succeeded, but it should have failed\n", nr);
-               *ok = false;
-       } else if (errno != ENOSYS) {
-               printf("[FAIL]\tsyscall %lu had error code %d, but it should have reported ENOSYS\n", nr, errno);
-               *ok = false;
-       }
+/*
+ * Shared memory block between tracer and test
+ */
+struct shared {
+       unsigned int nerr;      /* Total error count */
+       unsigned int indent;    /* Message indentation level */
+       enum ptrace_pass ptrace_pass;
+       bool probing_syscall;   /* In probe_syscall() */
+};
+static volatile struct shared *sh;
+
+static inline unsigned int offset(void)
+{
+       unsigned int level = sh ? sh->indent : 0;
+
+       return 8 + level * 4;
 }
 
-static void test_x32_without_x32_bit(void)
+#define msg(lvl, fmt, ...) printf("%-*s" fmt, offset(), "[" #lvl "]", \
+                                 ## __VA_ARGS__)
+
+#define run(fmt, ...)  msg(RUN,  fmt, ## __VA_ARGS__)
+#define info(fmt, ...) msg(INFO, fmt, ## __VA_ARGS__)
+#define ok(fmt, ...)   msg(OK,   fmt, ## __VA_ARGS__)
+
+#define fail(fmt, ...)                                 \
+       do {                                            \
+               msg(FAIL, fmt, ## __VA_ARGS__);         \
+               sh->nerr++;                             \
+       } while (0)
+
+#define crit(fmt, ...)                                 \
+       do {                                            \
+               sh->indent = 0;                         \
+               msg(FAIL, fmt, ## __VA_ARGS__);         \
+               msg(SKIP, "Unable to run test\n");      \
+               exit(EX_OSERR);                         \
+       } while (0)
+
+/* Sentinel for ptrace-modified return value */
+#define MODIFIED_BY_PTRACE     -9999
+
+/*
+ * Directly invokes the given syscall with nullfd as the first argument
+ * and the rest zero. Avoids involving glibc wrappers in case they ever
+ * end up intercepting some system calls for some reason, or modify
+ * the system call number itself.
+ */
+static long long probe_syscall(int msb, int lsb)
 {
-       bool ok = true;
+       register long long arg1 asm("rdi") = nullfd;
+       register long long arg2 asm("rsi") = 0;
+       register long long arg3 asm("rdx") = 0;
+       register long long arg4 asm("r10") = 0;
+       register long long arg5 asm("r8")  = 0;
+       register long long arg6 asm("r9")  = 0;
+       long long nr = ((long long)msb << 32) | (unsigned int)lsb;
+       long long ret;
 
        /*
-        * Syscalls 512-547 are "x32" syscalls.  They are intended to be
-        * called with the x32 (0x40000000) bit set.  Calling them without
-        * the x32 bit set is nonsense and should not work.
+        * We pass in an extra copy of the extended system call number
+        * in %rbx, so we can examine it from the ptrace handler without
+        * worrying about it being possibly modified. This is to test
+        * the validity of struct user regs.orig_rax a.k.a.
+        * struct pt_regs.orig_ax.
         */
-       printf("[RUN]\tChecking syscalls 512-547\n");
-       for (int i = 512; i <= 547; i++)
-               check_enosys(i, &ok);
+       sh->probing_syscall = true;
+       asm volatile("syscall"
+                    : "=a" (ret)
+                    : "a" (nr), "b" (nr),
+                      "r" (arg1), "r" (arg2), "r" (arg3),
+                      "r" (arg4), "r" (arg5), "r" (arg6)
+                    : "rcx", "r11", "memory", "cc");
+       sh->probing_syscall = false;
+
+       return ret;
+}
+
+static const char *syscall_str(int msb, int start, int end)
+{
+       static char buf[64];
+       const char * const type = (start & X32_BIT) ? "x32" : "x64";
+       int lsb = start;
 
        /*
-        * Check that a handful of 64-bit-only syscalls are rejected if the x32
-        * bit is set.
+        * Improve readability by stripping the x32 bit, but round
+        * toward zero so we don't display -1 as -1073741825.
         */
-       printf("[RUN]\tChecking some 64-bit syscalls in x32 range\n");
-       check_enosys(16 | X32_BIT, &ok);        /* ioctl */
-       check_enosys(19 | X32_BIT, &ok);        /* readv */
-       check_enosys(20 | X32_BIT, &ok);        /* writev */
+       if (lsb < 0)
+               lsb |= X32_BIT;
+       else
+               lsb &= ~X32_BIT;
+
+       if (start == end)
+               snprintf(buf, sizeof buf, "%s syscall %d:%d",
+                        type, msb, lsb);
+       else
+               snprintf(buf, sizeof buf, "%s syscalls %d:%d..%d",
+                        type, msb, lsb, lsb + (end-start));
+
+       return buf;
+}
+
+static unsigned int _check_for(int msb, int start, int end, long long expect,
+                              const char *expect_str)
+{
+       unsigned int err = 0;
+
+       sh->indent++;
+       if (start != end)
+               sh->indent++;
+
+       for (int nr = start; nr <= end; nr++) {
+               long long ret = probe_syscall(msb, nr);
+
+               if (ret != expect) {
+                       fail("%s returned %lld, but it should have returned %s\n",
+                              syscall_str(msb, nr, nr),
+                              ret, expect_str);
+                       err++;
+               }
+       }
+
+       if (start != end)
+               sh->indent--;
+
+       if (err) {
+               if (start != end)
+                       fail("%s had %u failure%s\n",
+                            syscall_str(msb, start, end),
+                            err, err == 1 ? "s" : "");
+       } else {
+               ok("%s returned %s as expected\n",
+                  syscall_str(msb, start, end), expect_str);
+       }
+
+       sh->indent--;
+
+       return err;
+}
+
+#define check_for(msb,start,end,expect) \
+       _check_for(msb,start,end,expect,#expect)
+
+static bool check_zero(int msb, int nr)
+{
+       return check_for(msb, nr, nr, 0);
+}
+
+static bool check_enosys(int msb, int nr)
+{
+       return check_for(msb, nr, nr, -ENOSYS);
+}
+
+/*
+ * Anyone diagnosing a failure will want to know whether the kernel
+ * supports x32. Tell them. This can also be used to conditionalize
+ * tests based on existence or nonexistence of x32.
+ */
+static bool test_x32(void)
+{
+       long long ret;
+       pid_t mypid = getpid();
+
+       run("Checking for x32 by calling x32 getpid()\n");
+       ret = probe_syscall(0, SYS_GETPID | X32_BIT);
+
+       sh->indent++;
+       if (ret == mypid) {
+               info("x32 is supported\n");
+               with_x32 = true;
+       } else if (ret == -ENOSYS) {
+               info("x32 is not supported\n");
+               with_x32 = false;
+       } else {
+               fail("x32 getpid() returned %lld, but it should have returned either %lld or -ENOSYS\n", ret, (long long)mypid);
+               with_x32 = false;
+       }
+       sh->indent--;
+       return with_x32;
+}
+
+static void test_syscalls_common(int msb)
+{
+       enum ptrace_pass pass = sh->ptrace_pass;
+
+       run("Checking some common syscalls as 64 bit\n");
+       check_zero(msb, SYS_READ);
+       check_zero(msb, SYS_WRITE);
+
+       run("Checking some 64-bit only syscalls as 64 bit\n");
+       check_zero(msb, X64_READV);
+       check_zero(msb, X64_WRITEV);
+
+       run("Checking out of range system calls\n");
+       check_for(msb, -64, -2, -ENOSYS);
+       if (pass >= PTP_FUZZRET)
+               check_for(msb, -1, -1, MODIFIED_BY_PTRACE);
+       else
+               check_for(msb, -1, -1, -ENOSYS);
+       check_for(msb, X32_BIT-64, X32_BIT-1, -ENOSYS);
+       check_for(msb, -64-X32_BIT, -1-X32_BIT, -ENOSYS);
+       check_for(msb, INT_MAX-64, INT_MAX-1, -ENOSYS);
+}
 
+static void test_syscalls_with_x32(int msb)
+{
        /*
-        * Check some syscalls with high bits set.
+        * Syscalls 512-547 are "x32" syscalls.  They are
+        * intended to be called with the x32 (0x40000000) bit
+        * set.  Calling them without the x32 bit set is
+        * nonsense and should not work.
         */
-       printf("[RUN]\tChecking numbers above 2^32-1\n");
-       check_enosys((1UL << 32), &ok);
-       check_enosys(X32_BIT | (1UL << 32), &ok);
+       run("Checking x32 syscalls as 64 bit\n");
+       check_for(msb, 512, 547, -ENOSYS);
 
-       if (!ok)
-               nerrs++;
-       else
-               printf("[OK]\tThey all returned -ENOSYS\n");
+       run("Checking some common syscalls as x32\n");
+       check_zero(msb, SYS_READ   | X32_BIT);
+       check_zero(msb, SYS_WRITE  | X32_BIT);
+
+       run("Checking some x32 syscalls as x32\n");
+       check_zero(msb, X32_READV  | X32_BIT);
+       check_zero(msb, X32_WRITEV | X32_BIT);
+
+       run("Checking some 64-bit syscalls as x32\n");
+       check_enosys(msb, X64_IOCTL  | X32_BIT);
+       check_enosys(msb, X64_READV  | X32_BIT);
+       check_enosys(msb, X64_WRITEV | X32_BIT);
 }
 
-int main()
+static void test_syscalls_without_x32(int msb)
 {
+       run("Checking for absence of x32 system calls\n");
+       check_for(msb, 0 | X32_BIT, 999 | X32_BIT, -ENOSYS);
+}
+
+static void test_syscall_numbering(void)
+{
+       static const int msbs[] = {
+               0, 1, -1, X32_BIT-1, X32_BIT, X32_BIT-1, -X32_BIT, INT_MAX,
+               INT_MIN, INT_MIN+1
+       };
+
+       sh->indent++;
+
        /*
-        * Anyone diagnosing a failure will want to know whether the kernel
-        * supports x32.  Tell them.
+        * The MSB is supposed to be ignored, so we loop over a few
+        * to test that out.
         */
-       printf("\tChecking for x32...");
-       fflush(stdout);
-       if (syscall(39 | X32_BIT, 0, 0, 0, 0, 0, 0) >= 0) {
-               printf(" supported\n");
-       } else if (errno == ENOSYS) {
-               printf(" not supported\n");
+       for (size_t i = 0; i < sizeof(msbs)/sizeof(msbs[0]); i++) {
+               int msb = msbs[i];
+               run("Checking system calls with msb = %d (0x%x)\n",
+                   msb, msb);
+
+               sh->indent++;
+
+               test_syscalls_common(msb);
+               if (with_x32)
+                       test_syscalls_with_x32(msb);
+               else
+                       test_syscalls_without_x32(msb);
+
+               sh->indent--;
+       }
+
+       sh->indent--;
+}
+
+static void syscall_numbering_tracee(void)
+{
+       enum ptrace_pass pass;
+
+       if (ptrace(PTRACE_TRACEME, 0, 0, 0)) {
+               crit("Failed to request tracing\n");
+               return;
+       }
+       raise(SIGSTOP);
+
+       for (sh->ptrace_pass = pass = PTP_NOTHING; pass < PTP_DONE;
+            sh->ptrace_pass = ++pass) {
+               run("Running tests under ptrace: %s\n", ptrace_pass_name[pass]);
+               test_syscall_numbering();
+       }
+}
+
+static void mess_with_syscall(pid_t testpid, enum ptrace_pass pass)
+{
+       struct user_regs_struct regs;
+
+       sh->probing_syscall = false; /* Do this on entry only */
+
+       /* For these, don't even getregs */
+       if (pass == PTP_NOTHING || pass == PTP_DONE)
+               return;
+
+       ptrace(PTRACE_GETREGS, testpid, NULL, &regs);
+
+       if (regs.orig_rax != regs.rbx) {
+               fail("orig_rax %#llx doesn't match syscall number %#llx\n",
+                    (unsigned long long)regs.orig_rax,
+                    (unsigned long long)regs.rbx);
+       }
+
+       switch (pass) {
+       case PTP_GETREGS:
+               /* Just read, no writeback */
+               return;
+       case PTP_WRITEBACK:
+               /* Write back the same register state verbatim */
+               break;
+       case PTP_FUZZRET:
+               regs.rax = MODIFIED_BY_PTRACE;
+               break;
+       case PTP_FUZZHIGH:
+               regs.rax = MODIFIED_BY_PTRACE;
+               regs.orig_rax = regs.orig_rax | 0xffffffff00000000ULL;
+               break;
+       case PTP_INTNUM:
+               regs.rax = MODIFIED_BY_PTRACE;
+               regs.orig_rax = (int)regs.orig_rax;
+               break;
+       default:
+               crit("invalid ptrace_pass\n");
+               break;
+       }
+
+       ptrace(PTRACE_SETREGS, testpid, NULL, &regs);
+}
+
+static void syscall_numbering_tracer(pid_t testpid)
+{
+       int wstatus;
+
+       do {
+               pid_t wpid = waitpid(testpid, &wstatus, 0);
+               if (wpid < 0 && errno != EINTR)
+                       break;
+               if (wpid != testpid)
+                       continue;
+               if (!WIFSTOPPED(wstatus))
+                       break;  /* Thread exited? */
+
+               if (sh->probing_syscall && WSTOPSIG(wstatus) == SIGTRAP)
+                       mess_with_syscall(testpid, sh->ptrace_pass);
+       } while (sh->ptrace_pass != PTP_DONE &&
+                !ptrace(PTRACE_SYSCALL, testpid, NULL, NULL));
+
+       ptrace(PTRACE_DETACH, testpid, NULL, NULL);
+
+       /* Wait for the child process to terminate */
+       while (waitpid(testpid, &wstatus, 0) != testpid || !WIFEXITED(wstatus))
+               /* wait some more */;
+}
+
+static void test_traced_syscall_numbering(void)
+{
+       pid_t testpid;
+
+       /* Launch the test thread; this thread continues as the tracer thread */
+       testpid = fork();
+
+       if (testpid < 0) {
+               crit("Unable to launch tracer process\n");
+       } else if (testpid == 0) {
+               syscall_numbering_tracee();
+               _exit(0);
        } else {
-               printf(" confused\n");
+               syscall_numbering_tracer(testpid);
        }
+}
 
-       test_x32_without_x32_bit();
+int main(void)
+{
+       unsigned int nerr;
 
-       return nerrs ? 1 : 0;
+       /*
+        * It is quite likely to get a segfault on a failure, so make
+        * sure the message gets out by setting stdout to nonbuffered.
+        */
+       setvbuf(stdout, NULL, _IONBF, 0);
+
+       /*
+        * Harmless file descriptor to work on...
+        */
+       nullfd = open("/dev/null", O_RDWR);
+       if (nullfd < 0) {
+               crit("Unable to open /dev/null: %s\n", strerror(errno));
+       }
+
+       /*
+        * Set up a block of shared memory...
+        */
+       sh = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_WRITE,
+                 MAP_ANONYMOUS|MAP_SHARED, 0, 0);
+       if (sh == MAP_FAILED) {
+               crit("Unable to allocated shared memory block: %s\n",
+                    strerror(errno));
+       }
+
+       with_x32 = test_x32();
+
+       run("Running tests without ptrace...\n");
+       test_syscall_numbering();
+
+       test_traced_syscall_numbering();
+
+       nerr = sh->nerr;
+       if (!nerr) {
+               ok("All system calls succeeded or failed as expected\n");
+               return 0;
+       } else {
+               fail("A total of %u system call%s had incorrect behavior\n",
+                    nerr, nerr != 1 ? "s" : "");
+               return 1;
+       }
 }
index 1c37ccd..62b3914 100644 (file)
@@ -63,3 +63,6 @@ config HAVE_KVM_NO_POLL
 
 config KVM_XFER_TO_GUEST_WORK
        bool
+
+config HAVE_KVM_PM_NOTIFIER
+       bool
diff --git a/virt/kvm/binary_stats.c b/virt/kvm/binary_stats.c
new file mode 100644 (file)
index 0000000..e609d42
--- /dev/null
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM binary statistics interface implementation
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+
+/**
+ * kvm_stats_read() - Common function to read from the binary statistics
+ * file descriptor.
+ *
+ * @id: identification string of the stats
+ * @header: stats header for a vm or a vcpu
+ * @desc: start address of an array of stats descriptors for a vm or a vcpu
+ * @stats: start address of stats data block for a vm or a vcpu
+ * @size_stats: the size of stats data block pointed by @stats
+ * @user_buffer: start address of userspace buffer
+ * @size: requested read size from userspace
+ * @offset: the start position from which the content will be read for the
+ *          corresponding vm or vcp file descriptor
+ *
+ * The file content of a vm/vcpu file descriptor is now defined as below:
+ * +-------------+
+ * |   Header    |
+ * +-------------+
+ * |  id string  |
+ * +-------------+
+ * | Descriptors |
+ * +-------------+
+ * | Stats Data  |
+ * +-------------+
+ * Although this function allows userspace to read any amount of data (as long
+ * as in the limit) from any position, the typical usage would follow below
+ * steps:
+ * 1. Read header from offset 0. Get the offset of descriptors and stats data
+ *    and some other necessary information. This is a one-time work for the
+ *    lifecycle of the corresponding vm/vcpu stats fd.
+ * 2. Read id string from its offset. This is a one-time work for the lifecycle
+ *    of the corresponding vm/vcpu stats fd.
+ * 3. Read descriptors from its offset and discover all the stats by parsing
+ *    descriptors. This is a one-time work for the lifecycle of the
+ *    corresponding vm/vcpu stats fd.
+ * 4. Periodically read stats data from its offset using pread.
+ *
+ * Return: the number of bytes that has been successfully read
+ */
+ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
+                      const struct _kvm_stats_desc *desc,
+                      void *stats, size_t size_stats,
+                      char __user *user_buffer, size_t size, loff_t *offset)
+{
+       ssize_t len;
+       ssize_t copylen;
+       ssize_t remain = size;
+       size_t size_desc;
+       size_t size_header;
+       void *src;
+       loff_t pos = *offset;
+       char __user *dest = user_buffer;
+
+       size_header = sizeof(*header);
+       size_desc = header->num_desc * sizeof(*desc);
+
+       len = KVM_STATS_NAME_SIZE + size_header + size_desc + size_stats - pos;
+       len = min(len, remain);
+       if (len <= 0)
+               return 0;
+       remain = len;
+
+       /*
+        * Copy kvm stats header.
+        * The header is the first block of content userspace usually read out.
+        * The pos is 0 and the copylen and remain would be the size of header.
+        * The copy of the header would be skipped if offset is larger than the
+        * size of header. That usually happens when userspace reads stats
+        * descriptors and stats data.
+        */
+       copylen = size_header - pos;
+       copylen = min(copylen, remain);
+       if (copylen > 0) {
+               src = (void *)header + pos;
+               if (copy_to_user(dest, src, copylen))
+                       return -EFAULT;
+               remain -= copylen;
+               pos += copylen;
+               dest += copylen;
+       }
+
+       /*
+        * Copy kvm stats header id string.
+        * The id string is unique for every vm/vcpu, which is stored in kvm
+        * and kvm_vcpu structure.
+        * The id string is part of the stat header from the perspective of
+        * userspace, it is usually read out together with previous constant
+        * header part and could be skipped for later descriptors and stats
+        * data readings.
+        */
+       copylen = header->id_offset + KVM_STATS_NAME_SIZE - pos;
+       copylen = min(copylen, remain);
+       if (copylen > 0) {
+               src = id + pos - header->id_offset;
+               if (copy_to_user(dest, src, copylen))
+                       return -EFAULT;
+               remain -= copylen;
+               pos += copylen;
+               dest += copylen;
+       }
+
+       /*
+        * Copy kvm stats descriptors.
+        * The descriptors copy would be skipped in the typical case that
+        * userspace periodically read stats data, since the pos would be
+        * greater than the end address of descriptors
+        * (header->header.desc_offset + size_desc) causing copylen <= 0.
+        */
+       copylen = header->desc_offset + size_desc - pos;
+       copylen = min(copylen, remain);
+       if (copylen > 0) {
+               src = (void *)desc + pos - header->desc_offset;
+               if (copy_to_user(dest, src, copylen))
+                       return -EFAULT;
+               remain -= copylen;
+               pos += copylen;
+               dest += copylen;
+       }
+
+       /* Copy kvm stats values */
+       copylen = header->data_offset + size_stats - pos;
+       copylen = min(copylen, remain);
+       if (copylen > 0) {
+               src = stats + pos - header->data_offset;
+               if (copy_to_user(dest, src, copylen))
+                       return -EFAULT;
+               remain -= copylen;
+               pos += copylen;
+               dest += copylen;
+       }
+
+       *offset = pos;
+       return len;
+}
index 6a6bc7a..6866c17 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/io.h>
 #include <linux/lockdep.h>
 #include <linux/kthread.h>
+#include <linux/suspend.h>
 
 #include <asm/processor.h>
 #include <asm/ioctl.h>
@@ -114,7 +115,6 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_running_vcpu);
 struct dentry *kvm_debugfs_dir;
 EXPORT_SYMBOL_GPL(kvm_debugfs_dir);
 
-static int kvm_debugfs_num_entries;
 static const struct file_operations stat_fops_per_vm;
 
 static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
@@ -331,7 +331,7 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
         */
        if (!kvm_arch_flush_remote_tlb(kvm)
            || kvm_make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH))
-               ++kvm->stat.remote_tlb_flush;
+               ++kvm->stat.generic.remote_tlb_flush;
        cmpxchg(&kvm->tlbs_dirty, dirty_count, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs);
@@ -780,6 +780,38 @@ static int kvm_init_mmu_notifier(struct kvm *kvm)
 
 #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */
 
+#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
+static int kvm_pm_notifier_call(struct notifier_block *bl,
+                               unsigned long state,
+                               void *unused)
+{
+       struct kvm *kvm = container_of(bl, struct kvm, pm_notifier);
+
+       return kvm_arch_pm_notifier(kvm, state);
+}
+
+static void kvm_init_pm_notifier(struct kvm *kvm)
+{
+       kvm->pm_notifier.notifier_call = kvm_pm_notifier_call;
+       /* Suspend KVM before we suspend ftrace, RCU, etc. */
+       kvm->pm_notifier.priority = INT_MAX;
+       register_pm_notifier(&kvm->pm_notifier);
+}
+
+static void kvm_destroy_pm_notifier(struct kvm *kvm)
+{
+       unregister_pm_notifier(&kvm->pm_notifier);
+}
+#else /* !CONFIG_HAVE_KVM_PM_NOTIFIER */
+static void kvm_init_pm_notifier(struct kvm *kvm)
+{
+}
+
+static void kvm_destroy_pm_notifier(struct kvm *kvm)
+{
+}
+#endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */
+
 static struct kvm_memslots *kvm_alloc_memslots(void)
 {
        int i;
@@ -827,9 +859,24 @@ static void kvm_free_memslots(struct kvm *kvm, struct kvm_memslots *slots)
        kvfree(slots);
 }
 
+static umode_t kvm_stats_debugfs_mode(const struct _kvm_stats_desc *pdesc)
+{
+       switch (pdesc->desc.flags & KVM_STATS_TYPE_MASK) {
+       case KVM_STATS_TYPE_INSTANT:
+               return 0444;
+       case KVM_STATS_TYPE_CUMULATIVE:
+       case KVM_STATS_TYPE_PEAK:
+       default:
+               return 0644;
+       }
+}
+
+
 static void kvm_destroy_vm_debugfs(struct kvm *kvm)
 {
        int i;
+       int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+                                     kvm_vcpu_stats_header.num_desc;
 
        if (!kvm->debugfs_dentry)
                return;
@@ -847,7 +894,10 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
 {
        char dir_name[ITOA_MAX_LEN * 2];
        struct kvm_stat_data *stat_data;
-       struct kvm_stats_debugfs_item *p;
+       const struct _kvm_stats_desc *pdesc;
+       int i;
+       int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+                                     kvm_vcpu_stats_header.num_desc;
 
        if (!debugfs_initialized())
                return 0;
@@ -861,15 +911,32 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd)
        if (!kvm->debugfs_stat_data)
                return -ENOMEM;
 
-       for (p = debugfs_entries; p->name; p++) {
+       for (i = 0; i < kvm_vm_stats_header.num_desc; ++i) {
+               pdesc = &kvm_vm_stats_desc[i];
+               stat_data = kzalloc(sizeof(*stat_data), GFP_KERNEL_ACCOUNT);
+               if (!stat_data)
+                       return -ENOMEM;
+
+               stat_data->kvm = kvm;
+               stat_data->desc = pdesc;
+               stat_data->kind = KVM_STAT_VM;
+               kvm->debugfs_stat_data[i] = stat_data;
+               debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
+                                   kvm->debugfs_dentry, stat_data,
+                                   &stat_fops_per_vm);
+       }
+
+       for (i = 0; i < kvm_vcpu_stats_header.num_desc; ++i) {
+               pdesc = &kvm_vcpu_stats_desc[i];
                stat_data = kzalloc(sizeof(*stat_data), GFP_KERNEL_ACCOUNT);
                if (!stat_data)
                        return -ENOMEM;
 
                stat_data->kvm = kvm;
-               stat_data->dbgfs_item = p;
-               kvm->debugfs_stat_data[p - debugfs_entries] = stat_data;
-               debugfs_create_file(p->name, KVM_DBGFS_GET_MODE(p),
+               stat_data->desc = pdesc;
+               stat_data->kind = KVM_STAT_VCPU;
+               kvm->debugfs_stat_data[i] = stat_data;
+               debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
                                    kvm->debugfs_dentry, stat_data,
                                    &stat_fops_per_vm);
        }
@@ -909,6 +976,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        mutex_init(&kvm->lock);
        mutex_init(&kvm->irq_lock);
        mutex_init(&kvm->slots_lock);
+       mutex_init(&kvm->slots_arch_lock);
        INIT_LIST_HEAD(&kvm->devices);
 
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
@@ -963,6 +1031,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        mutex_unlock(&kvm_lock);
 
        preempt_notifier_inc();
+       kvm_init_pm_notifier(kvm);
 
        return kvm;
 
@@ -1010,6 +1079,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
        int i;
        struct mm_struct *mm = kvm->mm;
 
+       kvm_destroy_pm_notifier(kvm);
        kvm_uevent_notify_change(KVM_EVENT_DESTROY_VM, kvm);
        kvm_destroy_vm_debugfs(kvm);
        kvm_arch_sync_events(kvm);
@@ -1281,6 +1351,14 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
        slots->generation = gen | KVM_MEMSLOT_GEN_UPDATE_IN_PROGRESS;
 
        rcu_assign_pointer(kvm->memslots[as_id], slots);
+
+       /*
+        * Acquired in kvm_set_memslot. Must be released before synchronize
+        * SRCU below in order to avoid deadlock with another thread
+        * acquiring the slots_arch_lock in an srcu critical section.
+        */
+       mutex_unlock(&kvm->slots_arch_lock);
+
        synchronize_srcu_expedited(&kvm->srcu);
 
        /*
@@ -1307,6 +1385,18 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
        return old_memslots;
 }
 
+static size_t kvm_memslots_size(int slots)
+{
+       return sizeof(struct kvm_memslots) +
+              (sizeof(struct kvm_memory_slot) * slots);
+}
+
+static void kvm_copy_memslots(struct kvm_memslots *to,
+                             struct kvm_memslots *from)
+{
+       memcpy(to, from, kvm_memslots_size(from->used_slots));
+}
+
 /*
  * Note, at a minimum, the current number of used slots must be allocated, even
  * when deleting a memslot, as we need a complete duplicate of the memslots for
@@ -1316,19 +1406,16 @@ static struct kvm_memslots *kvm_dup_memslots(struct kvm_memslots *old,
                                             enum kvm_mr_change change)
 {
        struct kvm_memslots *slots;
-       size_t old_size, new_size;
-
-       old_size = sizeof(struct kvm_memslots) +
-                  (sizeof(struct kvm_memory_slot) * old->used_slots);
+       size_t new_size;
 
        if (change == KVM_MR_CREATE)
-               new_size = old_size + sizeof(struct kvm_memory_slot);
+               new_size = kvm_memslots_size(old->used_slots + 1);
        else
-               new_size = old_size;
+               new_size = kvm_memslots_size(old->used_slots);
 
        slots = kvzalloc(new_size, GFP_KERNEL_ACCOUNT);
        if (likely(slots))
-               memcpy(slots, old, old_size);
+               kvm_copy_memslots(slots, old);
 
        return slots;
 }
@@ -1343,9 +1430,27 @@ static int kvm_set_memslot(struct kvm *kvm,
        struct kvm_memslots *slots;
        int r;
 
+       /*
+        * Released in install_new_memslots.
+        *
+        * Must be held from before the current memslots are copied until
+        * after the new memslots are installed with rcu_assign_pointer,
+        * then released before the synchronize srcu in install_new_memslots.
+        *
+        * When modifying memslots outside of the slots_lock, must be held
+        * before reading the pointer to the current memslots until after all
+        * changes to those memslots are complete.
+        *
+        * These rules ensure that installing new memslots does not lose
+        * changes made to the previous memslots.
+        */
+       mutex_lock(&kvm->slots_arch_lock);
+
        slots = kvm_dup_memslots(__kvm_memslots(kvm, as_id), change);
-       if (!slots)
+       if (!slots) {
+               mutex_unlock(&kvm->slots_arch_lock);
                return -ENOMEM;
+       }
 
        if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
                /*
@@ -1356,10 +1461,9 @@ static int kvm_set_memslot(struct kvm *kvm,
                slot->flags |= KVM_MEMSLOT_INVALID;
 
                /*
-                * We can re-use the old memslots, the only difference from the
-                * newly installed memslots is the invalid flag, which will get
-                * dropped by update_memslots anyway.  We'll also revert to the
-                * old memslots if preparing the new memory region fails.
+                * We can re-use the memory from the old memslots.
+                * It will be overwritten with a copy of the new memslots
+                * after reacquiring the slots_arch_lock below.
                 */
                slots = install_new_memslots(kvm, as_id, slots);
 
@@ -1371,6 +1475,17 @@ static int kvm_set_memslot(struct kvm *kvm,
                 *      - kvm_is_visible_gfn (mmu_check_root)
                 */
                kvm_arch_flush_shadow_memslot(kvm, slot);
+
+               /* Released in install_new_memslots. */
+               mutex_lock(&kvm->slots_arch_lock);
+
+               /*
+                * The arch-specific fields of the memslots could have changed
+                * between releasing the slots_arch_lock in
+                * install_new_memslots and here, so get a fresh copy of the
+                * slots.
+                */
+               kvm_copy_memslots(slots, __kvm_memslots(kvm, as_id));
        }
 
        r = kvm_arch_prepare_memory_region(kvm, new, mem, change);
@@ -1386,8 +1501,13 @@ static int kvm_set_memslot(struct kvm *kvm,
        return 0;
 
 out_slots:
-       if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
+       if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
+               slot = id_to_memslot(slots, old->id);
+               slot->flags &= ~KVM_MEMSLOT_INVALID;
                slots = install_new_memslots(kvm, as_id, slots);
+       } else {
+               mutex_unlock(&kvm->slots_arch_lock);
+       }
        kvfree(slots);
        return r;
 }
@@ -2055,6 +2175,13 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault)
        return true;
 }
 
+static int kvm_try_get_pfn(kvm_pfn_t pfn)
+{
+       if (kvm_is_reserved_pfn(pfn))
+               return 1;
+       return get_page_unless_zero(pfn_to_page(pfn));
+}
+
 static int hva_to_pfn_remapped(struct vm_area_struct *vma,
                               unsigned long addr, bool *async,
                               bool write_fault, bool *writable,
@@ -2104,13 +2231,21 @@ static int hva_to_pfn_remapped(struct vm_area_struct *vma,
         * Whoever called remap_pfn_range is also going to call e.g.
         * unmap_mapping_range before the underlying pages are freed,
         * causing a call to our MMU notifier.
+        *
+        * Certain IO or PFNMAP mappings can be backed with valid
+        * struct pages, but be allocated without refcounting e.g.,
+        * tail pages of non-compound higher order allocations, which
+        * would then underflow the refcount when the caller does the
+        * required put_page. Don't allow those pages here.
         */ 
-       kvm_get_pfn(pfn);
+       if (!kvm_try_get_pfn(pfn))
+               r = -EFAULT;
 
 out:
        pte_unmap_unlock(ptep, ptl);
        *p_pfn = pfn;
-       return 0;
+
+       return r;
 }
 
 /*
@@ -2943,9 +3078,9 @@ static inline void
 update_halt_poll_stats(struct kvm_vcpu *vcpu, u64 poll_ns, bool waited)
 {
        if (waited)
-               vcpu->stat.halt_poll_fail_ns += poll_ns;
+               vcpu->stat.generic.halt_poll_fail_ns += poll_ns;
        else
-               vcpu->stat.halt_poll_success_ns += poll_ns;
+               vcpu->stat.generic.halt_poll_success_ns += poll_ns;
 }
 
 /*
@@ -2963,16 +3098,16 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
        if (vcpu->halt_poll_ns && !kvm_arch_no_poll(vcpu)) {
                ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns);
 
-               ++vcpu->stat.halt_attempted_poll;
+               ++vcpu->stat.generic.halt_attempted_poll;
                do {
                        /*
                         * This sets KVM_REQ_UNHALT if an interrupt
                         * arrives.
                         */
                        if (kvm_vcpu_check_block(vcpu) < 0) {
-                               ++vcpu->stat.halt_successful_poll;
+                               ++vcpu->stat.generic.halt_successful_poll;
                                if (!vcpu_valid_wakeup(vcpu))
-                                       ++vcpu->stat.halt_poll_invalid;
+                                       ++vcpu->stat.generic.halt_poll_invalid;
                                goto out;
                        }
                        poll_end = cur = ktime_get();
@@ -3029,7 +3164,7 @@ bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
        waitp = kvm_arch_vcpu_get_wait(vcpu);
        if (rcuwait_wake_up(waitp)) {
                WRITE_ONCE(vcpu->ready, true);
-               ++vcpu->stat.halt_wakeup;
+               ++vcpu->stat.generic.halt_wakeup;
                return true;
        }
 
@@ -3362,6 +3497,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
        vcpu->vcpu_idx = atomic_read(&kvm->online_vcpus);
        BUG_ON(kvm->vcpus[vcpu->vcpu_idx]);
 
+       /* Fill the stats id string for the vcpu */
+       snprintf(vcpu->stats_id, sizeof(vcpu->stats_id), "kvm-%d/vcpu-%d",
+                task_pid_nr(current), id);
+
        /* Now it's all set up, let userspace reach it */
        kvm_get_kvm(kvm);
        r = create_vcpu_fd(vcpu);
@@ -3411,6 +3550,44 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
        return 0;
 }
 
+static ssize_t kvm_vcpu_stats_read(struct file *file, char __user *user_buffer,
+                             size_t size, loff_t *offset)
+{
+       struct kvm_vcpu *vcpu = file->private_data;
+
+       return kvm_stats_read(vcpu->stats_id, &kvm_vcpu_stats_header,
+                       &kvm_vcpu_stats_desc[0], &vcpu->stat,
+                       sizeof(vcpu->stat), user_buffer, size, offset);
+}
+
+static const struct file_operations kvm_vcpu_stats_fops = {
+       .read = kvm_vcpu_stats_read,
+       .llseek = noop_llseek,
+};
+
+static int kvm_vcpu_ioctl_get_stats_fd(struct kvm_vcpu *vcpu)
+{
+       int fd;
+       struct file *file;
+       char name[15 + ITOA_MAX_LEN + 1];
+
+       snprintf(name, sizeof(name), "kvm-vcpu-stats:%d", vcpu->vcpu_id);
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       file = anon_inode_getfile(name, &kvm_vcpu_stats_fops, vcpu, O_RDONLY);
+       if (IS_ERR(file)) {
+               put_unused_fd(fd);
+               return PTR_ERR(file);
+       }
+       file->f_mode |= FMODE_PREAD;
+       fd_install(fd, file);
+
+       return fd;
+}
+
 static long kvm_vcpu_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -3608,6 +3785,10 @@ out_free1:
                r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu);
                break;
        }
+       case KVM_GET_STATS_FD: {
+               r = kvm_vcpu_ioctl_get_stats_fd(vcpu);
+               break;
+       }
        default:
                r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
        }
@@ -3866,6 +4047,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
 #else
                return 0;
 #endif
+       case KVM_CAP_BINARY_STATS_FD:
+               return 1;
        default:
                break;
        }
@@ -3969,6 +4152,42 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
        }
 }
 
+static ssize_t kvm_vm_stats_read(struct file *file, char __user *user_buffer,
+                             size_t size, loff_t *offset)
+{
+       struct kvm *kvm = file->private_data;
+
+       return kvm_stats_read(kvm->stats_id, &kvm_vm_stats_header,
+                               &kvm_vm_stats_desc[0], &kvm->stat,
+                               sizeof(kvm->stat), user_buffer, size, offset);
+}
+
+static const struct file_operations kvm_vm_stats_fops = {
+       .read = kvm_vm_stats_read,
+       .llseek = noop_llseek,
+};
+
+static int kvm_vm_ioctl_get_stats_fd(struct kvm *kvm)
+{
+       int fd;
+       struct file *file;
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       file = anon_inode_getfile("kvm-vm-stats",
+                       &kvm_vm_stats_fops, kvm, O_RDONLY);
+       if (IS_ERR(file)) {
+               put_unused_fd(fd);
+               return PTR_ERR(file);
+       }
+       file->f_mode |= FMODE_PREAD;
+       fd_install(fd, file);
+
+       return fd;
+}
+
 static long kvm_vm_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -4151,6 +4370,9 @@ static long kvm_vm_ioctl(struct file *filp,
        case KVM_RESET_DIRTY_RINGS:
                r = kvm_vm_ioctl_reset_dirty_pages(kvm);
                break;
+       case KVM_GET_STATS_FD:
+               r = kvm_vm_ioctl_get_stats_fd(kvm);
+               break;
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
        }
@@ -4230,6 +4452,9 @@ static int kvm_dev_ioctl_create_vm(unsigned long type)
        if (r < 0)
                goto put_kvm;
 
+       snprintf(kvm->stats_id, sizeof(kvm->stats_id),
+                       "kvm-%d", task_pid_nr(current));
+
        file = anon_inode_getfile("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
        if (IS_ERR(file)) {
                put_unused_fd(r);
@@ -4724,7 +4949,7 @@ static int kvm_debugfs_open(struct inode *inode, struct file *file,
                return -ENOENT;
 
        if (simple_attr_open(inode, file, get,
-                   KVM_DBGFS_GET_MODE(stat_data->dbgfs_item) & 0222
+                   kvm_stats_debugfs_mode(stat_data->desc) & 0222
                    ? set : NULL,
                    fmt)) {
                kvm_put_kvm(stat_data->kvm);
@@ -4747,14 +4972,14 @@ static int kvm_debugfs_release(struct inode *inode, struct file *file)
 
 static int kvm_get_stat_per_vm(struct kvm *kvm, size_t offset, u64 *val)
 {
-       *val = *(ulong *)((void *)kvm + offset);
+       *val = *(u64 *)((void *)(&kvm->stat) + offset);
 
        return 0;
 }
 
 static int kvm_clear_stat_per_vm(struct kvm *kvm, size_t offset)
 {
-       *(ulong *)((void *)kvm + offset) = 0;
+       *(u64 *)((void *)(&kvm->stat) + offset) = 0;
 
        return 0;
 }
@@ -4767,7 +4992,7 @@ static int kvm_get_stat_per_vcpu(struct kvm *kvm, size_t offset, u64 *val)
        *val = 0;
 
        kvm_for_each_vcpu(i, vcpu, kvm)
-               *val += *(u64 *)((void *)vcpu + offset);
+               *val += *(u64 *)((void *)(&vcpu->stat) + offset);
 
        return 0;
 }
@@ -4778,7 +5003,7 @@ static int kvm_clear_stat_per_vcpu(struct kvm *kvm, size_t offset)
        struct kvm_vcpu *vcpu;
 
        kvm_for_each_vcpu(i, vcpu, kvm)
-               *(u64 *)((void *)vcpu + offset) = 0;
+               *(u64 *)((void *)(&vcpu->stat) + offset) = 0;
 
        return 0;
 }
@@ -4788,14 +5013,14 @@ static int kvm_stat_data_get(void *data, u64 *val)
        int r = -EFAULT;
        struct kvm_stat_data *stat_data = (struct kvm_stat_data *)data;
 
-       switch (stat_data->dbgfs_item->kind) {
+       switch (stat_data->kind) {
        case KVM_STAT_VM:
                r = kvm_get_stat_per_vm(stat_data->kvm,
-                                       stat_data->dbgfs_item->offset, val);
+                                       stat_data->desc->desc.offset, val);
                break;
        case KVM_STAT_VCPU:
                r = kvm_get_stat_per_vcpu(stat_data->kvm,
-                                         stat_data->dbgfs_item->offset, val);
+                                         stat_data->desc->desc.offset, val);
                break;
        }
 
@@ -4810,14 +5035,14 @@ static int kvm_stat_data_clear(void *data, u64 val)
        if (val)
                return -EINVAL;
 
-       switch (stat_data->dbgfs_item->kind) {
+       switch (stat_data->kind) {
        case KVM_STAT_VM:
                r = kvm_clear_stat_per_vm(stat_data->kvm,
-                                         stat_data->dbgfs_item->offset);
+                                         stat_data->desc->desc.offset);
                break;
        case KVM_STAT_VCPU:
                r = kvm_clear_stat_per_vcpu(stat_data->kvm,
-                                           stat_data->dbgfs_item->offset);
+                                           stat_data->desc->desc.offset);
                break;
        }
 
@@ -4874,6 +5099,7 @@ static int vm_stat_clear(void *_offset, u64 val)
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vm_stat_fops, vm_stat_get, vm_stat_clear, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(vm_stat_readonly_fops, vm_stat_get, NULL, "%llu\n");
 
 static int vcpu_stat_get(void *_offset, u64 *val)
 {
@@ -4910,11 +5136,7 @@ static int vcpu_stat_clear(void *_offset, u64 val)
 
 DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_fops, vcpu_stat_get, vcpu_stat_clear,
                        "%llu\n");
-
-static const struct file_operations *stat_fops[] = {
-       [KVM_STAT_VCPU] = &vcpu_stat_fops,
-       [KVM_STAT_VM]   = &vm_stat_fops,
-};
+DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_readonly_fops, vcpu_stat_get, NULL, "%llu\n");
 
 static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
 {
@@ -4968,15 +5190,32 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
 
 static void kvm_init_debug(void)
 {
-       struct kvm_stats_debugfs_item *p;
+       const struct file_operations *fops;
+       const struct _kvm_stats_desc *pdesc;
+       int i;
 
        kvm_debugfs_dir = debugfs_create_dir("kvm", NULL);
 
-       kvm_debugfs_num_entries = 0;
-       for (p = debugfs_entries; p->name; ++p, kvm_debugfs_num_entries++) {
-               debugfs_create_file(p->name, KVM_DBGFS_GET_MODE(p),
-                                   kvm_debugfs_dir, (void *)(long)p->offset,
-                                   stat_fops[p->kind]);
+       for (i = 0; i < kvm_vm_stats_header.num_desc; ++i) {
+               pdesc = &kvm_vm_stats_desc[i];
+               if (kvm_stats_debugfs_mode(pdesc) & 0222)
+                       fops = &vm_stat_fops;
+               else
+                       fops = &vm_stat_readonly_fops;
+               debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
+                               kvm_debugfs_dir,
+                               (void *)(long)pdesc->desc.offset, fops);
+       }
+
+       for (i = 0; i < kvm_vcpu_stats_header.num_desc; ++i) {
+               pdesc = &kvm_vcpu_stats_desc[i];
+               if (kvm_stats_debugfs_mode(pdesc) & 0222)
+                       fops = &vcpu_stat_fops;
+               else
+                       fops = &vcpu_stat_readonly_fops;
+               debugfs_create_file(pdesc->name, kvm_stats_debugfs_mode(pdesc),
+                               kvm_debugfs_dir,
+                               (void *)(long)pdesc->desc.offset, fops);
        }
 }
 
@@ -5025,7 +5264,7 @@ static void kvm_sched_out(struct preempt_notifier *pn,
 {
        struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
 
-       if (current->state == TASK_RUNNING) {
+       if (current->on_rq) {
                WRITE_ONCE(vcpu->preempted, true);
                WRITE_ONCE(vcpu->ready, true);
        }
@@ -5126,7 +5365,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
                kmem_cache_create_usercopy("kvm_vcpu", vcpu_size, vcpu_align,
                                           SLAB_ACCOUNT,
                                           offsetof(struct kvm_vcpu, arch),
-                                          sizeof_field(struct kvm_vcpu, arch),
+                                          offsetofend(struct kvm_vcpu, stats_id)
+                                          - offsetof(struct kvm_vcpu, arch),
                                           NULL);
        if (!kvm_vcpu_cache) {
                r = -ENOMEM;